expo-router 6.0.0-beta.0 → 6.0.0-beta.10

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 (140) hide show
  1. package/assets/modal.module.css +15 -14
  2. package/assets/native-tabs.module.css +109 -0
  3. package/build/ExpoRoot.d.ts.map +1 -1
  4. package/build/ExpoRoot.js +0 -2
  5. package/build/ExpoRoot.js.map +1 -1
  6. package/build/fork/NavigationContainer.d.ts.map +1 -1
  7. package/build/fork/NavigationContainer.js +2 -0
  8. package/build/fork/NavigationContainer.js.map +1 -1
  9. package/build/fork/extractPathFromURL.d.ts.map +1 -1
  10. package/build/fork/extractPathFromURL.js +4 -0
  11. package/build/fork/extractPathFromURL.js.map +1 -1
  12. package/build/fork/getPathFromState.d.ts.map +1 -1
  13. package/build/fork/getPathFromState.js +2 -0
  14. package/build/fork/getPathFromState.js.map +1 -1
  15. package/build/global-state/routing.d.ts +6 -5
  16. package/build/global-state/routing.d.ts.map +1 -1
  17. package/build/global-state/routing.js +20 -14
  18. package/build/global-state/routing.js.map +1 -1
  19. package/build/head/ExpoHead.android.d.ts +1 -3
  20. package/build/imperative-api.d.ts +3 -1
  21. package/build/imperative-api.d.ts.map +1 -1
  22. package/build/imperative-api.js +4 -4
  23. package/build/imperative-api.js.map +1 -1
  24. package/build/layouts/DrawerClient.d.ts +2 -12
  25. package/build/layouts/DrawerClient.d.ts.map +1 -1
  26. package/build/layouts/StackClient.d.ts +14 -19
  27. package/build/layouts/StackClient.d.ts.map +1 -1
  28. package/build/layouts/StackClient.js +27 -25
  29. package/build/layouts/StackClient.js.map +1 -1
  30. package/build/layouts/TabsClient.d.ts +3 -18
  31. package/build/layouts/TabsClient.d.ts.map +1 -1
  32. package/build/layouts/withLayoutContext.d.ts +5 -1
  33. package/build/layouts/withLayoutContext.d.ts.map +1 -1
  34. package/build/layouts/withLayoutContext.js +19 -6
  35. package/build/layouts/withLayoutContext.js.map +1 -1
  36. package/build/link/ExpoLink.d.ts.map +1 -1
  37. package/build/link/ExpoLink.js +4 -1
  38. package/build/link/ExpoLink.js.map +1 -1
  39. package/build/link/LinkWithPreview.d.ts.map +1 -1
  40. package/build/link/LinkWithPreview.js +19 -24
  41. package/build/link/LinkWithPreview.js.map +1 -1
  42. package/build/link/elements.d.ts +2 -10
  43. package/build/link/elements.d.ts.map +1 -1
  44. package/build/link/elements.js +1 -1
  45. package/build/link/elements.js.map +1 -1
  46. package/build/link/preview/native.d.ts +0 -2
  47. package/build/link/preview/native.d.ts.map +1 -1
  48. package/build/link/preview/native.js +1 -11
  49. package/build/link/preview/native.js.map +1 -1
  50. package/build/link/preview/utils.d.ts.map +1 -1
  51. package/build/link/preview/utils.js +5 -2
  52. package/build/link/preview/utils.js.map +1 -1
  53. package/build/modal/web/ModalStackRouteDrawer.js +9 -10
  54. package/build/modal/web/ModalStackRouteDrawer.js.map +1 -1
  55. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts +1 -0
  56. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.d.ts.map +1 -1
  57. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js +61 -9
  58. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsNavigator.js.map +1 -1
  59. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.d.ts.map +1 -1
  60. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js +6 -27
  61. package/build/native-tabs/NativeBottomTabs/NativeBottomTabsRouter.js.map +1 -1
  62. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.d.ts +11 -3
  63. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.d.ts.map +1 -1
  64. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.js +154 -62
  65. package/build/native-tabs/NativeBottomTabs/NativeTabTrigger.js.map +1 -1
  66. package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts +3 -2
  67. package/build/native-tabs/NativeBottomTabs/NativeTabs.d.ts.map +1 -1
  68. package/build/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.d.ts +24 -0
  69. package/build/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.d.ts.map +1 -0
  70. package/build/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.js +28 -0
  71. package/build/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.js.map +1 -0
  72. package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts +1 -1
  73. package/build/native-tabs/NativeBottomTabs/NativeTabsView.d.ts.map +1 -1
  74. package/build/native-tabs/NativeBottomTabs/NativeTabsView.js +114 -38
  75. package/build/native-tabs/NativeBottomTabs/NativeTabsView.js.map +1 -1
  76. package/build/native-tabs/NativeBottomTabs/NativeTabsView.web.d.ts +4 -0
  77. package/build/native-tabs/NativeBottomTabs/NativeTabsView.web.d.ts.map +1 -0
  78. package/build/native-tabs/NativeBottomTabs/NativeTabsView.web.js +158 -0
  79. package/build/native-tabs/NativeBottomTabs/NativeTabsView.web.js.map +1 -0
  80. package/build/native-tabs/NativeBottomTabs/appearance.d.ts +20 -0
  81. package/build/native-tabs/NativeBottomTabs/appearance.d.ts.map +1 -0
  82. package/build/native-tabs/NativeBottomTabs/appearance.js +119 -0
  83. package/build/native-tabs/NativeBottomTabs/appearance.js.map +1 -0
  84. package/build/native-tabs/NativeBottomTabs/types.d.ts +312 -46
  85. package/build/native-tabs/NativeBottomTabs/types.d.ts.map +1 -1
  86. package/build/native-tabs/NativeBottomTabs/types.js +51 -0
  87. package/build/native-tabs/NativeBottomTabs/types.js.map +1 -1
  88. package/build/native-tabs/common/elements.d.ts +84 -21
  89. package/build/native-tabs/common/elements.d.ts.map +1 -1
  90. package/build/native-tabs/common/elements.js +23 -0
  91. package/build/native-tabs/common/elements.js.map +1 -1
  92. package/build/native-tabs/index.d.ts +2 -1
  93. package/build/native-tabs/index.d.ts.map +1 -1
  94. package/build/native-tabs/index.js +3 -1
  95. package/build/native-tabs/index.js.map +1 -1
  96. package/build/navigationParams.d.ts +9 -0
  97. package/build/navigationParams.d.ts.map +1 -0
  98. package/build/navigationParams.js +67 -0
  99. package/build/navigationParams.js.map +1 -0
  100. package/build/rsc/router/client.d.ts +1 -3
  101. package/build/rsc/router/client.d.ts.map +1 -1
  102. package/build/testing-library/index.d.ts +15 -4
  103. package/build/testing-library/index.d.ts.map +1 -1
  104. package/build/testing-library/index.js +31 -28
  105. package/build/testing-library/index.js.map +1 -1
  106. package/build/testing-library/mocks.js +0 -7
  107. package/build/testing-library/mocks.js.map +1 -1
  108. package/build/typed-routes/generate.d.ts +2 -1
  109. package/build/typed-routes/generate.d.ts.map +1 -1
  110. package/build/typed-routes/generate.js +3 -1
  111. package/build/typed-routes/generate.js.map +1 -1
  112. package/build/ui/Slot.d.ts +5 -1
  113. package/build/ui/Slot.d.ts.map +1 -1
  114. package/build/ui/Slot.js.map +1 -1
  115. package/build/ui/TabContext.d.ts +11 -21
  116. package/build/ui/TabContext.d.ts.map +1 -1
  117. package/build/ui/TabRouter.d.ts +7 -0
  118. package/build/ui/TabRouter.d.ts.map +1 -1
  119. package/build/ui/Tabs.d.ts +14 -23
  120. package/build/ui/Tabs.d.ts.map +1 -1
  121. package/build/ui/Tabs.js +1 -1
  122. package/build/ui/Tabs.js.map +1 -1
  123. package/build/ui/common.d.ts +2 -3
  124. package/build/ui/common.d.ts.map +1 -1
  125. package/build/ui/common.js +1 -3
  126. package/build/ui/common.js.map +1 -1
  127. package/build/useFocusEffect.js +1 -1
  128. package/build/useFocusEffect.js.map +1 -1
  129. package/build/useScreens.d.ts +1 -1
  130. package/build/useScreens.d.ts.map +1 -1
  131. package/build/useScreens.js +6 -4
  132. package/build/useScreens.js.map +1 -1
  133. package/ios/ExpoHead.podspec +2 -0
  134. package/ios/LinkPreview/LinkPreviewNativeModule.swift +7 -9
  135. package/ios/LinkPreview/LinkPreviewNativeView.swift +13 -28
  136. package/package.json +22 -24
  137. package/plugin/build/index.js +1 -1
  138. package/plugin/src/index.ts +1 -1
  139. package/ios/LinkPreview/LinkPreviewNativeTriggerView.swift +0 -9
  140. package/plugin/tsconfig.tsbuildinfo +0 -1
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  'use client';
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.NativeTabTrigger = NativeTabTrigger;
4
+ exports.NativeTabTrigger = void 0;
5
5
  exports.convertTabPropsToOptions = convertTabPropsToOptions;
