@natsuneko-laboratory/react-native-desktop-navigation 0.1.0-alpha.12

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 (103) hide show
  1. package/DesktopNavigation.podspec +18 -0
  2. package/LICENSE +21 -0
  3. package/NATIVE.md +300 -0
  4. package/README.md +127 -0
  5. package/dist/core/NavigationContainer.d.ts +23 -0
  6. package/dist/core/NavigationContainer.js +68 -0
  7. package/dist/core/NavigationItem.d.ts +27 -0
  8. package/dist/core/NavigationItem.js +71 -0
  9. package/dist/core/Scene.d.ts +19 -0
  10. package/dist/core/Scene.js +124 -0
  11. package/dist/core/SelectionNavigator.d.ts +38 -0
  12. package/dist/core/SelectionNavigator.js +194 -0
  13. package/dist/core/builder.d.ts +40 -0
  14. package/dist/core/builder.js +81 -0
  15. package/dist/core/context.d.ts +26 -0
  16. package/dist/core/context.js +36 -0
  17. package/dist/core/focus.d.ts +14 -0
  18. package/dist/core/focus.js +39 -0
  19. package/dist/core/hooks.d.ts +8 -0
  20. package/dist/core/hooks.js +48 -0
  21. package/dist/core/navigation.d.ts +6 -0
  22. package/dist/core/navigation.js +57 -0
  23. package/dist/core/store.d.ts +39 -0
  24. package/dist/core/store.js +391 -0
  25. package/dist/core/types.d.ts +155 -0
  26. package/dist/core/types.js +2 -0
  27. package/dist/index.d.ts +15 -0
  28. package/dist/index.js +46 -0
  29. package/dist/native/host.d.ts +100 -0
  30. package/dist/native/host.js +190 -0
  31. package/dist/native/icons.d.ts +56 -0
  32. package/dist/native/icons.js +55 -0
  33. package/dist/native/index.d.ts +13 -0
  34. package/dist/native/index.js +44 -0
  35. package/dist/native/sidebar.d.ts +39 -0
  36. package/dist/native/sidebar.js +126 -0
  37. package/dist/native/specs/DesktopNavigationHostNativeComponent.d.ts +10 -0
  38. package/dist/native/specs/DesktopNavigationHostNativeComponent.js +4 -0
  39. package/dist/native/split.d.ts +27 -0
  40. package/dist/native/split.js +105 -0
  41. package/dist/native/stack.d.ts +26 -0
  42. package/dist/native/stack.js +66 -0
  43. package/dist/platform/index.d.ts +52 -0
  44. package/dist/platform/index.js +28 -0
  45. package/dist/platform/macos.d.ts +2 -0
  46. package/dist/platform/macos.js +18 -0
  47. package/dist/platform/windows.d.ts +2 -0
  48. package/dist/platform/windows.js +18 -0
  49. package/dist/routers/index.d.ts +23 -0
  50. package/dist/routers/index.js +393 -0
  51. package/dist/routers/types.d.ts +116 -0
  52. package/dist/routers/types.js +2 -0
  53. package/dist/sidebar/index.d.ts +17 -0
  54. package/dist/sidebar/index.js +18 -0
  55. package/dist/split/index.d.ts +42 -0
  56. package/dist/split/index.js +199 -0
  57. package/dist/stack/index.d.ts +23 -0
  58. package/dist/stack/index.js +88 -0
  59. package/dist/tabs/index.d.ts +13 -0
  60. package/dist/tabs/index.js +15 -0
  61. package/docs/GUIDE.md +384 -0
  62. package/macos/DDNNavigationComponentView.h +4 -0
  63. package/macos/DDNNavigationComponentView.mm +40 -0
  64. package/macos/DDNNavigationView.swift +398 -0
  65. package/macos/DDNNavigationViewManager.mm +11 -0
  66. package/package.json +82 -0
  67. package/react-native.config.js +19 -0
  68. package/src/core/NavigationContainer.tsx +137 -0
  69. package/src/core/NavigationItem.tsx +149 -0
  70. package/src/core/Scene.tsx +194 -0
  71. package/src/core/SelectionNavigator.tsx +371 -0
  72. package/src/core/builder.tsx +147 -0
  73. package/src/core/context.tsx +43 -0
  74. package/src/core/focus.tsx +50 -0
  75. package/src/core/hooks.ts +42 -0
  76. package/src/core/navigation.ts +77 -0
  77. package/src/core/store.ts +471 -0
  78. package/src/core/types.ts +176 -0
  79. package/src/index.ts +36 -0
  80. package/src/native/host.tsx +377 -0
  81. package/src/native/icons.ts +110 -0
  82. package/src/native/index.ts +56 -0
  83. package/src/native/sidebar.tsx +230 -0
  84. package/src/native/specs/DesktopNavigationHostNativeComponent.ts +12 -0
  85. package/src/native/split.tsx +160 -0
  86. package/src/native/stack.tsx +157 -0
  87. package/src/platform/index.tsx +76 -0
  88. package/src/platform/macos.ts +15 -0
  89. package/src/platform/windows.ts +15 -0
  90. package/src/routers/index.ts +442 -0
  91. package/src/routers/types.ts +117 -0
  92. package/src/sidebar/index.tsx +42 -0
  93. package/src/split/index.tsx +350 -0
  94. package/src/stack/index.tsx +213 -0
  95. package/src/tabs/index.tsx +40 -0
  96. package/windows/DesktopNavigation/DesktopNavigation.def +3 -0
  97. package/windows/DesktopNavigation/DesktopNavigation.vcxproj +125 -0
  98. package/windows/DesktopNavigation/NavigationHost.cpp +432 -0
  99. package/windows/DesktopNavigation/ReactPackageProvider.cpp +9 -0
  100. package/windows/DesktopNavigation/ReactPackageProvider.h +10 -0
  101. package/windows/DesktopNavigation/ReactPackageProvider.idl +6 -0
  102. package/windows/DesktopNavigation/pch.cpp +1 -0
  103. package/windows/DesktopNavigation/pch.h +27 -0
