react-native-screens 4.25.0-beta.1 → 4.25.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderAppBarLayout.kt +6 -14
  2. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderAppBarLayoutBehavior.kt +29 -0
  3. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderCoordinator.kt +56 -0
  4. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfig.kt +11 -0
  5. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfigProviding.kt +5 -0
  6. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfigViewManager.kt +35 -0
  7. package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/subview/StackHeaderSubview.kt +3 -7
  8. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsActionOrigin.kt +26 -0
  9. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt +227 -151
  10. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavigationState.kt +60 -0
  11. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/{TabsContainerDelegate.kt → TabsNavigationStateObserver.kt} +19 -14
  12. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavigationStateObserverRegistry.kt +88 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt +40 -24
  14. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostEventEmitter.kt +11 -9
  15. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt +19 -7
  16. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectedEvent.kt +4 -3
  17. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionPreventedEvent.kt +3 -3
  18. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionRejectedEvent.kt +11 -10
  19. package/ios/conversion/RNSConversions-Tabs.mm +19 -0
  20. package/ios/conversion/RNSConversions.h +3 -0
  21. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryHelper.mm +34 -5
  22. package/ios/tabs/host/RNSTabBarController.h +152 -99
  23. package/ios/tabs/host/RNSTabBarController.mm +137 -113
  24. package/ios/tabs/host/RNSTabsHostComponentView.h +7 -8
  25. package/ios/tabs/host/RNSTabsHostComponentView.mm +37 -33
  26. package/ios/tabs/host/RNSTabsHostEventEmitter.h +4 -4
  27. package/ios/tabs/host/RNSTabsHostEventEmitter.mm +5 -3
  28. package/ios/tabs/host/RNSTabsNavigationState.h +142 -27
  29. package/ios/tabs/host/RNSTabsNavigationState.mm +35 -2
  30. package/ios/tabs/host/RNSTabsNavigationStateObserverRegistry.h +62 -0
  31. package/ios/tabs/host/RNSTabsNavigationStateObserverRegistry.mm +104 -0
  32. package/lib/commonjs/components/gamma/stack/header/StackHeaderConfig.android.js +46 -1
  33. package/lib/commonjs/components/gamma/stack/header/StackHeaderConfig.android.js.map +1 -1
  34. package/lib/commonjs/components/safe-area/SafeAreaView.web.js +2 -3
  35. package/lib/commonjs/components/safe-area/SafeAreaView.web.js.map +1 -1
  36. package/lib/commonjs/components/tabs/host/TabsHost.android.js +2 -2
  37. package/lib/commonjs/components/tabs/host/TabsHost.android.js.map +1 -1
  38. package/lib/commonjs/components/tabs/host/TabsHost.ios.js +2 -2
  39. package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
  40. package/lib/commonjs/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  41. package/lib/commonjs/flags.js +1 -0
  42. package/lib/commonjs/flags.js.map +1 -1
  43. package/lib/module/components/gamma/stack/header/StackHeaderConfig.android.js +46 -1
  44. package/lib/module/components/gamma/stack/header/StackHeaderConfig.android.js.map +1 -1
  45. package/lib/module/components/safe-area/SafeAreaView.web.js +1 -1
  46. package/lib/module/components/safe-area/SafeAreaView.web.js.map +1 -1
  47. package/lib/module/components/tabs/host/TabsHost.android.js +2 -2
  48. package/lib/module/components/tabs/host/TabsHost.android.js.map +1 -1
  49. package/lib/module/components/tabs/host/TabsHost.ios.js +2 -2
  50. package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
  51. package/lib/module/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  52. package/lib/module/flags.js +1 -0
  53. package/lib/module/flags.js.map +1 -1
  54. package/lib/typescript/components/gamma/split/SplitHost.types.d.ts +1 -1
  55. package/lib/typescript/components/gamma/split/SplitHost.types.d.ts.map +1 -1
  56. package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
  57. package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.types.d.ts +183 -8
  58. package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
  59. package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.types.d.ts +37 -0
  60. package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.types.d.ts.map +1 -1
  61. package/lib/typescript/components/gamma/stack/header/android/StackHeaderSubview.android.types.d.ts +1 -1
  62. package/lib/typescript/components/gamma/stack/header/android/StackHeaderSubview.android.types.d.ts.map +1 -1
  63. package/lib/typescript/components/gamma/stack/host/StackHost.types.d.ts +1 -1
  64. package/lib/typescript/components/gamma/stack/host/StackHost.types.d.ts.map +1 -1
  65. package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts +1 -1
  66. package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts.map +1 -1
  67. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts +27 -17
  68. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts.map +1 -1
  69. package/lib/typescript/components/tabs/index.d.ts +1 -1
  70. package/lib/typescript/components/tabs/index.d.ts.map +1 -1
  71. package/lib/typescript/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.d.ts +5 -0
  72. package/lib/typescript/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.d.ts.map +1 -1
  73. package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts +4 -4
  74. package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts.map +1 -1
  75. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +4 -4
  76. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
  77. package/lib/typescript/flags.d.ts +1 -0
  78. package/lib/typescript/flags.d.ts.map +1 -1
  79. package/package.json +1 -1
  80. package/src/components/gamma/split/SplitHost.types.ts +1 -1
  81. package/src/components/gamma/stack/header/StackHeaderConfig.android.tsx +72 -2
  82. package/src/components/gamma/stack/header/StackHeaderConfig.android.types.ts +183 -8
  83. package/src/components/gamma/stack/header/StackHeaderConfig.types.ts +37 -0
  84. package/src/components/gamma/stack/header/android/StackHeaderSubview.android.types.ts +1 -1
  85. package/src/components/gamma/stack/host/StackHost.types.ts +1 -1
  86. package/src/components/safe-area/SafeAreaView.web.tsx +1 -1
  87. package/src/components/tabs/host/TabsHost.android.tsx +2 -2
  88. package/src/components/tabs/host/TabsHost.ios.tsx +2 -2
  89. package/src/components/tabs/host/TabsHost.types.ts +27 -17
  90. package/src/components/tabs/index.ts +1 -1
  91. package/src/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.ts +6 -0
  92. package/src/fabric/tabs/TabsHostAndroidNativeComponent.ts +4 -4
  93. package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +4 -4
  94. package/src/flags.ts +1 -0
  95. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainerOps.kt +0 -7
  96. package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavState.kt +0 -43
