@apexnative/navigation 1.0.0-alpha.4 → 1.0.0-alpha.6
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/CHANGELOG.md +38 -0
- package/README.md +1 -1
- package/android/CLAUDE.md +23 -14
- package/android/CORE.md +32 -19
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +60 -13
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +28 -13
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +39 -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 -51
- 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 +30 -39
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +34 -7
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +12 -12
- 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/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +22 -21
- 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 +12 -9
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.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/ModalCoordinator.kt +20 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +119 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +7 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -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 +45 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +25 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +3 -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 +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +3 -0
- 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 +2 -5
- 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/TopBarPresenter.kt +4 -9
- 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/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/ElementTransitions.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +11 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +318 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +18 -20
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +17 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +15 -22
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +84 -35
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +49 -40
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/splash/index.js +3 -1
- package/docs-md/architecture/transitions.md +4 -2
- package/docs-md/containers/modals.md +4 -2
- 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 +1 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/guides/cli.md +1 -2
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +23 -2
- package/docs-md/index.json +12 -0
- 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 +36 -0
- package/docs-md/screen-ui/bar-buttons.md +4 -4
- 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 +2 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/docs-md/start/installation.md +1 -1
- package/ios/Animations/ANNFrameDriver.mm +2 -0
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +70 -4
- 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 +6 -4
- package/ios/Animations/Interpolators/ANNViewTracks.mm +49 -9
- package/ios/CLAUDE.md +17 -15
- package/ios/CORE.md +30 -26
- package/ios/Contract/ANNCommandAnswer.h +9 -2
- package/ios/Contract/ANNCommandAnswer.mm +25 -12
- 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/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNJavaScriptCalls.h +11 -12
- package/ios/Core/ANNJavaScriptCalls.mm +7 -16
- package/ios/Core/ANNNavigationState.h +4 -6
- package/ios/Core/ANNNavigationState.mm +0 -4
- package/ios/Core/ANNReloadCoordinator.mm +4 -8
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- 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/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
- package/ios/Layouts/Screen/ANNComponentViewController.mm +9 -22
- 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 +142 -27
- 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/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +18 -0
- package/ios/Options/ANNOptions.mm +112 -1
- package/ios/Options/ANNOptionsReader.mm +110 -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/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 +6 -0
- package/ios/React/ANNSurfaceHostingView.mm +116 -0
- 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 +20 -16
- package/lib/module/ARCHITECTURE.md +8 -4
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.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/options/OptionsChain.js +2 -2
- package/lib/module/engine/commands.js +21 -1
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/places.js +8 -0
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/screens.js +29 -4
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +3 -3
- 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/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/places.d.ts +2 -0
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +20 -6
- package/lib/typescript/engine/screens.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 +30 -9
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +18 -5
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +8 -8
- package/lib/typescript/interfaces/options/stack.d.ts +9 -0
- 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 +32 -29
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +8 -4
- package/src/api/app/createNavigation.ts +3 -3
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/engine/commands.ts +30 -6
- package/src/engine/places.ts +9 -0
- package/src/engine/screens.tsx +29 -8
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/options/animations.ts +31 -9
- package/src/interfaces/options/bottomTabs.ts +18 -5
- package/src/interfaces/options/buttons.ts +8 -8
- package/src/interfaces/options/stack.ts +9 -0
- package/src/interfaces/options/system.ts +8 -5
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +32 -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/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/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
|
@@ -258,10 +258,12 @@ export type ElementAnimation = AppearingElementAnimation | DisappearingElementAn
|
|
|
258
258
|
* the way (an error in its animation) is skipped too, with a warning in the log: it shows and hides with its screen,
|
|
259
259
|
* and the transition and its command go on. Without an animation of the screens of its own, the screen that comes fades
|
|
260
260
|
* in (or the one that goes fades out) in 300 ms around the elements. When the transition ends or is cancelled, the
|
|
261
|
-
* element gets its own values back.
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
261
|
+
* element gets its own values back. The element's own `transform` counts: a property that doesn't animate keeps the
|
|
262
|
+
* element's value, and a missing end is that value (a turn read from −180° to 180°, as React Native draws it). `x`
|
|
263
|
+
* and `y` are the position in the parent of the element on both platforms. As on a side of a screen, don't set `x`
|
|
264
|
+
* with `translationX` or `y` with `translationY` on one element: the translation plays and the position doesn't.
|
|
265
|
+
* (Android) A view whose parent is a React view with `removeClippedSubviews` turned on, such as a child of a clipping
|
|
266
|
+
* list, is not moved: it counts as not found.
|
|
265
267
|
*/
|
|
266
268
|
export interface ElementTransition {
|
|
267
269
|
/** The `nativeID` of the view to animate. */
|
|
@@ -295,9 +297,12 @@ export interface ElementTransition {
|
|
|
295
297
|
* warning in the log: its views show and hide with their screens, and the transition and its command go on. (iOS) So is
|
|
296
298
|
* a pair with a view without a size, or one whose picture can't be taken. Without an animation of the screens of its
|
|
297
299
|
* own, the screen that comes fades in (or the one that goes fades out) in 300 ms around the pair. Text keeps its
|
|
298
|
-
* proportions and changes its picture within a quarter of the flight.
|
|
299
|
-
*
|
|
300
|
-
* `
|
|
300
|
+
* proportions and changes its picture within a quarter of the flight. A view turned or scaled by its own `transform` or
|
|
301
|
+
* by a parent's flies from where it shows, and its angle goes to the other view's along the shorter arc. The angle is
|
|
302
|
+
* the one React Native draws, from −180° to 180°: `rotate: '270deg'` turns back a quarter, and no pair spins a full
|
|
303
|
+
* turn. (Android) A picture that doesn't load within a second drops out of the transition, and so does a pair with a
|
|
304
|
+
* view whose parent is a React view with `removeClippedSubviews` turned on: it counts as not found. A skew and a tilt
|
|
305
|
+
* (`skewX`, `rotateX`, …) don't fly: the view flies without them and has them again at the end.
|
|
301
306
|
*/
|
|
302
307
|
export interface SharedElementTransition {
|
|
303
308
|
/** The `nativeID` of the view on the screen that goes. */
|
|
@@ -405,6 +410,20 @@ export interface StackPushAnimationOptions extends StackAnimationOptions {
|
|
|
405
410
|
zoom?: ZoomTransitionOptions;
|
|
406
411
|
}
|
|
407
412
|
|
|
413
|
+
/**
|
|
414
|
+
* The animation of a pop, read from the screen that goes. As {@link StackAnimationOptions}, with the preview of the
|
|
415
|
+
* back gesture on Android.
|
|
416
|
+
*/
|
|
417
|
+
export interface StackPopAnimationOptions extends StackAnimationOptions {
|
|
418
|
+
/**
|
|
419
|
+
* (Android 14+) Whether the back gesture on a pushed screen previews its pop as the user swipes: the screen shrinks
|
|
420
|
+
* and follows the finger, the screen under it shows behind. `false` pops the screen when the gesture is released,
|
|
421
|
+
* as on Android 13 and older; back still pops it. iOS ignores it: its swipe back is UIKit's.
|
|
422
|
+
* @default true
|
|
423
|
+
*/
|
|
424
|
+
preview?: boolean;
|
|
425
|
+
}
|
|
426
|
+
|
|
408
427
|
/**
|
|
409
428
|
* The animation of `setStackRoot`, read from the new top screen. As {@link StackAnimationOptions}: without an animation
|
|
410
429
|
* of its own, iOS plays the push animation of the new top screen or UIKit's transition, and Android plays a fade
|
|
@@ -468,8 +487,11 @@ export interface ModalAnimationOptions extends EnterExitAnimationOptions {
|
|
|
468
487
|
export interface AnimationOptions {
|
|
469
488
|
/** The push of a screen, read from the screen that comes. */
|
|
470
489
|
push?: StackPushAnimationOptions;
|
|
471
|
-
/**
|
|
472
|
-
|
|
490
|
+
/**
|
|
491
|
+
* The pop of a screen, also `popTo` and `popToRoot`, read from the screen that goes. The swipe back of iOS is
|
|
492
|
+
* UIKit's; the back gesture of Android previews the pop (`preview`).
|
|
493
|
+
*/
|
|
494
|
+
pop?: StackPopAnimationOptions;
|
|
473
495
|
/** The replacing of the screens of a stack, read from the new top screen. */
|
|
474
496
|
setStackRoot?: SetStackRootAnimationOptions;
|
|
475
497
|
/**
|
|
@@ -73,8 +73,10 @@ export interface OptionsBottomTabsAccessoryComponent {
|
|
|
73
73
|
/**
|
|
74
74
|
* (iOS 26+) The accessory above the tab bar, like the mini player of a music app. The system sizes it (48 points high)
|
|
75
75
|
* and the component fills that size. It is placed above the bar, or beside the bar when the bar is minimized; on an
|
|
76
|
-
* iPad with the bar at the top it sits at the bottom over the full width, always above the bar.
|
|
77
|
-
*
|
|
76
|
+
* iPad with the bar at the top it sits at the bottom over the full width, always above the bar. A hidden accessory
|
|
77
|
+
* (`visible: false`, or no name) keeps its React root and its state, and shows again with them. When another accessory
|
|
78
|
+
* (another `componentId`) shows, the replaced one stops once it has left the window and its state is gone. The last
|
|
79
|
+
* accessory stops together with the tabs. Android has no accessory.
|
|
78
80
|
*/
|
|
79
81
|
export interface OptionsBottomTabsAccessory {
|
|
80
82
|
/**
|
|
@@ -155,6 +157,16 @@ export interface OptionsBottomTabs {
|
|
|
155
157
|
* @default true
|
|
156
158
|
*/
|
|
157
159
|
animate?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* How the content changes when another tab is selected on screen, by a press, by back or from code. `'platform'`
|
|
162
|
+
* does what the platform does: on Android the tab that goes fades out and the new one fades in and grows (Material's
|
|
163
|
+
* fade through, 300 ms), on iOS the content changes at once. `'none'` changes it at once on both platforms. The
|
|
164
|
+
* appear events of a switch and `ANN.BottomTabSelected` come at its end, so with `'none'` right away. The tab that is
|
|
165
|
+
* selected decides: the value of the screen it shows, over its own, the tabs' and the default options. A
|
|
166
|
+
* `mergeOptions` applies from the next switch. Off screen the content always changes at once.
|
|
167
|
+
* @default 'platform'
|
|
168
|
+
*/
|
|
169
|
+
switchAnimation?: 'platform' | 'none';
|
|
158
170
|
/**
|
|
159
171
|
* The tab to select, as an index from 0. It selects once, when the options arrive, at creation (the first tab to
|
|
160
172
|
* show) or in `mergeOptions`; it is not kept. An index out of range selects nothing (or the first tab at creation)
|
|
@@ -188,8 +200,9 @@ export interface OptionsBottomTabs {
|
|
|
188
200
|
drawBehind?: boolean;
|
|
189
201
|
/**
|
|
190
202
|
* The background color of the bar; `null` gives the default one. On Android the default is the surface color of the
|
|
191
|
-
* Material 3 theme. Before iOS 26
|
|
192
|
-
*
|
|
203
|
+
* Material 3 theme. Before iOS 26, and in the compatibility mode (`UIDesignRequiresCompatibility` in Info.plist: iOS 26, and iOS 27
|
|
204
|
+
* only for an app built with an SDK before iOS 27), the bar is opaque with the color, or system opaque without it,
|
|
205
|
+
* and a transparent color makes it transparent. On iOS 26 and later with glass the color is ignored
|
|
193
206
|
* with one warning, since the system has no color for glass, while a transparent color gives a transparent bar. The
|
|
194
207
|
* theme color `bar` is its default option.
|
|
195
208
|
*/
|
|
@@ -396,7 +409,7 @@ export interface OptionsBottomTab {
|
|
|
396
409
|
selectedFontSize?: number;
|
|
397
410
|
/**
|
|
398
411
|
* (iOS) The insets of the icon. Each side is independent. They apply before iOS 26 only; iOS 26 and the compatibility
|
|
399
|
-
* mode ignore them, and so does a system role before iOS 18.
|
|
412
|
+
* mode (see `backgroundColor`) ignore them, and so does a system role before iOS 18.
|
|
400
413
|
*/
|
|
401
414
|
iconInsets?: IconInsets;
|
|
402
415
|
/**
|
|
@@ -60,7 +60,7 @@ export interface IconInsets {
|
|
|
60
60
|
* a color the other fields are ignored.
|
|
61
61
|
*
|
|
62
62
|
* On iOS the icon is drawn onto the shape and the button becomes a button of its own (the back button keeps its
|
|
63
|
-
* history menu), without the glass capsule
|
|
63
|
+
* history menu), without the glass capsule (glass design, iOS 26+) by default. On Android the icon sits on the shape, mirrored in a
|
|
64
64
|
* right-to-left layout. Layers merge differently: on iOS an object merges field by field like any other, on Android
|
|
65
65
|
* an `iconBackground` that has a `color` replaces the earlier one as a whole.
|
|
66
66
|
*/
|
|
@@ -189,7 +189,7 @@ export interface OptionsTopBarButton {
|
|
|
189
189
|
*/
|
|
190
190
|
icon?: ImageResource;
|
|
191
191
|
/**
|
|
192
|
-
* (iOS) The space around the image of `icon`; the button becomes a button of its own, without a capsule
|
|
192
|
+
* (iOS) The space around the image of `icon`; the button becomes a button of its own, without a capsule with the glass design (iOS 26+, see `UIDesignRequiresCompatibility`).
|
|
193
193
|
*/
|
|
194
194
|
iconInsets?: IconInsets;
|
|
195
195
|
/**
|
|
@@ -238,14 +238,14 @@ export interface OptionsTopBarButton {
|
|
|
238
238
|
disabledColor?: Color;
|
|
239
239
|
/**
|
|
240
240
|
* A shape behind the icon. It works with an `icon` image and a `color` of the shape; on iOS the button becomes a
|
|
241
|
-
* button of its own without menu, toggle or style, and without a capsule
|
|
241
|
+
* button of its own without menu, toggle or style, and without a capsule with the glass design by default. The color of a whole
|
|
242
242
|
* side is `leftButtonBackgroundColor` / `rightButtonBackgroundColor`.
|
|
243
243
|
*/
|
|
244
244
|
iconBackground?: IconBackgroundOptions;
|
|
245
245
|
/**
|
|
246
|
-
* (iOS) `'plain'` or `'prominent'`, the main action of the bar (Done, Send).
|
|
246
|
+
* (iOS) `'plain'` or `'prominent'`, the main action of the bar (Done, Send). With the glass design (iOS 26+, see `UIDesignRequiresCompatibility`) a prominent button is a
|
|
247
247
|
* capsule in the button's tint with bold text or icon on it (the tint is `color`, the bar's tint without it);
|
|
248
|
-
*
|
|
248
|
+
* without it, it is the system's done style with bold text. Not for component buttons, buttons with
|
|
249
249
|
* `iconBackground`, and `showText` buttons.
|
|
250
250
|
* @default 'plain'
|
|
251
251
|
*/
|
|
@@ -257,7 +257,7 @@ export interface OptionsTopBarButton {
|
|
|
257
257
|
*/
|
|
258
258
|
testID?: string;
|
|
259
259
|
/**
|
|
260
|
-
* (iOS 26
|
|
260
|
+
* (iOS 26+, glass design) Whether the button has no glass capsule under it; neighbors keep theirs. By default `true` for
|
|
261
261
|
* component buttons and for icon buttons with a background or insets, `false` for the rest. In a `group` of several
|
|
262
262
|
* buttons the capsule is shared and this has no effect. A change by `mergeOptions` builds the buttons anew.
|
|
263
263
|
*/
|
|
@@ -270,8 +270,8 @@ export interface OptionsTopBarButton {
|
|
|
270
270
|
*/
|
|
271
271
|
showText?: boolean;
|
|
272
272
|
/**
|
|
273
|
-
* (iOS 26
|
|
274
|
-
* own.
|
|
273
|
+
* (iOS 26+, glass design) Buttons next to each other with the same group share one capsule; a button without a group has its
|
|
274
|
+
* own. Without the glass design it does nothing, on iOS 15 there are no groups. A side that has a group of several buttons
|
|
275
275
|
* doesn't animate button changes. The toolbar has no groups: only icons share a capsule there. For center buttons
|
|
276
276
|
* the group is a section of the overflow menu, and its name is the id the customization is saved under.
|
|
277
277
|
*/
|
|
@@ -26,6 +26,15 @@ export interface HardwareBackButtonOptions {
|
|
|
26
26
|
* @internal
|
|
27
27
|
*/
|
|
28
28
|
dismissModalOnPress?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* (Android) Whether back on the first screen of the app, with nothing left to go back to, plays the system's
|
|
31
|
+
* animation of going home. The system decides it as the gesture starts, so with `false` the navigation keeps the
|
|
32
|
+
* back on that screen too: the gesture shows no animation, and on release the press goes to `BackHandler` listeners,
|
|
33
|
+
* then to the activity's own back (`invokeDefaultOnBackPressed` of the app's activity, such as `moveTaskToBack`).
|
|
34
|
+
* Read from the screen back acts on; set it in the default options for the whole app. iOS ignores it.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
systemAnimation?: boolean;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
/**
|
|
@@ -34,12 +34,15 @@ export interface OptionsLayout {
|
|
|
34
34
|
* indicator or navigation bar, the camera cutout. `[]` lets the content reach every edge. The array replaces the
|
|
35
35
|
* one from a lower layer. The screen adds the padding itself; `useSafeAreaInsets()` returns what is still covered,
|
|
36
36
|
* which is 0 on an edge the screen keeps and the whole covered size on an edge where the content goes under a bar.
|
|
37
|
-
* Edges listed here
|
|
37
|
+
* Edges listed here win, but the top under a large title: there the list keeps its first rows clear of the bar
|
|
38
|
+
* itself and scrolls under it, which collapses the title, so a `'top'` listed here counts for nothing.
|
|
38
39
|
*
|
|
39
|
-
* Without it
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* Without it the screen keeps the top and the sides, and its content goes down to the bottom: under the home
|
|
41
|
+
* indicator or the navigation bar, and under a tab bar or toolbar it goes under. A list keeps its last rows clear
|
|
42
|
+
* with `useSafeAreaInsets().bottom`. The top is free where the content goes under a top bar: on iOS under a bar
|
|
43
|
+
* that shows, on Android under a bar that hides on scroll; on both under a large title, so the list scrolls under
|
|
44
|
+
* the bar. On iOS the side of a vertical bar is free too. To have the screen keep the bottom, list every edge it
|
|
45
|
+
* keeps: listed edges replace the default.
|
|
43
46
|
*/
|
|
44
47
|
safeAreaEdges?: SafeAreaEdge[];
|
|
45
48
|
/**
|
|
@@ -4,7 +4,7 @@ import type { OptionsTopBarButton } from './buttons';
|
|
|
4
4
|
export interface OptionsToolbarSpace {
|
|
5
5
|
/**
|
|
6
6
|
* `'flexibleSpace'` takes the free width and pushes the next buttons to the far edge; `'fixedSpace'` is a gap of zero
|
|
7
|
-
* width that starts a new capsule
|
|
7
|
+
* width that starts a new capsule with the glass design (iOS 26+).
|
|
8
8
|
*/
|
|
9
9
|
systemItem: 'flexibleSpace' | 'fixedSpace';
|
|
10
10
|
}
|
|
@@ -36,7 +36,7 @@ export interface OptionsToolbar {
|
|
|
36
36
|
* The buttons from the leading edge, in the format of the bar buttons: text, icon, SF Symbol, `systemItem`, a
|
|
37
37
|
* component (drawn before the screen shows), `enabled`, `color`, `style`, `menu` (it opens upward), `toggle`,
|
|
38
38
|
* `showText`, `group`; also spaces and the search field. A press sends a button press. The color of a side doesn't
|
|
39
|
-
* apply to them, and badges are not drawn.
|
|
39
|
+
* apply to them, and badges are not drawn. With the glass design (iOS 26+, see `UIDesignRequiresCompatibility`) each button has its own capsule, neighbor icons with the same
|
|
40
40
|
* `group` share one (the toolbar has no real groups, so text buttons never share), and a zero-width space is put
|
|
41
41
|
* between neighbors of different groups unless an explicit space is there. The list is replaced as a whole;
|
|
42
42
|
* `mergeOptions` animates it.
|
|
@@ -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;
|
|
@@ -815,12 +815,15 @@ export interface OptionsScrollEdge {
|
|
|
815
815
|
|
|
816
816
|
/**
|
|
817
817
|
* (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
|
-
*
|
|
818
|
+
* under a bar. The scroll views draw it, and only where content goes under a bar. When the screen appears, it applies
|
|
819
|
+
* to the vertical lists and text views (a multi-line `TextInput`) in the view of the screen, except in hidden views
|
|
820
|
+
* (`display: none`). A list inside another vertical list gets none (UIKit draws no edge effect there); a scroll view
|
|
821
|
+
* that doesn't scroll vertically, like a pager, is searched for its lists. A list nested very deep in the screen's
|
|
822
|
+
* views may not get it. After React mounts, the main list of the screen gets it; a list mounted later gets it at the
|
|
823
|
+
* next appearance, or at a `mergeOptions` of `scrollEdgeEffect` or of the bar's background. The lists get the system
|
|
824
|
+
* effect back when the screen leaves or is destroyed, and a list React removes from the screen gets it back too. Under
|
|
825
|
+
* a bar with `background.color` or `background.component` there is no effect at the top unless the screen sets one for
|
|
826
|
+
* the top or for all edges. Before iOS 26 and on Android it does nothing.
|
|
824
827
|
*/
|
|
825
828
|
export interface OptionsScrollEdgeEffect {
|
|
826
829
|
/** 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 android.content.Context
|
|
4
|
-
import com.facebook.react.ReactApplication
|
|
5
|
-
import com.facebook.react.bridge.Arguments
|
|
6
|
-
import com.facebook.react.bridge.WritableMap
|
|
7
|
-
import dev.apexnative.navigation.react.events.EventContract
|
|
8
|
-
import dev.apexnative.navigation.react.events.EventEmitter
|
|
9
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The state of each screen of a pair (`useArrangement`): which screen of the pair it is, how the pair lies, whether it
|
|
13
|
-
* lies over the other one and whether it is out of the window. Set on the main thread as the pair lays out; JavaScript
|
|
14
|
-
* reads it from its own thread for a screen's first render, and gets every change as `ANN.ArrangementChanged`. A
|
|
15
|
-
* screen outside a pair has none.
|
|
16
|
-
*/
|
|
17
|
-
internal object ArrangementStates {
|
|
18
|
-
data class State(val placement: String, val layout: String, val front: Boolean, val hidden: Boolean)
|
|
19
|
-
|
|
20
|
-
private val states = ConcurrentHashMap<String, State>()
|
|
21
|
-
|
|
22
|
-
/** Keeps the screen's state, and tells JavaScript when it changed and [notify] holds. Main thread only. */
|
|
23
|
-
fun set(context: Context, screenId: String, state: State, notify: Boolean) {
|
|
24
|
-
if (states.put(screenId, state) == state || !notify) return
|
|
25
|
-
val reactContext = (context.applicationContext as? ReactApplication)?.reactHost?.currentReactContext ?: return
|
|
26
|
-
EventEmitter(reactContext).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 android.content.Context
|
|
4
|
-
import com.facebook.react.ReactApplication
|
|
5
|
-
import com.facebook.react.bridge.Arguments
|
|
6
|
-
import com.facebook.react.bridge.WritableMap
|
|
7
|
-
import dev.apexnative.navigation.react.events.EventContract
|
|
8
|
-
import dev.apexnative.navigation.react.events.EventEmitter
|
|
9
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The safe area of each screen, in dp: how much of its content the bars and the system cover on each side. The padding
|
|
13
|
-
* 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
|
|
14
|
-
* give. JavaScript gets the rest, what still covers the content (0 on a padded edge): it reads it from its own thread
|
|
15
|
-
* for a screen's first render, and gets every change as `ANN.ScreenInsetsChanged`.
|
|
16
|
-
*/
|
|
17
|
-
object ScreenInsets {
|
|
18
|
-
data class Insets(val top: Double, val right: Double, val bottom: Double, val left: Double)
|
|
19
|
-
|
|
20
|
-
private val insets = ConcurrentHashMap<String, Insets>()
|
|
21
|
-
// Main thread only.
|
|
22
|
-
private val padding = HashMap<String, Insets>()
|
|
23
|
-
private val paddingListeners = HashMap<String, MutableSet<() -> Unit>>()
|
|
24
|
-
|
|
25
|
-
/** The padding of the screen's safe area view; none before the screen was laid out. */
|
|
26
|
-
fun padding(screenId: String): Insets? = padding[screenId]
|
|
27
|
-
|
|
28
|
-
/** Calls `listener` when the padding of the screen changes; returns the function that stops it. */
|
|
29
|
-
fun listenToPadding(screenId: String, listener: () -> Unit): () -> Unit {
|
|
30
|
-
paddingListeners.getOrPut(screenId) { LinkedHashSet() }.add(listener)
|
|
31
|
-
return {
|
|
32
|
-
paddingListeners[screenId]?.let {
|
|
33
|
-
it.remove(listener)
|
|
34
|
-
if (it.isEmpty()) paddingListeners.remove(screenId)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Keeps the screen's insets and padding, and tells when they changed. */
|
|
40
|
-
fun update(context: Context, screenId: String, value: Insets, paddingValue: Insets) {
|
|
41
|
-
if (padding.put(screenId, paddingValue) != paddingValue) {
|
|
42
|
-
paddingListeners[screenId]?.toList()?.forEach { it() }
|
|
43
|
-
}
|
|
44
|
-
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
45
|
-
val uncovered = Insets(
|
|
46
|
-
top = (value.top - paddingValue.top).coerceAtLeast(0.0),
|
|
47
|
-
right = (value.right - paddingValue.right).coerceAtLeast(0.0),
|
|
48
|
-
bottom = (value.bottom - paddingValue.bottom).coerceAtLeast(0.0),
|
|
49
|
-
left = (value.left - paddingValue.left).coerceAtLeast(0.0),
|
|
50
|
-
)
|
|
51
|
-
if (insets.put(screenId, uncovered) == uncovered) return
|
|
52
|
-
val reactContext = (context.applicationContext as? ReactApplication)?.reactHost?.currentReactContext ?: return
|
|
53
|
-
EventEmitter(reactContext).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
|
-
}
|
package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
package dev.apexnative.navigation.react.events
|
|
2
|
-
|
|
3
|
-
import android.os.Handler
|
|
4
|
-
import android.os.Looper
|
|
5
|
-
import dev.apexnative.navigation.viewcontrollers.bottomtabs.BottomTabsController
|
|
6
|
-
import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
|
|
7
|
-
import dev.apexnative.navigation.viewcontrollers.parent.ParentController
|
|
8
|
-
import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Tells JavaScript the screen the user sees and the selected tab when they change. Every change of the screen the
|
|
12
|
-
* user sees comes with a screen appearing: a push, a pop, a modal, a tab, a menu. One update after the events of a
|
|
13
|
-
* pass of the main loop, and one at once before a command resolves its promise; each sent only when the state changed.
|
|
14
|
-
*/
|
|
15
|
-
object NavigationStateReporter {
|
|
16
|
-
internal data class State(val screenId: String?, val screenName: String?, val tab: Int?)
|
|
17
|
-
|
|
18
|
-
private val handler = Handler(Looper.getMainLooper())
|
|
19
|
-
private var state: State? = null
|
|
20
|
-
private var scheduled = false
|
|
21
|
-
|
|
22
|
-
/** The new JavaScript has no state yet: the next one goes to it whatever it is. */
|
|
23
|
-
fun reset() {
|
|
24
|
-
state = null
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
fun setNeedsUpdate(emitter: EventEmitter) {
|
|
28
|
-
if (scheduled) return
|
|
29
|
-
scheduled = true
|
|
30
|
-
handler.post {
|
|
31
|
-
scheduled = false
|
|
32
|
-
updateNow(emitter)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Sends the state at once when it differs from the last one sent. A command calls it right before it resolves its
|
|
38
|
-
* promise: the event and the resolution reach JavaScript in that order, so the state is new when the `await` of
|
|
39
|
-
* the command goes on. The update already scheduled then finds nothing new. Main thread only.
|
|
40
|
-
*/
|
|
41
|
-
fun updateNow(emitter: EventEmitter) {
|
|
42
|
-
// The navigation of the activity the commands run in (`Navigators.current`).
|
|
43
|
-
val navigator = Navigators.current()?.navigator ?: return
|
|
44
|
-
val next = stateOf(navigator.visibleLayout)
|
|
45
|
-
if (next == state) return
|
|
46
|
-
state = next
|
|
47
|
-
emitter.emitNavigationStateChanged(next.screenId, next.screenName, next.tab)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// The top modal, or the root ([layout]), down to the screen the user sees; overlays don't count. The tab is the
|
|
51
|
-
// selected one of the nearest tabs the screen is in, the last met on the way down, in a modal too: the tabs
|
|
52
|
-
// `selectTab` acts on from it. None for a screen out of tabs.
|
|
53
|
-
internal fun stateOf(layout: ViewController<*>?): State {
|
|
54
|
-
var tab: Int? = null
|
|
55
|
-
var current = layout ?: return State(null, null, null)
|
|
56
|
-
while (current is ParentController<*>) {
|
|
57
|
-
if (current is BottomTabsController) tab = current.selectedIndex
|
|
58
|
-
current = current.currentChild ?: return State(null, null, null)
|
|
59
|
-
}
|
|
60
|
-
return State(current.id, current.currentComponentName, tab)
|
|
61
|
-
}
|
|
62
|
-
}
|