@@ -0,0 +1,377 @@
1
+ import React from 'react';
2
+ import {
3
+ Platform,
4
+ UIManager,
5
+ View,
6
+ StyleSheet,
7
+ type StyleProp,
8
+ type ViewStyle,
9
+ type LayoutChangeEvent,
10
+ } from 'react-native';
11
+ import NativeHost from './specs/DesktopNavigationHostNativeComponent';
12
+ import type { ResolvedNativeIcon } from './icons';
13
+ import { useNavigationTheme } from '../core/context';
14
+
15
+ export interface NativeAppearance {
16
+ /**
17
+ * Hex colors, e.g. #202124 or #202124ff. Native controls retain OS interaction states.
18
+ * `null` skips the Container theme and uses the OS default (e.g. the macOS
19
+ * sidebar material, the system accent color, or the adaptive label color).
20
+ */
21
+ backgroundColor?: string | null;
22
+ foregroundColor?: string | null;
23
+ accentColor?: string | null;
24
+ sidebarBackgroundColor?: string | null;
25
+ }
26
+ export interface NativeItem {
27
+ key: string;
28
+ title: string;
29
+ disabled?: boolean;
30
+ hidden?: boolean;
31
+ section?: string;
32
+ icon?: ResolvedNativeIcon;
33
+ badge?: string;
34
+ }
35
+ export interface NativeColumn {
36
+ key: string;
37
+ width: number;
38
+ minWidth: number;
39
+ maxWidth?: number;
40
+ }
41
+ export interface NativeConfiguration {
42
+ mode: 'stack' | 'sidebar' | 'split';
43
+ items: NativeItem[];
44
+ activeKey: string;
45
+ appearance?: NativeAppearance;
46
+ headerShown?: boolean;
47
+ canGoBack?: boolean;
48
+ backTitle?: string;
49
+ collapsed?: boolean;
50
+ paneWidth?: number;
51
+ /** Height reserved below the sidebar list for a React footer. */
52
+ footerHeight?: number;
53
+ columns?: NativeColumn[];
54
+ }
55
+ export type NativeRequest =
56
+ | { type: 'back' }
57
+ | { type: 'pop'; count: number }
58
+ | { type: 'select'; key: string }
59
+ | { type: 'collapse'; collapsed: boolean }
60
+ | { type: 'resize'; key: string; width: number };
61
+ export interface NativeRect {
62
+ x: number;
63
+ y: number;
64
+ width: number;
65
+ height: number;
66
+ }
67
+ interface NativeIconFrame {
68
+ frame: NativeRect;
69
+ clip: NativeRect;
70
+ }
71
+ function isRect(frame: any): frame is NativeRect {
72
+ return (
73
+ !!frame &&
74
+ ['x', 'y', 'width', 'height'].every(
75
+ (key) => typeof frame[key] === 'number' && Number.isFinite(frame[key]),
76
+ ) &&
77
+ frame.width >= 0 &&
78
+ frame.height >= 0
79
+ );
80
+ }
81
+ interface LayoutEvent {
82
+ type: 'layout';
83
+ revision: number;
84
+ frames: Record<string, NativeRect>;
85
+ iconFrames?: Record<string, NativeIconFrame>;
86
+ footerFrame?: NativeRect;
87
+ }
88
+
89
+ // Keep native event payloads at this boundary. Native UI requests changes; the
90
+ // Store decides whether to accept them. Never restore a native state snapshot.
91
+ export function parseNativeEvent(
92
+ payload: string,
93
+ ): (NativeRequest & { revision: number }) | LayoutEvent | null {
94
+ let value: any;
95
+ try {
96
+ value = JSON.parse(payload);
97
+ } catch {
98
+ return null;
99
+ }
100
+ if (
101
+ !value ||
102
+ typeof value !== 'object' ||
103
+ !Number.isSafeInteger(value.revision)
104
+ )
105
+ return null;
106
+ switch (value.type) {
107
+ case 'back':
108
+ return value;
109
+ case 'pop':
110
+ return Number.isSafeInteger(value.count) && value.count > 0
111
+ ? value
112
+ : null;
113
+ case 'select':
114
+ return typeof value.key === 'string' ? value : null;
115
+ case 'collapse':
116
+ return typeof value.collapsed === 'boolean' ? value : null;
117
+ case 'resize':
118
+ return typeof value.key === 'string' &&
119
+ Number.isFinite(value.width) &&
120
+ value.width >= 0
121
+ ? value
122
+ : null;
123
+ case 'layout':
124
+ if (
125
+ !Number.isSafeInteger(value.revision) ||
126
+ !value.frames ||
127
+ typeof value.frames !== 'object' ||
128
+ Array.isArray(value.frames)
129
+ )
130
+ return null;
131
+ if (!Object.values(value.frames).every(isRect)) return null;
132
+ if (
133
+ value.iconFrames !== undefined &&
134
+ (!value.iconFrames ||
135
+ typeof value.iconFrames !== 'object' ||
136
+ Array.isArray(value.iconFrames) ||
137
+ !Object.values(value.iconFrames).every(
138
+ (entry: any) => entry && isRect(entry.frame) && isRect(entry.clip),
139
+ ))
140
+ )
141
+ return null;
142
+ if (value.footerFrame !== undefined && !isRect(value.footerFrame))
143
+ return null;
144
+ return value;
145
+ default:
146
+ return null;
147
+ }
148
+ }
149
+
150
+ export interface NativeSurfaceProps {
151
+ configuration: NativeConfiguration;
152
+ slots: {
153
+ key: string;
154
+ visible: boolean;
155
+ content: React.ReactNode | ((ready: boolean) => React.ReactNode);
156
+ }[];
157
+ icons?: { key: string; content: React.ReactElement }[];
158
+ /** Interactive React content placed in the native footer region. */
159
+ footer?: React.ReactNode;
160
+ onFooterHeight?: (height: number) => void;
161
+ style?: StyleProp<ViewStyle>;
162
+ onRequest: (request: NativeRequest) => void;
163
+ onLayout?: (event: LayoutChangeEvent) => void;
164
+ onMeasurements?: (frames: Record<string, NativeRect>) => void;
165
+ }
166
+ export function NativeSurface({
167
+ configuration,
168
+ slots,
169
+ icons = [],
170
+ footer,
171
+ onFooterHeight,
172
+ style,
173
+ onRequest,
174
+ onLayout,
175
+ onMeasurements,
176
+ }: NativeSurfaceProps) {
177
+ if (Platform.OS !== 'macos' && Platform.OS !== 'windows')
178
+ throw new Error(
179
+ 'Desktop native navigation supports macOS and Windows only.',
180
+ );
181
+ if (
182
+ !(globalThis as { nativeFabricUIManager?: unknown }).nativeFabricUIManager
183
+ )
184
+ throw new Error(
185
+ 'Desktop native navigation requires Fabric (New Architecture).',
186
+ );
187
+ if (!UIManager.hasViewManagerConfig('DesktopNavigationHost'))
188
+ throw new Error(
189
+ 'DesktopNavigationHost is not registered. Install the desktop native sources, enable Fabric, and rebuild the app. See the /native installation guide.',
190
+ );
191
+ const { colors } = useNavigationTheme();
192
+ // Omitted keys fall back to OS defaults natively, so `null` is simply dropped.
193
+ const appearance = Object.fromEntries(
194
+ Object.entries({
195
+ backgroundColor: colors.background,
196
+ foregroundColor: colors.text,
197
+ accentColor: colors.accent,
198
+ sidebarBackgroundColor: colors.surface,
199
+ ...configuration.appearance,
200
+ }).filter(([, color]) => color != null),
201
+ ) as NativeAppearance;
202
+ configuration = { ...configuration, appearance };
203
+ for (const color of Object.values(appearance)) {
204
+ if (
205
+ typeof color !== 'string' ||
206
+ !/^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(color)
207
+ )
208
+ throw new Error(
209
+ 'Native navigation appearance requires #RRGGBB or #RRGGBBAA colors.',
210
+ );
211
+ }
212
+ const [acknowledgement, acknowledge] = React.useReducer((n) => n + 1, 0);
213
+ const serialized = JSON.stringify(configuration);
214
+ const version = React.useRef({ serialized, acknowledgement, revision: 0 });
215
+ if (
216
+ version.current.serialized !== serialized ||
217
+ version.current.acknowledgement !== acknowledgement
218
+ ) {
219
+ version.current = {
220
+ serialized,
221
+ acknowledgement,
222
+ revision: version.current.revision + 1,
223
+ };
224
+ }
225
+ const revision = version.current.revision;
226
+ const [layout, setLayout] = React.useState<LayoutEvent | null>(null);
227
+ const footerFrame = layout?.footerFrame;
228
+ const footerPlaced = !!footerFrame && footerFrame.width > 0;
229
+ return (
230
+ <View style={[styles.container, style]} onLayout={onLayout}>
231
+ <NativeHost
232
+ style={StyleSheet.absoluteFillObject}
233
+ configuration={JSON.stringify({ ...configuration, revision })}
234
+ onNavigationEvent={(event) => {
235
+ const message = parseNativeEvent(event.nativeEvent.payload);
236
+ if (!message || message.revision !== revision) return;
237
+ if (message.type === 'layout') {
238
+ onMeasurements?.(message.frames);
239
+ setLayout((previous) =>
240
+ JSON.stringify(previous) === JSON.stringify(message)
241
+ ? previous
242
+ : message,
243
+ );
244
+ } else {
245
+ onRequest(message);
246
+ // Also send an acknowledgement after vetoed/no-op actions so that
247
+ // optimistic native selection/open state is rolled back.
248
+ acknowledge();
249
+ }
250
+ }}
251
+ />
252
+ <View pointerEvents="box-none" style={StyleSheet.absoluteFillObject}>
253
+ {slots.map((slot) => {
254
+ const frame = layout?.frames[slot.key];
255
+ const visible =
256
+ slot.visible && !!frame && frame.width > 0 && frame.height > 0;
257
+ return (
258
+ <View
259
+ key={slot.key}
260
+ collapsable={false}
261
+ pointerEvents={visible ? 'auto' : 'none'}
262
+ accessibilityElementsHidden={!visible}
263
+ importantForAccessibility={
264
+ visible ? 'auto' : 'no-hide-descendants'
265
+ }
266
+ style={[
267
+ styles.slot,
268
+ frame && {
269
+ left: frame.x,
270
+ top: frame.y,
271
+ width: frame.width,
272
+ height: frame.height,
273
+ },
274
+ !visible && styles.hidden,
275
+ ]}
276
+ >
277
+ {typeof slot.content === 'function'
278
+ ? slot.content(visible)
279
+ : slot.content}
280
+ </View>
281
+ );
282
+ })}
283
+ </View>
284
+ {footer != null && footer !== false && (
285
+ // Measured at its natural height so native can reserve exactly that
286
+ // much space; kept invisible until native reports the reserved frame.
287
+ <View
288
+ collapsable={false}
289
+ pointerEvents={footerPlaced ? 'box-none' : 'none'}
290
+ accessibilityElementsHidden={!footerPlaced}
291
+ importantForAccessibility={
292
+ footerPlaced ? 'auto' : 'no-hide-descendants'
293
+ }
294
+ onLayout={(event) =>
295
+ onFooterHeight?.(event.nativeEvent.layout.height)
296
+ }
297
+ style={[
298
+ styles.footer,
299
+ footerPlaced
300
+ ? {
301
+ left: footerFrame.x,
302
+ top: footerFrame.y,
303
+ width: footerFrame.width,
304
+ }
305
+ : {
306
+ left: 0,
307
+ top: 0,
308
+ width: configuration.paneWidth ?? 240,
309
+ opacity: 0,
310
+ },
311
+ ]}
312
+ >
313
+ {footer}
314
+ </View>
315
+ )}
316
+ <View
317
+ pointerEvents="none"
318
+ accessible={false}
319
+ accessibilityElementsHidden
320
+ importantForAccessibility="no-hide-descendants"
321
+ style={StyleSheet.absoluteFillObject}
322
+ >
323
+ {icons.map((icon) => {
324
+ // Never display a removed/resized icon at a previous revision's position.
325
+ const geometry =
326
+ layout?.revision === revision
327
+ ? layout.iconFrames?.[icon.key]
328
+ : undefined;
329
+ if (
330
+ !geometry ||
331
+ geometry.clip.width <= 0 ||
332
+ geometry.clip.height <= 0
333
+ )
334
+ return null;
335
+ const { frame, clip } = geometry;
336
+ return (
337
+ <View
338
+ key={icon.key}
339
+ collapsable={false}
340
+ pointerEvents="none"
341
+ style={[
342
+ styles.slot,
343
+ {
344
+ left: clip.x,
345
+ top: clip.y,
346
+ width: clip.width,
347
+ height: clip.height,
348
+ },
349
+ ]}
350
+ >
351
+ <View
352
+ pointerEvents="none"
353
+ style={{
354
+ position: 'absolute',
355
+ left: frame.x - clip.x,
356
+ top: frame.y - clip.y,
357
+ width: frame.width,
358
+ height: frame.height,
359
+ alignItems: 'center',
360
+ justifyContent: 'center',
361
+ }}
362
+ >
363
+ {icon.content}
364
+ </View>
365
+ </View>
366
+ );
367
+ })}
368
+ </View>
369
+ </View>
370
+ );
371
+ }
372
+ const styles = StyleSheet.create({
373
+ container: { flex: 1, overflow: 'hidden' },
374
+ slot: { position: 'absolute', overflow: 'hidden' },
375
+ footer: { position: 'absolute' },
376
+ hidden: { display: 'none' },
377
+ });
@@ -0,0 +1,110 @@
1
+ import { isValidElement, type ReactElement } from 'react';
2
+ import { Image, Platform } from 'react-native';
3
+
4
+ /** Serializable alternatives to React elements inside native menu controls. */
5
+ export type NativeSidebarIcon = (
6
+ | ({ type: 'system' } & (
7
+ | {
8
+ /** SF Symbols name. */
9
+ macos: string;
10
+ /** Unicode glyph; fontFamily defaults to WinUI's system icon font. */
11
+ windows?: { glyph: string; fontFamily?: string };
12
+ }
13
+ | {
14
+ macos?: string;
15
+ windows: { glyph: string; fontFamily?: string };
16
+ }
17
+ ))
18
+ | {
19
+ type: 'image';
20
+ /** Metro require('./icon.png') or a native-readable image URI. */
21
+ source: number | { uri: string };
22
+ /** Tint the image as a monochrome template (default: false). */
23
+ template?: boolean;
24
+ }
25
+ ) & {
26
+ /** Logical points / DIPs, default 16. */
27
+ size?: number;
28
+ /** #RRGGBB or #RRGGBBAA; omitted colors follow native item styling. */
29
+ color?: string;
30
+ };
31
+ export interface NativeSidebarIconState {
32
+ /** Selected route, matching the JS Sidebar's icon callback. */
33
+ focused: boolean;
34
+ disabled: boolean;
35
+ }
36
+ export type NativeSidebarIconOption =
37
+ | NativeSidebarIcon
38
+ | ReactElement
39
+ | null
40
+ | ((
41
+ state: NativeSidebarIconState,
42
+ ) => NativeSidebarIcon | ReactElement | null);
43
+ export type ResolvedNativeIcon = (
44
+ | { type: 'react' }
45
+ | { type: 'symbol'; name: string }
46
+ | { type: 'font'; glyph: string; fontFamily?: string }
47
+ | { type: 'image'; uri: string; template: boolean }
48
+ ) & { size: number; color?: string };
49
+
50
+ export function resolveNativeIcon(
51
+ option: NativeSidebarIconOption | undefined,
52
+ state: NativeSidebarIconState,
53
+ reactSize = 24,
54
+ ): ResolvedNativeIcon | undefined {
55
+ const icon = typeof option === 'function' ? option(state) : option;
56
+ if (icon == null) return undefined;
57
+ const element = isValidElement(icon);
58
+ const size = element ? reactSize : (icon.size ?? 16);
59
+ if (!Number.isFinite(size) || size <= 0)
60
+ throw new Error(
61
+ 'Native sidebar icon size must be a positive finite number.',
62
+ );
63
+ if (element) return { type: 'react', size };
64
+ if (
65
+ icon.color !== undefined &&
66
+ !/^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(icon.color)
67
+ )
68
+ throw new Error('Native sidebar icon color requires #RRGGBB or #RRGGBBAA.');
69
+ const style = { size, color: icon.color };
70
+ if (icon.type === 'system') {
71
+ if (Platform.OS === 'macos') {
72
+ if (icon.macos === undefined) return undefined;
73
+ if (typeof icon.macos !== 'string' || !icon.macos.trim())
74
+ throw new Error(
75
+ 'Native sidebar SF Symbols name must be a non-empty string.',
76
+ );
77
+ return { ...style, type: 'symbol', name: icon.macos };
78
+ }
79
+ if (!icon.windows) return undefined;
80
+ if (typeof icon.windows.glyph !== 'string' || !icon.windows.glyph.trim())
81
+ throw new Error('Native sidebar font icon requires a Unicode glyph.');
82
+ return {
83
+ ...style,
84
+ type: 'font',
85
+ glyph: icon.windows.glyph,
86
+ fontFamily: icon.windows.fontFamily,
87
+ };
88
+ }
89
+ if (icon.type !== 'image')
90
+ throw new Error(
91
+ 'Native sidebar icons must be React elements, system descriptors or image descriptors.',
92
+ );
93
+ const source = Image.resolveAssetSource(icon.source);
94
+ if (!source?.uri || typeof source.uri !== 'string')
95
+ throw new Error('Native sidebar image could not be resolved to a URI.');
96
+ const protocols =
97
+ Platform.OS === 'macos'
98
+ ? /^(https?|file):\/\//i
99
+ : /^(https?|file|ms-appx|ms-appdata):\/\//i;
100
+ if (!protocols.test(source.uri))
101
+ throw new Error(
102
+ 'Native sidebar images require an HTTP(S), file, or Windows ms-appx/ms-appdata URI.',
103
+ );
104
+ return {
105
+ ...style,
106
+ type: 'image',
107
+ uri: source.uri,
108
+ template: icon.template ?? false,
109
+ };
110
+ }
@@ -0,0 +1,56 @@
1
+ // Same context, Store, Router and hooks as the JS-rendered navigators.
2
+ export {
3
+ NavigationContainer,
4
+ type NavigationContainerProps,
5
+ type KeyboardShortcutOptions,
6
+ } from '../core/NavigationContainer';
7
+ export { createNavigationRef } from '../core/navigation';
8
+ export {
9
+ useNavigation,
10
+ useRoute,
11
+ useNavigationState,
12
+ useFocusEffect,
13
+ useIsFocused,
14
+ } from '../core/hooks';
15
+ export { NavigationFocusable, type FocusTarget } from '../core/focus';
16
+ export { DefaultTheme, useNavigationTheme } from '../core/context';
17
+ export {
18
+ NavigationStore,
19
+ serializeNavigationState,
20
+ restoreNavigationState,
21
+ type NavigationEvent,
22
+ type NavigationEventType,
23
+ } from '../core/store';
24
+ export * from '../routers';
25
+ export type {
26
+ Navigation,
27
+ StackNavigation,
28
+ SidebarNavigation,
29
+ StackScreenProps,
30
+ SidebarScreenProps,
31
+ SidebarFooterProps,
32
+ NavigationTheme,
33
+ NavigationRef,
34
+ } from '../core/types';
35
+ export {
36
+ createStackNavigator,
37
+ type NativeStackNavigatorProps,
38
+ type NativeStackScreenOptions,
39
+ } from './stack';
40
+ export {
41
+ createSidebarNavigator,
42
+ type NativeSidebarNavigatorProps,
43
+ type NativeSidebarScreenOptions,
44
+ } from './sidebar';
45
+ export {
46
+ createSplitNavigator,
47
+ type NativeSplitNavigatorProps,
48
+ type NativeSplitColumnProps,
49
+ } from './split';
50
+ export type { NativeAppearance } from './host';
51
+
52
+ export type {
53
+ NativeSidebarIcon,
54
+ NativeSidebarIconOption,
55
+ NativeSidebarIconState,
56
+ } from './icons';