@apexnative/navigation 1.0.0-alpha.5 → 1.0.0-alpha.7
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/ApexNavigation.podspec +2 -1
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/android/CLAUDE.md +31 -20
- package/android/CORE.md +12 -8
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +36 -5
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
- package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +0 -2
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +12 -49
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +13 -10
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +7 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +20 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +443 -58
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +33 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +50 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +10 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +36 -38
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +129 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +67 -3
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -42
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
- package/android/src/main/jni/ANNContentHeights.cpp +82 -0
- package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
- package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
- package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
- package/android/src/main/res/values/styles.xml +1 -1
- package/android/src/main/res/values-night/styles.xml +1 -1
- package/cli/doctor/checks/app.js +16 -1
- package/cli/project.js +4 -0
- package/cli/setup/index.js +5 -0
- package/cli/setup/steps/metro.js +46 -0
- package/docs-md/architecture/native-screens.md +4 -0
- package/docs-md/architecture/theme-and-context.md +131 -12
- package/docs-md/architecture/transitions.md +46 -5
- package/docs-md/containers/modals.md +2 -0
- package/docs-md/containers/overlays.md +1 -1
- package/docs-md/containers/side-menu.md +1 -1
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/fundamentals/screens-and-props.md +9 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +3 -1
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +22 -1
- package/docs-md/index.json +41 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +1 -1
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +17 -1
- package/docs-md/screen-ui/bar-buttons.md +5 -5
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +16 -11
- package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +16 -1
- package/ios/Animations/ANNFrameDriver.h +55 -15
- package/ios/Animations/ANNFrameDriver.mm +216 -60
- package/ios/Animations/ANNTransitionAnimator.h +26 -5
- package/ios/Animations/ANNTransitionAnimator.mm +49 -3
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/Elements/ANNElementFinder.h +2 -2
- package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
- package/ios/Animations/Elements/ANNElementTransition.h +3 -3
- package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
- package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +249 -45
- package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
- package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
- package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
- package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
- package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
- package/ios/CLAUDE.md +32 -22
- package/ios/CORE.md +25 -21
- package/ios/Contract/ANNCommandRunner.h +8 -7
- package/ios/Contract/ANNCommandRunner.mm +21 -27
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNDeepLinkQueue.h +6 -5
- package/ios/Core/ANNDeepLinkQueue.mm +22 -10
- package/ios/Core/ANNJavaScriptCalls.h +11 -12
- package/ios/Core/ANNJavaScriptCalls.mm +7 -16
- package/ios/Core/ANNReloadCoordinator.mm +4 -8
- package/ios/Core/ANNSceneDelegate.mm +2 -2
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +6 -2
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
- package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
- package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
- package/ios/Layouts/Screen/ANNComponentViewController.mm +13 -23
- package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
- package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
- package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
- package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +57 -5
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +153 -11
- package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
- package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
- package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
- package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
- package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
- package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
- package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
- package/ios/Options/ANNAnimationOptions.h +2 -1
- package/ios/Options/ANNAnimationOptions.mm +1 -1
- package/ios/Options/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +25 -0
- package/ios/Options/ANNOptions.mm +157 -1
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/Params/ANNParam.h +15 -0
- package/ios/Options/Params/ANNParam.mm +61 -0
- package/ios/Options/Params/Color.h +3 -0
- package/ios/Options/Params/Color.mm +21 -0
- package/ios/Options/Params/ColorParser.h +4 -3
- package/ios/Options/Params/ColorParser.mm +22 -4
- package/ios/Options/Params/Image.h +4 -0
- package/ios/Options/Params/Image.mm +20 -0
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
- package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
- package/ios/TopBar/ANNBarAppearance.h +2 -1
- package/ios/TopBar/ANNBarAppearance.mm +111 -30
- package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
- package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
- package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
- package/ios/TopBar/ANNBarButtons.h +5 -3
- package/ios/TopBar/ANNBarButtons.mm +186 -17
- package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
- package/ios/TopBar/ANNMainList.h +3 -0
- package/ios/TopBar/ANNMainList.mm +4 -0
- package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
- package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
- package/ios/TopBar/ANNSearchPresenter.mm +2 -2
- package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
- package/ios/TopBar/ANNTopBarPresenter.h +3 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
- package/ios/TurboModules/ANNTurboModule.mm +66 -16
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
- package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
- package/lib/module/ARCHITECTURE.md +17 -7
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/app/AppRegistry.js +14 -2
- package/lib/module/api/app/AppRegistry.js.map +1 -1
- package/lib/module/api/app/createNavigation.js +188 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/events/navigationEvents.js +6 -2
- package/lib/module/api/events/navigationEvents.js.map +1 -1
- package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
- package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/options/OptionsChain.js +2 -2
- package/lib/module/api/screens/defineScreen.js +45 -3
- package/lib/module/api/screens/defineScreen.js.map +1 -1
- package/lib/module/api/screens/nativeScreens.js +31 -6
- package/lib/module/api/screens/nativeScreens.js.map +1 -1
- package/lib/module/api/screens/registerScreens.js +172 -35
- package/lib/module/api/screens/registerScreens.js.map +1 -1
- package/lib/module/api/theme/theme.js +5 -0
- package/lib/module/api/theme/theme.js.map +1 -1
- package/lib/module/engine/commands.js +42 -2
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +7 -2
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/nativeScreens.js +9 -0
- package/lib/module/engine/nativeScreens.js.map +1 -1
- package/lib/module/engine/options.js +5 -4
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/optionsChange.js +102 -0
- package/lib/module/engine/optionsChange.js.map +1 -0
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +60 -0
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +55 -4
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +8 -3
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/index.d.ts +1 -1
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/api/linking/linking.d.ts +8 -0
- package/lib/typescript/api/linking/linking.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
- package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
- package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
- package/lib/typescript/api/theme/theme.d.ts +2 -0
- package/lib/typescript/api/theme/theme.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts +5 -0
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/layout.d.ts.map +1 -1
- package/lib/typescript/engine/nativeScreens.d.ts +5 -0
- package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
- package/lib/typescript/engine/optionsChange.d.ts +28 -0
- package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
- package/lib/typescript/engine/refresh.d.ts +35 -0
- package/lib/typescript/engine/refresh.d.ts.map +1 -0
- package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +27 -6
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/options/animations.d.ts +44 -14
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +19 -6
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +10 -10
- package/lib/typescript/interfaces/options/modals.d.ts +6 -7
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +8 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +8 -5
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
- package/lib/typescript/interfaces/options/topBar.d.ts +46 -29
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/metro/acceptPlugin.js +57 -0
- package/metro/babelTransformer.js +45 -0
- package/metro/index.js +36 -0
- package/package.json +3 -1
- package/src/ARCHITECTURE.md +17 -7
- package/src/adapters/NativeANNTurboModule.ts +7 -0
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +201 -69
- package/src/api/events/navigationEvents.ts +9 -3
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/api/screens/defineScreen.ts +49 -5
- package/src/api/screens/nativeScreens.ts +40 -4
- package/src/api/screens/registerScreens.tsx +170 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +51 -6
- package/src/engine/layout.ts +11 -2
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +6 -8
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +70 -0
- package/src/engine/screens.tsx +53 -8
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/options/animations.ts +44 -14
- package/src/interfaces/options/bottomTabs.ts +19 -6
- package/src/interfaces/options/buttons.ts +10 -10
- package/src/interfaces/options/modals.ts +6 -7
- package/src/interfaces/options/stack.ts +8 -3
- package/src/interfaces/options/system.ts +8 -5
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +46 -29
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -136
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -86
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -64
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -177
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -137
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
|
@@ -50,7 +50,7 @@ export interface OptionsTopBarTitleDocument {
|
|
|
50
50
|
export interface OptionsTopBarTitle {
|
|
51
51
|
/**
|
|
52
52
|
* The text of the title. Setting it removes a React title. On iOS it is the title of the screen's navigation item,
|
|
53
|
-
* the label the system shows on the next screen's back button
|
|
53
|
+
* the label the system shows on the next screen's back button without the glass design, and what Rename edits. On Android it
|
|
54
54
|
* is one line cut with an ellipsis, and also the text of the large title; a title component set together with the
|
|
55
55
|
* text drops the text and the subtitle (with a warning in development).
|
|
56
56
|
*/
|
|
@@ -94,9 +94,9 @@ export interface OptionsTopBarTitle {
|
|
|
94
94
|
*/
|
|
95
95
|
document?: OptionsTopBarTitleDocument;
|
|
96
96
|
/**
|
|
97
|
-
* (iOS 26
|
|
97
|
+
* (iOS 26+, glass design) Puts the title on a Liquid Glass capsule like the buttons: `'regular'` or `'clear'`; `'none'` and any
|
|
98
98
|
* other value mean no capsule. A text title and the subtitle are two lines on the capsule; a component title sits on
|
|
99
|
-
* it as it is, the capsule taking its size.
|
|
99
|
+
* it as it is, the capsule taking its size. Without the glass design (see `UIDesignRequiresCompatibility`) and on Android it does nothing.
|
|
100
100
|
*/
|
|
101
101
|
glass?: 'regular' | 'clear' | 'none';
|
|
102
102
|
/** (Android) The height of the row of title and buttons, in dp. By default 64, regardless of `topBar.height`. */
|
|
@@ -118,15 +118,15 @@ export interface OptionsTopBarTitle {
|
|
|
118
118
|
/** The subtitle: a second line under the title. */
|
|
119
119
|
export interface OptionsTopBarSubtitle {
|
|
120
120
|
/**
|
|
121
|
-
* The text of the second line. An empty text removes it.
|
|
122
|
-
* large title and the collapsed bar, and on the capsule when the title has `glass`; a React title hides it.
|
|
123
|
-
*
|
|
121
|
+
* The text of the second line. An empty text removes it. With the glass design (iOS 26+, see `UIDesignRequiresCompatibility`) it is the system subtitle, under the title, the
|
|
122
|
+
* large title and the collapsed bar, and on the capsule when the title has `glass`; a React title hides it. Without
|
|
123
|
+
* it, it makes a two-line title view, only without a large title or a React title. On Android it is the line under
|
|
124
124
|
* the title, hidden when empty and dropped when the title is a component.
|
|
125
125
|
*/
|
|
126
126
|
text?: string;
|
|
127
127
|
/**
|
|
128
|
-
* The size of the font.
|
|
129
|
-
* font;
|
|
128
|
+
* The size of the font. With the glass design only what is set goes to the system subtitle, and any font option sets the whole
|
|
129
|
+
* font; without it the size is 12. On Android it is in sp, 14 by default.
|
|
130
130
|
*/
|
|
131
131
|
fontSize?: number;
|
|
132
132
|
/** The color of the subtitle. On Android the theme's on-surface-variant color by default. */
|
|
@@ -177,14 +177,14 @@ export interface OptionsTopBarBackButton {
|
|
|
177
177
|
*/
|
|
178
178
|
visible?: boolean;
|
|
179
179
|
/**
|
|
180
|
-
* (iOS) The text of the back button.
|
|
181
|
-
* the screen below is never shown;
|
|
180
|
+
* (iOS) The text of the back button. With the glass design (iOS 26+, see `UIDesignRequiresCompatibility`) the system button without it is an arrow alone,
|
|
181
|
+
* since the title of the screen below is never shown; without it, it is that title while it fits. It is set on the screen below, as
|
|
182
182
|
* its back button title.
|
|
183
183
|
*/
|
|
184
184
|
title?: string;
|
|
185
185
|
/**
|
|
186
186
|
* (iOS) `true` shows the title of the screen below (or `title`), `false` shows an arrow alone (the minimal mode).
|
|
187
|
-
* Without it the system decides;
|
|
187
|
+
* Without it the system decides; with the glass design that is the arrow.
|
|
188
188
|
*/
|
|
189
189
|
showTitle?: boolean;
|
|
190
190
|
/**
|
|
@@ -207,7 +207,7 @@ export interface OptionsTopBarBackButton {
|
|
|
207
207
|
/**
|
|
208
208
|
* A shape behind the icon, as for a button. It takes effect with a `color` of the shape. On iOS the icon (the
|
|
209
209
|
* chevron by default) is drawn on it and the back button becomes an own button that keeps the history menu unless
|
|
210
|
-
* `enableMenu` is `false`; without a capsule
|
|
210
|
+
* `enableMenu` is `false`; without a capsule with the glass design by default. On Android the arrow sits on the shape.
|
|
211
211
|
*/
|
|
212
212
|
iconBackground?: IconBackgroundOptions;
|
|
213
213
|
/**
|
|
@@ -228,7 +228,7 @@ export interface OptionsTopBarBackButton {
|
|
|
228
228
|
*/
|
|
229
229
|
displayMode?: 'default' | 'generic' | 'minimal';
|
|
230
230
|
/**
|
|
231
|
-
* (iOS 26
|
|
231
|
+
* (iOS 26+, glass design) Whether the Liquid Glass capsule under the back button is hidden. It works only for an own button with
|
|
232
232
|
* an `iconBackground`, where the shape is already drawn into the icon; the system button ignores it.
|
|
233
233
|
* @default true
|
|
234
234
|
*/
|
|
@@ -245,9 +245,9 @@ export interface OptionsTopBarBackButton {
|
|
|
245
245
|
/** The background of the bar: a color, a component, translucency and blur. */
|
|
246
246
|
export interface OptionsTopBarBackground {
|
|
247
247
|
/**
|
|
248
|
-
* The color of the bar. On iOS it fills both the standard look and the one at the scroll edge;
|
|
249
|
-
* then solid in this color instead of glass. A transparent color makes a transparent bar. It beats `blur` and
|
|
250
|
-
* `translucent`. With a large title
|
|
248
|
+
* The color of the bar. On iOS it fills both the standard look and the one at the scroll edge; with the glass design the bar is
|
|
249
|
+
* then solid in this color instead of glass; without it (`UIDesignRequiresCompatibility`) it is the opaque bar of before iOS 26. A transparent color makes a transparent bar. It beats `blur` and
|
|
250
|
+
* `translucent`. With a large title and the glass design the color is drawn into the list under the title, and the collapsed bar
|
|
251
251
|
* paints itself. On Android it is the background of the bar with the status bar strip, by default the theme's
|
|
252
252
|
* surface color, changing at once on push and pop. Together with `component` the color lies under the component.
|
|
253
253
|
*/
|
|
@@ -266,8 +266,8 @@ export interface OptionsTopBarBackground {
|
|
|
266
266
|
*/
|
|
267
267
|
component?: OptionsTopBarBackgroundComponent;
|
|
268
268
|
/**
|
|
269
|
-
* (iOS) Whether content shows through the bar. By default `true`
|
|
270
|
-
* the bar is glass
|
|
269
|
+
* (iOS) Whether content shows through the bar. By default `true` with the glass design (iOS 26+, see `UIDesignRequiresCompatibility`) and `false` without it. With `true`
|
|
270
|
+
* the bar is glass with the glass design and the system translucent bar without it; with `false` it is solid in the system color.
|
|
271
271
|
* `color` and `blur` beat it. Only an explicit `true` puts the screen under the bar.
|
|
272
272
|
*/
|
|
273
273
|
translucent?: boolean;
|
|
@@ -301,7 +301,7 @@ export interface OptionsTopBarBackgroundComponent {
|
|
|
301
301
|
export interface OptionsTopBarScrollEdgeAppearanceTitle {
|
|
302
302
|
/** The size of the font, handled like `topBar.title.fontSize`. */
|
|
303
303
|
fontSize?: number;
|
|
304
|
-
/** The color of the title at the edge.
|
|
304
|
+
/** The color of the title at the edge. With the glass design it is fixed during a push, like the usual title color. */
|
|
305
305
|
color?: Color;
|
|
306
306
|
/** The font family, handled like `topBar.title.fontFamily`. */
|
|
307
307
|
fontFamily?: FontFamily;
|
|
@@ -327,7 +327,7 @@ export interface OptionsTopBarScrollEdgeAppearanceBackground {
|
|
|
327
327
|
|
|
328
328
|
/**
|
|
329
329
|
* (iOS) How the bar looks while the list is at its top edge. Without `active` the edge looks as the usual bar, except
|
|
330
|
-
* for the transparency under a large title
|
|
330
|
+
* for the transparency under a large title with the glass design; the title and the border at the edge still come from the fields
|
|
331
331
|
* here or from the usual ones. Android doesn't read it.
|
|
332
332
|
*/
|
|
333
333
|
export interface OptionsTopBarScrollEdgeAppearance {
|
|
@@ -337,7 +337,7 @@ export interface OptionsTopBarScrollEdgeAppearance {
|
|
|
337
337
|
background?: OptionsTopBarScrollEdgeAppearanceBackground;
|
|
338
338
|
/**
|
|
339
339
|
* Whether the bar has a background of its own at the edge (`background`). With it the edge isn't made transparent
|
|
340
|
-
* under a large title, and
|
|
340
|
+
* under a large title, and with the glass design an opaque color covers the large title. A change by `mergeOptions` applies at
|
|
341
341
|
* once.
|
|
342
342
|
* @default false
|
|
343
343
|
*/
|
|
@@ -373,7 +373,7 @@ export interface OptionsTopBarLargeTitle {
|
|
|
373
373
|
* Whether the large title collapses into the bar as the list scrolls. With `false` on iOS the bar follows an empty
|
|
374
374
|
* scroll view instead of the list, so the title stays as at the top of the list; under the row it then needs a
|
|
375
375
|
* background (`background.color`, else a system blur), and `searchBar.hideOnScroll` doesn't work. On Android `false`
|
|
376
|
-
* leaves the bar as it is and stops listening to the list.
|
|
376
|
+
* leaves the bar as it is and stops listening to the list. With the glass design in a right-to-left layout nothing collapses.
|
|
377
377
|
* @default true
|
|
378
378
|
*/
|
|
379
379
|
collapseOnScroll?: boolean;
|
|
@@ -637,7 +637,7 @@ export interface OptionsTopBar {
|
|
|
637
637
|
/**
|
|
638
638
|
* The shape color behind the icons of the left buttons that have an `icon` image and no `iconBackground.color`; the
|
|
639
639
|
* size and corners come from the button's `iconBackground`, or the icon's size without corners. On iOS only image
|
|
640
|
-
* buttons, not SF Symbols, and without a capsule
|
|
640
|
+
* buttons, not SF Symbols, and without a capsule with the glass design. A color sent by `mergeOptions` repaints all the side's
|
|
641
641
|
* image buttons, those with their own shape color too.
|
|
642
642
|
*/
|
|
643
643
|
leftButtonBackgroundColor?: Color;
|
|
@@ -654,6 +654,20 @@ export interface OptionsTopBar {
|
|
|
654
654
|
centerButtonColor?: Color;
|
|
655
655
|
/** (iOS 16+) The color of the disabled center buttons that have no `disabledColor` of their own. */
|
|
656
656
|
centerButtonDisabledColor?: Color;
|
|
657
|
+
/**
|
|
658
|
+
* (Android) The background of the bar's menus: "⋮" and the menus of the buttons, their submenus too. Without it the
|
|
659
|
+
* bar's color (`background.color`, else the theme's surface), unless the bar lets something through; then the
|
|
660
|
+
* theme's surface container color. It follows light and dark mode; an open menu closes as the mode switches. iOS
|
|
661
|
+
* draws its system menus in the system's colors.
|
|
662
|
+
*/
|
|
663
|
+
menuBackgroundColor?: Color;
|
|
664
|
+
/**
|
|
665
|
+
* (Android) The color of the text and the icons of the items of the bar's menus, and of the titles of their
|
|
666
|
+
* submenus. Without it the title's color (`title.color`) when the menu takes the bar's color, else the theme's
|
|
667
|
+
* colors. A destructive item stays red, and a button moved into "⋮" keeps its own color or the side's
|
|
668
|
+
* (`rightButtonColor`). A disabled item is dimmed. An open menu closes when either menu color is merged.
|
|
669
|
+
*/
|
|
670
|
+
menuTextColor?: Color;
|
|
657
671
|
/**
|
|
658
672
|
* Whether the content of the screen goes under the bar, starting at the top of the screen. The screen goes under the
|
|
659
673
|
* bar by itself in some cases (a large title that may show, `hideOnScroll`, a hidden bar, an explicit translucent
|
|
@@ -815,12 +829,15 @@ export interface OptionsScrollEdge {
|
|
|
815
829
|
|
|
816
830
|
/**
|
|
817
831
|
* (iOS 26+) The scroll edge effect of the scroll views of a screen: how the content fades or blurs where it scrolls
|
|
818
|
-
* under a bar. The scroll views draw it, and only where content goes under a bar.
|
|
819
|
-
*
|
|
820
|
-
* `
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
832
|
+
* under a bar. The scroll views draw it, and only where content goes under a bar. When the screen appears, it applies
|
|
833
|
+
* to the vertical lists and text views (a multi-line `TextInput`) in the view of the screen, except in hidden views
|
|
834
|
+
* (`display: none`). A list inside another vertical list gets none (UIKit draws no edge effect there); a scroll view
|
|
835
|
+
* that doesn't scroll vertically, like a pager, is searched for its lists. A list nested very deep in the screen's
|
|
836
|
+
* views may not get it. After React mounts, the main list of the screen gets it; a list mounted later gets it at the
|
|
837
|
+
* next appearance, or at a `mergeOptions` of `scrollEdgeEffect` or of the bar's background. The lists get the system
|
|
838
|
+
* effect back when the screen leaves or is destroyed, and a list React removes from the screen gets it back too. Under
|
|
839
|
+
* a bar with `background.color` or `background.component` there is no effect at the top unless the screen sets one for
|
|
840
|
+
* the top or for all edges. Before iOS 26 and on Android it does nothing.
|
|
824
841
|
*/
|
|
825
842
|
export interface OptionsScrollEdgeEffect {
|
|
826
843
|
/** Whether the effect is hidden on all four edges. The value of an edge beats it. */
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.react
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.bridge.Arguments
|
|
4
|
-
import com.facebook.react.bridge.WritableMap
|
|
5
|
-
import dev.apexnative.navigation.react.events.EventContract
|
|
6
|
-
import dev.apexnative.navigation.react.events.EventEmitter
|
|
7
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The state of each screen of a pair (`useArrangement`): which screen of the pair it is, how the pair lies, whether it
|
|
11
|
-
* lies over the other one and whether it is out of the window. Set on the main thread as the pair lays out; JavaScript
|
|
12
|
-
* reads it from its own thread for a screen's first render, and gets every change as `ANN.ArrangementChanged`. A
|
|
13
|
-
* screen outside a pair has none.
|
|
14
|
-
*/
|
|
15
|
-
internal object ArrangementStates {
|
|
16
|
-
data class State(val placement: String, val layout: String, val front: Boolean, val hidden: Boolean)
|
|
17
|
-
|
|
18
|
-
private val states = ConcurrentHashMap<String, State>()
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Keeps the screen's state, and tells JavaScript when it changed and [notify] holds, through [emitter], the one of
|
|
22
|
-
* the JavaScript the screen was made for: silent once it went. Main thread only.
|
|
23
|
-
*/
|
|
24
|
-
fun set(screenId: String, state: State, notify: Boolean, emitter: EventEmitter) {
|
|
25
|
-
if (states.put(screenId, state) == state || !notify) return
|
|
26
|
-
emitter.emitArrangementChanged(screenId, toMap(state))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** `{ placement, layout, front, hidden }`, empty for a screen outside a pair. Any thread. */
|
|
30
|
-
fun get(screenId: String): WritableMap = states[screenId]?.let(::toMap) ?: Arguments.createMap()
|
|
31
|
-
|
|
32
|
-
fun remove(screenId: String) {
|
|
33
|
-
states.remove(screenId)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private fun toMap(state: State): WritableMap = Arguments.createMap().apply {
|
|
37
|
-
putString(EventContract.ArrangementChanged.PLACEMENT, state.placement)
|
|
38
|
-
putString(EventContract.ArrangementChanged.LAYOUT, state.layout)
|
|
39
|
-
putBoolean(EventContract.ArrangementChanged.FRONT, state.front)
|
|
40
|
-
putBoolean(EventContract.ArrangementChanged.HIDDEN, state.hidden)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.react
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.bridge.Arguments
|
|
4
|
-
import com.facebook.react.bridge.WritableMap
|
|
5
|
-
import dev.apexnative.navigation.react.events.EventContract
|
|
6
|
-
import dev.apexnative.navigation.react.events.EventEmitter
|
|
7
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The safe area of each screen, in dp: how much of its content the bars and the system cover on each side. The padding
|
|
11
|
-
* is the part of it the screen's safe area view keeps its content out of: the insets on the edges the screen's options
|
|
12
|
-
* give. JavaScript gets the rest, what still covers the content (0 on a padded edge): it reads it from its own thread
|
|
13
|
-
* for a screen's first render, and gets every change as `ANN.ScreenInsetsChanged`.
|
|
14
|
-
*/
|
|
15
|
-
object ScreenInsets {
|
|
16
|
-
data class Insets(val top: Double, val right: Double, val bottom: Double, val left: Double)
|
|
17
|
-
|
|
18
|
-
private val insets = ConcurrentHashMap<String, Insets>()
|
|
19
|
-
// Main thread only.
|
|
20
|
-
private val padding = HashMap<String, Insets>()
|
|
21
|
-
private val paddingListeners = HashMap<String, MutableSet<() -> Unit>>()
|
|
22
|
-
|
|
23
|
-
/** The padding of the screen's safe area view; none before the screen was laid out. */
|
|
24
|
-
fun padding(screenId: String): Insets? = padding[screenId]
|
|
25
|
-
|
|
26
|
-
/** Calls `listener` when the padding of the screen changes; returns the function that stops it. */
|
|
27
|
-
fun listenToPadding(screenId: String, listener: () -> Unit): () -> Unit {
|
|
28
|
-
paddingListeners.getOrPut(screenId) { LinkedHashSet() }.add(listener)
|
|
29
|
-
return {
|
|
30
|
-
paddingListeners[screenId]?.let {
|
|
31
|
-
it.remove(listener)
|
|
32
|
-
if (it.isEmpty()) paddingListeners.remove(screenId)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Keeps the screen's insets and padding, and tells when they changed through [emitter], the one of the JavaScript
|
|
39
|
-
* the screen was made for: silent once it went.
|
|
40
|
-
*/
|
|
41
|
-
fun update(screenId: String, value: Insets, paddingValue: Insets, emitter: EventEmitter) {
|
|
42
|
-
if (padding.put(screenId, paddingValue) != paddingValue) {
|
|
43
|
-
paddingListeners[screenId]?.toList()?.forEach { it() }
|
|
44
|
-
}
|
|
45
|
-
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
46
|
-
val uncovered = Insets(
|
|
47
|
-
top = (value.top - paddingValue.top).coerceAtLeast(0.0),
|
|
48
|
-
right = (value.right - paddingValue.right).coerceAtLeast(0.0),
|
|
49
|
-
bottom = (value.bottom - paddingValue.bottom).coerceAtLeast(0.0),
|
|
50
|
-
left = (value.left - paddingValue.left).coerceAtLeast(0.0),
|
|
51
|
-
)
|
|
52
|
-
if (insets.put(screenId, uncovered) == uncovered) return
|
|
53
|
-
emitter.emitScreenInsetsChanged(screenId, toMap(uncovered))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** `{ top, right, bottom, left }`, empty before the screen was laid out. Any thread. */
|
|
57
|
-
fun get(screenId: String): WritableMap = insets[screenId]?.let(::toMap) ?: Arguments.createMap()
|
|
58
|
-
|
|
59
|
-
fun remove(screenId: String) {
|
|
60
|
-
insets.remove(screenId)
|
|
61
|
-
padding.remove(screenId)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private fun toMap(value: Insets): WritableMap = Arguments.createMap().apply {
|
|
65
|
-
putDouble(EventContract.ScreenInsetsChanged.TOP, value.top)
|
|
66
|
-
putDouble(EventContract.ScreenInsetsChanged.RIGHT, value.right)
|
|
67
|
-
putDouble(EventContract.ScreenInsetsChanged.BOTTOM, value.bottom)
|
|
68
|
-
putDouble(EventContract.ScreenInsetsChanged.LEFT, value.left)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.viewcontrollers.bottomtabs
|
|
2
|
-
|
|
3
|
-
import android.app.Activity
|
|
4
|
-
import android.app.Application
|
|
5
|
-
import android.os.Bundle
|
|
6
|
-
import android.view.View
|
|
7
|
-
import android.view.ViewGroup
|
|
8
|
-
import android.view.ViewTreeObserver
|
|
9
|
-
import androidx.core.view.ViewCompat
|
|
10
|
-
import androidx.core.view.WindowInsetsCompat
|
|
11
|
-
import dev.apexnative.navigation.NavigationActivity
|
|
12
|
-
import dev.apexnative.navigation.utils.UiUtils
|
|
13
|
-
import dev.apexnative.navigation.viewcontrollers.modal.ModalContainer
|
|
14
|
-
import dev.apexnative.navigation.views.bottomtabs.BottomTabsLayout
|
|
15
|
-
import dev.apexnative.navigation.views.bottomtabs.CustomTabRow
|
|
16
|
-
import java.util.WeakHashMap
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Puts the custom rows of the tabs in their place, as it works now: an observer of every activity of the process that
|
|
20
|
-
* touches only the navigation's activities; on each layout pass of such a window it finds the tabs with a row through
|
|
21
|
-
* the view tree, and puts each row in the window's content right above the layer holding its tabs (after the rows
|
|
22
|
-
* already there) — tabs in a modal: in the modal's own view, right above its root's view (or its sheet), so the row
|
|
23
|
-
* moves with the modal and newer modals cover it —, over the bar as [CustomTabRowGeometry] says — applied only when it
|
|
24
|
-
* changed, so UI tests reach idle. A row whose tabs left the window leaves it too, and comes back to its place as they
|
|
25
|
-
* do. Before each frame the row takes its tabs' alpha (a root that waits under the old one is transparent) and the
|
|
26
|
-
* motion of the bar's container, and stays out of accessibility and touches while they wait. Main thread only.
|
|
27
|
-
*/
|
|
28
|
-
internal object CustomTabRowPlacer : Application.ActivityLifecycleCallbacks {
|
|
29
|
-
private var registered = false
|
|
30
|
-
// The listeners of each observed activity's window.
|
|
31
|
-
private val observed = WeakHashMap<Activity, Listeners>()
|
|
32
|
-
// The rows placed at the last layout pass of each activity, with their tabs.
|
|
33
|
-
private val rows = WeakHashMap<CustomTabRow, BottomTabsLayout>()
|
|
34
|
-
|
|
35
|
-
private class Listeners(
|
|
36
|
-
val observer: ViewTreeObserver,
|
|
37
|
-
val layout: ViewTreeObserver.OnGlobalLayoutListener,
|
|
38
|
-
val draw: ViewTreeObserver.OnPreDrawListener,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
/** [activity] has tabs with a row: its window is observed from now on, and the process's later activities. */
|
|
42
|
-
fun track(activity: Activity) {
|
|
43
|
-
if (!registered) {
|
|
44
|
-
registered = true
|
|
45
|
-
activity.application?.registerActivityLifecycleCallbacks(this)
|
|
46
|
-
}
|
|
47
|
-
observe(activity)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** The tabs of [row] go: the row leaves the window. */
|
|
51
|
-
fun forget(row: CustomTabRow) {
|
|
52
|
-
rows.remove(row)
|
|
53
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
override fun onActivityResumed(activity: Activity) = observe(activity)
|
|
57
|
-
|
|
58
|
-
override fun onActivityDestroyed(activity: Activity) {
|
|
59
|
-
val listeners = observed.remove(activity) ?: return
|
|
60
|
-
if (!listeners.observer.isAlive) return
|
|
61
|
-
listeners.observer.removeOnGlobalLayoutListener(listeners.layout)
|
|
62
|
-
listeners.observer.removeOnPreDrawListener(listeners.draw)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
|
|
66
|
-
|
|
67
|
-
override fun onActivityStarted(activity: Activity) = Unit
|
|
68
|
-
|
|
69
|
-
override fun onActivityPaused(activity: Activity) = Unit
|
|
70
|
-
|
|
71
|
-
override fun onActivityStopped(activity: Activity) = Unit
|
|
72
|
-
|
|
73
|
-
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
|
|
74
|
-
|
|
75
|
-
// Only the navigation's activities: another activity's views are never looked for.
|
|
76
|
-
private fun observe(activity: Activity) {
|
|
77
|
-
if (activity !is NavigationActivity || observed.containsKey(activity)) return
|
|
78
|
-
val decor = activity.window?.decorView ?: return
|
|
79
|
-
val observer = decor.viewTreeObserver
|
|
80
|
-
val layout = ViewTreeObserver.OnGlobalLayoutListener { place(activity) }
|
|
81
|
-
val draw = ViewTreeObserver.OnPreDrawListener {
|
|
82
|
-
follow(activity)
|
|
83
|
-
true
|
|
84
|
-
}
|
|
85
|
-
observer.addOnGlobalLayoutListener(layout)
|
|
86
|
-
observer.addOnPreDrawListener(draw)
|
|
87
|
-
observed[activity] = Listeners(observer, layout, draw)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private fun contentOf(activity: Activity): ViewGroup? =
|
|
91
|
-
activity.window?.decorView?.findViewById(android.R.id.content)
|
|
92
|
-
|
|
93
|
-
// Each layout pass: the tabs with a row in the content, and the rows in their places.
|
|
94
|
-
private fun place(activity: NavigationActivity) {
|
|
95
|
-
val content = contentOf(activity) ?: return
|
|
96
|
-
val found = ArrayList<BottomTabsLayout>()
|
|
97
|
-
collect(content, found)
|
|
98
|
-
val placed = found.mapNotNull { tabs -> tabs.row?.also { place(activity, content, tabs, it) } }.toSet()
|
|
99
|
-
// A row whose tabs left the window leaves it too.
|
|
100
|
-
rows.entries.filter { (row, tabs) -> row !in placed && tabs.context === activity }.forEach { (row, _) ->
|
|
101
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private fun collect(view: View, found: MutableList<BottomTabsLayout>) {
|
|
106
|
-
if (view is CustomTabRow) return
|
|
107
|
-
if (view is BottomTabsLayout && view.row != null) found += view
|
|
108
|
-
if (view is ViewGroup) for (index in 0 until view.childCount) collect(view.getChildAt(index), found)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private fun place(activity: NavigationActivity, content: ViewGroup, tabs: BottomTabsLayout, row: CustomTabRow) {
|
|
112
|
-
rows[row] = tabs
|
|
113
|
-
val (host, layer) = placeIn(content, tabs) ?: return
|
|
114
|
-
if (row.parent !== host) {
|
|
115
|
-
(row.parent as? ViewGroup)?.removeView(row)
|
|
116
|
-
// Margins of the host's own kind: the host converts them (a frame or a coordinator layout).
|
|
117
|
-
host.addView(row, indexAbove(host, layer, row), ViewGroup.MarginLayoutParams(0, 0))
|
|
118
|
-
row.place = null
|
|
119
|
-
} else if (host.indexOfChild(row) != indexAbove(host, layer, row)) {
|
|
120
|
-
val params = row.layoutParams
|
|
121
|
-
host.removeView(row)
|
|
122
|
-
host.addView(row, indexAbove(host, layer, row), params)
|
|
123
|
-
}
|
|
124
|
-
row.showWith(tabs.bar)
|
|
125
|
-
if (tabs.bar.visibility == View.GONE || tabs.bar.width == 0) return
|
|
126
|
-
val place = placeOf(activity, host, tabs, row)
|
|
127
|
-
if (!CustomTabRowGeometry.needsPlacing(row.place, place)) return
|
|
128
|
-
row.place = place
|
|
129
|
-
val params = row.layoutParams as? ViewGroup.MarginLayoutParams ?: return
|
|
130
|
-
params.width = place.right - place.left
|
|
131
|
-
params.height = place.bottom - place.top
|
|
132
|
-
params.leftMargin = place.left
|
|
133
|
-
params.topMargin = place.top
|
|
134
|
-
row.layoutParams = params
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Over the bar: its edges less the margins, its bottom, the height of the content and the margin below it, in the
|
|
138
|
-
// coordinates of the row's [host].
|
|
139
|
-
private fun placeOf(
|
|
140
|
-
activity: Activity,
|
|
141
|
-
host: ViewGroup,
|
|
142
|
-
tabs: BottomTabsLayout,
|
|
143
|
-
row: CustomTabRow,
|
|
144
|
-
): CustomTabRowGeometry.Place {
|
|
145
|
-
val bar = IntArray(2).also(tabs.bar::getLocationInWindow)
|
|
146
|
-
val origin = IntArray(2).also(host::getLocationInWindow)
|
|
147
|
-
val options = row.options
|
|
148
|
-
val margin = UiUtils.dpToPixels(
|
|
149
|
-
activity,
|
|
150
|
-
options.horizontalMargin.get(CustomTabRowGeometry.HORIZONTAL_MARGIN_DP.toDouble()),
|
|
151
|
-
)
|
|
152
|
-
val height = options.height.get(null)?.let { UiUtils.dpToPixels(activity, it) }
|
|
153
|
-
val extra = UiUtils.dpToPixels(activity, CustomTabRowGeometry.EXTRA_HEIGHT_DP.toDouble())
|
|
154
|
-
// Where the bar rests: its container's motion (a ride, a slide, the hide on scroll) the row takes before each
|
|
155
|
-
// frame as its own translation.
|
|
156
|
-
val left = bar[0] - origin[0] - tabs.container.translationX.toInt()
|
|
157
|
-
val top = bar[1] - origin[1] - tabs.container.translationY.toInt()
|
|
158
|
-
// Never over the navigation bar's buttons: the bar is above them, and so is the row.
|
|
159
|
-
val navigationBar = if ((activity as? NavigationActivity)?.isEdgeToEdge == true) navigationBarOf(host) else 0
|
|
160
|
-
return CustomTabRowGeometry.place(
|
|
161
|
-
barLeft = left,
|
|
162
|
-
barRight = left + tabs.bar.width,
|
|
163
|
-
barBottom = minOf(top + tabs.bar.height, host.height - navigationBar),
|
|
164
|
-
margin = margin,
|
|
165
|
-
content = CustomTabRowGeometry.content(tabs.bar.height, height, extra),
|
|
166
|
-
bottomMargin = UiUtils.dpToPixels(activity, options.bottomMargin.get(0.0)),
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// The navigation bar at the bottom of the window, through the compat insets on every version.
|
|
171
|
-
private fun navigationBarOf(view: View): Int =
|
|
172
|
-
ViewCompat.getRootWindowInsets(view)?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
|
|
173
|
-
|
|
174
|
-
// Where the row of [tabs] goes, and the child there it goes right above: tabs in a modal, the modal's own view and
|
|
175
|
-
// the view in it that holds them (its root's, or its sheet's container); else the content and the layer of the
|
|
176
|
-
// root or of the overlays. A sheet's drag moves it without a layout: the row doesn't follow a drag.
|
|
177
|
-
private fun placeIn(content: ViewGroup, tabs: View): Pair<ViewGroup, View>? {
|
|
178
|
-
var current: View = tabs
|
|
179
|
-
while (true) {
|
|
180
|
-
val parent = current.parent as? ViewGroup ?: return null
|
|
181
|
-
if (parent is ModalContainer || parent === content) return parent to current
|
|
182
|
-
current = parent
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Right above [layer], after the rows already there.
|
|
187
|
-
private fun indexAbove(host: ViewGroup, layer: View, row: CustomTabRow): Int {
|
|
188
|
-
var index = host.indexOfChild(layer) + 1
|
|
189
|
-
while (index < host.childCount) {
|
|
190
|
-
val child = host.getChildAt(index)
|
|
191
|
-
if (child !is CustomTabRow || child === row) break
|
|
192
|
-
index++
|
|
193
|
-
}
|
|
194
|
-
return index
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Before each frame: the row takes the alpha of its tabs up to the view it is in and the container's translation,
|
|
198
|
-
// and leaves accessibility while they wait to show.
|
|
199
|
-
private fun follow(activity: Activity) {
|
|
200
|
-
val content = contentOf(activity) ?: return
|
|
201
|
-
for ((row, tabs) in rows) {
|
|
202
|
-
val host = row.parent as? View ?: continue
|
|
203
|
-
if (host !== content && host !is ModalContainer) continue
|
|
204
|
-
var alpha = tabs.container.alpha
|
|
205
|
-
var current: View? = tabs
|
|
206
|
-
while (current != null && current !== host) {
|
|
207
|
-
alpha *= current.alpha
|
|
208
|
-
current = current.parent as? View
|
|
209
|
-
}
|
|
210
|
-
if (row.alpha != alpha) row.alpha = alpha
|
|
211
|
-
// The row goes with the bar's container: a ride, a slide, the hide on scroll.
|
|
212
|
-
val container = tabs.container
|
|
213
|
-
if (row.translationX != container.translationX) row.translationX = container.translationX
|
|
214
|
-
if (row.translationY != container.translationY) row.translationY = container.translationY
|
|
215
|
-
val mode = if (row.hiddenFromAccessibility()) {
|
|
216
|
-
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
217
|
-
} else {
|
|
218
|
-
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
219
|
-
}
|
|
220
|
-
if (row.importantForAccessibility != mode) row.importantForAccessibility = mode
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.views.element
|
|
2
|
-
|
|
3
|
-
import android.annotation.SuppressLint
|
|
4
|
-
import android.content.Context
|
|
5
|
-
import android.graphics.Canvas
|
|
6
|
-
import android.view.MotionEvent
|
|
7
|
-
import android.view.View
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The empty view that stands in an element's place in its parent while the element is in the transition layer: the same
|
|
11
|
-
* id at the same index with the same layout, so Fabric finds the parent's children as it left them; React removing it
|
|
12
|
-
* removes the element for good. It has no `nativeID`, so no search finds it as the element. It draws nothing and takes
|
|
13
|
-
* no touches. Main thread only.
|
|
14
|
-
*/
|
|
15
|
-
@SuppressLint("ViewConstructor")
|
|
16
|
-
internal class ElementStub(context: Context, element: View) : View(context) {
|
|
17
|
-
init {
|
|
18
|
-
id = element.id
|
|
19
|
-
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
|
|
20
|
-
isClickable = false
|
|
21
|
-
isFocusable = false
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) =
|
|
25
|
-
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec))
|
|
26
|
-
|
|
27
|
-
override fun draw(canvas: Canvas) = Unit
|
|
28
|
-
|
|
29
|
-
@SuppressLint("ClickableViewAccessibility")
|
|
30
|
-
override fun onTouchEvent(event: MotionEvent?): Boolean = false
|
|
31
|
-
}
|