6
+ exports.appendIconOptions = appendIconOptions;
6
7
  exports.isNativeTabTrigger = isNativeTabTrigger;
7
8
  const native_1 = require("@react-navigation/native");
8
9
  const react_1 = require("react");
10
+ const NativeTabsTriggerTabBar_1 = require("./NativeTabsTriggerTabBar");
9
11
  const utils_1 = require("./utils");
12
+ const PreviewRouteContext_1 = require("../../link/preview/PreviewRouteContext");
10
13
  const useSafeLayoutEffect_1 = require("../../views/useSafeLayoutEffect");
11
14
  const elements_1 = require("../common/elements");
12
15
  /**
@@ -45,96 +48,185 @@ const elements_1 = require("../common/elements");
45
48
  * </View>
46
49
  * );
47
50
  * }
51
+ * ```
48
52
  *
49
- * **Note:** You can use the alias `NativeTabs.Trigger` for this component.
53
+ * > **Note:** You can use the alias `NativeTabs.Trigger` for this component.
50
54
  */
51
- function NativeTabTrigger(props) {
55
+ function NativeTabTriggerImpl(props) {
52
56
  const route = (0, native_1.useRoute)();
53
57
  const navigation = (0, native_1.useNavigation)();
54
58
  const isFocused = navigation.isFocused();
59
+ const isInPreview = (0, PreviewRouteContext_1.useIsPreview)();
55
60
  (0, useSafeLayoutEffect_1.useSafeLayoutEffect)(() => {
56
61
  // This will cause the tab to update only when it is focused.
57
62
  // As long as all tabs are loaded at the start, we don't need this check.
58
63
  // It is here to ensure similar behavior to stack
59
- if (isFocused) {
64
+ if (isFocused && !isInPreview) {
60
65
  if (navigation.getState()?.type !== 'tab') {
61
66
  throw new Error(`Trigger component can only be used in the tab screen. Current route: ${route.name}`);
62
67
  }
63
- const options = convertTabPropsToOptions(props);
68
+ const options = convertTabPropsToOptions(props, true);
64
69
  navigation.setOptions(options);
65
70
  }
66
- }, [isFocused, props]);
71
+ }, [isFocused, props, isInPreview]);
67
72
  return null;
68
73
  }
