@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,550 @@
|
|
|
1
|
+
// Drawer, the Vue lifecycle half. The open/closed + focused-route router (drawer-router-state)
|
|
2
|
+
// and the pure swipe/geometry math (drawer-options) live in @symbiote-native/navigation core,
|
|
3
|
+
// shared verbatim with the React/Angular adapters; here Vue supplies the lifecycle - a plain ref
|
|
4
|
+
// for the router (Vue's twin of useReducer), a PanResponder for the swipe gesture (built ONCE in
|
|
5
|
+
// setup, its callbacks reading options/window-width/isOpen LIVE off Vue's own reactive `attrs` /
|
|
6
|
+
// composable refs at gesture time - Vue's reactivity already gives every gesture callback the
|
|
7
|
+
// CURRENT value with no ref-mirroring dance, unlike React's useRef(value); value = X every
|
|
8
|
+
// render), an Animated.Value driving the slide/opacity transforms, and expose() for the
|
|
9
|
+
// open/close/toggle/jumpTo handle - mirroring tabs.ts's shape (Tab is the closer sibling: both are
|
|
10
|
+
// fixed-route-list, no-react-native-screens navigators; Stack's push/pop + native-screen bridging
|
|
11
|
+
// don't apply here).
|
|
12
|
+
//
|
|
13
|
+
// FEASIBILITY NOTE (see the drawer skill / PR description for the full writeup, mirrored from
|
|
14
|
+
// react/drawer.ts): the REAL @react-navigation/drawer is built on react-native-gesture-handler +
|
|
15
|
+
// react-native-reanimated, neither of which this codebase depends on. What's built here reaches
|
|
16
|
+
// the same swipe-to-open/close + front/back/slide/permanent behavior using only PanResponder +
|
|
17
|
+
// Animated (both already in @symbiote-native/engine), which is sufficient for a solid drawer but
|
|
18
|
+
// NOT byte-for-byte parity - see the explicit gap list at the bottom of this file (verbatim from
|
|
19
|
+
// the React twin - the gaps are architectural, not adapter-specific).
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
defineComponent,
|
|
23
|
+
h,
|
|
24
|
+
nextTick,
|
|
25
|
+
onMounted,
|
|
26
|
+
onUnmounted,
|
|
27
|
+
shallowRef,
|
|
28
|
+
useId,
|
|
29
|
+
watch,
|
|
30
|
+
} from '@vue/runtime-core';
|
|
31
|
+
import type { VNode } from '@vue/runtime-core';
|
|
32
|
+
import {
|
|
33
|
+
Animated,
|
|
34
|
+
PanResponder,
|
|
35
|
+
normalizeVueAttrs,
|
|
36
|
+
useWindowDimensions,
|
|
37
|
+
} from '@symbiote-native/vue';
|
|
38
|
+
import type { IPanResponderGestureState, ISymbioteEvent } from '@symbiote-native/vue';
|
|
39
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
40
|
+
import { dlog } from '@symbiote-native/engine';
|
|
41
|
+
import type { IStyleProp, IViewStyle } from '@symbiote-native/engine';
|
|
42
|
+
import {
|
|
43
|
+
DRAWER_DEFAULT_OVERLAY_COLOR,
|
|
44
|
+
NAVIGATION_EVENT_BLUR,
|
|
45
|
+
NAVIGATION_EVENT_FOCUS,
|
|
46
|
+
createInitialDrawerRouterState,
|
|
47
|
+
createNavigationEmitter,
|
|
48
|
+
diffFocusedRoute,
|
|
49
|
+
drawerChildOrder,
|
|
50
|
+
drawerRouterReducer,
|
|
51
|
+
isDrawerAnimated,
|
|
52
|
+
isRecord,
|
|
53
|
+
renderDrawer,
|
|
54
|
+
resolveDragProgress,
|
|
55
|
+
resolveDrawerGeometry,
|
|
56
|
+
resolveDrawerSlotInterpolation,
|
|
57
|
+
resolveSwipeIntent,
|
|
58
|
+
shouldClaimDrawerSwipe,
|
|
59
|
+
} from '../../core';
|
|
60
|
+
import type {
|
|
61
|
+
IDrawerDescriptorMap,
|
|
62
|
+
IDrawerNavigatorHandle,
|
|
63
|
+
IDrawerOptions,
|
|
64
|
+
IDrawerPosition,
|
|
65
|
+
IDrawerRouterState,
|
|
66
|
+
IDrawerScreenOptions,
|
|
67
|
+
IDrawerSlot,
|
|
68
|
+
IDrawerType,
|
|
69
|
+
INavigationEmitter,
|
|
70
|
+
IRoute,
|
|
71
|
+
} from '../../core';
|
|
72
|
+
import { NavigationScope, injectNavigationScope } from '../navigation-context';
|
|
73
|
+
import { DrawerScreen } from '../drawer-screen';
|
|
74
|
+
import type { IDrawerScreenOptionsArgs, IDrawerScreenProps } from '../drawer-screen';
|
|
75
|
+
|
|
76
|
+
export type { IDrawerNavigatorHandle, IDrawerDescriptorMap } from '../../core';
|
|
77
|
+
|
|
78
|
+
// React's `renderDrawerContent` render-PROP becomes a scoped SLOT here, mirroring Pressable's own
|
|
79
|
+
// `slots.default(state)` scoped-slot precedent in this codebase.
|
|
80
|
+
|
|
81
|
+
export type IDrawerContentSlotProps = {
|
|
82
|
+
state: IDrawerRouterState;
|
|
83
|
+
descriptors: IDrawerDescriptorMap;
|
|
84
|
+
navigation: IDrawerNavigatorHandle;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// React's `children?: ReactNode` becomes Vue's default slot instead (registered screens, read via
|
|
88
|
+
// collectRegistry below); `renderDrawerContent` becomes the `drawerContent` scoped slot above.
|
|
89
|
+
export type IDrawerProps = IDrawerOptions & {
|
|
90
|
+
initialRouteName?: string;
|
|
91
|
+
drawerStyle?: IStyleProp<IViewStyle>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type IDrawerRegistryEntry = {
|
|
95
|
+
component: IDrawerScreenProps['component'];
|
|
96
|
+
options: IDrawerScreenProps['options'];
|
|
97
|
+
initialParams: unknown;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
function asString(value: unknown): string | undefined {
|
|
101
|
+
return typeof value === 'string' ? value : undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function asNumber(value: unknown): number | undefined {
|
|
105
|
+
return typeof value === 'number' ? value : undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function asBoolean(value: unknown): boolean | undefined {
|
|
109
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isStyleProp(value: unknown): value is IStyleProp<IViewStyle> {
|
|
113
|
+
return isRecord(value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const DRAWER_TYPES: ReadonlyArray<IDrawerType> = ['front', 'back', 'slide', 'permanent'];
|
|
117
|
+
// .some() itself doesn't narrow `value`'s type back at the call site - the `value is IDrawerType`
|
|
118
|
+
// predicate on THIS function is what lets asDrawerType's ternary return `value` typed, mirroring
|
|
119
|
+
// Modal's isOrientation guard (adapters/vue/src/components/modal.ts).
|
|
120
|
+
function isDrawerType(value: unknown): value is IDrawerType {
|
|
121
|
+
return typeof value === 'string' && DRAWER_TYPES.some(type => type === value);
|
|
122
|
+
}
|
|
123
|
+
function asDrawerType(value: unknown): IDrawerType | undefined {
|
|
124
|
+
return isDrawerType(value) ? value : undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const DRAWER_POSITIONS: ReadonlyArray<IDrawerPosition> = ['left', 'right'];
|
|
128
|
+
function isDrawerPosition(value: unknown): value is IDrawerPosition {
|
|
129
|
+
return typeof value === 'string' && DRAWER_POSITIONS.some(position => position === value);
|
|
130
|
+
}
|
|
131
|
+
function asDrawerPosition(value: unknown): IDrawerPosition | undefined {
|
|
132
|
+
return isDrawerPosition(value) ? value : undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function asComponent(value: unknown): IDrawerScreenProps['component'] | undefined {
|
|
136
|
+
if (typeof value === 'function') return value as IDrawerScreenProps['component'];
|
|
137
|
+
return isRecord(value) ? (value as IDrawerScreenProps['component']) : undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// IDrawerScreenOptions carries only `title`/`drawerLabel`, small enough for direct field guards -
|
|
141
|
+
// kept as a single cast-at-the-edge helper anyway for symmetry with stack.ts/tabs.ts's
|
|
142
|
+
// asScreenOptions/asTabOptions (same CLAUDE.md-sanctioned I/O-edge narrowing).
|
|
143
|
+
function asDrawerScreenOptions(value: unknown): IDrawerScreenOptions | undefined {
|
|
144
|
+
return isRecord(value) ? (value as IDrawerScreenOptions) : undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function asDrawerScreenOptionsOrResolver(value: unknown): IDrawerScreenProps['options'] {
|
|
148
|
+
if (typeof value === 'function') return value as IDrawerScreenProps['options'];
|
|
149
|
+
return asDrawerScreenOptions(value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function collectRegistry(vnodes: readonly VNode[]): Map<string, IDrawerRegistryEntry> {
|
|
153
|
+
const registry = new Map<string, IDrawerRegistryEntry>();
|
|
154
|
+
for (const vnode of vnodes) {
|
|
155
|
+
if (vnode.type !== DrawerScreen || !isRecord(vnode.props)) continue;
|
|
156
|
+
const name = asString(vnode.props.name);
|
|
157
|
+
const component = asComponent(vnode.props.component);
|
|
158
|
+
if (name === undefined || component === undefined) continue;
|
|
159
|
+
registry.set(name, {
|
|
160
|
+
component,
|
|
161
|
+
options: asDrawerScreenOptionsOrResolver(vnode.props.options),
|
|
162
|
+
initialParams: vnode.props.initialParams,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return registry;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function resolveDrawerScreenOptions(
|
|
169
|
+
entry: IDrawerRegistryEntry,
|
|
170
|
+
screenComponentProps: IDrawerScreenOptionsArgs,
|
|
171
|
+
): IDrawerScreenOptions {
|
|
172
|
+
if (typeof entry.options === 'function') return entry.options(screenComponentProps);
|
|
173
|
+
return entry.options ?? {};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const DRAWER_SNAP_DURATION = 250;
|
|
177
|
+
|
|
178
|
+
const DrawerImpl = defineComponent<IDrawerProps>(
|
|
179
|
+
(_props, { attrs: rawAttrs, slots, expose }) => {
|
|
180
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
181
|
+
|
|
182
|
+
// Read BEFORE this Drawer establishes its own per-screen NavigationScope below - becomes the
|
|
183
|
+
// `parent` link a nested screen's useNavigation().getParent() walks. undefined when this
|
|
184
|
+
// Drawer is the nesting root.
|
|
185
|
+
const ambientScopeRef = injectNavigationScope();
|
|
186
|
+
|
|
187
|
+
function currentOptions(): IDrawerOptions {
|
|
188
|
+
return {
|
|
189
|
+
drawerType: asDrawerType(attrs.drawerType),
|
|
190
|
+
drawerPosition: asDrawerPosition(attrs.drawerPosition),
|
|
191
|
+
drawerWidth: asNumber(attrs.drawerWidth),
|
|
192
|
+
overlayColor: asString(attrs.overlayColor),
|
|
193
|
+
swipeEnabled: asBoolean(attrs.swipeEnabled),
|
|
194
|
+
swipeEdgeWidth: asNumber(attrs.swipeEdgeWidth),
|
|
195
|
+
swipeMinDistance: asNumber(attrs.swipeMinDistance),
|
|
196
|
+
swipeMinVelocity: asNumber(attrs.swipeMinVelocity),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let routeSequence = 0;
|
|
201
|
+
const routeIdPrefix = useId();
|
|
202
|
+
|
|
203
|
+
function buildRoutes(registry: Map<string, IDrawerRegistryEntry>): IRoute<unknown>[] {
|
|
204
|
+
return Array.from(registry.entries()).map(([name, entry]) => {
|
|
205
|
+
routeSequence += 1;
|
|
206
|
+
return {
|
|
207
|
+
key: `${routeIdPrefix}-${name}-${routeSequence}`,
|
|
208
|
+
name,
|
|
209
|
+
params: entry.initialParams,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const initialRegistry = collectRegistry(slots.default?.() ?? []);
|
|
215
|
+
const initialRoutes = buildRoutes(initialRegistry);
|
|
216
|
+
if (initialRoutes.length === 0) dlog('Drawer: no <Drawer.Screen> children registered');
|
|
217
|
+
|
|
218
|
+
const state = shallowRef(
|
|
219
|
+
createInitialDrawerRouterState(initialRoutes, asString(attrs.initialRouteName)),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
function dispatch(action: Parameters<typeof drawerRouterReducer>[1]): void {
|
|
223
|
+
state.value = drawerRouterReducer(state.value, action);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const windowDimensions = useWindowDimensions();
|
|
227
|
+
|
|
228
|
+
// progress: 0 closed -> 1 open, the single Animated.Value every slide/opacity transform below
|
|
229
|
+
// interpolates from. A plain `const` (not a ref): setup() runs once, so this needs no
|
|
230
|
+
// re-creation guard the way React's useRef(new Animated.Value(...)).current does.
|
|
231
|
+
const progress = new Animated.Value(state.value.isOpen ? 1 : 0);
|
|
232
|
+
// Where a drag STARTS from, in progress units. Always exactly 0 or 1: a gesture only ever
|
|
233
|
+
// begins at rest, since terminate/release always snap the value back to a resting state
|
|
234
|
+
// before another grant can fire.
|
|
235
|
+
let dragStartProgress = 0;
|
|
236
|
+
|
|
237
|
+
function animateProgressTo(open: boolean): void {
|
|
238
|
+
dlog(`Drawer: animateProgressTo(open=${open}) starting at t=${Date.now()}`);
|
|
239
|
+
Animated.timing(progress, {
|
|
240
|
+
toValue: open ? 1 : 0,
|
|
241
|
+
duration: DRAWER_SNAP_DURATION,
|
|
242
|
+
// Native-driver wiring is deferred for v1 - see this file's header feasibility note. The
|
|
243
|
+
// JS timing loop still drives every frame, same as any other non-native-driven
|
|
244
|
+
// Animated.timing in this codebase.
|
|
245
|
+
useNativeDriver: false,
|
|
246
|
+
}).start();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const handle: IDrawerNavigatorHandle = {
|
|
250
|
+
openDrawer: () => {
|
|
251
|
+
dlog(`Drawer: openDrawer() called, isOpen=${state.value.isOpen} at t=${Date.now()}`);
|
|
252
|
+
animateProgressTo(true);
|
|
253
|
+
dispatch({ type: 'openDrawer' });
|
|
254
|
+
},
|
|
255
|
+
closeDrawer: () => {
|
|
256
|
+
dlog(`Drawer: closeDrawer() called, isOpen=${state.value.isOpen} at t=${Date.now()}`);
|
|
257
|
+
animateProgressTo(false);
|
|
258
|
+
dispatch({ type: 'closeDrawer' });
|
|
259
|
+
},
|
|
260
|
+
toggleDrawer: () => {
|
|
261
|
+
dlog(`Drawer: toggleDrawer() called, isOpen=${state.value.isOpen} at t=${Date.now()}`);
|
|
262
|
+
animateProgressTo(!state.value.isOpen);
|
|
263
|
+
dispatch({ type: 'toggleDrawer' });
|
|
264
|
+
},
|
|
265
|
+
jumpTo: (name: string) => {
|
|
266
|
+
// Captured BEFORE dispatch: unlike React's isOpenRef (only refreshed at the TOP of the
|
|
267
|
+
// next render, so it still holds the pre-dispatch value here since React batches the
|
|
268
|
+
// re-render asynchronously), this ref's `.value` mutates SYNCHRONOUSLY inside dispatch -
|
|
269
|
+
// reading it after dispatch would already see the reducer's own isOpen: false.
|
|
270
|
+
const wasOpen = state.value.isOpen;
|
|
271
|
+
dispatch({ type: 'jumpTo', name });
|
|
272
|
+
if (wasOpen) animateProgressTo(false);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
expose(handle);
|
|
276
|
+
|
|
277
|
+
const panResponder = PanResponder.create({
|
|
278
|
+
onStartShouldSetPanResponder: (
|
|
279
|
+
event: ISymbioteEvent,
|
|
280
|
+
gestureState: IPanResponderGestureState,
|
|
281
|
+
): boolean =>
|
|
282
|
+
shouldClaimDrawerSwipe(
|
|
283
|
+
event,
|
|
284
|
+
gestureState,
|
|
285
|
+
windowDimensions.value.width,
|
|
286
|
+
state.value.isOpen,
|
|
287
|
+
currentOptions(),
|
|
288
|
+
'start',
|
|
289
|
+
),
|
|
290
|
+
onMoveShouldSetPanResponder: (
|
|
291
|
+
event: ISymbioteEvent,
|
|
292
|
+
gestureState: IPanResponderGestureState,
|
|
293
|
+
): boolean =>
|
|
294
|
+
shouldClaimDrawerSwipe(
|
|
295
|
+
event,
|
|
296
|
+
gestureState,
|
|
297
|
+
windowDimensions.value.width,
|
|
298
|
+
state.value.isOpen,
|
|
299
|
+
currentOptions(),
|
|
300
|
+
'move',
|
|
301
|
+
),
|
|
302
|
+
onPanResponderGrant: (): void => {
|
|
303
|
+
dlog('Drawer: gesture grant');
|
|
304
|
+
dragStartProgress = state.value.isOpen ? 1 : 0;
|
|
305
|
+
},
|
|
306
|
+
onPanResponderMove: (
|
|
307
|
+
_event: ISymbioteEvent,
|
|
308
|
+
gestureState: IPanResponderGestureState,
|
|
309
|
+
): void => {
|
|
310
|
+
progress.setValue(resolveDragProgress(gestureState, dragStartProgress, currentOptions()));
|
|
311
|
+
},
|
|
312
|
+
onPanResponderRelease: (
|
|
313
|
+
_event: ISymbioteEvent,
|
|
314
|
+
gestureState: IPanResponderGestureState,
|
|
315
|
+
): void => {
|
|
316
|
+
const intent = resolveSwipeIntent(gestureState, state.value.isOpen, currentOptions());
|
|
317
|
+
const open = intent === 'open';
|
|
318
|
+
dlog(`Drawer: gesture release -> ${open ? 'open' : 'close'}`);
|
|
319
|
+
animateProgressTo(open);
|
|
320
|
+
dispatch(open ? { type: 'openDrawer' } : { type: 'closeDrawer' });
|
|
321
|
+
},
|
|
322
|
+
onPanResponderTerminate: (): void => {
|
|
323
|
+
dlog('Drawer: gesture terminated, snapping back');
|
|
324
|
+
animateProgressTo(state.value.isOpen);
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Only the focused route's screen is ever mounted (like Tab, unlike Stack which keeps every
|
|
329
|
+
// pushed route alive). One emitter per route.key, created lazily and cached for the
|
|
330
|
+
// navigator's whole lifetime (mirrors stack.ts's own `emitters` map) - see tabs.ts's matching
|
|
331
|
+
// comment for why a stable per-key lookup, not a recreate-on-change scheme, is what actually
|
|
332
|
+
// avoids racing Vue's own render/mount cycle regardless of which watch `flush` timing is used.
|
|
333
|
+
function focusedKeyOf(current: IDrawerRouterState): string | undefined {
|
|
334
|
+
return current.routes[current.index]?.key;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const emitters = new Map<string, INavigationEmitter>();
|
|
338
|
+
function emitterFor(routeKey: string): INavigationEmitter {
|
|
339
|
+
let emitter = emitters.get(routeKey);
|
|
340
|
+
if (emitter === undefined) {
|
|
341
|
+
emitter = createNavigationEmitter();
|
|
342
|
+
emitters.set(routeKey, emitter);
|
|
343
|
+
}
|
|
344
|
+
return emitter;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Emitted from onMounted (NOT from inside the render closure below, which runs before the
|
|
348
|
+
// focused screen's own component ever mounts - an emit there always has zero subscribers).
|
|
349
|
+
let focusedRouteKey = focusedKeyOf(state.value);
|
|
350
|
+
|
|
351
|
+
onMounted(() => {
|
|
352
|
+
if (focusedRouteKey !== undefined) {
|
|
353
|
+
dlog(`Drawer: route "${focusedRouteKey}" focused at t=${Date.now()}`);
|
|
354
|
+
emitterFor(focusedRouteKey).emit(NAVIGATION_EVENT_FOCUS);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// The bookkeeping (which key is focused) updates immediately so the render closure below
|
|
359
|
+
// always reads the right route; the actual emit is deferred to nextTick(), which resolves
|
|
360
|
+
// only after the CURRENT flush cycle fully drains - including the newly-focused screen's own
|
|
361
|
+
// onMounted (subscribing its useIsFocused/useFocusEffect listeners). flush:'post' alone is
|
|
362
|
+
// NOT enough here: it only guarantees this callback runs after THIS component's own render
|
|
363
|
+
// effect, not after an arbitrary sibling post-flush job (a just-mounted child's onMounted)
|
|
364
|
+
// that may be queued after it in the same batch - nextTick is the one API that waits for the
|
|
365
|
+
// WHOLE cycle, not just this watcher's own slot in it.
|
|
366
|
+
watch(
|
|
367
|
+
() => focusedKeyOf(state.value),
|
|
368
|
+
nextKey => {
|
|
369
|
+
const { blurKey, focusKey } = diffFocusedRoute(focusedRouteKey, nextKey);
|
|
370
|
+
if (blurKey === undefined && focusKey === undefined) return;
|
|
371
|
+
focusedRouteKey = nextKey;
|
|
372
|
+
nextTick(() => {
|
|
373
|
+
if (blurKey !== undefined) {
|
|
374
|
+
dlog(`Drawer: route "${blurKey}" blurred at t=${Date.now()}`);
|
|
375
|
+
emitterFor(blurKey).emit(NAVIGATION_EVENT_BLUR);
|
|
376
|
+
}
|
|
377
|
+
if (focusKey !== undefined) {
|
|
378
|
+
dlog(`Drawer: route "${focusKey}" focused at t=${Date.now()}`);
|
|
379
|
+
emitterFor(focusKey).emit(NAVIGATION_EVENT_FOCUS);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
);
|
|
384
|
+
onUnmounted(() => {
|
|
385
|
+
if (focusedRouteKey !== undefined) emitterFor(focusedRouteKey).emit(NAVIGATION_EVENT_BLUR);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
return () => {
|
|
389
|
+
const registry = collectRegistry(slots.default?.() ?? []);
|
|
390
|
+
const options = currentOptions();
|
|
391
|
+
const drawerStyle = isStyleProp(attrs.drawerStyle) ? attrs.drawerStyle : undefined;
|
|
392
|
+
|
|
393
|
+
if (registry.size === 0) dlog('Drawer: no <Drawer.Screen> children registered');
|
|
394
|
+
|
|
395
|
+
const animated = isDrawerAnimated(options);
|
|
396
|
+
const geometry = resolveDrawerGeometry(options);
|
|
397
|
+
|
|
398
|
+
const panelTranslateX = animated
|
|
399
|
+
? progress.interpolate(resolveDrawerSlotInterpolation(geometry, 'panel').translateX)
|
|
400
|
+
: undefined;
|
|
401
|
+
const contentTranslateX = animated
|
|
402
|
+
? progress.interpolate(resolveDrawerSlotInterpolation(geometry, 'content').translateX)
|
|
403
|
+
: undefined;
|
|
404
|
+
// The overlay is a full-screen absolutely-positioned sibling BELOW content in paint order
|
|
405
|
+
// (see render-drawer.ts's drawerChildOrder) - for 'front' that's fine since content never
|
|
406
|
+
// moves, but for 'slide' content itself translates away by contentTranslateX, and without
|
|
407
|
+
// following it the overlay stays pinned full-screen. resolveDrawerSlotInterpolation's
|
|
408
|
+
// 'overlay' branch ties its translateX to the SAME range as content's for exactly this
|
|
409
|
+
// reason, so overlayOpacity and overlayTranslateX below share one resolved config.
|
|
410
|
+
const overlayInterpolation = animated
|
|
411
|
+
? resolveDrawerSlotInterpolation(geometry, 'overlay')
|
|
412
|
+
: undefined;
|
|
413
|
+
const overlayOpacity = overlayInterpolation
|
|
414
|
+
? progress.interpolate(overlayInterpolation.opacity)
|
|
415
|
+
: undefined;
|
|
416
|
+
const overlayTranslateX = overlayInterpolation
|
|
417
|
+
? progress.interpolate(overlayInterpolation.translateX)
|
|
418
|
+
: undefined;
|
|
419
|
+
|
|
420
|
+
const focusedRoute = state.value.routes[state.value.index];
|
|
421
|
+
const focusedEntry = focusedRoute ? registry.get(focusedRoute.name) : undefined;
|
|
422
|
+
if (focusedRoute && !focusedEntry) {
|
|
423
|
+
dlog(`Drawer: no screen registered for route name "${focusedRoute.name}"`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const content =
|
|
427
|
+
focusedEntry && focusedRoute
|
|
428
|
+
? h(
|
|
429
|
+
NavigationScope,
|
|
430
|
+
{
|
|
431
|
+
value: {
|
|
432
|
+
route: focusedRoute,
|
|
433
|
+
navigation: handle,
|
|
434
|
+
emitter: emitterFor(focusedRoute.key),
|
|
435
|
+
parent: ambientScopeRef?.value,
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
// No route/navigation props: the screen reads both through composables off the
|
|
439
|
+
// NavigationScope provided just above (useRoute / useDrawerNavigation).
|
|
440
|
+
() => h(focusedEntry.component),
|
|
441
|
+
)
|
|
442
|
+
: null;
|
|
443
|
+
|
|
444
|
+
const descriptors: IDrawerDescriptorMap = {};
|
|
445
|
+
for (const route of state.value.routes) {
|
|
446
|
+
const entry = registry.get(route.name);
|
|
447
|
+
if (entry === undefined) continue;
|
|
448
|
+
descriptors[route.key] = {
|
|
449
|
+
options: resolveDrawerScreenOptions(entry, { route, navigation: handle }),
|
|
450
|
+
navigation: handle,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const drawerContent =
|
|
455
|
+
slots.drawerContent?.({ state: state.value, descriptors, navigation: handle }) ?? null;
|
|
456
|
+
|
|
457
|
+
const root = renderDrawer(
|
|
458
|
+
{
|
|
459
|
+
overlayColor: asString(attrs.overlayColor) ?? DRAWER_DEFAULT_OVERLAY_COLOR,
|
|
460
|
+
drawerStyle,
|
|
461
|
+
contentPassthrough: {},
|
|
462
|
+
overlayPassthrough: animated
|
|
463
|
+
? {
|
|
464
|
+
pointerEvents: state.value.isOpen ? 'auto' : 'none',
|
|
465
|
+
onStartShouldSetResponder: () => true,
|
|
466
|
+
onResponderRelease: () => {
|
|
467
|
+
animateProgressTo(false);
|
|
468
|
+
dispatch({ type: 'closeDrawer' });
|
|
469
|
+
},
|
|
470
|
+
}
|
|
471
|
+
: {},
|
|
472
|
+
panelPassthrough: {},
|
|
473
|
+
},
|
|
474
|
+
options,
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
const order = drawerChildOrder(options);
|
|
478
|
+
const slotDescriptors = new Map<IDrawerSlot, IDescriptor>();
|
|
479
|
+
order.forEach((slot, index) => {
|
|
480
|
+
const descriptor = root.children[index];
|
|
481
|
+
if (typeof descriptor !== 'string') slotDescriptors.set(slot, descriptor);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
const slotChildren: Record<IDrawerSlot, VNode[] | null> = {
|
|
485
|
+
content: content === null ? [] : [content],
|
|
486
|
+
overlay: null,
|
|
487
|
+
panel: drawerContent,
|
|
488
|
+
};
|
|
489
|
+
// Each animated style holds an AnimatedInterpolation node, not a plain number/color - it
|
|
490
|
+
// feeds only Animated.View's deliberately permissive `style?: unknown`, never the plain-
|
|
491
|
+
// IViewStyle branch below, so this stays untyped rather than widening IViewStyle.
|
|
492
|
+
const slotAnimatedStyle: Record<IDrawerSlot, unknown> = {
|
|
493
|
+
content:
|
|
494
|
+
contentTranslateX === undefined
|
|
495
|
+
? undefined
|
|
496
|
+
: { transform: [{ translateX: contentTranslateX }] },
|
|
497
|
+
overlay:
|
|
498
|
+
overlayOpacity === undefined
|
|
499
|
+
? undefined
|
|
500
|
+
: { opacity: overlayOpacity, transform: [{ translateX: overlayTranslateX }] },
|
|
501
|
+
panel:
|
|
502
|
+
panelTranslateX === undefined
|
|
503
|
+
? undefined
|
|
504
|
+
: { transform: [{ translateX: panelTranslateX }] },
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
function renderSlot(slot: IDrawerSlot): VNode | null {
|
|
508
|
+
const descriptor = slotDescriptors.get(slot);
|
|
509
|
+
if (descriptor === undefined) return null;
|
|
510
|
+
const children = slotChildren[slot] ?? [];
|
|
511
|
+
const animatedStyle = slotAnimatedStyle[slot];
|
|
512
|
+
if (animatedStyle === undefined) {
|
|
513
|
+
return h(descriptor.type, { key: descriptor.key, ...descriptor.props }, children);
|
|
514
|
+
}
|
|
515
|
+
const style = [descriptor.props.style, animatedStyle];
|
|
516
|
+
return h(Animated.View, { key: descriptor.key, ...descriptor.props, style }, children);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const drawerChildren = order
|
|
520
|
+
.map(renderSlot)
|
|
521
|
+
.filter((element): element is VNode => element !== null);
|
|
522
|
+
|
|
523
|
+
return h(
|
|
524
|
+
'symbiote-view',
|
|
525
|
+
{ style: root.props.style, ...panResponder.panHandlers },
|
|
526
|
+
drawerChildren,
|
|
527
|
+
);
|
|
528
|
+
};
|
|
529
|
+
},
|
|
530
|
+
{ name: 'Drawer', inheritAttrs: false },
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
export const Drawer = Object.assign(DrawerImpl, { Screen: DrawerScreen });
|
|
534
|
+
|
|
535
|
+
// --- Explicit gap list vs the real react-native-gesture-handler + react-native-reanimated
|
|
536
|
+
// @react-navigation/drawer (confirmed against its current docs, mirrored verbatim from the React
|
|
537
|
+
// twin - the gaps are architectural, not adapter-specific) ---
|
|
538
|
+
// 1. `configureGestureHandler` - a raw react-native-gesture-handler `Gesture` object escape
|
|
539
|
+
// hatch. No PanResponder equivalent exists; not ported.
|
|
540
|
+
// 2. Simultaneous/failure gesture RELATIONSHIPS (gesture-handler's declarative composition vs a
|
|
541
|
+
// nested ScrollView, another PanResponder, etc.) - PanResponder only offers negotiation via the
|
|
542
|
+
// should-set boolean gates used here (edge-start + dominant-axis), which is more prone to an
|
|
543
|
+
// accidental hijack of a nested horizontal ScrollView/Swiper than gesture-handler's system.
|
|
544
|
+
// 3. `useDrawerProgress` - a Reanimated SharedValue read on the UI thread. `progress` here is a
|
|
545
|
+
// JS-thread AnimatedValue; interpolating it for consumer-facing content animation works, but
|
|
546
|
+
// without native-driver wiring (gap noted above) it does not carry the same synchronous
|
|
547
|
+
// UI-thread guarantee under JS-thread load.
|
|
548
|
+
// 4. `hideStatusBarOnOpen` / `keyboardDismissMode` / `statusBarAnimation` / `overlayStyle` - not
|
|
549
|
+
// wired in this pass; straightforward additions once StatusBar/Keyboard module wiring is
|
|
550
|
+
// needed here (not a PanResponder/Animated limitation, just unscoped for v1).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Drawer.Screen: a declarative marker, never rendered on its own - Drawer reads its props via a
|
|
2
|
+
// default-slot scan (see drawer.ts's collectRegistry) to build the static name -> {component,
|
|
3
|
+
// options} registry, then mounts the FOCUSED route's component. The Vue twin of
|
|
4
|
+
// react/drawer-screen.ts's DrawerScreen, mirroring tab-screen.ts's slot-scanning marker (Tab is
|
|
5
|
+
// the closer sibling - both are fixed-route-list/no-push navigators) and screen.ts's; see
|
|
6
|
+
// CLAUDE.md <third_party_rn_packages_are_react_only> - this and Drawer import nothing from
|
|
7
|
+
// react-native.
|
|
8
|
+
|
|
9
|
+
import { defineComponent } from '@vue/runtime-core';
|
|
10
|
+
import type { Component } from '@vue/runtime-core';
|
|
11
|
+
import type { IDrawerScreenOptions, IRoute, IDrawerNavigatorHandle } from '../core';
|
|
12
|
+
|
|
13
|
+
export type IDrawerScreenOptionsArgs = {
|
|
14
|
+
route: IRoute<unknown>;
|
|
15
|
+
navigation: IDrawerNavigatorHandle;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type IDrawerScreenOptionsResolver = (
|
|
19
|
+
props: IDrawerScreenOptionsArgs,
|
|
20
|
+
) => IDrawerScreenOptions;
|
|
21
|
+
|
|
22
|
+
export type IDrawerScreenProps = {
|
|
23
|
+
name: string;
|
|
24
|
+
component: Component;
|
|
25
|
+
options?: IDrawerScreenOptions | IDrawerScreenOptionsResolver;
|
|
26
|
+
initialParams?: unknown;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const DrawerScreen = defineComponent<IDrawerScreenProps>(() => () => null, {
|
|
30
|
+
name: 'DrawerScreen',
|
|
31
|
+
inheritAttrs: false,
|
|
32
|
+
});
|
package/src/vue/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @symbiote-native/navigation/vue: the Vue native-stack navigator over react-native-screens'
|
|
2
|
+
// native view primitives. Importing this barrel first registers the native views' ViewConfigs
|
|
3
|
+
// (../register, a side-effect import of the three codegen specs - never react-native-screens' own
|
|
4
|
+
// React components), then exposes Stack (with Stack.Screen attached) and the navigator handle.
|
|
5
|
+
|
|
6
|
+
import '../register';
|
|
7
|
+
|
|
8
|
+
export { Stack } from './stack';
|
|
9
|
+
export type { INavigatorHandle, IStackProps } from './stack';
|
|
10
|
+
export { Screen } from './screen';
|
|
11
|
+
export type {
|
|
12
|
+
IScreenOptionsArgs,
|
|
13
|
+
IScreenOptionsResolver,
|
|
14
|
+
IScreenProps,
|
|
15
|
+
IVueScreenOptions,
|
|
16
|
+
IVueSearchBarOptions,
|
|
17
|
+
} from './screen';
|
|
18
|
+
export type { IScreenOptions, IStackAnimation, IStackPresentation } from '../core';
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
useNavigation,
|
|
22
|
+
useStackNavigation,
|
|
23
|
+
useTabNavigation,
|
|
24
|
+
useDrawerNavigation,
|
|
25
|
+
useRoute,
|
|
26
|
+
useIsFocused,
|
|
27
|
+
useFocusEffect,
|
|
28
|
+
useNavigationState,
|
|
29
|
+
} from './composables';
|
|
30
|
+
export type {
|
|
31
|
+
INavigationHandle,
|
|
32
|
+
IStackNavigationHandle,
|
|
33
|
+
ITabNavigationHandle,
|
|
34
|
+
IDrawerNavigationHandle,
|
|
35
|
+
} from './composables';
|
|
36
|
+
export type { INavigationScopeValue, IAnyNavigatorHandle } from './navigation-context';
|
|
37
|
+
|
|
38
|
+
export { useLinkingIntegration } from './linking';
|
|
39
|
+
export type { ILinkingConfig, IScreenLinkingConfig } from '../core';
|
|
40
|
+
|
|
41
|
+
// Tab: the bottom-tabs navigator, a PURE-JS UI (no react-native-screens views involved, so no
|
|
42
|
+
// extra ViewConfig registration is needed beyond the ../register import above).
|
|
43
|
+
export { Tab } from './tabs';
|
|
44
|
+
export type { ITabNavigatorHandle, ITabProps } from './tabs';
|
|
45
|
+
export { TabScreen } from './tab-screen';
|
|
46
|
+
export type {
|
|
47
|
+
ITabScreenOptionsArgs,
|
|
48
|
+
ITabScreenOptionsResolver,
|
|
49
|
+
ITabScreenProps,
|
|
50
|
+
} from './tab-screen';
|
|
51
|
+
export type { ITabOptions, ITabBarIcon } from '../core';
|
|
52
|
+
|
|
53
|
+
// Drawer: the swipeable drawer navigator, a PURE-JS UI (PanResponder + Animated, no
|
|
54
|
+
// react-native-screens views involved, so no extra ViewConfig registration is needed beyond the
|
|
55
|
+
// ../register import above). See drawer.ts's header for the feasibility note re:
|
|
56
|
+
// react-native-gesture-handler / react-native-reanimated parity gaps.
|
|
57
|
+
export { Drawer } from './drawer';
|
|
58
|
+
export type {
|
|
59
|
+
IDrawerContentSlotProps,
|
|
60
|
+
IDrawerNavigatorHandle,
|
|
61
|
+
IDrawerProps,
|
|
62
|
+
IDrawerDescriptorMap,
|
|
63
|
+
} from './drawer';
|
|
64
|
+
export { DrawerScreen } from './drawer-screen';
|
|
65
|
+
export type {
|
|
66
|
+
IDrawerScreenOptionsArgs,
|
|
67
|
+
IDrawerScreenOptionsResolver,
|
|
68
|
+
IDrawerScreenProps,
|
|
69
|
+
} from './drawer-screen';
|
|
70
|
+
export type { IDrawerOptions, IDrawerScreenOptions, IDrawerType, IDrawerPosition } from '../core';
|