@@ -4,7 +4,10 @@ import type { StackHeaderConfigProps } from './StackHeaderConfig.types';
4
4
  import StackHeaderConfigAndroidNativeComponent from '../../../../fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent';
5
5
  import type { NativeProps as StackHeaderConfigAndroidNativeComponentProps } from '../../../../fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent';
6
6
  import StackHeaderSubview from './android/StackHeaderSubview.android';
7
- import type { StackHeaderConfigPropsAndroid } from './StackHeaderConfig.android.types';
7
+ import type {
8
+ StackHeaderConfigPropsAndroid,
9
+ StackHeaderTypeAndroid,
10
+ } from './StackHeaderConfig.android.types';
8
11
 
9
12
  /**
10
13
  * EXPERIMENTAL API, MIGHT CHANGE W/O ANY NOTICE
@@ -20,10 +23,22 @@ function StackHeaderConfig(props: StackHeaderConfigProps) {
20
23
  centerSubview,
21
24
  trailingSubview,
22
25
  backButtonIcon,
26
+ scrollFlagScroll,
27
+ scrollFlagEnterAlways,
28
+ scrollFlagEnterAlwaysCollapsed,
29
+ scrollFlagExitUntilCollapsed,
30
+ scrollFlagSnap,
23
31
  ...filteredAndroidProps
24
32
  } = android ?? {};
25
33
 
26
34
  const backButtonIconProps = parseBackButtonIconToNativeProps(backButtonIcon);
35
+ const scrollFlagProps = resolveScrollFlags(filteredAndroidProps.type, {
36
+ scrollFlagScroll,
37
+ scrollFlagEnterAlways,
38
+ scrollFlagEnterAlwaysCollapsed,
39
+ scrollFlagExitUntilCollapsed,
40
+ scrollFlagSnap,
41
+ });
27
42
 
28
43
  return (
29
44
  <StackHeaderConfigAndroidNativeComponent
@@ -31,7 +46,8 @@ function StackHeaderConfig(props: StackHeaderConfigProps) {
31
46
  style={StyleSheet.absoluteFill}
32
47
  {...baseProps}
33
48
  {...filteredAndroidProps}
34
- {...backButtonIconProps}>
49
+ {...backButtonIconProps}
50
+ {...scrollFlagProps}>
35
51
  {/*
36
52
  Please note that the order of the subviews MUST match
37
53
  the order in native StackHeaderConfig.getConfigSubviewAt.
@@ -93,4 +109,58 @@ function parseBackButtonIconToNativeProps(
93
109
  }
94
110
  }
95
111
 
112
+ type ScrollFlagFields = {
113
+ scrollFlagScroll: boolean;
114
+ scrollFlagEnterAlways: boolean;
115
+ scrollFlagEnterAlwaysCollapsed: boolean;
116
+ scrollFlagExitUntilCollapsed: boolean;
117
+ scrollFlagSnap: boolean;
118
+ };
119
+
120
+ const SCROLL_FLAG_DEFAULTS_BY_TYPE: Record<
121
+ StackHeaderTypeAndroid,
122
+ ScrollFlagFields
123
+ > = {
124
+ small: {
125
+ scrollFlagScroll: false,
126
+ scrollFlagEnterAlways: false,
127
+ scrollFlagEnterAlwaysCollapsed: false,
128
+ scrollFlagExitUntilCollapsed: false,
129
+ scrollFlagSnap: false,
130
+ },
131
+ medium: {
132
+ scrollFlagScroll: true,
133
+ scrollFlagEnterAlways: false,
134
+ scrollFlagEnterAlwaysCollapsed: false,
135
+ scrollFlagExitUntilCollapsed: true,
136
+ scrollFlagSnap: true,
137
+ },
138
+ large: {
139
+ scrollFlagScroll: true,
140
+ scrollFlagEnterAlways: false,
141
+ scrollFlagEnterAlwaysCollapsed: false,
142
+ scrollFlagExitUntilCollapsed: true,
143
+ scrollFlagSnap: true,
144
+ },
145
+ };
146
+
147
+ function resolveScrollFlags(
148
+ type: StackHeaderTypeAndroid | undefined,
149
+ overrides: Pick<StackHeaderConfigPropsAndroid, keyof ScrollFlagFields>,
150
+ ): ScrollFlagFields {
151
+ const defaults = SCROLL_FLAG_DEFAULTS_BY_TYPE[type ?? 'small'];
152
+ return {
153
+ scrollFlagScroll: overrides.scrollFlagScroll ?? defaults.scrollFlagScroll,
154
+ scrollFlagEnterAlways:
155
+ overrides.scrollFlagEnterAlways ?? defaults.scrollFlagEnterAlways,
156
+ scrollFlagEnterAlwaysCollapsed:
157
+ overrides.scrollFlagEnterAlwaysCollapsed ??
158
+ defaults.scrollFlagEnterAlwaysCollapsed,
159
+ scrollFlagExitUntilCollapsed:
160
+ overrides.scrollFlagExitUntilCollapsed ??
161
+ defaults.scrollFlagExitUntilCollapsed,
162
+ scrollFlagSnap: overrides.scrollFlagSnap ?? defaults.scrollFlagSnap,
163
+ };
164
+ }
165
+
96
166
  export default StackHeaderConfig;
@@ -9,30 +9,205 @@ export type StackHeaderBackgroundSubviewCollapseModeAndroid =
9
9
  StackHeaderSubviewCollapseModeAndroid;
10
10
 
11
11
  export interface StackHeaderToolbarSubviewAndroid {
12
- Component: ReactNode;
12
+ /**
13
+ * @summary The React component rendered in this toolbar slot.
14
+ *
15
+ * The subview is sized by React Native's layout engine but positioned by the
16
+ * platform native layout. Each subview is placed independently — subviews do
17
+ * not participate in a shared flex layout and cannot influence each other's
18
+ * sizing.
19
+ *
20
+ *
21
+ * @remarks
22
+ * Intrinsic sizing and explicit dimensions work as expected. Avoid
23
+ * parent-relative sizing (e.g. `flex: 1`) on the root element — it will
24
+ * produce incorrect dimensions. Flex layout within a root that has a known
25
+ * size works as expected.
26
+ *
27
+ * @platform android
28
+ */
29
+ Component: NonNullable<ReactNode>;
13
30
  }
