@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.10
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 +120 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +78 -25
- package/android/CORE.md +49 -25
- package/android/RECIPES.md +13 -6
- package/android/consumer-rules.pro +6 -0
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- 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/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -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/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- 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/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- 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/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- 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 +10 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- 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 +108 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
- 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/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
- 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 +83 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
- 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 +30 -20
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
- 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 +222 -48
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
- 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/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
- 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 +56 -41
- 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/sidemenu/SideMenuView.kt +12 -3
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- 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 -17
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -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 +125 -178
- 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/app.js +1 -1
- package/cli/doctor/checks/app.js +77 -14
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/migrate/native.js +18 -0
- package/cli/project.js +10 -2
- package/cli/setup/index.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/mainApplication.js +134 -19
- package/cli/setup/steps/metro.js +46 -0
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/cli/splash/index.js +3 -1
- 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 +58 -12
- package/docs-md/containers/modals.md +8 -4
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +19 -2
- package/docs-md/containers/tabs.md +5 -1
- package/docs-md/flows/bottom-sheets.md +4 -2
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- 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 +4 -3
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/help/glossary.md +4 -4
- package/docs-md/help/troubleshooting.md +44 -6
- package/docs-md/index.json +57 -1
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +9 -3
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +46 -2
- 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 +17 -12
- 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 +21 -3
- 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 +61 -13
- package/ios/Animations/ANNTransitionPlan.h +2 -2
- package/ios/Animations/ANNTransitionPlan.mm +10 -0
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +10 -8
- package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
- package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
- 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 +60 -24
- package/ios/CORE.md +44 -34
- package/ios/Contract/ANNCommandAnswer.h +13 -5
- package/ios/Contract/ANNCommandAnswer.mm +40 -32
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Contract/ANNCommandRunner.h +10 -9
- package/ios/Contract/ANNCommandRunner.mm +22 -28
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNAppDelegate.mm +0 -2
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNDeepLinkQueue.h +22 -2
- package/ios/Core/ANNDeepLinkQueue.mm +121 -14
- package/ios/Core/ANNErrorHandler.h +9 -4
- package/ios/Core/ANNErrorHandler.mm +20 -2
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +6 -2
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.h +6 -0
- package/ios/Core/ANNHinge.mm +15 -4
- package/ios/Core/ANNJavaScriptCalls.h +33 -0
- package/ios/Core/ANNJavaScriptCalls.mm +52 -0
- package/ios/Core/ANNLayoutProtocol.h +5 -5
- package/ios/Core/ANNNavigationState.h +7 -5
- package/ios/Core/ANNNavigationState.mm +8 -7
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNParking.h +5 -4
- package/ios/Core/ANNReloadCoordinator.mm +5 -12
- package/ios/Core/ANNRenderWait.h +20 -6
- package/ios/Core/ANNRenderWait.mm +143 -56
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Core/ANNUtils.h +7 -0
- package/ios/Core/ANNUtils.mm +10 -0
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Core/ApexNavigation.mm +7 -6
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
- package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
- package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- 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/ANNScreenPlace.h +53 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
- package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
- package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
- package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
- package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.h +8 -0
- package/ios/Layouts/Stack/ANNStackController.mm +184 -16
- package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- 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/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
- 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/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNOptionsReader.mm +108 -0
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Options/ANNSideMenuOptions.h +2 -0
- package/ios/Options/ANNSideMenuOptions.mm +2 -0
- package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
- package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -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 +15 -2
- package/ios/Options/Params/Image.mm +35 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +13 -6
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
- package/ios/React/ANNSurfaceHostingView.h +14 -0
- package/ios/React/ANNSurfaceHostingView.mm +144 -1
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/React/Slots/ANNSlotHost.mm +1 -3
- 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 +14 -8
- package/ios/TopBar/ANNBarButtons.mm +397 -80
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
- 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 +172 -21
- package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
- package/ios/TopBar/ANNTopBarPresenter.h +8 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +104 -33
- 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 +40 -27
- 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 +190 -66
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.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/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.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/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/api/linking/linking.js +11 -0
- package/lib/module/api/linking/linking.js.map +1 -1
- package/lib/module/api/navigation.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 +193 -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 +51 -9
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +20 -11
- 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 +49 -15
- 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/places.js +52 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/refresh.js +85 -0
- package/lib/module/engine/refresh.js.map +1 -0
- package/lib/module/engine/rememberedOptions.js +61 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +77 -16
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
- 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/commands/commands.d.ts.map +1 -1
- package/lib/typescript/api/commands/presentation.d.ts +4 -3
- package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.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/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- 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/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.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/options.d.ts +5 -2
- package/lib/typescript/engine/options.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/places.d.ts +7 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- 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 +4 -4
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +28 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/Options.d.ts +1 -1
- package/lib/typescript/interfaces/Options.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +80 -22
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +34 -26
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +17 -3
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +18 -11
- 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 +68 -38
- 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 +40 -27
- package/src/adapters/NativeANNTurboModule.ts +12 -2
- package/src/api/app/AppRegistry.ts +16 -2
- package/src/api/app/createNavigation.ts +203 -69
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/events/navigationEvents.ts +10 -4
- package/src/api/hooks/useNavigation.ts +9 -4
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/index.ts +1 -0
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/api/linking/linking.ts +22 -1
- package/src/api/navigation.ts +4 -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 +185 -42
- package/src/api/theme/theme.ts +5 -0
- package/src/engine/commands.ts +70 -13
- package/src/engine/layout.ts +27 -11
- package/src/engine/nativeScreens.ts +10 -1
- package/src/engine/options.ts +45 -19
- package/src/engine/optionsChange.ts +107 -0
- package/src/engine/places.ts +65 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/refresh.ts +97 -0
- package/src/engine/rememberedOptions.ts +74 -1
- package/src/engine/screens.tsx +76 -21
- package/src/interfaces/ComponentEvents.ts +4 -4
- package/src/interfaces/Events.ts +29 -10
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +81 -22
- package/src/interfaces/options/bottomTabs.ts +21 -7
- package/src/interfaces/options/buttons.ts +23 -15
- package/src/interfaces/options/modals.ts +34 -26
- package/src/interfaces/options/sideMenu.ts +24 -6
- package/src/interfaces/options/stack.ts +17 -3
- package/src/interfaces/options/system.ts +18 -11
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +68 -38
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
- 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 -138
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
- 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 -66
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
- package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
package/src/engine/layout.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { nextId } from './ids';
|
|
|
14
14
|
import { showNativeScreen } from './nativeScreens';
|
|
15
15
|
import { toNativeOptions } from './options';
|
|
16
16
|
import { setProps } from './props';
|
|
17
|
+
import { noteOwnOptions } from './rememberedOptions';
|
|
17
18
|
import { getStartInfo } from './native';
|
|
18
19
|
import { noteAlone } from './places';
|
|
19
20
|
import {
|
|
@@ -103,6 +104,13 @@ function screen(component: LayoutComponent, inPair = false, keyed = !inPair): La
|
|
|
103
104
|
if (nativeName) {
|
|
104
105
|
// A native screen: its props go to the native side as data, its own options over those of the show.
|
|
105
106
|
const options = takeButtonHandlers(id, component.options ?? {});
|
|
107
|
+
if (__DEV__) {
|
|
108
|
+
noteOwnOptions(
|
|
109
|
+
id,
|
|
110
|
+
name,
|
|
111
|
+
mergeOptions(screenOptions(name, props ?? {}), component.options ?? {})
|
|
112
|
+
);
|
|
113
|
+
}
|
|
106
114
|
const node = external({
|
|
107
115
|
id,
|
|
108
116
|
name: nativeName,
|
|
@@ -113,8 +121,9 @@ function screen(component: LayoutComponent, inPair = false, keyed = !inPair): La
|
|
|
113
121
|
}
|
|
114
122
|
// The screen's own options under those of the show (a command has them there already: merging again changes
|
|
115
123
|
// nothing).
|
|
116
|
-
const own = screenOptions(name, props ?? {});
|
|
117
|
-
|
|
124
|
+
const own = mergeOptions(screenOptions(name, props ?? {}), component.options ?? {});
|
|
125
|
+
noteOwnOptions(id, name, own);
|
|
126
|
+
const options = takeButtonHandlers(id, own);
|
|
118
127
|
const key = keyed ? screenKey(name, props ?? {}) : undefined;
|
|
119
128
|
setProps(id, props);
|
|
120
129
|
return {
|
|
@@ -122,7 +131,7 @@ function screen(component: LayoutComponent, inPair = false, keyed = !inPair): La
|
|
|
122
131
|
type: 'Component',
|
|
123
132
|
data: {
|
|
124
133
|
name: rendersInSlot(name) ? slotName(id, name) : name,
|
|
125
|
-
options: toNativeOptions(options),
|
|
134
|
+
options: toNativeOptions(options, id),
|
|
126
135
|
...(key !== undefined && { key }),
|
|
127
136
|
},
|
|
128
137
|
children: [],
|
|
@@ -167,12 +176,13 @@ function arrangement(
|
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
function external(component: ExternalComponent): LayoutNode {
|
|
179
|
+
const id = component.id || nextId('ExternalComponent');
|
|
170
180
|
return {
|
|
171
|
-
id
|
|
181
|
+
id,
|
|
172
182
|
type: 'ExternalComponent',
|
|
173
183
|
data: {
|
|
174
184
|
name: String(component.name),
|
|
175
|
-
options: toNativeOptions(component.options),
|
|
185
|
+
options: toNativeOptions(component.options, id),
|
|
176
186
|
passProps: component.passProps,
|
|
177
187
|
},
|
|
178
188
|
children: [],
|
|
@@ -185,10 +195,11 @@ function parent(
|
|
|
185
195
|
options: Options | undefined,
|
|
186
196
|
children: Layout[] = []
|
|
187
197
|
): LayoutNode {
|
|
198
|
+
const nodeId = id || nextId(type);
|
|
188
199
|
return {
|
|
189
|
-
id:
|
|
200
|
+
id: nodeId,
|
|
190
201
|
type,
|
|
191
|
-
data: { options: toNativeOptions(options) },
|
|
202
|
+
data: { options: toNativeOptions(options, nodeId) },
|
|
192
203
|
children: children.map(toNativeLayout),
|
|
193
204
|
};
|
|
194
205
|
}
|
|
@@ -213,10 +224,11 @@ function sideMenu(menu: LayoutSideMenu): LayoutNode {
|
|
|
213
224
|
data: {},
|
|
214
225
|
children: [toNativeLayout(content)],
|
|
215
226
|
});
|
|
227
|
+
const id = menu.id || nextId('SideMenuRoot');
|
|
216
228
|
return {
|
|
217
|
-
id
|
|
229
|
+
id,
|
|
218
230
|
type: 'SideMenuRoot',
|
|
219
|
-
data: { options: toNativeOptions(menu.options) },
|
|
231
|
+
data: { options: toNativeOptions(menu.options, id) },
|
|
220
232
|
children: [
|
|
221
233
|
...(menu.left ? [side('SideMenuLeft', menu.left)] : []),
|
|
222
234
|
side('SideMenuCenter', menu.center),
|
|
@@ -238,10 +250,14 @@ function splitView(split: LayoutSplitView): LayoutNode {
|
|
|
238
250
|
] as [string, Layout | undefined][]
|
|
239
251
|
).filter((column): column is [string, Layout] => column[1] !== undefined);
|
|
240
252
|
const present = split.master && split.detail ? columns : [];
|
|
253
|
+
const id = split.id || nextId('SplitView');
|
|
241
254
|
return {
|
|
242
|
-
id
|
|
255
|
+
id,
|
|
243
256
|
type: 'SplitView',
|
|
244
|
-
data: {
|
|
257
|
+
data: {
|
|
258
|
+
options: toNativeOptions(split.options, id),
|
|
259
|
+
columns: present.map(([column]) => column),
|
|
260
|
+
},
|
|
245
261
|
children: present.map(([, content]) => toNativeLayout(content)),
|
|
246
262
|
};
|
|
247
263
|
}
|
|
@@ -38,6 +38,8 @@ interface NativeProps {
|
|
|
38
38
|
interface OpenScreen {
|
|
39
39
|
id: string;
|
|
40
40
|
name: string;
|
|
41
|
+
/** The props the command gave, as they are. */
|
|
42
|
+
given: object;
|
|
41
43
|
props: NativeProps;
|
|
42
44
|
/** The data the native side has, and the names of the functions; none before the command sends the screen. */
|
|
43
45
|
sent?: { data: Map<string, string>; functions: string };
|
|
@@ -78,7 +80,7 @@ export const nativeScreenHooks = {
|
|
|
78
80
|
* screen with `useProps` starts its hook, and its props go in once the hook has returned (`whenNativeScreensReady`).
|
|
79
81
|
*/
|
|
80
82
|
export function showNativeScreen(node: LayoutNode, name: string, props: object): void {
|
|
81
|
-
const screen: OpenScreen = { id: node.id, name, props: toNativeProps(props) };
|
|
83
|
+
const screen: OpenScreen = { id: node.id, name, given: props, props: toNativeProps(props) };
|
|
82
84
|
const Controller = nativeScreenController(name);
|
|
83
85
|
if (Controller) {
|
|
84
86
|
screen.first = deferred();
|
|
@@ -135,6 +137,13 @@ export function callNativeScreenFunction(id: string, name: string, args: unknown
|
|
|
135
137
|
return fn(...args);
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
/** The native screens with the name that are open, each with the props its command gave. */
|
|
141
|
+
export function openNativeScreens(name: string): { id: string; props: object }[] {
|
|
142
|
+
return [...screens.values()]
|
|
143
|
+
.filter((screen) => screen.name === name)
|
|
144
|
+
.map((screen) => ({ id: screen.id, props: screen.given }));
|
|
145
|
+
}
|
|
146
|
+
|
|
138
147
|
/** The native screen with the id, for the navigation of its calls. */
|
|
139
148
|
export function nativeScreenInfo(id: string): { id: string; name: string } | undefined {
|
|
140
149
|
const screen = screens.get(id);
|
package/src/engine/options.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Image, Platform, processColor } from 'react-native';
|
|
2
2
|
import type { ColorValue, ImageSourcePropType } from 'react-native';
|
|
3
3
|
import { nextId } from './ids';
|
|
4
|
-
import { rememberButtonRoot, setProps } from './props';
|
|
4
|
+
import { rememberButtonRoot, rememberOptionsComponent, setProps } from './props';
|
|
5
5
|
|
|
6
6
|
type Fields = Record<string, unknown>;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The options as the native side reads them: colors in the format of the platform, images resolved, and every
|
|
10
10
|
* component in them with an id of its own (its props stay in JavaScript). Options come in their own form only:
|
|
11
|
-
* animations with `enter` and `exit`, `searchBar` and `interpolation` as objects.
|
|
11
|
+
* animations with `enter` and `exit`, `searchBar` and `interpolation` as objects. `owner` is the id of the node the
|
|
12
|
+
* options are for, or `'defaultOptions'`: a component without an id of its own gets one made of the owner, its place
|
|
13
|
+
* in the options and its name, the same for every `mergeOptions` of the node, so the native side keeps the mounted
|
|
14
|
+
* component and only its props change. Without an owner each conversion gives it a new one.
|
|
12
15
|
*/
|
|
13
|
-
export function toNativeOptions<T>(options: T): T {
|
|
14
|
-
return convert(options) as T;
|
|
16
|
+
export function toNativeOptions<T>(options: T, owner?: string): T {
|
|
17
|
+
return convert(options, undefined, { owner, path: '' }) as T;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Where a value is in the options being converted: the node they are for, and the path to the value
|
|
21
|
+
// (`topBar.rightButtons[0].component`).
|
|
22
|
+
interface Place {
|
|
23
|
+
owner: string | undefined;
|
|
24
|
+
path: string;
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
/**
|
|
@@ -35,11 +45,16 @@ function isGroup(value: unknown): value is Fields {
|
|
|
35
45
|
return isFields(value) && !Array.isArray(value);
|
|
36
46
|
}
|
|
37
47
|
|
|
38
|
-
function convert(value: unknown, key
|
|
48
|
+
function convert(value: unknown, key: string | undefined, place: Place): unknown {
|
|
39
49
|
if (key !== undefined && isColor(key)) return nativeColor(value);
|
|
40
50
|
if (key !== undefined && isImage(key)) return nativeImage(value);
|
|
41
51
|
if (Array.isArray(value)) {
|
|
42
|
-
|
|
52
|
+
// An item is known by its id where it has one (a button, a suggestion), so a component keeps its root when the
|
|
53
|
+
// list around it changes; by its place in the list otherwise.
|
|
54
|
+
const items = value.map((item, index) => {
|
|
55
|
+
const id = isFields(item) && typeof item.id === 'string' && item.id ? item.id : index;
|
|
56
|
+
return convert(item, undefined, { ...place, path: `${place.path}[${id}]` });
|
|
57
|
+
});
|
|
43
58
|
if (key?.endsWith('Buttons') || key === 'buttons') items.forEach(noteButtonRoot);
|
|
44
59
|
return key?.endsWith('Buttons') ? items.map(takeButtonProps) : items;
|
|
45
60
|
}
|
|
@@ -47,9 +62,12 @@ function convert(value: unknown, key?: string): unknown {
|
|
|
47
62
|
const result: Fields = {};
|
|
48
63
|
for (const [name, item] of Object.entries(withSymbols(value))) {
|
|
49
64
|
// The props of a component are its own, not options.
|
|
50
|
-
|
|
65
|
+
const path = place.path ? `${place.path}.${name}` : name;
|
|
66
|
+
result[name] = name === 'passProps' ? item : convert(item, name, { ...place, path });
|
|
51
67
|
}
|
|
52
|
-
return key === 'component' || key === 'resultsComponent'
|
|
68
|
+
return key === 'component' || key === 'resultsComponent'
|
|
69
|
+
? takeComponentProps(result, place)
|
|
70
|
+
: result;
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
function isColor(key: string): boolean {
|
|
@@ -105,13 +123,23 @@ function isFields(value: unknown): value is Fields {
|
|
|
105
123
|
return typeof value === 'object' && value !== null;
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
// A component in the options gets an id; the native side creates it with that id, and its props wait here.
|
|
109
|
-
|
|
110
|
-
|
|
126
|
+
// A component in the options gets an id; the native side creates it with that id, and its props wait here. Without
|
|
127
|
+
// an id of its own it is the owner's, the place of the component (`topBar.title`, `topBar.rightButtons[Save]` by the
|
|
128
|
+
// button's id, `topBar.searchBar.resultsComponent`) and its name: another name there is another component.
|
|
129
|
+
function takeComponentProps({ passProps, ...component }: Fields, place: Place): Fields {
|
|
130
|
+
const componentId = (component.id as string | undefined) || componentIdAt(place, component.name);
|
|
111
131
|
if (passProps) setProps(componentId, passProps as object);
|
|
112
132
|
return { ...component, componentId };
|
|
113
133
|
}
|
|
114
134
|
|
|
135
|
+
function componentIdAt({ owner, path }: Place, name: unknown): string {
|
|
136
|
+
if (owner === undefined) return nextId('CustomComponent');
|
|
137
|
+
const at = path.endsWith('.component') ? path.slice(0, -'.component'.length) : path;
|
|
138
|
+
const id = `${owner}/${at}/${String(name)}`;
|
|
139
|
+
rememberOptionsComponent(owner, id);
|
|
140
|
+
return id;
|
|
141
|
+
}
|
|
142
|
+
|
|
115
143
|
// The component of a bar button (the top bar's `*Buttons`, the toolbar's `buttons`) is a root the native side only
|
|
116
144
|
// sizes: its wrapper centers the content in the button's slot.
|
|
117
145
|
function noteButtonRoot(button: unknown): void {
|
|
@@ -134,19 +162,17 @@ function nativeColor(value: unknown): unknown {
|
|
|
134
162
|
return Platform.OS === 'ios' ? iosColor(value) : androidColor(value);
|
|
135
163
|
}
|
|
136
164
|
|
|
137
|
-
// One color, a pair for the light and the dark appearance, or a semantic color; null takes the color away.
|
|
165
|
+
// One color, a pair for the light and the dark appearance, or a semantic color; null takes the color away. A pair goes
|
|
166
|
+
// as `{ light, dark }`, an app's `DynamicColorIOS` too; a side without a color is left out and shows the platform's.
|
|
138
167
|
function iosColor(value: unknown): unknown {
|
|
139
168
|
if (value === null) return 'NoColor';
|
|
140
169
|
if (!isFields(value)) return processColor(value as ColorValue);
|
|
141
170
|
if ('semantic' in value) return value;
|
|
142
171
|
const pair = ('dynamic' in value ? value.dynamic : value) as {
|
|
143
|
-
light
|
|
144
|
-
dark
|
|
172
|
+
light?: ColorValue;
|
|
173
|
+
dark?: ColorValue;
|
|
145
174
|
};
|
|
146
|
-
return
|
|
147
|
-
light: processColor(pair.light) as ColorValue,
|
|
148
|
-
dark: processColor(pair.dark) as ColorValue,
|
|
149
|
-
});
|
|
175
|
+
return { light: processColor(pair.light), dark: processColor(pair.dark) };
|
|
150
176
|
}
|
|
151
177
|
|
|
152
178
|
// Android always takes a pair; one color goes to both, and the side without a color has none.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Options } from '../interfaces/Options';
|
|
2
|
+
|
|
3
|
+
/** What an edit of a screen's options changed: the options to merge, and the paths of the options it took out. */
|
|
4
|
+
export interface OptionsChange {
|
|
5
|
+
/** The options that are new or have another value; undefined when none. */
|
|
6
|
+
merge?: Options;
|
|
7
|
+
/** The paths of the options set before and not now, such as `['topBar', 'subtitle']`. */
|
|
8
|
+
removed: string[][];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* What `next` changes of `previous`, both the options of one screen. Objects compare key by key; anything else, an
|
|
13
|
+
* array such as buttons too, changes as a whole, and a function by identity (`sameValue`).
|
|
14
|
+
*/
|
|
15
|
+
export function optionsChange(previous: Options, next: Options): OptionsChange {
|
|
16
|
+
const removed: string[][] = [];
|
|
17
|
+
const merge = changed(previous, next, [], removed) as Options | undefined;
|
|
18
|
+
return merge ? { merge, removed } : { removed };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function changed(previous: unknown, next: unknown, path: string[], removed: string[][]): unknown {
|
|
22
|
+
if (isWholeValue(path) && isPlainObject(previous) && isPlainObject(next)) {
|
|
23
|
+
if (sameValue(previous, next)) return undefined;
|
|
24
|
+
// A part of it taken out: the native side may merge the parts, so the value goes first.
|
|
25
|
+
if (Object.keys(previous).some((key) => next[key] === undefined)) removed.push(path);
|
|
26
|
+
return next;
|
|
27
|
+
}
|
|
28
|
+
if (!isPlainObject(previous) || !isPlainObject(next)) {
|
|
29
|
+
return sameValue(previous, next) ? undefined : next;
|
|
30
|
+
}
|
|
31
|
+
const result: Record<string, unknown> = {};
|
|
32
|
+
for (const [key, value] of Object.entries(next)) {
|
|
33
|
+
if (value === undefined) continue;
|
|
34
|
+
const change = changed(previous[key], value, [...path, key], removed);
|
|
35
|
+
if (change !== undefined) result[key] = change;
|
|
36
|
+
}
|
|
37
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
38
|
+
if (value !== undefined && next[key] === undefined) removed.push([...path, key]);
|
|
39
|
+
}
|
|
40
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// A color (`{ light, dark }`), an icon or an image, and a menu are one value each on the native side, not a group: a
|
|
44
|
+
// part of one taken out goes as the whole value again.
|
|
45
|
+
function isWholeValue(path: string[]): boolean {
|
|
46
|
+
const key = path[path.length - 1];
|
|
47
|
+
return key !== undefined && /^(color|icon|image|menu)$|(Color|Icon|Image)$/.test(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Whether two values are the same: plain objects key by key, arrays item by item, anything else, functions too, by
|
|
52
|
+
* identity. A module that ran again makes its functions anew, so they count as changed: Hermes keeps no source to tell
|
|
53
|
+
* an edited one, and sending a button's handler again costs little. With `functionsAlike` any two functions are alike.
|
|
54
|
+
*/
|
|
55
|
+
export function sameValue(a: unknown, b: unknown, functionsAlike = false): boolean {
|
|
56
|
+
if (functionsAlike && typeof a === 'function' && typeof b === 'function') return true;
|
|
57
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
58
|
+
return (
|
|
59
|
+
a.length === b.length && a.every((item, index) => sameValue(item, b[index], functionsAlike))
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
63
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
64
|
+
return [...keys].every((key) => sameValue(a[key], b[key], functionsAlike));
|
|
65
|
+
}
|
|
66
|
+
return Object.is(a, b);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
70
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
71
|
+
const prototype = Object.getPrototypeOf(value);
|
|
72
|
+
return prototype === Object.prototype || prototype === null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The part of an edit's change that the screen shows the old definition's value of: where the command that showed it,
|
|
77
|
+
* or a merge since, set another value, that value stays. `before` is what the old definition gave, `own` the screen's
|
|
78
|
+
* own options now.
|
|
79
|
+
*/
|
|
80
|
+
export function changeOverOwn(change: OptionsChange, before: Options, own: Options): OptionsChange {
|
|
81
|
+
// The functions of the definition are made anew each time it is read (a chain's button handlers): any function
|
|
82
|
+
// there stands for the definition's.
|
|
83
|
+
const fromDefinition = (path: string[]) =>
|
|
84
|
+
sameValue(valueAt(own, path), valueAt(before, path), true);
|
|
85
|
+
const removed = change.removed.filter(fromDefinition);
|
|
86
|
+
const merge =
|
|
87
|
+
change.merge && (keptWhere(change.merge, [], fromDefinition) as Options | undefined);
|
|
88
|
+
return merge ? { merge, removed } : { removed };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function keptWhere(value: unknown, path: string[], keep: (path: string[]) => boolean): unknown {
|
|
92
|
+
if (!isPlainObject(value) || isWholeValue(path)) return keep(path) ? value : undefined;
|
|
93
|
+
const result: Record<string, unknown> = {};
|
|
94
|
+
for (const [key, item] of Object.entries(value)) {
|
|
95
|
+
const kept = keptWhere(item, [...path, key], keep);
|
|
96
|
+
if (kept !== undefined) result[key] = kept;
|
|
97
|
+
}
|
|
98
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The value at a path of options, such as `['topBar', 'title', 'text']`; undefined where there is none. */
|
|
102
|
+
export function valueAt(options: unknown, path: readonly string[]): unknown {
|
|
103
|
+
return path.reduce<unknown>(
|
|
104
|
+
(value, key) => (isPlainObject(value) ? value[key] : undefined),
|
|
105
|
+
options
|
|
106
|
+
);
|
|
107
|
+
}
|
package/src/engine/places.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SplitViewColumnsStackedEvent } from '../interfaces/Events';
|
|
2
2
|
import type { LayoutNode } from './layout';
|
|
3
3
|
import { onNativeEvent } from './native';
|
|
4
|
+
import { forgetProps } from './props';
|
|
4
5
|
import { screenNameOf } from './slots';
|
|
5
6
|
|
|
6
7
|
// Where each screen is, noted as the engine builds the layouts of the commands: what it shows in and its place in its
|
|
@@ -51,6 +52,11 @@ const stackedSplits = new Set<string>();
|
|
|
51
52
|
let listeningToSplitViews = false;
|
|
52
53
|
// The primaries of pairs shown alone, noted as their node is built, until their place is noted.
|
|
53
54
|
const alone = new Set<string>();
|
|
55
|
+
// The layouts each screen shows in (its stack, pair, tabs, menu, split view, and the root of its layer), and how many
|
|
56
|
+
// live screens each layout holds. A layout whose last screen went is gone, and with it the props of the components the
|
|
57
|
+
// library named in its options: they stay as long as any of its screens may show them again.
|
|
58
|
+
const layoutsOfScreen = new Map<string, readonly string[]>();
|
|
59
|
+
const screensInLayout = new Map<string, number>();
|
|
54
60
|
// The last screens that went, so a command from one of them can say so; a screen the engine never saw is not one.
|
|
55
61
|
const gone = new Set<string>();
|
|
56
62
|
const GONE_KEPT = 200;
|
|
@@ -59,6 +65,15 @@ export function placeOf(screenId: string): ScreenPlace | undefined {
|
|
|
59
65
|
return places.get(screenId);
|
|
60
66
|
}
|
|
61
67
|
|
|
68
|
+
/** The first screen of a stack, as the engine noted it; with a pair first, its primary. */
|
|
69
|
+
export function firstScreenOf(stack: string): string | undefined {
|
|
70
|
+
for (const [id, place] of places) {
|
|
71
|
+
if (place.stack === stack && place.index === 0 && place.arrangement?.placement !== 'secondary')
|
|
72
|
+
return id;
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
62
77
|
/** Notes that a screen is the primary of a pair shown alone, where the native side shows no pairs. */
|
|
63
78
|
export function noteAlone(screenId: string): void {
|
|
64
79
|
alone.add(screenId);
|
|
@@ -69,9 +84,15 @@ export function isGone(screenId: string): boolean {
|
|
|
69
84
|
return gone.has(screenId);
|
|
70
85
|
}
|
|
71
86
|
|
|
87
|
+
/** The layouts the screen shows in, outermost first: those whose screens come with it in a command go in it too. */
|
|
88
|
+
export function layoutsOf(screenId: string): readonly string[] {
|
|
89
|
+
return layoutsOfScreen.get(screenId) ?? [];
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
/**
|
|
73
93
|
* Notes the screens of a layout, the first of a stack at `index`. A modal or an overlay given as a whole is a layer of
|
|
74
|
-
* its own; screens added to one, such as a push, take the layer of the screen they come from
|
|
94
|
+
* its own; screens added to one, such as a push, take the layer of the screen they come from, and `within`, the
|
|
95
|
+
* layouts they show in (`layoutsOf` that screen).
|
|
75
96
|
*/
|
|
76
97
|
export function notePlaces(
|
|
77
98
|
node: LayoutNode,
|
|
@@ -79,12 +100,14 @@ export function notePlaces(
|
|
|
79
100
|
stack: string | null = null,
|
|
80
101
|
index = 0,
|
|
81
102
|
menu?: ScreenPlace['menu'],
|
|
82
|
-
layer: string = container === 'root' ? 'root' : node.id
|
|
103
|
+
layer: string = container === 'root' ? 'root' : node.id,
|
|
104
|
+
within: readonly string[] = []
|
|
83
105
|
): void {
|
|
84
106
|
if (node.type === 'Component' || node.type === 'ExternalComponent') {
|
|
85
107
|
const name = node.data.name ?? '';
|
|
86
108
|
gone.delete(node.id);
|
|
87
109
|
columnOfScreen.delete(node.id);
|
|
110
|
+
noteLayouts(node.id, within);
|
|
88
111
|
places.set(node.id, {
|
|
89
112
|
name: screenNameOf(name),
|
|
90
113
|
container,
|
|
@@ -99,7 +122,7 @@ export function notePlaces(
|
|
|
99
122
|
} else if (node.type === 'Arrangement') {
|
|
100
123
|
// One entry of its stack: both screens have its place there, and each knows the pair.
|
|
101
124
|
node.children.forEach((child, childIndex) => {
|
|
102
|
-
notePlaces(child, container, stack, index, menu, layer);
|
|
125
|
+
notePlaces(child, container, stack, index, menu, layer, [...within, node.id]);
|
|
103
126
|
const place = places.get(child.id);
|
|
104
127
|
if (place) {
|
|
105
128
|
const placement = childIndex === 0 ? 'primary' : 'secondary';
|
|
@@ -109,7 +132,7 @@ export function notePlaces(
|
|
|
109
132
|
} else if (node.type === 'Stack') {
|
|
110
133
|
columnOfStack.delete(node.id);
|
|
111
134
|
node.children.forEach((child, childIndex) =>
|
|
112
|
-
notePlaces(child, container, node.id, childIndex, menu, layer)
|
|
135
|
+
notePlaces(child, container, node.id, childIndex, menu, layer, [...within, node.id])
|
|
113
136
|
);
|
|
114
137
|
} else if (node.type === 'SplitView') {
|
|
115
138
|
// A split view sent again with its id starts anew: its columns are noted again, and it isn't one stack until the
|
|
@@ -118,7 +141,7 @@ export function notePlaces(
|
|
|
118
141
|
const columns = node.data.columns ?? [];
|
|
119
142
|
const stacks: Partial<Record<string, string>> = {};
|
|
120
143
|
node.children.forEach((child, childIndex) => {
|
|
121
|
-
notePlaces(child, container, null, 0, menu, layer);
|
|
144
|
+
notePlaces(child, container, null, 0, menu, layer, [...within, node.id]);
|
|
122
145
|
const column = columns[childIndex];
|
|
123
146
|
if (!column) return;
|
|
124
147
|
if (child.type === 'Stack') stacks[column] = child.id;
|
|
@@ -128,12 +151,46 @@ export function notePlaces(
|
|
|
128
151
|
} else if (node.type === 'SideMenuRoot') {
|
|
129
152
|
for (const part of node.children) {
|
|
130
153
|
const side = MENU_PARTS[part.type];
|
|
154
|
+
const parts = [...within, node.id, part.id];
|
|
131
155
|
part.children.forEach((child) =>
|
|
132
|
-
notePlaces(
|
|
156
|
+
notePlaces(
|
|
157
|
+
child,
|
|
158
|
+
container,
|
|
159
|
+
null,
|
|
160
|
+
0,
|
|
161
|
+
side ? { id: node.id, part: side } : menu,
|
|
162
|
+
layer,
|
|
163
|
+
parts
|
|
164
|
+
)
|
|
133
165
|
);
|
|
134
166
|
}
|
|
135
167
|
} else {
|
|
136
|
-
node.children.forEach((child) =>
|
|
168
|
+
node.children.forEach((child) =>
|
|
169
|
+
notePlaces(child, container, null, 0, menu, layer, [...within, node.id])
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// A screen noted again under its id (a layout sent again) leaves the layouts it was in before.
|
|
175
|
+
function noteLayouts(screenId: string, within: readonly string[]): void {
|
|
176
|
+
leaveLayouts(screenId);
|
|
177
|
+
const layouts = [...new Set(within)];
|
|
178
|
+
layoutsOfScreen.set(screenId, layouts);
|
|
179
|
+
for (const layout of layouts) screensInLayout.set(layout, (screensInLayout.get(layout) ?? 0) + 1);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function leaveLayouts(screenId: string): void {
|
|
183
|
+
const layouts = layoutsOfScreen.get(screenId);
|
|
184
|
+
if (!layouts) return;
|
|
185
|
+
layoutsOfScreen.delete(screenId);
|
|
186
|
+
for (const layout of layouts) {
|
|
187
|
+
const count = (screensInLayout.get(layout) ?? 1) - 1;
|
|
188
|
+
if (count > 0) {
|
|
189
|
+
screensInLayout.set(layout, count);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
screensInLayout.delete(layout);
|
|
193
|
+
forgetProps(layout);
|
|
137
194
|
}
|
|
138
195
|
}
|
|
139
196
|
|
|
@@ -198,6 +255,7 @@ export function listenToSplitViews(): void {
|
|
|
198
255
|
|
|
199
256
|
/** The screen is gone. */
|
|
200
257
|
export function forgetPlace(screenId: string): void {
|
|
258
|
+
leaveLayouts(screenId);
|
|
201
259
|
places.delete(screenId);
|
|
202
260
|
columnOfScreen.delete(screenId);
|
|
203
261
|
gone.add(screenId);
|
package/src/engine/props.ts
CHANGED
|
@@ -7,6 +7,11 @@ const watchers = new Map<string, Set<() => void>>();
|
|
|
7
7
|
const none = {};
|
|
8
8
|
// The roots that are the components of bar buttons: their wrapper centers the content in the button's slot.
|
|
9
9
|
const buttonRoots = new Set<string>();
|
|
10
|
+
// The ids the library gave components in options, by the node whose options they are in. Such an id stays the same
|
|
11
|
+
// for every show of the node and may have several roots at once (a component of the default or a stack's options):
|
|
12
|
+
// its props go with the node, not with a root.
|
|
13
|
+
const optionComponents = new Map<string, Set<string>>();
|
|
14
|
+
const optionComponentIds = new Set<string>();
|
|
10
15
|
|
|
11
16
|
export function setProps(id: string, props: object | undefined): void {
|
|
12
17
|
if (props === undefined) byId.delete(id);
|
|
@@ -38,8 +43,32 @@ export function isButtonRoot(id: string): boolean {
|
|
|
38
43
|
return buttonRoots.has(id);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
/**
|
|
46
|
+
/** Notes an id the library gave a component in the options of the node `owner`. */
|
|
47
|
+
export function rememberOptionsComponent(owner: string, id: string): void {
|
|
48
|
+
let ids = optionComponents.get(owner);
|
|
49
|
+
if (!ids) optionComponents.set(owner, (ids = new Set()));
|
|
50
|
+
ids.add(id);
|
|
51
|
+
optionComponentIds.add(id);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Whether the library gave the id to a component in options: its props go with the node, not with a root. */
|
|
55
|
+
export function isOptionsComponent(id: string): boolean {
|
|
56
|
+
return optionComponentIds.has(id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The view is gone: its props, and whether it is a button's root, are not needed again; nor are those of the
|
|
61
|
+
* components the library named in its options.
|
|
62
|
+
*/
|
|
42
63
|
export function forgetProps(id: string): void {
|
|
43
64
|
byId.delete(id);
|
|
44
65
|
buttonRoots.delete(id);
|
|
66
|
+
const ids = optionComponents.get(id);
|
|
67
|
+
if (!ids) return;
|
|
68
|
+
optionComponents.delete(id);
|
|
69
|
+
for (const component of ids) {
|
|
70
|
+
byId.delete(component);
|
|
71
|
+
buttonRoots.delete(component);
|
|
72
|
+
optionComponentIds.delete(component);
|
|
73
|
+
}
|
|
45
74
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Fast Refresh runs an edited module again, and every component it exports is a new function. React Refresh keeps
|
|
2
|
+
// the versions of one component in a family: Metro registers each export under its module and name, and React renders
|
|
3
|
+
// the newest version of the family in place of the old one. What the library keeps of a screen (its options, its key,
|
|
4
|
+
// its pair) is read through the same family, so an edit reaches it without a reload.
|
|
5
|
+
|
|
6
|
+
/** The versions of one component React Refresh keeps, `current` the newest. */
|
|
7
|
+
interface Family {
|
|
8
|
+
current: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ReactRefresh {
|
|
12
|
+
getFamilyByType?: (type: unknown) => Family | undefined;
|
|
13
|
+
register?: (type: unknown, id: string) => void;
|
|
14
|
+
createSignatureFunctionForTransform?: () => (
|
|
15
|
+
type: unknown,
|
|
16
|
+
key: string,
|
|
17
|
+
forceReset?: boolean
|
|
18
|
+
) => unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// React Native puts React Refresh where Metro's module system finds it, in development only.
|
|
22
|
+
function reactRefresh(): ReactRefresh | undefined {
|
|
23
|
+
if (!__DEV__) return undefined;
|
|
24
|
+
const global = globalThis as { __METRO_GLOBAL_PREFIX__?: string } & Record<string, unknown>;
|
|
25
|
+
return global[`${global.__METRO_GLOBAL_PREFIX__ ?? ''}__ReactRefresh`] as
|
|
26
|
+
ReactRefresh | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Whether React Refresh runs: development with Metro. */
|
|
30
|
+
export function refreshRuns(): boolean {
|
|
31
|
+
return reactRefresh()?.getFamilyByType !== undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The family a component's versions are kept in; undefined in a release build or for a value Metro didn't export. */
|
|
35
|
+
export function familyOf(type: unknown): Family | undefined {
|
|
36
|
+
return reactRefresh()?.getFamilyByType?.(type);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The newest version of a component after Fast Refresh ran its module again; the component itself when there is none
|
|
41
|
+
* newer, and in a release build.
|
|
42
|
+
*/
|
|
43
|
+
export function newestType<T extends object>(type: T): T {
|
|
44
|
+
return (familyOf(type)?.current as T | undefined) ?? type;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let redefinedListener: ((screen: object) => void) | undefined;
|
|
48
|
+
|
|
49
|
+
/** Sets what runs when a module makes a screen again: Fast Refresh ran it after an edit. */
|
|
50
|
+
export function onRedefined(listener: (screen: object) => void): void {
|
|
51
|
+
redefinedListener = listener;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Tells about a screen a module made, once the module ran: Metro registers its exports after it, so the family of the
|
|
56
|
+
* screen is known by then, and a new version of a screen that shows is found by it. Development only.
|
|
57
|
+
*/
|
|
58
|
+
export function redefined(screen: object): void {
|
|
59
|
+
if (!__DEV__ || !redefinedListener) return;
|
|
60
|
+
const listener = redefinedListener;
|
|
61
|
+
Promise.resolve().then(() => listener(screen));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The id each family of screens gives the components they render, so their versions join one family too.
|
|
65
|
+
const innerIds = new WeakMap<Family, string>();
|
|
66
|
+
let innerCount = 0;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Puts a component a screen or the app renders (`owner`: the screen, or the app made by createNavigation; `role`: which
|
|
70
|
+
* of its components) in a family of its own, once the owner's module ran and Metro has given the owner its family: the
|
|
71
|
+
* next version of the owner registers its component under the same id, so React Refresh keeps the component's state
|
|
72
|
+
* when the module runs again, also when the module doesn't export it. A component React Refresh knows already (its
|
|
73
|
+
* module exports it, or Babel registered it) keeps its own family. Development only.
|
|
74
|
+
*/
|
|
75
|
+
export function keepStateOf(owner: object, component: unknown, role = 'component'): void {
|
|
76
|
+
const refresh = reactRefresh();
|
|
77
|
+
if (!refresh?.register || component === undefined) return;
|
|
78
|
+
const register = refresh.register;
|
|
79
|
+
Promise.resolve().then(() => {
|
|
80
|
+
const family = familyOf(owner);
|
|
81
|
+
if (!family) return;
|
|
82
|
+
let id = innerIds.get(family);
|
|
83
|
+
if (id === undefined) {
|
|
84
|
+
id = `apexnative.navigation#${++innerCount}`;
|
|
85
|
+
innerIds.set(family, id);
|
|
86
|
+
}
|
|
87
|
+
register(component, `${id}.${role}`);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Makes React Refresh mount a component of the library again, not keep its state, when a new version of it comes: its
|
|
93
|
+
* hooks are the app's, which may have changed, and the library's code has no signature of them. Development only.
|
|
94
|
+
*/
|
|
95
|
+
export function resetOnEdit(type: object): void {
|
|
96
|
+
reactRefresh()?.createSignatureFunctionForTransform?.()(type, 'apexnative.navigation', true);
|
|
97
|
+
}
|