@symbiote-native/navigation 2.0.3 → 2.2.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.
- package/README.md +42 -12
- package/build/angular/drawer/index.js +29 -13
- package/build/angular/index.d.ts +4 -4
- package/build/angular/injectors/inject-navigation.js +1 -1
- package/build/angular/navigation-scope.directive.js +1 -1
- package/build/angular/search-bar-ref.directive.js +1 -1
- package/build/angular/stack/index.d.ts +2 -0
- package/build/angular/stack/index.js +43 -9
- package/build/angular/tabs/index.d.ts +1 -1
- package/build/angular/tabs/index.js +40 -13
- package/build/core/drawer-options/index.js +19 -5
- package/build/core/drawer-router-state/index.js +8 -2
- package/build/core/guards.js +3 -1
- package/build/core/header-bar-buttons.js +14 -4
- package/build/core/index.d.ts +6 -5
- package/build/core/index.js +7 -3
- package/build/core/navigator-state/index.js +12 -4
- package/build/core/render-drawer.js +4 -1
- package/build/core/render-stack.js +13 -4
- package/build/core/screen-options.js +1 -1
- package/build/core/search-bar-commands.js +1 -1
- package/build/core/stack-router-state/index.d.ts +2 -0
- package/build/core/stack-router-state/index.js +44 -0
- package/build/core/state-persistence/index.js +6 -2
- package/build/core/tab-router-state/index.d.ts +1 -0
- package/build/core/tab-router-state/index.js +27 -2
- package/build/react/drawer/index.js +59 -26
- package/build/react/index.d.ts +7 -7
- package/build/react/index.js +2 -2
- package/build/react/stack/index.js +47 -10
- package/build/react/tabs/index.js +36 -12
- package/build/solid/drawer/index.d.ts +22 -0
- package/build/solid/drawer/index.js +394 -0
- package/build/solid/drawer-screen-props.d.ts +13 -0
- package/build/solid/drawer-screen-props.js +2 -0
- package/build/solid/host.d.ts +2 -0
- package/build/solid/host.js +23 -0
- package/build/solid/index.d.ts +19 -0
- package/build/solid/index.js +24 -0
- package/build/solid/linking.d.ts +3 -0
- package/build/solid/linking.js +55 -0
- package/build/solid/navigation-context.d.ts +13 -0
- package/build/solid/navigation-context.js +37 -0
- package/build/solid/primitives/create-focus-effect.d.ts +1 -0
- package/build/solid/primitives/create-focus-effect.js +30 -0
- package/build/solid/primitives/create-is-focused.d.ts +2 -0
- package/build/solid/primitives/create-is-focused.js +31 -0
- package/build/solid/primitives/create-navigation-state.d.ts +3 -0
- package/build/solid/primitives/create-navigation-state.js +30 -0
- package/build/solid/primitives/index.d.ts +12 -0
- package/build/solid/primitives/index.js +8 -0
- package/build/solid/primitives/use-drawer-navigation.d.ts +5 -0
- package/build/solid/primitives/use-drawer-navigation.js +15 -0
- package/build/solid/primitives/use-navigation.d.ts +8 -0
- package/build/solid/primitives/use-navigation.js +23 -0
- package/build/solid/primitives/use-route.d.ts +3 -0
- package/build/solid/primitives/use-route.js +14 -0
- package/build/solid/primitives/use-stack-navigation.d.ts +5 -0
- package/build/solid/primitives/use-stack-navigation.js +19 -0
- package/build/solid/primitives/use-tab-navigation.d.ts +5 -0
- package/build/solid/primitives/use-tab-navigation.js +15 -0
- package/build/solid/screen-props.d.ts +19 -0
- package/build/solid/screen-props.js +9 -0
- package/build/solid/screen-registry.d.ts +31 -0
- package/build/solid/screen-registry.js +86 -0
- package/build/solid/screen.d.ts +6 -0
- package/build/solid/screen.js +69 -0
- package/build/solid/stack/index.d.ts +15 -0
- package/build/solid/stack/index.js +348 -0
- package/build/solid/tab-screen-props.d.ts +13 -0
- package/build/solid/tab-screen-props.js +3 -0
- package/build/solid/tabs/index.d.ts +14 -0
- package/build/solid/tabs/index.js +228 -0
- package/build/svelte/attachments.d.ts +5 -0
- package/build/svelte/attachments.js +61 -0
- package/build/svelte/descriptor-subtree.d.ts +3 -0
- package/build/svelte/descriptor-subtree.js +39 -0
- package/build/svelte/drawer/drawer-props.d.ts +14 -0
- package/build/svelte/drawer/drawer-props.js +3 -0
- package/build/svelte/drawer/index.d.ts +10 -0
- package/build/svelte/drawer/index.js +6 -0
- package/build/svelte/drawer/index.svelte +559 -0
- package/build/svelte/drawer/index.svelte.d.ts +10 -0
- package/build/svelte/drawer-screen-props.d.ts +13 -0
- package/build/svelte/drawer-screen-props.js +4 -0
- package/build/svelte/drawer-screen.svelte +25 -0
- package/build/svelte/drawer-screen.svelte.d.ts +4 -0
- package/build/svelte/index.d.ts +21 -0
- package/build/svelte/index.js +20 -0
- package/build/svelte/linking.svelte.d.ts +2 -0
- package/build/svelte/linking.svelte.js +55 -0
- package/build/svelte/navigation-context.d.ts +14 -0
- package/build/svelte/navigation-context.js +44 -0
- package/build/svelte/navigation-scope.svelte +27 -0
- package/build/svelte/navigation-scope.svelte.d.ts +9 -0
- package/build/svelte/registry-host.d.ts +1 -0
- package/build/svelte/registry-host.js +26 -0
- package/build/svelte/runes/index.d.ts +12 -0
- package/build/svelte/runes/index.js +12 -0
- package/build/svelte/runes/use-drawer-navigation.svelte.d.ts +6 -0
- package/build/svelte/runes/use-drawer-navigation.svelte.js +19 -0
- package/build/svelte/runes/use-focus-effect.svelte.d.ts +1 -0
- package/build/svelte/runes/use-focus-effect.svelte.js +31 -0
- package/build/svelte/runes/use-is-focused.svelte.d.ts +3 -0
- package/build/svelte/runes/use-is-focused.svelte.js +34 -0
- package/build/svelte/runes/use-navigation-state.svelte.d.ts +4 -0
- package/build/svelte/runes/use-navigation-state.svelte.js +39 -0
- package/build/svelte/runes/use-navigation.svelte.d.ts +9 -0
- package/build/svelte/runes/use-navigation.svelte.js +26 -0
- package/build/svelte/runes/use-route.svelte.d.ts +4 -0
- package/build/svelte/runes/use-route.svelte.js +12 -0
- package/build/svelte/runes/use-stack-navigation.svelte.d.ts +6 -0
- package/build/svelte/runes/use-stack-navigation.svelte.js +22 -0
- package/build/svelte/runes/use-tab-navigation.svelte.d.ts +6 -0
- package/build/svelte/runes/use-tab-navigation.svelte.js +19 -0
- package/build/svelte/screen-props.d.ts +21 -0
- package/build/svelte/screen-props.js +6 -0
- package/build/svelte/screen-registry.d.ts +17 -0
- package/build/svelte/screen-registry.js +57 -0
- package/build/svelte/screen.svelte +28 -0
- package/build/svelte/screen.svelte.d.ts +4 -0
- package/build/svelte/stack/index.d.ts +14 -0
- package/build/svelte/stack/index.js +7 -0
- package/build/svelte/stack/index.svelte +261 -0
- package/build/svelte/stack/index.svelte.d.ts +15 -0
- package/build/svelte/stack/stack-props.d.ts +20 -0
- package/build/svelte/stack/stack-props.js +4 -0
- package/build/svelte/stack/stack-screen.svelte +205 -0
- package/build/svelte/stack/stack-screen.svelte.d.ts +4 -0
- package/build/svelte/tab-screen-props.d.ts +13 -0
- package/build/svelte/tab-screen-props.js +4 -0
- package/build/svelte/tab-screen.svelte +26 -0
- package/build/svelte/tab-screen.svelte.d.ts +4 -0
- package/build/svelte/tabs/index.d.ts +8 -0
- package/build/svelte/tabs/index.js +6 -0
- package/build/svelte/tabs/index.svelte +269 -0
- package/build/svelte/tabs/index.svelte.d.ts +8 -0
- package/build/svelte/tabs/tab-props.d.ts +7 -0
- package/build/svelte/tabs/tab-props.js +3 -0
- package/build/vue/composables/use-navigation.js +5 -1
- package/build/vue/drawer/index.js +36 -13
- package/build/vue/index.d.ts +3 -3
- package/build/vue/navigation-context.js +1 -1
- package/build/vue/stack/index.js +43 -18
- package/build/vue/tabs/index.js +65 -39
- package/build-ngc/angular/drawer/index.js +40 -18
- package/build-ngc/angular/drawer/index.js.map +1 -1
- package/build-ngc/angular/drawer-screen.directive.js +3 -3
- package/build-ngc/angular/index.d.ts +4 -4
- package/build-ngc/angular/index.js.map +1 -1
- package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -1
- package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -1
- package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -1
- package/build-ngc/angular/injectors/inject-navigation.js +1 -1
- package/build-ngc/angular/injectors/inject-navigation.js.map +1 -1
- package/build-ngc/angular/linking.js.map +1 -1
- package/build-ngc/angular/navigation-context.service.js +3 -3
- package/build-ngc/angular/navigation-context.service.js.map +1 -1
- package/build-ngc/angular/navigation-scope.directive.js +4 -4
- package/build-ngc/angular/navigation-scope.directive.js.map +1 -1
- package/build-ngc/angular/screen.directive.js +3 -3
- package/build-ngc/angular/screen.directive.js.map +1 -1
- package/build-ngc/angular/search-bar-ref.directive.js +4 -4
- package/build-ngc/angular/search-bar-ref.directive.js.map +1 -1
- package/build-ngc/angular/stack/index.d.ts +2 -0
- package/build-ngc/angular/stack/index.js +52 -14
- package/build-ngc/angular/stack/index.js.map +1 -1
- package/build-ngc/angular/tab-screen.directive.js +3 -3
- package/build-ngc/angular/tab-screen.directive.js.map +1 -1
- package/build-ngc/angular/tabs/index.d.ts +1 -1
- package/build-ngc/angular/tabs/index.js +43 -16
- package/build-ngc/angular/tabs/index.js.map +1 -1
- package/build-ngc/core/constants.js.map +1 -1
- package/build-ngc/core/drawer-options/index.js +19 -5
- package/build-ngc/core/drawer-options/index.js.map +1 -1
- package/build-ngc/core/drawer-router-state/index.js +8 -2
- package/build-ngc/core/drawer-router-state/index.js.map +1 -1
- package/build-ngc/core/guards.js +3 -1
- package/build-ngc/core/guards.js.map +1 -1
- package/build-ngc/core/header-bar-buttons.js +14 -4
- package/build-ngc/core/header-bar-buttons.js.map +1 -1
- package/build-ngc/core/index.d.ts +6 -5
- package/build-ngc/core/index.js +7 -3
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/linking-config/index.js.map +1 -1
- package/build-ngc/core/navigation-events/index.js.map +1 -1
- package/build-ngc/core/navigator-handles/index.js.map +1 -1
- package/build-ngc/core/navigator-state/index.js +12 -4
- package/build-ngc/core/navigator-state/index.js.map +1 -1
- package/build-ngc/core/render-drawer.js +4 -1
- package/build-ngc/core/render-drawer.js.map +1 -1
- package/build-ngc/core/render-stack.js +13 -4
- package/build-ngc/core/render-stack.js.map +1 -1
- package/build-ngc/core/render-tabs.js.map +1 -1
- package/build-ngc/core/screen-options.js +1 -1
- package/build-ngc/core/screen-options.js.map +1 -1
- package/build-ngc/core/search-bar-commands.js +1 -1
- package/build-ngc/core/search-bar-commands.js.map +1 -1
- package/build-ngc/core/stack-router-state/index.d.ts +2 -0
- package/build-ngc/core/stack-router-state/index.js +45 -0
- package/build-ngc/core/stack-router-state/index.js.map +1 -0
- package/build-ngc/core/state-persistence/index.js +6 -2
- package/build-ngc/core/state-persistence/index.js.map +1 -1
- package/build-ngc/core/tab-router-state/index.d.ts +1 -0
- package/build-ngc/core/tab-router-state/index.js +27 -2
- package/build-ngc/core/tab-router-state/index.js.map +1 -1
- package/package.json +44 -16
- package/src/angular/drawer/index.ts +75 -29
- package/src/angular/index.ts +20 -4
- package/src/angular/injectors/inject-focus-effect.ts +8 -2
- package/src/angular/injectors/inject-is-focused.ts +6 -4
- package/src/angular/injectors/inject-navigation-state.ts +7 -4
- package/src/angular/injectors/inject-navigation.ts +12 -3
- package/src/angular/linking.ts +4 -1
- package/src/angular/navigation-context.service.ts +5 -2
- package/src/angular/navigation-scope.directive.ts +6 -2
- package/src/angular/screen.directive.ts +13 -3
- package/src/angular/search-bar-ref.directive.ts +10 -2
- package/src/angular/stack/index.ts +91 -24
- package/src/angular/tab-screen.directive.ts +3 -1
- package/src/angular/tabs/index.ts +54 -16
- package/src/core/constants.ts +6 -3
- package/src/core/drawer-options/index.ts +40 -13
- package/src/core/drawer-router-state/index.ts +11 -3
- package/src/core/guards.ts +3 -1
- package/src/core/header-bar-buttons.ts +41 -12
- package/src/core/index.ts +29 -5
- package/src/core/linking-config/index.ts +31 -10
- package/src/core/navigation-events/index.ts +8 -2
- package/src/core/navigator-handles/index.ts +8 -3
- package/src/core/navigator-props.ts +13 -4
- package/src/core/navigator-state/index.ts +24 -7
- package/src/core/render-drawer.ts +24 -9
- package/src/core/render-stack.ts +52 -13
- package/src/core/render-tabs.ts +24 -6
- package/src/core/screen-options.ts +15 -5
- package/src/core/search-bar-commands.ts +12 -3
- package/src/core/stack-router-state/index.ts +52 -0
- package/src/core/state-persistence/index.ts +13 -3
- package/src/core/tab-router-state/index.ts +35 -3
- package/src/react/drawer/index.ts +409 -330
- package/src/react/drawer-screen.ts +8 -2
- package/src/react/hooks/use-focus-effect.ts +8 -2
- package/src/react/hooks/use-is-focused.ts +6 -2
- package/src/react/hooks/use-navigation.ts +8 -2
- package/src/react/index.ts +37 -7
- package/src/react/linking.ts +4 -1
- package/src/react/navigation-context.ts +6 -2
- package/src/react/screen.ts +12 -3
- package/src/react/stack/index.ts +297 -220
- package/src/react/tab-screen.ts +3 -1
- package/src/react/tabs/index.ts +202 -139
- package/src/solid/drawer/index.ts +570 -0
- package/src/solid/drawer-screen-props.ts +24 -0
- package/src/solid/host.ts +29 -0
- package/src/solid/index.ts +87 -0
- package/src/solid/linking.ts +74 -0
- package/src/solid/navigation-context.ts +56 -0
- package/src/solid/primitives/create-focus-effect.ts +41 -0
- package/src/solid/primitives/create-is-focused.ts +41 -0
- package/src/solid/primitives/create-navigation-state.ts +44 -0
- package/src/solid/primitives/index.ts +12 -0
- package/src/solid/primitives/use-drawer-navigation.ts +25 -0
- package/src/solid/primitives/use-navigation.ts +44 -0
- package/src/solid/primitives/use-route.ts +18 -0
- package/src/solid/primitives/use-stack-navigation.ts +29 -0
- package/src/solid/primitives/use-tab-navigation.ts +25 -0
- package/src/solid/screen-props.ts +51 -0
- package/src/solid/screen-registry.ts +159 -0
- package/src/solid/screen.ts +80 -0
- package/src/solid/stack/index.ts +528 -0
- package/src/solid/tab-screen-props.ts +21 -0
- package/src/solid/tabs/index.ts +327 -0
- package/src/svelte/attachments.ts +70 -0
- package/src/svelte/descriptor-subtree.ts +51 -0
- package/src/svelte/drawer/drawer-props.ts +28 -0
- package/src/svelte/drawer/index.svelte +559 -0
- package/src/svelte/drawer/index.ts +10 -0
- package/src/svelte/drawer-screen-props.ts +26 -0
- package/src/svelte/drawer-screen.svelte +25 -0
- package/src/svelte/fabric-tree.test-helper.ts +95 -0
- package/src/svelte/index.ts +83 -0
- package/src/svelte/linking.svelte.ts +72 -0
- package/src/svelte/navigation-context.ts +62 -0
- package/src/svelte/navigation-scope.svelte +27 -0
- package/src/svelte/registry-host.ts +26 -0
- package/src/svelte/runes/index.ts +17 -0
- package/src/svelte/runes/use-drawer-navigation.svelte.ts +31 -0
- package/src/svelte/runes/use-focus-effect.svelte.ts +41 -0
- package/src/svelte/runes/use-is-focused.svelte.ts +38 -0
- package/src/svelte/runes/use-navigation-state.svelte.ts +48 -0
- package/src/svelte/runes/use-navigation.svelte.ts +49 -0
- package/src/svelte/runes/use-route.svelte.ts +16 -0
- package/src/svelte/runes/use-stack-navigation.svelte.ts +34 -0
- package/src/svelte/runes/use-tab-navigation.svelte.ts +29 -0
- package/src/svelte/screen-props.ts +50 -0
- package/src/svelte/screen-registry.ts +98 -0
- package/src/svelte/screen.svelte +28 -0
- package/src/svelte/stack/index.svelte +261 -0
- package/src/svelte/stack/index.ts +11 -0
- package/src/svelte/stack/stack-props.ts +31 -0
- package/src/svelte/stack/stack-screen.svelte +205 -0
- package/src/svelte/svelte-ambient.d.ts +6 -0
- package/src/svelte/svelte-compile.test-helper.ts +147 -0
- package/src/svelte/tab-screen-props.ts +22 -0
- package/src/svelte/tab-screen.svelte +26 -0
- package/src/svelte/tabs/index.svelte +269 -0
- package/src/svelte/tabs/index.ts +10 -0
- package/src/svelte/tabs/tab-props.ts +13 -0
- package/src/vue/composables/use-navigation-state.ts +7 -4
- package/src/vue/composables/use-navigation.ts +13 -3
- package/src/vue/drawer/index.ts +128 -41
- package/src/vue/drawer-screen.ts +12 -5
- package/src/vue/index.ts +15 -3
- package/src/vue/linking.ts +7 -2
- package/src/vue/navigation-context.ts +17 -5
- package/src/vue/screen.ts +7 -2
- package/src/vue/stack/index.ts +108 -43
- package/src/vue/tab-screen.ts +3 -1
- package/src/vue/tabs/index.ts +109 -68
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A native stack/tab/drawer navigator for [SymbioteNative](../../README.md), built directly on
|
|
4
4
|
[`react-native-screens`](https://github.com/software-mansion/react-native-screens)' native view
|
|
5
5
|
primitives (`RNSScreen`/`RNSScreenStack`/`RNSScreenStackHeaderConfig`/`RNSSearchBar`) — reachable
|
|
6
|
-
from **every** adapter: React, Vue, and Angular. Unlike the third-party-view wrappers
|
|
6
|
+
from **every** adapter: React, Vue, Svelte, Solid, and Angular. Unlike the third-party-view wrappers
|
|
7
7
|
([`@symbiote-native/slider`](../slider), [`@symbiote-native/splash-screen`](../splash-screen)),
|
|
8
8
|
there is no upstream React component to route around here at all — `react-navigation`'s own
|
|
9
9
|
navigator UI is itself React-only (it calls hooks off the React dispatcher), so wrapping it was
|
|
@@ -38,14 +38,16 @@ src/
|
|
|
38
38
|
│ react-native-screens' own React components)
|
|
39
39
|
├── react/ @symbiote-native/navigation/react — Stack/Tab/Drawer + hooks
|
|
40
40
|
├── vue/ @symbiote-native/navigation/vue — Stack/Tab/Drawer + composables
|
|
41
|
+
├── svelte/ @symbiote-native/navigation/svelte — Stack/Tab/Drawer + runes
|
|
42
|
+
├── solid/ @symbiote-native/navigation/solid — Stack/Tab/Drawer + primitives
|
|
41
43
|
└── angular/ @symbiote-native/navigation/angular — Stack/Tab/Drawer + directives + inject*
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
Each adapter entry imports `../register` first (so every native view's `ViewConfig` is registered
|
|
45
47
|
before a screen ever mounts), then exposes `Stack`, `Tab`, and `Drawer`. The router/reducer logic
|
|
46
48
|
and every `react-native-screens` prop fold are written once in `core/` and shared verbatim; each
|
|
47
|
-
adapter supplies only its own lifecycle (hooks / composables / `inject*`
|
|
48
|
-
descriptor bridge.
|
|
49
|
+
adapter supplies only its own lifecycle (hooks / composables / runes / primitives / `inject*`
|
|
50
|
+
functions) and the descriptor bridge.
|
|
49
51
|
|
|
50
52
|
## Use it
|
|
51
53
|
|
|
@@ -65,8 +67,16 @@ function App() {
|
|
|
65
67
|
|
|
66
68
|
return (
|
|
67
69
|
<Stack ref={setStackHandle} initialRouteName="Menu">
|
|
68
|
-
<Stack.Screen
|
|
69
|
-
|
|
70
|
+
<Stack.Screen
|
|
71
|
+
name="Menu"
|
|
72
|
+
component={MenuScreen}
|
|
73
|
+
options={{ title: 'Navigation Demos' }}
|
|
74
|
+
/>
|
|
75
|
+
<Stack.Screen
|
|
76
|
+
name="Details"
|
|
77
|
+
component={DetailsScreen}
|
|
78
|
+
options={{ title: 'Details' }}
|
|
79
|
+
/>
|
|
70
80
|
</Stack>
|
|
71
81
|
);
|
|
72
82
|
}
|
|
@@ -84,8 +94,16 @@ const stackHandle = ref<INavigatorHandle | null>(null);
|
|
|
84
94
|
|
|
85
95
|
<template>
|
|
86
96
|
<Stack ref="stackHandle" initial-route-name="Menu">
|
|
87
|
-
<Screen
|
|
88
|
-
|
|
97
|
+
<Screen
|
|
98
|
+
name="Menu"
|
|
99
|
+
:component="MenuScreen"
|
|
100
|
+
:options="{ title: 'Navigation Demos' }"
|
|
101
|
+
/>
|
|
102
|
+
<Screen
|
|
103
|
+
name="Details"
|
|
104
|
+
:component="DetailsScreen"
|
|
105
|
+
:options="{ title: 'Details' }"
|
|
106
|
+
/>
|
|
89
107
|
</Stack>
|
|
90
108
|
</template>
|
|
91
109
|
```
|
|
@@ -100,8 +118,18 @@ import { Stack, ScreenDirective } from '@symbiote-native/navigation/angular';
|
|
|
100
118
|
imports: [Stack, ScreenDirective],
|
|
101
119
|
template: `
|
|
102
120
|
<Stack #nav initialRouteName="Menu">
|
|
103
|
-
<ng-template
|
|
104
|
-
|
|
121
|
+
<ng-template
|
|
122
|
+
symbioteScreen
|
|
123
|
+
name="Menu"
|
|
124
|
+
[component]="menuScreen"
|
|
125
|
+
[options]="menuOptions"
|
|
126
|
+
></ng-template>
|
|
127
|
+
<ng-template
|
|
128
|
+
symbioteScreen
|
|
129
|
+
name="Details"
|
|
130
|
+
[component]="detailsScreen"
|
|
131
|
+
[options]="detailsOptions"
|
|
132
|
+
></ng-template>
|
|
105
133
|
</Stack>
|
|
106
134
|
`,
|
|
107
135
|
})
|
|
@@ -125,8 +153,10 @@ swipeable drawer navigator (`Drawer`/`Drawer.Screen`, built on `PanResponder`/`A
|
|
|
125
153
|
codebase doesn't depend on `react-native-gesture-handler`/`react-native-reanimated` — see
|
|
126
154
|
[Known gaps](#known-gaps-drawer-parity) below), the full `useNavigation`/`useRoute`/
|
|
127
155
|
`useIsFocused`/`useFocusEffect`/`useNavigationState` hook family (narrowed per navigator as
|
|
128
|
-
`useStackNavigation`/`useTabNavigation`/`useDrawerNavigation`, with Vue composable
|
|
129
|
-
`inject*` twins of all of them
|
|
156
|
+
`useStackNavigation`/`useTabNavigation`/`useDrawerNavigation`, with Vue composable, Svelte rune,
|
|
157
|
+
Solid primitive and Angular `inject*` twins of all of them — Solid spells the three that own state
|
|
158
|
+
`createIsFocused`/`createFocusEffect`/`createNavigationState`, since it reserves `use*` for reading
|
|
159
|
+
an existing context), header/search-bar screen options (bar buttons, menus,
|
|
130
160
|
`formSheet`/modal presentation, `sheetAllowedDetents`), a `resolveRouteFromUrl`/
|
|
131
161
|
`useLinkingIntegration` deep-linking layer, and `serializeNavigatorState`/
|
|
132
162
|
`deserializeNavigatorState` for state persistence. See the docs-site navigation section
|
|
@@ -153,7 +183,7 @@ horizontal `ScrollView` hijacking the swipe), `useDrawerProgress` as a UI-thread
|
|
|
153
183
|
## Test it
|
|
154
184
|
|
|
155
185
|
Headless tests live next to each adapter entry and the shared core
|
|
156
|
-
(`src/{core,react,vue,angular}/**/*.test.{ts,tsx}`) and drive the same reducers/prop folds every
|
|
186
|
+
(`src/{core,react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`) and drive the same reducers/prop folds every
|
|
157
187
|
adapter shares, plus per-adapter component tests against a fake `nativeFabricUIManager` slot.
|
|
158
188
|
Native rendering (the real `RNSScreenStack` push/pop transitions, header/search-bar chrome,
|
|
159
189
|
`formSheet` detents) is verified on-device (see the parent [README](../../README.md) for the
|
|
@@ -92,7 +92,10 @@ let Drawer = (() => {
|
|
|
92
92
|
@for (slot of slotOrder(); track slot) {
|
|
93
93
|
@switch (slot) {
|
|
94
94
|
@case ('content') {
|
|
95
|
-
<AnimatedView
|
|
95
|
+
<AnimatedView
|
|
96
|
+
[style]="contentStyle()"
|
|
97
|
+
[animatedProps]="slotAnimatedProps('content')"
|
|
98
|
+
>
|
|
96
99
|
@if (focusedRoute(); as route) {
|
|
97
100
|
@if (componentForRoute(route); as component) {
|
|
98
101
|
<ng-container
|
|
@@ -113,7 +116,10 @@ let Drawer = (() => {
|
|
|
113
116
|
/>
|
|
114
117
|
}
|
|
115
118
|
@case ('panel') {
|
|
116
|
-
<AnimatedView
|
|
119
|
+
<AnimatedView
|
|
120
|
+
[style]="panelStyle()"
|
|
121
|
+
[animatedProps]="slotAnimatedProps('panel')"
|
|
122
|
+
>
|
|
117
123
|
@if (drawerContentTemplate) {
|
|
118
124
|
<ng-container
|
|
119
125
|
*ngTemplateOutlet="
|
|
@@ -214,7 +220,8 @@ let Drawer = (() => {
|
|
|
214
220
|
swipeEdgeWidth = (__runInitializers(this, _swipeEnabled_extraInitializers), __runInitializers(this, _swipeEdgeWidth_initializers, void 0));
|
|
215
221
|
swipeMinDistance = (__runInitializers(this, _swipeEdgeWidth_extraInitializers), __runInitializers(this, _swipeMinDistance_initializers, void 0));
|
|
216
222
|
swipeMinVelocity = (__runInitializers(this, _swipeMinDistance_extraInitializers), __runInitializers(this, _swipeMinVelocity_initializers, void 0));
|
|
217
|
-
windowDimensions = (__runInitializers(this, _swipeMinVelocity_extraInitializers), inject(WindowDimensionsService)
|
|
223
|
+
windowDimensions = (__runInitializers(this, _swipeMinVelocity_extraInitializers), inject(WindowDimensionsService)
|
|
224
|
+
.dimensions);
|
|
218
225
|
routeIdPrefix = `drawer-${(drawerInstanceCounter += 1)}`;
|
|
219
226
|
// Keyed by name -> the LIVE DrawerScreenDirective instance - see stack.ts's matching comment
|
|
220
227
|
// for why a snapshot copy would go stale on an in-place `[options]`/`[component]` change.
|
|
@@ -243,12 +250,14 @@ let Drawer = (() => {
|
|
|
243
250
|
this.dispatch({ type: 'toggleDrawer' });
|
|
244
251
|
};
|
|
245
252
|
jumpTo = (name) => {
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
253
|
+
// Both sides of the dispatch, mirroring vue/drawer/index.ts's jumpTo: an unregistered name is
|
|
254
|
+
// a documented reducer no-op that hands the SAME state back, so animating off the pre-dispatch
|
|
255
|
+
// snapshot alone would slide the panel shut while the router still says isOpen. The signal is
|
|
256
|
+
// set synchronously inside dispatch, so the second read is already the reducer's own answer.
|
|
249
257
|
const wasOpen = this.stateSignal()?.isOpen ?? false;
|
|
250
258
|
this.dispatch({ type: 'jumpTo', name });
|
|
251
|
-
|
|
259
|
+
const isOpenNow = this.stateSignal()?.isOpen ?? false;
|
|
260
|
+
if (wasOpen && !isOpenNow)
|
|
252
261
|
this.animateProgressTo(false);
|
|
253
262
|
};
|
|
254
263
|
panResponder = PanResponder.create({
|
|
@@ -276,9 +285,10 @@ let Drawer = (() => {
|
|
|
276
285
|
ngAfterContentInit() {
|
|
277
286
|
this.rebuildRegistry();
|
|
278
287
|
this.initializeState();
|
|
279
|
-
this.drawerScreenChildrenSubscription =
|
|
280
|
-
this.
|
|
281
|
-
|
|
288
|
+
this.drawerScreenChildrenSubscription =
|
|
289
|
+
this.drawerScreenChildren.changes.subscribe(() => {
|
|
290
|
+
this.rebuildRegistry();
|
|
291
|
+
});
|
|
282
292
|
}
|
|
283
293
|
ngOnDestroy() {
|
|
284
294
|
this.drawerScreenChildrenSubscription?.unsubscribe();
|
|
@@ -363,7 +373,9 @@ let Drawer = (() => {
|
|
|
363
373
|
overlayColor: this.optionsSnapshot().overlayColor ?? DRAWER_DEFAULT_OVERLAY_COLOR,
|
|
364
374
|
drawerStyle: this.drawerStyleSnapshot(),
|
|
365
375
|
contentPassthrough: {},
|
|
366
|
-
overlayPassthrough: this.isAnimated()
|
|
376
|
+
overlayPassthrough: this.isAnimated()
|
|
377
|
+
? this.overlayResponderPassthrough()
|
|
378
|
+
: {},
|
|
367
379
|
panelPassthrough: {},
|
|
368
380
|
}, this.optionsSnapshot()));
|
|
369
381
|
slotsMap = computed(() => {
|
|
@@ -398,7 +410,9 @@ let Drawer = (() => {
|
|
|
398
410
|
}
|
|
399
411
|
slotStyle(slot, animatedStyle) {
|
|
400
412
|
const base = this.slotsMap().get(slot)?.props.style;
|
|
401
|
-
return this.isAnimated()
|
|
413
|
+
return this.isAnimated()
|
|
414
|
+
? flattenStyle([base, animatedStyle()])
|
|
415
|
+
: flattenStyle(base);
|
|
402
416
|
}
|
|
403
417
|
contentStyle() {
|
|
404
418
|
return this.slotStyle('content', () => {
|
|
@@ -500,7 +514,9 @@ let Drawer = (() => {
|
|
|
500
514
|
navigation: this,
|
|
501
515
|
};
|
|
502
516
|
}
|
|
503
|
-
return {
|
|
517
|
+
return {
|
|
518
|
+
$implicit: { state: currentState, descriptors, navigation: this },
|
|
519
|
+
};
|
|
504
520
|
}
|
|
505
521
|
};
|
|
506
522
|
return Drawer = _classThis;
|
package/build/angular/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { Stack } from './stack';
|
|
|
3
3
|
export type { INavigatorHandle } from './stack';
|
|
4
4
|
export { ScreenDirective } from './screen.directive';
|
|
5
5
|
export type { IAngularScreenOptions, IAngularSearchBarOptions, IScreenOptionsArgs, IScreenOptionsResolver, } from './screen.directive';
|
|
6
|
-
export type { IScreenOptions, IStackAnimation, IStackPresentation } from '../core';
|
|
6
|
+
export type { IScreenOptions, IStackAnimation, IStackPresentation, } from '../core';
|
|
7
7
|
export { injectNavigation, injectStackNavigation, injectTabNavigation, injectDrawerNavigation, injectRoute, injectIsFocused, injectFocusEffect, injectNavigationState, } from './injectors';
|
|
8
8
|
export type { INavigationHandle, IStackNavigationHandle, ITabNavigationHandle, IDrawerNavigationHandle, IFocusEffectCallback, } from './injectors';
|
|
9
9
|
export { NavigationContextService } from './navigation-context.service';
|
|
@@ -14,10 +14,10 @@ export type { ILinkingConfig, IScreenLinkingConfig } from '../core';
|
|
|
14
14
|
export { Tab } from './tabs';
|
|
15
15
|
export type { ITabNavigatorHandle } from './tabs';
|
|
16
16
|
export { TabScreenDirective } from './tab-screen.directive';
|
|
17
|
-
export type { ITabScreenOptionsArgs, ITabScreenOptionsResolver } from './tab-screen.directive';
|
|
17
|
+
export type { ITabScreenOptionsArgs, ITabScreenOptionsResolver, } from './tab-screen.directive';
|
|
18
18
|
export type { ITabOptions, ITabBarIcon } from '../core';
|
|
19
19
|
export { Drawer } from './drawer';
|
|
20
|
-
export type { IDrawerNavigatorHandle, IDrawerDescriptorMap, IDrawerContentContext } from './drawer';
|
|
20
|
+
export type { IDrawerNavigatorHandle, IDrawerDescriptorMap, IDrawerContentContext, } from './drawer';
|
|
21
21
|
export { DrawerScreenDirective } from './drawer-screen.directive';
|
|
22
22
|
export type { IDrawerScreenOptionsArgs, IDrawerScreenOptionsResolver, } from './drawer-screen.directive';
|
|
23
|
-
export type { IDrawerOptions, IDrawerScreenOptions, IDrawerType, IDrawerPosition } from '../core';
|
|
23
|
+
export type { IDrawerOptions, IDrawerScreenOptions, IDrawerType, IDrawerPosition, } from '../core';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// that route's own emitter - mirrors @react-navigation's `navigation.addListener('focus', cb)`
|
|
6
6
|
// surface. All pub/sub logic lives in ../../core/navigation-events; this function only reads
|
|
7
7
|
// NavigationContextService and binds identity.
|
|
8
|
-
import { requireNavigationContext } from '../navigation-context.service.js';
|
|
8
|
+
import { requireNavigationContext, } from '../navigation-context.service.js';
|
|
9
9
|
export function injectNavigation() {
|
|
10
10
|
const context = requireNavigationContext('injectNavigation');
|
|
11
11
|
return {
|
|
@@ -41,7 +41,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
41
41
|
return useValue ? value : void 0;
|
|
42
42
|
};
|
|
43
43
|
import { Directive, Input, inject } from '@angular/core';
|
|
44
|
-
import { NavigationContextService } from './navigation-context.service.js';
|
|
44
|
+
import { NavigationContextService, } from './navigation-context.service.js';
|
|
45
45
|
let NavigationScopeDirective = (() => {
|
|
46
46
|
let _classDecorators = [Directive({
|
|
47
47
|
selector: '[symbioteNavigationScope]',
|
|
@@ -40,7 +40,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
40
40
|
}
|
|
41
41
|
return useValue ? value : void 0;
|
|
42
42
|
};
|
|
43
|
-
import { Directive, Input, inject, ElementRef } from '@angular/core';
|
|
43
|
+
import { Directive, Input, inject, ElementRef, } from '@angular/core';
|
|
44
44
|
import { isSymbioteNode, dlog, debugNodeId } from '@symbiote-native/engine';
|
|
45
45
|
import { buildSearchBarHandle } from '../core/index.js';
|
|
46
46
|
let SearchBarRefDirective = (() => {
|
|
@@ -32,9 +32,11 @@ export declare class Stack implements AfterContentInit, OnDestroy, INavigatorHan
|
|
|
32
32
|
ngAfterContentInit(): void;
|
|
33
33
|
ngOnDestroy(): void;
|
|
34
34
|
private rebuildRegistry;
|
|
35
|
+
private reconcileWithRegistry;
|
|
35
36
|
private initializeState;
|
|
36
37
|
private createRoute;
|
|
37
38
|
private dispatch;
|
|
39
|
+
private commitState;
|
|
38
40
|
emitterFor(routeKey: string): INavigationEmitter;
|
|
39
41
|
private mergedOptionsFor;
|
|
40
42
|
componentFor(route: IRoute<unknown>): Type<unknown> | null;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
// self-registers instead: `adapters/angular/babel-register-composed.cjs` (a Metro babel preset
|
|
36
36
|
// applied bundle-wide, not scoped to adapters/angular) scans this package's own AOT-compiled
|
|
37
37
|
// (`ngc`) `ɵɵngDeclareComponent({selector: 'Stack', ...})` output and auto-calls
|
|
38
|
-
// `registerComposedComponent('Stack')` at bundle time - same mechanism
|
|
38
|
+
// `registerComposedComponent('Stack')` at bundle time - same mechanism `examples/angular`
|
|
39
39
|
// navigation-demo screens and `@symbiote-native/slider`'s `Slider` rely on for their own composed
|
|
40
40
|
// components mounted statically or via `NgComponentOutlet`. Unregistered, `createElement('Stack')`
|
|
41
41
|
// falls through to a real `createNode` call and RN paints its own "Unimplemented component"
|
|
@@ -81,13 +81,15 @@ import { ChangeDetectionStrategy, Component, ContentChildren, Input, NO_ERRORS_S
|
|
|
81
81
|
import { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
|
|
82
82
|
import { SymbioteHostPropsDirective } from '@symbiote-native/angular';
|
|
83
83
|
import { Platform, dlog } from '@symbiote-native/engine';
|
|
84
|
-
import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, NAVIGATION_EVENT_STATE, RNS_MODAL_SCREEN_VIEW_NAME, SCREEN_ON_APPEAR, SCREEN_ON_DISAPPEAR, SCREEN_ON_DISMISSED, SCREEN_ON_HEADER_BACK_BUTTON_CLICKED, STACK_ON_FINISH_TRANSITIONING, buildSearchBarPassthrough, createInitialNavigatorState, createNavigationEmitter, navigatorReducer, resolveHeaderInModalStackStyle, resolveScreenRenderPlan, resolveStackProps, } from '../../core/index.js';
|
|
84
|
+
import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, NAVIGATION_EVENT_STATE, RNS_MODAL_SCREEN_VIEW_NAME, SCREEN_ON_APPEAR, SCREEN_ON_DISAPPEAR, SCREEN_ON_DISMISSED, SCREEN_ON_HEADER_BACK_BUTTON_CLICKED, STACK_ON_FINISH_TRANSITIONING, buildSearchBarPassthrough, createInitialNavigatorState, createNavigationEmitter, navigatorReducer, reconcileStackRoutes, resolveHeaderInModalStackStyle, resolveScreenRenderPlan, resolveStackProps, } from '../../core/index.js';
|
|
85
85
|
import { NavigationScopeDirective } from '../navigation-scope.directive.js';
|
|
86
86
|
import { SearchBarRefDirective } from '../search-bar-ref.directive.js';
|
|
87
87
|
import { ScreenDirective } from '../screen.directive.js';
|
|
88
88
|
// backTitleVisible defaults to `true` on both platforms per the codegen spec's own default - no
|
|
89
89
|
// ios/android divergence in v1 scope (mirrors react/stack.ts's own constant exactly).
|
|
90
|
-
const NAVIGATOR_PLATFORM = {
|
|
90
|
+
const NAVIGATOR_PLATFORM = {
|
|
91
|
+
defaultHeaderBackTitleVisible: true,
|
|
92
|
+
};
|
|
91
93
|
let stackInstanceCounter = 0;
|
|
92
94
|
let Stack = (() => {
|
|
93
95
|
let _classDecorators = [Component({
|
|
@@ -151,7 +153,9 @@ let Stack = (() => {
|
|
|
151
153
|
</ng-template>
|
|
152
154
|
|
|
153
155
|
<ng-template #headerAndContentTpl let-route let-index="index">
|
|
154
|
-
<RNSScreenStackHeaderConfig
|
|
156
|
+
<RNSScreenStackHeaderConfig
|
|
157
|
+
[symbioteHostProps]="headerConfigProps(route, index)"
|
|
158
|
+
>
|
|
155
159
|
@if (hasSearchBar(route)) {
|
|
156
160
|
<RNSScreenStackHeaderSubview [symbioteHostProps]="headerSubviewProps">
|
|
157
161
|
<RNSSearchBar
|
|
@@ -161,7 +165,9 @@ let Stack = (() => {
|
|
|
161
165
|
</RNSScreenStackHeaderSubview>
|
|
162
166
|
}
|
|
163
167
|
</RNSScreenStackHeaderConfig>
|
|
164
|
-
<RNSScreenContentWrapper
|
|
168
|
+
<RNSScreenContentWrapper
|
|
169
|
+
[symbioteHostProps]="contentWrapperProps(route, index)"
|
|
170
|
+
>
|
|
165
171
|
<ng-container
|
|
166
172
|
[symbioteNavigationScope]="route"
|
|
167
173
|
[navigation]="this"
|
|
@@ -246,6 +252,21 @@ let Stack = (() => {
|
|
|
246
252
|
for (const screen of this.screenChildren) {
|
|
247
253
|
this.registry.set(screen.name, screen);
|
|
248
254
|
}
|
|
255
|
+
this.reconcileWithRegistry();
|
|
256
|
+
}
|
|
257
|
+
// A `<ng-template symbioteScreen>` marker can leave the @ContentChildren query (a marker behind
|
|
258
|
+
// an `@if`, a data-driven screen list) while its route is still in the pushed history, which
|
|
259
|
+
// would leave that entry with nothing for componentFor() to mount (reconcileStackRoutes' header).
|
|
260
|
+
// The signal write lives HERE, in the query-change callback, and never in a computed/template
|
|
261
|
+
// accessor - reconciliation is a reaction to the registry changing, not a derivation of it.
|
|
262
|
+
reconcileWithRegistry() {
|
|
263
|
+
const current = this.stateSignal();
|
|
264
|
+
if (current === undefined)
|
|
265
|
+
return;
|
|
266
|
+
const next = reconcileStackRoutes(current, [...this.registry.keys()]);
|
|
267
|
+
if (next === current)
|
|
268
|
+
return;
|
|
269
|
+
this.commitState(next);
|
|
249
270
|
}
|
|
250
271
|
initializeState() {
|
|
251
272
|
if (this.stateSignal() !== undefined)
|
|
@@ -253,20 +274,33 @@ let Stack = (() => {
|
|
|
253
274
|
const initialRouteName = this.initialRouteName ?? this.registry.keys().next().value;
|
|
254
275
|
if (initialRouteName === undefined) {
|
|
255
276
|
dlog('Stack: no <ng-template symbioteScreen> children registered');
|
|
256
|
-
this.stateSignal.set(createInitialNavigatorState({
|
|
277
|
+
this.stateSignal.set(createInitialNavigatorState({
|
|
278
|
+
key: this.routeIdPrefix,
|
|
279
|
+
name: '',
|
|
280
|
+
params: undefined,
|
|
281
|
+
}));
|
|
257
282
|
return;
|
|
258
283
|
}
|
|
259
284
|
this.stateSignal.set(createInitialNavigatorState(this.createRoute(initialRouteName, this.registry.get(initialRouteName)?.initialParams)));
|
|
260
285
|
}
|
|
261
286
|
createRoute(name, params) {
|
|
262
287
|
this.routeSequence += 1;
|
|
263
|
-
return {
|
|
288
|
+
return {
|
|
289
|
+
key: `${this.routeIdPrefix}-${name}-${this.routeSequence}`,
|
|
290
|
+
name,
|
|
291
|
+
params,
|
|
292
|
+
};
|
|
264
293
|
}
|
|
265
294
|
dispatch(action) {
|
|
266
295
|
const current = this.stateSignal();
|
|
267
296
|
if (current === undefined)
|
|
268
297
|
return;
|
|
269
|
-
|
|
298
|
+
this.commitState(navigatorReducer(current, action));
|
|
299
|
+
}
|
|
300
|
+
// The one write path into stateSignal, shared by a dispatched action and a registry-driven
|
|
301
|
+
// reconciliation: both invalidate the plan cache, broadcast to every still-live route, and prune
|
|
302
|
+
// the emitters of routes that are gone.
|
|
303
|
+
commitState(next) {
|
|
270
304
|
this.planCache.clear();
|
|
271
305
|
this.stateSignal.set(next);
|
|
272
306
|
const liveRouteKeys = new Set(next.routes.map(route => route.key));
|
|
@@ -350,7 +384,7 @@ let Stack = (() => {
|
|
|
350
384
|
return plan;
|
|
351
385
|
}
|
|
352
386
|
outerScreenIsModal(route, index) {
|
|
353
|
-
return this.planFor(route, index).screenViewName === RNS_MODAL_SCREEN_VIEW_NAME;
|
|
387
|
+
return (this.planFor(route, index).screenViewName === RNS_MODAL_SCREEN_VIEW_NAME);
|
|
354
388
|
}
|
|
355
389
|
isInModal(route, index) {
|
|
356
390
|
return this.planFor(route, index).inModal;
|
|
@@ -32,7 +32,7 @@ export declare class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHa
|
|
|
32
32
|
ngOnDestroy(): void;
|
|
33
33
|
private rebuildRegistry;
|
|
34
34
|
private routesFromRegistry;
|
|
35
|
-
private
|
|
35
|
+
private syncRegistry;
|
|
36
36
|
private dispatch;
|
|
37
37
|
private resolveTabOptions;
|
|
38
38
|
focusedRoute(): IRoute<unknown> | undefined;
|
|
@@ -53,7 +53,7 @@ import { ChangeDetectionStrategy, Component, ContentChildren, Input, QueryList,
|
|
|
53
53
|
import { NgComponentOutlet } from '@angular/common';
|
|
54
54
|
import { dlog } from '@symbiote-native/engine';
|
|
55
55
|
import { DescriptorOutlet, View } from '@symbiote-native/angular';
|
|
56
|
-
import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, createInitialTabState, createNavigationEmitter, diffFocusedRoute, isFocusedRoute, renderTabBar, tabRouterReducer, } from '../../core/index.js';
|
|
56
|
+
import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, createInitialTabState, createNavigationEmitter, diffFocusedRoute, isFocusedRoute, reconcileTabRoutes, renderTabBar, tabRouterReducer, } from '../../core/index.js';
|
|
57
57
|
import { NavigationScopeDirective } from '../navigation-scope.directive.js';
|
|
58
58
|
import { TabScreenDirective } from '../tab-screen.directive.js';
|
|
59
59
|
const TAB_ROOT_STYLE = { flex: 1 };
|
|
@@ -63,7 +63,12 @@ let Tab = (() => {
|
|
|
63
63
|
let _classDecorators = [Component({
|
|
64
64
|
selector: 'Tab',
|
|
65
65
|
standalone: true,
|
|
66
|
-
imports: [
|
|
66
|
+
imports: [
|
|
67
|
+
NgComponentOutlet,
|
|
68
|
+
NavigationScopeDirective,
|
|
69
|
+
DescriptorOutlet,
|
|
70
|
+
View,
|
|
71
|
+
],
|
|
67
72
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
68
73
|
template: `
|
|
69
74
|
<View [style]="rootStyle">
|
|
@@ -128,11 +133,11 @@ let Tab = (() => {
|
|
|
128
133
|
jumpTo = (name, params) => this.dispatch({ type: 'jumpTo', name, params });
|
|
129
134
|
setParams = (params, key) => this.dispatch({ type: 'setParams', key, params });
|
|
130
135
|
ngAfterContentInit() {
|
|
131
|
-
this.
|
|
132
|
-
this.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
this.syncRegistry();
|
|
137
|
+
this.tabScreenChildrenSubscription =
|
|
138
|
+
this.tabScreenChildren.changes.subscribe(() => {
|
|
139
|
+
this.syncRegistry();
|
|
140
|
+
});
|
|
136
141
|
}
|
|
137
142
|
ngOnDestroy() {
|
|
138
143
|
this.tabScreenChildrenSubscription?.unsubscribe();
|
|
@@ -152,12 +157,26 @@ let Tab = (() => {
|
|
|
152
157
|
params: entry.initialParams,
|
|
153
158
|
}));
|
|
154
159
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
// A <ng-template symbioteTabScreen> can appear or disappear after mount (a marker behind an
|
|
161
|
+
// @if, a data-driven screen list), so the route list follows the LIVE query instead of staying
|
|
162
|
+
// frozen at whatever ngAfterContentInit first saw: reconcileTabRoutes (core) keeps each
|
|
163
|
+
// surviving route's key and accumulated params and moves focus only when the focused route is
|
|
164
|
+
// the one that left. Runs from the query's own `changes` subscription - an ordinary imperative
|
|
165
|
+
// callback, deliberately not a computed, since this writes the state signal.
|
|
166
|
+
syncRegistry() {
|
|
167
|
+
this.rebuildRegistry();
|
|
158
168
|
const routes = this.routesFromRegistry();
|
|
159
169
|
if (routes.length === 0)
|
|
160
170
|
dlog('Tab: no <ng-template symbioteTabScreen> children registered');
|
|
171
|
+
const current = this.stateSignal();
|
|
172
|
+
if (current !== undefined) {
|
|
173
|
+
this.stateSignal.set(reconcileTabRoutes(current, routes));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Seeding an empty list would resolve initialRouteName against nothing and lose it once the
|
|
177
|
+
// markers do arrive, so the state stays unseeded until at least one has registered.
|
|
178
|
+
if (routes.length === 0)
|
|
179
|
+
return;
|
|
161
180
|
this.stateSignal.set(createInitialTabState(routes, this.initialRouteName));
|
|
162
181
|
}
|
|
163
182
|
dispatch(action) {
|
|
@@ -168,7 +187,9 @@ let Tab = (() => {
|
|
|
168
187
|
}
|
|
169
188
|
resolveTabOptions(entry, route) {
|
|
170
189
|
const props = { route, navigation: this };
|
|
171
|
-
const own = typeof entry.options === 'function'
|
|
190
|
+
const own = typeof entry.options === 'function'
|
|
191
|
+
? entry.options(props)
|
|
192
|
+
: entry.options;
|
|
172
193
|
return { ...this.screenOptions, ...own };
|
|
173
194
|
}
|
|
174
195
|
focusedRoute() {
|
|
@@ -251,11 +272,17 @@ let Tab = (() => {
|
|
|
251
272
|
};
|
|
252
273
|
});
|
|
253
274
|
const focusedRoute = this.focusedRoute();
|
|
254
|
-
const focusedEntry = focusedRoute
|
|
275
|
+
const focusedEntry = focusedRoute
|
|
276
|
+
? this.registry.get(focusedRoute.name)
|
|
277
|
+
: undefined;
|
|
255
278
|
const focusedOptions = focusedEntry && focusedRoute
|
|
256
279
|
? this.resolveTabOptions(focusedEntry, focusedRoute)
|
|
257
280
|
: this.screenOptions;
|
|
258
|
-
return renderTabBar({
|
|
281
|
+
return renderTabBar({
|
|
282
|
+
items,
|
|
283
|
+
style: focusedOptions?.tabBarStyle,
|
|
284
|
+
passthrough: {},
|
|
285
|
+
});
|
|
259
286
|
}
|
|
260
287
|
};
|
|
261
288
|
return Tab = _classThis;
|
|
@@ -85,25 +85,37 @@ export function resolveDrawerSlotInterpolation(geometry, slot) {
|
|
|
85
85
|
return {
|
|
86
86
|
translateX: {
|
|
87
87
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
88
|
-
outputRange: [
|
|
88
|
+
outputRange: [
|
|
89
|
+
geometry.contentTranslateXClosed,
|
|
90
|
+
geometry.contentTranslateXOpen,
|
|
91
|
+
],
|
|
89
92
|
},
|
|
90
93
|
};
|
|
91
94
|
case 'overlay':
|
|
92
95
|
return {
|
|
93
96
|
opacity: {
|
|
94
97
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
95
|
-
outputRange: [
|
|
98
|
+
outputRange: [
|
|
99
|
+
geometry.overlayOpacityClosed,
|
|
100
|
+
geometry.overlayOpacityOpen,
|
|
101
|
+
],
|
|
96
102
|
},
|
|
97
103
|
translateX: {
|
|
98
104
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
99
|
-
outputRange: [
|
|
105
|
+
outputRange: [
|
|
106
|
+
geometry.contentTranslateXClosed,
|
|
107
|
+
geometry.contentTranslateXOpen,
|
|
108
|
+
],
|
|
100
109
|
},
|
|
101
110
|
};
|
|
102
111
|
case 'panel':
|
|
103
112
|
return {
|
|
104
113
|
translateX: {
|
|
105
114
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
106
|
-
outputRange: [
|
|
115
|
+
outputRange: [
|
|
116
|
+
geometry.panelTranslateXClosed,
|
|
117
|
+
geometry.panelTranslateXOpen,
|
|
118
|
+
],
|
|
107
119
|
},
|
|
108
120
|
};
|
|
109
121
|
}
|
|
@@ -154,7 +166,9 @@ export function clamp01(value) {
|
|
|
154
166
|
return Math.min(1, Math.max(0, value));
|
|
155
167
|
}
|
|
156
168
|
function toFiniteNumber(value) {
|
|
157
|
-
return typeof value === 'number' && Number.isFinite(value)
|
|
169
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
170
|
+
? value
|
|
171
|
+
: undefined;
|
|
158
172
|
}
|
|
159
173
|
// The touch's real starting page-X, read off the raw event rather than gestureState.x0: the
|
|
160
174
|
// engine's capture phase (core/engine/src/pan-responder/index.ts's
|
|
@@ -11,7 +11,11 @@ export function createInitialDrawerRouterState(routes, initialRouteName) {
|
|
|
11
11
|
return { routes, index: INITIAL_FOCUSED_INDEX, isOpen: false };
|
|
12
12
|
}
|
|
13
13
|
const index = routes.findIndex(route => route.name === initialRouteName);
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
routes,
|
|
16
|
+
index: index === -1 ? INITIAL_FOCUSED_INDEX : index,
|
|
17
|
+
isOpen: false,
|
|
18
|
+
};
|
|
15
19
|
}
|
|
16
20
|
// Mirrors @react-navigation/drawer's DrawerActions: jumpTo focuses a route by NAME (TabRouter's
|
|
17
21
|
// own convention, not the stack's by-key popTo) AND closes the drawer - selecting a destination
|
|
@@ -23,7 +27,9 @@ export function drawerRouterReducer(state, action) {
|
|
|
23
27
|
const index = state.routes.findIndex(route => route.name === action.name);
|
|
24
28
|
if (index === -1)
|
|
25
29
|
return state;
|
|
26
|
-
return index === state.index && !state.isOpen
|
|
30
|
+
return index === state.index && !state.isOpen
|
|
31
|
+
? state
|
|
32
|
+
: { ...state, index, isOpen: false };
|
|
27
33
|
}
|
|
28
34
|
case 'openDrawer':
|
|
29
35
|
return state.isOpen ? state : { ...state, isOpen: true };
|
package/build/core/guards.js
CHANGED
|
@@ -18,5 +18,7 @@ export function isRecord(value) {
|
|
|
18
18
|
// navigator-state.ts (Stack) and tab-router-state.ts (Tabs) so the two reducers can't drift on
|
|
19
19
|
// this rule independently.
|
|
20
20
|
export function mergeParams(current, incoming) {
|
|
21
|
-
return isRecord(current) && isRecord(incoming)
|
|
21
|
+
return isRecord(current) && isRecord(incoming)
|
|
22
|
+
? { ...current, ...incoming }
|
|
23
|
+
: incoming;
|
|
22
24
|
}
|
|
@@ -21,7 +21,9 @@ function prepareIcon(icon) {
|
|
|
21
21
|
case 'imageSource':
|
|
22
22
|
return { imageSource: imageStatics.resolveAssetSource(icon.imageSource) };
|
|
23
23
|
case 'templateSource':
|
|
24
|
-
return {
|
|
24
|
+
return {
|
|
25
|
+
templateSource: imageStatics.resolveAssetSource(icon.templateSource),
|
|
26
|
+
};
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
// The one id algorithm both the payload tagger (prepareMenuItems/prepareHeaderBarButtonItems)
|
|
@@ -38,7 +40,9 @@ function prepareTitleStyle(titleStyle) {
|
|
|
38
40
|
return undefined;
|
|
39
41
|
return {
|
|
40
42
|
...titleStyle,
|
|
41
|
-
color: titleStyle.color === undefined
|
|
43
|
+
color: titleStyle.color === undefined
|
|
44
|
+
? undefined
|
|
45
|
+
: processColor(titleStyle.color),
|
|
42
46
|
};
|
|
43
47
|
}
|
|
44
48
|
function prepareBadge(badge) {
|
|
@@ -49,7 +53,9 @@ function prepareBadge(badge) {
|
|
|
49
53
|
style: badge.style
|
|
50
54
|
? {
|
|
51
55
|
...badge.style,
|
|
52
|
-
color: badge.style.color === undefined
|
|
56
|
+
color: badge.style.color === undefined
|
|
57
|
+
? undefined
|
|
58
|
+
: processColor(badge.style.color),
|
|
53
59
|
backgroundColor: badge.style.backgroundColor === undefined
|
|
54
60
|
? undefined
|
|
55
61
|
: processColor(badge.style.backgroundColor),
|
|
@@ -88,7 +94,11 @@ function prepareMenuItems(menuLike, index, side, path = '') {
|
|
|
88
94
|
const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
|
|
89
95
|
const icon = prepareIcon(menuItem.icon);
|
|
90
96
|
if (menuItem.type === 'submenu') {
|
|
91
|
-
return {
|
|
97
|
+
return {
|
|
98
|
+
...menuItem,
|
|
99
|
+
...icon,
|
|
100
|
+
...prepareMenuItems(menuItem, index, side, currentPath),
|
|
101
|
+
};
|
|
92
102
|
}
|
|
93
103
|
return {
|
|
94
104
|
...excludeOnPress(menuItem),
|