14
31
 
15
32
  export interface StackHeaderBackgroundSubviewAndroid {
33
+ /**
34
+ * @summary Controls how the background subview behaves when the app bar
35
+ * collapses.
36
+ *
37
+ * The following values are available:
38
+ * - `off` - the subview scrolls away with the app bar,
39
+ * - `parallax` - the subview scrolls at a slower rate, creating a parallax
40
+ * effect.
41
+ *
42
+ * @remarks
43
+ * `pin` is not currently supported because the background subview is
44
+ * stretched to match the entire `AppBarLayout`, which causes pinned content
45
+ * to move immediately rather than staying fixed. Support for `pin` collapse
46
+ * mode might be added in the future.
47
+ *
48
+ * @default off
49
+ *
50
+ * @platform android
51
+ */
16
52
  collapseMode?: StackHeaderSubviewCollapseModeAndroid | undefined;
17
- Component: ReactNode;
53
+ /**
54
+ * @summary The React component rendered as the header background.
55
+ *
56
+ * The subview is stretched to match the header (`AppBarLayout`) dimensions,
57
+ * so parent-relative sizing (e.g. `flex: 1`) works correctly.
58
+ *
59
+ * @platform android
60
+ */
61
+ Component: NonNullable<ReactNode>;
18
62
  }
