@sigmela/router 0.3.7 → 0.4.0

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 (118) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +2 -1
  3. package/README.md +108 -479
  4. package/dist/Router.d.ts +190 -0
  5. package/dist/Router.d.ts.map +1 -0
  6. package/dist/components/Modal.d.ts +56 -0
  7. package/dist/components/Modal.d.ts.map +1 -0
  8. package/dist/components/OverlayContentScope.d.ts +8 -0
  9. package/dist/components/OverlayContentScope.d.ts.map +1 -0
  10. package/dist/components/RouterCloseButton.d.ts +9 -0
  11. package/dist/components/RouterCloseButton.d.ts.map +1 -0
  12. package/dist/components/Sheet.d.ts +53 -0
  13. package/dist/components/Sheet.d.ts.map +1 -0
  14. package/dist/components/SheetSurface.d.ts +27 -0
  15. package/dist/components/SheetSurface.d.ts.map +1 -0
  16. package/dist/components/index.d.ts +4 -0
  17. package/dist/components/index.d.ts.map +1 -0
  18. package/dist/components/pageScrollLock.d.ts +3 -0
  19. package/dist/components/pageScrollLock.d.ts.map +1 -0
  20. package/dist/components/sheetDragEngine.d.ts +27 -0
  21. package/dist/components/sheetDragEngine.d.ts.map +1 -0
  22. package/dist/index.d.ts +5 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +3649 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/navigationHistory.d.ts +17 -0
  27. package/dist/navigationHistory.d.ts.map +1 -0
  28. package/dist/router.css +971 -0
  29. package/dist/types.d.ts +3 -0
  30. package/dist/types.d.ts.map +1 -0
  31. package/dist/utils/id.d.ts +2 -0
  32. package/dist/utils/id.d.ts.map +1 -0
  33. package/package.json +69 -174
  34. package/lib/module/Drawer/Drawer.js +0 -250
  35. package/lib/module/Drawer/DrawerContext.js +0 -4
  36. package/lib/module/Drawer/DrawerIcon.web.js +0 -47
  37. package/lib/module/Drawer/RenderDrawer.native.js +0 -248
  38. package/lib/module/Drawer/RenderDrawer.web.js +0 -197
  39. package/lib/module/Drawer/useDrawer.js +0 -11
  40. package/lib/module/Navigation.js +0 -80
  41. package/lib/module/NavigationStack.js +0 -254
  42. package/lib/module/Router.js +0 -2171
  43. package/lib/module/RouterContext.js +0 -33
  44. package/lib/module/ScreenStack/ScreenStack.native.js +0 -3
  45. package/lib/module/ScreenStack/ScreenStack.web.js +0 -561
  46. package/lib/module/ScreenStack/ScreenStackContext.js +0 -21
  47. package/lib/module/ScreenStack/animationHelpers.js +0 -87
  48. package/lib/module/ScreenStack/index.js +0 -3
  49. package/lib/module/ScreenStackItem/ScreenStackItem.js +0 -70
  50. package/lib/module/ScreenStackItem/ScreenStackItem.types.js +0 -3
  51. package/lib/module/ScreenStackItem/ScreenStackItem.web.js +0 -171
  52. package/lib/module/ScreenStackItem/index.js +0 -3
  53. package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.native.js +0 -70
  54. package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.web.js +0 -5
  55. package/lib/module/ScreenStackSheetItem/index.js +0 -3
  56. package/lib/module/SplitView/RenderSplitView.native.js +0 -101
  57. package/lib/module/SplitView/RenderSplitView.web.js +0 -107
  58. package/lib/module/SplitView/SplitView.js +0 -97
  59. package/lib/module/SplitView/SplitViewContext.js +0 -4
  60. package/lib/module/SplitView/index.js +0 -5
  61. package/lib/module/SplitView/useSplitView.js +0 -11
  62. package/lib/module/StackRenderer.js +0 -42
  63. package/lib/module/TabBar/RenderTabBar.native.js +0 -418
  64. package/lib/module/TabBar/RenderTabBar.web.js +0 -218
  65. package/lib/module/TabBar/TabBar.js +0 -208
  66. package/lib/module/TabBar/TabBarContext.js +0 -4
  67. package/lib/module/TabBar/TabIcon.web.js +0 -47
  68. package/lib/module/TabBar/index.js +0 -6
  69. package/lib/module/TabBar/useTabBar.js +0 -11
  70. package/lib/module/TabBar/useTabBarHeight.js +0 -22
  71. package/lib/module/createController.js +0 -5
  72. package/lib/module/index.js +0 -15
  73. package/lib/module/navigationNode.js +0 -3
  74. package/lib/module/package.json +0 -1
  75. package/lib/module/styles.css +0 -1111
  76. package/lib/module/types.js +0 -13
  77. package/lib/typescript/package.json +0 -1
  78. package/lib/typescript/src/Drawer/Drawer.d.ts +0 -100
  79. package/lib/typescript/src/Drawer/DrawerContext.d.ts +0 -3
  80. package/lib/typescript/src/Drawer/DrawerIcon.web.d.ts +0 -7
  81. package/lib/typescript/src/Drawer/RenderDrawer.native.d.ts +0 -8
  82. package/lib/typescript/src/Drawer/RenderDrawer.web.d.ts +0 -8
  83. package/lib/typescript/src/Drawer/useDrawer.d.ts +0 -2
  84. package/lib/typescript/src/Navigation.d.ts +0 -17
  85. package/lib/typescript/src/NavigationStack.d.ts +0 -46
  86. package/lib/typescript/src/Router.d.ts +0 -232
  87. package/lib/typescript/src/RouterContext.d.ts +0 -18
  88. package/lib/typescript/src/ScreenStack/ScreenStack.native.d.ts +0 -2
  89. package/lib/typescript/src/ScreenStack/ScreenStack.web.d.ts +0 -9
  90. package/lib/typescript/src/ScreenStack/ScreenStackContext.d.ts +0 -31
  91. package/lib/typescript/src/ScreenStack/animationHelpers.d.ts +0 -6
  92. package/lib/typescript/src/ScreenStack/index.d.ts +0 -2
  93. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.d.ts +0 -3
  94. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.types.d.ts +0 -14
  95. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.web.d.ts +0 -3
  96. package/lib/typescript/src/ScreenStackItem/index.d.ts +0 -3
  97. package/lib/typescript/src/ScreenStackSheetItem/ScreenStackSheetItem.native.d.ts +0 -11
  98. package/lib/typescript/src/ScreenStackSheetItem/ScreenStackSheetItem.web.d.ts +0 -2
  99. package/lib/typescript/src/ScreenStackSheetItem/index.d.ts +0 -2
  100. package/lib/typescript/src/SplitView/RenderSplitView.native.d.ts +0 -19
  101. package/lib/typescript/src/SplitView/RenderSplitView.web.d.ts +0 -8
  102. package/lib/typescript/src/SplitView/SplitView.d.ts +0 -33
  103. package/lib/typescript/src/SplitView/SplitViewContext.d.ts +0 -3
  104. package/lib/typescript/src/SplitView/index.d.ts +0 -5
  105. package/lib/typescript/src/SplitView/useSplitView.d.ts +0 -2
  106. package/lib/typescript/src/StackRenderer.d.ts +0 -8
  107. package/lib/typescript/src/TabBar/RenderTabBar.native.d.ts +0 -8
  108. package/lib/typescript/src/TabBar/RenderTabBar.web.d.ts +0 -8
  109. package/lib/typescript/src/TabBar/TabBar.d.ts +0 -112
  110. package/lib/typescript/src/TabBar/TabBarContext.d.ts +0 -3
  111. package/lib/typescript/src/TabBar/TabIcon.web.d.ts +0 -7
  112. package/lib/typescript/src/TabBar/index.d.ts +0 -5
  113. package/lib/typescript/src/TabBar/useTabBar.d.ts +0 -2
  114. package/lib/typescript/src/TabBar/useTabBarHeight.d.ts +0 -18
  115. package/lib/typescript/src/createController.d.ts +0 -15
  116. package/lib/typescript/src/index.d.ts +0 -21
  117. package/lib/typescript/src/navigationNode.d.ts +0 -41
  118. package/lib/typescript/src/types.d.ts +0 -140