69
- function convertTabPropsToOptions({ options, hidden, children, disablePopToTop, disableScrollToTop, }) {
70
- const initialOptions = {
71
- ...options,
72
- hidden: !!hidden,
73
- specialEffects: {
74
- repeatedTabSelection: {
75
- popToRoot: !disablePopToTop,
76
- scrollToTop: !disableScrollToTop,
74
+ exports.NativeTabTrigger = Object.assign(NativeTabTriggerImpl, {
75
+ TabBar: NativeTabsTriggerTabBar_1.NativeTabsTriggerTabBar,
76
+ });
77
+ function convertTabPropsToOptions({ options, hidden, children, role, disablePopToTop, disableScrollToTop }, isDynamic = false) {
78
+ const initialOptions = isDynamic
79
+ ? { ...options }
80
+ : {
81
+ ...options,
82
+ hidden: !!hidden,
83
+ specialEffects: {
84
+ repeatedTabSelection: {
85
+ popToRoot: !disablePopToTop,
86
+ scrollToTop: !disableScrollToTop,
87
+ },
77
88
  },
78
- },
79
- };
80
- const allowedChildren = (0, utils_1.filterAllowedChildrenElements)(children, [elements_1.Badge, elements_1.Label, elements_1.Icon]);
89
+ role: role ?? options?.role,
90
+ };
91
+ const allowedChildren = (0, utils_1.filterAllowedChildrenElements)(children, [
92
+ elements_1.Badge,
93
+ elements_1.Label,
94
+ elements_1.Icon,
95
+ NativeTabsTriggerTabBar_1.NativeTabsTriggerTabBar,
96
+ ]);
81
97
  return allowedChildren.reduce((acc, child) => {
82
98
  if ((0, utils_1.isChildOfType)(child, elements_1.Badge)) {
83
- if (child.props.children) {
84
- acc.badgeValue = String(child.props.children);
85
- }
86
- else if (!child.props.hidden) {
87
- // If no value is provided, we set it to a space to show the badge
88
- // Otherwise, the `react-native-screens` will interpret it as a hidden badge
89
- // https://github.com/software-mansion/react-native-screens/blob/b4358fd95dd0736fc54df6bb97f210dc89edf24c/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm#L172
90
- acc.badgeValue = ' ';
91
- }
99
+ appendBadgeOptions(acc, child.props);
92
100
  }
93
101
  else if ((0, utils_1.isChildOfType)(child, elements_1.Label)) {
94
- if (child.props.hidden) {
95
- acc.title = '';
96
- }
97
- else {
98
- acc.title = child.props.children;
99
- }
102
+ appendLabelOptions(acc, child.props);
100
103
  }
101
104
  else if ((0, utils_1.isChildOfType)(child, elements_1.Icon)) {
102
- if ('src' in child.props || 'selectedSrc' in child.props) {
103
- acc.icon = child.props.src
104
- ? {
105
- src: child.props.src,
106
- }
107
- : undefined;
108
- acc.selectedIcon = child.props.selectedSrc
109
- ? {
110
- src: child.props.selectedSrc,
111
- }
112
- : undefined;
113
- }
114
- else if ('sf' in child.props || 'selectedSf' in child.props) {
115
- if (process.env.EXPO_OS === 'ios') {
116
- acc.icon = child.props.sf
117
- ? {
118
- sf: child.props.sf,
119
- }
120
- : undefined;
121
- acc.selectedIcon = child.props.selectedSf
122
- ? {
123
- sf: child.props.selectedSf,
124
- }
125
- : undefined;
105
+ appendIconOptions(acc, child.props);
106
+ }
107
+ else if ((0, utils_1.isChildOfType)(child, NativeTabsTriggerTabBar_1.NativeTabsTriggerTabBar)) {
108
+ appendTabBarOptions(acc, child.props);
109
+ }
110
+ return acc;
111
+ }, { ...initialOptions });
112
+ }
113
+ function appendBadgeOptions(options, props) {
114
+ if (props.children) {
115
+ options.badgeValue = String(props.children);
116
+ options.selectedBadgeBackgroundColor = props.selectedBackgroundColor;
117
+ }
118
+ else if (!props.hidden) {
119
+ // If no value is provided, we set it to a space to show the badge
120
+ // Otherwise, the `react-native-screens` will interpret it as a hidden badge
121
+ // https://github.com/software-mansion/react-native-screens/blob/b4358fd95dd0736fc54df6bb97f210dc89edf24c/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm#L172
122
+ options.badgeValue = ' ';
123
+ }
124
+ }
125
+ function appendLabelOptions(options, props) {
126
+ if (props.hidden) {
127
+ options.title = '';
128
+ }
129
+ else {
130
+ options.title = props.children;
131
+ options.selectedLabelStyle = props.selectedStyle;
132
+ }
133
+ }
134
+ function appendIconOptions(options, props) {
135
+ if ('src' in props && props.src) {
136
+ const icon = convertIconSrcToIconOption(props);
137
+ options.icon = icon?.icon;
138
+ options.selectedIcon = icon?.selectedIcon;
139
+ }
140
+ else if ('sf' in props && process.env.EXPO_OS === 'ios') {
141
+ if (typeof props.sf === 'string') {
142
+ options.icon = props.sf
143
+ ? {
144
+ sf: props.sf,
145
+ }
146
+ : undefined;
147
+ options.selectedIcon = undefined;
148
+ }
149
+ else if (props.sf) {
150
+ options.icon = props.sf.default
151
+ ? {
152
+ sf: props.sf.default,
153
+ }
154
+ : undefined;
155
+ options.selectedIcon = props.sf.selected
156
+ ? {
157
+ sf: props.sf.selected,
126
158
  }
159
+ : undefined;
160
+ }
161
+ }
162
+ else if ('drawable' in props && process.env.EXPO_OS === 'android') {
163
+ options.icon = { drawable: props.drawable };
164
+ options.selectedIcon = undefined;
165
+ }
166
+ options.selectedIconColor = props.selectedColor;
167
+ }
168
+ function convertIconSrcToIconOption(icon) {
169
+ if (icon && icon.src) {
170
+ const { defaultIcon, selected } = typeof icon.src === 'object' && 'selected' in icon.src
171
+ ? { defaultIcon: icon.src.default, selected: icon.src.selected }
172
+ : { defaultIcon: icon.src };
173
+ const options = {};
174
+ options.icon = convertSrcOrComponentToSrc(defaultIcon);
175
+ options.selectedIcon = convertSrcOrComponentToSrc(selected);
176
+ return options;
177
+ }
178
+ return undefined;
179
+ }
180
+ function convertSrcOrComponentToSrc(src) {
181
+ if (src) {
182
+ if ((0, react_1.isValidElement)(src)) {
183
+ if (src.type === elements_1.VectorIcon) {
184
+ const props = src.props;
185
+ return { src: props.family.getImageSource(props.name, 24, 'white') };
127
186
  }
128
- if (process.env.EXPO_OS === 'android') {
129
- acc.icon = { drawable: child.props.drawable };
130
- acc.selectedIcon = undefined;
187
+ else {
188
+ console.warn('Only VectorIcon is supported as a React element in Icon.src');
131
189
  }
132
190
  }
133
- return acc;
134
- }, { ...initialOptions });
191
+ else {
192
+ return { src };
193
+ }
194
+ }
195
+ return undefined;
196
+ }
197
+ function appendTabBarOptions(options, props) {
198
+ const { backgroundColor, blurEffect, iconColor, disableTransparentOnScrollEdge, badgeBackgroundColor, badgeTextColor, indicatorColor, labelStyle, } = props;
199
+ if (backgroundColor) {
200
+ options.backgroundColor = backgroundColor;
201
+ }
202
+ // We need better native integration of this on Android
203
+ // Simulating from JS side creates ugly transitions
204
+ if (process.env.EXPO_OS !== 'android') {
205
+ if (blurEffect) {
206
+ options.blurEffect = blurEffect;
207
+ }
208
+ if (iconColor) {
209
+ options.iconColor = iconColor;
210
+ }
211
+ if (disableTransparentOnScrollEdge !== undefined) {
212
+ options.disableTransparentOnScrollEdge = disableTransparentOnScrollEdge;
213
+ }
214
+ if (badgeBackgroundColor) {
215
+ options.badgeBackgroundColor = badgeBackgroundColor;
216
+ }
217
+ if (badgeTextColor) {
218
+ options.badgeTextColor = badgeTextColor;
219
+ }
220
+ if (indicatorColor) {
221
+ options.indicatorColor = indicatorColor;
222
+ }
223
+ if (labelStyle) {
224
+ options.labelStyle = labelStyle;
225
+ }
226
+ }
135
227
  }
136
228
  function isNativeTabTrigger(child, contextKey) {
137
- if ((0, react_1.isValidElement)(child) && child && child.type === NativeTabTrigger) {
229
+ if ((0, react_1.isValidElement)(child) && child && child.type === exports.NativeTabTrigger) {
138
230
  if (typeof child.props === 'object' &&
139
231
  child.props &&
140
232
  'name' in child.props &&
@@ -1 +1 @@
1
- {"version":3,"file":"NativeTabTrigger.js","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabTrigger.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { isValidElement, type ReactElement, type ReactNode } from 'react';\n\nimport type { ExtendedNativeTabOptions, NativeTabTriggerProps } from './types';\nimport { filterAllowedChildrenElements, isChildOfType } from './utils';\nimport { useSafeLayoutEffect } from '../../views/useSafeLayoutEffect';\nimport { Icon, Badge, Label } from '../common/elements';\n\n/**\n * The component used to customize the native tab options both in the _layout file and from the tab screen.\n *\n * When used in the _layout file, you need to provide a `name` prop.\n * When used in the tab screen, the `name` prop takes no effect.\n *\n * @example\n * ```tsx\n * // In _layout file\n * import { NativeTabs } from 'expo-router/unstable-native-tabs';\n *\n * export default function Layout() {\n * return (\n * <NativeTabs>\n * <NativeTabs.Trigger name=\"home\" />\n * <NativeTabs.Trigger name=\"settings\" />\n * </NativeTabs>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // In a tab screen\n * import { NativeTabs } from 'expo-router/unstable-native-tabs';\n *\n * export default function HomeScreen() {\n * return (\n * <View>\n * <NativeTabs.Trigger>\n * <Label>Home</Label>\n * </NativeTabs.Trigger>\n * <Text>This is home screen!</Text>\n * </View>\n * );\n * }\n *\n * **Note:** You can use the alias `NativeTabs.Trigger` for this component.\n */\nexport function NativeTabTrigger(props: NativeTabTriggerProps) {\n const route = useRoute();\n const navigation = useNavigation();\n const isFocused = navigation.isFocused();\n\n useSafeLayoutEffect(() => {\n // This will cause the tab to update only when it is focused.\n // As long as all tabs are loaded at the start, we don't need this check.\n // It is here to ensure similar behavior to stack\n if (isFocused) {\n if (navigation.getState()?.type !== 'tab') {\n throw new Error(\n `Trigger component can only be used in the tab screen. Current route: ${route.name}`\n );\n }\n const options = convertTabPropsToOptions(props);\n navigation.setOptions(options);\n }\n }, [isFocused, props]);\n\n return null;\n}\n\nexport function convertTabPropsToOptions({\n options,\n hidden,\n children,\n disablePopToTop,\n disableScrollToTop,\n}: NativeTabTriggerProps) {\n const initialOptions: ExtendedNativeTabOptions = {\n ...options,\n hidden: !!hidden,\n specialEffects: {\n repeatedTabSelection: {\n popToRoot: !disablePopToTop,\n scrollToTop: !disableScrollToTop,\n },\n },\n };\n const allowedChildren = filterAllowedChildrenElements(children, [Badge, Label, Icon]);\n return allowedChildren.reduce<ExtendedNativeTabOptions>(\n (acc, child) => {\n if (isChildOfType(child, Badge)) {\n if (child.props.children) {\n acc.badgeValue = String(child.props.children);\n } else if (!child.props.hidden) {\n // If no value is provided, we set it to a space to show the badge\n // Otherwise, the `react-native-screens` will interpret it as a hidden badge\n // https://github.com/software-mansion/react-native-screens/blob/b4358fd95dd0736fc54df6bb97f210dc89edf24c/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm#L172\n acc.badgeValue = ' ';\n }\n } else if (isChildOfType(child, Label)) {\n if (child.props.hidden) {\n acc.title = '';\n } else {\n acc.title = child.props.children;\n }\n } else if (isChildOfType(child, Icon)) {\n if ('src' in child.props || 'selectedSrc' in child.props) {\n acc.icon = child.props.src\n ? {\n src: child.props.src,\n }\n : undefined;\n acc.selectedIcon = child.props.selectedSrc\n ? {\n src: child.props.selectedSrc,\n }\n : undefined;\n } else if ('sf' in child.props || 'selectedSf' in child.props) {\n if (process.env.EXPO_OS === 'ios') {\n acc.icon = child.props.sf\n ? {\n sf: child.props.sf,\n }\n : undefined;\n acc.selectedIcon = child.props.selectedSf\n ? {\n sf: child.props.selectedSf,\n }\n : undefined;\n }\n }\n if (process.env.EXPO_OS === 'android') {\n acc.icon = { drawable: child.props.drawable };\n acc.selectedIcon = undefined;\n }\n }\n return acc;\n },\n { ...initialOptions }\n );\n}\n\nexport function isNativeTabTrigger(\n child: ReactNode,\n contextKey?: string\n): child is ReactElement<NativeTabTriggerProps & { name: string }> {\n if (isValidElement(child) && child && child.type === NativeTabTrigger) {\n if (\n typeof child.props === 'object' &&\n child.props &&\n 'name' in child.props &&\n !child.props.name\n ) {\n throw new Error(\n `<Trigger /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must have a \\`name\\` prop when used as a child of a Layout Route.`\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (\n ['component', 'getComponent'].some(\n (key) => child.props && typeof child.props === 'object' && key in child.props\n )\n ) {\n throw new Error(\n `<Trigger /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must not have a \\`component\\` or \\`getComponent\\` prop when used as a child of a Layout Route`\n );\n }\n }\n\n return true;\n }\n\n return false;\n}\n"]}
1
+ {"version":3,"file":"NativeTabTrigger.js","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabTrigger.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;AAgGb,4DAsCC;AAuBD,8CA8BC;AAiFD,gDAgCC;AA1SD,qDAAmE;AACnE,iCAA0E;AAG1E,uEAAoE;AAOpE,mCAAuE;AACvE,gFAAsE;AACtE,yEAAsE;AACtE,iDAU4B;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,SAAS,oBAAoB,CAAC,KAA4B;IACxD,MAAM,KAAK,GAAG,IAAA,iBAAQ,GAAE,CAAC;IACzB,MAAM,UAAU,GAAG,IAAA,sBAAa,GAAE,CAAC;IACnC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,IAAA,kCAAY,GAAE,CAAC;IAEnC,IAAA,yCAAmB,EAAC,GAAG,EAAE;QACvB,6DAA6D;QAC7D,yEAAyE;QACzE,iDAAiD;QACjD,IAAI,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9B,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CACb,wEAAwE,KAAK,CAAC,IAAI,EAAE,CACrF,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,GAAG,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACtD,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;IAEpC,OAAO,IAAI,CAAC;AACd,CAAC;AAEY,QAAA,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;IAClE,MAAM,EAAE,iDAAuB;CAChC,CAAC,CAAC;AAEH,SAAgB,wBAAwB,CACtC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,kBAAkB,EAAyB,EAC/F,YAAqB,KAAK;IAE1B,MAAM,cAAc,GAA6B,SAAS;QACxD,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE;QAChB,CAAC,CAAC;YACE,GAAG,OAAO;YACV,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,cAAc,EAAE;gBACd,oBAAoB,EAAE;oBACpB,SAAS,EAAE,CAAC,eAAe;oBAC3B,WAAW,EAAE,CAAC,kBAAkB;iBACjC;aACF;YACD,IAAI,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI;SAC5B,CAAC;IACN,MAAM,eAAe,GAAG,IAAA,qCAA6B,EAAC,QAAQ,EAAE;QAC9D,gBAAK;QACL,gBAAK;QACL,eAAI;QACJ,iDAAuB;KACxB,CAAC,CAAC;IACH,OAAO,eAAe,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACb,IAAI,IAAA,qBAAa,EAAC,KAAK,EAAE,gBAAK,CAAC,EAAE,CAAC;YAChC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,IAAA,qBAAa,EAAC,KAAK,EAAE,gBAAK,CAAC,EAAE,CAAC;YACvC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,IAAA,qBAAa,EAAC,KAAK,EAAE,eAAI,CAAC,EAAE,CAAC;YACtC,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,IAAA,qBAAa,EAAC,KAAK,EAAE,iDAAuB,CAAC,EAAE,CAAC;YACzD,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,GAAG,cAAc,EAAE,CACtB,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAiC,EAAE,KAAiB;IAC9E,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5C,OAAO,CAAC,4BAA4B,GAAG,KAAK,CAAC,uBAAuB,CAAC;IACvE,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACzB,kEAAkE;QAClE,4EAA4E;QAC5E,kKAAkK;QAClK,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAiC,EAAE,KAAiB;IAC9E,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;IACrB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,OAAO,CAAC,kBAAkB,GAAG,KAAK,CAAC,aAAa,CAAC;IACnD,CAAC;AACH,CAAC;AAED,SAAgB,iBAAiB,CAAC,OAAiC,EAAE,KAAgB;IACnF,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QAC1B,OAAO,CAAC,YAAY,GAAG,IAAI,EAAE,YAAY,CAAC;IAC5C,CAAC;SAAM,IAAI,IAAI,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1D,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE;gBACrB,CAAC,CAAC;oBACE,EAAE,EAAE,KAAK,CAAC,EAAE;iBACb;gBACH,CAAC,CAAC,SAAS,CAAC;YACd,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;QACnC,CAAC;aAAM,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO;gBAC7B,CAAC,CAAC;oBACE,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO;iBACrB;gBACH,CAAC,CAAC,SAAS,CAAC;YACd,OAAO,CAAC,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ;gBACtC,CAAC,CAAC;oBACE,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ;iBACtB;gBACH,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;IACH,CAAC;SAAM,IAAI,UAAU,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACpE,OAAO,CAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC5C,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IACnC,CAAC;IACD,OAAO,CAAC,iBAAiB,GAAG,KAAK,CAAC,aAAa,CAAC;AAClD,CAAC;AAED,SAAS,0BAA0B,CACjC,IAAuC;IAEvC,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAC7B,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,UAAU,IAAI,IAAI,CAAC,GAAG;YACpD,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE;YAChE,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QAEhC,MAAM,OAAO,GAAoD,EAAE,CAAC;QACpE,OAAO,CAAC,IAAI,GAAG,0BAA0B,CAAC,WAAW,CAAC,CAAC;QACvD,OAAO,CAAC,YAAY,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;QAC5D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,0BAA0B,CAAC,GAAmD;IACrF,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,IAAA,sBAAc,EAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAU,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAgC,CAAC;gBACnD,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;YACvE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAC1B,OAAiC,EACjC,KAAmC;IAEnC,MAAM,EACJ,eAAe,EACf,UAAU,EACV,SAAS,EACT,8BAA8B,EAC9B,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,UAAU,GACX,GAAG,KAAK,CAAC;IAEV,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,CAAC,eAAe,GAAG,eAAe,CAAC;IAC5C,CAAC;IACD,uDAAuD;IACvD,mDAAmD;IACnD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACtC,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;QAClC,CAAC;QACD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAChC,CAAC;QACD,IAAI,8BAA8B,KAAK,SAAS,EAAE,CAAC;YACjD,OAAO,CAAC,8BAA8B,GAAG,8BAA8B,CAAC;QAC1E,CAAC;QACD,IAAI,oBAAoB,EAAE,CAAC;YACzB,OAAO,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QACtD,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC;QAC1C,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC;QAC1C,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;QAClC,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAChC,KAAgB,EAChB,UAAmB;IAEnB,IAAI,IAAA,sBAAc,EAAC,KAAK,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAgB,EAAE,CAAC;QACtE,IACE,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAC/B,KAAK,CAAC,KAAK;YACX,MAAM,IAAI,KAAK,CAAC,KAAK;YACrB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EACjB,CAAC;YACD,MAAM,IAAI,KAAK,CACb,uDAAuD,UAAU,8EAA8E,CAChJ,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC1C,IACE,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,IAAI,CAChC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,IAAI,KAAK,CAAC,KAAK,CAC9E,EACD,CAAC;gBACD,MAAM,IAAI,KAAK,CACb,uDAAuD,UAAU,0GAA0G,CAC5K,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["'use client';\n\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { isValidElement, type ReactElement, type ReactNode } from 'react';\nimport type { ImageSourcePropType } from 'react-native';\n\nimport { NativeTabsTriggerTabBar } from './NativeTabsTriggerTabBar';\nimport type {\n ExtendedNativeTabOptions,\n NativeTabOptions,\n NativeTabsTriggerTabBarProps,\n NativeTabTriggerProps,\n} from './types';\nimport { filterAllowedChildrenElements, isChildOfType } from './utils';\nimport { useIsPreview } from '../../link/preview/PreviewRouteContext';\nimport { useSafeLayoutEffect } from '../../views/useSafeLayoutEffect';\nimport {\n Icon,\n Badge,\n Label,\n type LabelProps,\n type IconProps,\n type BadgeProps,\n type SourceIconCombination,\n VectorIcon,\n type VectorIconProps,\n} from '../common/elements';\n\n/**\n * The component used to customize the native tab options both in the _layout file and from the tab screen.\n *\n * When used in the _layout file, you need to provide a `name` prop.\n * When used in the tab screen, the `name` prop takes no effect.\n *\n * @example\n * ```tsx\n * // In _layout file\n * import { NativeTabs } from 'expo-router/unstable-native-tabs';\n *\n * export default function Layout() {\n * return (\n * <NativeTabs>\n * <NativeTabs.Trigger name=\"home\" />\n * <NativeTabs.Trigger name=\"settings\" />\n * </NativeTabs>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // In a tab screen\n * import { NativeTabs } from 'expo-router/unstable-native-tabs';\n *\n * export default function HomeScreen() {\n * return (\n * <View>\n * <NativeTabs.Trigger>\n * <Label>Home</Label>\n * </NativeTabs.Trigger>\n * <Text>This is home screen!</Text>\n * </View>\n * );\n * }\n * ```\n *\n * > **Note:** You can use the alias `NativeTabs.Trigger` for this component.\n */\nfunction NativeTabTriggerImpl(props: NativeTabTriggerProps) {\n const route = useRoute();\n const navigation = useNavigation();\n const isFocused = navigation.isFocused();\n const isInPreview = useIsPreview();\n\n useSafeLayoutEffect(() => {\n // This will cause the tab to update only when it is focused.\n // As long as all tabs are loaded at the start, we don't need this check.\n // It is here to ensure similar behavior to stack\n if (isFocused && !isInPreview) {\n if (navigation.getState()?.type !== 'tab') {\n throw new Error(\n `Trigger component can only be used in the tab screen. Current route: ${route.name}`\n );\n }\n const options = convertTabPropsToOptions(props, true);\n navigation.setOptions(options);\n }\n }, [isFocused, props, isInPreview]);\n\n return null;\n}\n\nexport const NativeTabTrigger = Object.assign(NativeTabTriggerImpl, {\n TabBar: NativeTabsTriggerTabBar,\n});\n\nexport function convertTabPropsToOptions(\n { options, hidden, children, role, disablePopToTop, disableScrollToTop }: NativeTabTriggerProps,\n isDynamic: boolean = false\n) {\n const initialOptions: ExtendedNativeTabOptions = isDynamic\n ? { ...options }\n : {\n ...options,\n hidden: !!hidden,\n specialEffects: {\n repeatedTabSelection: {\n popToRoot: !disablePopToTop,\n scrollToTop: !disableScrollToTop,\n },\n },\n role: role ?? options?.role,\n };\n const allowedChildren = filterAllowedChildrenElements(children, [\n Badge,\n Label,\n Icon,\n NativeTabsTriggerTabBar,\n ]);\n return allowedChildren.reduce<ExtendedNativeTabOptions>(\n (acc, child) => {\n if (isChildOfType(child, Badge)) {\n appendBadgeOptions(acc, child.props);\n } else if (isChildOfType(child, Label)) {\n appendLabelOptions(acc, child.props);\n } else if (isChildOfType(child, Icon)) {\n appendIconOptions(acc, child.props);\n } else if (isChildOfType(child, NativeTabsTriggerTabBar)) {\n appendTabBarOptions(acc, child.props);\n }\n return acc;\n },\n { ...initialOptions }\n );\n}\n\nfunction appendBadgeOptions(options: ExtendedNativeTabOptions, props: BadgeProps) {\n if (props.children) {\n options.badgeValue = String(props.children);\n options.selectedBadgeBackgroundColor = props.selectedBackgroundColor;\n } else if (!props.hidden) {\n // If no value is provided, we set it to a space to show the badge\n // Otherwise, the `react-native-screens` will interpret it as a hidden badge\n // https://github.com/software-mansion/react-native-screens/blob/b4358fd95dd0736fc54df6bb97f210dc89edf24c/ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm#L172\n options.badgeValue = ' ';\n }\n}\n\nfunction appendLabelOptions(options: ExtendedNativeTabOptions, props: LabelProps) {\n if (props.hidden) {\n options.title = '';\n } else {\n options.title = props.children;\n options.selectedLabelStyle = props.selectedStyle;\n }\n}\n\nexport function appendIconOptions(options: ExtendedNativeTabOptions, props: IconProps) {\n if ('src' in props && props.src) {\n const icon = convertIconSrcToIconOption(props);\n options.icon = icon?.icon;\n options.selectedIcon = icon?.selectedIcon;\n } else if ('sf' in props && process.env.EXPO_OS === 'ios') {\n if (typeof props.sf === 'string') {\n options.icon = props.sf\n ? {\n sf: props.sf,\n }\n : undefined;\n options.selectedIcon = undefined;\n } else if (props.sf) {\n options.icon = props.sf.default\n ? {\n sf: props.sf.default,\n }\n : undefined;\n options.selectedIcon = props.sf.selected\n ? {\n sf: props.sf.selected,\n }\n : undefined;\n }\n } else if ('drawable' in props && process.env.EXPO_OS === 'android') {\n options.icon = { drawable: props.drawable };\n options.selectedIcon = undefined;\n }\n options.selectedIconColor = props.selectedColor;\n}\n\nfunction convertIconSrcToIconOption(\n icon: SourceIconCombination | undefined\n): Pick<NativeTabOptions, 'icon' | 'selectedIcon'> | undefined {\n if (icon && icon.src) {\n const { defaultIcon, selected } =\n typeof icon.src === 'object' && 'selected' in icon.src\n ? { defaultIcon: icon.src.default, selected: icon.src.selected }\n : { defaultIcon: icon.src };\n\n const options: Pick<NativeTabOptions, 'icon' | 'selectedIcon'> = {};\n options.icon = convertSrcOrComponentToSrc(defaultIcon);\n options.selectedIcon = convertSrcOrComponentToSrc(selected);\n return options;\n }\n\n return undefined;\n}\n\nfunction convertSrcOrComponentToSrc(src: ImageSourcePropType | ReactElement | undefined) {\n if (src) {\n if (isValidElement(src)) {\n if (src.type === VectorIcon) {\n const props = src.props as VectorIconProps<string>;\n return { src: props.family.getImageSource(props.name, 24, 'white') };\n } else {\n console.warn('Only VectorIcon is supported as a React element in Icon.src');\n }\n } else {\n return { src };\n }\n }\n return undefined;\n}\n\nfunction appendTabBarOptions(\n options: ExtendedNativeTabOptions,\n props: NativeTabsTriggerTabBarProps\n) {\n const {\n backgroundColor,\n blurEffect,\n iconColor,\n disableTransparentOnScrollEdge,\n badgeBackgroundColor,\n badgeTextColor,\n indicatorColor,\n labelStyle,\n } = props;\n\n if (backgroundColor) {\n options.backgroundColor = backgroundColor;\n }\n // We need better native integration of this on Android\n // Simulating from JS side creates ugly transitions\n if (process.env.EXPO_OS !== 'android') {\n if (blurEffect) {\n options.blurEffect = blurEffect;\n }\n if (iconColor) {\n options.iconColor = iconColor;\n }\n if (disableTransparentOnScrollEdge !== undefined) {\n options.disableTransparentOnScrollEdge = disableTransparentOnScrollEdge;\n }\n if (badgeBackgroundColor) {\n options.badgeBackgroundColor = badgeBackgroundColor;\n }\n if (badgeTextColor) {\n options.badgeTextColor = badgeTextColor;\n }\n if (indicatorColor) {\n options.indicatorColor = indicatorColor;\n }\n if (labelStyle) {\n options.labelStyle = labelStyle;\n }\n }\n}\n\nexport function isNativeTabTrigger(\n child: ReactNode,\n contextKey?: string\n): child is ReactElement<NativeTabTriggerProps & { name: string }> {\n if (isValidElement(child) && child && child.type === NativeTabTrigger) {\n if (\n typeof child.props === 'object' &&\n child.props &&\n 'name' in child.props &&\n !child.props.name\n ) {\n throw new Error(\n `<Trigger /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must have a \\`name\\` prop when used as a child of a Layout Route.`\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (\n ['component', 'getComponent'].some(\n (key) => child.props && typeof child.props === 'object' && key in child.props\n )\n ) {\n throw new Error(\n `<Trigger /> component in \\`default export\\` at \\`app${contextKey}/_layout\\` must not have a \\`component\\` or \\`getComponent\\` prop when used as a child of a Layout Route`\n );\n }\n }\n\n return true;\n }\n\n return false;\n}\n"]}
@@ -1,4 +1,3 @@
1
- import { NativeTabTrigger } from './NativeTabTrigger';
2
1
  import type { NativeTabsProps } from './types';
3
2
  /**
4
3
  * The component used to create native tabs layout.
@@ -19,6 +18,8 @@ import type { NativeTabsProps } from './types';
19
18
  * ```
20
19
  */
21
20
  export declare const NativeTabs: ((props: NativeTabsProps) => import("react").JSX.Element) & {
22
- Trigger: typeof NativeTabTrigger;
21
+ Trigger: ((props: import("./types").NativeTabTriggerProps) => null) & {
22
+ TabBar: typeof import("./NativeTabsTriggerTabBar").NativeTabsTriggerTabBar;
23
+ };
23
24
  };
24
25
  //# sourceMappingURL=NativeTabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeTabs.d.ts","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabs.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,WACb,eAAe;;CAIxB,CAAC"}
1
+ {"version":3,"file":"NativeTabs.d.ts","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,WACb,eAAe;;;;CAIxB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { NativeTabsTriggerTabBarProps } from './types';
2
+ /**
3
+ * The component used to customize the style of the tab bar, when given trigger is selected.
4
+ *
5
+ * Prefer this to global changes of tab bar styles, directly in the page.
6
+ *
7
+ * > **Note:** You can use the alias `NativeTabs.Trigger.TabBar` for this component.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <NativeTabs
12
+ * backgroundColor="black"
13
+ * >
14
+ * <NativeTabs.Trigger name="page">
15
+ * <NativeTabs.Trigger.TabBar
16
+ * backgroundColor="white"
17
+ * />
18
+ * <Label>Page</Label>
19
+ * </NativeTabs.Trigger>
20
+ * </NativeTabs>
21
+ *
22
+ */
23
+ export declare function NativeTabsTriggerTabBar(props: NativeTabsTriggerTabBarProps): React.ReactNode;
24
+ //# sourceMappingURL=NativeTabsTriggerTabBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeTabsTriggerTabBar.d.ts","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,4BAA4B,GAAG,KAAK,CAAC,SAAS,CAE5F"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NativeTabsTriggerTabBar = NativeTabsTriggerTabBar;
4
+ /**
5
+ * The component used to customize the style of the tab bar, when given trigger is selected.
6
+ *
7
+ * Prefer this to global changes of tab bar styles, directly in the page.
8
+ *
9
+ * > **Note:** You can use the alias `NativeTabs.Trigger.TabBar` for this component.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <NativeTabs
14
+ * backgroundColor="black"
15
+ * >
16
+ * <NativeTabs.Trigger name="page">
17
+ * <NativeTabs.Trigger.TabBar
18
+ * backgroundColor="white"
19
+ * />
20
+ * <Label>Page</Label>
21
+ * </NativeTabs.Trigger>
22
+ * </NativeTabs>
23
+ *
24
+ */
25
+ function NativeTabsTriggerTabBar(props) {
26
+ return null;
27
+ }
28
+ //# sourceMappingURL=NativeTabsTriggerTabBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeTabsTriggerTabBar.js","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabsTriggerTabBar.tsx"],"names":[],"mappings":";;AAuBA,0DAEC;AAvBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,uBAAuB,CAAC,KAAmC;IACzE,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { NativeTabsTriggerTabBarProps } from './types';\n\n/**\n * The component used to customize the style of the tab bar, when given trigger is selected.\n *\n * Prefer this to global changes of tab bar styles, directly in the page.\n *\n * > **Note:** You can use the alias `NativeTabs.Trigger.TabBar` for this component.\n *\n * @example\n * ```tsx\n * <NativeTabs\n * backgroundColor=\"black\"\n * >\n * <NativeTabs.Trigger name=\"page\">\n * <NativeTabs.Trigger.TabBar\n * backgroundColor=\"white\"\n * />\n * <Label>Page</Label>\n * </NativeTabs.Trigger>\n * </NativeTabs>\n *\n */\nexport function NativeTabsTriggerTabBar(props: NativeTabsTriggerTabBarProps): React.ReactNode {\n return null;\n}\n"]}
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import type { NativeTabsViewProps } from './types';
2
+ import { type NativeTabsViewProps } from './types';
3
3
  export declare function NativeTabsView(props: NativeTabsViewProps): React.JSX.Element;
4
4
  //# sourceMappingURL=NativeTabsView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeTabsView.d.ts","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabsView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAStC,OAAO,KAAK,EAAoB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAYrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,qBAkGxD"}
1
+ {"version":3,"file":"NativeTabsView.d.ts","sourceRoot":"","sources":["../../../src/native-tabs/NativeBottomTabs/NativeTabsView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAkB9E,OAAO,EAKL,KAAK,mBAAmB,EACzB,MAAM,SAAS,CAAC;AASjB,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,qBA4IxD"}
@@ -36,57 +36,73 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.NativeTabsView = NativeTabsView;
37
37
  const react_1 = __importStar(require("react"));
38
38
  const react_native_screens_1 = require("react-native-screens");
39
+ const appearance_1 = require("./appearance");
40
+ const types_1 = require("./types");
39
41
  const utils_1 = require("./utils");
40
- const linking_1 = require("../../link/linking");
41
42
  // We let native tabs to control the changes. This requires freeze to be disabled for tab bar.
42
43
  // Otherwise user may see glitches when switching between tabs.
43
44
  react_native_screens_1.featureFlags.experiment.controlledBottomTabs = false;
44
- // TODO: ENG-16896: Enable freeze globally and disable only for NativeTabsView
45
- (0, react_native_screens_1.enableFreeze)(false);
46
- // TODO: Add support for dynamic params inside a route
45
+ const supportedBlurEffectsSet = new Set(types_1.SUPPORTED_BLUR_EFFECTS);
47
46
  function NativeTabsView(props) {
48
- const { builder, style, minimizeBehavior, disableIndicator } = props;
47
+ const { builder, minimizeBehavior, disableIndicator, focusedIndex } = props;
49
48
  const { state, descriptors, navigation } = builder;
50
49
  const { routes } = state;
51
- let focusedIndex = state.index;
52
- const isAnyRouteFocused = routes[focusedIndex].key &&
53
- descriptors[routes[focusedIndex].key] &&
54
- (0, utils_1.shouldTabBeVisible)(descriptors[routes[focusedIndex].key].options);
55
- if (!isAnyRouteFocused) {
56
- if (process.env.NODE_ENV !== 'production') {
57
- throw new Error(`The focused tab in NativeTabsView cannot be displayed. Make sure path is correct and the route is not hidden. Path: "${(0, linking_1.getPathFromState)(state)}"`);
58
- }
59
- // Set focusedIndex to the first visible tab
60
- focusedIndex = routes.findIndex((route) => (0, utils_1.shouldTabBeVisible)(descriptors[route.key].options));
50
+ let blurEffect = props.blurEffect;
51
+ if (blurEffect && !supportedBlurEffectsSet.has(blurEffect)) {
52
+ console.warn(`Unsupported blurEffect: ${blurEffect}. Supported values are: ${types_1.SUPPORTED_BLUR_EFFECTS.map((effect) => `"${effect}"`).join(', ')}`);
53
+ blurEffect = undefined;
61
54
  }
62
- // This is flag that is set to true, when the transition is executed by native tab change
63
- // In this case we don't need to change the isFocused of the screens, because the transition will happen on native side
64
- const isDuringNativeTransition = (0, react_1.useRef)(false);
65
- // This is the last index that was not part of a native transition, e.g navigation from link
66
- const lastNotNativeTransitionIndex = (0, react_1.useRef)(focusedIndex);
67
- // If the flag was set in the onNativeFocusChange handler, it will be still true here
68
- // It is set to false, later in this function
69
- // Thus if it is false, we know that the transition was not triggered by a native tab change
70
- // and we need to reset the lastNotNativeTransitionIndex
71
- if (!isDuringNativeTransition.current) {
72
- lastNotNativeTransitionIndex.current = focusedIndex;
55
+ const deferredFocusedIndex = (0, react_1.useDeferredValue)(focusedIndex);
56
+ let standardAppearance = (0, appearance_1.convertStyleToAppearance)({
57
+ ...props.labelStyle,
58
+ iconColor: props.iconColor,
59
+ blurEffect,
60
+ backgroundColor: props.backgroundColor,
61
+ badgeBackgroundColor: props.badgeBackgroundColor,
62
+ });
63
+ if (props.tintColor) {
64
+ standardAppearance = (0, appearance_1.appendSelectedStyleToAppearance)({ iconColor: props.tintColor, color: props.tintColor }, standardAppearance);
73
65
  }
66
+ const scrollEdgeAppearance = (0, appearance_1.convertStyleToAppearance)({
67
+ ...props.labelStyle,
68
+ iconColor: props.iconColor,
69
+ blurEffect,
70
+ backgroundColor: props.backgroundColor,
71
+ badgeBackgroundColor: props.badgeBackgroundColor,
72
+ });
73
+ const appearances = routes.map((route) => ({
74
+ standardAppearance: (0, appearance_1.createStandardAppearanceFromOptions)(descriptors[route.key].options, standardAppearance),
75
+ scrollEdgeAppearance: (0, appearance_1.createScrollEdgeAppearanceFromOptions)(descriptors[route.key].options, scrollEdgeAppearance),
76
+ }));
77
+ const options = routes.map((route) => descriptors[route.key].options);
74
78
  const children = routes
75
79
  .map((route, index) => ({ route, index }))
76
80
  .filter(({ route: { key } }) => (0, utils_1.shouldTabBeVisible)(descriptors[key].options))
77
81
  .map(({ route, index }) => {
78
82
  const descriptor = descriptors[route.key];
79
- // In case of native transition we want to keep the last focused index
80
- // Otherwise the lastNotNativeTransitionIndex is set to focusedIndex in the if above this statement
81
- const isFocused = index === lastNotNativeTransitionIndex.current;
82
- const title = descriptor.options.title ?? route.name;
83
- return (<react_native_screens_1.BottomTabsScreen key={route.key} {...descriptor.options} iconResourceName={descriptor.options.icon?.drawable} icon={convertOptionsIconToPropsIcon(descriptor.options.icon)} selectedIcon={convertOptionsIconToPropsIcon(descriptor.options.selectedIcon)} title={title} tabKey={route.key} isFocused={isFocused}>
84
- {descriptor.render()}
85
- </react_native_screens_1.BottomTabsScreen>);
83
+ const isFocused = index === deferredFocusedIndex;
84
+ return (<Screen key={route.key} routeKey={route.key} name={route.name} descriptor={descriptor} isFocused={isFocused} standardAppearance={appearances[index].standardAppearance} scrollEdgeAppearance={appearances[index].scrollEdgeAppearance} badgeTextColor={props.badgeTextColor}/>);
86
85
  });
87
- // The native render is over, we can reset the flag
88
- isDuringNativeTransition.current = false;
89
- return (<react_native_screens_1.BottomTabs tabBarItemTitleFontColor={style?.color} tabBarItemTitleFontFamily={style?.fontFamily} tabBarItemTitleFontSize={style?.fontSize} tabBarItemTitleFontWeight={style?.fontWeight} tabBarItemTitleFontStyle={style?.fontStyle} tabBarBackgroundColor={style?.backgroundColor} tabBarBlurEffect={style?.blurEffect} tabBarTintColor={style?.tintColor} tabBarItemBadgeBackgroundColor={style?.badgeBackgroundColor} tabBarItemRippleColor={style?.rippleColor} tabBarItemLabelVisibilityMode={style?.labelVisibilityMode} tabBarItemIconColor={style?.iconColor} tabBarItemIconColorActive={style?.['&:active']?.iconColor ?? style?.tintColor} tabBarItemTitleFontColorActive={style?.['&:active']?.color ?? style?.tintColor} tabBarItemTitleFontSizeActive={style?.['&:active']?.fontSize} tabBarItemActiveIndicatorColor={style?.['&:active']?.indicatorColor} tabBarItemActiveIndicatorEnabled={!disableIndicator} tabBarMinimizeBehavior={minimizeBehavior} onNativeFocusChange={({ nativeEvent: { tabKey } }) => {
86
+ return (<BottomTabsWrapper
87
+ // #region android props
88
+ tabBarItemTitleFontColor={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
89
+ ?.tabBarItemTitleFontColor} tabBarItemTitleFontFamily={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
90
+ ?.tabBarItemTitleFontFamily} tabBarItemTitleFontSize={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
91
+ ?.tabBarItemTitleFontSize} tabBarItemTitleFontSizeActive={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
92
+ ?.tabBarItemTitleFontSize} tabBarItemTitleFontWeight={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
93
+ ?.tabBarItemTitleFontWeight} tabBarItemTitleFontStyle={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal
94
+ ?.tabBarItemTitleFontStyle} tabBarItemIconColor={appearances[deferredFocusedIndex].standardAppearance.stacked?.normal?.tabBarItemIconColor} tabBarBackgroundColor={appearances[deferredFocusedIndex].standardAppearance.tabBarBackgroundColor ??
95
+ props.backgroundColor ??
96
+ undefined} tabBarItemRippleColor={props.rippleColor} tabBarItemLabelVisibilityMode={props.labelVisibilityMode} tabBarItemIconColorActive={appearances[deferredFocusedIndex].standardAppearance?.stacked?.selected
97
+ ?.tabBarItemIconColor ?? props?.tintColor} tabBarItemTitleFontColorActive={appearances[deferredFocusedIndex].standardAppearance?.stacked?.selected
98
+ ?.tabBarItemTitleFontColor ?? props?.tintColor}
99
+ // tabBarItemTitleFontSizeActive={activeStyle?.fontSize}
100
+ tabBarItemActiveIndicatorColor={options[deferredFocusedIndex]?.indicatorColor ?? props?.indicatorColor} tabBarItemActiveIndicatorEnabled={!disableIndicator}
101
+ // #endregion
102
+ // #region iOS props
103
+ tabBarTintColor={props?.tintColor} tabBarMinimizeBehavior={minimizeBehavior}
104
+ // #endregion
105
+ onNativeFocusChange={({ nativeEvent: { tabKey } }) => {
90
106
  const descriptor = descriptors[tabKey];
91
107
  const route = descriptor.route;
92
108
  navigation.dispatch({
@@ -96,10 +112,43 @@ function NativeTabsView(props) {
96
112
  name: route.name,
97
113
  },
98
114
  });
99
- isDuringNativeTransition.current = true;
100
115
  }}>
101
116
  {children}
102
- </react_native_screens_1.BottomTabs>);
117
+ </BottomTabsWrapper>);
118
+ }
119
+ function Screen(props) {
120
+ const { routeKey, name, descriptor, isFocused, standardAppearance, scrollEdgeAppearance, badgeTextColor, } = props;
121
+ const role = descriptor.options.role;
122
+ // To align with apple documentation and prevent untested cases,
123
+ // title and icon cannot be changed when role is defined
124
+ const shouldResetTitleAndIcon = !!role && process.env.EXPO_OS === 'ios';
125
+ const title = descriptor.options.title ?? name;
126
+ const icon = useAwaitedScreensIcon(descriptor.options.icon);
127
+ const selectedIcon = useAwaitedScreensIcon(descriptor.options.selectedIcon);
128
+ return (<react_native_screens_1.BottomTabsScreen {...descriptor.options} tabBarItemBadgeBackgroundColor={standardAppearance.stacked?.normal?.tabBarItemBadgeBackgroundColor} tabBarItemBadgeTextColor={badgeTextColor} standardAppearance={standardAppearance} scrollEdgeAppearance={scrollEdgeAppearance} iconResourceName={getAndroidIconResourceName(icon)} iconResource={getAndroidIconResource(icon)} icon={shouldResetTitleAndIcon ? undefined : convertOptionsIconToPropsIcon(icon)} selectedIcon={shouldResetTitleAndIcon ? undefined : convertOptionsIconToPropsIcon(selectedIcon)} title={shouldResetTitleAndIcon ? undefined : title} freezeContents={false} tabKey={routeKey} systemItem={descriptor.options.role} isFocused={isFocused}>
129
+ {descriptor.render()}
130
+ </react_native_screens_1.BottomTabsScreen>);
131
+ }
132
+ function useAwaitedScreensIcon(icon) {
133
+ const src = icon && typeof icon === 'object' && 'src' in icon ? icon.src : undefined;
134
+ const [awaitedIcon, setAwaitedIcon] = (0, react_1.useState)(undefined);
135
+ (0, react_1.useEffect)(() => {
136
+ const loadIcon = async () => {
137
+ if (src && src instanceof Promise) {
138
+ const currentAwaitedIcon = { src: await src };
139
+ setAwaitedIcon(currentAwaitedIcon);
140
+ }
141
+ };
142
+ loadIcon();
143
+ // Checking `src` rather then icon here, to avoid unnecessary re-renders
144
+ // The icon object can be recreated, while src should stay the same
145
+ // In this case as we control `VectorIcon`, it will only change if `family` or `name` props change
146
+ // So we should be safe with promise resolving
147
+ }, [src]);
148
+ return (0, react_1.useMemo)(() => (isAwaitedIcon(icon) ? icon : awaitedIcon), [awaitedIcon, icon]);
149
+ }
150
+ function isAwaitedIcon(icon) {
151
+ return !icon || !('src' in icon && icon.src instanceof Promise);
103
152
  }
104
153
  function convertOptionsIconToPropsIcon(icon) {
105
154
  if (!icon) {
@@ -113,4 +162,31 @@ function convertOptionsIconToPropsIcon(icon) {
113
162
  }
114
163
  return undefined;
115
164
  }
165
+ function getAndroidIconResource(icon) {
166
+ if (icon && 'src' in icon && icon.src) {
167
+ return icon.src;
168
+ }
169
+ return undefined;
170
+ }
171
+ function getAndroidIconResourceName(icon) {
172
+ if (icon && 'drawable' in icon && icon.drawable) {
173
+ return icon.drawable;
174
+ }
175
+ return undefined;
176
+ }
177
+ const supportedTabBarMinimizeBehaviorsSet = new Set(types_1.SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS);
178
+ const supportedTabBarItemLabelVisibilityModesSet = new Set(types_1.SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES);
179
+ function BottomTabsWrapper(props) {
180
+ let { tabBarMinimizeBehavior, tabBarItemLabelVisibilityMode, ...rest } = props;
181
+ if (tabBarMinimizeBehavior && !supportedTabBarMinimizeBehaviorsSet.has(tabBarMinimizeBehavior)) {
182
+ console.warn(`Unsupported minimizeBehavior: ${tabBarMinimizeBehavior}. Supported values are: ${types_1.SUPPORTED_TAB_BAR_MINIMIZE_BEHAVIORS.map((behavior) => `"${behavior}"`).join(', ')}`);
183
+ tabBarMinimizeBehavior = undefined;
184
+ }
185
+ if (tabBarItemLabelVisibilityMode &&
186
+ !supportedTabBarItemLabelVisibilityModesSet.has(tabBarItemLabelVisibilityMode)) {
187
+ console.warn(`Unsupported labelVisibilityMode: ${tabBarItemLabelVisibilityMode}. Supported values are: ${types_1.SUPPORTED_TAB_BAR_ITEM_LABEL_VISIBILITY_MODES.map((mode) => `"${mode}"`).join(', ')}`);
188
+ tabBarItemLabelVisibilityMode = undefined;
189
+ }
190
+ return (<react_native_screens_1.BottomTabs tabBarItemLabelVisibilityMode={tabBarItemLabelVisibilityMode} tabBarMinimizeBehavior={tabBarMinimizeBehavior} {...rest}/>);
191
+ }
116
192
  //# sourceMappingURL=NativeTabsView.js.map