19
63
 
20
64
  export interface StackHeaderConfigPropsAndroid {
65
+ /**
66
+ * @summary Specifies the type of the Material 3 app bar.
67
+ *
68
+ * The following values are available:
69
+ * - `small` - small app bar with fixed title,
70
+ * - `medium` - medium app bar with collapsing title,
71
+ * - `large` - large app bar with collapsing title.
72
+ *
73
+ * @remarks
74
+ * M3 Expressive headers aren't currently supported (there is no stable
75
+ * `MDC-Android` version yet).
76
+ *
77
+ * @see {@link https://m3.material.io/components/app-bars/overview|Material Design 3: App bars}
78
+ *
79
+ * @default small
80
+ *
81
+ * @platform android
82
+ */
21
83
  type?: StackHeaderTypeAndroid | undefined;
84
+ /**
85
+ * @summary Custom view rendered behind the header content.
86
+ *
87
+ * @platform android
88
+ */
22
89
  backgroundSubview?: StackHeaderBackgroundSubviewAndroid | undefined;
90
+ /**
91
+ * @summary Custom view placed in the leading (start) slot of the toolbar.
92
+ *
93
+ * @platform android
94
+ */
23
95
  leadingSubview?: StackHeaderToolbarSubviewAndroid | undefined;
96
+ /**
97
+ * @summary Custom view placed in the center slot of the toolbar.
98
+ *
99
+ * @platform android
100
+ */
24
101
  centerSubview?: StackHeaderToolbarSubviewAndroid | undefined;
102
+ /**
103
+ * @summary Custom view placed in the trailing (end) slot of the toolbar.
104
+ *
105
+ * @platform android
106
+ */
25
107
  trailingSubview?: StackHeaderToolbarSubviewAndroid | undefined;
26
108
  /**
27
- * Tint color for the back button icon.
28
- * - `undefined` — use default tint (for custom images, no tint is applied)
29
- * - `ColorValue` apply a custom tint color
109
+ * @summary Tint color applied to the back button icon.
110
+ *
111
+ * When `undefined`, the default tint color is used. This applies to the
112
+ * native back arrow and `drawableResource` icons that have an associated
113
+ * tint. For `imageSource` icons, no tint is applied by default.
114
+ *
115
+ * @platform android
30
116
  */
31
117
  backButtonTintColor?: ColorValue | undefined;
32
118
  /**
33
- * Custom icon for the back button.
34
- * - `undefined` — use the native default back arrow
35
- * - `PlatformIconAndroid` use a custom icon (drawableResource or imageSource)
119
+ * @summary Custom icon for the back button.
120
+ *
121
+ * When `undefined`, the native back arrow (`homeAsUpIndicator`) is used.
122
+ *
123
+ * Supported values:
124
+ * - `{ type: 'imageSource', imageSource }`
125
+ * Uses an image from the provided resource.
126
+ *
127
+ * Remarks: `imageSource` type doesn't support SVGs on Android.
128
+ * For loading SVGs use `drawableResource` type.
129
+ *
130
+ * - `{ type: 'drawableResource', name }`
131
+ * Uses a drawable resource with the given name.
132
+ *
133
+ * Remarks: Requires passing a drawable to resources via Android Studio.
134
+ *
135
+ * @platform android
36
136
  */
37
137
  backButtonIcon?: PlatformIconAndroid | undefined;
138
+ /**
139
+ * @summary Whether the header reacts to nested scroll. Required for any
140
+ * other `scrollFlag*` prop to take effect.
141
+ *
142
+ * When `undefined`, falls back to the type-specific default:
143
+ * - `small` -> `false`
144
+ * - `medium` / `large` -> `true`
145
+ *
146
+ * @remarks
147
+ * Changing any `scrollFlag*` at runtime forces the header back to
148
+ * its fully expanded state, which produces a visible snap. Treat these
149
+ * props as a static configuration.
150
+ *
151
+ * @platform android
152
+ */
153
+ scrollFlagScroll?: boolean | undefined;
154
+ /**
155
+ * @summary When enabled, the header re-expands as soon as the user scrolls
156
+ * back toward the top of the content, regardless of the ScrollView's current
157
+ * scroll position. Without this flag, the header only begins expanding once
158
+ * the list has reached the top of its content. Requires `scrollFlagScroll`.
159
+ *
160
+ * When `undefined`, falls back to the type-specific default (`false` for
161
+ * all types).
162
+ *
163
+ * @platform android
164
+ */
165
+ scrollFlagEnterAlways?: boolean | undefined;
166
+ /**
167
+ * @summary Modifies `scrollFlagEnterAlways` so that the initial re-entry
168
+ * stops at the header's collapsed height (the toolbar); the remainder
169
+ * expands only after the ScrollView reaches the top of its content. Requires
170
+ * `scrollFlagEnterAlways`.
171
+ *
172
+ * When `undefined`, falls back to the type-specific default (`false` for
173
+ * all types).
174
+ *
175
+ * @remarks
176
+ * This flag does not have any effect for `small` header.
177
+ *
178
+ * @platform android
179
+ */
180
+ scrollFlagEnterAlwaysCollapsed?: boolean | undefined;
181
+ /**
182
+ * @summary When enabled, the header collapses only until its minimum height
183
+ * (the toolbar) remains pinned at the top. Without this flag, the entire
184
+ * header scrolls off the screen. Requires `scrollFlagScroll`.
185
+ *
186
+ * When `undefined`, falls back to the type-specific default:
187
+ * - `small` -> `false`
188
+ * - `medium` / `large` -> `true`
189
+ *
190
+ * @remarks
191
+ * Setting this flag for `small` header is equivalent to disabling
192
+ * `scrollFlagScroll`.
193
+ *
194
+ * Even when this flag is disabled, a strip with the height of the system top
195
+ * inset (status bar and display cutout) remains visible at the top.
196
+ *
197
+ * @platform android
198
+ */
199
+ scrollFlagExitUntilCollapsed?: boolean | undefined;
200
+ /**
201
+ * @summary When enabled, the header snaps to its nearest edge (fully
202
+ * expanded, or fully collapsed as defined by `scrollFlagExitUntilCollapsed`)
203
+ * after a scroll gesture ends, instead of resting partway. Requires
204
+ * `scrollFlagScroll`.
205
+ *
206
+ * When `undefined`, falls back to the type-specific default:
207
+ * - `small` -> `false`
208
+ * - `medium` / `large` -> `true`
209
+ *
210
+ * @platform android
211
+ */
212
+ scrollFlagSnap?: boolean | undefined;
38
213
  }
