@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
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
// time (both the structured `icon` field AND the flat native keys reach native - RNS's own
|
|
22
22
|
// prepareHeaderBarButtonItems keeps both), and resolves image assets through the same resolver
|
|
23
23
|
// the Image component uses.
|
|
24
|
-
function prepareIcon(
|
|
24
|
+
function prepareIcon(
|
|
25
|
+
icon: IHeaderBarButtonIcon | undefined,
|
|
26
|
+
): Record<string, unknown> {
|
|
25
27
|
if (!icon) return {};
|
|
26
28
|
switch (icon.type) {
|
|
27
29
|
case 'sfSymbol':
|
|
@@ -31,7 +33,9 @@ function prepareIcon(icon: IHeaderBarButtonIcon | undefined): Record<string, unk
|
|
|
31
33
|
case 'imageSource':
|
|
32
34
|
return { imageSource: imageStatics.resolveAssetSource(icon.imageSource) };
|
|
33
35
|
case 'templateSource':
|
|
34
|
-
return {
|
|
36
|
+
return {
|
|
37
|
+
templateSource: imageStatics.resolveAssetSource(icon.templateSource),
|
|
38
|
+
};
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
|
|
@@ -40,7 +44,11 @@ type ISharedItem = IHeaderBarButtonItemAction | IHeaderBarButtonItemMenu;
|
|
|
40
44
|
// The one id algorithm both the payload tagger (prepareMenuItems/prepareHeaderBarButtonItems)
|
|
41
45
|
// and the dispatch-lookup builder (collectMenuHandlers/collectBarButtonHandlers) call - so a
|
|
42
46
|
// change to the id scheme genuinely can't desync payload tagging from dispatch lookup.
|
|
43
|
-
function buildMenuId(
|
|
47
|
+
function buildMenuId(
|
|
48
|
+
path: string,
|
|
49
|
+
index: number,
|
|
50
|
+
side: 'left' | 'right',
|
|
51
|
+
): string {
|
|
44
52
|
return `${path}-${index}-${side}`;
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -54,18 +62,26 @@ function prepareTitleStyle(
|
|
|
54
62
|
if (!titleStyle) return undefined;
|
|
55
63
|
return {
|
|
56
64
|
...titleStyle,
|
|
57
|
-
color:
|
|
65
|
+
color:
|
|
66
|
+
titleStyle.color === undefined
|
|
67
|
+
? undefined
|
|
68
|
+
: processColor(titleStyle.color),
|
|
58
69
|
};
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
function prepareBadge(
|
|
72
|
+
function prepareBadge(
|
|
73
|
+
badge: ISharedItem['badge'],
|
|
74
|
+
): Record<string, unknown> | undefined {
|
|
62
75
|
if (!badge) return undefined;
|
|
63
76
|
return {
|
|
64
77
|
...badge,
|
|
65
78
|
style: badge.style
|
|
66
79
|
? {
|
|
67
80
|
...badge.style,
|
|
68
|
-
color:
|
|
81
|
+
color:
|
|
82
|
+
badge.style.color === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: processColor(badge.style.color),
|
|
69
85
|
backgroundColor:
|
|
70
86
|
badge.style.backgroundColor === undefined
|
|
71
87
|
? undefined
|
|
@@ -81,7 +97,9 @@ function prepareBadge(badge: ISharedItem['badge']): Record<string, unknown> | un
|
|
|
81
97
|
// headerRightBarButtonItems array it's nested in - not just the one bad field - so bar buttons and
|
|
82
98
|
// menu actions never reached native at all, despite the buttonId/menuId dispatch wiring itself
|
|
83
99
|
// being entirely correct.
|
|
84
|
-
function excludeOnPress<T extends { onPress: unknown }>(
|
|
100
|
+
function excludeOnPress<T extends { onPress: unknown }>(
|
|
101
|
+
item: T,
|
|
102
|
+
): Omit<T, 'onPress'> {
|
|
85
103
|
const { onPress: _onPress, ...rest } = item;
|
|
86
104
|
return rest;
|
|
87
105
|
}
|
|
@@ -95,12 +113,15 @@ function prepareSharedFields(
|
|
|
95
113
|
...(item.type === 'button' ? excludeOnPress(item) : item),
|
|
96
114
|
...prepareIcon(item.icon),
|
|
97
115
|
titleStyle: prepareTitleStyle(item.titleStyle),
|
|
98
|
-
tintColor:
|
|
116
|
+
tintColor:
|
|
117
|
+
item.tintColor === undefined ? undefined : processColor(item.tintColor),
|
|
99
118
|
badge: prepareBadge(item.badge),
|
|
100
119
|
};
|
|
101
120
|
}
|
|
102
121
|
|
|
103
|
-
type IMenuLike = {
|
|
122
|
+
type IMenuLike = {
|
|
123
|
+
items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[];
|
|
124
|
+
};
|
|
104
125
|
|
|
105
126
|
// Recursively tags every menu action with a `menuId` derived from its tree position
|
|
106
127
|
// (`${path}-${index}-${side}`), mirroring RNS's own prepareMenu exactly - the id must match what
|
|
@@ -117,7 +138,11 @@ function prepareMenuItems<T extends IMenuLike>(
|
|
|
117
138
|
const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
|
|
118
139
|
const icon = prepareIcon(menuItem.icon);
|
|
119
140
|
if (menuItem.type === 'submenu') {
|
|
120
|
-
return {
|
|
141
|
+
return {
|
|
142
|
+
...menuItem,
|
|
143
|
+
...icon,
|
|
144
|
+
...prepareMenuItems(menuItem, index, side, currentPath),
|
|
145
|
+
};
|
|
121
146
|
}
|
|
122
147
|
return {
|
|
123
148
|
...excludeOnPress(menuItem),
|
|
@@ -139,7 +164,8 @@ export function prepareHeaderBarButtonItems(
|
|
|
139
164
|
return items.map((item, index) => {
|
|
140
165
|
if (item.type === 'spacing') return item;
|
|
141
166
|
const prepared = prepareSharedFields(item);
|
|
142
|
-
if (item.type === 'button')
|
|
167
|
+
if (item.type === 'button')
|
|
168
|
+
return { ...prepared, buttonId: buildButtonId(index, side) };
|
|
143
169
|
return { ...prepared, menu: prepareMenuItems(item.menu, index, side) };
|
|
144
170
|
});
|
|
145
171
|
}
|
|
@@ -176,7 +202,10 @@ function collectBarButtonHandlers(
|
|
|
176
202
|
});
|
|
177
203
|
}
|
|
178
204
|
|
|
179
|
-
function readStringField(
|
|
205
|
+
function readStringField(
|
|
206
|
+
record: Record<string, unknown>,
|
|
207
|
+
key: string,
|
|
208
|
+
): string | undefined {
|
|
180
209
|
const value = record[key];
|
|
181
210
|
return typeof value === 'string' ? value : undefined;
|
|
182
211
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -14,7 +14,16 @@ export {
|
|
|
14
14
|
computeActivityState,
|
|
15
15
|
isTopRoute,
|
|
16
16
|
} from './navigator-state';
|
|
17
|
-
export type {
|
|
17
|
+
export type {
|
|
18
|
+
IRoute,
|
|
19
|
+
INavigatorState,
|
|
20
|
+
INavigatorAction,
|
|
21
|
+
} from './navigator-state';
|
|
22
|
+
|
|
23
|
+
// Drops history entries whose `<Stack.Screen>` marker has unregistered - see
|
|
24
|
+
// stack-router-state.ts's header for why the Stack's history needs this and the Tab's projection
|
|
25
|
+
// does not.
|
|
26
|
+
export { reconcileStackRoutes } from './stack-router-state';
|
|
18
27
|
|
|
19
28
|
export type {
|
|
20
29
|
IStackAnimation,
|
|
@@ -45,7 +54,11 @@ export type {
|
|
|
45
54
|
ISearchBarViewProps,
|
|
46
55
|
} from './navigator-props';
|
|
47
56
|
|
|
48
|
-
export {
|
|
57
|
+
export {
|
|
58
|
+
resolveHeaderConfigView,
|
|
59
|
+
resolveScreenView,
|
|
60
|
+
resolveSearchBarView,
|
|
61
|
+
} from './screen-options';
|
|
49
62
|
|
|
50
63
|
export { buildSearchBarHandle } from './search-bar-commands';
|
|
51
64
|
export type { ISearchBarCommands } from './search-bar-commands';
|
|
@@ -65,7 +78,10 @@ export {
|
|
|
65
78
|
} from './render-stack';
|
|
66
79
|
export type { IScreenRenderPlanInput, IScreenRenderPlan } from './render-stack';
|
|
67
80
|
|
|
68
|
-
export {
|
|
81
|
+
export {
|
|
82
|
+
serializeNavigatorState,
|
|
83
|
+
deserializeNavigatorState,
|
|
84
|
+
} from './state-persistence';
|
|
69
85
|
|
|
70
86
|
export {
|
|
71
87
|
createNavigationEmitter,
|
|
@@ -89,7 +105,12 @@ export { isRecord } from './guards';
|
|
|
89
105
|
|
|
90
106
|
// Bottom-tabs navigator: a FOCUSED-INDEX router (not a stack - see tab-router-state.ts) driving
|
|
91
107
|
// a pure-JS tab bar render, framework-agnostic and shared verbatim by every adapter.
|
|
92
|
-
export {
|
|
108
|
+
export {
|
|
109
|
+
createInitialTabState,
|
|
110
|
+
tabRouterReducer,
|
|
111
|
+
reconcileTabRoutes,
|
|
112
|
+
isFocusedRoute,
|
|
113
|
+
} from './tab-router-state';
|
|
93
114
|
export type { ITabRouterState, ITabRouterAction } from './tab-router-state';
|
|
94
115
|
|
|
95
116
|
export type { ITabBarIcon, ITabOptions } from './tab-options';
|
|
@@ -110,7 +131,10 @@ export {
|
|
|
110
131
|
drawerRouterReducer,
|
|
111
132
|
focusedDrawerRoute,
|
|
112
133
|
} from './drawer-router-state';
|
|
113
|
-
export type {
|
|
134
|
+
export type {
|
|
135
|
+
IDrawerRouterState,
|
|
136
|
+
IDrawerRouterAction,
|
|
137
|
+
} from './drawer-router-state';
|
|
114
138
|
|
|
115
139
|
export type {
|
|
116
140
|
IDrawerType,
|
|
@@ -49,7 +49,9 @@ function normalizeSegment(segment: string): string {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function joinPath(parent: string, child: string): string {
|
|
52
|
-
const parts = [normalizeSegment(parent), normalizeSegment(child)].filter(
|
|
52
|
+
const parts = [normalizeSegment(parent), normalizeSegment(child)].filter(
|
|
53
|
+
part => part.length > 0,
|
|
54
|
+
);
|
|
53
55
|
return parts.join('/');
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -68,14 +70,17 @@ function flattenScreens(
|
|
|
68
70
|
continue;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
const nextParent =
|
|
73
|
+
const nextParent =
|
|
74
|
+
entry.path !== undefined ? joinPath(parentPath, entry.path) : parentPath;
|
|
72
75
|
|
|
73
76
|
if (entry.screens !== undefined) {
|
|
74
77
|
flattenScreens(entry.screens, nextParent, out);
|
|
75
78
|
} else if (entry.path !== undefined) {
|
|
76
79
|
out.push({ name, pattern: nextParent });
|
|
77
80
|
} else {
|
|
78
|
-
dlog(
|
|
81
|
+
dlog(
|
|
82
|
+
`linking-config: screen "${name}" has neither a path nor nested screens, skipping`,
|
|
83
|
+
);
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
return out;
|
|
@@ -93,12 +98,16 @@ function segmentCount(pattern: string): number {
|
|
|
93
98
|
// More static segments should win over a param that would also match (e.g. a literal
|
|
94
99
|
// '/user/me' pattern over '/user/:id'), mirroring how react-navigation prefers exact matches.
|
|
95
100
|
function bySpecificity(a: IFlatRoutePattern, b: IFlatRoutePattern): number {
|
|
96
|
-
const dynamicDiff =
|
|
101
|
+
const dynamicDiff =
|
|
102
|
+
dynamicSegmentCount(a.pattern) - dynamicSegmentCount(b.pattern);
|
|
97
103
|
if (dynamicDiff !== 0) return dynamicDiff;
|
|
98
104
|
return segmentCount(b.pattern) - segmentCount(a.pattern);
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
function matchPattern(
|
|
107
|
+
function matchPattern(
|
|
108
|
+
pattern: string,
|
|
109
|
+
pathname: string,
|
|
110
|
+
): Record<string, string> | null {
|
|
102
111
|
const patternSegments = pattern.length === 0 ? [] : pattern.split('/');
|
|
103
112
|
const pathSegments = pathname.length === 0 ? [] : pathname.split('/');
|
|
104
113
|
if (patternSegments.length !== pathSegments.length) return null;
|
|
@@ -127,7 +136,9 @@ function stripQueryAndHash(url: string): string {
|
|
|
127
136
|
// neither applies - an unrecognized scheme/host, not "no route matched".
|
|
128
137
|
function extractPathname(config: ILinkingConfig, url: string): string | null {
|
|
129
138
|
const withoutQuery = stripQueryAndHash(url);
|
|
130
|
-
const sortedPrefixes = [...config.prefixes].sort(
|
|
139
|
+
const sortedPrefixes = [...config.prefixes].sort(
|
|
140
|
+
(a, b) => b.length - a.length,
|
|
141
|
+
);
|
|
131
142
|
for (const prefix of sortedPrefixes) {
|
|
132
143
|
if (withoutQuery.startsWith(prefix)) {
|
|
133
144
|
return normalizeSegment(withoutQuery.slice(prefix.length));
|
|
@@ -137,14 +148,19 @@ function extractPathname(config: ILinkingConfig, url: string): string | null {
|
|
|
137
148
|
return null;
|
|
138
149
|
}
|
|
139
150
|
|
|
140
|
-
export function resolveRouteFromUrl(
|
|
151
|
+
export function resolveRouteFromUrl(
|
|
152
|
+
config: ILinkingConfig,
|
|
153
|
+
url: string,
|
|
154
|
+
): IRoute<unknown> | null {
|
|
141
155
|
const pathname = extractPathname(config, url);
|
|
142
156
|
if (pathname === null) {
|
|
143
157
|
dlog(`linking-config: url "${url}" matched no configured prefix`);
|
|
144
158
|
return null;
|
|
145
159
|
}
|
|
146
160
|
|
|
147
|
-
const candidates = flattenScreens(config.config.screens, '', []).sort(
|
|
161
|
+
const candidates = flattenScreens(config.config.screens, '', []).sort(
|
|
162
|
+
bySpecificity,
|
|
163
|
+
);
|
|
148
164
|
for (const candidate of candidates) {
|
|
149
165
|
const params = matchPattern(candidate.pattern, pathname);
|
|
150
166
|
if (params !== null) {
|
|
@@ -159,7 +175,9 @@ export function resolveRouteFromUrl(config: ILinkingConfig, url: string): IRoute
|
|
|
159
175
|
}
|
|
160
176
|
}
|
|
161
177
|
|
|
162
|
-
dlog(
|
|
178
|
+
dlog(
|
|
179
|
+
`linking-config: url "${url}" (path "${pathname}") matched no configured screen`,
|
|
180
|
+
);
|
|
163
181
|
return null;
|
|
164
182
|
}
|
|
165
183
|
|
|
@@ -182,7 +200,10 @@ function fillPattern(pattern: string, params: unknown): string | null {
|
|
|
182
200
|
return segments.join('/');
|
|
183
201
|
}
|
|
184
202
|
|
|
185
|
-
export function resolveUrlFromRoute(
|
|
203
|
+
export function resolveUrlFromRoute(
|
|
204
|
+
config: ILinkingConfig,
|
|
205
|
+
route: IRoute<unknown>,
|
|
206
|
+
): string | null {
|
|
186
207
|
const candidate = flattenScreens(config.config.screens, '', []).find(
|
|
187
208
|
entry => entry.name === route.name,
|
|
188
209
|
);
|
|
@@ -32,11 +32,17 @@ export type INavigationEventListener<TData = unknown> = (data: TData) => void;
|
|
|
32
32
|
|
|
33
33
|
export type INavigationEmitter = {
|
|
34
34
|
emit: (event: INavigationEventName, data?: unknown) => void;
|
|
35
|
-
addListener: (
|
|
35
|
+
addListener: (
|
|
36
|
+
event: INavigationEventName,
|
|
37
|
+
listener: INavigationEventListener,
|
|
38
|
+
) => () => void;
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
export function createNavigationEmitter(): INavigationEmitter {
|
|
39
|
-
const listenersByEvent = new Map<
|
|
42
|
+
const listenersByEvent = new Map<
|
|
43
|
+
INavigationEventName,
|
|
44
|
+
Set<INavigationEventListener>
|
|
45
|
+
>();
|
|
40
46
|
|
|
41
47
|
function addListener(
|
|
42
48
|
event: INavigationEventName,
|
|
@@ -44,9 +44,12 @@ export type IDrawerDescriptorMap = Record<
|
|
|
44
44
|
// return this union since they don't know which navigator mounted the calling component; the
|
|
45
45
|
// three guards below narrow it (used once, inside useStackNavigation/useTabNavigation/
|
|
46
46
|
// useDrawerNavigation and their Vue/Angular equivalents) so app code never writes the guard itself.
|
|
47
|
-
export type IAnyNavigatorHandle =
|
|
47
|
+
export type IAnyNavigatorHandle =
|
|
48
|
+
INavigatorHandle | ITabNavigatorHandle | IDrawerNavigatorHandle;
|
|
48
49
|
|
|
49
|
-
export function isStackNavigatorHandle(
|
|
50
|
+
export function isStackNavigatorHandle(
|
|
51
|
+
handle: IAnyNavigatorHandle,
|
|
52
|
+
): handle is INavigatorHandle {
|
|
50
53
|
return 'push' in handle;
|
|
51
54
|
}
|
|
52
55
|
|
|
@@ -58,6 +61,8 @@ export function isDrawerNavigatorHandle(
|
|
|
58
61
|
|
|
59
62
|
// jumpTo exists on both Tab and Drawer handles, so a Tab handle is a jumpTo-having handle that
|
|
60
63
|
// isn't a Drawer handle (Drawer's own openDrawer/closeDrawer/toggleDrawer rule it out).
|
|
61
|
-
export function isTabNavigatorHandle(
|
|
64
|
+
export function isTabNavigatorHandle(
|
|
65
|
+
handle: IAnyNavigatorHandle,
|
|
66
|
+
): handle is ITabNavigatorHandle {
|
|
62
67
|
return 'jumpTo' in handle && !isDrawerNavigatorHandle(handle);
|
|
63
68
|
}
|
|
@@ -51,8 +51,10 @@ export type IOptionalBooleanNativeProp = 'undefined' | 'false' | 'true';
|
|
|
51
51
|
// mirrors react-native-screens' own ScreenProps['sheetAllowedDetents'] - a plain fraction array,
|
|
52
52
|
// sorted ascending, or one of RNS's named presets; the fold to the native `sheetAllowedDetents:
|
|
53
53
|
// number[]` array happens in screen-options.ts, replicating RNS's own resolveSheetAllowedDetents.
|
|
54
|
-
export type ISheetAllowedDetents =
|
|
55
|
-
|
|
54
|
+
export type ISheetAllowedDetents =
|
|
55
|
+
number[] | 'fitToContents' | 'large' | 'medium' | 'all';
|
|
56
|
+
export type ISheetLargestUndimmedDetent =
|
|
57
|
+
number | 'last' | 'none' | 'all' | 'large' | 'medium';
|
|
56
58
|
export type ISheetInitialDetent = number | 'last';
|
|
57
59
|
|
|
58
60
|
// A bar-button item's icon: SF Symbol / iOS asset-catalog name, or an image asset. Mirrors RNS's
|
|
@@ -143,13 +145,20 @@ export type IHeaderBarButtonItemMenu = ISharedHeaderBarButtonItem & {
|
|
|
143
145
|
export type IHeaderBarButtonItemSpacing = { type: 'spacing'; spacing: number };
|
|
144
146
|
|
|
145
147
|
export type IHeaderBarButtonItem =
|
|
146
|
-
|
|
148
|
+
| IHeaderBarButtonItemAction
|
|
149
|
+
| IHeaderBarButtonItemMenu
|
|
150
|
+
| IHeaderBarButtonItemSpacing;
|
|
147
151
|
|
|
148
152
|
export type ISearchBarAutoCapitalize =
|
|
149
153
|
'systemDefault' | 'none' | 'words' | 'sentences' | 'characters';
|
|
150
154
|
|
|
151
155
|
export type ISearchBarPlacement =
|
|
152
|
-
|
|
156
|
+
| 'automatic'
|
|
157
|
+
| 'inline'
|
|
158
|
+
| 'stacked'
|
|
159
|
+
| 'integrated'
|
|
160
|
+
| 'integratedButton'
|
|
161
|
+
| 'integratedCentered';
|
|
153
162
|
|
|
154
163
|
// RNSSearchBar's full static config surface plus every event callback react-native-screens'
|
|
155
164
|
// own SearchBarProps exposes (types.tsx): onChangeText/onSearchButtonPress carry the current
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
// (`key`) is generated by the CALLER (the adapter, via React's useId or an equivalent) - the
|
|
5
5
|
// reducer never invents identity itself, so it stays a pure (state, action) => state function.
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
SCREEN_ACTIVITY_STATE_FOCUSED,
|
|
9
|
+
SCREEN_ACTIVITY_STATE_INACTIVE,
|
|
10
|
+
} from '../constants';
|
|
8
11
|
import { mergeParams } from '../guards';
|
|
9
12
|
|
|
10
13
|
export type IRoute<TParams = undefined> = Readonly<{
|
|
@@ -28,7 +31,9 @@ export type INavigatorAction =
|
|
|
28
31
|
| { type: 'setParams'; key?: string; params: unknown }
|
|
29
32
|
| { type: 'reset'; state: INavigatorState };
|
|
30
33
|
|
|
31
|
-
export function createInitialNavigatorState(
|
|
34
|
+
export function createInitialNavigatorState(
|
|
35
|
+
initialRoute: IRouteEntry,
|
|
36
|
+
): INavigatorState {
|
|
32
37
|
return { routes: [initialRoute] };
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -50,7 +55,9 @@ export function navigatorReducer(
|
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
case 'popToTop':
|
|
53
|
-
return state.routes.length <= 1
|
|
58
|
+
return state.routes.length <= 1
|
|
59
|
+
? state
|
|
60
|
+
: { routes: state.routes.slice(0, 1) };
|
|
54
61
|
|
|
55
62
|
case 'popTo': {
|
|
56
63
|
const index = state.routes.findIndex(route => route.key === action.key);
|
|
@@ -68,7 +75,8 @@ export function navigatorReducer(
|
|
|
68
75
|
// `source`-defaults-to-focused-route behavior, minus the cross-navigator target routing this
|
|
69
76
|
// single-navigator reducer has no need for.
|
|
70
77
|
case 'setParams': {
|
|
71
|
-
const targetKey =
|
|
78
|
+
const targetKey =
|
|
79
|
+
action.key ?? state.routes[state.routes.length - 1]?.key;
|
|
72
80
|
if (targetKey === undefined) return state;
|
|
73
81
|
const index = state.routes.findIndex(route => route.key === targetKey);
|
|
74
82
|
if (index === -1) return state;
|
|
@@ -78,7 +86,11 @@ export function navigatorReducer(
|
|
|
78
86
|
params: mergeParams(target.params, action.params),
|
|
79
87
|
};
|
|
80
88
|
return {
|
|
81
|
-
routes: [
|
|
89
|
+
routes: [
|
|
90
|
+
...state.routes.slice(0, index),
|
|
91
|
+
nextRoute,
|
|
92
|
+
...state.routes.slice(index + 1),
|
|
93
|
+
],
|
|
82
94
|
};
|
|
83
95
|
}
|
|
84
96
|
|
|
@@ -102,9 +114,14 @@ export function navigatorReducer(
|
|
|
102
114
|
// an already-mounted NativeStack screen's activityState can never decrease via a plain prop
|
|
103
115
|
// update ("activityState can only progress in NativeStack") - since no mounted route's index ever
|
|
104
116
|
// exceeds routesLength - 1, this formula never produces a decrease across a push or pop.
|
|
105
|
-
export function computeActivityState(
|
|
117
|
+
export function computeActivityState(
|
|
118
|
+
index: number,
|
|
119
|
+
routesLength: number,
|
|
120
|
+
): number {
|
|
106
121
|
const focusedIndex = routesLength - 1;
|
|
107
|
-
return index > focusedIndex
|
|
122
|
+
return index > focusedIndex
|
|
123
|
+
? SCREEN_ACTIVITY_STATE_INACTIVE
|
|
124
|
+
: SCREEN_ACTIVITY_STATE_FOCUSED;
|
|
108
125
|
}
|
|
109
126
|
|
|
110
127
|
export function isTopRoute(index: number, routesLength: number): boolean {
|
|
@@ -32,7 +32,9 @@ export type IDrawerSlot = 'content' | 'overlay' | 'panel';
|
|
|
32
32
|
// slide: panel, overlay, content (both panel and content animate; content stays visually on top).
|
|
33
33
|
// permanent: NOT absolutely positioned (an ordinary flexDirection:'row' sidebar), so sibling
|
|
34
34
|
// order IS the left-to-right screen position - it must follow drawerPosition.
|
|
35
|
-
export function drawerChildOrder(
|
|
35
|
+
export function drawerChildOrder(
|
|
36
|
+
options: IDrawerOptions,
|
|
37
|
+
): readonly IDrawerSlot[] {
|
|
36
38
|
const type = resolveDrawerType(options);
|
|
37
39
|
switch (type) {
|
|
38
40
|
case 'back':
|
|
@@ -89,12 +91,22 @@ function panelBaseStyle(options: IDrawerOptions): IViewStyle {
|
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
export function renderDrawer(
|
|
94
|
+
export function renderDrawer(
|
|
95
|
+
view: IDrawerViewProps,
|
|
96
|
+
options: IDrawerOptions,
|
|
97
|
+
): IDescriptor {
|
|
93
98
|
const type = resolveDrawerType(options);
|
|
94
|
-
const content = el(
|
|
99
|
+
const content = el(
|
|
100
|
+
'symbiote-view',
|
|
101
|
+
{ ...view.contentPassthrough, style: CONTENT_STYLE },
|
|
102
|
+
[],
|
|
103
|
+
);
|
|
95
104
|
const panel = el(
|
|
96
105
|
'symbiote-view',
|
|
97
|
-
{
|
|
106
|
+
{
|
|
107
|
+
...view.panelPassthrough,
|
|
108
|
+
style: [panelBaseStyle(options), view.drawerStyle],
|
|
109
|
+
},
|
|
98
110
|
[],
|
|
99
111
|
);
|
|
100
112
|
|
|
@@ -110,11 +122,14 @@ export function renderDrawer(view: IDrawerViewProps, options: IDrawerOptions): I
|
|
|
110
122
|
);
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
const children = drawerChildOrder(options).reduce<IDescriptor[]>(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
const children = drawerChildOrder(options).reduce<IDescriptor[]>(
|
|
126
|
+
(acc, slot) => {
|
|
127
|
+
const descriptor = slots[slot];
|
|
128
|
+
if (descriptor !== undefined) acc.push(descriptor);
|
|
129
|
+
return acc;
|
|
130
|
+
},
|
|
131
|
+
[],
|
|
132
|
+
);
|
|
118
133
|
|
|
119
134
|
const rootStyle: IViewStyle =
|
|
120
135
|
type === 'permanent' ? { ...ROOT_STYLE, flexDirection: 'row' } : ROOT_STYLE;
|
package/src/core/render-stack.ts
CHANGED
|
@@ -41,7 +41,11 @@ import type {
|
|
|
41
41
|
IStackPresentation,
|
|
42
42
|
IStackViewProps,
|
|
43
43
|
} from './navigator-props';
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
resolveHeaderConfigView,
|
|
46
|
+
resolveScreenView,
|
|
47
|
+
resolveSearchBarView,
|
|
48
|
+
} from './screen-options';
|
|
45
49
|
|
|
46
50
|
// Mirrors react-native-screens' ScreenStackItem.tsx (getPositioningStyle): a formSheet's content
|
|
47
51
|
// wrapper does not get `flex: 1`. RNSScreen.mm's updateBounds pushes the sheet's live native size
|
|
@@ -101,7 +105,9 @@ export function resolveScreenViewName(
|
|
|
101
105
|
stackPresentation === 'push' ||
|
|
102
106
|
stackPresentation === 'containedModal' ||
|
|
103
107
|
stackPresentation === 'containedTransparentModal';
|
|
104
|
-
return isPlainPresentation
|
|
108
|
+
return isPlainPresentation
|
|
109
|
+
? RNS_SCREEN_VIEW_NAME
|
|
110
|
+
: RNS_MODAL_SCREEN_VIEW_NAME;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
export function resolveScreenContentWrapperStyle(
|
|
@@ -141,14 +147,23 @@ export function isHeaderInModal(
|
|
|
141
147
|
isAndroid: boolean,
|
|
142
148
|
): boolean {
|
|
143
149
|
if (isAndroid) return false;
|
|
144
|
-
return (
|
|
150
|
+
return (
|
|
151
|
+
(stackPresentation ?? STACK_DEFAULT_PRESENTATION) !== 'push' &&
|
|
152
|
+
!headerHidden
|
|
153
|
+
);
|
|
145
154
|
}
|
|
146
155
|
|
|
147
156
|
// Inner-modal wrapper styles for isHeaderInModal: the inner RNSScreenStack fills its outer
|
|
148
157
|
// RNSScreen, and the inner RNSScreen fills the stack absolutely on all four edges. This mirrors
|
|
149
158
|
// react-native-screens' own `styles.container` / `StyleSheet.absoluteFill` for this exact pair.
|
|
150
159
|
const HEADER_IN_MODAL_STACK_STYLE = { flex: 1 };
|
|
151
|
-
const HEADER_IN_MODAL_SCREEN_STYLE = {
|
|
160
|
+
const HEADER_IN_MODAL_SCREEN_STYLE = {
|
|
161
|
+
position: 'absolute',
|
|
162
|
+
top: 0,
|
|
163
|
+
start: 0,
|
|
164
|
+
end: 0,
|
|
165
|
+
bottom: 0,
|
|
166
|
+
};
|
|
152
167
|
|
|
153
168
|
export function resolveHeaderInModalStackStyle(): Record<string, unknown> {
|
|
154
169
|
return HEADER_IN_MODAL_STACK_STYLE;
|
|
@@ -160,7 +175,9 @@ export function resolveHeaderInModalScreenStyle(): Record<string, unknown> {
|
|
|
160
175
|
|
|
161
176
|
// The RNSScreen leaf's own props; the adapter spreads this record directly onto the element it
|
|
162
177
|
// builds and appends the header config child and real screen content itself, not here.
|
|
163
|
-
export function resolveScreenProps(
|
|
178
|
+
export function resolveScreenProps(
|
|
179
|
+
view: IScreenViewProps,
|
|
180
|
+
): Record<string, unknown> {
|
|
164
181
|
return {
|
|
165
182
|
...view.passthrough,
|
|
166
183
|
screenId: view.screenId,
|
|
@@ -175,7 +192,8 @@ export function resolveScreenProps(view: IScreenViewProps): Record<string, unkno
|
|
|
175
192
|
// coerceChildScrollViewComponentSizeToSize) is driven by that same state, so an async push
|
|
176
193
|
// likely lags one step behind a fast drag. Scoped to formSheet: push/plain-modal screens have
|
|
177
194
|
// no comparable live-resize need.
|
|
178
|
-
synchronousShadowStateUpdatesEnabled:
|
|
195
|
+
synchronousShadowStateUpdatesEnabled:
|
|
196
|
+
view.stackPresentation === 'formSheet',
|
|
179
197
|
transitionDuration: view.transitionDuration,
|
|
180
198
|
sheetAllowedDetents: view.sheetAllowedDetents,
|
|
181
199
|
// Native RNSScreen's real prop names carry an "Index" suffix (react-native-screens' own
|
|
@@ -199,7 +217,9 @@ export function resolveScreenProps(view: IScreenViewProps): Record<string, unkno
|
|
|
199
217
|
// `style: {flex: 1}` is ours, not react-native-screens': RNSScreenStackView sizes its nav
|
|
200
218
|
// controller to `self.bounds`, which Yoga would otherwise collapse to zero, and (unlike RN's
|
|
201
219
|
// own ScreenStack.tsx) we drive the native view directly (<third_party_rn_packages_are_react_only>).
|
|
202
|
-
export function resolveStackProps(
|
|
220
|
+
export function resolveStackProps(
|
|
221
|
+
view: IStackViewProps,
|
|
222
|
+
): Record<string, unknown> {
|
|
203
223
|
return { style: { flex: 1 }, ...view.passthrough };
|
|
204
224
|
}
|
|
205
225
|
|
|
@@ -257,7 +277,9 @@ export function renderHeaderConfig(
|
|
|
257
277
|
// The RNSSearchBar leaf's static config props; event handlers ride in `passthrough`.
|
|
258
278
|
// renderHeaderConfig wraps this into the RNSSearchBar Descriptor and nests it as the header
|
|
259
279
|
// config's child.
|
|
260
|
-
export function resolveSearchBarProps(
|
|
280
|
+
export function resolveSearchBarProps(
|
|
281
|
+
view: ISearchBarViewProps,
|
|
282
|
+
): Record<string, unknown> {
|
|
261
283
|
return {
|
|
262
284
|
...view.passthrough,
|
|
263
285
|
placeholder: view.placeholder,
|
|
@@ -368,19 +390,29 @@ export type IScreenRenderPlan = {
|
|
|
368
390
|
innerScreenStyle: Record<string, unknown>;
|
|
369
391
|
};
|
|
370
392
|
|
|
371
|
-
export function resolveScreenRenderPlan(
|
|
393
|
+
export function resolveScreenRenderPlan(
|
|
394
|
+
input: IScreenRenderPlanInput,
|
|
395
|
+
): IScreenRenderPlan {
|
|
372
396
|
const { options, isAndroid } = input;
|
|
373
397
|
const headerHidden = options?.headerShown === false;
|
|
374
398
|
const activityState = computeActivityState(input.index, input.routeCount);
|
|
375
399
|
|
|
376
400
|
const screenProps = resolveScreenProps(
|
|
377
|
-
resolveScreenView(
|
|
401
|
+
resolveScreenView(
|
|
402
|
+
input.screenId,
|
|
403
|
+
activityState,
|
|
404
|
+
options,
|
|
405
|
+
input.screenPassthrough,
|
|
406
|
+
),
|
|
378
407
|
);
|
|
379
408
|
|
|
380
409
|
const searchBarOptions = options?.headerSearchBarOptions;
|
|
381
410
|
const searchBarProps = searchBarOptions
|
|
382
411
|
? resolveSearchBarProps(
|
|
383
|
-
resolveSearchBarView(
|
|
412
|
+
resolveSearchBarView(
|
|
413
|
+
searchBarOptions,
|
|
414
|
+
input.searchBarPassthrough ?? {},
|
|
415
|
+
),
|
|
384
416
|
)
|
|
385
417
|
: undefined;
|
|
386
418
|
|
|
@@ -394,7 +426,10 @@ export function resolveScreenRenderPlan(input: IScreenRenderPlanInput): IScreenR
|
|
|
394
426
|
|
|
395
427
|
return {
|
|
396
428
|
activityState,
|
|
397
|
-
screenViewName: resolveScreenViewName(
|
|
429
|
+
screenViewName: resolveScreenViewName(
|
|
430
|
+
options?.stackPresentation,
|
|
431
|
+
isAndroid,
|
|
432
|
+
),
|
|
398
433
|
screenProps,
|
|
399
434
|
headerConfig,
|
|
400
435
|
searchBarProps,
|
|
@@ -407,7 +442,11 @@ export function resolveScreenRenderPlan(input: IScreenRenderPlanInput): IScreenR
|
|
|
407
442
|
),
|
|
408
443
|
collapsable: false,
|
|
409
444
|
},
|
|
410
|
-
inModal: isHeaderInModal(
|
|
445
|
+
inModal: isHeaderInModal(
|
|
446
|
+
options?.stackPresentation,
|
|
447
|
+
headerHidden,
|
|
448
|
+
isAndroid,
|
|
449
|
+
),
|
|
411
450
|
innerStackStyle: resolveHeaderInModalStackStyle(),
|
|
412
451
|
innerScreenStyle: resolveHeaderInModalScreenStyle(),
|
|
413
452
|
};
|