@terreno/ui 0.11.4-beta.2 → 0.11.4-beta.3
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/dist/Common.d.ts +13 -0
- package/dist/SidebarNavigation.native.d.ts +9 -17
- package/dist/SidebarNavigation.native.js +167 -103
- package/dist/SidebarNavigation.native.js.map +1 -1
- package/package.json +1 -1
- package/src/Common.ts +13 -0
- package/src/SidebarNavigation.native.tsx +275 -158
package/dist/Common.d.ts
CHANGED
|
@@ -2533,5 +2533,18 @@ export interface SidebarNavigationPanelProps {
|
|
|
2533
2533
|
* Additional styles applied to each navigation item.
|
|
2534
2534
|
*/
|
|
2535
2535
|
itemStyle?: StyleProp<ViewStyle>;
|
|
2536
|
+
/**
|
|
2537
|
+
* Controlled open state. When provided, the panel hides its internal hamburger
|
|
2538
|
+
* button and defers open/close to the caller.
|
|
2539
|
+
*
|
|
2540
|
+
* @platform mobile — the web sidebar is always visible; this prop is ignored on web.
|
|
2541
|
+
*/
|
|
2542
|
+
isOpen?: boolean;
|
|
2543
|
+
/**
|
|
2544
|
+
* Called when the panel requests an open or close (controlled mode only).
|
|
2545
|
+
*
|
|
2546
|
+
* @platform mobile — the web sidebar is always visible; this prop is ignored on web.
|
|
2547
|
+
*/
|
|
2548
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
2536
2549
|
}
|
|
2537
2550
|
export {};
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
+
import { Screen } from "expo-router/build/views/Screen";
|
|
1
2
|
import { type FC } from "react";
|
|
2
3
|
import type { SidebarNavigationPanelProps, SidebarNavigationProps } from "./Common";
|
|
3
4
|
/**
|
|
4
|
-
* Renders the
|
|
5
|
-
*/
|
|
6
|
-
export declare const SidebarNavigationPanel: FC<SidebarNavigationPanelProps>;
|
|
7
|
-
/**
|
|
8
|
-
* Custom expo-router navigator with a hamburger-triggered slide-in drawer.
|
|
9
|
-
* Use in _layout.tsx files:
|
|
5
|
+
* Renders the bottom sheet overlay and children. Works without expo-router Navigator context.
|
|
10
6
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* <SidebarNavigation
|
|
15
|
-
* topItems={[{label: "Home", route: "index", iconName: "house"}]}
|
|
16
|
-
* bottomItems={[{label: "Settings", route: "settings", iconName: "gear"}]}
|
|
17
|
-
* />
|
|
18
|
-
* );
|
|
19
|
-
* }
|
|
20
|
-
* ```
|
|
7
|
+
* Supports two modes:
|
|
8
|
+
* - Uncontrolled (default): manages open state internally and shows a floating hamburger button.
|
|
9
|
+
* - Controlled: caller provides isOpen + onOpenChange and owns the trigger (e.g. a header button).
|
|
21
10
|
*/
|
|
22
|
-
export declare const
|
|
11
|
+
export declare const SidebarNavigationPanel: FC<SidebarNavigationPanelProps>;
|
|
12
|
+
export declare const SidebarNavigation: FC<SidebarNavigationProps> & {
|
|
13
|
+
Screen: typeof Screen;
|
|
14
|
+
};
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { TabRouter } from "@react-navigation/native";
|
|
3
3
|
import { Navigator, Slot } from "expo-router";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// Screen is not exported from expo-router's public API (exports.d.ts only exposes ScreenProps).
|
|
5
|
+
// Stack.Screen and Tabs.Screen use this same internal path. If expo-router upgrades break this,
|
|
6
|
+
// update the import path here — this is the only place in the codebase that references it.
|
|
7
|
+
// eslint-disable-next-line import/no-internal-modules
|
|
8
|
+
import { Screen } from "expo-router/build/views/Screen";
|
|
9
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { Animated, Dimensions, PanResponder, Pressable, View, } from "react-native";
|
|
11
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
12
|
import { Badge } from "./Badge";
|
|
7
13
|
import { SIDEBAR_BADGE_STATUS_MAP } from "./Common";
|
|
8
14
|
import { Icon } from "./Icon";
|
|
9
15
|
import { Text } from "./Text";
|
|
10
16
|
import { useTheme } from "./Theme";
|
|
11
|
-
const
|
|
12
|
-
const ITEM_HEIGHT = 48;
|
|
17
|
+
const ITEM_HEIGHT = 44;
|
|
13
18
|
const ICON_SIZE = 20;
|
|
14
19
|
const BACKDROP_OPACITY = 0.5;
|
|
15
|
-
const ANIMATION_DURATION =
|
|
20
|
+
const ANIMATION_DURATION = 300;
|
|
21
|
+
const DISMISS_THRESHOLD = 0.3;
|
|
16
22
|
const SidebarItem = ({ item, isActive, onPress, itemStyle }) => {
|
|
17
23
|
var _a;
|
|
18
24
|
const { theme } = useTheme();
|
|
@@ -22,136 +28,192 @@ const SidebarItem = ({ item, isActive, onPress, itemStyle }) => {
|
|
|
22
28
|
return (_jsxs(Pressable, { accessibilityLabel: item.label, accessibilityRole: "button", onPress: handlePress, style: [
|
|
23
29
|
{
|
|
24
30
|
alignItems: "center",
|
|
25
|
-
backgroundColor: isActive ? theme.surface.
|
|
31
|
+
backgroundColor: isActive ? theme.surface.neutralLight : "transparent",
|
|
26
32
|
borderRadius: theme.radius.default,
|
|
27
33
|
flexDirection: "row",
|
|
28
|
-
gap:
|
|
34
|
+
gap: 12,
|
|
29
35
|
height: ITEM_HEIGHT,
|
|
30
|
-
marginHorizontal:
|
|
31
|
-
paddingHorizontal:
|
|
36
|
+
marginHorizontal: 8,
|
|
37
|
+
paddingHorizontal: 12,
|
|
32
38
|
},
|
|
33
39
|
itemStyle,
|
|
34
|
-
], children: [_jsxs(View, { style: { alignItems: "center", justifyContent: "center", width: ICON_SIZE }, children: [_jsx(Icon, { color: isActive ? "primary" : "
|
|
40
|
+
], children: [_jsxs(View, { style: { alignItems: "center", justifyContent: "center", width: ICON_SIZE }, children: [_jsx(Icon, { color: isActive ? "primary" : "secondaryLight", iconName: item.iconName, size: "lg" }), Boolean(item.badge) && (_jsx(View, { style: {
|
|
35
41
|
bottom: item.badge === true ? -4 : undefined,
|
|
36
42
|
position: "absolute",
|
|
37
43
|
right: -6,
|
|
38
44
|
top: item.badge === true ? undefined : -4,
|
|
39
|
-
}, children: _jsx(Badge, { maxValue: 99, status: SIDEBAR_BADGE_STATUS_MAP[(_a = item.badgeStatus) !== null && _a !== void 0 ? _a : "error"], value: item.badge === true ? undefined : String(item.badge), variant: item.badge === true ? "iconOnly" : "numberOnly" }) }))] }), _jsx(Text, { bold: isActive, color: isActive ? "primary" : "
|
|
45
|
+
}, children: _jsx(Badge, { maxValue: 99, status: SIDEBAR_BADGE_STATUS_MAP[(_a = item.badgeStatus) !== null && _a !== void 0 ? _a : "error"], value: item.badge === true ? undefined : String(item.badge), variant: item.badge === true ? "iconOnly" : "numberOnly" }) }))] }), _jsx(Text, { bold: isActive, color: isActive ? "primary" : "secondaryLight", size: "md", children: item.label })] }));
|
|
40
46
|
};
|
|
47
|
+
const SidebarHamburger = ({ onOpen }) => (_jsx(Pressable, { accessibilityLabel: "Open navigation menu", accessibilityRole: "button", onPress: onOpen, style: { alignItems: "center", height: 40, justifyContent: "center", width: 40 }, children: _jsx(Icon, { color: "primary", iconName: "bars", size: "md" }) }));
|
|
41
48
|
/**
|
|
42
|
-
* Renders the
|
|
49
|
+
* Renders the bottom sheet overlay and children. Works without expo-router Navigator context.
|
|
50
|
+
*
|
|
51
|
+
* Supports two modes:
|
|
52
|
+
* - Uncontrolled (default): manages open state internally and shows a floating hamburger button.
|
|
53
|
+
* - Controlled: caller provides isOpen + onOpenChange and owns the trigger (e.g. a header button).
|
|
43
54
|
*/
|
|
44
|
-
export const SidebarNavigationPanel = ({ topItems, bottomItems, activeRoute, onNavigate, children, panelStyle, itemStyle, }) => {
|
|
55
|
+
export const SidebarNavigationPanel = ({ topItems, bottomItems, activeRoute, onNavigate, children, panelStyle, itemStyle, isOpen: isOpenProp, onOpenChange, }) => {
|
|
45
56
|
const { theme } = useTheme();
|
|
46
|
-
const
|
|
47
|
-
const
|
|
57
|
+
const insets = useSafeAreaInsets();
|
|
58
|
+
const isControlled = isOpenProp !== undefined;
|
|
59
|
+
const [isOpenInternal, setIsOpenInternal] = useState(false);
|
|
60
|
+
const isOpen = isControlled ? isOpenProp : isOpenInternal;
|
|
61
|
+
const sheetHeight = useMemo(() => Dimensions.get("window").height * 0.65, []);
|
|
62
|
+
const slideAnim = useRef(new Animated.Value(sheetHeight)).current;
|
|
48
63
|
const backdropAnim = useRef(new Animated.Value(0)).current;
|
|
49
|
-
|
|
64
|
+
const capturedSlideValue = useRef(0);
|
|
65
|
+
// Play open animation whenever isOpen becomes true
|
|
50
66
|
useEffect(() => {
|
|
51
|
-
if (isOpen) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
if (!isOpen) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
slideAnim.setValue(sheetHeight);
|
|
71
|
+
backdropAnim.setValue(0);
|
|
72
|
+
Animated.parallel([
|
|
73
|
+
Animated.timing(slideAnim, {
|
|
74
|
+
duration: ANIMATION_DURATION,
|
|
75
|
+
toValue: 0,
|
|
76
|
+
useNativeDriver: true,
|
|
77
|
+
}),
|
|
78
|
+
Animated.timing(backdropAnim, {
|
|
79
|
+
duration: ANIMATION_DURATION,
|
|
80
|
+
toValue: BACKDROP_OPACITY,
|
|
81
|
+
useNativeDriver: true,
|
|
82
|
+
}),
|
|
83
|
+
]).start();
|
|
84
|
+
}, [isOpen, slideAnim, backdropAnim, sheetHeight]);
|
|
85
|
+
// Play close animation then update state
|
|
86
|
+
const handleClose = useCallback(() => {
|
|
87
|
+
Animated.parallel([
|
|
88
|
+
Animated.timing(slideAnim, {
|
|
89
|
+
duration: ANIMATION_DURATION,
|
|
90
|
+
toValue: sheetHeight,
|
|
91
|
+
useNativeDriver: true,
|
|
92
|
+
}),
|
|
93
|
+
Animated.timing(backdropAnim, {
|
|
94
|
+
duration: ANIMATION_DURATION,
|
|
95
|
+
toValue: 0,
|
|
96
|
+
useNativeDriver: true,
|
|
97
|
+
}),
|
|
98
|
+
]).start(() => {
|
|
99
|
+
if (isControlled) {
|
|
100
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(false);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
setIsOpenInternal(false);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}, [isControlled, onOpenChange, slideAnim, backdropAnim, sheetHeight]);
|
|
107
|
+
const handleOpen = useCallback(() => {
|
|
108
|
+
if (isControlled) {
|
|
109
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(true);
|
|
64
110
|
}
|
|
65
111
|
else {
|
|
66
|
-
|
|
67
|
-
Animated.timing(slideAnim, {
|
|
68
|
-
duration: ANIMATION_DURATION,
|
|
69
|
-
toValue: -DRAWER_WIDTH,
|
|
70
|
-
useNativeDriver: true,
|
|
71
|
-
}),
|
|
72
|
-
Animated.timing(backdropAnim, {
|
|
73
|
-
duration: ANIMATION_DURATION,
|
|
74
|
-
toValue: 0,
|
|
75
|
-
useNativeDriver: true,
|
|
76
|
-
}),
|
|
77
|
-
]).start();
|
|
112
|
+
setIsOpenInternal(true);
|
|
78
113
|
}
|
|
79
|
-
}, [
|
|
80
|
-
const handleOpen = useCallback(() => setIsOpen(true), []);
|
|
81
|
-
const handleClose = useCallback(() => setIsOpen(false), []);
|
|
114
|
+
}, [isControlled, onOpenChange]);
|
|
82
115
|
const handleNavigate = useCallback((route) => {
|
|
83
|
-
|
|
116
|
+
handleClose();
|
|
84
117
|
onNavigate(route);
|
|
85
|
-
}, [onNavigate]);
|
|
86
|
-
const
|
|
87
|
-
|
|
118
|
+
}, [handleClose, onNavigate]);
|
|
119
|
+
const panResponder = useMemo(() => PanResponder.create({
|
|
120
|
+
onMoveShouldSetPanResponder: (_, { dx, dy }) => Math.abs(dy) > Math.abs(dx) && dy > 4,
|
|
121
|
+
onPanResponderGrant: () => {
|
|
122
|
+
slideAnim.stopAnimation((value) => {
|
|
123
|
+
capturedSlideValue.current = value;
|
|
124
|
+
});
|
|
125
|
+
backdropAnim.stopAnimation();
|
|
126
|
+
},
|
|
127
|
+
onPanResponderMove: (_, { dy }) => {
|
|
128
|
+
const next = capturedSlideValue.current + dy;
|
|
129
|
+
if (next < 0) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
slideAnim.setValue(next);
|
|
133
|
+
backdropAnim.setValue(BACKDROP_OPACITY * Math.max(0, 1 - next / sheetHeight));
|
|
134
|
+
},
|
|
135
|
+
onPanResponderRelease: (_, { dy, vy }) => {
|
|
136
|
+
if (dy > sheetHeight * DISMISS_THRESHOLD || vy > 0.5) {
|
|
137
|
+
handleClose();
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
Animated.parallel([
|
|
141
|
+
Animated.timing(slideAnim, {
|
|
142
|
+
duration: 200,
|
|
143
|
+
toValue: 0,
|
|
144
|
+
useNativeDriver: true,
|
|
145
|
+
}),
|
|
146
|
+
Animated.timing(backdropAnim, {
|
|
147
|
+
duration: 200,
|
|
148
|
+
toValue: BACKDROP_OPACITY,
|
|
149
|
+
useNativeDriver: true,
|
|
150
|
+
}),
|
|
151
|
+
]).start();
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
}), [slideAnim, backdropAnim, sheetHeight, handleClose]);
|
|
155
|
+
return (_jsxs(View, { style: { flex: 1 }, children: [children, !isControlled && (_jsx(Pressable, { accessibilityLabel: "Open navigation menu", accessibilityRole: "button", onPress: handleOpen, style: {
|
|
88
156
|
alignItems: "center",
|
|
89
|
-
backgroundColor: theme.surface.primary,
|
|
90
|
-
borderRadius: theme.radius.full,
|
|
91
|
-
elevation: 4,
|
|
92
157
|
height: 44,
|
|
93
158
|
justifyContent: "center",
|
|
94
159
|
left: 16,
|
|
95
160
|
position: "absolute",
|
|
96
|
-
|
|
97
|
-
shadowOffset: { height: 2, width: 0 },
|
|
98
|
-
shadowOpacity: 0.25,
|
|
99
|
-
shadowRadius: 4,
|
|
100
|
-
top: 16,
|
|
161
|
+
top: insets.top + 16,
|
|
101
162
|
width: 44,
|
|
102
163
|
zIndex: 10,
|
|
103
|
-
}, children: _jsx(Icon, { color: "
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
paddingTop: 20,
|
|
124
|
-
position: "absolute",
|
|
125
|
-
top: 0,
|
|
126
|
-
transform: [{ translateX: slideAnim }],
|
|
127
|
-
width: DRAWER_WIDTH,
|
|
128
|
-
zIndex: 200,
|
|
129
|
-
},
|
|
130
|
-
panelStyle,
|
|
131
|
-
], children: [_jsxs(View, { children: [_jsx(Pressable, { accessibilityLabel: "Close navigation menu", accessibilityRole: "button", onPress: handleClose, style: {
|
|
132
|
-
alignItems: "center",
|
|
133
|
-
alignSelf: "flex-end",
|
|
134
|
-
height: 40,
|
|
135
|
-
justifyContent: "center",
|
|
136
|
-
marginRight: 12,
|
|
137
|
-
width: 40,
|
|
138
|
-
}, children: _jsx(Icon, { color: "secondaryDark", iconName: "xmark", size: "md" }) }), _jsx(View, { style: { gap: 4, marginTop: 8 }, children: topItems.map((item) => (_jsx(SidebarItem, { isActive: activeRoute === item.route, item: item, itemStyle: itemStyle, onPress: handleNavigate }, item.route))) })] }), _jsx(View, { style: { gap: 4 }, children: bottomItems.map((item) => (_jsx(SidebarItem, { isActive: activeRoute === item.route, item: item, onPress: handleNavigate }, item.route))) })] })] }));
|
|
164
|
+
}, children: _jsx(Icon, { color: "primary", iconName: "bars", size: "md" }) })), isOpen && (_jsxs(_Fragment, { children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: handleClose, style: { bottom: 0, left: 0, position: "absolute", right: 0, top: 0, zIndex: 100 }, children: _jsx(Animated.View, { style: { backgroundColor: "#000", flex: 1, opacity: backdropAnim } }) }), _jsxs(Animated.View, { style: [
|
|
165
|
+
{
|
|
166
|
+
backgroundColor: theme.surface.base,
|
|
167
|
+
borderTopLeftRadius: 16,
|
|
168
|
+
borderTopRightRadius: 16,
|
|
169
|
+
bottom: 0,
|
|
170
|
+
height: sheetHeight,
|
|
171
|
+
left: 0,
|
|
172
|
+
position: "absolute",
|
|
173
|
+
right: 0,
|
|
174
|
+
transform: [{ translateY: slideAnim }],
|
|
175
|
+
zIndex: 200,
|
|
176
|
+
},
|
|
177
|
+
panelStyle,
|
|
178
|
+
], children: [_jsx(View, Object.assign({}, panResponder.panHandlers, { accessibilityHint: "Drag down to close", accessibilityLabel: "Navigation menu drag handle", accessibilityRole: "adjustable", style: { alignItems: "center", paddingBottom: 8, paddingTop: 12 }, children: _jsx(View, { style: {
|
|
179
|
+
backgroundColor: theme.border.default,
|
|
180
|
+
borderRadius: 2,
|
|
181
|
+
height: 4,
|
|
182
|
+
width: 36,
|
|
183
|
+
} }) })), _jsx(View, { style: { gap: 4, paddingBottom: insets.bottom + 8 }, children: [...topItems, ...bottomItems].map((item) => (_jsx(SidebarItem, { isActive: activeRoute === item.route, item: item, itemStyle: itemStyle, onPress: handleNavigate }, item.route))) })] })] }))] }));
|
|
139
184
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
185
|
+
const SidebarHeader = ({ onOpen }) => {
|
|
186
|
+
var _a, _b;
|
|
187
|
+
const { theme } = useTheme();
|
|
188
|
+
const insets = useSafeAreaInsets();
|
|
189
|
+
const { state, descriptors } = Navigator.useContext();
|
|
190
|
+
const activeRoute = state.routes[state.index];
|
|
191
|
+
const { headerLeft, headerRight, title } = ((_b = (_a = descriptors[activeRoute === null || activeRoute === void 0 ? void 0 : activeRoute.key]) === null || _a === void 0 ? void 0 : _a.options) !== null && _b !== void 0 ? _b : {});
|
|
192
|
+
return (_jsx(View, { style: {
|
|
193
|
+
backgroundColor: theme.surface.base,
|
|
194
|
+
borderBottomColor: theme.border.default,
|
|
195
|
+
borderBottomWidth: 1,
|
|
196
|
+
paddingTop: insets.top,
|
|
197
|
+
}, children: _jsxs(View, { style: {
|
|
198
|
+
alignItems: "center",
|
|
199
|
+
flexDirection: "row",
|
|
200
|
+
height: 44,
|
|
201
|
+
justifyContent: "space-between",
|
|
202
|
+
paddingHorizontal: 16,
|
|
203
|
+
}, children: [_jsxs(View, { style: { alignItems: "center", flexDirection: "row", gap: 12 }, children: [_jsx(SidebarHamburger, { onOpen: onOpen }), headerLeft === null || headerLeft === void 0 ? void 0 : headerLeft({}), Boolean(title) && (_jsx(Text, { bold: true, size: "lg", children: title }))] }), Boolean(headerRight) && _jsx(View, { style: { alignItems: "flex-end" }, children: headerRight === null || headerRight === void 0 ? void 0 : headerRight({}) })] }) }));
|
|
204
|
+
};
|
|
205
|
+
/** Renders the content panel and bottom sheet for the active screen. */
|
|
206
|
+
const SidebarNavigatorContent = ({ topItems, bottomItems, isOpen, onOpenChange, onNavigate, panelStyle, itemStyle }) => {
|
|
145
207
|
const { state, navigation } = Navigator.useContext();
|
|
146
|
-
const activeRoute =
|
|
208
|
+
const activeRoute = state.routes[state.index];
|
|
147
209
|
const handleNavigate = useCallback((route) => {
|
|
148
210
|
navigation.navigate(route);
|
|
149
211
|
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(route);
|
|
150
212
|
}, [navigation, onNavigate]);
|
|
151
|
-
return (_jsx(SidebarNavigationPanel, { activeRoute: activeRoute, bottomItems: bottomItems, itemStyle: itemStyle, onNavigate: handleNavigate, panelStyle: panelStyle, topItems: topItems, children: _jsx(Slot, {}) }));
|
|
213
|
+
return (_jsx(SidebarNavigationPanel, { activeRoute: activeRoute === null || activeRoute === void 0 ? void 0 : activeRoute.name, bottomItems: bottomItems, isOpen: isOpen, itemStyle: itemStyle, onNavigate: handleNavigate, onOpenChange: onOpenChange, panelStyle: panelStyle, topItems: topItems, children: _jsx(Slot, {}) }));
|
|
152
214
|
};
|
|
153
215
|
/**
|
|
154
|
-
* Custom expo-router navigator with a hamburger-triggered
|
|
216
|
+
* Custom expo-router navigator with a header bar and hamburger-triggered bottom sheet.
|
|
155
217
|
* Use in _layout.tsx files:
|
|
156
218
|
*
|
|
157
219
|
* ```tsx
|
|
@@ -165,7 +227,9 @@ const SidebarNavigatorContent = ({ topItems, bottomItems, onNavigate, panelStyle
|
|
|
165
227
|
* }
|
|
166
228
|
* ```
|
|
167
229
|
*/
|
|
168
|
-
|
|
169
|
-
|
|
230
|
+
const SidebarNavigationBase = ({ topItems, bottomItems, onNavigate, initialRouteName, screenOptions, panelStyle, itemStyle, children, }) => {
|
|
231
|
+
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
232
|
+
return (_jsxs(Navigator, { initialRouteName: initialRouteName, router: TabRouter, screenOptions: screenOptions, children: [_jsxs(View, { style: { flex: 1 }, children: [_jsx(SidebarHeader, { onOpen: () => setIsSheetOpen(true) }), _jsx(SidebarNavigatorContent, { bottomItems: bottomItems, isOpen: isSheetOpen, itemStyle: itemStyle, onNavigate: onNavigate, onOpenChange: setIsSheetOpen, panelStyle: panelStyle, topItems: topItems })] }), children] }));
|
|
170
233
|
};
|
|
234
|
+
export const SidebarNavigation = Object.assign(SidebarNavigationBase, { Screen });
|
|
171
235
|
//# sourceMappingURL=SidebarNavigation.native.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SidebarNavigation.native.js","sourceRoot":"","sources":["../src/SidebarNavigation.native.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SidebarNavigation.native.js","sourceRoot":"","sources":["../src/SidebarNavigation.native.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/Common.ts
CHANGED
|
@@ -3044,4 +3044,17 @@ export interface SidebarNavigationPanelProps {
|
|
|
3044
3044
|
* Additional styles applied to each navigation item.
|
|
3045
3045
|
*/
|
|
3046
3046
|
itemStyle?: StyleProp<ViewStyle>;
|
|
3047
|
+
/**
|
|
3048
|
+
* Controlled open state. When provided, the panel hides its internal hamburger
|
|
3049
|
+
* button and defers open/close to the caller.
|
|
3050
|
+
*
|
|
3051
|
+
* @platform mobile — the web sidebar is always visible; this prop is ignored on web.
|
|
3052
|
+
*/
|
|
3053
|
+
isOpen?: boolean;
|
|
3054
|
+
/**
|
|
3055
|
+
* Called when the panel requests an open or close (controlled mode only).
|
|
3056
|
+
*
|
|
3057
|
+
* @platform mobile — the web sidebar is always visible; this prop is ignored on web.
|
|
3058
|
+
*/
|
|
3059
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
3047
3060
|
}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import {TabRouter} from "@react-navigation/native";
|
|
2
2
|
import {Navigator, Slot} from "expo-router";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// Screen is not exported from expo-router's public API (exports.d.ts only exposes ScreenProps).
|
|
4
|
+
// Stack.Screen and Tabs.Screen use this same internal path. If expo-router upgrades break this,
|
|
5
|
+
// update the import path here — this is the only place in the codebase that references it.
|
|
6
|
+
// eslint-disable-next-line import/no-internal-modules
|
|
7
|
+
import {Screen} from "expo-router/build/views/Screen";
|
|
8
|
+
import {type FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
|
|
9
|
+
import {
|
|
10
|
+
Animated,
|
|
11
|
+
Dimensions,
|
|
12
|
+
PanResponder,
|
|
13
|
+
Pressable,
|
|
14
|
+
type StyleProp,
|
|
15
|
+
View,
|
|
16
|
+
type ViewStyle,
|
|
17
|
+
} from "react-native";
|
|
18
|
+
import {useSafeAreaInsets} from "react-native-safe-area-context";
|
|
5
19
|
|
|
6
20
|
import {Badge} from "./Badge";
|
|
7
21
|
import type {
|
|
@@ -14,11 +28,11 @@ import {Icon} from "./Icon";
|
|
|
14
28
|
import {Text} from "./Text";
|
|
15
29
|
import {useTheme} from "./Theme";
|
|
16
30
|
|
|
17
|
-
const
|
|
18
|
-
const ITEM_HEIGHT = 48;
|
|
31
|
+
const ITEM_HEIGHT = 44;
|
|
19
32
|
const ICON_SIZE = 20;
|
|
20
33
|
const BACKDROP_OPACITY = 0.5;
|
|
21
|
-
const ANIMATION_DURATION =
|
|
34
|
+
const ANIMATION_DURATION = 300;
|
|
35
|
+
const DISMISS_THRESHOLD = 0.3;
|
|
22
36
|
|
|
23
37
|
const SidebarItem: FC<{
|
|
24
38
|
item: SidebarNavigationItem;
|
|
@@ -40,19 +54,19 @@ const SidebarItem: FC<{
|
|
|
40
54
|
style={[
|
|
41
55
|
{
|
|
42
56
|
alignItems: "center",
|
|
43
|
-
backgroundColor: isActive ? theme.surface.
|
|
57
|
+
backgroundColor: isActive ? theme.surface.neutralLight : "transparent",
|
|
44
58
|
borderRadius: theme.radius.default,
|
|
45
59
|
flexDirection: "row",
|
|
46
|
-
gap:
|
|
60
|
+
gap: 12,
|
|
47
61
|
height: ITEM_HEIGHT,
|
|
48
|
-
marginHorizontal:
|
|
49
|
-
paddingHorizontal:
|
|
62
|
+
marginHorizontal: 8,
|
|
63
|
+
paddingHorizontal: 12,
|
|
50
64
|
},
|
|
51
65
|
itemStyle,
|
|
52
66
|
]}
|
|
53
67
|
>
|
|
54
68
|
<View style={{alignItems: "center", justifyContent: "center", width: ICON_SIZE}}>
|
|
55
|
-
<Icon color={isActive ? "primary" : "
|
|
69
|
+
<Icon color={isActive ? "primary" : "secondaryLight"} iconName={item.iconName} size="lg" />
|
|
56
70
|
{Boolean(item.badge) && (
|
|
57
71
|
<View
|
|
58
72
|
style={{
|
|
@@ -71,15 +85,30 @@ const SidebarItem: FC<{
|
|
|
71
85
|
</View>
|
|
72
86
|
)}
|
|
73
87
|
</View>
|
|
74
|
-
<Text bold={isActive} color={isActive ? "primary" : "
|
|
88
|
+
<Text bold={isActive} color={isActive ? "primary" : "secondaryLight"} size="md">
|
|
75
89
|
{item.label}
|
|
76
90
|
</Text>
|
|
77
91
|
</Pressable>
|
|
78
92
|
);
|
|
79
93
|
};
|
|
80
94
|
|
|
95
|
+
const SidebarHamburger: FC<{onOpen: () => void}> = ({onOpen}) => (
|
|
96
|
+
<Pressable
|
|
97
|
+
accessibilityLabel="Open navigation menu"
|
|
98
|
+
accessibilityRole="button"
|
|
99
|
+
onPress={onOpen}
|
|
100
|
+
style={{alignItems: "center", height: 40, justifyContent: "center", width: 40}}
|
|
101
|
+
>
|
|
102
|
+
<Icon color="primary" iconName="bars" size="md" />
|
|
103
|
+
</Pressable>
|
|
104
|
+
);
|
|
105
|
+
|
|
81
106
|
/**
|
|
82
|
-
* Renders the
|
|
107
|
+
* Renders the bottom sheet overlay and children. Works without expo-router Navigator context.
|
|
108
|
+
*
|
|
109
|
+
* Supports two modes:
|
|
110
|
+
* - Uncontrolled (default): manages open state internally and shows a floating hamburger button.
|
|
111
|
+
* - Controlled: caller provides isOpen + onOpenChange and owns the trigger (e.g. a header button).
|
|
83
112
|
*/
|
|
84
113
|
export const SidebarNavigationPanel: FC<SidebarNavigationPanelProps> = ({
|
|
85
114
|
topItems,
|
|
@@ -89,187 +118,262 @@ export const SidebarNavigationPanel: FC<SidebarNavigationPanelProps> = ({
|
|
|
89
118
|
children,
|
|
90
119
|
panelStyle,
|
|
91
120
|
itemStyle,
|
|
121
|
+
isOpen: isOpenProp,
|
|
122
|
+
onOpenChange,
|
|
92
123
|
}) => {
|
|
93
124
|
const {theme} = useTheme();
|
|
94
|
-
const
|
|
95
|
-
const
|
|
125
|
+
const insets = useSafeAreaInsets();
|
|
126
|
+
const isControlled = isOpenProp !== undefined;
|
|
127
|
+
const [isOpenInternal, setIsOpenInternal] = useState(false);
|
|
128
|
+
const isOpen = isControlled ? isOpenProp : isOpenInternal;
|
|
129
|
+
|
|
130
|
+
const sheetHeight = useMemo(() => Dimensions.get("window").height * 0.65, []);
|
|
131
|
+
const slideAnim = useRef(new Animated.Value(sheetHeight)).current;
|
|
96
132
|
const backdropAnim = useRef(new Animated.Value(0)).current;
|
|
133
|
+
const capturedSlideValue = useRef(0);
|
|
97
134
|
|
|
98
|
-
//
|
|
135
|
+
// Play open animation whenever isOpen becomes true
|
|
99
136
|
useEffect(() => {
|
|
100
|
-
if (isOpen) {
|
|
101
|
-
|
|
102
|
-
Animated.timing(slideAnim, {
|
|
103
|
-
duration: ANIMATION_DURATION,
|
|
104
|
-
toValue: 0,
|
|
105
|
-
useNativeDriver: true,
|
|
106
|
-
}),
|
|
107
|
-
Animated.timing(backdropAnim, {
|
|
108
|
-
duration: ANIMATION_DURATION,
|
|
109
|
-
toValue: BACKDROP_OPACITY,
|
|
110
|
-
useNativeDriver: true,
|
|
111
|
-
}),
|
|
112
|
-
]).start();
|
|
113
|
-
} else {
|
|
114
|
-
Animated.parallel([
|
|
115
|
-
Animated.timing(slideAnim, {
|
|
116
|
-
duration: ANIMATION_DURATION,
|
|
117
|
-
toValue: -DRAWER_WIDTH,
|
|
118
|
-
useNativeDriver: true,
|
|
119
|
-
}),
|
|
120
|
-
Animated.timing(backdropAnim, {
|
|
121
|
-
duration: ANIMATION_DURATION,
|
|
122
|
-
toValue: 0,
|
|
123
|
-
useNativeDriver: true,
|
|
124
|
-
}),
|
|
125
|
-
]).start();
|
|
137
|
+
if (!isOpen) {
|
|
138
|
+
return;
|
|
126
139
|
}
|
|
127
|
-
|
|
140
|
+
slideAnim.setValue(sheetHeight);
|
|
141
|
+
backdropAnim.setValue(0);
|
|
142
|
+
Animated.parallel([
|
|
143
|
+
Animated.timing(slideAnim, {
|
|
144
|
+
duration: ANIMATION_DURATION,
|
|
145
|
+
toValue: 0,
|
|
146
|
+
useNativeDriver: true,
|
|
147
|
+
}),
|
|
148
|
+
Animated.timing(backdropAnim, {
|
|
149
|
+
duration: ANIMATION_DURATION,
|
|
150
|
+
toValue: BACKDROP_OPACITY,
|
|
151
|
+
useNativeDriver: true,
|
|
152
|
+
}),
|
|
153
|
+
]).start();
|
|
154
|
+
}, [isOpen, slideAnim, backdropAnim, sheetHeight]);
|
|
128
155
|
|
|
129
|
-
|
|
130
|
-
const handleClose = useCallback(() =>
|
|
156
|
+
// Play close animation then update state
|
|
157
|
+
const handleClose = useCallback(() => {
|
|
158
|
+
Animated.parallel([
|
|
159
|
+
Animated.timing(slideAnim, {
|
|
160
|
+
duration: ANIMATION_DURATION,
|
|
161
|
+
toValue: sheetHeight,
|
|
162
|
+
useNativeDriver: true,
|
|
163
|
+
}),
|
|
164
|
+
Animated.timing(backdropAnim, {
|
|
165
|
+
duration: ANIMATION_DURATION,
|
|
166
|
+
toValue: 0,
|
|
167
|
+
useNativeDriver: true,
|
|
168
|
+
}),
|
|
169
|
+
]).start(() => {
|
|
170
|
+
if (isControlled) {
|
|
171
|
+
onOpenChange?.(false);
|
|
172
|
+
} else {
|
|
173
|
+
setIsOpenInternal(false);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}, [isControlled, onOpenChange, slideAnim, backdropAnim, sheetHeight]);
|
|
177
|
+
|
|
178
|
+
const handleOpen = useCallback(() => {
|
|
179
|
+
if (isControlled) {
|
|
180
|
+
onOpenChange?.(true);
|
|
181
|
+
} else {
|
|
182
|
+
setIsOpenInternal(true);
|
|
183
|
+
}
|
|
184
|
+
}, [isControlled, onOpenChange]);
|
|
131
185
|
|
|
132
186
|
const handleNavigate = useCallback(
|
|
133
187
|
(route: string) => {
|
|
134
|
-
|
|
188
|
+
handleClose();
|
|
135
189
|
onNavigate(route);
|
|
136
190
|
},
|
|
137
|
-
[onNavigate]
|
|
191
|
+
[handleClose, onNavigate]
|
|
138
192
|
);
|
|
139
193
|
|
|
140
|
-
const
|
|
194
|
+
const panResponder = useMemo(
|
|
195
|
+
() =>
|
|
196
|
+
PanResponder.create({
|
|
197
|
+
onMoveShouldSetPanResponder: (_, {dx, dy}) => Math.abs(dy) > Math.abs(dx) && dy > 4,
|
|
198
|
+
onPanResponderGrant: () => {
|
|
199
|
+
slideAnim.stopAnimation((value) => {
|
|
200
|
+
capturedSlideValue.current = value;
|
|
201
|
+
});
|
|
202
|
+
backdropAnim.stopAnimation();
|
|
203
|
+
},
|
|
204
|
+
onPanResponderMove: (_, {dy}) => {
|
|
205
|
+
const next = capturedSlideValue.current + dy;
|
|
206
|
+
if (next < 0) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
slideAnim.setValue(next);
|
|
210
|
+
backdropAnim.setValue(BACKDROP_OPACITY * Math.max(0, 1 - next / sheetHeight));
|
|
211
|
+
},
|
|
212
|
+
onPanResponderRelease: (_, {dy, vy}) => {
|
|
213
|
+
if (dy > sheetHeight * DISMISS_THRESHOLD || vy > 0.5) {
|
|
214
|
+
handleClose();
|
|
215
|
+
} else {
|
|
216
|
+
Animated.parallel([
|
|
217
|
+
Animated.timing(slideAnim, {
|
|
218
|
+
duration: 200,
|
|
219
|
+
toValue: 0,
|
|
220
|
+
useNativeDriver: true,
|
|
221
|
+
}),
|
|
222
|
+
Animated.timing(backdropAnim, {
|
|
223
|
+
duration: 200,
|
|
224
|
+
toValue: BACKDROP_OPACITY,
|
|
225
|
+
useNativeDriver: true,
|
|
226
|
+
}),
|
|
227
|
+
]).start();
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
[slideAnim, backdropAnim, sheetHeight, handleClose]
|
|
232
|
+
);
|
|
141
233
|
|
|
142
234
|
return (
|
|
143
235
|
<View style={{flex: 1}}>
|
|
144
236
|
{children}
|
|
145
237
|
|
|
146
|
-
{/*
|
|
147
|
-
|
|
148
|
-
accessibilityLabel="Open navigation menu"
|
|
149
|
-
accessibilityRole="button"
|
|
150
|
-
onPress={handleOpen}
|
|
151
|
-
style={{
|
|
152
|
-
alignItems: "center",
|
|
153
|
-
backgroundColor: theme.surface.primary,
|
|
154
|
-
borderRadius: theme.radius.full,
|
|
155
|
-
elevation: 4,
|
|
156
|
-
height: 44,
|
|
157
|
-
justifyContent: "center",
|
|
158
|
-
left: 16,
|
|
159
|
-
position: "absolute",
|
|
160
|
-
shadowColor: "#000",
|
|
161
|
-
shadowOffset: {height: 2, width: 0},
|
|
162
|
-
shadowOpacity: 0.25,
|
|
163
|
-
shadowRadius: 4,
|
|
164
|
-
top: 16,
|
|
165
|
-
width: 44,
|
|
166
|
-
zIndex: 10,
|
|
167
|
-
}}
|
|
168
|
-
>
|
|
169
|
-
<Icon color="inverted" iconName="bars" size="md" />
|
|
170
|
-
</Pressable>
|
|
171
|
-
|
|
172
|
-
{/* Backdrop */}
|
|
173
|
-
{isOpen && (
|
|
238
|
+
{/* Floating hamburger — only shown in uncontrolled (standalone) mode */}
|
|
239
|
+
{!isControlled && (
|
|
174
240
|
<Pressable
|
|
175
|
-
|
|
241
|
+
accessibilityLabel="Open navigation menu"
|
|
242
|
+
accessibilityRole="button"
|
|
243
|
+
onPress={handleOpen}
|
|
176
244
|
style={{
|
|
177
|
-
|
|
178
|
-
|
|
245
|
+
alignItems: "center",
|
|
246
|
+
height: 44,
|
|
247
|
+
justifyContent: "center",
|
|
248
|
+
left: 16,
|
|
179
249
|
position: "absolute",
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
zIndex:
|
|
250
|
+
top: insets.top + 16,
|
|
251
|
+
width: 44,
|
|
252
|
+
zIndex: 10,
|
|
183
253
|
}}
|
|
184
254
|
>
|
|
185
|
-
<
|
|
186
|
-
style={{
|
|
187
|
-
backgroundColor: "#000",
|
|
188
|
-
flex: 1,
|
|
189
|
-
opacity: backdropAnim,
|
|
190
|
-
}}
|
|
191
|
-
/>
|
|
255
|
+
<Icon color="primary" iconName="bars" size="md" />
|
|
192
256
|
</Pressable>
|
|
193
257
|
)}
|
|
194
258
|
|
|
195
|
-
{
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
backgroundColor: theme.surface.base,
|
|
200
|
-
borderColor: theme.border.default,
|
|
201
|
-
borderRightWidth: 1,
|
|
202
|
-
height: screenHeight,
|
|
203
|
-
justifyContent: "space-between",
|
|
204
|
-
left: 0,
|
|
205
|
-
paddingBottom: 32,
|
|
206
|
-
paddingTop: 20,
|
|
207
|
-
position: "absolute",
|
|
208
|
-
top: 0,
|
|
209
|
-
transform: [{translateX: slideAnim}],
|
|
210
|
-
width: DRAWER_WIDTH,
|
|
211
|
-
zIndex: 200,
|
|
212
|
-
},
|
|
213
|
-
panelStyle,
|
|
214
|
-
]}
|
|
215
|
-
>
|
|
216
|
-
{/* Close button */}
|
|
217
|
-
<View>
|
|
259
|
+
{isOpen && (
|
|
260
|
+
<>
|
|
261
|
+
{/* Backdrop */}
|
|
218
262
|
<Pressable
|
|
219
|
-
|
|
220
|
-
accessibilityRole="button"
|
|
263
|
+
accessibilityElementsHidden
|
|
221
264
|
onPress={handleClose}
|
|
222
|
-
style={{
|
|
223
|
-
alignItems: "center",
|
|
224
|
-
alignSelf: "flex-end",
|
|
225
|
-
height: 40,
|
|
226
|
-
justifyContent: "center",
|
|
227
|
-
marginRight: 12,
|
|
228
|
-
width: 40,
|
|
229
|
-
}}
|
|
265
|
+
style={{bottom: 0, left: 0, position: "absolute", right: 0, top: 0, zIndex: 100}}
|
|
230
266
|
>
|
|
231
|
-
<
|
|
267
|
+
<Animated.View style={{backgroundColor: "#000", flex: 1, opacity: backdropAnim}} />
|
|
232
268
|
</Pressable>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
269
|
+
|
|
270
|
+
{/* Bottom sheet */}
|
|
271
|
+
<Animated.View
|
|
272
|
+
style={[
|
|
273
|
+
{
|
|
274
|
+
backgroundColor: theme.surface.base,
|
|
275
|
+
borderTopLeftRadius: 16,
|
|
276
|
+
borderTopRightRadius: 16,
|
|
277
|
+
bottom: 0,
|
|
278
|
+
height: sheetHeight,
|
|
279
|
+
left: 0,
|
|
280
|
+
position: "absolute",
|
|
281
|
+
right: 0,
|
|
282
|
+
transform: [{translateY: slideAnim}],
|
|
283
|
+
zIndex: 200,
|
|
284
|
+
},
|
|
285
|
+
panelStyle,
|
|
286
|
+
]}
|
|
287
|
+
>
|
|
288
|
+
{/* Drag bar */}
|
|
289
|
+
<View
|
|
290
|
+
{...panResponder.panHandlers}
|
|
291
|
+
accessibilityHint="Drag down to close"
|
|
292
|
+
accessibilityLabel="Navigation menu drag handle"
|
|
293
|
+
accessibilityRole="adjustable"
|
|
294
|
+
style={{alignItems: "center", paddingBottom: 8, paddingTop: 12}}
|
|
295
|
+
>
|
|
296
|
+
<View
|
|
297
|
+
style={{
|
|
298
|
+
backgroundColor: theme.border.default,
|
|
299
|
+
borderRadius: 2,
|
|
300
|
+
height: 4,
|
|
301
|
+
width: 36,
|
|
302
|
+
}}
|
|
241
303
|
/>
|
|
242
|
-
|
|
243
|
-
</View>
|
|
244
|
-
</View>
|
|
304
|
+
</View>
|
|
245
305
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
306
|
+
{/* Nav items */}
|
|
307
|
+
<View style={{gap: 4, paddingBottom: insets.bottom + 8}}>
|
|
308
|
+
{[...topItems, ...bottomItems].map((item) => (
|
|
309
|
+
<SidebarItem
|
|
310
|
+
isActive={activeRoute === item.route}
|
|
311
|
+
item={item}
|
|
312
|
+
itemStyle={itemStyle}
|
|
313
|
+
key={item.route}
|
|
314
|
+
onPress={handleNavigate}
|
|
315
|
+
/>
|
|
316
|
+
))}
|
|
317
|
+
</View>
|
|
318
|
+
</Animated.View>
|
|
319
|
+
</>
|
|
320
|
+
)}
|
|
321
|
+
</View>
|
|
322
|
+
);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const SidebarHeader: FC<{onOpen: () => void}> = ({onOpen}) => {
|
|
326
|
+
const {theme} = useTheme();
|
|
327
|
+
const insets = useSafeAreaInsets();
|
|
328
|
+
const {state, descriptors} = Navigator.useContext();
|
|
329
|
+
const activeRoute = state.routes[state.index];
|
|
330
|
+
const {headerLeft, headerRight, title} = (descriptors[activeRoute?.key]?.options ?? {}) as any;
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<View
|
|
334
|
+
style={{
|
|
335
|
+
backgroundColor: theme.surface.base,
|
|
336
|
+
borderBottomColor: theme.border.default,
|
|
337
|
+
borderBottomWidth: 1,
|
|
338
|
+
paddingTop: insets.top,
|
|
339
|
+
}}
|
|
340
|
+
>
|
|
341
|
+
<View
|
|
342
|
+
style={{
|
|
343
|
+
alignItems: "center",
|
|
344
|
+
flexDirection: "row",
|
|
345
|
+
height: 44,
|
|
346
|
+
justifyContent: "space-between",
|
|
347
|
+
paddingHorizontal: 16,
|
|
348
|
+
}}
|
|
349
|
+
>
|
|
350
|
+
<View style={{alignItems: "center", flexDirection: "row", gap: 12}}>
|
|
351
|
+
<SidebarHamburger onOpen={onOpen} />
|
|
352
|
+
{headerLeft?.({})}
|
|
353
|
+
{Boolean(title) && (
|
|
354
|
+
<Text bold size="lg">
|
|
355
|
+
{title}
|
|
356
|
+
</Text>
|
|
357
|
+
)}
|
|
255
358
|
</View>
|
|
256
|
-
|
|
359
|
+
{Boolean(headerRight) && <View style={{alignItems: "flex-end"}}>{headerRight?.({})}</View>}
|
|
360
|
+
</View>
|
|
257
361
|
</View>
|
|
258
362
|
);
|
|
259
363
|
};
|
|
260
364
|
|
|
261
|
-
/**
|
|
262
|
-
* Reads active route from Navigator context and renders the drawer + Slot.
|
|
263
|
-
*/
|
|
365
|
+
/** Renders the content panel and bottom sheet for the active screen. */
|
|
264
366
|
const SidebarNavigatorContent: FC<{
|
|
265
367
|
topItems: SidebarNavigationItem[];
|
|
266
368
|
bottomItems: SidebarNavigationItem[];
|
|
369
|
+
isOpen: boolean;
|
|
370
|
+
onOpenChange: (isOpen: boolean) => void;
|
|
267
371
|
onNavigate?: (route: string) => void;
|
|
268
372
|
panelStyle?: StyleProp<ViewStyle>;
|
|
269
373
|
itemStyle?: StyleProp<ViewStyle>;
|
|
270
|
-
}> = ({topItems, bottomItems, onNavigate, panelStyle, itemStyle}) => {
|
|
374
|
+
}> = ({topItems, bottomItems, isOpen, onOpenChange, onNavigate, panelStyle, itemStyle}) => {
|
|
271
375
|
const {state, navigation} = Navigator.useContext();
|
|
272
|
-
const activeRoute = state.routes[state.index]
|
|
376
|
+
const activeRoute = state.routes[state.index];
|
|
273
377
|
|
|
274
378
|
const handleNavigate = useCallback(
|
|
275
379
|
(route: string) => {
|
|
@@ -281,10 +385,12 @@ const SidebarNavigatorContent: FC<{
|
|
|
281
385
|
|
|
282
386
|
return (
|
|
283
387
|
<SidebarNavigationPanel
|
|
284
|
-
activeRoute={activeRoute}
|
|
388
|
+
activeRoute={activeRoute?.name}
|
|
285
389
|
bottomItems={bottomItems}
|
|
390
|
+
isOpen={isOpen}
|
|
286
391
|
itemStyle={itemStyle}
|
|
287
392
|
onNavigate={handleNavigate}
|
|
393
|
+
onOpenChange={onOpenChange}
|
|
288
394
|
panelStyle={panelStyle}
|
|
289
395
|
topItems={topItems}
|
|
290
396
|
>
|
|
@@ -294,7 +400,7 @@ const SidebarNavigatorContent: FC<{
|
|
|
294
400
|
};
|
|
295
401
|
|
|
296
402
|
/**
|
|
297
|
-
* Custom expo-router navigator with a hamburger-triggered
|
|
403
|
+
* Custom expo-router navigator with a header bar and hamburger-triggered bottom sheet.
|
|
298
404
|
* Use in _layout.tsx files:
|
|
299
405
|
*
|
|
300
406
|
* ```tsx
|
|
@@ -308,7 +414,7 @@ const SidebarNavigatorContent: FC<{
|
|
|
308
414
|
* }
|
|
309
415
|
* ```
|
|
310
416
|
*/
|
|
311
|
-
|
|
417
|
+
const SidebarNavigationBase: FC<SidebarNavigationProps> = ({
|
|
312
418
|
topItems,
|
|
313
419
|
bottomItems,
|
|
314
420
|
onNavigate,
|
|
@@ -316,16 +422,27 @@ export const SidebarNavigation: FC<SidebarNavigationProps> = ({
|
|
|
316
422
|
screenOptions,
|
|
317
423
|
panelStyle,
|
|
318
424
|
itemStyle,
|
|
425
|
+
children,
|
|
319
426
|
}) => {
|
|
427
|
+
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
428
|
+
|
|
320
429
|
return (
|
|
321
430
|
<Navigator initialRouteName={initialRouteName} router={TabRouter} screenOptions={screenOptions}>
|
|
322
|
-
<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
431
|
+
<View style={{flex: 1}}>
|
|
432
|
+
<SidebarHeader onOpen={() => setIsSheetOpen(true)} />
|
|
433
|
+
<SidebarNavigatorContent
|
|
434
|
+
bottomItems={bottomItems}
|
|
435
|
+
isOpen={isSheetOpen}
|
|
436
|
+
itemStyle={itemStyle}
|
|
437
|
+
onNavigate={onNavigate}
|
|
438
|
+
onOpenChange={setIsSheetOpen}
|
|
439
|
+
panelStyle={panelStyle}
|
|
440
|
+
topItems={topItems}
|
|
441
|
+
/>
|
|
442
|
+
</View>
|
|
443
|
+
{children}
|
|
329
444
|
</Navigator>
|
|
330
445
|
);
|
|
331
446
|
};
|
|
447
|
+
|
|
448
|
+
export const SidebarNavigation = Object.assign(SidebarNavigationBase, {Screen});
|