@@ -2,9 +2,46 @@ import { StackHeaderConfigPropsAndroid } from './StackHeaderConfig.android.types
2
2
  import { StackHeaderConfigPropsIOS } from './StackHeaderConfig.ios.types';
3
3
 
4
4
  export interface StackHeaderConfigPropsBase {
5
+ /**
6
+ * @summary Title displayed in the header.
7
+ *
8
+ * @platform android, ios
9
+ */
5
10
  title?: string | undefined;
11
+ /**
12
+ * @summary Specifies if the header should be hidden.
13
+ *
14
+ * @default false
15
+ *
16
+ * @platform android, ios
17
+ */
6
18
  hidden?: boolean | undefined;
19
+ /**
20
+ * @summary Specifies if the content should be rendered behind the header.
21
+ *
22
+ * When `true`, content is rendered behind the header instead of starting
23
+ * below it.
24
+ *
25
+ * On Android:
26
+ * - The header background color is not affected by this prop.
27
+ * - Setting this prop to `true` is not supported when header scrolling is
28
+ * enabled.
29
+ *
30
+ * @default false
31
+ *
32
+ * @platform android, ios
33
+ */
7
34
  transparent?: boolean | undefined;
35
+ /**
36
+ * @summary Specifies if the back button should be hidden.
37
+ *
38
+ * This prop does not apply to the root screen of the stack for which the back
39
+ * button is always hidden.
40
+ *
41
+ * @default false
42
+ *
43
+ * @platform android, ios
44
+ */
8
45
  backButtonHidden?: boolean | undefined;
9
46
  }
10
47
 
@@ -9,7 +9,7 @@ export type StackHeaderSubviewTypeAndroid =
9
9
  export type StackHeaderSubviewCollapseModeAndroid = 'off' | 'parallax';
10
10
 
