Skip to content

Commit c56d64b

Browse files
authored
refactor(iOS): add type to header bar button items (#3306)
## Description Follow up PR after discussions and changes in react-navigation/react-navigation#12657 ## Changes Following this comment react-navigation/react-navigation#12657 (comment) this PR adds a `type`-property to all items in headerLeftBarButtonItems and headerRightBarButtonItems. Also updates the "Bar Button Items" to the latest API added in react-navigation/react-navigation#12657 ## Screenshots / GIFs Here you can add screenshots / GIFs documenting your change. You can add before / after section if you're changing some behavior. ### Before ### After --> ## Test code and steps to reproduce Run the "Bar Button Items" example. ## Checklist - [x] Included code example that can be used to test this change - [x] Updated TS types - [x] Updated documentation: <!-- For adding new props to native-stack --> - [x] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md - [x] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx - [ ] Ensured that CI passes
1 parent 7349c59 commit c56d64b

File tree

5 files changed

+89
-32
lines changed

5 files changed

+89
-32
lines changed

apps/src/screens/BarButtonItems.tsx

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ export default function BarButtonItemsExample() {
8787
component={PlainButtonDemo}
8888
options={{
8989
title: 'Plain Button',
90-
headerRightItems: [
90+
headerRightItems: () => [
9191
{
92+
type: "button",
9293
label: 'Info',
9394
onPress: () => Alert.alert('Info pressed'),
9495
},
@@ -100,12 +101,14 @@ export default function BarButtonItemsExample() {
100101
component={IconButtonDemo}
101102
options={{
102103
title: 'Icon Button',
103-
headerRightItems: [
104+
headerRightItems: () => [
104105
{
106+
type: "button",
105107
icon: {
106108
type: "imageSource",
107109
imageSource: require('../../assets/search_black.png')
108110
},
111+
label: "Label",
109112
onPress: () => Alert.alert('Icon pressed'),
110113
},
111114
],
@@ -116,12 +119,14 @@ export default function BarButtonItemsExample() {
116119
component={IconButtonDemo}
117120
options={{
118121
title: 'System image Button',
119-
headerRightItems: [
122+
headerRightItems: () => [
120123
{
124+
type: "button",
121125
icon: {
122126
type: "sfSymbol",
123127
name: "square.and.arrow.up"
124128
},
129+
label: "Label",
125130
onPress: () => Alert.alert('Icon pressed'),
126131
},
127132
],
@@ -132,8 +137,9 @@ export default function BarButtonItemsExample() {
132137
component={MenuButtonDemo}
133138
options={{
134139
title: 'Menu Button',
135-
headerRightItems: [
140+
headerRightItems: () => [
136141
{
142+
type: "menu",
137143
label: 'Menu',
138144
menu: {
139145
items: [
@@ -158,8 +164,9 @@ export default function BarButtonItemsExample() {
158164
component={BadgeButtonDemo}
159165
options={{
160166
title: 'Badge Button',
161-
headerRightItems: [
167+
headerRightItems: () => [
162168
{
169+
type: "button",
163170
label: 'Badge',
164171
badge: {
165172
value: '3',
@@ -178,8 +185,9 @@ export default function BarButtonItemsExample() {
178185
component={DisabledButtonDemo}
179186
options={{
180187
title: 'Disabled Button',
181-
headerRightItems: [
188+
headerRightItems: () => [
182189
{
190+
type: "button",
183191
label: 'Disabled',
184192
disabled: true,
185193
onPress: () => Alert.alert('Should not fire'),
@@ -192,8 +200,9 @@ export default function BarButtonItemsExample() {
192200
component={CustomColorButtonDemo}
193201
options={{
194202
title: 'Custom Color Button',
195-
headerRightItems: [
203+
headerRightItems: () => [
196204
{
205+
type: "button",
197206
label: 'Purple',
198207
tintColor: 'purple',
199208
onPress: () => Alert.alert('Purple pressed'),
@@ -206,8 +215,9 @@ export default function BarButtonItemsExample() {
206215
component={ProminentStyleButtonDemo}
207216
options={{
208217
title: 'Prominent Style Button',
209-
headerRightItems: [
218+
headerRightItems: () => [
210219
{
220+
type: "button",
211221
label: 'Prominent',
212222
variant: 'prominent',
213223
tintColor: 'green',
@@ -221,8 +231,9 @@ export default function BarButtonItemsExample() {
221231
component={LabelStyleButtonDemo}
222232
options={{
223233
title: 'Label Style Button',
224-
headerRightItems: [
234+
headerRightItems: () => [
225235
{
236+
type: "button",
226237
label: 'Styled',
227238
labelStyle: {
228239
fontFamily: 'Georgia',
@@ -240,23 +251,31 @@ export default function BarButtonItemsExample() {
240251
component={IconSharesBgButtonDemo}
241252
options={{
242253
title: 'Icon SharesBackground',
243-
headerRightItems: [
254+
headerRightItems: () => [
244255
{
256+
type: "button",
257+
label: "Label",
245258
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
246259
onPress: () => Alert.alert('Icon with sharesBackground pressed'),
247260
sharesBackground: true,
248261
},
249262
{
263+
type: "button",
264+
label: "Label",
250265
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
251266
onPress: () => Alert.alert('Icon with sharesBackground pressed'),
252267
sharesBackground: true,
253268
},
254269
{
270+
type: "button",
271+
label: "Label",
255272
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
256273
onPress: () => Alert.alert('Icon with sharesBackground pressed'),
257274
sharesBackground: false,
258275
},
259276
{
277+
type: "button",
278+
label: "Label",
260279
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
261280
hidesSharedBackground: true,
262281
onPress: () => Alert.alert('Icon with sharesBackground false pressed'),
@@ -269,8 +288,9 @@ export default function BarButtonItemsExample() {
269288
component={TextButtonWithWidthDemo}
270289
options={{
271290
title: 'Text Button With Width',
272-
headerRightItems: [
291+
headerRightItems: () => [
273292
{
293+
type: "button",
274294
label: 'Wide',
275295
width: 100,
276296
onPress: () => Alert.alert('Wide text button pressed'),
@@ -283,15 +303,20 @@ export default function BarButtonItemsExample() {
283303
component={IconButtonsWithSpacingDemo}
284304
options={{
285305
title: 'Icon Buttons With Spacing',
286-
headerRightItems: [
306+
headerRightItems: () => [
287307
{
308+
type: "button",
309+
label: "Label",
288310
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
289311
onPress: () => Alert.alert('First icon pressed'),
290312
},
291313
{
314+
type: "spacing",
292315
spacing: 100,
293316
},
294317
{
318+
type: "button",
319+
label: "Label",
295320
icon: { type: "imageSource", imageSource: require('../../assets/search_white.png') },
296321
onPress: () => Alert.alert('Second icon pressed'),
297322
},
@@ -304,12 +329,15 @@ export default function BarButtonItemsExample() {
304329
options={{
305330
title: 'Header Tint Color',
306331
headerTintColor: 'red',
307-
headerRightItems: [
332+
headerRightItems: () => [
308333
{
334+
type: "button",
309335
label: 'Tinted',
310336
onPress: () => Alert.alert('Tinted pressed'),
311337
},
312338
{
339+
type: "button",
340+
label: "Label",
313341
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
314342
onPress: () => Alert.alert('Tinted icon pressed'),
315343
},
@@ -321,13 +349,16 @@ export default function BarButtonItemsExample() {
321349
component={DoneStyleButtonDemo}
322350
options={{
323351
title: 'Done Style Button',
324-
headerRightItems: [
352+
headerRightItems: () => [
325353
{
354+
type: "button",
326355
label: 'Done',
327356
variant: 'done',
328357
onPress: () => Alert.alert('Done text pressed'),
329358
},
330359
{
360+
type: "button",
361+
label: "DoneIcon",
331362
icon: { type: "imageSource", imageSource: require('../../assets/search_black.png') },
332363
variant: 'done',
333364
onPress: () => Alert.alert('Done icon pressed'),
@@ -340,8 +371,9 @@ export default function BarButtonItemsExample() {
340371
component={AdvancedMenuButtonDemo}
341372
options={{
342373
title: 'Advanced Menu Button',
343-
headerRightItems: [
374+
headerRightItems: () => [
344375
{
376+
type: "menu",
345377
label: 'Menu',
346378
menu: {
347379
label: 'Context menu',
@@ -396,22 +428,23 @@ export default function BarButtonItemsExample() {
396428
options={{
397429
title: 'React Node Button',
398430
headerBackVisible: true,
399-
headerRightItems: [
431+
headerRightItems: () => [
400432
{
401-
// eslint-disable-next-line react/no-unstable-nested-components
402-
customView: () => <TouchableOpacity onPress={() => Alert.alert('React Node 1 pressed')}>
433+
type: "custom",
434+
element: <TouchableOpacity onPress={() => Alert.alert('React Node 1 pressed')}>
403435
<Text style={{ color: 'blue' }}>React Node 1</Text>
404436
</TouchableOpacity>,
405437
hidesSharedBackground: true
406438
},
407439
{
440+
type: "button",
408441
label: "Native",
409442
onPress: () => Alert.alert('Native button pressed'),
410443
sharesBackground: true,
411444
},
412445
{
413-
// eslint-disable-next-line react/no-unstable-nested-components
414-
customView: () => <TouchableOpacity onPress={() => Alert.alert('React Node 2 pressed')}>
446+
type: "custom",
447+
element: <TouchableOpacity onPress={() => Alert.alert('React Node 2 pressed')}>
415448
<Text style={{ color: 'red' }}>React Node 2</Text>
416449
</TouchableOpacity>
417450
},
@@ -422,14 +455,15 @@ export default function BarButtonItemsExample() {
422455
options={{
423456
title: 'Back Button Visible',
424457
headerBackVisible: true,
425-
headerLeftItems: [
458+
headerLeftItems: () => [
426459
{
427-
// eslint-disable-next-line react/no-unstable-nested-components
428-
customView: () => <TouchableOpacity onPress={() => Alert.alert('Left React Node')}>
460+
type: "custom",
461+
element: <TouchableOpacity onPress={() => Alert.alert('Left React Node')}>
429462
<Text style={{ color: 'blue' }}>React Node</Text>
430463
</TouchableOpacity>
431464
},
432465
{
466+
type: "button",
433467
label: "Native",
434468
onPress: () => Alert.alert('Native button pressed'),
435469
},
@@ -439,8 +473,9 @@ export default function BarButtonItemsExample() {
439473
component={IdentifierExample}
440474
options={({ navigation }) => ({
441475
title: 'Identifier Example',
442-
headerRightItems: [
476+
headerRightItems: () => [
443477
{
478+
type: "button",
444479
label: 'Button',
445480
onPress: () => {
446481
navigation.navigate('IdentifierExample2');
@@ -453,8 +488,9 @@ export default function BarButtonItemsExample() {
453488
component={IdentifierExample2}
454489
options={{
455490
title: 'Identifier Example 2',
456-
headerRightItems: [
491+
headerRightItems: () => [
457492
{
493+
type: "button",
458494
label: 'Btn',
459495
onPress: () => Alert.alert('Button 1 pressed'),
460496
},
@@ -464,20 +500,24 @@ export default function BarButtonItemsExample() {
464500
component={ExessiveItemsExample}
465501
options={{
466502
title: 'Exessive Items Example',
467-
headerRightItems: [
503+
headerRightItems: () => [
468504
{
505+
type: "button",
469506
label: "Button 1",
470507
onPress: () => Alert.alert('Button 1 pressed'),
471508
},
472509
{
510+
type: "button",
473511
label: "Button 2",
474512
onPress: () => Alert.alert('Button 2 pressed'),
475513
},
476514
{
515+
type: "button",
477516
label: "Button 3",
478517
onPress: () => Alert.alert('Button 3 pressed'),
479518
},
480519
{
520+
type: "button",
481521
label: "Button 4",
482522
onPress: () => Alert.alert('Button 4 pressed'),
483523
},

guides/GUIDE_FOR_LIBRARY_AUTHORS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ An array of objects describing native bar button items to display on the left or
575575

576576
#### The button and menu items support:
577577

578+
`type: 'button' | 'menu'` — Type of the item.
579+
578580
`label: string` — Label of the button.
579581

580582
`labelStyle?: { fontFamily?: string; fontSize?: number; fontWeight?: string; color?: ColorValue; }` — Style for the button label.
@@ -607,6 +609,7 @@ An array of objects describing native bar button items to display on the left or
607609

608610
```
609611
menu?: {
612+
type: 'menu';
610613
label?: string;
611614
items: Array<
612615
| {
@@ -632,6 +635,7 @@ menu?: {
632635

633636
#### The spacing item supports:
634637

638+
`type: 'spacing'` — Type of the item.
635639
`spacing?: number` — Fixed space between items. The numeric value is only supported on iOS 18-
636640

637641
#### Example configuration:
@@ -641,18 +645,22 @@ menu?: {
641645
options={{
642646
headerRightItems: [
643647
{
648+
type: 'button',
644649
label: 'Text button',
645650
onPress: () => Alert.alert('Text pressed'),
646651
},
647652
{
653+
type: 'button',
648654
image: require('../../assets/search_black.png'),
649655
onPress: () => Alert.alert('Icon pressed'),
650656
},
651657
{
658+
type: 'button',
652659
sfSymbolName: "square.and.arrow.up",
653660
onPress: () => Alert.alert('SF symbol pressed'),
654661
},
655662
{
663+
type: 'menu',
656664
label: 'Menu',
657665
menu: {
658666
items: [
@@ -670,6 +678,7 @@ menu?: {
670678
},
671679
},
672680
{
681+
type: 'button',
673682
label: 'Badge',
674683
badge: {
675684
value: '3',
@@ -679,6 +688,7 @@ menu?: {
679688
onPress: () => Alert.alert('Badge pressed'),
680689
},
681690
{
691+
type: 'button',
682692
label: 'Prominent',
683693
variant: 'prominent',
684694
tintColor: 'green',

0 commit comments

Comments
 (0)