@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
|
@@ -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"
|
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
createInitialNavigatorState,
|
|
74
74
|
createNavigationEmitter,
|
|
75
75
|
navigatorReducer,
|
|
76
|
+
reconcileStackRoutes,
|
|
76
77
|
resolveHeaderInModalStackStyle,
|
|
77
78
|
resolveScreenRenderPlan,
|
|
78
79
|
resolveStackProps,
|
|
@@ -90,13 +91,18 @@ import type {
|
|
|
90
91
|
import { NavigationScopeDirective } from '../navigation-scope.directive';
|
|
91
92
|
import { SearchBarRefDirective } from '../search-bar-ref.directive';
|
|
92
93
|
import { ScreenDirective } from '../screen.directive';
|
|
93
|
-
import type {
|
|
94
|
+
import type {
|
|
95
|
+
IAngularScreenOptions,
|
|
96
|
+
IScreenOptionsArgs,
|
|
97
|
+
} from '../screen.directive';
|
|
94
98
|
|
|
95
99
|
export type { INavigatorHandle } from '../../core';
|
|
96
100
|
|
|
97
101
|
// backTitleVisible defaults to `true` on both platforms per the codegen spec's own default - no
|
|
98
102
|
// ios/android divergence in v1 scope (mirrors react/stack.ts's own constant exactly).
|
|
99
|
-
const NAVIGATOR_PLATFORM: INavigatorPlatform = {
|
|
103
|
+
const NAVIGATOR_PLATFORM: INavigatorPlatform = {
|
|
104
|
+
defaultHeaderBackTitleVisible: true,
|
|
105
|
+
};
|
|
100
106
|
|
|
101
107
|
let stackInstanceCounter = 0;
|
|
102
108
|
|
|
@@ -161,7 +167,9 @@ let stackInstanceCounter = 0;
|
|
|
161
167
|
</ng-template>
|
|
162
168
|
|
|
163
169
|
<ng-template #headerAndContentTpl let-route let-index="index">
|
|
164
|
-
<RNSScreenStackHeaderConfig
|
|
170
|
+
<RNSScreenStackHeaderConfig
|
|
171
|
+
[symbioteHostProps]="headerConfigProps(route, index)"
|
|
172
|
+
>
|
|
165
173
|
@if (hasSearchBar(route)) {
|
|
166
174
|
<RNSScreenStackHeaderSubview [symbioteHostProps]="headerSubviewProps">
|
|
167
175
|
<RNSSearchBar
|
|
@@ -171,7 +179,9 @@ let stackInstanceCounter = 0;
|
|
|
171
179
|
</RNSScreenStackHeaderSubview>
|
|
172
180
|
}
|
|
173
181
|
</RNSScreenStackHeaderConfig>
|
|
174
|
-
<RNSScreenContentWrapper
|
|
182
|
+
<RNSScreenContentWrapper
|
|
183
|
+
[symbioteHostProps]="contentWrapperProps(route, index)"
|
|
184
|
+
>
|
|
175
185
|
<ng-container
|
|
176
186
|
[symbioteNavigationScope]="route"
|
|
177
187
|
[navigation]="this"
|
|
@@ -184,7 +194,8 @@ let stackInstanceCounter = 0;
|
|
|
184
194
|
`,
|
|
185
195
|
})
|
|
186
196
|
export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
187
|
-
@ContentChildren(ScreenDirective)
|
|
197
|
+
@ContentChildren(ScreenDirective)
|
|
198
|
+
private readonly screenChildren!: QueryList<ScreenDirective>;
|
|
188
199
|
|
|
189
200
|
@Input() initialRouteName?: string;
|
|
190
201
|
@Input() screenOptions?: IAngularScreenOptions;
|
|
@@ -214,7 +225,8 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
214
225
|
|
|
215
226
|
readonly push = (name: string, params?: unknown): void =>
|
|
216
227
|
this.dispatch({ type: 'push', route: this.createRoute(name, params) });
|
|
217
|
-
readonly pop = (count?: number): void =>
|
|
228
|
+
readonly pop = (count?: number): void =>
|
|
229
|
+
this.dispatch({ type: 'pop', count });
|
|
218
230
|
readonly popToTop = (): void => this.dispatch({ type: 'popToTop' });
|
|
219
231
|
readonly popTo = (key: string): void => this.dispatch({ type: 'popTo', key });
|
|
220
232
|
readonly replace = (name: string, params?: unknown): void =>
|
|
@@ -223,14 +235,17 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
223
235
|
this.dispatch({ type: 'setParams', key, params });
|
|
224
236
|
readonly reset = (nextState: INavigatorState): void =>
|
|
225
237
|
this.dispatch({ type: 'reset', state: nextState });
|
|
226
|
-
readonly canGoBack = (): boolean =>
|
|
238
|
+
readonly canGoBack = (): boolean =>
|
|
239
|
+
(this.stateSignal()?.routes.length ?? 0) > 1;
|
|
227
240
|
|
|
228
241
|
ngAfterContentInit(): void {
|
|
229
242
|
this.rebuildRegistry();
|
|
230
243
|
this.initializeState();
|
|
231
|
-
this.screenChildrenSubscription = this.screenChildren.changes.subscribe(
|
|
232
|
-
|
|
233
|
-
|
|
244
|
+
this.screenChildrenSubscription = this.screenChildren.changes.subscribe(
|
|
245
|
+
() => {
|
|
246
|
+
this.rebuildRegistry();
|
|
247
|
+
},
|
|
248
|
+
);
|
|
234
249
|
}
|
|
235
250
|
|
|
236
251
|
ngOnDestroy(): void {
|
|
@@ -242,34 +257,66 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
242
257
|
for (const screen of this.screenChildren) {
|
|
243
258
|
this.registry.set(screen.name, screen);
|
|
244
259
|
}
|
|
260
|
+
this.reconcileWithRegistry();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// A `<ng-template symbioteScreen>` marker can leave the @ContentChildren query (a marker behind
|
|
264
|
+
// an `@if`, a data-driven screen list) while its route is still in the pushed history, which
|
|
265
|
+
// would leave that entry with nothing for componentFor() to mount (reconcileStackRoutes' header).
|
|
266
|
+
// The signal write lives HERE, in the query-change callback, and never in a computed/template
|
|
267
|
+
// accessor - reconciliation is a reaction to the registry changing, not a derivation of it.
|
|
268
|
+
private reconcileWithRegistry(): void {
|
|
269
|
+
const current = this.stateSignal();
|
|
270
|
+
if (current === undefined) return;
|
|
271
|
+
const next = reconcileStackRoutes(current, [...this.registry.keys()]);
|
|
272
|
+
if (next === current) return;
|
|
273
|
+
this.commitState(next);
|
|
245
274
|
}
|
|
246
275
|
|
|
247
276
|
private initializeState(): void {
|
|
248
277
|
if (this.stateSignal() !== undefined) return;
|
|
249
|
-
const initialRouteName =
|
|
278
|
+
const initialRouteName =
|
|
279
|
+
this.initialRouteName ?? this.registry.keys().next().value;
|
|
250
280
|
if (initialRouteName === undefined) {
|
|
251
281
|
dlog('Stack: no <ng-template symbioteScreen> children registered');
|
|
252
282
|
this.stateSignal.set(
|
|
253
|
-
createInitialNavigatorState({
|
|
283
|
+
createInitialNavigatorState({
|
|
284
|
+
key: this.routeIdPrefix,
|
|
285
|
+
name: '',
|
|
286
|
+
params: undefined,
|
|
287
|
+
}),
|
|
254
288
|
);
|
|
255
289
|
return;
|
|
256
290
|
}
|
|
257
291
|
this.stateSignal.set(
|
|
258
292
|
createInitialNavigatorState(
|
|
259
|
-
this.createRoute(
|
|
293
|
+
this.createRoute(
|
|
294
|
+
initialRouteName,
|
|
295
|
+
this.registry.get(initialRouteName)?.initialParams,
|
|
296
|
+
),
|
|
260
297
|
),
|
|
261
298
|
);
|
|
262
299
|
}
|
|
263
300
|
|
|
264
301
|
private createRoute(name: string, params: unknown): IRoute<unknown> {
|
|
265
302
|
this.routeSequence += 1;
|
|
266
|
-
return {
|
|
303
|
+
return {
|
|
304
|
+
key: `${this.routeIdPrefix}-${name}-${this.routeSequence}`,
|
|
305
|
+
name,
|
|
306
|
+
params,
|
|
307
|
+
};
|
|
267
308
|
}
|
|
268
309
|
|
|
269
310
|
private dispatch(action: INavigatorAction): void {
|
|
270
311
|
const current = this.stateSignal();
|
|
271
312
|
if (current === undefined) return;
|
|
272
|
-
|
|
313
|
+
this.commitState(navigatorReducer(current, action));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// The one write path into stateSignal, shared by a dispatched action and a registry-driven
|
|
317
|
+
// reconciliation: both invalidate the plan cache, broadcast to every still-live route, and prune
|
|
318
|
+
// the emitters of routes that are gone.
|
|
319
|
+
private commitState(next: INavigatorState): void {
|
|
273
320
|
this.planCache.clear();
|
|
274
321
|
this.stateSignal.set(next);
|
|
275
322
|
const liveRouteKeys = new Set(next.routes.map(route => route.key));
|
|
@@ -340,7 +387,8 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
340
387
|
isAndroid: Platform.OS === 'android',
|
|
341
388
|
screenPassthrough: {
|
|
342
389
|
[SCREEN_ON_DISMISSED]: () => this.dispatch({ type: 'pop', count: 1 }),
|
|
343
|
-
[SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
|
|
390
|
+
[SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
|
|
391
|
+
this.dispatch({ type: 'pop', count: 1 }),
|
|
344
392
|
[SCREEN_ON_APPEAR]: () => {
|
|
345
393
|
dlog(`Stack: route "${route.name}" appeared (focus)`);
|
|
346
394
|
this.emitterFor(route.key).emit(NAVIGATION_EVENT_FOCUS);
|
|
@@ -359,14 +407,19 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
359
407
|
}
|
|
360
408
|
|
|
361
409
|
outerScreenIsModal(route: IRoute<unknown>, index: number): boolean {
|
|
362
|
-
return
|
|
410
|
+
return (
|
|
411
|
+
this.planFor(route, index).screenViewName === RNS_MODAL_SCREEN_VIEW_NAME
|
|
412
|
+
);
|
|
363
413
|
}
|
|
364
414
|
|
|
365
415
|
isInModal(route: IRoute<unknown>, index: number): boolean {
|
|
366
416
|
return this.planFor(route, index).inModal;
|
|
367
417
|
}
|
|
368
418
|
|
|
369
|
-
screenHostProps(
|
|
419
|
+
screenHostProps(
|
|
420
|
+
route: IRoute<unknown>,
|
|
421
|
+
index: number,
|
|
422
|
+
): Record<string, unknown> {
|
|
370
423
|
return this.planFor(route, index).screenProps;
|
|
371
424
|
}
|
|
372
425
|
|
|
@@ -374,16 +427,25 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
374
427
|
return { style: resolveHeaderInModalStackStyle() };
|
|
375
428
|
}
|
|
376
429
|
|
|
377
|
-
innerScreenProps(
|
|
430
|
+
innerScreenProps(
|
|
431
|
+
route: IRoute<unknown>,
|
|
432
|
+
index: number,
|
|
433
|
+
): Record<string, unknown> {
|
|
378
434
|
const plan = this.planFor(route, index);
|
|
379
435
|
return { style: plan.innerScreenStyle, activityState: plan.activityState };
|
|
380
436
|
}
|
|
381
437
|
|
|
382
|
-
contentWrapperProps(
|
|
438
|
+
contentWrapperProps(
|
|
439
|
+
route: IRoute<unknown>,
|
|
440
|
+
index: number,
|
|
441
|
+
): Record<string, unknown> {
|
|
383
442
|
return this.planFor(route, index).contentWrapperProps;
|
|
384
443
|
}
|
|
385
444
|
|
|
386
|
-
headerConfigProps(
|
|
445
|
+
headerConfigProps(
|
|
446
|
+
route: IRoute<unknown>,
|
|
447
|
+
index: number,
|
|
448
|
+
): Record<string, unknown> {
|
|
387
449
|
return this.planFor(route, index).headerConfig.props;
|
|
388
450
|
}
|
|
389
451
|
|
|
@@ -391,11 +453,16 @@ export class Stack implements AfterContentInit, OnDestroy, INavigatorHandle {
|
|
|
391
453
|
return this.mergedOptionsFor(route).headerSearchBarOptions !== undefined;
|
|
392
454
|
}
|
|
393
455
|
|
|
394
|
-
searchBarRef(
|
|
456
|
+
searchBarRef(
|
|
457
|
+
route: IRoute<unknown>,
|
|
458
|
+
): { current: ISearchBarCommands | null } | undefined {
|
|
395
459
|
return this.mergedOptionsFor(route).headerSearchBarOptions?.ref;
|
|
396
460
|
}
|
|
397
461
|
|
|
398
|
-
searchBarProps(
|
|
462
|
+
searchBarProps(
|
|
463
|
+
route: IRoute<unknown>,
|
|
464
|
+
index: number,
|
|
465
|
+
): Record<string, unknown> {
|
|
399
466
|
return this.planFor(route, index).searchBarProps ?? {};
|
|
400
467
|
}
|
|
401
468
|
}
|
|
@@ -12,7 +12,9 @@ export type ITabScreenOptionsArgs = {
|
|
|
12
12
|
navigation: ITabNavigatorHandle;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export type ITabScreenOptionsResolver = (
|
|
15
|
+
export type ITabScreenOptionsResolver = (
|
|
16
|
+
props: ITabScreenOptionsArgs,
|
|
17
|
+
) => ITabOptions;
|
|
16
18
|
|
|
17
19
|
@Directive({
|
|
18
20
|
selector: 'ng-template[symbioteTabScreen]',
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
createNavigationEmitter,
|
|
40
40
|
diffFocusedRoute,
|
|
41
41
|
isFocusedRoute,
|
|
42
|
+
reconcileTabRoutes,
|
|
42
43
|
renderTabBar,
|
|
43
44
|
tabRouterReducer,
|
|
44
45
|
} from '../../core';
|
|
@@ -65,7 +66,12 @@ let tabInstanceCounter = 0;
|
|
|
65
66
|
@Component({
|
|
66
67
|
selector: 'Tab',
|
|
67
68
|
standalone: true,
|
|
68
|
-
imports: [
|
|
69
|
+
imports: [
|
|
70
|
+
NgComponentOutlet,
|
|
71
|
+
NavigationScopeDirective,
|
|
72
|
+
DescriptorOutlet,
|
|
73
|
+
View,
|
|
74
|
+
],
|
|
69
75
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
70
76
|
template: `
|
|
71
77
|
<View [style]="rootStyle">
|
|
@@ -100,7 +106,8 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
100
106
|
// Keyed by name -> the LIVE TabScreenDirective instance - see stack.ts's matching comment for
|
|
101
107
|
// why a snapshot copy would go stale on an in-place `[options]`/`[component]` change.
|
|
102
108
|
private readonly registry = new Map<string, TabScreenDirective>();
|
|
103
|
-
private tabScreenChildrenSubscription:
|
|
109
|
+
private tabScreenChildrenSubscription:
|
|
110
|
+
{ unsubscribe: () => void } | undefined;
|
|
104
111
|
|
|
105
112
|
private readonly stateSignal = signal<ITabRouterState | undefined>(undefined);
|
|
106
113
|
readonly state = this.stateSignal.asReadonly();
|
|
@@ -114,11 +121,11 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
114
121
|
this.dispatch({ type: 'setParams', key, params });
|
|
115
122
|
|
|
116
123
|
ngAfterContentInit(): void {
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
this.syncRegistry();
|
|
125
|
+
this.tabScreenChildrenSubscription =
|
|
126
|
+
this.tabScreenChildren.changes.subscribe(() => {
|
|
127
|
+
this.syncRegistry();
|
|
128
|
+
});
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
ngOnDestroy(): void {
|
|
@@ -141,10 +148,25 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
141
148
|
}));
|
|
142
149
|
}
|
|
143
150
|
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
// A <ng-template symbioteTabScreen> can appear or disappear after mount (a marker behind an
|
|
152
|
+
// @if, a data-driven screen list), so the route list follows the LIVE query instead of staying
|
|
153
|
+
// frozen at whatever ngAfterContentInit first saw: reconcileTabRoutes (core) keeps each
|
|
154
|
+
// surviving route's key and accumulated params and moves focus only when the focused route is
|
|
155
|
+
// the one that left. Runs from the query's own `changes` subscription - an ordinary imperative
|
|
156
|
+
// callback, deliberately not a computed, since this writes the state signal.
|
|
157
|
+
private syncRegistry(): void {
|
|
158
|
+
this.rebuildRegistry();
|
|
146
159
|
const routes = this.routesFromRegistry();
|
|
147
|
-
if (routes.length === 0)
|
|
160
|
+
if (routes.length === 0)
|
|
161
|
+
dlog('Tab: no <ng-template symbioteTabScreen> children registered');
|
|
162
|
+
const current = this.stateSignal();
|
|
163
|
+
if (current !== undefined) {
|
|
164
|
+
this.stateSignal.set(reconcileTabRoutes(current, routes));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Seeding an empty list would resolve initialRouteName against nothing and lose it once the
|
|
168
|
+
// markers do arrive, so the state stays unseeded until at least one has registered.
|
|
169
|
+
if (routes.length === 0) return;
|
|
148
170
|
this.stateSignal.set(createInitialTabState(routes, this.initialRouteName));
|
|
149
171
|
}
|
|
150
172
|
|
|
@@ -154,9 +176,15 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
154
176
|
this.stateSignal.set(tabRouterReducer(current, action));
|
|
155
177
|
}
|
|
156
178
|
|
|
157
|
-
private resolveTabOptions(
|
|
179
|
+
private resolveTabOptions(
|
|
180
|
+
entry: TabScreenDirective,
|
|
181
|
+
route: IRoute<unknown>,
|
|
182
|
+
): ITabOptions {
|
|
158
183
|
const props: ITabScreenOptionsArgs = { route, navigation: this };
|
|
159
|
-
const own =
|
|
184
|
+
const own =
|
|
185
|
+
typeof entry.options === 'function'
|
|
186
|
+
? entry.options(props)
|
|
187
|
+
: entry.options;
|
|
160
188
|
return { ...this.screenOptions, ...own };
|
|
161
189
|
}
|
|
162
190
|
|
|
@@ -193,8 +221,12 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
193
221
|
focusedRouteEmitter(): INavigationEmitter {
|
|
194
222
|
const key = this.focusedRoute()?.key;
|
|
195
223
|
return untracked(() => {
|
|
196
|
-
if (key === this.currentEmitterKey && this.currentEmitter)
|
|
197
|
-
|
|
224
|
+
if (key === this.currentEmitterKey && this.currentEmitter)
|
|
225
|
+
return this.currentEmitter;
|
|
226
|
+
const { blurKey, focusKey } = diffFocusedRoute(
|
|
227
|
+
this.currentEmitterKey,
|
|
228
|
+
key,
|
|
229
|
+
);
|
|
198
230
|
if (blurKey !== undefined && this.currentEmitter) {
|
|
199
231
|
dlog('Tab: previous route blurred');
|
|
200
232
|
this.currentEmitter.emit(NAVIGATION_EVENT_BLUR);
|
|
@@ -243,12 +275,18 @@ export class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHandle {
|
|
|
243
275
|
});
|
|
244
276
|
|
|
245
277
|
const focusedRoute = this.focusedRoute();
|
|
246
|
-
const focusedEntry = focusedRoute
|
|
278
|
+
const focusedEntry = focusedRoute
|
|
279
|
+
? this.registry.get(focusedRoute.name)
|
|
280
|
+
: undefined;
|
|
247
281
|
const focusedOptions =
|
|
248
282
|
focusedEntry && focusedRoute
|
|
249
283
|
? this.resolveTabOptions(focusedEntry, focusedRoute)
|
|
250
284
|
: this.screenOptions;
|
|
251
285
|
|
|
252
|
-
return renderTabBar({
|
|
286
|
+
return renderTabBar({
|
|
287
|
+
items,
|
|
288
|
+
style: focusedOptions?.tabBarStyle,
|
|
289
|
+
passthrough: {},
|
|
290
|
+
});
|
|
253
291
|
}
|
|
254
292
|
}
|
package/src/core/constants.ts
CHANGED
|
@@ -11,12 +11,14 @@ export const RNS_SCREEN_VIEW_NAME = 'RNSScreen';
|
|
|
11
11
|
// render-stack.ts for why a formSheet/modal screen MUST use this different Fabric name.
|
|
12
12
|
export const RNS_MODAL_SCREEN_VIEW_NAME = 'RNSModalScreen';
|
|
13
13
|
export const RNS_SCREEN_STACK_VIEW_NAME = 'RNSScreenStack';
|
|
14
|
-
export const RNS_SCREEN_STACK_HEADER_CONFIG_VIEW_NAME =
|
|
14
|
+
export const RNS_SCREEN_STACK_HEADER_CONFIG_VIEW_NAME =
|
|
15
|
+
'RNSScreenStackHeaderConfig';
|
|
15
16
|
// The header-subview leaf react-native-screens itself uses to host arbitrary framework children
|
|
16
17
|
// (left/right/back/title/center/searchBar) inside the header. Registered here for ground-truth
|
|
17
18
|
// parity, but unconsumed by any fold in v1 scope: renderHeaderConfig's Descriptor never takes
|
|
18
19
|
// framework children (see render-stack.ts), so mounting a subview child is left to the adapter.
|
|
19
|
-
export const RNS_SCREEN_STACK_HEADER_SUBVIEW_VIEW_NAME =
|
|
20
|
+
export const RNS_SCREEN_STACK_HEADER_SUBVIEW_VIEW_NAME =
|
|
21
|
+
'RNSScreenStackHeaderSubview';
|
|
20
22
|
export const RNS_SEARCH_BAR_VIEW_NAME = 'RNSSearchBar';
|
|
21
23
|
// react-native-screens' own JS layer (ScreenStackItem -> DebugContainer -> ScreenContentWrapper)
|
|
22
24
|
// ALWAYS wraps a screen's content in this native view, `collapsable: false` so Fabric can never
|
|
@@ -43,7 +45,8 @@ export const STACK_ON_FINISH_TRANSITIONING = 'onFinishTransitioning';
|
|
|
43
45
|
// plain bar-button-item press, and a press on a (possibly nested) menu action of a 'menu'-type
|
|
44
46
|
// bar-button item.
|
|
45
47
|
export const HEADER_ON_PRESS_BAR_BUTTON_ITEM = 'onPressHeaderBarButtonItem';
|
|
46
|
-
export const HEADER_ON_PRESS_BAR_BUTTON_MENU_ITEM =
|
|
48
|
+
export const HEADER_ON_PRESS_BAR_BUTTON_MENU_ITEM =
|
|
49
|
+
'onPressHeaderBarButtonMenuItem';
|
|
47
50
|
|
|
48
51
|
// RNSSearchBar event prop keys (all DirectEventHandler in the codegen spec). onClose/onOpen are
|
|
49
52
|
// Android-only per the codegen spec's own comment.
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
// PanResponder equivalent (see packages/navigation's README / the drawer feasibility note for the
|
|
8
8
|
// full gap list).
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
IPanResponderGestureState,
|
|
12
|
+
ISymbioteEvent,
|
|
13
|
+
} from '@symbiote-native/engine';
|
|
11
14
|
import { isRecord } from '../guards';
|
|
12
15
|
import type { IDrawerSlot } from '../render-drawer';
|
|
13
16
|
|
|
@@ -59,7 +62,9 @@ export function resolveDrawerType(options: IDrawerOptions): IDrawerType {
|
|
|
59
62
|
return options.drawerType ?? DRAWER_DEFAULT_TYPE;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
export function resolveDrawerPosition(
|
|
65
|
+
export function resolveDrawerPosition(
|
|
66
|
+
options: IDrawerOptions,
|
|
67
|
+
): IDrawerPosition {
|
|
63
68
|
return options.drawerPosition ?? DRAWER_DEFAULT_POSITION;
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -90,7 +95,9 @@ export function isDrawerOverlayVisible(options: IDrawerOptions): boolean {
|
|
|
90
95
|
// slide: panel AND content move together by the same delta, overlay fades in (content still
|
|
91
96
|
// covers the panel partially as they slide in tandem, same as front visually at rest).
|
|
92
97
|
// permanent: static, all zero (isDrawerAnimated() gates callers off this path already).
|
|
93
|
-
export function resolveDrawerGeometry(
|
|
98
|
+
export function resolveDrawerGeometry(
|
|
99
|
+
options: IDrawerOptions,
|
|
100
|
+
): IDrawerGeometry {
|
|
94
101
|
const width = resolveDrawerWidth(options);
|
|
95
102
|
const type = resolveDrawerType(options);
|
|
96
103
|
const sign = resolveDrawerPosition(options) === 'left' ? 1 : -1;
|
|
@@ -188,25 +195,37 @@ export function resolveDrawerSlotInterpolation(
|
|
|
188
195
|
return {
|
|
189
196
|
translateX: {
|
|
190
197
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
191
|
-
outputRange: [
|
|
198
|
+
outputRange: [
|
|
199
|
+
geometry.contentTranslateXClosed,
|
|
200
|
+
geometry.contentTranslateXOpen,
|
|
201
|
+
],
|
|
192
202
|
},
|
|
193
203
|
};
|
|
194
204
|
case 'overlay':
|
|
195
205
|
return {
|
|
196
206
|
opacity: {
|
|
197
207
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
198
|
-
outputRange: [
|
|
208
|
+
outputRange: [
|
|
209
|
+
geometry.overlayOpacityClosed,
|
|
210
|
+
geometry.overlayOpacityOpen,
|
|
211
|
+
],
|
|
199
212
|
},
|
|
200
213
|
translateX: {
|
|
201
214
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
202
|
-
outputRange: [
|
|
215
|
+
outputRange: [
|
|
216
|
+
geometry.contentTranslateXClosed,
|
|
217
|
+
geometry.contentTranslateXOpen,
|
|
218
|
+
],
|
|
203
219
|
},
|
|
204
220
|
};
|
|
205
221
|
case 'panel':
|
|
206
222
|
return {
|
|
207
223
|
translateX: {
|
|
208
224
|
inputRange: DRAWER_PROGRESS_INPUT_RANGE,
|
|
209
|
-
outputRange: [
|
|
225
|
+
outputRange: [
|
|
226
|
+
geometry.panelTranslateXClosed,
|
|
227
|
+
geometry.panelTranslateXOpen,
|
|
228
|
+
],
|
|
210
229
|
},
|
|
211
230
|
};
|
|
212
231
|
}
|
|
@@ -235,7 +254,9 @@ export function isSwipeStartInEdge(
|
|
|
235
254
|
// ScrollView's way).
|
|
236
255
|
const MOVE_CLAIM_THRESHOLD = 5;
|
|
237
256
|
|
|
238
|
-
export function isHorizontalDrag(
|
|
257
|
+
export function isHorizontalDrag(
|
|
258
|
+
gestureState: IPanResponderGestureState,
|
|
259
|
+
): boolean {
|
|
239
260
|
return (
|
|
240
261
|
Math.abs(gestureState.dx) > MOVE_CLAIM_THRESHOLD &&
|
|
241
262
|
Math.abs(gestureState.dx) > Math.abs(gestureState.dy)
|
|
@@ -258,8 +279,10 @@ export function resolveSwipeIntent(
|
|
|
258
279
|
// symmetrically for a right drawer's leftward drag).
|
|
259
280
|
const signedDx = sign * gestureState.dx;
|
|
260
281
|
const signedVx = sign * gestureState.vx;
|
|
261
|
-
const minDistance =
|
|
262
|
-
|
|
282
|
+
const minDistance =
|
|
283
|
+
options.swipeMinDistance ?? DRAWER_DEFAULT_SWIPE_MIN_DISTANCE;
|
|
284
|
+
const minVelocity =
|
|
285
|
+
options.swipeMinVelocity ?? DRAWER_DEFAULT_SWIPE_MIN_VELOCITY;
|
|
263
286
|
|
|
264
287
|
const pastDistance = Math.abs(signedDx) >= minDistance;
|
|
265
288
|
const pastVelocity = Math.abs(signedVx) >= minVelocity;
|
|
@@ -276,7 +299,9 @@ export function clamp01(value: number): number {
|
|
|
276
299
|
}
|
|
277
300
|
|
|
278
301
|
function toFiniteNumber(value: unknown): number | undefined {
|
|
279
|
-
return typeof value === 'number' && Number.isFinite(value)
|
|
302
|
+
return typeof value === 'number' && Number.isFinite(value)
|
|
303
|
+
? value
|
|
304
|
+
: undefined;
|
|
280
305
|
}
|
|
281
306
|
|
|
282
307
|
// The touch's real starting page-X, read off the raw event rather than gestureState.x0: the
|
|
@@ -293,7 +318,8 @@ export function startPageXOf(event: ISymbioteEvent): number | undefined {
|
|
|
293
318
|
const direct = toFiniteNumber(nativeEvent.pageX);
|
|
294
319
|
if (direct !== undefined) return direct;
|
|
295
320
|
const touches = nativeEvent.touches;
|
|
296
|
-
if (Array.isArray(touches) && isRecord(touches[0]))
|
|
321
|
+
if (Array.isArray(touches) && isRecord(touches[0]))
|
|
322
|
+
return toFiniteNumber(touches[0].pageX);
|
|
297
323
|
return undefined;
|
|
298
324
|
}
|
|
299
325
|
|
|
@@ -323,7 +349,8 @@ export function shouldClaimDrawerSwipe(
|
|
|
323
349
|
options: IDrawerOptions,
|
|
324
350
|
phase: 'start' | 'move',
|
|
325
351
|
): boolean {
|
|
326
|
-
if ((options.swipeEnabled ?? DRAWER_DEFAULT_SWIPE_ENABLED) === false)
|
|
352
|
+
if ((options.swipeEnabled ?? DRAWER_DEFAULT_SWIPE_ENABLED) === false)
|
|
353
|
+
return false;
|
|
327
354
|
if (!isDrawerAnimated(options)) return false;
|
|
328
355
|
const startX = startPageXOf(event) ?? gestureState.x0;
|
|
329
356
|
if (!isSwipeStartInEdge(startX, screenWidth, isOpen, options)) return false;
|
|
@@ -34,7 +34,11 @@ export function createInitialDrawerRouterState(
|
|
|
34
34
|
return { routes, index: INITIAL_FOCUSED_INDEX, isOpen: false };
|
|
35
35
|
}
|
|
36
36
|
const index = routes.findIndex(route => route.name === initialRouteName);
|
|
37
|
-
return {
|
|
37
|
+
return {
|
|
38
|
+
routes,
|
|
39
|
+
index: index === -1 ? INITIAL_FOCUSED_INDEX : index,
|
|
40
|
+
isOpen: false,
|
|
41
|
+
};
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
// Mirrors @react-navigation/drawer's DrawerActions: jumpTo focuses a route by NAME (TabRouter's
|
|
@@ -49,7 +53,9 @@ export function drawerRouterReducer(
|
|
|
49
53
|
case 'jumpTo': {
|
|
50
54
|
const index = state.routes.findIndex(route => route.name === action.name);
|
|
51
55
|
if (index === -1) return state;
|
|
52
|
-
return index === state.index && !state.isOpen
|
|
56
|
+
return index === state.index && !state.isOpen
|
|
57
|
+
? state
|
|
58
|
+
: { ...state, index, isOpen: false };
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
case 'openDrawer':
|
|
@@ -66,6 +72,8 @@ export function drawerRouterReducer(
|
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
export function focusedDrawerRoute(
|
|
75
|
+
export function focusedDrawerRoute(
|
|
76
|
+
state: IDrawerRouterState,
|
|
77
|
+
): IRouteEntry | undefined {
|
|
70
78
|
return state.routes[state.index];
|
|
71
79
|
}
|
package/src/core/guards.ts
CHANGED
|
@@ -19,5 +19,7 @@ export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
19
19
|
// navigator-state.ts (Stack) and tab-router-state.ts (Tabs) so the two reducers can't drift on
|
|
20
20
|
// this rule independently.
|
|
21
21
|
export function mergeParams(current: unknown, incoming: unknown): unknown {
|
|
22
|
-
return isRecord(current) && isRecord(incoming)
|
|
22
|
+
return isRecord(current) && isRecord(incoming)
|
|
23
|
+
? { ...current, ...incoming }
|
|
24
|
+
: incoming;
|
|
23
25
|
}
|