11
11
  export type StackHeaderSubviewProps = {
12
- children?: ViewProps['children'] | undefined;
12
+ children: NonNullable<ViewProps['children']>;
13
13
 
14
14
  type?: StackHeaderSubviewTypeAndroid | undefined;
15
15
  collapseMode?: StackHeaderSubviewCollapseModeAndroid | undefined;
@@ -3,7 +3,7 @@ import type { ReactNativeElement, ViewProps } from 'react-native';
3
3
  import { type NativeProps } from '../../../../fabric/gamma/stack/StackHostNativeComponent';
4
4
 
5
5
  export type StackHostProps = {
6
- children: ViewProps['children'];
6
+ children: NonNullable<ViewProps['children']>;
7
7
  // TODO: Work on these types
8
8
  ref?:
9
9
  | React.RefObject<
@@ -2,4 +2,4 @@ import { View } from 'react-native';
2
2
 
3
3
  const SafeAreaView = View;
4
4
 
5
- export default SafeAreaView;
5
+ export { SafeAreaView };
@@ -25,7 +25,7 @@ function TabsHost(props: TabsHostProps) {
25
25
  direction,
26
26
  nativeContainerStyle,
27
27
  onTabSelected,
28
- navState,
28
+ navStateRequest,
29
29
  ...filteredBaseProps
30
30
  } = baseProps;
31
31
 
@@ -41,7 +41,7 @@ function TabsHost(props: TabsHostProps) {
41
41
  return (
42
42
  <TabsHostAndroidNativeComponent
43
43
  style={[styles.fillParent, { direction }]}
44
- navState={navState}
44
+ navStateRequest={navStateRequest}
45
45
  onTabSelected={onTabSelectedCallback}
46
46
  nativeContainerBackgroundColor={nativeContainerStyle?.backgroundColor}
47
47
  // @ts-ignore suppress ref - debug only
@@ -28,7 +28,7 @@ function TabsHost(props: TabsHostProps) {
28
28
  direction,
29
29
  nativeContainerStyle,
30
30
  onTabSelected,
31
- navState,
31
+ navStateRequest,
32
32
  ...filteredBaseProps
33
33
  } = baseProps;
34
34
 
@@ -47,7 +47,7 @@ function TabsHost(props: TabsHostProps) {
47
47
  return (
48
48
  <TabsHostIOSNativeComponent
49
49
  style={styles.fillParent}
50
- navState={navState}
50
+ navStateRequest={navStateRequest}
51
51
  onTabSelected={onTabSelectedCallback}
52
52
  nativeContainerBackgroundColor={nativeContainerStyle?.backgroundColor}
53
53
  // @ts-ignore suppress ref - debug only
@@ -5,7 +5,7 @@ import type { ColorScheme, Direction } from '../../shared/types';
5
5
 
6
6
  // #region Control
7
7
 
8
- export type TabsHostNavState = {
8
+ export type TabsHostNavStateRequest = {
9
9
  /**
10
10
  * @summary Valid screen key.
11
11
  *
@@ -14,13 +14,12 @@ export type TabsHostNavState = {
14
14
  */
15
15
  selectedScreenKey: string;
16
16
  /**
17
- * @summary A number describing the provenance of the state instance.
17
+ * @summary Provenance of the navigation state this request is derived from.
18
18
  *
19
19
  * @description
20
20
  * The provenance value establishes a relationship between different navigation state instances
21
- * held by given state holder. The assumption here is that when the navigation
22
- * state is progressed (modified), the provenance number is incremented.
23
- * This creates a relationship where we can say that:
21
+ * held by given state holder. The assumption is that when the navigation state is progressed
22
+ * (modified), the provenance number is incremented. This creates a relationship where we can say:
24
23
  *
25
24
  * 1. State with provenance = n + 1 has been derived from state with provenance = n.
26
25
  * 2. For two given navigation states A and B, we can say that A *is stale* iff
@@ -31,12 +30,15 @@ export type TabsHostNavState = {
31
30
  *
32
31
  * Currently, the native implementation of TabsHost is the state holder.
33
32
  *
34
- * When you use object of this shape to trigger a navigation via {@link TabsHostPropsBase#navState},
35
- * pass here THE PROVENANCE OF THE LAST ACKNOWLEDGED state you received from native side
36
- * via {@link TabsHostPropsBase#onTabSelected}. In other words this should be the provenance number
37
- * of last confirmed state you base your update request on.
33
+ * Pass here THE PROVENANCE OF THE LAST ACKNOWLEDGED state you received from native side
34
+ * via {@link TabsHostPropsBase#onTabSelected}. In other words this should be the provenance
35
+ * number of last confirmed state you base your update request on.
36
+ *
37
+ * It is named `baseProvenance` (rather than `provenance`) to disambiguate it from the
38
+ * `provenance` field on the {@link TabSelectedEvent} payload, which carries the provenance
39
+ * of the state *resulting* from a transition.
38
40
  */
39
- provenance: number;
41
+ baseProvenance: number;
40
42
  };
41
43
 
42
44
  // #endregion Control
@@ -60,10 +62,18 @@ export type TabSelectedEvent = {
60
62
  /** Whether the selection triggered a special effect (e.g. scroll-to-top on repeated selection). */
61
63
  hasTriggeredSpecialEffect: boolean;
62
64
  /**
63
- * False in case the event is a result of JS-driven update. True otherwise, e.g. in case of user action (tap)
64
- * or implicit UIKit action (app resize, orientation change, etc.).
65
+ * @summary Origin (actor) that requested this tab transition.
66
+ *
67
+ * @description
68
+ * - `user` — direct native UI interaction (e.g. tab bar tap, iOS tab drag-and-drop).
69
+ * - `programmatic-js` — JS-initiated request delivered via the `navStateRequest` prop.
70
+ * - `programmatic-native` — request initiated from the native side by an actor
71
+ * integrating directly against the native container.
72
+ * - `implicit` — platform side effect not attributable to an explicit actor
73
+ * (e.g. UIKit reshuffling the selection during a horizontal size-class transition on iPad).
74
+ * Currently only emitted on iOS.
65
75
  */
66
- isNativeAction: boolean;
76
+ actionOrigin: 'user' | 'programmatic-js' | 'programmatic-native' | 'implicit';
67
77
  };
68
78
 
69
79
  /**
@@ -140,15 +150,15 @@ export interface TabsHostPropsBase {
140
150
  * the update might get accepted or rejected.
141
151
  *
142
152
  * @see {@link TabsHostPropsBase#rejectStaleNavStateUpdates}
143
- * @see {@link TabsHostNavState} for description of the type model & accepted values.
153
+ * @see {@link TabsHostNavStateRequest} for description of the type model & accepted values.
144
154
  */
145
- navState: TabsHostNavState;
155
+ navStateRequest: TabsHostNavStateRequest;
146
156
  /**
147
157
  * @summary If true, the native side will reject any navigation state updates coming from JS
148
158
  * if they are stale.
149
159
  *
150
160
  * @description A navigation state update is considered stale if it is based of an stale state
151
- * (@{link TabsHostNavState#provenance} indicates the base state).
161
+ * ({@link TabsHostNavStateRequest#baseProvenance} indicates the base state).
152
162
  * A state is stale, when at the time of executing update, there already had been accepted a newer state
153
163
  * of different origin.
154
164
  *
@@ -167,7 +177,7 @@ export interface TabsHostPropsBase {
167
177
  rejectStaleNavStateUpdates?: boolean | undefined;
168
178
 
169
179
  // General
170
- children?: ViewProps['children'] | undefined;
180
+ children: NonNullable<ViewProps['children']>;
171
181
  /**
172
182
  * @summary Hides the tab bar.
173
183
  *
@@ -2,7 +2,7 @@ import { TabsHost } from './host';
2
2
  import { TabsScreen } from './screen';
3
3
 
4
4
  export type {
5
- TabsHostNavState,
5
+ TabsHostNavStateRequest,
6
6
  TabSelectedEvent,
7
7
  TabSelectionRejectedEvent,
8
8
  TabSelectionRejectionReason,
@@ -22,6 +22,12 @@ export interface NativeProps extends ViewProps {
22
22
  backButtonTintColor?: ColorValue | undefined;
23
23
  backButtonDrawableIconResourceName?: string | undefined;
24
24
  backButtonImageIconResource?: ImageSource | undefined;
25
+
26
+ scrollFlagScroll?: CT.WithDefault<boolean, false>;
27
+ scrollFlagEnterAlways?: CT.WithDefault<boolean, false>;
28
+ scrollFlagEnterAlwaysCollapsed?: CT.WithDefault<boolean, false>;
29
+ scrollFlagExitUntilCollapsed?: CT.WithDefault<boolean, false>;
30
+ scrollFlagSnap?: CT.WithDefault<boolean, false>;
25
31
  }
26
32
 
27
33
  export default codegenNativeComponent<NativeProps>(
@@ -10,12 +10,12 @@ type TabSelectedEvent = {
10
10
  provenance: CT.Int32;
11
11
  isRepeated: boolean;
12
12
  hasTriggeredSpecialEffect: boolean;
13
- isNativeAction: boolean;
13
+ actionOrigin: 'user' | 'programmatic-js' | 'programmatic-native' | 'implicit';
14
14
  };
15
15
 
16
- type NavigationState = {
16
+ type NavigationStateRequest = {
17
17
  selectedScreenKey: string;
18
- provenance: CT.Int32;
18
+ baseProvenance: CT.Int32;
19
19
  };
20
20
 
21
21
  type TabSelectionRejectedEvent = Readonly<{
@@ -42,7 +42,7 @@ type TabsHostColorScheme = 'inherit' | 'light' | 'dark';
42
42
 
43
43
  export interface NativeProps extends ViewProps {
44
44
  // Control
45
- navState: NavigationState;
45
+ navStateRequest: NavigationStateRequest;
46
46
  rejectStaleNavStateUpdates?: CT.WithDefault<boolean, false>;
47
47
 
48
48
  // Events
@@ -10,12 +10,12 @@ type TabSelectedEvent = Readonly<{
10
10
  provenance: CT.Int32;
11
11
  isRepeated: boolean;
12
12
  hasTriggeredSpecialEffect: boolean;
13
- isNativeAction: boolean;
13
+ actionOrigin: 'user' | 'programmatic-js' | 'programmatic-native' | 'implicit';
14
14
  }>;
15
15
 
16
- type NavigationState = Readonly<{
16
+ type NavigationStateRequest = Readonly<{
17
17
  selectedScreenKey: string;
18
- provenance: CT.Int32;
18
+ baseProvenance: CT.Int32;
19
19
  }>;
20
20
 
21
21
  type TabSelectionRejectedEvent = Readonly<{
@@ -57,7 +57,7 @@ type TabBarControllerMode = 'automatic' | 'tabBar' | 'tabSidebar';
57
57
 
58
58
  export interface NativeProps extends ViewProps {
59
59
  // Control
60
- navState: NavigationState;
60
+ navStateRequest: NavigationStateRequest;
61
61
  rejectStaleNavStateUpdates?: CT.WithDefault<boolean, false>;
62
62
 
63
63
  // Events
package/src/flags.ts CHANGED
@@ -65,6 +65,7 @@ export const compatibilityFlags = {
65
65
  * * https://github.com/software-mansion/react-native-screens/pull/3863
66
66
  * * https://github.com/software-mansion/react-native-screens/pull/3875
67
67
  * * https://github.com/software-mansion/react-native-screens/pull/3895
68
+ * * https://github.com/software-mansion/react-native-screens/pull/3918
68
69
  */
69
70
  usesStableTabsApi: true,
70
71
  } as const;
@@ -1,7 +0,0 @@
1
- package com.swmansion.rnscreens.gamma.tabs.container
2
-
3
- internal sealed class TabsContainerOp
4
-
5
- internal data class TabSelectOp(
6
- val navState: TabsNavState,
7
- ) : TabsContainerOp()
@@ -1,43 +0,0 @@
1
- package com.swmansion.rnscreens.gamma.tabs.container
2
-
3
- import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionReason.REPEATED
4
- import com.swmansion.rnscreens.gamma.tabs.container.TabsNavStateUpdateRejectionReason.STALE
5
-
6
- /**
7
- * Describes navigation state of a tabs container.
8
- *
9
- * @property selectedKey Screen key of the currently selected tab.
10
- * @property provenance Monotonically increasing number describing the history (generation) of the state.
11
- * State with provenance `N + 1` is derived from state with provenance `N`.
12
- * This allows detecting stale updates.
13
- */
14
- data class TabsNavState(
15
- val selectedKey: String,
16
- val provenance: Int,
17
- ) {
18
- internal fun isEmpty(): Boolean = this === EMPTY
19
-
20
- internal fun isNotEmpty(): Boolean = !this.isEmpty()
21
-
22
- companion object {
23
- val EMPTY = TabsNavState("", Int.MIN_VALUE)
24
- }
25
- }
26
-
27
- /**
28
- * Reason why a navigation state update was rejected by the container.
29
- *
30
- * - [STALE] — the update's provenance indicates that it is based on a stale state.
31
- * - [REPEATED] — the requested tab is already selected.
32
- */
33
- enum class TabsNavStateUpdateRejectionReason {
34
- STALE,
35
- REPEATED,
36
- ;
37
-
38
- override fun toString(): String =
39
- when (this) {
40
- STALE -> "stale"
41
- REPEATED -> "repeated"
42
- }
43
- }