@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,181 @@
|
|
|
1
|
+
// Pure folds from a route's agnostic IScreenOptions into the native view-props shapes
|
|
2
|
+
// (RNSScreen + RNSScreenStackHeaderConfig + RNSSearchBar paint from). Framework-agnostic and
|
|
3
|
+
// shared verbatim by every adapter - the adapter's own job is only wiring identity (screenId),
|
|
4
|
+
// position (activityState via computeActivityState) and the lifecycle event handlers into
|
|
5
|
+
// `passthrough`.
|
|
6
|
+
//
|
|
7
|
+
// The header bar-button payload+dispatch cluster (id-tagging, onPress lookup) lives in
|
|
8
|
+
// header-bar-buttons.ts - self-contained, consumed here only as a black box by
|
|
9
|
+
// resolveHeaderConfigView.
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
IHeaderConfigViewProps,
|
|
13
|
+
INavigatorPlatform,
|
|
14
|
+
IOptionalBooleanNativeProp,
|
|
15
|
+
IScreenOptions,
|
|
16
|
+
IScreenViewProps,
|
|
17
|
+
ISearchBarOptions,
|
|
18
|
+
ISearchBarViewProps,
|
|
19
|
+
ISheetAllowedDetents,
|
|
20
|
+
ISheetInitialDetent,
|
|
21
|
+
ISheetLargestUndimmedDetent,
|
|
22
|
+
} from './navigator-props';
|
|
23
|
+
import { buildHeaderBarButtonDispatch, prepareHeaderBarButtonItems } from './header-bar-buttons';
|
|
24
|
+
|
|
25
|
+
// These sentinels must be kept in sync with react-native-screens' native side - they are RNS's
|
|
26
|
+
// own compat values for the 'fitToContents'/'large'/'medium'/'all' legacy presets, replicated
|
|
27
|
+
// here because we drive RNSScreen directly (no react-native-screens JS component in the path).
|
|
28
|
+
const SHEET_FIT_TO_CONTENTS: number[] = [-1];
|
|
29
|
+
const SHEET_COMPAT_LARGE: number[] = [1.0];
|
|
30
|
+
const SHEET_COMPAT_MEDIUM: number[] = [0.5];
|
|
31
|
+
const SHEET_COMPAT_ALL: number[] = [0.5, 1.0];
|
|
32
|
+
const SHEET_DIMMED_ALWAYS = -1;
|
|
33
|
+
|
|
34
|
+
function resolveSheetAllowedDetents(compat: ISheetAllowedDetents | undefined): number[] {
|
|
35
|
+
if (compat === undefined) return SHEET_COMPAT_LARGE;
|
|
36
|
+
if (Array.isArray(compat)) return compat;
|
|
37
|
+
switch (compat) {
|
|
38
|
+
case 'fitToContents':
|
|
39
|
+
return SHEET_FIT_TO_CONTENTS;
|
|
40
|
+
case 'large':
|
|
41
|
+
return SHEET_COMPAT_LARGE;
|
|
42
|
+
case 'medium':
|
|
43
|
+
return SHEET_COMPAT_MEDIUM;
|
|
44
|
+
case 'all':
|
|
45
|
+
return SHEET_COMPAT_ALL;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveSheetLargestUndimmedDetent(
|
|
50
|
+
compat: ISheetLargestUndimmedDetent | undefined,
|
|
51
|
+
lastDetentIndex: number,
|
|
52
|
+
): number {
|
|
53
|
+
if (typeof compat === 'number') return compat;
|
|
54
|
+
switch (compat) {
|
|
55
|
+
case 'last':
|
|
56
|
+
return lastDetentIndex;
|
|
57
|
+
case 'large':
|
|
58
|
+
return 1;
|
|
59
|
+
case 'medium':
|
|
60
|
+
return 0;
|
|
61
|
+
case 'none':
|
|
62
|
+
case 'all':
|
|
63
|
+
case undefined:
|
|
64
|
+
return SHEET_DIMMED_ALWAYS;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function resolveSheetInitialDetent(
|
|
69
|
+
compat: ISheetInitialDetent | undefined,
|
|
70
|
+
lastDetentIndex: number,
|
|
71
|
+
): number {
|
|
72
|
+
if (compat === 'last') return lastDetentIndex;
|
|
73
|
+
if (compat === undefined) return 0;
|
|
74
|
+
return compat;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function toOptionalBooleanNativeProp(value: boolean | undefined): IOptionalBooleanNativeProp {
|
|
78
|
+
if (value === undefined) return 'undefined';
|
|
79
|
+
return value ? 'true' : 'false';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function resolveHeaderConfigView(
|
|
83
|
+
options: IScreenOptions | undefined,
|
|
84
|
+
platform: INavigatorPlatform,
|
|
85
|
+
passthrough: Record<string, unknown> = {},
|
|
86
|
+
): IHeaderConfigViewProps {
|
|
87
|
+
return {
|
|
88
|
+
title: options?.title,
|
|
89
|
+
hidden: options?.headerShown === false,
|
|
90
|
+
backTitle: options?.headerBackTitle,
|
|
91
|
+
backTitleVisible: platform.defaultHeaderBackTitleVisible,
|
|
92
|
+
backButtonDisplayMode: options?.headerBackButtonDisplayMode,
|
|
93
|
+
largeTitle: options?.headerLargeTitle,
|
|
94
|
+
translucent: options?.headerTranslucent,
|
|
95
|
+
color: options?.headerTintColor,
|
|
96
|
+
titleColor: options?.headerTitleColor,
|
|
97
|
+
backgroundColor: options?.headerStyle?.backgroundColor,
|
|
98
|
+
largeTitleBackgroundColor: options?.headerLargeStyle?.backgroundColor,
|
|
99
|
+
userInterfaceStyle: options?.headerUserInterfaceStyle,
|
|
100
|
+
headerLeftBarButtonItems: prepareHeaderBarButtonItems(
|
|
101
|
+
options?.headerLeftBarButtonItems,
|
|
102
|
+
'left',
|
|
103
|
+
),
|
|
104
|
+
headerRightBarButtonItems: prepareHeaderBarButtonItems(
|
|
105
|
+
options?.headerRightBarButtonItems,
|
|
106
|
+
'right',
|
|
107
|
+
),
|
|
108
|
+
...buildHeaderBarButtonDispatch(
|
|
109
|
+
options?.headerLeftBarButtonItems,
|
|
110
|
+
options?.headerRightBarButtonItems,
|
|
111
|
+
),
|
|
112
|
+
passthrough,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function resolveScreenView(
|
|
117
|
+
screenId: string,
|
|
118
|
+
activityState: number,
|
|
119
|
+
options: IScreenOptions | undefined,
|
|
120
|
+
passthrough: Record<string, unknown> = {},
|
|
121
|
+
): IScreenViewProps {
|
|
122
|
+
const sheetAllowedDetents = resolveSheetAllowedDetents(options?.sheetAllowedDetents);
|
|
123
|
+
const lastDetentIndex = sheetAllowedDetents.length - 1;
|
|
124
|
+
return {
|
|
125
|
+
screenId,
|
|
126
|
+
activityState,
|
|
127
|
+
gestureEnabled: options?.gestureEnabled,
|
|
128
|
+
stackAnimation: options?.stackAnimation,
|
|
129
|
+
stackPresentation: options?.stackPresentation,
|
|
130
|
+
transitionDuration: options?.transitionDuration,
|
|
131
|
+
sheetAllowedDetents,
|
|
132
|
+
sheetLargestUndimmedDetent: resolveSheetLargestUndimmedDetent(
|
|
133
|
+
options?.sheetLargestUndimmedDetentIndex,
|
|
134
|
+
lastDetentIndex,
|
|
135
|
+
),
|
|
136
|
+
sheetInitialDetent: resolveSheetInitialDetent(
|
|
137
|
+
options?.sheetInitialDetentIndex,
|
|
138
|
+
lastDetentIndex,
|
|
139
|
+
),
|
|
140
|
+
sheetGrabberVisible: options?.sheetGrabberVisible,
|
|
141
|
+
sheetCornerRadius: options?.sheetCornerRadius,
|
|
142
|
+
sheetExpandsWhenScrolledToEdge: options?.sheetExpandsWhenScrolledToEdge,
|
|
143
|
+
sheetElevation: options?.sheetElevation,
|
|
144
|
+
sheetShouldOverflowTopInset: options?.sheetShouldOverflowTopInset,
|
|
145
|
+
sheetDefaultResizeAnimationEnabled: options?.sheetDefaultResizeAnimationEnabled,
|
|
146
|
+
statusBarStyle: options?.statusBarStyle,
|
|
147
|
+
statusBarHidden: options?.statusBarHidden,
|
|
148
|
+
statusBarAnimation: options?.statusBarAnimation,
|
|
149
|
+
screenOrientation: options?.screenOrientation,
|
|
150
|
+
passthrough,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// RNSSearchBar is a standalone Fabric leaf (react-native-screens mounts it as a header-subview
|
|
155
|
+
// child in its own JS component) - resolveSearchBarView only folds the static config surface;
|
|
156
|
+
// where/how the adapter mounts the resulting leaf in the header tree is an adapter concern.
|
|
157
|
+
export function resolveSearchBarView(
|
|
158
|
+
options: ISearchBarOptions | undefined,
|
|
159
|
+
passthrough: Record<string, unknown> = {},
|
|
160
|
+
): ISearchBarViewProps {
|
|
161
|
+
return {
|
|
162
|
+
placeholder: options?.placeholder,
|
|
163
|
+
autoCapitalize: options?.autoCapitalize,
|
|
164
|
+
placement: options?.placement,
|
|
165
|
+
hideWhenScrolling: options?.hideWhenScrolling,
|
|
166
|
+
allowToolbarIntegration: options?.allowToolbarIntegration,
|
|
167
|
+
obscureBackground: toOptionalBooleanNativeProp(options?.obscureBackground),
|
|
168
|
+
hideNavigationBar: toOptionalBooleanNativeProp(options?.hideNavigationBar),
|
|
169
|
+
cancelButtonText: options?.cancelButtonText,
|
|
170
|
+
barTintColor: options?.barTintColor,
|
|
171
|
+
tintColor: options?.tintColor,
|
|
172
|
+
textColor: options?.textColor,
|
|
173
|
+
autoFocus: options?.autoFocus,
|
|
174
|
+
disableBackButtonOverride: options?.disableBackButtonOverride,
|
|
175
|
+
inputType: options?.inputType,
|
|
176
|
+
hintTextColor: options?.hintTextColor,
|
|
177
|
+
headerIconColor: options?.headerIconColor,
|
|
178
|
+
shouldShowHintSearchIcon: options?.shouldShowHintSearchIcon,
|
|
179
|
+
passthrough,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The imperative API react-native-screens' own SearchBarProps exposes via its `ref` field
|
|
2
|
+
// (SearchBarCommands): each method dispatches a native view command on the RNSSearchBar node
|
|
3
|
+
// (SearchBarNativeComponent's supportedCommands: blur/focus/clearText/toggleCancelButton/
|
|
4
|
+
// setText/cancelSearch). Framework-agnostic - mirrors @symbiote-native/components'
|
|
5
|
+
// buildScrollViewHandle exactly (same lazy-getter shape); the adapter supplies the node getter
|
|
6
|
+
// and its own framework-specific ref field (see react/screen.ts's IReactSearchBarOptions - the
|
|
7
|
+
// ref itself is per-adapter, same split as IPressableProps).
|
|
8
|
+
import { dispatchViewCommand, dlog, type ISymbioteNode } from '@symbiote-native/engine';
|
|
9
|
+
|
|
10
|
+
export interface ISearchBarCommands {
|
|
11
|
+
focus(): void;
|
|
12
|
+
blur(): void;
|
|
13
|
+
clearText(): void;
|
|
14
|
+
setText(text: string): void;
|
|
15
|
+
cancelSearch(): void;
|
|
16
|
+
toggleCancelButton(show: boolean): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// dispatchViewCommand itself dlogs a "node not committed" skip; this null case (the ref never
|
|
20
|
+
// attached to a live RNSSearchBar at all - e.g. the header's search bar isn't mounted, or a
|
|
21
|
+
// stale handle outlived its screen) was the one unlogged gap, silently indistinguishable from
|
|
22
|
+
// "the command fired but did nothing". Investigation instrumentation (HeaderOptionsScreen
|
|
23
|
+
// unresponsive-buttons bug); kept behind DEBUG per <keep_logs_gate_behind_DEBUG>, never removed.
|
|
24
|
+
function warnIfDetached(command: string, node: ISymbioteNode | null): node is ISymbioteNode {
|
|
25
|
+
if (node !== null) return true;
|
|
26
|
+
dlog(
|
|
27
|
+
`SearchBarCommands.${command}: skipped, node is null (ref never attached) at t=${Date.now()}`,
|
|
28
|
+
);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Every command is the same 3-line dance: get the (lazily-read) node, bail with a dlog'd warning
|
|
33
|
+
// if it's detached, dispatch the native view command. Factored once so the six methods below
|
|
34
|
+
// differ only in which command name they dispatch.
|
|
35
|
+
function makeCommand(
|
|
36
|
+
getNode: () => ISymbioteNode | null,
|
|
37
|
+
command: string,
|
|
38
|
+
): (...args: unknown[]) => void {
|
|
39
|
+
return (...args: unknown[]): void => {
|
|
40
|
+
const node = getNode();
|
|
41
|
+
if (!warnIfDetached(command, node)) return;
|
|
42
|
+
dispatchViewCommand(node, command, args);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// `getNode` is a LAZY getter, read on every call - see buildScrollViewHandle's comment for why
|
|
47
|
+
// an eager capture would freeze `null`.
|
|
48
|
+
export function buildSearchBarHandle(getNode: () => ISymbioteNode | null): ISearchBarCommands {
|
|
49
|
+
return {
|
|
50
|
+
focus: makeCommand(getNode, 'focus'),
|
|
51
|
+
blur: makeCommand(getNode, 'blur'),
|
|
52
|
+
clearText: makeCommand(getNode, 'clearText'),
|
|
53
|
+
setText: makeCommand(getNode, 'setText'),
|
|
54
|
+
cancelSearch: makeCommand(getNode, 'cancelSearch'),
|
|
55
|
+
toggleCancelButton: makeCommand(getNode, 'toggleCancelButton'),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Lightweight state persistence: pure serialize/deserialize for INavigatorState, the primitive
|
|
2
|
+
// @react-navigation's `initialState`/`onStateChange` persistence recipe is built on. Routes are
|
|
3
|
+
// already `{key, name, params}` - plain data, no functions/refs/class instances - so a JSON-safe
|
|
4
|
+
// passthrough is sufficient; no framework wiring lives here yet (that's an adapter-level task).
|
|
5
|
+
|
|
6
|
+
import type { INavigatorState } from '../navigator-state';
|
|
7
|
+
import type { IRoute } from '../navigator-state';
|
|
8
|
+
import { isRecord } from '../guards';
|
|
9
|
+
|
|
10
|
+
// No `'params' in value` check: a route pushed with no params serializes to `{key, name,
|
|
11
|
+
// params: undefined}`, and JSON.stringify drops undefined-valued keys - a JSON round trip of a
|
|
12
|
+
// perfectly valid route legitimately arrives here without a `params` key at all.
|
|
13
|
+
function isRoute(value: unknown): value is IRoute<unknown> {
|
|
14
|
+
return isRecord(value) && typeof value.key === 'string' && typeof value.name === 'string';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isNavigatorState(value: unknown): value is INavigatorState {
|
|
18
|
+
return isRecord(value) && Array.isArray(value.routes) && value.routes.every(isRoute);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function serializeNavigatorState(state: INavigatorState): unknown {
|
|
22
|
+
return state;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function deserializeNavigatorState(raw: unknown): INavigatorState {
|
|
26
|
+
if (!isNavigatorState(raw)) {
|
|
27
|
+
throw new Error('deserializeNavigatorState: persisted value is not a valid navigator state');
|
|
28
|
+
}
|
|
29
|
+
return raw;
|
|
30
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Co-located unit test (ADR 0025) for the pure serialize/deserialize passthrough. No framework,
|
|
2
|
+
// no wiring - just the JSON-safe round trip and the deserialize-side runtime guard rejecting
|
|
3
|
+
// malformed persisted data (a corrupted AsyncStorage entry, a schema change across app versions).
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { deserializeNavigatorState, serializeNavigatorState } from './index';
|
|
7
|
+
import type { INavigatorState } from '../navigator-state';
|
|
8
|
+
|
|
9
|
+
describe('serializeNavigatorState / deserializeNavigatorState', () => {
|
|
10
|
+
it('round-trips a navigator state through JSON', () => {
|
|
11
|
+
const state: INavigatorState = {
|
|
12
|
+
routes: [{ key: 'home-1', name: 'Home', params: { tab: 'feed' } }],
|
|
13
|
+
};
|
|
14
|
+
const roundTripped = deserializeNavigatorState(
|
|
15
|
+
JSON.parse(JSON.stringify(serializeNavigatorState(state))),
|
|
16
|
+
);
|
|
17
|
+
expect(roundTripped).toEqual(state);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('rejects a payload missing the routes array', () => {
|
|
21
|
+
expect(() => deserializeNavigatorState({ notRoutes: [] })).toThrow();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('rejects a payload whose routes are not route-shaped', () => {
|
|
25
|
+
expect(() => deserializeNavigatorState({ routes: [{ key: 'r1' }] })).toThrow();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('rejects a non-object payload', () => {
|
|
29
|
+
expect(() => deserializeNavigatorState('not a state')).toThrow();
|
|
30
|
+
expect(() => deserializeNavigatorState(null)).toThrow();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('round-trips a route pushed without params (JSON.stringify drops the undefined key)', () => {
|
|
34
|
+
const state: INavigatorState = {
|
|
35
|
+
routes: [{ key: 'menu-1', name: 'Menu', params: undefined }],
|
|
36
|
+
};
|
|
37
|
+
const roundTripped = deserializeNavigatorState(
|
|
38
|
+
JSON.parse(JSON.stringify(serializeNavigatorState(state))),
|
|
39
|
+
);
|
|
40
|
+
expect(roundTripped).toEqual(state);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Per-tab agnostic options. Mirrors @react-navigation/bottom-tabs' `options` surface (title,
|
|
2
|
+
// tabBarLabel, tabBarIcon, tabBarBadge, tint colors, tabBarStyle) minus anything that requires a
|
|
3
|
+
// framework element: `tabBarIcon` there is a render prop returning a platform icon element, but
|
|
4
|
+
// per <prop_types_split_agnostic_vs_per_adapter> a render-callback-returning-a-framework-element
|
|
5
|
+
// field can't live in the shared agnostic type, so here it is EITHER a pre-built `IDescriptor`
|
|
6
|
+
// (an adapter can bridge any host node it already resolved, image or vector icon) or a bare icon
|
|
7
|
+
// NAME string the renderer paints as a label-style glyph - both framework-agnostic. An adapter
|
|
8
|
+
// wanting a `(props) => ReactNode`-style callback resolves it to one of these two forms itself,
|
|
9
|
+
// same split as IPressableProps's per-adapter children.
|
|
10
|
+
|
|
11
|
+
import type { IColorValue } from '@symbiote-native/engine';
|
|
12
|
+
import type { IViewStyle, IStyleProp } from '@symbiote-native/engine';
|
|
13
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
14
|
+
|
|
15
|
+
export type ITabBarIcon = IDescriptor | string;
|
|
16
|
+
|
|
17
|
+
export type ITabOptions = {
|
|
18
|
+
title?: string;
|
|
19
|
+
tabBarLabel?: string;
|
|
20
|
+
tabBarIcon?: ITabBarIcon;
|
|
21
|
+
tabBarBadge?: string | number;
|
|
22
|
+
tabBarActiveTintColor?: IColorValue;
|
|
23
|
+
tabBarInactiveTintColor?: IColorValue;
|
|
24
|
+
tabBarStyle?: IStyleProp<IViewStyle>;
|
|
25
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// TabRouter: the logic half (framework-agnostic, zero render). A pure reducer over a FOCUSED
|
|
2
|
+
// INDEX into a fixed route list - jumpTo/setParams - mirroring what @react-navigation/routers'
|
|
3
|
+
// TabRouter keeps, minus the React-specific action-creator/linking machinery. The key structural
|
|
4
|
+
// difference from navigator-state's Stack: tabs never push/pop a route, they move a focused
|
|
5
|
+
// index between a fixed set (mirrors TabRouter.getInitialState / getStateForAction for
|
|
6
|
+
// JUMP_TO - see the tab-actions docs: jumpTo takes a route NAME, not a stack push). Route
|
|
7
|
+
// identity (`key`) is generated by the CALLER, same convention as navigator-state.ts - reused
|
|
8
|
+
// verbatim from there so Stack and Tabs share one route shape.
|
|
9
|
+
|
|
10
|
+
import { mergeParams } from '../guards';
|
|
11
|
+
import type { IRoute } from '../navigator-state';
|
|
12
|
+
|
|
13
|
+
export type { IRoute } from '../navigator-state';
|
|
14
|
+
|
|
15
|
+
type IRouteEntry = IRoute<unknown>;
|
|
16
|
+
|
|
17
|
+
export type ITabRouterState = Readonly<{
|
|
18
|
+
routes: readonly IRouteEntry[];
|
|
19
|
+
index: number;
|
|
20
|
+
}>;
|
|
21
|
+
|
|
22
|
+
export type ITabRouterAction =
|
|
23
|
+
| { type: 'jumpTo'; name: string; params?: unknown }
|
|
24
|
+
| { type: 'setParams'; key: string; params: unknown };
|
|
25
|
+
|
|
26
|
+
const INITIAL_FOCUSED_INDEX = 0;
|
|
27
|
+
|
|
28
|
+
export function createInitialTabState(
|
|
29
|
+
routes: readonly IRouteEntry[],
|
|
30
|
+
initialRouteName?: string,
|
|
31
|
+
): ITabRouterState {
|
|
32
|
+
if (initialRouteName === undefined) return { routes, index: INITIAL_FOCUSED_INDEX };
|
|
33
|
+
const index = routes.findIndex(route => route.name === initialRouteName);
|
|
34
|
+
return { routes, index: index === -1 ? INITIAL_FOCUSED_INDEX : index };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// jumpTo moves the focused index to an existing route by name and optionally merges params
|
|
38
|
+
// (navigation.jumpTo(name, params) - the tab-actions doc's own signature); it never adds,
|
|
39
|
+
// removes, or reorders routes (mirrors TabRouter: JUMP_TO is a no-op when the target name isn't
|
|
40
|
+
// registered, same as navigatorReducer's popTo bailing on an unknown key). setParams merges into
|
|
41
|
+
// the target route's params by key (CommonActions.setParams semantics - a merge, not a replace).
|
|
42
|
+
export function tabRouterReducer(
|
|
43
|
+
state: ITabRouterState,
|
|
44
|
+
action: ITabRouterAction,
|
|
45
|
+
): ITabRouterState {
|
|
46
|
+
switch (action.type) {
|
|
47
|
+
case 'jumpTo': {
|
|
48
|
+
const index = state.routes.findIndex(route => route.name === action.name);
|
|
49
|
+
if (index === -1) return state;
|
|
50
|
+
if (action.params === undefined) {
|
|
51
|
+
return index === state.index ? state : { ...state, index };
|
|
52
|
+
}
|
|
53
|
+
const target = state.routes[index];
|
|
54
|
+
const routes = state.routes.slice();
|
|
55
|
+
routes[index] = { ...target, params: mergeParams(target.params, action.params) };
|
|
56
|
+
return { ...state, index, routes };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
case 'setParams': {
|
|
60
|
+
const index = state.routes.findIndex(route => route.key === action.key);
|
|
61
|
+
if (index === -1) return state;
|
|
62
|
+
const target = state.routes[index];
|
|
63
|
+
const routes = state.routes.slice();
|
|
64
|
+
routes[index] = { ...target, params: mergeParams(target.params, action.params) };
|
|
65
|
+
return { ...state, routes };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
default:
|
|
69
|
+
return state;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function isFocusedRoute(index: number, focusedIndex: number): boolean {
|
|
74
|
+
return index === focusedIndex;
|
|
75
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Co-located unit test (ADR 0025) for the pure tab-router reducer, targeting the params-merge
|
|
2
|
+
// behavior of jumpTo/setParams directly, framework-free - twin of navigator-state.test.ts's
|
|
3
|
+
// setParams coverage.
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { tabRouterReducer } from './index';
|
|
7
|
+
import type { ITabRouterState } from './index';
|
|
8
|
+
|
|
9
|
+
const FEED = { key: 'feed-1', name: 'Feed', params: { sort: 'new' } };
|
|
10
|
+
const PROFILE = { key: 'profile-1', name: 'Profile', params: { id: 1 } };
|
|
11
|
+
|
|
12
|
+
function twoRouteState(): ITabRouterState {
|
|
13
|
+
return { routes: [FEED, PROFILE], index: 0 };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('tabRouterReducer — params merge guards against array params', () => {
|
|
17
|
+
it('jumpTo replaces (not merges) params when incoming params is an array', () => {
|
|
18
|
+
const next = tabRouterReducer(twoRouteState(), {
|
|
19
|
+
type: 'jumpTo',
|
|
20
|
+
name: 'Profile',
|
|
21
|
+
params: [1, 2, 3],
|
|
22
|
+
});
|
|
23
|
+
expect(next.routes[1].params).toEqual([1, 2, 3]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('setParams replaces (not merges) params when incoming params is an array', () => {
|
|
27
|
+
const next = tabRouterReducer(twoRouteState(), {
|
|
28
|
+
type: 'setParams',
|
|
29
|
+
key: 'profile-1',
|
|
30
|
+
params: [1, 2, 3],
|
|
31
|
+
});
|
|
32
|
+
expect(next.routes[1].params).toEqual([1, 2, 3]);
|
|
33
|
+
});
|
|
34
|
+
});
|
package/src/globals.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Runtime global provided by the Hermes/RN host but absent from the ES2022 lib this package
|
|
2
|
+
// builds against (no DOM, no @types/node - see core/engine/src/globals.d.ts's identical
|
|
3
|
+
// declaration, which this package's own tsconfig scope doesn't inherit).
|
|
4
|
+
declare function queueMicrotask(callback: () => void): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Shared by stack.ts/tabs.ts/drawer.ts: each navigator registers its own Screen marker
|
|
2
|
+
// component's props into a name -> entry map via React.Children, differing only in the marker
|
|
3
|
+
// component (isMarkerElement) and the props shape (TProps). Stays in react/ rather than core/:
|
|
4
|
+
// Children/isValidElement are React-only APIs (see CLAUDE.md <adapter_src_follows_framework_idioms>).
|
|
5
|
+
|
|
6
|
+
import { Children, type ReactElement, type ReactNode } from 'react';
|
|
7
|
+
|
|
8
|
+
export function collectRegistry<TProps extends { name: string }>(
|
|
9
|
+
children: ReactNode,
|
|
10
|
+
isMarkerElement: (child: ReactNode) => child is ReactElement<TProps>,
|
|
11
|
+
): Map<string, Omit<TProps, 'name'>> {
|
|
12
|
+
const registry = new Map<string, Omit<TProps, 'name'>>();
|
|
13
|
+
Children.forEach(children, child => {
|
|
14
|
+
if (!isMarkerElement(child)) return;
|
|
15
|
+
const { name, ...entry } = child.props;
|
|
16
|
+
registry.set(name, entry);
|
|
17
|
+
});
|
|
18
|
+
return registry;
|
|
19
|
+
}
|