@@ -1,97 +0,0 @@
1
- "use strict";
2
-
3
- import React from 'react';
4
- import { RenderSplitView } from './RenderSplitView';
5
- class SecondaryStackWrapper {
6
- constructor(stack) {
7
- this.stack = stack;
8
- }
9
- getId() {
10
- return this.stack.getId();
11
- }
12
- getNodeRoutes() {
13
- // IMPORTANT:
14
- // - do not mutate routes/options from the original NavigationStack
15
- // - allowRootPop is used by Router.goBack so that a single-screen secondary can be dismissed
16
- return this.stack.getNodeRoutes().map(r => ({
17
- ...r,
18
- options: {
19
- ...(r.options ?? {}),
20
- allowRootPop: true
21
- }
22
- }));
23
- }
24
- getNodeChildren() {
25
- return this.stack.getNodeChildren();
26
- }
27
- getRenderer() {
28
- return this.stack.getRenderer();
29
- }
30
- seed() {
31
- return this.stack.seed?.() ?? null;
32
- }
33
- getDefaultOptions() {
34
- return this.stack.getDefaultOptions?.();
35
- }
36
- }
37
- export class SplitView {
38
- _cachedRenderer = null;
39
- constructor(options) {
40
- this.splitViewId = `splitview-${Math.random().toString(36).slice(2)}`;
41
- this.primary = options.primary;
42
- this.secondary = options.secondary;
43
- this.minWidth = options.minWidth;
44
- this.primaryMaxWidth = options.primaryMaxWidth ?? 390;
45
- this.secondaryWrapper = new SecondaryStackWrapper(this.secondary);
46
- }
47
- getId() {
48
- return this.splitViewId;
49
- }
50
- getNodeRoutes() {
51
- return [];
52
- }
53
- getNodeChildren() {
54
- return [{
55
- prefix: '',
56
- node: this.primary
57
- }, {
58
- prefix: '',
59
- node: this.secondaryWrapper
60
- }];
61
- }
62
- getRenderer() {
63
- if (this._cachedRenderer) {
64
- return this._cachedRenderer;
65
- }
66
-
67
- // eslint-disable-next-line consistent-this
68
- const instance = this;
69
- const renderer = function SplitViewScreen(props) {
70
- return /*#__PURE__*/React.createElement(RenderSplitView, {
71
- splitView: instance,
72
- appearance: props?.appearance
73
- });
74
- };
75
- this._cachedRenderer = renderer;
76
- return renderer;
77
- }
78
- hasRoute(routeId) {
79
- return this.primary.getRoutes().some(r => r.routeId === routeId) || this.secondary.getRoutes().some(r => r.routeId === routeId);
80
- }
81
- switchToRoute(_routeId) {
82
- // SplitView does not have a single "active" child like TabBar.
83
- // It renders both stacks (or overlays secondary on narrow via CSS).
84
- }
85
- setActiveChildByRoute(routeId) {
86
- this.switchToRoute(routeId);
87
- }
88
- seed() {
89
- const firstRoute = this.primary.getFirstRoute();
90
- if (!firstRoute) return null;
91
- return {
92
- routeId: firstRoute.routeId,
93
- path: firstRoute.path,
94
- stackId: this.primary.getId()
95
- };
96
- }
97
- }
@@ -1,4 +0,0 @@
1
- "use strict";
2
-
3
- import { createContext } from 'react';
4
- export const SplitViewContext = /*#__PURE__*/createContext(null);
@@ -1,5 +0,0 @@
1
- "use strict";
2
-
3
- export { SplitView } from "./SplitView.js";
4
- export { RenderSplitView } from './RenderSplitView';
5
- export { useSplitView } from "./useSplitView.js";
@@ -1,11 +0,0 @@
1
- "use strict";
2
-
3
- import { useContext } from 'react';
4
- import { SplitViewContext } from "./SplitViewContext.js";
5
- export const useSplitView = () => {
6
- const splitView = useContext(SplitViewContext);
7
- if (!splitView) {
8
- throw new Error('useSplitView must be used within a SplitViewProvider');
9
- }
10
- return splitView;
11
- };
@@ -1,42 +0,0 @@
1
- "use strict";
2
-
3
- import { memo, useEffect, useState, startTransition } from 'react';
4
- import { ScreenStackItem } from "./ScreenStackItem/index.js";
5
- import { ScreenStack } from "./ScreenStack/index.js";
6
- import { useRouter } from "./RouterContext.js";
7
- import { StyleSheet } from 'react-native';
8
- import { jsx as _jsx } from "react/jsx-runtime";
9
- export const StackRenderer = /*#__PURE__*/memo(({
10
- stackId,
11
- appearance,
12
- history
13
- }) => {
14
- const router = useRouter();
15
- const hasHistoryProp = history != null;
16
- const [internalHistory, setInternalHistory] = useState(() => hasHistoryProp ? history : router.getStackHistory(stackId));
17
- useEffect(() => {
18
- if (hasHistoryProp) return;
19
- const update = () => {
20
- startTransition(() => {
21
- setInternalHistory(router.getStackHistory(stackId));
22
- });
23
- };
24
- const unsub = router.subscribeStack(stackId, update);
25
- update();
26
- return unsub;
27
- }, [router, stackId, hasHistoryProp]);
28
- const historyForThisStack = hasHistoryProp ? history : internalHistory;
29
- return /*#__PURE__*/_jsx(ScreenStack, {
30
- style: [styles.flex, appearance?.screen],
31
- children: historyForThisStack.map(item => /*#__PURE__*/_jsx(ScreenStackItem, {
32
- appearance: appearance,
33
- stackId: stackId,
34
- item: item
35
- }, `stack-renderer-${item.key}`))
36
- }, `stack-${stackId}`);
37
- });
38
- const styles = StyleSheet.create({
39
- flex: {
40
- flex: 1
41
- }
42
- });
@@ -1,418 +0,0 @@
1
- "use strict";
2
-
3
- import { StackRenderer } from "../StackRenderer.js";
4
- import { TabBarContext } from "./TabBarContext.js";
5
- import { useRouter } from "../RouterContext.js";
6
- import { Tabs } from 'react-native-screens';
7
- import { Platform, StyleSheet, View } from 'react-native';
8
- import { useCallback, useSyncExternalStore, memo, useEffect, useState, useMemo, startTransition } from 'react';
9
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
- const EMPTY_HISTORY = [];
11
- const isImageSource = value => {
12
- if (value == null) return false;
13
- const valueType = typeof value;
14
- if (valueType === 'number') return true;
15
- if (Array.isArray(value)) return value.length > 0;
16
- if (valueType === 'object') {
17
- const v = value;
18
- if ('uri' in v || 'width' in v || 'height' in v) return true;
19
- // Check for new PlatformIcon format
20
- if ('ios' in v || 'android' in v || 'shared' in v) return false;
21
- // Check for legacy format
22
- if ('sfSymbolName' in v || 'imageSource' in v || 'templateSource' in v) return false;
23
- // Check for new type-based format
24
- if ('type' in v) return false;
25
- }
26
- return false;
27
- };
28
- const isPlatformIcon = value => {
29
- if (value == null || typeof value !== 'object') return false;
30
- const v = value;
31
- return 'ios' in v || 'android' in v || 'shared' in v;
32
- };
33
- const isLegacyIOSIcon = value => {
34
- if (value == null || typeof value !== 'object') return false;
35
- const v = value;
36
- return 'sfSymbolName' in v || 'imageSource' in v || 'templateSource' in v;
37
- };
38
- const convertLegacyIOSIconToPlatformIconIOS = value => {
39
- if (!value || typeof value !== 'object') return undefined;
40
- const v = value;
41
- if ('sfSymbolName' in v) {
42
- return {
43
- type: 'sfSymbol',
44
- name: v.sfSymbolName
45
- };
46
- }
47
- if ('templateSource' in v) {
48
- return {
49
- type: 'templateSource',
50
- templateSource: v.templateSource
51
- };
52
- }
53
- if ('imageSource' in v) {
54
- return {
55
- type: 'imageSource',
56
- imageSource: v.imageSource
57
- };
58
- }
59
- return undefined;
60
- };
61
- const buildIOSIcon = value => {
62
- if (!value) return undefined;
63
-
64
- // If it's already a PlatformIcon, extract ios
65
- if (isPlatformIcon(value)) {
66
- return value.ios;
67
- }
68
-
69
- // If it's a legacy format, convert it
70
- if (isLegacyIOSIcon(value)) {
71
- return convertLegacyIOSIconToPlatformIconIOS(value);
72
- }
73
-
74
- // If it's an ImageSourcePropType, convert to templateSource
75
- if (isImageSource(value)) {
76
- return {
77
- type: 'templateSource',
78
- templateSource: value
79
- };
80
- }
81
- return undefined;
82
- };
83
- const buildPlatformIcon = (icon, selectedIcon) => {
84
- if (!icon && !selectedIcon) return undefined;
85
- const iosIcon = buildIOSIcon(icon);
86
- const iosSelectedIcon = buildIOSIcon(selectedIcon);
87
-
88
- // If it's already a PlatformIcon, use it directly
89
- if (isPlatformIcon(icon)) {
90
- return {
91
- ...icon,
92
- ios: iosSelectedIcon || icon.ios
93
- };
94
- }
95
-
96
- // Build new PlatformIcon
97
- const result = {};
98
- if (iosIcon || iosSelectedIcon) {
99
- result.ios = iosSelectedIcon || iosIcon;
100
- }
101
-
102
- // For shared imageSource (works on both platforms)
103
- if (isImageSource(icon) && !iosIcon) {
104
- result.shared = {
105
- type: 'imageSource',
106
- imageSource: icon
107
- };
108
- }
109
- return Object.keys(result).length > 0 ? result : undefined;
110
- };
111
- const getTabIcon = tab => {
112
- const {
113
- icon,
114
- selectedIcon
115
- } = tab;
116
- if (!icon && !selectedIcon) return undefined;
117
-
118
- // Build PlatformIcon for new API
119
- const platformIcon = buildPlatformIcon(icon, selectedIcon);
120
- if (!platformIcon) return undefined;
121
-
122
- // For Android, if icon is a direct ImageSourcePropType, use shared
123
- if (Platform.OS === 'android' && isImageSource(icon) && !platformIcon.shared) {
124
- platformIcon.shared = {
125
- type: 'imageSource',
126
- imageSource: icon
127
- };
128
- }
129
- return {
130
- icon: platformIcon,
131
- selectedIcon: platformIcon.ios
132
- };
133
- };
134
- const TabStackRenderer = /*#__PURE__*/memo(({
135
- stack,
136
- appearance
137
- }) => {
138
- const router = useRouter();
139
- const stackId = stack.getId();
140
-
141
- // Start with empty history — useEffect populates via startTransition.
142
- // This avoids mounting ScreenStackItems before parent Fragments attach.
143
- const [history, setHistory] = useState(EMPTY_HISTORY);
144
- useEffect(() => {
145
- const update = () => {
146
- startTransition(() => {
147
- setHistory(router.getStackHistory(stackId));
148
- });
149
- };
150
- const unsub = router.subscribeStack(stackId, update);
151
- update();
152
- return unsub;
153
- }, [router, stackId]);
154
- return /*#__PURE__*/_jsx(StackRenderer, {
155
- appearance: appearance,
156
- stackId: stackId,
157
- history: history
158
- });
159
- });
160
- TabStackRenderer.displayName = 'TabStackRenderer';
161
- const TabNodeRenderer = /*#__PURE__*/memo(({
162
- node,
163
- appearance
164
- }) => {
165
- const Renderer = useMemo(() => node.getRenderer(), [node]);
166
- return /*#__PURE__*/_jsx(Renderer, {
167
- appearance: appearance
168
- });
169
- });
170
- TabNodeRenderer.displayName = 'TabNodeRenderer';
171
- export const RenderTabBar = /*#__PURE__*/memo(({
172
- tabBar,
173
- appearance = {}
174
- }) => {
175
- const router = useRouter();
176
- const subscribe = useCallback(cb => tabBar.subscribe(cb), [tabBar]);
177
- const snapshot = useSyncExternalStore(subscribe, tabBar.getState, tabBar.getState);
178
- const {
179
- tabs,
180
- index,
181
- config
182
- } = snapshot;
183
-
184
- // Local focus state driven by startTransition so that isFocused changes
185
- // are deferred until the native Fragment lifecycle completes (Android Fabric).
186
- const [focusedTabKey, setFocusedTabKey] = useState(() => tabs[index]?.tabKey);
187
-
188
- // Sync focusedTabKey when index changes from external sources (programmatic navigation).
189
- useEffect(() => {
190
- const key = tabs[index]?.tabKey;
191
- if (key && key !== focusedTabKey) {
192
- startTransition(() => {
193
- setFocusedTabKey(key);
194
- });
195
- }
196
- }, [tabs, index, focusedTabKey]);
197
- const {
198
- iconColor,
199
- iconColorActive,
200
- androidActiveIndicatorEnabled,
201
- androidActiveIndicatorColor,
202
- androidRippleColor,
203
- labelVisibilityMode,
204
- title,
205
- backgroundColor,
206
- badgeBackgroundColor,
207
- iOSShadowColor,
208
- hidden,
209
- tintColor,
210
- controllerMode,
211
- minimizeBehavior,
212
- nativeContainerBackgroundColor,
213
- iOSBlurEffect
214
- } = appearance?.tabBar ?? {};
215
- const onNativeFocusChange = useCallback(event => {
216
- const tabKey = event.nativeEvent.tabKey;
217
- const tabIndex = tabs.findIndex(route => route.tabKey === tabKey);
218
- if (tabIndex === -1) return;
219
-
220
- // Defer isFocused update so the native Fragment has time to attach.
221
- startTransition(() => {
222
- setFocusedTabKey(tabKey);
223
- });
224
- if (tabIndex !== index) {
225
- tabBar.onIndexChange(tabIndex);
226
- }
227
- }, [tabs, tabBar, index]);
228
- const seedTabIfNeeded = useCallback(targetTab => {
229
- if (!targetTab) return;
230
- const targetStack = tabBar.stacks[targetTab.tabKey];
231
- const targetNode = tabBar.nodes[targetTab.tabKey];
232
- if (targetStack) {
233
- const stackId = targetStack.getId();
234
- const stackHistory = router.getStackHistory(stackId);
235
- if (stackHistory.length === 0) {
236
- const firstRoute = targetStack.getFirstRoute();
237
- if (firstRoute?.path) {
238
- router.navigate(firstRoute.path);
239
- }
240
- }
241
- return;
242
- }
243
- if (targetNode) {
244
- const nodeId = targetNode.getId?.();
245
- if (!nodeId) return;
246
- const nodeHistory = router.getStackHistory(nodeId);
247
- if (nodeHistory.length === 0) {
248
- const seed = targetNode.seed?.();
249
- if (seed?.path) {
250
- const prefix = targetTab.tabPrefix ?? '';
251
- const fullPath = prefix && !seed.path.startsWith(prefix) ? `${prefix}${seed.path.startsWith('/') ? '' : '/'}${seed.path}` : seed.path;
252
- router.navigate(fullPath);
253
- }
254
- }
255
- }
256
- }, [tabBar.nodes, tabBar.stacks, router]);
257
- useEffect(() => {
258
- seedTabIfNeeded(tabs[index]);
259
- }, [tabs, index, seedTabIfNeeded]);
260
- const onTabPress = useCallback(nextIndex => {
261
- const targetTab = tabs[nextIndex];
262
- if (!targetTab) return;
263
-
264
- // Update TabBar UI state
265
- if (nextIndex !== index) {
266
- tabBar.onIndexChange(nextIndex);
267
- }
268
- seedTabIfNeeded(targetTab);
269
- }, [tabs, tabBar, index, seedTabIfNeeded]);
270
- const containerProps = useMemo(() => ({
271
- tabBarBackgroundColor: backgroundColor,
272
- tabBarItemTitleFontFamily: title?.fontFamily,
273
- tabBarItemTitleFontSize: title?.fontSize,
274
- tabBarItemTitleFontSizeActive: title?.activeFontSize,
275
- tabBarItemTitleFontWeight: title?.fontWeight,
276
- tabBarItemTitleFontStyle: title?.fontStyle,
277
- tabBarItemTitleFontColor: title?.color,
278
- tabBarItemTitleFontColorActive: title?.activeColor,
279
- tabBarItemIconColor: iconColor,
280
- tabBarItemIconColorActive: iconColorActive,
281
- tabBarItemActiveIndicatorColor: androidActiveIndicatorColor,
282
- tabBarItemActiveIndicatorEnabled: androidActiveIndicatorEnabled,
283
- tabBarItemRippleColor: androidRippleColor,
284
- tabBarItemLabelVisibilityMode: labelVisibilityMode,
285
- tabBarHidden: hidden,
286
- tabBarTintColor: tintColor,
287
- tabBarControllerMode: controllerMode,
288
- tabBarMinimizeBehavior: minimizeBehavior,
289
- nativeContainerStyle: nativeContainerBackgroundColor ? {
290
- backgroundColor: nativeContainerBackgroundColor
291
- } : undefined
292
- }), [backgroundColor, title?.fontFamily, title?.fontSize, title?.activeFontSize, title?.fontWeight, title?.fontStyle, title?.color, title?.activeColor, iconColor, iconColorActive, androidActiveIndicatorColor, androidActiveIndicatorEnabled, androidRippleColor, labelVisibilityMode, hidden, tintColor, controllerMode, minimizeBehavior, nativeContainerBackgroundColor]);
293
- const iosNormalState = useMemo(() => ({
294
- tabBarItemTitleFontFamily: title?.fontFamily,
295
- tabBarItemTitleFontSize: title?.fontSize,
296
- tabBarItemTitleFontWeight: title?.fontWeight,
297
- tabBarItemTitleFontStyle: title?.fontStyle,
298
- tabBarItemTitleFontColor: title?.color,
299
- tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
300
- tabBarItemIconColor: iconColor
301
- }), [title?.fontFamily, title?.fontSize, title?.fontWeight, title?.fontStyle, title?.color, badgeBackgroundColor, iconColor]);
302
- const iosSelectedState = useMemo(() => ({
303
- tabBarItemTitleFontFamily: title?.fontFamily,
304
- tabBarItemTitleFontSize: title?.fontSize,
305
- tabBarItemTitleFontWeight: title?.fontWeight,
306
- tabBarItemTitleFontStyle: title?.fontStyle,
307
- tabBarItemTitleFontColor: title?.activeColor ?? title?.color,
308
- tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
309
- tabBarItemIconColor: iconColorActive ?? iconColor
310
- }), [title?.fontFamily, title?.fontSize, title?.fontWeight, title?.fontStyle, title?.color, title?.activeColor, badgeBackgroundColor, iconColorActive, iconColor]);
311
- const iosAppearance = useMemo(() => Platform.select({
312
- default: undefined,
313
- ios: {
314
- tabBarBackgroundColor: backgroundColor,
315
- tabBarShadowColor: iOSShadowColor,
316
- tabBarBlurEffect: iOSBlurEffect,
317
- compactInline: {
318
- normal: iosNormalState,
319
- selected: iosSelectedState
320
- },
321
- stacked: {
322
- normal: iosNormalState,
323
- selected: iosSelectedState
324
- },
325
- inline: {
326
- normal: iosNormalState,
327
- selected: iosSelectedState
328
- }
329
- }
330
- }), [backgroundColor, iOSShadowColor, iOSBlurEffect, iosNormalState, iosSelectedState]);
331
- const CustomTabBar = config.component;
332
- const tabIcons = useMemo(() => tabs.map(tab => getTabIcon(tab)), [tabs]);
333
- const [visited, setVisited] = useState({});
334
- useEffect(() => {
335
- const key = tabs[index]?.tabKey;
336
- if (key) {
337
- startTransition(() => {
338
- setVisited(prev => prev[key] ? prev : {
339
- ...prev,
340
- [key]: true
341
- });
342
- });
343
- }
344
- }, [tabs, index]);
345
- if (CustomTabBar) {
346
- return /*#__PURE__*/_jsxs(TabBarContext.Provider, {
347
- value: tabBar,
348
- children: [/*#__PURE__*/_jsx(View, {
349
- style: styles.flex,
350
- children: tabs.filter(t => visited[t.tabKey]).map(tab => {
351
- const isActive = tab.tabKey === tabs[index]?.tabKey;
352
- const stackForTab = tabBar.stacks[tab.tabKey];
353
- const nodeForTab = tabBar.nodes[tab.tabKey];
354
- const ScreenForTab = tabBar.screens[tab.tabKey];
355
- return /*#__PURE__*/_jsx(View, {
356
- style: [styles.flex, !isActive && styles.hidden],
357
- children: stackForTab ? /*#__PURE__*/_jsx(TabStackRenderer, {
358
- appearance: appearance,
359
- stack: stackForTab
360
- }) : nodeForTab ? /*#__PURE__*/_jsx(TabNodeRenderer, {
361
- appearance: appearance,
362
- node: nodeForTab
363
- }) : ScreenForTab ? /*#__PURE__*/_jsx(ScreenForTab, {}) : null
364
- }, `tab-content-${tab.tabKey}`);
365
- })
366
- }), /*#__PURE__*/_jsx(CustomTabBar, {
367
- onTabPress: onTabPress,
368
- activeIndex: index,
369
- tabs: tabs
370
- })]
371
- });
372
- }
373
- return /*#__PURE__*/_jsx(TabBarContext.Provider, {
374
- value: tabBar,
375
- children: /*#__PURE__*/_jsx(Tabs.Host, {
376
- onNativeFocusChange: onNativeFocusChange,
377
- bottomAccessory: config.bottomAccessory,
378
- experimentalControlNavigationStateInJS: config.experimentalControlNavigationStateInJS,
379
- ...containerProps,
380
- children: tabs.map((tab, i) => {
381
- const isFocused = tab.tabKey === focusedTabKey;
382
- const stack = tabBar.stacks[tab.tabKey];
383
- const node = tabBar.nodes[tab.tabKey];
384
- const Screen = tabBar.screens[tab.tabKey];
385
- const convertedIcon = tabIcons[i];
386
- const {
387
- icon: _icon,
388
- selectedIcon: _selectedIcon,
389
- tabPrefix: _prefix,
390
- ...tabScreenProps
391
- } = tab;
392
- return /*#__PURE__*/_jsx(Tabs.Screen, {
393
- ...tabScreenProps,
394
- scrollEdgeAppearance: iosAppearance,
395
- standardAppearance: iosAppearance,
396
- isFocused: isFocused,
397
- icon: convertedIcon?.icon,
398
- selectedIcon: convertedIcon?.selectedIcon,
399
- children: stack ? /*#__PURE__*/_jsx(TabStackRenderer, {
400
- appearance: appearance,
401
- stack: stack
402
- }) : node ? /*#__PURE__*/_jsx(TabNodeRenderer, {
403
- appearance: appearance,
404
- node: node
405
- }) : Screen ? /*#__PURE__*/_jsx(Screen, {}) : null
406
- }, tab.tabKey);
407
- })
408
- })
409
- });
410
- });
411
- const styles = StyleSheet.create({
412
- flex: {
413
- flex: 1
414
- },
415
- hidden: {
416
- display: 'none'
417
- }
418
- });