@sigmela/router 0.3.0 → 0.3.1
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.
package/README.md
CHANGED
|
@@ -8,9 +8,11 @@ This library is **URL-first**: you navigate by **paths** (`/users/42?tab=posts`)
|
|
|
8
8
|
|
|
9
9
|
- **Stacks**: predictable stack-based navigation
|
|
10
10
|
- **Tabs**: `TabBar` with native + web renderers (or custom tab bar)
|
|
11
|
+
- **Drawer**: side-panel navigation (`Drawer`)
|
|
11
12
|
- **Split view**: master/details navigation (`SplitView`)
|
|
12
13
|
- **Modals & sheets**: via `stackPresentation` (`modal`, `sheet`, …)
|
|
13
14
|
- **Controllers**: async/guarded navigation (only present when ready)
|
|
15
|
+
- **Appearance**: global styling via `NavigationAppearance` (tab bar colors, fonts, blur effects, etc.)
|
|
14
16
|
- **Web History integration**: keeps Router state in sync with `pushState`, `replaceState`, `popstate`
|
|
15
17
|
- **Dynamic root**: swap root navigation tree at runtime (`router.setRoot`)
|
|
16
18
|
- **Type-safe hooks**: `useParams`, `useQueryParams`, `useRoute`, `useCurrentRoute`
|
|
@@ -27,7 +29,7 @@ yarn add @sigmela/native-sheet
|
|
|
27
29
|
|
|
28
30
|
- `react`
|
|
29
31
|
- `react-native`
|
|
30
|
-
- `react-native-screens` (>= `4.
|
|
32
|
+
- `react-native-screens` (>= `4.24.0`)
|
|
31
33
|
- `@sigmela/native-sheet` (>= `0.0.1`) — only if you use sheets
|
|
32
34
|
|
|
33
35
|
### Web CSS
|
|
@@ -292,10 +294,45 @@ Key methods:
|
|
|
292
294
|
Notes:
|
|
293
295
|
- Exactly one of `stack`, `node`, `screen` must be provided.
|
|
294
296
|
- Use `prefix` to mount a tab's routes under a base path (e.g. `/mail`).
|
|
297
|
+
- All `TabsScreenProps` from `react-native-screens` are forwarded to native. This includes lifecycle events (`onWillAppear`, `onDidAppear`, `onWillDisappear`, `onDidDisappear`), accessibility props (`testID`, `accessibilityLabel`, `tabBarItemTestID`, `tabBarItemAccessibilityLabel`), `orientation`, `systemItem`, `freezeContents`, `placeholder`, `scrollEdgeEffects`, badge styling, and more.
|
|
298
|
+
|
|
299
|
+
#### `setTabBarConfig()`
|
|
300
|
+
|
|
301
|
+
Runtime tab bar configuration:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
tabBar.setTabBarConfig({
|
|
305
|
+
bottomAccessory: (environment) => <MiniPlayer layout={environment} />, // iOS 26+
|
|
306
|
+
experimentalControlNavigationStateInJS: true,
|
|
307
|
+
});
|
|
308
|
+
```
|
|
295
309
|
|
|
296
310
|
Web behavior note:
|
|
297
311
|
- The built-in **web** tab bar renderer resets Router history on tab switch (to keep URL and Router state consistent) using `router.reset(firstRoutePath)`.
|
|
298
312
|
|
|
313
|
+
### `Drawer`
|
|
314
|
+
|
|
315
|
+
`Drawer` provides side-panel navigation, similar to `TabBar` but with a slide-out panel.
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { Drawer, NavigationStack } from '@sigmela/router';
|
|
319
|
+
|
|
320
|
+
const homeStack = new NavigationStack().addScreen('/', HomeScreen);
|
|
321
|
+
const settingsStack = new NavigationStack().addScreen('/settings', SettingsScreen);
|
|
322
|
+
|
|
323
|
+
const drawer = new Drawer({ width: 280 })
|
|
324
|
+
.addTab({ key: 'home', stack: homeStack, title: 'Home' })
|
|
325
|
+
.addTab({ key: 'settings', stack: settingsStack, title: 'Settings' });
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Key methods:
|
|
329
|
+
- `addTab({ key, stack?, node?, screen?, prefix?, title?, icon?, ... })`
|
|
330
|
+
- `open()`, `close()`, `toggle()` — manage drawer state
|
|
331
|
+
- `getIsOpen()` — current open state
|
|
332
|
+
- `subscribeOpenState(listener)` — subscribe to open/close changes
|
|
333
|
+
- `onIndexChange(index)` — switch active tab
|
|
334
|
+
- `setBadge(index, badge | null)`
|
|
335
|
+
|
|
299
336
|
### `SplitView`
|
|
300
337
|
|
|
301
338
|
`SplitView` renders **two stacks**: `primary` and `secondary`.
|
|
@@ -350,6 +387,54 @@ stack.addScreen('/users/:userId', UserDetails);
|
|
|
350
387
|
|
|
351
388
|
If you never call `present()`, the screen is not pushed/replaced.
|
|
352
389
|
|
|
390
|
+
## Appearance
|
|
391
|
+
|
|
392
|
+
Pass `NavigationAppearance` to `<Navigation>` to customize styling globally:
|
|
393
|
+
|
|
394
|
+
```tsx
|
|
395
|
+
import { Navigation, type NavigationAppearance } from '@sigmela/router';
|
|
396
|
+
|
|
397
|
+
const appearance: NavigationAppearance = {
|
|
398
|
+
tabBar: {
|
|
399
|
+
backgroundColor: '#ffffff',
|
|
400
|
+
iconColor: '#999999',
|
|
401
|
+
iconColorActive: '#007AFF',
|
|
402
|
+
badgeBackgroundColor: '#FF3B30',
|
|
403
|
+
iOSShadowColor: '#00000020',
|
|
404
|
+
title: {
|
|
405
|
+
fontFamily: 'Inter',
|
|
406
|
+
fontSize: 10,
|
|
407
|
+
color: '#999999',
|
|
408
|
+
activeColor: '#007AFF',
|
|
409
|
+
activeFontSize: 12, // Android: active tab title font size
|
|
410
|
+
},
|
|
411
|
+
|
|
412
|
+
// Android-specific
|
|
413
|
+
androidActiveIndicatorEnabled: true,
|
|
414
|
+
androidActiveIndicatorColor: '#007AFF20',
|
|
415
|
+
androidRippleColor: '#007AFF10',
|
|
416
|
+
labelVisibilityMode: 'labeled',
|
|
417
|
+
|
|
418
|
+
// Tab bar behavior
|
|
419
|
+
hidden: false, // hide/show the tab bar
|
|
420
|
+
tintColor: '#007AFF', // iOS: selected tab tint + glow color
|
|
421
|
+
controllerMode: 'automatic', // iOS 18+: 'automatic' | 'tabBar' | 'tabSidebar'
|
|
422
|
+
minimizeBehavior: 'automatic', // iOS 26+: 'automatic' | 'never' | 'onScrollDown' | 'onScrollUp'
|
|
423
|
+
nativeContainerBackgroundColor: '#fff', // native container background
|
|
424
|
+
iOSBlurEffect: 'systemDefault', // iOS: tab bar blur effect
|
|
425
|
+
},
|
|
426
|
+
header: { /* ScreenStackHeaderConfigProps */ },
|
|
427
|
+
sheet: {
|
|
428
|
+
cornerRadius: 16,
|
|
429
|
+
backgroundColor: '#ffffff',
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
export default function App() {
|
|
434
|
+
return <Navigation router={router} appearance={appearance} />;
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
353
438
|
## Hooks
|
|
354
439
|
|
|
355
440
|
### `useRouter()`
|
|
@@ -410,6 +495,27 @@ function ScreenInsideTabs() {
|
|
|
410
495
|
}
|
|
411
496
|
```
|
|
412
497
|
|
|
498
|
+
### `useTabBarHeight()`
|
|
499
|
+
|
|
500
|
+
Returns the tab bar height constant (`57`). Useful for bottom padding.
|
|
501
|
+
|
|
502
|
+
### `useDrawer()`
|
|
503
|
+
|
|
504
|
+
Returns the nearest `Drawer` from context (only inside drawer screens).
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
import { useDrawer } from '@sigmela/router';
|
|
508
|
+
|
|
509
|
+
function ScreenInsideDrawer() {
|
|
510
|
+
const drawer = useDrawer();
|
|
511
|
+
return <Button title="Open menu" onPress={() => drawer.open()} />;
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### `useSplitView()`
|
|
516
|
+
|
|
517
|
+
Returns the nearest `SplitView` from context (only inside split view screens).
|
|
518
|
+
|
|
413
519
|
## Web integration
|
|
414
520
|
|
|
415
521
|
### History API syncing
|
|
@@ -5,6 +5,7 @@ import { DrawerContext } from "./DrawerContext.js";
|
|
|
5
5
|
import { useRouter } from "../RouterContext.js";
|
|
6
6
|
import { ScreenStackItem } from 'react-native-screens';
|
|
7
7
|
import { Pressable, StyleSheet, View, Text } from 'react-native';
|
|
8
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
8
9
|
import { useCallback, useSyncExternalStore, memo, useEffect, useState, useMemo } from 'react';
|
|
9
10
|
import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
|
|
10
11
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -43,6 +44,7 @@ export const RenderDrawer = /*#__PURE__*/memo(({
|
|
|
43
44
|
appearance = {}
|
|
44
45
|
}) => {
|
|
45
46
|
const router = useRouter();
|
|
47
|
+
const insets = useSafeAreaInsets();
|
|
46
48
|
const drawerWidth = drawer.width;
|
|
47
49
|
const subscribe = useCallback(cb => drawer.subscribe(cb), [drawer]);
|
|
48
50
|
const snapshot = useSyncExternalStore(subscribe, drawer.getState, drawer.getState);
|
|
@@ -143,7 +145,9 @@ export const RenderDrawer = /*#__PURE__*/memo(({
|
|
|
143
145
|
isOpen: isOpen,
|
|
144
146
|
onClose: handleOverlayPress
|
|
145
147
|
}) : /*#__PURE__*/_jsx(View, {
|
|
146
|
-
style: styles.sidebarContent,
|
|
148
|
+
style: [styles.sidebarContent, {
|
|
149
|
+
paddingTop: insets.top + 12
|
|
150
|
+
}],
|
|
147
151
|
children: tabs.map((tab, i) => {
|
|
148
152
|
const isActive = i === index;
|
|
149
153
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
@@ -200,8 +204,7 @@ const styles = StyleSheet.create({
|
|
|
200
204
|
backgroundColor: '#ffffff'
|
|
201
205
|
},
|
|
202
206
|
sidebarContent: {
|
|
203
|
-
flex: 1
|
|
204
|
-
paddingTop: 12
|
|
207
|
+
flex: 1
|
|
205
208
|
},
|
|
206
209
|
main: {
|
|
207
210
|
flex: 1,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { StackRenderer } from "../StackRenderer.js";
|
|
4
4
|
import { TabBarContext } from "./TabBarContext.js";
|
|
5
5
|
import { useRouter } from "../RouterContext.js";
|
|
6
|
-
import {
|
|
6
|
+
import { Tabs, ScreenStackItem } from 'react-native-screens';
|
|
7
7
|
import { Platform, StyleSheet, View } from 'react-native';
|
|
8
8
|
import { useCallback, useSyncExternalStore, memo, useEffect, useState, useMemo } from 'react';
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -178,7 +178,13 @@ export const RenderTabBar = /*#__PURE__*/memo(({
|
|
|
178
178
|
title,
|
|
179
179
|
backgroundColor,
|
|
180
180
|
badgeBackgroundColor,
|
|
181
|
-
iOSShadowColor
|
|
181
|
+
iOSShadowColor,
|
|
182
|
+
hidden,
|
|
183
|
+
tintColor,
|
|
184
|
+
controllerMode,
|
|
185
|
+
minimizeBehavior,
|
|
186
|
+
nativeContainerBackgroundColor,
|
|
187
|
+
iOSBlurEffect
|
|
182
188
|
} = appearance?.tabBar ?? {};
|
|
183
189
|
const onNativeFocusChange = useCallback(event => {
|
|
184
190
|
const tabKey = event.nativeEvent.tabKey;
|
|
@@ -263,6 +269,7 @@ export const RenderTabBar = /*#__PURE__*/memo(({
|
|
|
263
269
|
tabBarBackgroundColor: backgroundColor,
|
|
264
270
|
tabBarItemTitleFontFamily: title?.fontFamily,
|
|
265
271
|
tabBarItemTitleFontSize: title?.fontSize,
|
|
272
|
+
tabBarItemTitleFontSizeActive: title?.activeFontSize,
|
|
266
273
|
tabBarItemTitleFontWeight: title?.fontWeight,
|
|
267
274
|
tabBarItemTitleFontStyle: title?.fontStyle,
|
|
268
275
|
tabBarItemTitleFontColor: title?.color,
|
|
@@ -272,35 +279,53 @@ export const RenderTabBar = /*#__PURE__*/memo(({
|
|
|
272
279
|
tabBarItemActiveIndicatorColor: androidActiveIndicatorColor,
|
|
273
280
|
tabBarItemActiveIndicatorEnabled: androidActiveIndicatorEnabled,
|
|
274
281
|
tabBarItemRippleColor: androidRippleColor,
|
|
275
|
-
tabBarItemLabelVisibilityMode: labelVisibilityMode
|
|
276
|
-
|
|
277
|
-
|
|
282
|
+
tabBarItemLabelVisibilityMode: labelVisibilityMode,
|
|
283
|
+
tabBarHidden: hidden,
|
|
284
|
+
tabBarTintColor: tintColor,
|
|
285
|
+
tabBarControllerMode: controllerMode,
|
|
286
|
+
tabBarMinimizeBehavior: minimizeBehavior,
|
|
287
|
+
nativeContainerStyle: nativeContainerBackgroundColor ? {
|
|
288
|
+
backgroundColor: nativeContainerBackgroundColor
|
|
289
|
+
} : undefined
|
|
290
|
+
}), [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]);
|
|
291
|
+
const iosNormalState = useMemo(() => ({
|
|
278
292
|
tabBarItemTitleFontFamily: title?.fontFamily,
|
|
279
293
|
tabBarItemTitleFontSize: title?.fontSize,
|
|
280
294
|
tabBarItemTitleFontWeight: title?.fontWeight,
|
|
281
295
|
tabBarItemTitleFontStyle: title?.fontStyle,
|
|
282
296
|
tabBarItemTitleFontColor: title?.color,
|
|
283
297
|
tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
|
|
284
|
-
tabBarItemTitleFontColorActive: title?.activeColor ?? title?.color,
|
|
285
|
-
tabBarItemIconColorActive: iconColorActive,
|
|
286
298
|
tabBarItemIconColor: iconColor
|
|
299
|
+
}), [title?.fontFamily, title?.fontSize, title?.fontWeight, title?.fontStyle, title?.color, badgeBackgroundColor, iconColor]);
|
|
300
|
+
const iosSelectedState = useMemo(() => ({
|
|
301
|
+
tabBarItemTitleFontFamily: title?.fontFamily,
|
|
302
|
+
tabBarItemTitleFontSize: title?.fontSize,
|
|
303
|
+
tabBarItemTitleFontWeight: title?.fontWeight,
|
|
304
|
+
tabBarItemTitleFontStyle: title?.fontStyle,
|
|
305
|
+
tabBarItemTitleFontColor: title?.activeColor ?? title?.color,
|
|
306
|
+
tabBarItemBadgeBackgroundColor: badgeBackgroundColor,
|
|
307
|
+
tabBarItemIconColor: iconColorActive ?? iconColor
|
|
287
308
|
}), [title?.fontFamily, title?.fontSize, title?.fontWeight, title?.fontStyle, title?.color, title?.activeColor, badgeBackgroundColor, iconColorActive, iconColor]);
|
|
288
309
|
const iosAppearance = useMemo(() => Platform.select({
|
|
289
310
|
default: undefined,
|
|
290
311
|
ios: {
|
|
291
312
|
tabBarBackgroundColor: backgroundColor,
|
|
292
313
|
tabBarShadowColor: iOSShadowColor,
|
|
314
|
+
tabBarBlurEffect: iOSBlurEffect,
|
|
293
315
|
compactInline: {
|
|
294
|
-
normal:
|
|
316
|
+
normal: iosNormalState,
|
|
317
|
+
selected: iosSelectedState
|
|
295
318
|
},
|
|
296
319
|
stacked: {
|
|
297
|
-
normal:
|
|
320
|
+
normal: iosNormalState,
|
|
321
|
+
selected: iosSelectedState
|
|
298
322
|
},
|
|
299
323
|
inline: {
|
|
300
|
-
normal:
|
|
324
|
+
normal: iosNormalState,
|
|
325
|
+
selected: iosSelectedState
|
|
301
326
|
}
|
|
302
327
|
}
|
|
303
|
-
}), [backgroundColor, iOSShadowColor,
|
|
328
|
+
}), [backgroundColor, iOSShadowColor, iOSBlurEffect, iosNormalState, iosSelectedState]);
|
|
304
329
|
const CustomTabBar = config.component;
|
|
305
330
|
const tabIcons = useMemo(() => tabs.map(tab => getTabIcon(tab)), [tabs]);
|
|
306
331
|
const [visited, setVisited] = useState({});
|
|
@@ -358,25 +383,30 @@ export const RenderTabBar = /*#__PURE__*/memo(({
|
|
|
358
383
|
stackAnimation: "slide_from_right",
|
|
359
384
|
children: /*#__PURE__*/_jsx(TabBarContext.Provider, {
|
|
360
385
|
value: tabBar,
|
|
361
|
-
children: /*#__PURE__*/_jsx(
|
|
386
|
+
children: /*#__PURE__*/_jsx(Tabs.Host, {
|
|
362
387
|
onNativeFocusChange: onNativeFocusChange,
|
|
388
|
+
bottomAccessory: config.bottomAccessory,
|
|
389
|
+
experimentalControlNavigationStateInJS: config.experimentalControlNavigationStateInJS,
|
|
363
390
|
...containerProps,
|
|
364
391
|
children: tabs.map((tab, i) => {
|
|
365
392
|
const isFocused = tab.tabKey === tabs[index]?.tabKey;
|
|
366
393
|
const stack = tabBar.stacks[tab.tabKey];
|
|
367
394
|
const node = tabBar.nodes[tab.tabKey];
|
|
368
395
|
const Screen = tabBar.screens[tab.tabKey];
|
|
369
|
-
const
|
|
370
|
-
|
|
396
|
+
const convertedIcon = tabIcons[i];
|
|
397
|
+
const {
|
|
398
|
+
icon: _icon,
|
|
399
|
+
selectedIcon: _selectedIcon,
|
|
400
|
+
tabPrefix: _prefix,
|
|
401
|
+
...tabScreenProps
|
|
402
|
+
} = tab;
|
|
403
|
+
return /*#__PURE__*/_jsx(Tabs.Screen, {
|
|
404
|
+
...tabScreenProps,
|
|
371
405
|
scrollEdgeAppearance: iosAppearance,
|
|
372
406
|
standardAppearance: iosAppearance,
|
|
373
407
|
isFocused: isFocused,
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
badgeValue: tab.badgeValue,
|
|
377
|
-
specialEffects: tab.specialEffects,
|
|
378
|
-
icon: icon?.icon,
|
|
379
|
-
selectedIcon: icon?.selectedIcon,
|
|
408
|
+
icon: convertedIcon?.icon,
|
|
409
|
+
selectedIcon: convertedIcon?.selectedIcon,
|
|
380
410
|
children: stack ? /*#__PURE__*/_jsx(TabStackRenderer, {
|
|
381
411
|
appearance: appearance,
|
|
382
412
|
stack: stack
|
package/lib/module/styles.css
CHANGED
|
@@ -1094,9 +1094,18 @@
|
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
1096
|
/* ==================== DESKTOP DRAWER (>= 641px) ==================== */
|
|
1097
|
+
/* Inverted logic: sidebar is visible by default, data-drawer-open='true' hides it.
|
|
1098
|
+
This way toggle() works on both viewports with a single boolean:
|
|
1099
|
+
isOpen=false (default) → mobile: hidden, desktop: visible
|
|
1100
|
+
isOpen=true (toggled) → mobile: visible, desktop: hidden */
|
|
1097
1101
|
@media (min-width: 641px) {
|
|
1098
|
-
/* On desktop, drawer is always visible — data-drawer-open is irrelevant */
|
|
1099
1102
|
.drawer-sidebar {
|
|
1100
1103
|
border-right: 1px solid rgba(0, 0, 0, 0.08);
|
|
1104
|
+
transition: margin-left var(--drawer-transition);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
.drawer-container[data-drawer-open='true'] .drawer-sidebar {
|
|
1108
|
+
margin-left: calc(-1 * var(--drawer-width));
|
|
1109
|
+
border-right: none;
|
|
1101
1110
|
}
|
|
1102
1111
|
}
|
|
@@ -4,7 +4,7 @@ import type { ComponentType } from 'react';
|
|
|
4
4
|
import type { TabItem } from '../types';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import type { NavigationNode, NodeChild, NodeRoute } from '../navigationNode';
|
|
7
|
-
import type { PlatformIcon } from 'react-native-screens';
|
|
7
|
+
import type { PlatformIcon, TabAccessoryComponentFactory } from 'react-native-screens';
|
|
8
8
|
type LegacyIOSIconShape = {
|
|
9
9
|
sfSymbolName: string;
|
|
10
10
|
} | {
|
|
@@ -52,6 +52,14 @@ type TabBarConfig = Omit<InternalTabItem, 'tabKey' | 'key'> & {
|
|
|
52
52
|
* Custom tab bar component (UI). Kept for compatibility.
|
|
53
53
|
*/
|
|
54
54
|
component?: ComponentType<TabBarProps>;
|
|
55
|
+
/**
|
|
56
|
+
* iOS 26+ bottom accessory factory.
|
|
57
|
+
*/
|
|
58
|
+
bottomAccessory?: TabAccessoryComponentFactory;
|
|
59
|
+
/**
|
|
60
|
+
* Experimental: control navigation state in JS.
|
|
61
|
+
*/
|
|
62
|
+
experimentalControlNavigationStateInJS?: boolean;
|
|
55
63
|
};
|
|
56
64
|
type TabBarOptions = {
|
|
57
65
|
component?: ComponentType<TabBarProps>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ColorValue, StyleProp, ViewStyle, TextStyle } from 'react-native';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TabsScreenProps, ScreenProps as RNSScreenProps, ScreenStackHeaderConfigProps, TabBarItemLabelVisibilityMode, TabBarMinimizeBehavior, TabBarControllerMode, TabAccessoryComponentFactory, TabsScreenBlurEffect } from 'react-native-screens';
|
|
3
3
|
export type StackPresentationTypes = 'push' | 'modal' | 'modalRight' | 'transparentModal' | 'containedModal' | 'containedTransparentModal' | 'fullScreenModal' | 'formSheet' | 'pageSheet' | 'sheet';
|
|
4
4
|
/**
|
|
5
5
|
* Presentations that behave like modals (overlay on top of content).
|
|
@@ -9,7 +9,7 @@ export declare const MODAL_LIKE_PRESENTATIONS: ReadonlySet<StackPresentationType
|
|
|
9
9
|
* Check if a presentation type is modal-like (renders as overlay).
|
|
10
10
|
*/
|
|
11
11
|
export declare function isModalLikePresentation(presentation: StackPresentationTypes | undefined): boolean;
|
|
12
|
-
export type TabItem = Omit<
|
|
12
|
+
export type TabItem = Omit<TabsScreenProps, 'isFocused' | 'children'>;
|
|
13
13
|
export type NavigationState<Route extends TabItem> = {
|
|
14
14
|
index: number;
|
|
15
15
|
routes: Route[];
|
|
@@ -98,6 +98,8 @@ export type CompiledRoute = {
|
|
|
98
98
|
};
|
|
99
99
|
export type TabBarConfig = {
|
|
100
100
|
tabBarMinimizeBehavior?: TabBarMinimizeBehavior;
|
|
101
|
+
bottomAccessory?: TabAccessoryComponentFactory;
|
|
102
|
+
experimentalControlNavigationStateInJS?: boolean;
|
|
101
103
|
};
|
|
102
104
|
export type SheetAppearance = {
|
|
103
105
|
androidFullScreenTopInset?: number;
|
|
@@ -115,6 +117,12 @@ export interface NavigationAppearance {
|
|
|
115
117
|
androidRippleColor?: ColorValue;
|
|
116
118
|
labelVisibilityMode?: TabBarItemLabelVisibilityMode;
|
|
117
119
|
iOSShadowColor?: ColorValue;
|
|
120
|
+
hidden?: boolean;
|
|
121
|
+
tintColor?: ColorValue;
|
|
122
|
+
controllerMode?: TabBarControllerMode;
|
|
123
|
+
minimizeBehavior?: TabBarMinimizeBehavior;
|
|
124
|
+
nativeContainerBackgroundColor?: ColorValue;
|
|
125
|
+
iOSBlurEffect?: TabsScreenBlurEffect;
|
|
118
126
|
title: {
|
|
119
127
|
fontFamily?: TextStyle['fontFamily'];
|
|
120
128
|
fontSize?: TextStyle['fontSize'];
|
|
@@ -122,6 +130,7 @@ export interface NavigationAppearance {
|
|
|
122
130
|
fontStyle?: TextStyle['fontStyle'];
|
|
123
131
|
color?: TextStyle['color'];
|
|
124
132
|
activeColor?: TextStyle['color'];
|
|
133
|
+
activeFontSize?: TextStyle['fontSize'];
|
|
125
134
|
};
|
|
126
135
|
};
|
|
127
136
|
screen?: StyleProp<ViewStyle>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigmela/router",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "React Native Router",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
"@eslint/eslintrc": "^3.3.1",
|
|
72
72
|
"@eslint/js": "^9.35.0",
|
|
73
73
|
"@evilmartians/lefthook": "^1.12.3",
|
|
74
|
-
"@react-native/babel-preset": "0.
|
|
75
|
-
"@react-native/eslint-config": "^0.
|
|
74
|
+
"@react-native/babel-preset": "0.83.2",
|
|
75
|
+
"@react-native/eslint-config": "^0.83.2",
|
|
76
76
|
"@release-it/conventional-changelog": "^10.0.1",
|
|
77
77
|
"@sigmela/native-sheet": "^0.0.1",
|
|
78
78
|
"@types/jest": "^29.5.14",
|
|
@@ -83,12 +83,13 @@
|
|
|
83
83
|
"eslint-config-prettier": "^10.1.8",
|
|
84
84
|
"eslint-plugin-prettier": "^5.5.4",
|
|
85
85
|
"jest": "^29.7.0",
|
|
86
|
-
"prettier": "^3.
|
|
87
|
-
"react": "19.
|
|
88
|
-
"react-native": "0.
|
|
89
|
-
"react-native-builder-bob": "^0.40.
|
|
86
|
+
"prettier": "^3.8.1",
|
|
87
|
+
"react": "19.2.0",
|
|
88
|
+
"react-native": "0.83.2",
|
|
89
|
+
"react-native-builder-bob": "^0.40.18",
|
|
90
90
|
"react-native-reanimated": "^4.2.2",
|
|
91
|
-
"react-native-
|
|
91
|
+
"react-native-safe-area-context": "^5.7.0",
|
|
92
|
+
"react-native-screens": "^4.24.0",
|
|
92
93
|
"react-native-worklets": "^0.7.4",
|
|
93
94
|
"release-it": "^19.0.4",
|
|
94
95
|
"typescript": "^5.9.2"
|
|
@@ -98,6 +99,7 @@
|
|
|
98
99
|
"react": "*",
|
|
99
100
|
"react-native": ">=0.72.0",
|
|
100
101
|
"react-native-reanimated": ">=3.0.0",
|
|
102
|
+
"react-native-safe-area-context": ">=4.0.0",
|
|
101
103
|
"react-native-screens": ">=4.18.0"
|
|
102
104
|
},
|
|
103
105
|
"peerDependenciesMeta": {
|
|
@@ -106,6 +108,9 @@
|
|
|
106
108
|
},
|
|
107
109
|
"react-native-reanimated": {
|
|
108
110
|
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"react-native-safe-area-context": {
|
|
113
|
+
"optional": true
|
|
109
114
|
}
|
|
110
115
|
},
|
|
111
116
|
"workspaces": [
|
|
@@ -182,6 +187,6 @@
|
|
|
182
187
|
"nanoid": "^5.1.6",
|
|
183
188
|
"path-to-regexp": "^8.3.0",
|
|
184
189
|
"query-string": "^9.3.1",
|
|
185
|
-
"react-transition-state": "^2.3.
|
|
190
|
+
"react-transition-state": "^2.3.3"
|
|
186
191
|
}
|
|
187
192
|
}
|