@symbiote-native/navigation 2.1.0 → 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 +23 -9
- 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.js +20 -6
- package/build/angular/tabs/index.js +21 -7
- 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 +4 -4
- package/build/core/index.js +2 -2
- 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/state-persistence/index.js +6 -2
- package/build/core/tab-router-state/index.js +8 -2
- package/build/react/drawer/index.js +36 -13
- package/build/react/index.d.ts +7 -7
- package/build/react/index.js +2 -2
- package/build/react/stack/index.js +34 -8
- package/build/react/tabs/index.js +14 -4
- 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/descriptor-subtree.js +3 -1
- package/build/svelte/drawer/index.svelte +163 -25
- package/build/svelte/drawer-screen.svelte +2 -1
- package/build/svelte/index.d.ts +3 -3
- package/build/svelte/navigation-scope.svelte +4 -1
- package/build/svelte/runes/use-navigation.svelte.js +5 -1
- package/build/svelte/stack/index.svelte +43 -6
- package/build/svelte/stack/stack-screen.svelte +66 -9
- package/build/svelte/tabs/index.svelte +42 -20
- package/build/vue/composables/use-navigation.js +5 -1
- package/build/vue/drawer/index.js +30 -8
- package/build/vue/index.d.ts +3 -3
- package/build/vue/navigation-context.js +1 -1
- package/build/vue/stack/index.js +17 -6
- package/build/vue/tabs/index.js +18 -5
- package/build-ngc/angular/drawer/index.js +31 -11
- package/build-ngc/angular/drawer/index.js.map +1 -1
- 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.map +1 -1
- package/build-ngc/angular/navigation-scope.directive.js +1 -1
- package/build-ngc/angular/navigation-scope.directive.js.map +1 -1
- package/build-ngc/angular/screen.directive.js.map +1 -1
- package/build-ngc/angular/search-bar-ref.directive.js +1 -1
- package/build-ngc/angular/search-bar-ref.directive.js.map +1 -1
- package/build-ngc/angular/stack/index.js +26 -8
- package/build-ngc/angular/stack/index.js.map +1 -1
- package/build-ngc/angular/tab-screen.directive.js.map +1 -1
- package/build-ngc/angular/tabs/index.js +21 -7
- 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 +4 -4
- package/build-ngc/core/index.js +2 -2
- 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.js.map +1 -1
- 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.js +8 -2
- package/build-ngc/core/tab-router-state/index.js.map +1 -1
- package/package.json +23 -9
- package/src/angular/drawer/index.ts +69 -25
- 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 +68 -22
- package/src/angular/tab-screen.directive.ts +3 -1
- package/src/angular/tabs/index.ts +36 -12
- 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 +18 -4
- 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 +5 -2
- package/src/core/state-persistence/index.ts +13 -3
- package/src/core/tab-router-state/index.ts +10 -3
- package/src/react/drawer/index.ts +408 -344
- 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 +294 -231
- package/src/react/tab-screen.ts +3 -1
- package/src/react/tabs/index.ts +188 -158
- 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 +3 -1
- package/src/svelte/descriptor-subtree.ts +3 -1
- package/src/svelte/drawer/index.svelte +163 -25
- package/src/svelte/drawer-screen-props.ts +8 -2
- package/src/svelte/drawer-screen.svelte +2 -1
- package/src/svelte/fabric-tree.test-helper.ts +37 -3
- package/src/svelte/index.ts +15 -3
- package/src/svelte/linking.svelte.ts +11 -5
- package/src/svelte/navigation-scope.svelte +4 -1
- package/src/svelte/runes/use-drawer-navigation.svelte.ts +3 -1
- package/src/svelte/runes/use-focus-effect.svelte.ts +8 -2
- package/src/svelte/runes/use-navigation-state.svelte.ts +3 -1
- package/src/svelte/runes/use-navigation.svelte.ts +13 -3
- package/src/svelte/runes/use-stack-navigation.svelte.ts +3 -1
- package/src/svelte/screen-props.ts +7 -2
- package/src/svelte/screen-registry.ts +9 -3
- package/src/svelte/stack/index.svelte +43 -6
- package/src/svelte/stack/stack-screen.svelte +66 -9
- package/src/svelte/svelte-compile.test-helper.ts +16 -12
- package/src/svelte/tab-screen-props.ts +3 -1
- package/src/svelte/tabs/index.svelte +42 -20
- 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 +122 -36
- 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 +82 -34
- package/src/vue/tab-screen.ts +3 -1
- package/src/vue/tabs/index.ts +51 -13
package/src/vue/stack/index.ts
CHANGED
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
import { defineComponent, h, shallowRef, useId } from '@vue/runtime-core';
|
|
14
14
|
import type { VNode } from '@vue/runtime-core';
|
|
15
15
|
import { descriptorToVue, normalizeVueAttrs } from '@symbiote-native/vue';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
Platform,
|
|
18
|
+
debugNodeId,
|
|
19
|
+
dlog,
|
|
20
|
+
isSymbioteNode,
|
|
21
|
+
} from '@symbiote-native/engine';
|
|
17
22
|
import {
|
|
18
23
|
NAVIGATION_EVENT_BLUR,
|
|
19
24
|
NAVIGATION_EVENT_FOCUS,
|
|
@@ -48,7 +53,11 @@ import type {
|
|
|
48
53
|
} from '../../core';
|
|
49
54
|
import { NavigationScope, injectNavigationScope } from '../navigation-context';
|
|
50
55
|
import { Screen } from '../screen';
|
|
51
|
-
import type {
|
|
56
|
+
import type {
|
|
57
|
+
IScreenOptionsArgs,
|
|
58
|
+
IScreenProps,
|
|
59
|
+
IVueScreenOptions,
|
|
60
|
+
} from '../screen';
|
|
52
61
|
|
|
53
62
|
export type { INavigatorHandle } from '../../core';
|
|
54
63
|
|
|
@@ -62,7 +71,9 @@ export type IStackProps = {
|
|
|
62
71
|
// backTitleVisible defaults to `true` on both platforms per the codegen spec's own default
|
|
63
72
|
// (CT.WithDefault<boolean, 'true'>) - no ios/android divergence in v1 scope, so a single constant
|
|
64
73
|
// stands in for the per-platform injection point ISliderPlatform-style adapters use elsewhere.
|
|
65
|
-
const NAVIGATOR_PLATFORM: INavigatorPlatform = {
|
|
74
|
+
const NAVIGATOR_PLATFORM: INavigatorPlatform = {
|
|
75
|
+
defaultHeaderBackTitleVisible: true,
|
|
76
|
+
};
|
|
66
77
|
|
|
67
78
|
type IScreenRegistryEntry = {
|
|
68
79
|
component: IScreenProps['component'];
|
|
@@ -93,7 +104,9 @@ function asScreenOptionsOrResolver(value: unknown): IScreenProps['options'] {
|
|
|
93
104
|
return asScreenOptions(value);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
function collectRegistry(
|
|
107
|
+
function collectRegistry(
|
|
108
|
+
vnodes: readonly VNode[],
|
|
109
|
+
): Map<string, IScreenRegistryEntry> {
|
|
97
110
|
const registry = new Map<string, IScreenRegistryEntry>();
|
|
98
111
|
for (const vnode of vnodes) {
|
|
99
112
|
if (vnode.type !== Screen || !isRecord(vnode.props)) continue;
|
|
@@ -115,7 +128,9 @@ function resolveScreenOptions(
|
|
|
115
128
|
screenOptions: IVueScreenOptions | undefined,
|
|
116
129
|
): IVueScreenOptions {
|
|
117
130
|
const own =
|
|
118
|
-
typeof entry.options === 'function'
|
|
131
|
+
typeof entry.options === 'function'
|
|
132
|
+
? entry.options(screenOptionsArgs)
|
|
133
|
+
: entry.options;
|
|
119
134
|
return { ...screenOptions, ...own };
|
|
120
135
|
}
|
|
121
136
|
|
|
@@ -168,7 +183,10 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
168
183
|
});
|
|
169
184
|
} else {
|
|
170
185
|
initialState = createInitialNavigatorState(
|
|
171
|
-
createRoute(
|
|
186
|
+
createRoute(
|
|
187
|
+
initialRouteName,
|
|
188
|
+
initialRegistry.get(initialRouteName)?.initialParams,
|
|
189
|
+
),
|
|
172
190
|
);
|
|
173
191
|
}
|
|
174
192
|
|
|
@@ -193,11 +211,13 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
193
211
|
}
|
|
194
212
|
|
|
195
213
|
const handle: INavigatorHandle = {
|
|
196
|
-
push: (name, params) =>
|
|
214
|
+
push: (name, params) =>
|
|
215
|
+
dispatch({ type: 'push', route: createRoute(name, params) }),
|
|
197
216
|
pop: count => dispatch({ type: 'pop', count }),
|
|
198
217
|
popToTop: () => dispatch({ type: 'popToTop' }),
|
|
199
218
|
popTo: key => dispatch({ type: 'popTo', key }),
|
|
200
|
-
replace: (name, params) =>
|
|
219
|
+
replace: (name, params) =>
|
|
220
|
+
dispatch({ type: 'replace', route: createRoute(name, params) }),
|
|
201
221
|
setParams: (params, key) => dispatch({ type: 'setParams', key, params }),
|
|
202
222
|
reset: nextState => dispatch({ type: 'reset', state: nextState }),
|
|
203
223
|
canGoBack: () => currentState().routes.length > 1,
|
|
@@ -215,7 +235,8 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
215
235
|
emitterFor(route.key).emit(NAVIGATION_EVENT_STATE, current);
|
|
216
236
|
}
|
|
217
237
|
for (const routeKey of emitters.keys()) {
|
|
218
|
-
if (!current.routes.some(route => route.key === routeKey))
|
|
238
|
+
if (!current.routes.some(route => route.key === routeKey))
|
|
239
|
+
emitters.delete(routeKey);
|
|
219
240
|
}
|
|
220
241
|
}
|
|
221
242
|
|
|
@@ -245,9 +266,19 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
245
266
|
return null;
|
|
246
267
|
}
|
|
247
268
|
|
|
248
|
-
const screenOptionsArgs: IScreenOptionsArgs = {
|
|
249
|
-
|
|
250
|
-
|
|
269
|
+
const screenOptionsArgs: IScreenOptionsArgs = {
|
|
270
|
+
route,
|
|
271
|
+
navigation: handle,
|
|
272
|
+
};
|
|
273
|
+
const mergedOptions = resolveScreenOptions(
|
|
274
|
+
entry,
|
|
275
|
+
screenOptionsArgs,
|
|
276
|
+
screenOptions,
|
|
277
|
+
);
|
|
278
|
+
const activityState = computeActivityState(
|
|
279
|
+
index,
|
|
280
|
+
current.routes.length,
|
|
281
|
+
);
|
|
251
282
|
// Investigation instrumentation (flicker-on-focus bug): fires on EVERY Stack render, not
|
|
252
283
|
// just on transitions, so the log stream shows whether a route's activityState/index ever
|
|
253
284
|
// changes outside of a push/pop dispatch. Kept behind DEBUG, never removed.
|
|
@@ -268,21 +299,30 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
268
299
|
isAndroid: Platform.OS === 'android',
|
|
269
300
|
screenPassthrough: {
|
|
270
301
|
[SCREEN_ON_DISMISSED]: () => dispatch({ type: 'pop', count: 1 }),
|
|
271
|
-
[SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
|
|
302
|
+
[SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
|
|
303
|
+
dispatch({ type: 'pop', count: 1 }),
|
|
272
304
|
// onAppear/onDisappear are the definitive visibility boundary (post-transition-
|
|
273
305
|
// animation), so 'focus'/'blur' fire exactly once per transition; onWillAppear/
|
|
274
306
|
// onWillDisappear fire BEFORE the animation runs, so wiring them to emit() too would
|
|
275
307
|
// double-invoke useFocusEffect per transition - they only get a debug log here.
|
|
276
308
|
[SCREEN_ON_WILL_APPEAR]: () =>
|
|
277
|
-
dlog(
|
|
309
|
+
dlog(
|
|
310
|
+
`Stack: route "${route.name}" will appear at t=${Date.now()}`,
|
|
311
|
+
),
|
|
278
312
|
[SCREEN_ON_APPEAR]: () => {
|
|
279
|
-
dlog(
|
|
313
|
+
dlog(
|
|
314
|
+
`Stack: route "${route.name}" appeared (focus) at t=${Date.now()}`,
|
|
315
|
+
);
|
|
280
316
|
routeEmitter.emit(NAVIGATION_EVENT_FOCUS);
|
|
281
317
|
},
|
|
282
318
|
[SCREEN_ON_WILL_DISAPPEAR]: () =>
|
|
283
|
-
dlog(
|
|
319
|
+
dlog(
|
|
320
|
+
`Stack: route "${route.name}" will disappear at t=${Date.now()}`,
|
|
321
|
+
),
|
|
284
322
|
[SCREEN_ON_DISAPPEAR]: () => {
|
|
285
|
-
dlog(
|
|
323
|
+
dlog(
|
|
324
|
+
`Stack: route "${route.name}" disappeared (blur) at t=${Date.now()}`,
|
|
325
|
+
);
|
|
286
326
|
routeEmitter.emit(NAVIGATION_EVENT_BLUR);
|
|
287
327
|
},
|
|
288
328
|
},
|
|
@@ -309,7 +349,8 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
309
349
|
);
|
|
310
350
|
const appRef = searchBarOptions.ref;
|
|
311
351
|
if (appRef === undefined) return;
|
|
312
|
-
appRef.value =
|
|
352
|
+
appRef.value =
|
|
353
|
+
node === null ? null : buildSearchBarHandle(() => node);
|
|
313
354
|
},
|
|
314
355
|
}
|
|
315
356
|
: undefined,
|
|
@@ -334,22 +375,26 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
334
375
|
// sizing (see RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME's comment in core/constants.ts). A
|
|
335
376
|
// `push` screen doesn't need it, but a `formSheet` one is otherwise left with no content
|
|
336
377
|
// ever attached natively.
|
|
337
|
-
const content = h(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
378
|
+
const content = h(
|
|
379
|
+
RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME,
|
|
380
|
+
plan.contentWrapperProps,
|
|
381
|
+
[
|
|
382
|
+
h(
|
|
383
|
+
NavigationScope,
|
|
384
|
+
{
|
|
385
|
+
value: {
|
|
386
|
+
route,
|
|
387
|
+
navigation: handle,
|
|
388
|
+
emitter: routeEmitter,
|
|
389
|
+
parent: ambientScopeRef?.value,
|
|
390
|
+
},
|
|
346
391
|
},
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
392
|
+
// No route/navigation props: the screen reads both through composables off the
|
|
393
|
+
// NavigationScope provided just above (useRoute / useStackNavigation).
|
|
394
|
+
() => h(entry.component),
|
|
395
|
+
),
|
|
396
|
+
],
|
|
397
|
+
);
|
|
353
398
|
|
|
354
399
|
// react-native-screens' own Screen.tsx swaps in a DIFFERENT Fabric component
|
|
355
400
|
// ('RNSModalScreen') for a modally-presented screen - its native updateLayoutMetrics:
|
|
@@ -373,7 +418,10 @@ const StackImpl = defineComponent<IStackProps>(
|
|
|
373
418
|
// RNSScreen.mm treats an unset/inactive nested screen as not yet pushed,
|
|
374
419
|
// leaving it parked at its pre-push transition position (off past the bottom
|
|
375
420
|
// edge) instead of its real, presented frame.
|
|
376
|
-
{
|
|
421
|
+
{
|
|
422
|
+
style: plan.innerScreenStyle,
|
|
423
|
+
activityState: plan.activityState,
|
|
424
|
+
},
|
|
377
425
|
[descriptorToVue(plan.headerConfig), content],
|
|
378
426
|
),
|
|
379
427
|
]),
|
package/src/vue/tab-screen.ts
CHANGED
|
@@ -14,7 +14,9 @@ export type ITabScreenOptionsArgs = {
|
|
|
14
14
|
navigation: ITabNavigatorHandle;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export type ITabScreenOptionsResolver = (
|
|
17
|
+
export type ITabScreenOptionsResolver = (
|
|
18
|
+
props: ITabScreenOptionsArgs,
|
|
19
|
+
) => ITabOptions;
|
|
18
20
|
|
|
19
21
|
export type ITabScreenProps = {
|
|
20
22
|
name: string;
|
package/src/vue/tabs/index.ts
CHANGED
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
// `symbiote-view`/`symbiote-text` primitives via the shared render fn, so there is no
|
|
8
8
|
// react-native-screens ViewConfig to register here - Tab needs no `../register` import.
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
defineComponent,
|
|
12
|
+
h,
|
|
13
|
+
nextTick,
|
|
14
|
+
onUnmounted,
|
|
15
|
+
shallowRef,
|
|
16
|
+
useId,
|
|
17
|
+
} from '@vue/runtime-core';
|
|
11
18
|
import type { VNode } from '@vue/runtime-core';
|
|
12
19
|
import { descriptorToVue, normalizeVueAttrs } from '@symbiote-native/vue';
|
|
13
20
|
import { dlog } from '@symbiote-native/engine';
|
|
@@ -72,7 +79,9 @@ function asTabOptionsOrResolver(value: unknown): ITabScreenProps['options'] {
|
|
|
72
79
|
return asTabOptions(value);
|
|
73
80
|
}
|
|
74
81
|
|
|
75
|
-
function collectRegistry(
|
|
82
|
+
function collectRegistry(
|
|
83
|
+
vnodes: readonly VNode[],
|
|
84
|
+
): Map<string, ITabRegistryEntry> {
|
|
76
85
|
const registry = new Map<string, ITabRegistryEntry>();
|
|
77
86
|
for (const vnode of vnodes) {
|
|
78
87
|
if (vnode.type !== TabScreen || !isRecord(vnode.props)) continue;
|
|
@@ -94,7 +103,9 @@ function resolveTabOptions(
|
|
|
94
103
|
screenOptions: ITabOptions | undefined,
|
|
95
104
|
): ITabOptions {
|
|
96
105
|
const own =
|
|
97
|
-
typeof entry.options === 'function'
|
|
106
|
+
typeof entry.options === 'function'
|
|
107
|
+
? entry.options(screenComponentProps)
|
|
108
|
+
: entry.options;
|
|
98
109
|
return { ...screenOptions, ...own };
|
|
99
110
|
}
|
|
100
111
|
|
|
@@ -112,7 +123,9 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
112
123
|
const ambientScopeRef = injectNavigationScope();
|
|
113
124
|
const routeIdPrefix = useId();
|
|
114
125
|
|
|
115
|
-
function buildRoutes(
|
|
126
|
+
function buildRoutes(
|
|
127
|
+
registry: Map<string, ITabRegistryEntry>,
|
|
128
|
+
): IRoute<unknown>[] {
|
|
116
129
|
return Array.from(registry.entries()).map(([name, entry]) => ({
|
|
117
130
|
key: `${routeIdPrefix}-${name}`,
|
|
118
131
|
name,
|
|
@@ -122,7 +135,8 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
122
135
|
|
|
123
136
|
const initialRegistry = collectRegistry(slots.default?.() ?? []);
|
|
124
137
|
const initialRoutes = buildRoutes(initialRegistry);
|
|
125
|
-
if (initialRoutes.length === 0)
|
|
138
|
+
if (initialRoutes.length === 0)
|
|
139
|
+
dlog('Tab: no <Tab.Screen> children registered');
|
|
126
140
|
|
|
127
141
|
// A <Tab.Screen> can appear or disappear after mount (a marker behind a v-if, a data-driven
|
|
128
142
|
// screen list), so the route list is re-collected from the slot on every render and the
|
|
@@ -147,7 +161,10 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
function dispatch(action: ITabRouterAction): void {
|
|
150
|
-
dispatchedState.value = tabRouterReducer(
|
|
164
|
+
dispatchedState.value = tabRouterReducer(
|
|
165
|
+
resolveState(latestRoutes),
|
|
166
|
+
action,
|
|
167
|
+
);
|
|
151
168
|
}
|
|
152
169
|
|
|
153
170
|
const jumpTo = (name: string, params?: unknown): void =>
|
|
@@ -215,7 +232,8 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
215
232
|
}
|
|
216
233
|
|
|
217
234
|
onUnmounted(() => {
|
|
218
|
-
if (focusedRouteKey !== undefined)
|
|
235
|
+
if (focusedRouteKey !== undefined)
|
|
236
|
+
emitterFor(focusedRouteKey).emit(NAVIGATION_EVENT_BLUR);
|
|
219
237
|
});
|
|
220
238
|
|
|
221
239
|
return () => {
|
|
@@ -229,17 +247,27 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
229
247
|
const state = resolveState(routes);
|
|
230
248
|
syncFocus(state);
|
|
231
249
|
|
|
232
|
-
const focusedRoute: IRoute<unknown> | undefined =
|
|
250
|
+
const focusedRoute: IRoute<unknown> | undefined =
|
|
251
|
+
state.routes[state.index];
|
|
233
252
|
|
|
234
253
|
const items: ITabBarItemView[] = state.routes.map((route, index) => {
|
|
235
254
|
const entry = registry.get(route.name);
|
|
236
255
|
const focused = isFocusedRoute(index, state.index);
|
|
237
256
|
if (entry === undefined) {
|
|
238
257
|
dlog(`Tab: no screen registered for route name "${route.name}"`);
|
|
239
|
-
return {
|
|
258
|
+
return {
|
|
259
|
+
key: route.key,
|
|
260
|
+
focused,
|
|
261
|
+
label: route.name,
|
|
262
|
+
passthrough: {},
|
|
263
|
+
};
|
|
240
264
|
}
|
|
241
265
|
|
|
242
|
-
const options = resolveTabOptions(
|
|
266
|
+
const options = resolveTabOptions(
|
|
267
|
+
entry,
|
|
268
|
+
{ route, navigation: handle },
|
|
269
|
+
screenOptions,
|
|
270
|
+
);
|
|
243
271
|
|
|
244
272
|
return {
|
|
245
273
|
key: route.key,
|
|
@@ -257,7 +285,9 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
257
285
|
};
|
|
258
286
|
});
|
|
259
287
|
|
|
260
|
-
const focusedEntry = focusedRoute
|
|
288
|
+
const focusedEntry = focusedRoute
|
|
289
|
+
? registry.get(focusedRoute.name)
|
|
290
|
+
: undefined;
|
|
261
291
|
const focusedOptions: ITabOptions | undefined =
|
|
262
292
|
focusedEntry && focusedRoute
|
|
263
293
|
? resolveTabOptions(
|
|
@@ -268,7 +298,11 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
268
298
|
: screenOptions;
|
|
269
299
|
|
|
270
300
|
const tabBar = descriptorToVue(
|
|
271
|
-
renderTabBar({
|
|
301
|
+
renderTabBar({
|
|
302
|
+
items,
|
|
303
|
+
style: focusedOptions?.tabBarStyle,
|
|
304
|
+
passthrough: {},
|
|
305
|
+
}),
|
|
272
306
|
);
|
|
273
307
|
|
|
274
308
|
// Only the focused route's screen is ever mounted (unlike Stack, which keeps every pushed
|
|
@@ -294,7 +328,11 @@ const TabImpl = defineComponent<ITabProps>(
|
|
|
294
328
|
: null;
|
|
295
329
|
|
|
296
330
|
return h('symbiote-view', { style: TAB_ROOT_STYLE }, [
|
|
297
|
-
h(
|
|
331
|
+
h(
|
|
332
|
+
'symbiote-view',
|
|
333
|
+
{ style: TAB_CONTENT_STYLE },
|
|
334
|
+
content === null ? [] : [content],
|
|
335
|
+
),
|
|
298
336
|
tabBar,
|
|
299
337
|
]);
|
|
300
338
|
};
|