@symbiote-native/navigation 1.0.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/LICENSE +21 -0
- package/build/angular/drawer/index.d.ts +76 -0
- package/build/angular/drawer/index.js +508 -0
- package/build/angular/drawer-screen.directive.d.ts +14 -0
- package/build/angular/drawer-screen.directive.js +87 -0
- package/build/angular/index.d.ts +23 -0
- package/build/angular/index.js +22 -0
- package/build/angular/injectors/index.d.ts +13 -0
- package/build/angular/injectors/index.js +8 -0
- package/build/angular/injectors/inject-drawer-navigation.d.ts +4 -0
- package/build/angular/injectors/inject-drawer-navigation.js +12 -0
- package/build/angular/injectors/inject-focus-effect.d.ts +2 -0
- package/build/angular/injectors/inject-focus-effect.js +29 -0
- package/build/angular/injectors/inject-is-focused.d.ts +2 -0
- package/build/angular/injectors/inject-is-focused.js +20 -0
- package/build/angular/injectors/inject-navigation-state.d.ts +3 -0
- package/build/angular/injectors/inject-navigation-state.js +35 -0
- package/build/angular/injectors/inject-navigation.d.ts +7 -0
- package/build/angular/injectors/inject-navigation.js +16 -0
- package/build/angular/injectors/inject-route.d.ts +3 -0
- package/build/angular/injectors/inject-route.js +20 -0
- package/build/angular/injectors/inject-stack-navigation.d.ts +4 -0
- package/build/angular/injectors/inject-stack-navigation.js +15 -0
- package/build/angular/injectors/inject-tab-navigation.d.ts +4 -0
- package/build/angular/injectors/inject-tab-navigation.js +11 -0
- package/build/angular/linking.d.ts +3 -0
- package/build/angular/linking.js +43 -0
- package/build/angular/navigation-context.service.d.ts +13 -0
- package/build/angular/navigation-context.service.js +105 -0
- package/build/angular/navigation-scope.directive.d.ts +10 -0
- package/build/angular/navigation-scope.directive.js +90 -0
- package/build/angular/screen.directive.d.ts +22 -0
- package/build/angular/screen.directive.js +90 -0
- package/build/angular/search-bar-ref.directive.d.ts +10 -0
- package/build/angular/search-bar-ref.directive.js +88 -0
- package/build/angular/stack/index.d.ts +55 -0
- package/build/angular/stack/index.js +386 -0
- package/build/angular/tab-screen.directive.d.ts +14 -0
- package/build/angular/tab-screen.directive.js +87 -0
- package/build/angular/tabs/index.d.ts +42 -0
- package/build/angular/tabs/index.js +263 -0
- package/build/core/constants.d.ts +27 -0
- package/build/core/constants.js +61 -0
- package/build/core/drawer-options/index.d.ts +64 -0
- package/build/core/drawer-options/index.js +200 -0
- package/build/core/drawer-router-state/index.d.ts +21 -0
- package/build/core/drawer-router-state/index.js +40 -0
- package/build/core/guards.d.ts +2 -0
- package/build/core/guards.js +22 -0
- package/build/core/header-bar-buttons.d.ts +9 -0
- package/build/core/header-bar-buttons.js +163 -0
- package/build/core/index.d.ts +29 -0
- package/build/core/index.js +32 -0
- package/build/core/linking-config/index.d.ts +13 -0
- package/build/core/linking-config/index.js +171 -0
- package/build/core/navigation-events/index.d.ts +16 -0
- package/build/core/navigation-events/index.js +57 -0
- package/build/core/navigator-handles/index.d.ts +30 -0
- package/build/core/navigator-handles/index.js +15 -0
- package/build/core/navigator-props.d.ts +216 -0
- package/build/core/navigator-props.js +7 -0
- package/build/core/navigator-state/index.d.ts +36 -0
- package/build/core/navigator-state/index.js +81 -0
- package/build/core/render-drawer.d.ts +13 -0
- package/build/core/render-drawer.js +88 -0
- package/build/core/render-stack.d.ts +35 -0
- package/build/core/render-stack.js +294 -0
- package/build/core/render-tabs.d.ts +20 -0
- package/build/core/render-tabs.js +97 -0
- package/build/core/screen-options.d.ts +4 -0
- package/build/core/screen-options.js +133 -0
- package/build/core/search-bar-commands.d.ts +10 -0
- package/build/core/search-bar-commands.js +42 -0
- package/build/core/state-persistence/index.d.ts +3 -0
- package/build/core/state-persistence/index.js +23 -0
- package/build/core/tab-options.d.ts +13 -0
- package/build/core/tab-options.js +10 -0
- package/build/core/tab-router-state/index.d.ts +19 -0
- package/build/core/tab-router-state/index.js +51 -0
- package/build/react/collect-registry.d.ts +4 -0
- package/build/react/collect-registry.js +15 -0
- package/build/react/drawer/index.d.ts +29 -0
- package/build/react/drawer/index.js +277 -0
- package/build/react/drawer-screen.d.ts +14 -0
- package/build/react/drawer-screen.js +8 -0
- package/build/react/hooks/index.d.ts +12 -0
- package/build/react/hooks/index.js +8 -0
- package/build/react/hooks/use-drawer-navigation.d.ts +4 -0
- package/build/react/hooks/use-drawer-navigation.js +12 -0
- package/build/react/hooks/use-focus-effect.d.ts +2 -0
- package/build/react/hooks/use-focus-effect.js +29 -0
- package/build/react/hooks/use-is-focused.d.ts +1 -0
- package/build/react/hooks/use-is-focused.js +22 -0
- package/build/react/hooks/use-navigation-state/index.d.ts +2 -0
- package/build/react/hooks/use-navigation-state/index.js +39 -0
- package/build/react/hooks/use-navigation.d.ts +7 -0
- package/build/react/hooks/use-navigation.js +16 -0
- package/build/react/hooks/use-route.d.ts +2 -0
- package/build/react/hooks/use-route.js +8 -0
- package/build/react/hooks/use-stack-navigation.d.ts +4 -0
- package/build/react/hooks/use-stack-navigation.js +14 -0
- package/build/react/hooks/use-tab-navigation.d.ts +4 -0
- package/build/react/hooks/use-tab-navigation.js +12 -0
- package/build/react/index.d.ts +24 -0
- package/build/react/index.js +21 -0
- package/build/react/linking.d.ts +3 -0
- package/build/react/linking.js +47 -0
- package/build/react/navigation-context.d.ts +10 -0
- package/build/react/navigation-context.js +22 -0
- package/build/react/screen.d.ts +22 -0
- package/build/react/screen.js +7 -0
- package/build/react/stack/index.d.ts +13 -0
- package/build/react/stack/index.js +202 -0
- package/build/react/tab-screen.d.ts +15 -0
- package/build/react/tab-screen.js +8 -0
- package/build/react/tabs/index.d.ts +12 -0
- package/build/react/tabs/index.js +116 -0
- package/build/register.d.ts +7 -0
- package/build/register.js +58 -0
- package/build/vue/composables/index.d.ts +12 -0
- package/build/vue/composables/index.js +8 -0
- package/build/vue/composables/use-drawer-navigation.d.ts +5 -0
- package/build/vue/composables/use-drawer-navigation.js +15 -0
- package/build/vue/composables/use-focus-effect.d.ts +1 -0
- package/build/vue/composables/use-focus-effect.js +31 -0
- package/build/vue/composables/use-is-focused.d.ts +2 -0
- package/build/vue/composables/use-is-focused.js +28 -0
- package/build/vue/composables/use-navigation-state.d.ts +3 -0
- package/build/vue/composables/use-navigation-state.js +29 -0
- package/build/vue/composables/use-navigation.d.ts +8 -0
- package/build/vue/composables/use-navigation.js +13 -0
- package/build/vue/composables/use-route.d.ts +3 -0
- package/build/vue/composables/use-route.js +9 -0
- package/build/vue/composables/use-stack-navigation.d.ts +5 -0
- package/build/vue/composables/use-stack-navigation.js +18 -0
- package/build/vue/composables/use-tab-navigation.d.ts +5 -0
- package/build/vue/composables/use-tab-navigation.js +15 -0
- package/build/vue/drawer/index.d.ts +19 -0
- package/build/vue/drawer/index.js +390 -0
- package/build/vue/drawer-screen.d.ts +14 -0
- package/build/vue/drawer-screen.js +12 -0
- package/build/vue/index.d.ts +21 -0
- package/build/vue/index.js +19 -0
- package/build/vue/linking.d.ts +3 -0
- package/build/vue/linking.js +57 -0
- package/build/vue/navigation-context.d.ts +16 -0
- package/build/vue/navigation-context.js +65 -0
- package/build/vue/screen.d.ts +21 -0
- package/build/vue/screen.js +12 -0
- package/build/vue/stack/index.d.ts +9 -0
- package/build/vue/stack/index.js +279 -0
- package/build/vue/tab-screen.d.ts +14 -0
- package/build/vue/tab-screen.js +11 -0
- package/build/vue/tabs/index.d.ts +10 -0
- package/build/vue/tabs/index.js +209 -0
- package/build-ngc/angular/drawer/index.d.ts +79 -0
- package/build-ngc/angular/drawer/index.js +479 -0
- package/build-ngc/angular/drawer/index.js.map +1 -0
- package/build-ngc/angular/drawer-screen.directive.d.ts +17 -0
- package/build-ngc/angular/drawer-screen.directive.js +32 -0
- package/build-ngc/angular/drawer-screen.directive.js.map +1 -0
- package/build-ngc/angular/drawer.d.ts +79 -0
- package/build-ngc/angular/drawer.js +475 -0
- package/build-ngc/angular/drawer.js.map +1 -0
- package/build-ngc/angular/index.d.ts +23 -0
- package/build-ngc/angular/index.js +23 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/injectors/index.d.ts +13 -0
- package/build-ngc/angular/injectors/index.js +9 -0
- package/build-ngc/angular/injectors/index.js.map +1 -0
- package/build-ngc/angular/injectors/inject-drawer-navigation.d.ts +4 -0
- package/build-ngc/angular/injectors/inject-drawer-navigation.js +13 -0
- package/build-ngc/angular/injectors/inject-drawer-navigation.js.map +1 -0
- package/build-ngc/angular/injectors/inject-focus-effect.d.ts +2 -0
- package/build-ngc/angular/injectors/inject-focus-effect.js +30 -0
- package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -0
- package/build-ngc/angular/injectors/inject-is-focused.d.ts +2 -0
- package/build-ngc/angular/injectors/inject-is-focused.js +22 -0
- package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -0
- package/build-ngc/angular/injectors/inject-navigation-state.d.ts +3 -0
- package/build-ngc/angular/injectors/inject-navigation-state.js +37 -0
- package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -0
- package/build-ngc/angular/injectors/inject-navigation.d.ts +7 -0
- package/build-ngc/angular/injectors/inject-navigation.js +17 -0
- package/build-ngc/angular/injectors/inject-navigation.js.map +1 -0
- package/build-ngc/angular/injectors/inject-route.d.ts +3 -0
- package/build-ngc/angular/injectors/inject-route.js +21 -0
- package/build-ngc/angular/injectors/inject-route.js.map +1 -0
- package/build-ngc/angular/injectors/inject-stack-navigation.d.ts +4 -0
- package/build-ngc/angular/injectors/inject-stack-navigation.js +16 -0
- package/build-ngc/angular/injectors/inject-stack-navigation.js.map +1 -0
- package/build-ngc/angular/injectors/inject-tab-navigation.d.ts +4 -0
- package/build-ngc/angular/injectors/inject-tab-navigation.js +12 -0
- package/build-ngc/angular/injectors/inject-tab-navigation.js.map +1 -0
- package/build-ngc/angular/linking.d.ts +3 -0
- package/build-ngc/angular/linking.js +44 -0
- package/build-ngc/angular/linking.js.map +1 -0
- package/build-ngc/angular/navigation-context.service.d.ts +16 -0
- package/build-ngc/angular/navigation-context.service.js +63 -0
- package/build-ngc/angular/navigation-context.service.js.map +1 -0
- package/build-ngc/angular/navigation-scope.directive.d.ts +13 -0
- package/build-ngc/angular/navigation-scope.directive.js +42 -0
- package/build-ngc/angular/navigation-scope.directive.js.map +1 -0
- package/build-ngc/angular/screen.directive.d.ts +25 -0
- package/build-ngc/angular/screen.directive.js +35 -0
- package/build-ngc/angular/screen.directive.js.map +1 -0
- package/build-ngc/angular/search-bar-ref.directive.d.ts +13 -0
- package/build-ngc/angular/search-bar-ref.directive.js +44 -0
- package/build-ngc/angular/search-bar-ref.directive.js.map +1 -0
- package/build-ngc/angular/stack/index.d.ts +58 -0
- package/build-ngc/angular/stack/index.js +406 -0
- package/build-ngc/angular/stack/index.js.map +1 -0
- package/build-ngc/angular/stack.d.ts +58 -0
- package/build-ngc/angular/stack.js +402 -0
- package/build-ngc/angular/stack.js.map +1 -0
- package/build-ngc/angular/tab-screen.directive.d.ts +17 -0
- package/build-ngc/angular/tab-screen.directive.js +32 -0
- package/build-ngc/angular/tab-screen.directive.js.map +1 -0
- package/build-ngc/angular/tabs/index.d.ts +45 -0
- package/build-ngc/angular/tabs/index.js +231 -0
- package/build-ngc/angular/tabs/index.js.map +1 -0
- package/build-ngc/angular/tabs.d.ts +45 -0
- package/build-ngc/angular/tabs.js +231 -0
- package/build-ngc/angular/tabs.js.map +1 -0
- package/build-ngc/core/constants.d.ts +27 -0
- package/build-ngc/core/constants.js +62 -0
- package/build-ngc/core/constants.js.map +1 -0
- package/build-ngc/core/drawer-options/index.d.ts +64 -0
- package/build-ngc/core/drawer-options/index.js +201 -0
- package/build-ngc/core/drawer-options/index.js.map +1 -0
- package/build-ngc/core/drawer-options.d.ts +64 -0
- package/build-ngc/core/drawer-options.js +201 -0
- package/build-ngc/core/drawer-options.js.map +1 -0
- package/build-ngc/core/drawer-router-state/index.d.ts +21 -0
- package/build-ngc/core/drawer-router-state/index.js +41 -0
- package/build-ngc/core/drawer-router-state/index.js.map +1 -0
- package/build-ngc/core/drawer-router-state.d.ts +21 -0
- package/build-ngc/core/drawer-router-state.js +41 -0
- package/build-ngc/core/drawer-router-state.js.map +1 -0
- package/build-ngc/core/guards.d.ts +2 -0
- package/build-ngc/core/guards.js +23 -0
- package/build-ngc/core/guards.js.map +1 -0
- package/build-ngc/core/header-bar-buttons.d.ts +9 -0
- package/build-ngc/core/header-bar-buttons.js +164 -0
- package/build-ngc/core/header-bar-buttons.js.map +1 -0
- package/build-ngc/core/href.d.ts +16 -0
- package/build-ngc/core/href.js +55 -0
- package/build-ngc/core/href.js.map +1 -0
- package/build-ngc/core/index.d.ts +29 -0
- package/build-ngc/core/index.js +33 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/linking-config/index.d.ts +13 -0
- package/build-ngc/core/linking-config/index.js +172 -0
- package/build-ngc/core/linking-config/index.js.map +1 -0
- package/build-ngc/core/linking-config.d.ts +13 -0
- package/build-ngc/core/linking-config.js +172 -0
- package/build-ngc/core/linking-config.js.map +1 -0
- package/build-ngc/core/navigation-events/index.d.ts +16 -0
- package/build-ngc/core/navigation-events/index.js +58 -0
- package/build-ngc/core/navigation-events/index.js.map +1 -0
- package/build-ngc/core/navigation-events.d.ts +16 -0
- package/build-ngc/core/navigation-events.js +58 -0
- package/build-ngc/core/navigation-events.js.map +1 -0
- package/build-ngc/core/navigator-handles/index.d.ts +30 -0
- package/build-ngc/core/navigator-handles/index.js +16 -0
- package/build-ngc/core/navigator-handles/index.js.map +1 -0
- package/build-ngc/core/navigator-handles.d.ts +30 -0
- package/build-ngc/core/navigator-handles.js +16 -0
- package/build-ngc/core/navigator-handles.js.map +1 -0
- package/build-ngc/core/navigator-props.d.ts +216 -0
- package/build-ngc/core/navigator-props.js +8 -0
- package/build-ngc/core/navigator-props.js.map +1 -0
- package/build-ngc/core/navigator-state/index.d.ts +36 -0
- package/build-ngc/core/navigator-state/index.js +82 -0
- package/build-ngc/core/navigator-state/index.js.map +1 -0
- package/build-ngc/core/navigator-state.d.ts +36 -0
- package/build-ngc/core/navigator-state.js +82 -0
- package/build-ngc/core/navigator-state.js.map +1 -0
- package/build-ngc/core/render-drawer.d.ts +13 -0
- package/build-ngc/core/render-drawer.js +89 -0
- package/build-ngc/core/render-drawer.js.map +1 -0
- package/build-ngc/core/render-stack.d.ts +35 -0
- package/build-ngc/core/render-stack.js +295 -0
- package/build-ngc/core/render-stack.js.map +1 -0
- package/build-ngc/core/render-tabs.d.ts +20 -0
- package/build-ngc/core/render-tabs.js +98 -0
- package/build-ngc/core/render-tabs.js.map +1 -0
- package/build-ngc/core/screen-options.d.ts +4 -0
- package/build-ngc/core/screen-options.js +134 -0
- package/build-ngc/core/screen-options.js.map +1 -0
- package/build-ngc/core/search-bar-commands.d.ts +10 -0
- package/build-ngc/core/search-bar-commands.js +43 -0
- package/build-ngc/core/search-bar-commands.js.map +1 -0
- package/build-ngc/core/search-params.d.ts +9 -0
- package/build-ngc/core/search-params.js +60 -0
- package/build-ngc/core/search-params.js.map +1 -0
- package/build-ngc/core/state-persistence/index.d.ts +3 -0
- package/build-ngc/core/state-persistence/index.js +24 -0
- package/build-ngc/core/state-persistence/index.js.map +1 -0
- package/build-ngc/core/state-persistence.d.ts +3 -0
- package/build-ngc/core/state-persistence.js +24 -0
- package/build-ngc/core/state-persistence.js.map +1 -0
- package/build-ngc/core/tab-options.d.ts +13 -0
- package/build-ngc/core/tab-options.js +11 -0
- package/build-ngc/core/tab-options.js.map +1 -0
- package/build-ngc/core/tab-router-state/index.d.ts +19 -0
- package/build-ngc/core/tab-router-state/index.js +52 -0
- package/build-ngc/core/tab-router-state/index.js.map +1 -0
- package/build-ngc/core/tab-router-state.d.ts +19 -0
- package/build-ngc/core/tab-router-state.js +52 -0
- package/build-ngc/core/tab-router-state.js.map +1 -0
- package/build-ngc/register.d.ts +7 -0
- package/build-ngc/register.js +59 -0
- package/build-ngc/register.js.map +1 -0
- package/codegen-specs/FullWindowOverlayNativeComponent.ts +13 -0
- package/codegen-specs/ModalScreenNativeComponent.ts +129 -0
- package/codegen-specs/NativeScreensModule.ts +8 -0
- package/codegen-specs/NativeScreensModule.web.ts +1 -0
- package/codegen-specs/ScreenContainerNativeComponent.ts +8 -0
- package/codegen-specs/ScreenContentWrapperNativeComponent.ts +9 -0
- package/codegen-specs/ScreenFooterNativeComponent.ts +6 -0
- package/codegen-specs/ScreenNativeComponent.ts +133 -0
- package/codegen-specs/ScreenNavigationContainerNativeComponent.ts +11 -0
- package/codegen-specs/ScreenStackHeaderConfigNativeComponent.ts +99 -0
- package/codegen-specs/ScreenStackHeaderSubviewNativeComponent.ts +25 -0
- package/codegen-specs/ScreenStackNativeComponent.ts +17 -0
- package/codegen-specs/SearchBarNativeComponent.ts +101 -0
- package/codegen-specs/codegenUtils.ts +6 -0
- package/codegen-specs/gamma/ScrollViewMarkerNativeComponent.ts +15 -0
- package/codegen-specs/gamma/modals/form-sheet/FormSheetContentWrapperNativeComponent.ts +10 -0
- package/codegen-specs/gamma/modals/form-sheet/FormSheetHostNativeComponent.ts +47 -0
- package/codegen-specs/gamma/split/SplitHostNativeComponent.ts +124 -0
- package/codegen-specs/gamma/split/SplitScreenNativeComponent.ts +24 -0
- package/codegen-specs/gamma/stack/StackHeaderConfigAndroidNativeComponent.ts +144 -0
- package/codegen-specs/gamma/stack/StackHeaderConfigIOSNativeComponent.ts +34 -0
- package/codegen-specs/gamma/stack/StackHeaderItemIOSNativeComponent.ts +47 -0
- package/codegen-specs/gamma/stack/StackHeaderItemSpacerIOSNativeComponent.ts +20 -0
- package/codegen-specs/gamma/stack/StackHeaderSubviewAndroidNativeComponent.ts +27 -0
- package/codegen-specs/gamma/stack/StackHostNativeComponent.ts +8 -0
- package/codegen-specs/gamma/stack/StackScreenNativeComponent.ts +42 -0
- package/codegen-specs/safe-area/SafeAreaViewNativeComponent.ts +24 -0
- package/codegen-specs/tabs/TabsBottomAccessoryContentNativeComponent.ts +15 -0
- package/codegen-specs/tabs/TabsBottomAccessoryNativeComponent.ts +19 -0
- package/codegen-specs/tabs/TabsHostAndroidNativeComponent.ts +69 -0
- package/codegen-specs/tabs/TabsHostIOSNativeComponent.ts +92 -0
- package/codegen-specs/tabs/TabsScreenAndroidNativeComponent.ts +112 -0
- package/codegen-specs/tabs/TabsScreenIOSNativeComponent.ts +171 -0
- package/package.json +201 -0
- package/react-native.config.cjs +58 -0
- package/src/angular/drawer/drawer.test.ts +299 -0
- package/src/angular/drawer/index.ts +546 -0
- package/src/angular/drawer-screen.directive.ts +28 -0
- package/src/angular/index.ts +63 -0
- package/src/angular/injectors/index.ts +13 -0
- package/src/angular/injectors/inject-drawer-navigation.ts +21 -0
- package/src/angular/injectors/inject-focus-effect.ts +37 -0
- package/src/angular/injectors/inject-is-focused.ts +28 -0
- package/src/angular/injectors/inject-navigation-state.ts +46 -0
- package/src/angular/injectors/inject-navigation.ts +26 -0
- package/src/angular/injectors/inject-route.ts +25 -0
- package/src/angular/injectors/inject-stack-navigation.ts +24 -0
- package/src/angular/injectors/inject-tab-navigation.ts +20 -0
- package/src/angular/injectors/injectors.test.ts +247 -0
- package/src/angular/injectors/use-typed-navigation.test.ts +229 -0
- package/src/angular/linking.ts +55 -0
- package/src/angular/navigation-context.service.ts +68 -0
- package/src/angular/navigation-scope.directive.ts +31 -0
- package/src/angular/nested-navigation.test.ts +189 -0
- package/src/angular/screen.directive.ts +48 -0
- package/src/angular/search-bar-ref.directive.ts +38 -0
- package/src/angular/stack/index.ts +401 -0
- package/src/angular/stack/stack.test.ts +419 -0
- package/src/angular/tab-screen.directive.ts +26 -0
- package/src/angular/tabs/index.ts +254 -0
- package/src/angular/tabs/tabs.test.ts +249 -0
- package/src/core/constants.ts +68 -0
- package/src/core/drawer-options/drawer-options.test.ts +415 -0
- package/src/core/drawer-options/index.ts +331 -0
- package/src/core/drawer-router-state/drawer-router-state.test.ts +116 -0
- package/src/core/drawer-router-state/index.ts +71 -0
- package/src/core/guards.ts +23 -0
- package/src/core/header-bar-buttons.ts +212 -0
- package/src/core/index.ts +170 -0
- package/src/core/linking-config/index.ts +209 -0
- package/src/core/linking-config/linking-config.test.ts +109 -0
- package/src/core/navigation-events/index.ts +94 -0
- package/src/core/navigation-events/navigation-events.test.ts +56 -0
- package/src/core/navigator-handles/index.ts +63 -0
- package/src/core/navigator-handles/navigator-handles.test.ts +46 -0
- package/src/core/navigator-props.ts +323 -0
- package/src/core/navigator-state/index.ts +112 -0
- package/src/core/navigator-state/navigator-state.test.ts +80 -0
- package/src/core/render-drawer.ts +123 -0
- package/src/core/render-stack.ts +414 -0
- package/src/core/render-tabs.ts +138 -0
- package/src/core/screen-options.ts +181 -0
- package/src/core/search-bar-commands.ts +57 -0
- package/src/core/state-persistence/index.ts +30 -0
- package/src/core/state-persistence/state-persistence.test.ts +42 -0
- package/src/core/tab-options.ts +25 -0
- package/src/core/tab-router-state/index.ts +75 -0
- package/src/core/tab-router-state/tab-router-state.test.ts +34 -0
- package/src/globals.d.ts +4 -0
- package/src/react/collect-registry.ts +19 -0
- package/src/react/drawer/drawer.test.tsx +472 -0
- package/src/react/drawer/index.ts +451 -0
- package/src/react/drawer-screen.ts +29 -0
- package/src/react/hooks/hooks.test.tsx +199 -0
- package/src/react/hooks/index.ts +12 -0
- package/src/react/hooks/use-drawer-navigation.ts +21 -0
- package/src/react/hooks/use-focus-effect.ts +36 -0
- package/src/react/hooks/use-is-focused.ts +26 -0
- package/src/react/hooks/use-navigation-state/index.ts +47 -0
- package/src/react/hooks/use-navigation-state/use-navigation-state.test.ts +85 -0
- package/src/react/hooks/use-navigation.ts +36 -0
- package/src/react/hooks/use-route.ts +11 -0
- package/src/react/hooks/use-stack-navigation.ts +23 -0
- package/src/react/hooks/use-tab-navigation.ts +21 -0
- package/src/react/hooks/use-typed-navigation.test.tsx +187 -0
- package/src/react/index.ts +52 -0
- package/src/react/linking.ts +59 -0
- package/src/react/navigation-context.ts +40 -0
- package/src/react/nested-navigation.test.tsx +145 -0
- package/src/react/screen.ts +44 -0
- package/src/react/stack/index.ts +323 -0
- package/src/react/stack/stack.test.tsx +514 -0
- package/src/react/tab-screen.ts +30 -0
- package/src/react/tabs/index.ts +204 -0
- package/src/react/tabs/tabs.test.tsx +256 -0
- package/src/register.ts +59 -0
- package/src/vue/composables/composables.test.ts +221 -0
- package/src/vue/composables/index.ts +12 -0
- package/src/vue/composables/use-drawer-navigation.ts +25 -0
- package/src/vue/composables/use-focus-effect.ts +37 -0
- package/src/vue/composables/use-is-focused.ts +34 -0
- package/src/vue/composables/use-navigation-state.ts +38 -0
- package/src/vue/composables/use-navigation.ts +30 -0
- package/src/vue/composables/use-route.ts +13 -0
- package/src/vue/composables/use-stack-navigation.ts +28 -0
- package/src/vue/composables/use-tab-navigation.ts +25 -0
- package/src/vue/composables/use-typed-navigation.test.ts +205 -0
- package/src/vue/drawer/drawer.test.ts +451 -0
- package/src/vue/drawer/index.ts +550 -0
- package/src/vue/drawer-screen.ts +32 -0
- package/src/vue/index.ts +70 -0
- package/src/vue/linking.ts +69 -0
- package/src/vue/navigation-context.ts +87 -0
- package/src/vue/nested-navigation.test.ts +155 -0
- package/src/vue/screen.ts +52 -0
- package/src/vue/stack/index.ts +376 -0
- package/src/vue/stack/stack.test.ts +501 -0
- package/src/vue/tab-screen.ts +29 -0
- package/src/vue/tabs/index.ts +302 -0
- package/src/vue/tabs/tabs.test.ts +278 -0
- package/symbiote-navigation.podspec +84 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Header bar-button payload + dispatch: the native-shaped `headerLeftBarButtonItems`/
|
|
2
|
+
// `headerRightBarButtonItems` fold react-native-screens' own ScreenStackHeaderConfig component
|
|
3
|
+
// would send down, plus the buttonId/menuId -> onPress lookup that answers RNSScreenStackHeader-
|
|
4
|
+
// Config's `onPressHeaderBarButtonItem`/`onPressHeaderBarButtonMenuItem` events. Self-contained:
|
|
5
|
+
// only `resolveHeaderConfigView` (screen-options.ts) calls into this file, as a black box - the
|
|
6
|
+
// id-tagging scheme below is this cluster's own internal invariant, never a cross-file contract.
|
|
7
|
+
|
|
8
|
+
import { imageStatics } from '@symbiote-native/components';
|
|
9
|
+
import { processColor } from '@symbiote-native/engine';
|
|
10
|
+
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
11
|
+
import type {
|
|
12
|
+
IHeaderBarButtonIcon,
|
|
13
|
+
IHeaderBarButtonItem,
|
|
14
|
+
IHeaderBarButtonItemAction,
|
|
15
|
+
IHeaderBarButtonItemMenu,
|
|
16
|
+
IHeaderBarButtonMenuAction,
|
|
17
|
+
IHeaderBarButtonSubmenu,
|
|
18
|
+
} from './navigator-props';
|
|
19
|
+
|
|
20
|
+
// RNS flattens `icon` into sfSymbolName/xcassetName/imageSource/templateSource at native-payload
|
|
21
|
+
// time (both the structured `icon` field AND the flat native keys reach native - RNS's own
|
|
22
|
+
// prepareHeaderBarButtonItems keeps both), and resolves image assets through the same resolver
|
|
23
|
+
// the Image component uses.
|
|
24
|
+
function prepareIcon(icon: IHeaderBarButtonIcon | undefined): Record<string, unknown> {
|
|
25
|
+
if (!icon) return {};
|
|
26
|
+
switch (icon.type) {
|
|
27
|
+
case 'sfSymbol':
|
|
28
|
+
return { sfSymbolName: icon.name };
|
|
29
|
+
case 'xcasset':
|
|
30
|
+
return { xcassetName: icon.name };
|
|
31
|
+
case 'imageSource':
|
|
32
|
+
return { imageSource: imageStatics.resolveAssetSource(icon.imageSource) };
|
|
33
|
+
case 'templateSource':
|
|
34
|
+
return { templateSource: imageStatics.resolveAssetSource(icon.templateSource) };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type ISharedItem = IHeaderBarButtonItemAction | IHeaderBarButtonItemMenu;
|
|
39
|
+
|
|
40
|
+
// The one id algorithm both the payload tagger (prepareMenuItems/prepareHeaderBarButtonItems)
|
|
41
|
+
// and the dispatch-lookup builder (collectMenuHandlers/collectBarButtonHandlers) call - so a
|
|
42
|
+
// change to the id scheme genuinely can't desync payload tagging from dispatch lookup.
|
|
43
|
+
function buildMenuId(path: string, index: number, side: 'left' | 'right'): string {
|
|
44
|
+
return `${path}-${index}-${side}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function buildButtonId(index: number, side: 'left' | 'right'): string {
|
|
48
|
+
return `${index}-${side}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function prepareTitleStyle(
|
|
52
|
+
titleStyle: ISharedItem['titleStyle'],
|
|
53
|
+
): Record<string, unknown> | undefined {
|
|
54
|
+
if (!titleStyle) return undefined;
|
|
55
|
+
return {
|
|
56
|
+
...titleStyle,
|
|
57
|
+
color: titleStyle.color === undefined ? undefined : processColor(titleStyle.color),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function prepareBadge(badge: ISharedItem['badge']): Record<string, unknown> | undefined {
|
|
62
|
+
if (!badge) return undefined;
|
|
63
|
+
return {
|
|
64
|
+
...badge,
|
|
65
|
+
style: badge.style
|
|
66
|
+
? {
|
|
67
|
+
...badge.style,
|
|
68
|
+
color: badge.style.color === undefined ? undefined : processColor(badge.style.color),
|
|
69
|
+
backgroundColor:
|
|
70
|
+
badge.style.backgroundColor === undefined
|
|
71
|
+
? undefined
|
|
72
|
+
: processColor(badge.style.backgroundColor),
|
|
73
|
+
}
|
|
74
|
+
: undefined,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// onPress is captured separately into the buttonId/menuId -> handler map (collectMenuHandlers/
|
|
79
|
+
// collectBarButtonHandlers below) and must never reach native: a function value fails Fabric's
|
|
80
|
+
// dynamic-value serialization, which silently drops the WHOLE headerLeftBarButtonItems/
|
|
81
|
+
// headerRightBarButtonItems array it's nested in - not just the one bad field - so bar buttons and
|
|
82
|
+
// menu actions never reached native at all, despite the buttonId/menuId dispatch wiring itself
|
|
83
|
+
// being entirely correct.
|
|
84
|
+
function excludeOnPress<T extends { onPress: unknown }>(item: T): Omit<T, 'onPress'> {
|
|
85
|
+
const { onPress: _onPress, ...rest } = item;
|
|
86
|
+
return rest;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Shared fields common to the 'button' and 'menu' item variants (title/icon/tint/badge/...) - the
|
|
90
|
+
// 'spacing' variant carries none of these and passes through untouched.
|
|
91
|
+
function prepareSharedFields(
|
|
92
|
+
item: IHeaderBarButtonItem & { type: 'button' | 'menu' },
|
|
93
|
+
): Record<string, unknown> {
|
|
94
|
+
return {
|
|
95
|
+
...(item.type === 'button' ? excludeOnPress(item) : item),
|
|
96
|
+
...prepareIcon(item.icon),
|
|
97
|
+
titleStyle: prepareTitleStyle(item.titleStyle),
|
|
98
|
+
tintColor: item.tintColor === undefined ? undefined : processColor(item.tintColor),
|
|
99
|
+
badge: prepareBadge(item.badge),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type IMenuLike = { items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[] };
|
|
104
|
+
|
|
105
|
+
// Recursively tags every menu action with a `menuId` derived from its tree position
|
|
106
|
+
// (`${path}-${index}-${side}`), mirroring RNS's own prepareMenu exactly - the id must match what
|
|
107
|
+
// buildHeaderBarButtonDispatch computes below, or a press silently no-ops.
|
|
108
|
+
function prepareMenuItems<T extends IMenuLike>(
|
|
109
|
+
menuLike: T,
|
|
110
|
+
index: number,
|
|
111
|
+
side: 'left' | 'right',
|
|
112
|
+
path = '',
|
|
113
|
+
): T {
|
|
114
|
+
return {
|
|
115
|
+
...menuLike,
|
|
116
|
+
items: menuLike.items.map((menuItem, menuIndex) => {
|
|
117
|
+
const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
|
|
118
|
+
const icon = prepareIcon(menuItem.icon);
|
|
119
|
+
if (menuItem.type === 'submenu') {
|
|
120
|
+
return { ...menuItem, ...icon, ...prepareMenuItems(menuItem, index, side, currentPath) };
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
...excludeOnPress(menuItem),
|
|
124
|
+
...icon,
|
|
125
|
+
menuId: buildMenuId(currentPath, index, side),
|
|
126
|
+
};
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Builds the native-shaped payload react-native-screens' own ScreenStackHeaderConfig component
|
|
132
|
+
// would send down (buttonId/menuId-tagged, colors processColor'd) - this is what
|
|
133
|
+
// IHeaderConfigViewProps.headerLeftBarButtonItems/headerRightBarButtonItems actually carry.
|
|
134
|
+
export function prepareHeaderBarButtonItems(
|
|
135
|
+
items: IHeaderBarButtonItem[] | undefined,
|
|
136
|
+
side: 'left' | 'right',
|
|
137
|
+
): unknown[] | undefined {
|
|
138
|
+
if (!items) return undefined;
|
|
139
|
+
return items.map((item, index) => {
|
|
140
|
+
if (item.type === 'spacing') return item;
|
|
141
|
+
const prepared = prepareSharedFields(item);
|
|
142
|
+
if (item.type === 'button') return { ...prepared, buttonId: buildButtonId(index, side) };
|
|
143
|
+
return { ...prepared, menu: prepareMenuItems(item.menu, index, side) };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function collectMenuHandlers(
|
|
148
|
+
items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[],
|
|
149
|
+
index: number,
|
|
150
|
+
side: 'left' | 'right',
|
|
151
|
+
path: string,
|
|
152
|
+
handlers: Map<string, () => void>,
|
|
153
|
+
): void {
|
|
154
|
+
items.forEach((item, menuIndex) => {
|
|
155
|
+
const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
|
|
156
|
+
if (item.type === 'submenu') {
|
|
157
|
+
collectMenuHandlers(item.items, index, side, currentPath, handlers);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
handlers.set(buildMenuId(currentPath, index, side), item.onPress);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function collectBarButtonHandlers(
|
|
165
|
+
items: IHeaderBarButtonItem[] | undefined,
|
|
166
|
+
side: 'left' | 'right',
|
|
167
|
+
buttonHandlers: Map<string, () => void>,
|
|
168
|
+
menuHandlers: Map<string, () => void>,
|
|
169
|
+
): void {
|
|
170
|
+
items?.forEach((item, index) => {
|
|
171
|
+
if (item.type === 'button') {
|
|
172
|
+
buttonHandlers.set(buildButtonId(index, side), item.onPress);
|
|
173
|
+
} else if (item.type === 'menu') {
|
|
174
|
+
collectMenuHandlers(item.menu.items, index, side, '', menuHandlers);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function readStringField(record: Record<string, unknown>, key: string): string | undefined {
|
|
180
|
+
const value = record[key];
|
|
181
|
+
return typeof value === 'string' ? value : undefined;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
type IHeaderBarButtonDispatch = {
|
|
185
|
+
onPressHeaderBarButtonItem?: (event: ISymbioteEvent) => void;
|
|
186
|
+
onPressHeaderBarButtonMenuItem?: (event: ISymbioteEvent) => void;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// The buttonId/menuId → onPress lookup is built independently from prepareHeaderBarButtonItems'
|
|
190
|
+
// native payload (rather than re-parsing it back out of the `unknown[]` result), over the
|
|
191
|
+
// ORIGINAL typed items - but both sides call the same buildMenuId/buildButtonId, so the id
|
|
192
|
+
// scheme lives in one place and can't desync payload tagging from dispatch lookup.
|
|
193
|
+
export function buildHeaderBarButtonDispatch(
|
|
194
|
+
leftItems: IHeaderBarButtonItem[] | undefined,
|
|
195
|
+
rightItems: IHeaderBarButtonItem[] | undefined,
|
|
196
|
+
): IHeaderBarButtonDispatch {
|
|
197
|
+
const buttonHandlers = new Map<string, () => void>();
|
|
198
|
+
const menuHandlers = new Map<string, () => void>();
|
|
199
|
+
collectBarButtonHandlers(leftItems, 'left', buttonHandlers, menuHandlers);
|
|
200
|
+
collectBarButtonHandlers(rightItems, 'right', buttonHandlers, menuHandlers);
|
|
201
|
+
if (buttonHandlers.size === 0 && menuHandlers.size === 0) return {};
|
|
202
|
+
return {
|
|
203
|
+
onPressHeaderBarButtonItem: event => {
|
|
204
|
+
const buttonId = readStringField(event.nativeEvent, 'buttonId');
|
|
205
|
+
if (buttonId !== undefined) buttonHandlers.get(buttonId)?.();
|
|
206
|
+
},
|
|
207
|
+
onPressHeaderBarButtonMenuItem: event => {
|
|
208
|
+
const menuId = readStringField(event.nativeEvent, 'menuId');
|
|
209
|
+
if (menuId !== undefined) menuHandlers.get(menuId)?.();
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// @symbiote-native/navigation (core): the framework-agnostic half of the native stack navigator -
|
|
2
|
+
// a pure route-stack reducer plus the react-native-screens prop folds and native-leaf prop
|
|
3
|
+
// resolvers. symbiote ships zero runtime metadata for RNSScreen/RNSScreenStack/
|
|
4
|
+
// RNSScreenStackHeaderConfig - the engine derives their events and color processors from
|
|
5
|
+
// react-native-screens' own ViewConfig - so this layer is the pure JS every adapter reuses
|
|
6
|
+
// verbatim, supplying only its lifecycle (route-key generation, useReducer/reactive state) and
|
|
7
|
+
// the descriptor bridge.
|
|
8
|
+
|
|
9
|
+
export * from './constants';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
createInitialNavigatorState,
|
|
13
|
+
navigatorReducer,
|
|
14
|
+
computeActivityState,
|
|
15
|
+
isTopRoute,
|
|
16
|
+
} from './navigator-state';
|
|
17
|
+
export type { IRoute, INavigatorState, INavigatorAction } from './navigator-state';
|
|
18
|
+
|
|
19
|
+
export type {
|
|
20
|
+
IStackAnimation,
|
|
21
|
+
IStackPresentation,
|
|
22
|
+
IHeaderBackButtonDisplayMode,
|
|
23
|
+
IHeaderUserInterfaceStyle,
|
|
24
|
+
IOptionalBooleanNativeProp,
|
|
25
|
+
ISheetAllowedDetents,
|
|
26
|
+
ISheetLargestUndimmedDetent,
|
|
27
|
+
ISheetInitialDetent,
|
|
28
|
+
IHeaderBarButtonIcon,
|
|
29
|
+
IHeaderBarButtonItemBadge,
|
|
30
|
+
IHeaderBarButtonItemAction,
|
|
31
|
+
IHeaderBarButtonMenuAction,
|
|
32
|
+
IHeaderBarButtonSubmenu,
|
|
33
|
+
IHeaderBarButtonItemMenu,
|
|
34
|
+
IHeaderBarButtonItemSpacing,
|
|
35
|
+
IHeaderBarButtonItem,
|
|
36
|
+
ISearchBarAutoCapitalize,
|
|
37
|
+
ISearchBarPlacement,
|
|
38
|
+
ISearchBarOptions,
|
|
39
|
+
IScreenOrientation,
|
|
40
|
+
IScreenOptions,
|
|
41
|
+
INavigatorPlatform,
|
|
42
|
+
IScreenViewProps,
|
|
43
|
+
IHeaderConfigViewProps,
|
|
44
|
+
IStackViewProps,
|
|
45
|
+
ISearchBarViewProps,
|
|
46
|
+
} from './navigator-props';
|
|
47
|
+
|
|
48
|
+
export { resolveHeaderConfigView, resolveScreenView, resolveSearchBarView } from './screen-options';
|
|
49
|
+
|
|
50
|
+
export { buildSearchBarHandle } from './search-bar-commands';
|
|
51
|
+
export type { ISearchBarCommands } from './search-bar-commands';
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
resolveScreenProps,
|
|
55
|
+
resolveStackProps,
|
|
56
|
+
renderHeaderConfig,
|
|
57
|
+
resolveSearchBarProps,
|
|
58
|
+
resolveScreenContentWrapperStyle,
|
|
59
|
+
resolveScreenViewName,
|
|
60
|
+
isHeaderInModal,
|
|
61
|
+
resolveHeaderInModalStackStyle,
|
|
62
|
+
resolveHeaderInModalScreenStyle,
|
|
63
|
+
buildSearchBarPassthrough,
|
|
64
|
+
resolveScreenRenderPlan,
|
|
65
|
+
} from './render-stack';
|
|
66
|
+
export type { IScreenRenderPlanInput, IScreenRenderPlan } from './render-stack';
|
|
67
|
+
|
|
68
|
+
export { serializeNavigatorState, deserializeNavigatorState } from './state-persistence';
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
createNavigationEmitter,
|
|
72
|
+
diffFocusedRoute,
|
|
73
|
+
NAVIGATION_EVENT_FOCUS,
|
|
74
|
+
NAVIGATION_EVENT_BLUR,
|
|
75
|
+
NAVIGATION_EVENT_STATE,
|
|
76
|
+
NAVIGATION_EVENT_BEFORE_REMOVE,
|
|
77
|
+
} from './navigation-events';
|
|
78
|
+
export type {
|
|
79
|
+
INavigationEmitter,
|
|
80
|
+
INavigationEventListener,
|
|
81
|
+
INavigationEventName,
|
|
82
|
+
IFocusTransition,
|
|
83
|
+
} from './navigation-events';
|
|
84
|
+
|
|
85
|
+
// Runtime guards shared across core (and re-exported for adapters narrowing their own untyped
|
|
86
|
+
// inputs - vnode props, gesture/event data, persisted JSON) - see guards.ts's header for which
|
|
87
|
+
// call sites this consolidates and why array-exclusion is the right default everywhere it's used.
|
|
88
|
+
export { isRecord } from './guards';
|
|
89
|
+
|
|
90
|
+
// Bottom-tabs navigator: a FOCUSED-INDEX router (not a stack - see tab-router-state.ts) driving
|
|
91
|
+
// a pure-JS tab bar render, framework-agnostic and shared verbatim by every adapter.
|
|
92
|
+
export { createInitialTabState, tabRouterReducer, isFocusedRoute } from './tab-router-state';
|
|
93
|
+
export type { ITabRouterState, ITabRouterAction } from './tab-router-state';
|
|
94
|
+
|
|
95
|
+
export type { ITabBarIcon, ITabOptions } from './tab-options';
|
|
96
|
+
|
|
97
|
+
export { renderTabBarItem, renderTabBar } from './render-tabs';
|
|
98
|
+
export type { ITabBarItemView, ITabBarViewProps } from './render-tabs';
|
|
99
|
+
|
|
100
|
+
// Linking config: resolves a URL to a route (and back), the piece @react-navigation's
|
|
101
|
+
// NavigationContainer `linking` prop provides on top of the framework-agnostic Linking module.
|
|
102
|
+
export { resolveRouteFromUrl, resolveUrlFromRoute } from './linking-config';
|
|
103
|
+
export type { ILinkingConfig, IScreenLinkingConfig } from './linking-config';
|
|
104
|
+
|
|
105
|
+
// Drawer navigator: an OPEN/CLOSED-flag router over a fixed route list (see
|
|
106
|
+
// drawer-router-state.ts's header for why it isn't a push/pop stack), a pure swipe/geometry math
|
|
107
|
+
// module, and a Descriptor render fn - all framework-agnostic, shared verbatim by every adapter.
|
|
108
|
+
export {
|
|
109
|
+
createInitialDrawerRouterState,
|
|
110
|
+
drawerRouterReducer,
|
|
111
|
+
focusedDrawerRoute,
|
|
112
|
+
} from './drawer-router-state';
|
|
113
|
+
export type { IDrawerRouterState, IDrawerRouterAction } from './drawer-router-state';
|
|
114
|
+
|
|
115
|
+
export type {
|
|
116
|
+
IDrawerType,
|
|
117
|
+
IDrawerPosition,
|
|
118
|
+
IDrawerOptions,
|
|
119
|
+
IDrawerScreenOptions,
|
|
120
|
+
IDrawerGeometry,
|
|
121
|
+
ISwipeIntent,
|
|
122
|
+
} from './drawer-options';
|
|
123
|
+
export {
|
|
124
|
+
DRAWER_DEFAULT_TYPE,
|
|
125
|
+
DRAWER_DEFAULT_POSITION,
|
|
126
|
+
DRAWER_DEFAULT_WIDTH,
|
|
127
|
+
DRAWER_DEFAULT_OVERLAY_COLOR,
|
|
128
|
+
DRAWER_DEFAULT_SWIPE_ENABLED,
|
|
129
|
+
DRAWER_DEFAULT_SWIPE_EDGE_WIDTH,
|
|
130
|
+
DRAWER_DEFAULT_SWIPE_MIN_DISTANCE,
|
|
131
|
+
DRAWER_DEFAULT_SWIPE_MIN_VELOCITY,
|
|
132
|
+
resolveDrawerType,
|
|
133
|
+
resolveDrawerPosition,
|
|
134
|
+
resolveDrawerWidth,
|
|
135
|
+
isDrawerAnimated,
|
|
136
|
+
isDrawerOverlayVisible,
|
|
137
|
+
resolveDrawerGeometry,
|
|
138
|
+
isSwipeStartInEdge,
|
|
139
|
+
isHorizontalDrag,
|
|
140
|
+
resolveSwipeIntent,
|
|
141
|
+
clamp01,
|
|
142
|
+
startPageXOf,
|
|
143
|
+
resolveDragProgress,
|
|
144
|
+
shouldClaimDrawerSwipe,
|
|
145
|
+
resolveDrawerSlotInterpolation,
|
|
146
|
+
} from './drawer-options';
|
|
147
|
+
export type {
|
|
148
|
+
IDrawerInterpolationRange,
|
|
149
|
+
IDrawerContentSlotInterpolation,
|
|
150
|
+
IDrawerOverlaySlotInterpolation,
|
|
151
|
+
IDrawerPanelSlotInterpolation,
|
|
152
|
+
} from './drawer-options';
|
|
153
|
+
|
|
154
|
+
export { renderDrawer, drawerChildOrder } from './render-drawer';
|
|
155
|
+
export type { IDrawerSlot, IDrawerViewProps } from './render-drawer';
|
|
156
|
+
|
|
157
|
+
// Imperative navigator handles (Stack/Tab/Drawer): framework-agnostic, declared once here and
|
|
158
|
+
// re-exported verbatim by every adapter (see navigator-handles.ts's header).
|
|
159
|
+
export type {
|
|
160
|
+
INavigatorHandle,
|
|
161
|
+
ITabNavigatorHandle,
|
|
162
|
+
IDrawerNavigatorHandle,
|
|
163
|
+
IDrawerDescriptorMap,
|
|
164
|
+
IAnyNavigatorHandle,
|
|
165
|
+
} from './navigator-handles';
|
|
166
|
+
export {
|
|
167
|
+
isStackNavigatorHandle,
|
|
168
|
+
isTabNavigatorHandle,
|
|
169
|
+
isDrawerNavigatorHandle,
|
|
170
|
+
} from './navigator-handles';
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Linking config: the piece @react-navigation's `NavigationContainer`'s `linking` prop provides
|
|
2
|
+
// on top of the framework-agnostic `Linking` module (core/engine/src/linking) - resolving a URL
|
|
3
|
+
// ('myapp://user/42', '/user/42') to a route, and a route back to a URL. This is OUR OWN type,
|
|
4
|
+
// not imported from react-navigation, kept close to its shape (`prefixes` + `config.screens`)
|
|
5
|
+
// only so the DX is familiar.
|
|
6
|
+
//
|
|
7
|
+
// Why hand-rolled matching instead of react-router's `matchPath`/`generatePath` (evaluated per
|
|
8
|
+
// task): react-router 8's package has no subpath export for the pure `lib/router/utils.ts`
|
|
9
|
+
// matcher - its only general entry point (`.`) eagerly imports `./lib/dom/*`
|
|
10
|
+
// (BrowserRouter/ScrollRestoration/cookies) and `./lib/server-runtime/*`, code that assumes DOM
|
|
11
|
+
// and Node globals a Metro/Hermes RN bundle doesn't have; its `peerDependencies` also pin
|
|
12
|
+
// `react-dom`, which this DOM-free monorepo never installs (see CLAUDE.md
|
|
13
|
+
// react_native_is_an_explicit_top_level_peer - no foreign runtime singleton gets smuggled in).
|
|
14
|
+
// On top of the bundling risk, `matchPath`'s/`generatePath`'s param-name extraction is a
|
|
15
|
+
// template-literal-type trick that only fires for a compile-time LITERAL path string; our
|
|
16
|
+
// patterns come from a runtime config object (`Path` widens to plain `string`), so the generic
|
|
17
|
+
// degrades to an empty params type and using the result would force an `as` cast - forbidden by
|
|
18
|
+
// this project's TS conventions. A minimal `:param`-segment matcher sidesteps both problems and
|
|
19
|
+
// is the right size for a single flat Stack (no optional/splat segments - no nested-navigator use
|
|
20
|
+
// for them yet).
|
|
21
|
+
|
|
22
|
+
import { dlog } from '@symbiote-native/engine';
|
|
23
|
+
import type { IRoute } from '../navigator-state';
|
|
24
|
+
import { isRecord } from '../guards';
|
|
25
|
+
|
|
26
|
+
export type IScreenLinkingConfig =
|
|
27
|
+
| string
|
|
28
|
+
| {
|
|
29
|
+
path?: string;
|
|
30
|
+
screens?: Record<string, IScreenLinkingConfig>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type ILinkingConfig = {
|
|
34
|
+
prefixes: string[];
|
|
35
|
+
config: {
|
|
36
|
+
screens: Record<string, IScreenLinkingConfig>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type IFlatRoutePattern = {
|
|
41
|
+
name: string;
|
|
42
|
+
pattern: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Strips leading/trailing slashes so segments join predictably regardless of how the caller
|
|
46
|
+
// wrote a path ('feed/:sort', '/feed/:sort/', etc).
|
|
47
|
+
function normalizeSegment(segment: string): string {
|
|
48
|
+
return segment.replace(/^\/+|\/+$/g, '');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function joinPath(parent: string, child: string): string {
|
|
52
|
+
const parts = [normalizeSegment(parent), normalizeSegment(child)].filter(part => part.length > 0);
|
|
53
|
+
return parts.join('/');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Walks `screens` recursively, accumulating the path down to each LEAF screen. Unlike
|
|
57
|
+
// react-navigation (which resolves nested config into nested navigation state), our navigator is
|
|
58
|
+
// a single flat Stack - a `screens` group with no `path` of its own is transparent (consumes no
|
|
59
|
+
// URL segment); a group WITH a `path` but no nested `screens` is itself a leaf using that path.
|
|
60
|
+
function flattenScreens(
|
|
61
|
+
screens: Record<string, IScreenLinkingConfig>,
|
|
62
|
+
parentPath: string,
|
|
63
|
+
out: IFlatRoutePattern[],
|
|
64
|
+
): IFlatRoutePattern[] {
|
|
65
|
+
for (const [name, entry] of Object.entries(screens)) {
|
|
66
|
+
if (typeof entry === 'string') {
|
|
67
|
+
out.push({ name, pattern: joinPath(parentPath, entry) });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const nextParent = entry.path !== undefined ? joinPath(parentPath, entry.path) : parentPath;
|
|
72
|
+
|
|
73
|
+
if (entry.screens !== undefined) {
|
|
74
|
+
flattenScreens(entry.screens, nextParent, out);
|
|
75
|
+
} else if (entry.path !== undefined) {
|
|
76
|
+
out.push({ name, pattern: nextParent });
|
|
77
|
+
} else {
|
|
78
|
+
dlog(`linking-config: screen "${name}" has neither a path nor nested screens, skipping`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function dynamicSegmentCount(pattern: string): number {
|
|
85
|
+
if (pattern.length === 0) return 0;
|
|
86
|
+
return pattern.split('/').filter(segment => segment.startsWith(':')).length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function segmentCount(pattern: string): number {
|
|
90
|
+
return pattern.length === 0 ? 0 : pattern.split('/').length;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// More static segments should win over a param that would also match (e.g. a literal
|
|
94
|
+
// '/user/me' pattern over '/user/:id'), mirroring how react-navigation prefers exact matches.
|
|
95
|
+
function bySpecificity(a: IFlatRoutePattern, b: IFlatRoutePattern): number {
|
|
96
|
+
const dynamicDiff = dynamicSegmentCount(a.pattern) - dynamicSegmentCount(b.pattern);
|
|
97
|
+
if (dynamicDiff !== 0) return dynamicDiff;
|
|
98
|
+
return segmentCount(b.pattern) - segmentCount(a.pattern);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function matchPattern(pattern: string, pathname: string): Record<string, string> | null {
|
|
102
|
+
const patternSegments = pattern.length === 0 ? [] : pattern.split('/');
|
|
103
|
+
const pathSegments = pathname.length === 0 ? [] : pathname.split('/');
|
|
104
|
+
if (patternSegments.length !== pathSegments.length) return null;
|
|
105
|
+
|
|
106
|
+
const params: Record<string, string> = {};
|
|
107
|
+
for (let index = 0; index < patternSegments.length; index += 1) {
|
|
108
|
+
const patternSegment = patternSegments[index];
|
|
109
|
+
const pathSegment = pathSegments[index];
|
|
110
|
+
if (patternSegment.startsWith(':')) {
|
|
111
|
+
params[patternSegment.slice(1)] = decodeURIComponent(pathSegment);
|
|
112
|
+
} else if (patternSegment !== pathSegment) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return params;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function stripQueryAndHash(url: string): string {
|
|
120
|
+
const match = /[?#]/.exec(url);
|
|
121
|
+
return match === null ? url : url.slice(0, match.index);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Resolves a full URL down to the bare path segment string ('user/42', no leading slash) by
|
|
125
|
+
// stripping the longest matching configured prefix, falling back to treating the URL as an
|
|
126
|
+
// already-bare path when it starts with '/' (the task's second example form). Returns null when
|
|
127
|
+
// neither applies - an unrecognized scheme/host, not "no route matched".
|
|
128
|
+
function extractPathname(config: ILinkingConfig, url: string): string | null {
|
|
129
|
+
const withoutQuery = stripQueryAndHash(url);
|
|
130
|
+
const sortedPrefixes = [...config.prefixes].sort((a, b) => b.length - a.length);
|
|
131
|
+
for (const prefix of sortedPrefixes) {
|
|
132
|
+
if (withoutQuery.startsWith(prefix)) {
|
|
133
|
+
return normalizeSegment(withoutQuery.slice(prefix.length));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (withoutQuery.startsWith('/')) return normalizeSegment(withoutQuery);
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function resolveRouteFromUrl(config: ILinkingConfig, url: string): IRoute<unknown> | null {
|
|
141
|
+
const pathname = extractPathname(config, url);
|
|
142
|
+
if (pathname === null) {
|
|
143
|
+
dlog(`linking-config: url "${url}" matched no configured prefix`);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const candidates = flattenScreens(config.config.screens, '', []).sort(bySpecificity);
|
|
148
|
+
for (const candidate of candidates) {
|
|
149
|
+
const params = matchPattern(candidate.pattern, pathname);
|
|
150
|
+
if (params !== null) {
|
|
151
|
+
dlog(`linking-config: resolved "${url}" -> ${candidate.name}`);
|
|
152
|
+
// `key` is not real route identity here - the navigator mints its own on push/replace
|
|
153
|
+
// (stack.ts's createRoute); `name` is a stable enough placeholder to satisfy IRoute's shape.
|
|
154
|
+
return {
|
|
155
|
+
key: candidate.name,
|
|
156
|
+
name: candidate.name,
|
|
157
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
dlog(`linking-config: url "${url}" (path "${pathname}") matched no configured screen`);
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// The inverse of matchPattern: fills a pattern's ':param' segments from `params`, or returns
|
|
167
|
+
// null when a required param is missing (mirrors react-router's generatePath throwing, minus the
|
|
168
|
+
// throw - a resolver returning null reads more naturally at the call site here).
|
|
169
|
+
function fillPattern(pattern: string, params: unknown): string | null {
|
|
170
|
+
if (pattern.length === 0) return '';
|
|
171
|
+
const source = isRecord(params) ? params : {};
|
|
172
|
+
const segments: string[] = [];
|
|
173
|
+
for (const segment of pattern.split('/')) {
|
|
174
|
+
if (!segment.startsWith(':')) {
|
|
175
|
+
segments.push(segment);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const value = source[segment.slice(1)];
|
|
179
|
+
if (value === undefined || value === null) return null;
|
|
180
|
+
segments.push(encodeURIComponent(String(value)));
|
|
181
|
+
}
|
|
182
|
+
return segments.join('/');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function resolveUrlFromRoute(config: ILinkingConfig, route: IRoute<unknown>): string | null {
|
|
186
|
+
const candidate = flattenScreens(config.config.screens, '', []).find(
|
|
187
|
+
entry => entry.name === route.name,
|
|
188
|
+
);
|
|
189
|
+
if (candidate === undefined) {
|
|
190
|
+
dlog(`linking-config: no configured screen for route name "${route.name}"`);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const path = fillPattern(candidate.pattern, route.params);
|
|
195
|
+
if (path === null) {
|
|
196
|
+
dlog(
|
|
197
|
+
`linking-config: route "${route.name}" is missing a param required by "${candidate.pattern}"`,
|
|
198
|
+
);
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const prefix = config.prefixes[0];
|
|
203
|
+
if (prefix === undefined) return path.length > 0 ? `/${path}` : '/';
|
|
204
|
+
|
|
205
|
+
// A prefix already carrying its own trailing separator ('myapp://') must not be truncated to
|
|
206
|
+
// 'myapp:/' by naively slicing one char off - only add a '/' when the prefix doesn't have one.
|
|
207
|
+
if (path.length === 0) return prefix;
|
|
208
|
+
return prefix.endsWith('/') ? `${prefix}${path}` : `${prefix}/${path}`;
|
|
209
|
+
}
|