@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.2

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.
Files changed (125) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +147 -51
  3. package/android/CLAUDE.md +10 -4
  4. package/android/CORE.md +4 -1
  5. package/android/RECIPES.md +4 -3
  6. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +5 -4
  7. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  8. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +3 -2
  9. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +1 -1
  10. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +5 -4
  11. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +7 -6
  12. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +3 -35
  13. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  14. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +101 -87
  15. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  16. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  17. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +12 -8
  19. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +12 -11
  20. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +2 -2
  21. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +25 -0
  22. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +1 -1
  23. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +1 -3
  24. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +4 -7
  25. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  26. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +8 -1
  27. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +2 -1
  28. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +2 -1
  29. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +5 -5
  30. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  31. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +85 -27
  32. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +5 -4
  33. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  34. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  35. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +45 -1
  36. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +3 -5
  37. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +3 -5
  38. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +3 -5
  39. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +2 -0
  40. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +4 -6
  41. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +4 -6
  42. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +4 -3
  43. package/cli/app.js +1 -1
  44. package/cli/project.js +6 -2
  45. package/cli/setup/index.js +13 -0
  46. package/cli/setup/steps/appDelegate.js +66 -11
  47. package/cli/setup/steps/sceneDelegate.js +108 -0
  48. package/docs-md/architecture/transitions.md +1 -1
  49. package/docs-md/guides/deep-links.md +15 -33
  50. package/docs-md/start/installation.md +1 -0
  51. package/ios/Animations/ANNTransitionAnimator.mm +13 -11
  52. package/ios/Animations/ANNTransitionWait.mm +6 -7
  53. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  54. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  55. package/ios/Animations/Elements/ANNElementTransition.h +7 -5
  56. package/ios/Animations/Elements/ANNElementTransition.mm +17 -19
  57. package/ios/Animations/Elements/ANNSharedElementFlight.h +13 -8
  58. package/ios/Animations/Elements/ANNSharedElementFlight.mm +59 -24
  59. package/ios/CLAUDE.md +10 -2
  60. package/ios/CORE.md +3 -2
  61. package/ios/Contract/ANNCommandAnswer.h +4 -3
  62. package/ios/Contract/ANNCommandAnswer.mm +12 -2
  63. package/ios/Contract/ANNCommandRunner.h +2 -2
  64. package/ios/Contract/ANNCommandRunner.mm +1 -1
  65. package/ios/Contract/ANNErrorTexts.h +6 -2
  66. package/ios/Contract/ANNErrorTexts.mm +18 -10
  67. package/ios/Core/ANNDeepLinkQueue.h +20 -1
  68. package/ios/Core/ANNDeepLinkQueue.mm +107 -12
  69. package/ios/Core/ANNErrorHandler.h +8 -3
  70. package/ios/Core/ANNErrorHandler.mm +17 -1
  71. package/ios/Core/ANNEventContract.h +246 -0
  72. package/ios/Core/ANNEventContract.mm +225 -0
  73. package/ios/Core/ANNEventEmitter.h +5 -1
  74. package/ios/Core/ANNEventEmitter.mm +117 -80
  75. package/ios/Core/ANNHinge.mm +6 -4
  76. package/ios/Core/ANNSceneDelegate.mm +25 -15
  77. package/ios/Core/ANNSystemUI.h +3 -2
  78. package/ios/Core/ANNSystemUI.mm +7 -0
  79. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +6 -4
  80. package/ios/Layouts/Modal/ANNModalCoordinator.mm +1 -1
  81. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  82. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  83. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  84. package/ios/Layouts/Root/ANNRootCoordinator.mm +12 -3
  85. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  86. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  87. package/ios/Layouts/Screen/ANNComponentViewController.mm +28 -7
  88. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  89. package/ios/Layouts/Screen/ANNScreenInsets.mm +6 -4
  90. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -6
  91. package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -7
  92. package/ios/Options/ANNSheetOptions.h +4 -1
  93. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  94. package/ios/RECIPES.md +2 -1
  95. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  96. package/ios/TurboModules/ANNTurboModule.mm +5 -2
  97. package/lib/module/ARCHITECTURE.md +7 -4
  98. package/lib/module/api/app/createNavigation.js +2 -0
  99. package/lib/module/api/app/createNavigation.js.map +1 -1
  100. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  101. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  102. package/lib/module/interfaces/contract/errors.json +275 -0
  103. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  104. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  105. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  106. package/lib/typescript/interfaces/Events.d.ts +9 -0
  107. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  108. package/lib/typescript/interfaces/options/animations.d.ts +17 -13
  109. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  110. package/lib/typescript/interfaces/options/modals.d.ts +15 -11
  111. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  112. package/lib/typescript/interfaces/options/sideMenu.d.ts +7 -6
  113. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  114. package/lib/typescript/interfaces/options/system.d.ts +4 -3
  115. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  116. package/package.json +1 -1
  117. package/src/ARCHITECTURE.md +7 -4
  118. package/src/api/app/createNavigation.ts +2 -0
  119. package/src/api/linking/dispatchedLinks.ts +18 -0
  120. package/src/interfaces/Events.ts +10 -0
  121. package/src/interfaces/contract/errors.json +275 -0
  122. package/src/interfaces/options/animations.ts +17 -13
  123. package/src/interfaces/options/modals.ts +15 -11
  124. package/src/interfaces/options/sideMenu.ts +7 -6
  125. package/src/interfaces/options/system.ts +4 -3
@@ -18,8 +18,8 @@ export interface SideMenuSide {
18
18
  visible?: boolean;
19
19
  /**
20
20
  * Whether the opening or closing that `visible` asks for is animated. With `false` it happens at once and the
21
- * screens of the menu get the same appearance events in the same order, except that on Android a menu that opens at
22
- * once sends its screens DidAppear without WillAppear. It acts only together with `visible` in the same merge.
21
+ * screens of the menu get the same appearance events in the same order: WillAppear, then DidAppear. It acts only
22
+ * together with `visible` in the same merge.
23
23
  * @default true
24
24
  */
25
25
  animate?: boolean;
@@ -32,15 +32,16 @@ export interface SideMenuSide {
32
32
  enabled?: boolean;
33
33
  /**
34
34
  * The width of the menu, in points on iOS and dp on Android. It is capped at the width of the side menu (iOS) and at
35
- * that width less 64 dp (Android). On iOS a change applies at once, also to an open menu. On Android it applies the
36
- * next time a screen in the side menu appears, the center's or a menu's.
35
+ * that width less 64 dp (Android). A change in `mergeOptions` applies at once, also to an open menu. A width set by
36
+ * a screen of the center acts while that screen shows.
37
37
  * Without it, 280 points on iOS and the width of the side menu less 64 dp on Android (the least gap the Material
38
38
  * drawer leaves).
39
39
  */
40
40
  width?: number;
41
41
  /**
42
- * (Android) The height of the menu in dp; a menu lower than the container is pinned to the top. It is read only when
43
- * the side menu is created. Without it, the menu takes the full height under the status bar. iOS doesn't read it.
42
+ * (Android) The height of the menu in dp; a menu lower than the container is pinned to the top. A change in
43
+ * `mergeOptions` applies at once, also to an open menu. Without it, the menu takes the full height under the status
44
+ * bar. iOS doesn't read it.
44
45
  */
45
46
  height?: number;
46
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"sideMenu.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/sideMenu.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IAC1C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,cAAc,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,OAAO,GAAG,iBAAiB,GAAG,MAAM,CAAC;AAEtF;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,qBAAqB;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,sBAAsB;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C;;;OAGG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"sideMenu.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/sideMenu.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IAC1C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,cAAc,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,OAAO,GAAG,iBAAiB,GAAG,MAAM,CAAC;AAEtF;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,qBAAqB;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,sBAAsB;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C;;;OAGG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -165,9 +165,10 @@ export interface OptionsStatusBar {
165
165
  */
166
166
  hideWithTopBar?: boolean;
167
167
  /**
168
- * (iOS) Whether a blur shows under the status bar, drawn over the screen in the frame the status bar has when the
169
- * option applies. It applies when the screen appears and through `mergeOptions`; `false` removes it. The blur does
170
- * not follow a rotation or a change of window size.
168
+ * (iOS) Whether a blur shows under the status bar, drawn over the screen in the status bar's frame. It applies when
169
+ * the screen appears and through `mergeOptions`; `false` removes it. The blur follows the status bar's frame as it
170
+ * changes: a rotation, a new window size, the status bar hidden or shown. Android has no blur under the status bar,
171
+ * so it does nothing there.
171
172
  * @default false
172
173
  */
173
174
  blur?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAU,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,SAAS,GACT,UAAU,GACV,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,iBAAiB,GACjB,gBAAgB,CAAC;AAErB;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;OAGG;IACH,wBAAwB,CAAC,EAAE,KAAK,CAAC;IACjC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC;IACrC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,qHAAqH;AACrH,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEjG;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,8FAA8F;IAC9F,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,+GAA+G;IAC/G,SAAS,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACxC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/options/system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAU,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,SAAS,GACT,UAAU,GACV,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,iBAAiB,GACjB,gBAAgB,CAAC;AAErB;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;OAGG;IACH,wBAAwB,CAAC,EAAE,KAAK,CAAC;IACjC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC;IACrC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,qHAAqH;AACrH,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEjG;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,8FAA8F;IAC9F,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,+GAA+G;IAC/G,SAAS,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACxC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apexnative/navigation",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Native navigation for React Native: platform stacks, tabs, modals and side menus on iOS, iPadOS and Android",
5
5
  "keywords": [
6
6
  "react-native",
@@ -63,7 +63,8 @@ form of `src/api/events/navigationEvents.ts`. Everything in `src/engine` is inte
63
63
  `LinkParams`, `PendingLink`, …). `linkPaths.ts`: a URL into its path and query (`parseLink`), the patterns ordered
64
64
  (`compileRoutes`) and matched (`matchLink`). `linking.ts`: the links of the app — the launch link, the `url` events
65
65
  of React Native's `Linking`, the routes run, the pending link opened after `setContext`. `pendingLinks.ts`: the one
66
- waiting link and its listeners, which `navigation` and `usePendingLink` read.
66
+ waiting link and its listeners, which `navigation` and `usePendingLink` read. `dispatchedLinks.ts` (iOS): hands
67
+ `Linking` the links of `ANN.DeepLinkDispatched`.
67
68
  - `events/` — `navigationEvents.ts`: the events by name, the native event behind each, `onNavigationEvent`,
68
69
  `listeners`. `screenLifecycle.ts`: what goes when a screen unmounts, `whenScreenUnmounts`. `tabPresses.ts`: the
69
70
  handlers of `useTabPress`.
@@ -268,7 +269,9 @@ its push, which the hook ignores.
268
269
  given once; JS asks only with `linking`) and `getStartInfo` (synchronous: `coldStart`, true for the whole life of
269
270
  the first JavaScript runtime of the process, and `splashLogo`, the size of the native splash's logo the CLI wrote,
270
271
  or null; `arrangements`, whether it shows pairs). The links that come while the app runs reach JS through React Native's
271
- `Linking`, not through `ANN.*` events.
272
+ `Linking`, not through `ANN.*` events. One exception, iOS only: a link the app dispatched (`dispatchDeepLinkURL`) that
273
+ `Linking` doesn't take from the native side (React Native 0.88 and newer, with a scene delegate) comes as
274
+ `ANN.DeepLinkDispatched`, and `src/api/linking/dispatchedLinks.ts` hands it to `Linking` as a `url` event.
272
275
  - Events: `ANN.AppLaunched`, `ANN.ComponentWillAppear`, `ANN.ComponentDidAppear`, `ANN.ComponentDidDisappear`,
273
276
  `ANN.NavigationButtonPressed`, `ANN.BottomTabSelected`, `ANN.BottomTabPressed`, `ANN.BottomTabLongPressed`,
274
277
  `ANN.ModalDismissed`, `ANN.ModalAttemptedToDismiss`, `ANN.ScreenPopped`, `ANN.SearchBarUpdated`,
@@ -276,8 +279,8 @@ its push, which the hook ignores.
276
279
  `ANN.NavigationStateChanged`, `ANN.SlotDestroyed`, `ANN.ScreenInsetsChanged`, `ANN.TitleRenamed`,
277
280
  `ANN.BottomAccessoryPlacementChanged`, `ANN.SheetDetentChanged`, `ANN.SplitViewDisplayModeChanged`,
278
281
  `ANN.KeyCommandPressed`, `ANN.NativeScreenCall`, `ANN.NativeScreenReleased`, `ANN.ScreenRegionsChanged`,
279
- `ANN.ArrangementChanged`, `ANN.HingeChanged`, `ANN.SplitViewColumnsStacked`. Their payloads are typed in
280
- `src/interfaces/ComponentEvents.ts` and `Events.ts`. Both platforms also send `ANN.CommandCompleted`
282
+ `ANN.ArrangementChanged`, `ANN.HingeChanged`, `ANN.SplitViewColumnsStacked`, `ANN.DeepLinkDispatched` (iOS). Their
283
+ payloads are typed in `src/interfaces/ComponentEvents.ts` and `Events.ts`. Both platforms also send `ANN.CommandCompleted`
281
284
  (`CommandCompletedEvent`), which nothing in JS listens to.
282
285
  - Native components: `ANNSlot` (`src/api/slots`) and `ANNSafeAreaView` (`src/api/safeArea`), with C++ of their own in
283
286
  `ios/cpp`, which Android builds too (their states hold a size and a padding; the first one comes from the props
@@ -43,6 +43,7 @@ import {
43
43
  import { launchState } from '../../engine/launchState';
44
44
  import { watchBackListeners } from '../../engine/backListeners';
45
45
  import { resolveRoot, type RootsMap, type RootTarget, type UsesOfRootValue } from './roots';
46
+ import { listenToDispatchedLinks } from '../linking/dispatchedLinks';
46
47
  import {
47
48
  launchLink,
48
49
  launchRoot,
@@ -501,6 +502,7 @@ export function createNavigation<
501
502
  if (config.context !== undefined) setAppContext(config.context);
502
503
  if (config.appProvider) enableSlots(config.appProvider);
503
504
  listenToNavigationState();
505
+ listenToDispatchedLinks();
504
506
  watchSideMenus();
505
507
  listenToNativeScreens();
506
508
  listenToSplitViews();
@@ -0,0 +1,18 @@
1
+ import { DeviceEventEmitter, Platform } from 'react-native';
2
+ import { onNativeEvent } from '../../engine/native';
3
+ import type { DeepLinkDispatchedEvent } from '../../interfaces/Events';
4
+
5
+ let listening = false;
6
+
7
+ /**
8
+ * (iOS) Hands `Linking` the links the app dispatched that it didn't take from the native side: on React Native 0.88
9
+ * and newer, in an app with a scene delegate, it takes only the links a scene opened. `Linking` listens to its `url`
10
+ * events through `DeviceEventEmitter`, so every listener of the app gets them, the navigation's links too.
11
+ */
12
+ export function listenToDispatchedLinks() {
13
+ if (listening || Platform.OS !== 'ios') return;
14
+ listening = true;
15
+ onNativeEvent<DeepLinkDispatchedEvent>('DeepLinkDispatched', ({ url }) => {
16
+ DeviceEventEmitter.emit('url', { url });
17
+ });
18
+ }
@@ -105,6 +105,16 @@ export interface SplitViewColumnsStackedEvent {
105
105
  stacked: boolean;
106
106
  }
107
107
 
108
+ /**
109
+ * (iOS) A link the app dispatched (`dispatchDeepLinkURL`) that React Native's `Linking` doesn't take from the native
110
+ * side: on React Native 0.88 and newer, in an app whose Info.plist names a scene delegate, it takes only the links a
111
+ * scene opened. JavaScript hands it to `Linking` as a `url` event.
112
+ */
113
+ export interface DeepLinkDispatchedEvent {
114
+ /** The link. */
115
+ url: string;
116
+ }
117
+
108
118
  /**
109
119
  * A screen of the single React tree was destroyed and the slot still belongs to it: JavaScript removes the slot from
110
120
  * its tree. It is not sent for a prepared screen that was never pushed, nor when JavaScript reloads.
@@ -0,0 +1,275 @@
1
+ {
2
+ "description": "Every text the native side rejects a command with, or logs for a command without a promise: one sentence per case, the values in single quotes, {name} for a parameter. scripts/contract.mjs makes ios/Contract/ANNErrorTexts.{h,mm} and android/.../react/ErrorTexts.kt from it; `platforms` limits a text to one platform.",
3
+ "groups": [
4
+ {
5
+ "title": "Where the screen is",
6
+ "texts": [
7
+ {
8
+ "name": "screenNotShown",
9
+ "params": ["componentId"],
10
+ "text": "the screen '{componentId}' is not shown"
11
+ },
12
+ {
13
+ "name": "notInStack",
14
+ "params": ["componentId"],
15
+ "text": "the screen '{componentId}' is not in a stack"
16
+ },
17
+ {
18
+ "name": "firstScreenOfStack",
19
+ "params": ["componentId"],
20
+ "text": "the screen '{componentId}' is the first screen of its stack"
21
+ },
22
+ {
23
+ "name": "notInThisStack",
24
+ "params": ["componentId"],
25
+ "text": "the screen '{componentId}' is not in this stack"
26
+ },
27
+ {
28
+ "name": "notInModal",
29
+ "params": ["componentId"],
30
+ "text": "the screen '{componentId}' is not in a modal"
31
+ },
32
+ {
33
+ "name": "notInOverlay",
34
+ "params": ["componentId"],
35
+ "text": "the screen '{componentId}' is not in an overlay"
36
+ },
37
+ {
38
+ "name": "notInSplitView",
39
+ "params": ["componentId"],
40
+ "text": "the screen '{componentId}' is not in a split view"
41
+ },
42
+ {
43
+ "name": "neitherSplitViewNorStack",
44
+ "params": ["componentId"],
45
+ "text": "the screen '{componentId}' is neither in a split view nor in a stack"
46
+ },
47
+ {
48
+ "name": "noSuchColumn",
49
+ "params": ["componentId", "column"],
50
+ "text": "the split view of the screen '{componentId}' has no '{column}' column"
51
+ },
52
+ {
53
+ "name": "columnIsStack",
54
+ "params": ["componentId", "column"],
55
+ "text": "the '{column}' column of the split view of the screen '{componentId}' is a stack: it takes a screen, not a stack"
56
+ },
57
+ {
58
+ "name": "columnNotStack",
59
+ "params": ["componentId", "column"],
60
+ "text": "the '{column}' column of the split view of the screen '{componentId}' is not a stack"
61
+ },
62
+ {
63
+ "name": "noScreensForStack",
64
+ "params": ["componentId"],
65
+ "text": "there are no screens to put in the stack of the screen '{componentId}'"
66
+ },
67
+ {
68
+ "name": "alreadyShown",
69
+ "params": ["componentId"],
70
+ "text": "the screen '{componentId}' shows already: an id goes to one screen"
71
+ }
72
+ ]
73
+ },
74
+ {
75
+ "title": "Root, modals, the app",
76
+ "texts": [
77
+ {
78
+ "name": "setRootReplaced",
79
+ "params": ["rootId"],
80
+ "text": "setRoot was replaced by a newer setRoot before the root '{rootId}' finished showing"
81
+ },
82
+ {
83
+ "name": "rootDestroyed",
84
+ "params": ["rootId"],
85
+ "text": "the root '{rootId}' was destroyed before it showed"
86
+ },
87
+ {
88
+ "name": "modalWithoutRoot",
89
+ "params": ["componentId"],
90
+ "text": "the modal '{componentId}' can't be dismissed: there is no root under it"
91
+ },
92
+ {
93
+ "name": "nowhereToShow",
94
+ "params": [],
95
+ "text": "the navigation has nowhere to show screens: the app has no activity or window"
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ "title": "Native screens",
101
+ "texts": [
102
+ {
103
+ "name": "nativeScreenNotRegistered",
104
+ "params": ["name"],
105
+ "text": "no native screen is registered as '{name}'"
106
+ },
107
+ {
108
+ "name": "nativeScreenNotCreated",
109
+ "params": ["name"],
110
+ "text": "the native screen '{name}' could not be created: its creator returned nothing"
111
+ },
112
+ {
113
+ "name": "nativeCallReloaded",
114
+ "params": ["name", "componentId"],
115
+ "text": "JavaScript reloaded before the call '{name}' of the screen '{componentId}' was answered",
116
+ "doc": "The error of a call of a native screen whose JavaScript reloaded before it answered."
117
+ },
118
+ {
119
+ "name": "nativeCallNotRunning",
120
+ "params": ["name", "componentId"],
121
+ "text": "the navigation is not running: the call '{name}' of the screen '{componentId}' can't be answered",
122
+ "doc": "The error of a call of a native screen while no JavaScript can answer it."
123
+ }
124
+ ]
125
+ },
126
+ {
127
+ "title": "The layout",
128
+ "texts": [
129
+ {
130
+ "name": "unknownNodeType",
131
+ "params": ["type"],
132
+ "text": "the layout has a node of unknown type '{type}'"
133
+ },
134
+ {
135
+ "name": "nodeWithoutId",
136
+ "params": ["type"],
137
+ "text": "the layout has a node of type '{type}' without an id"
138
+ },
139
+ {
140
+ "name": "sideMenuChild",
141
+ "params": ["menuId", "type"],
142
+ "text": "the side menu '{menuId}' has a child of type '{type}': it takes SideMenuLeft, SideMenuCenter and SideMenuRight"
143
+ },
144
+ {
145
+ "name": "stackTakesScreens",
146
+ "params": ["stackId", "type"],
147
+ "text": "the stack '{stackId}' takes screens, not a '{type}'"
148
+ },
149
+ {
150
+ "name": "emptyStack",
151
+ "params": ["stackId"],
152
+ "text": "the stack '{stackId}' has no screens"
153
+ },
154
+ {
155
+ "name": "emptyTabs",
156
+ "params": ["tabsId"],
157
+ "text": "the tabs '{tabsId}' have no tabs"
158
+ },
159
+ {
160
+ "name": "tooManyTabs",
161
+ "params": [
162
+ "tabsId",
163
+ {
164
+ "name": "count",
165
+ "type": "int"
166
+ }
167
+ ],
168
+ "text": "the tabs '{tabsId}' have {count} tabs: Android shows at most 5",
169
+ "doc": "Only Android checks it: its tab bar shows at most 5 tabs."
170
+ },
171
+ {
172
+ "name": "splitViewColumns",
173
+ "params": ["splitViewId"],
174
+ "text": "the split view '{splitViewId}' needs its primary and its secondary column"
175
+ },
176
+ {
177
+ "name": "pairUnsupported",
178
+ "params": ["pairId"],
179
+ "text": "the pair '{pairId}' needs iOS 27.1 and an app built with its SDK",
180
+ "doc": "Only iOS checks it: Android has pairs on every version."
181
+ },
182
+ {
183
+ "name": "pairNeedsTwoScreens",
184
+ "params": ["pairId"],
185
+ "text": "the pair '{pairId}' needs two screens: its primary and its secondary"
186
+ },
187
+ {
188
+ "name": "nodeWithoutName",
189
+ "params": ["type", "nodeId"],
190
+ "text": "the layout has a node '{nodeId}' of type '{type}' without a name"
191
+ },
192
+ {
193
+ "name": "rootMissing",
194
+ "params": [],
195
+ "text": "the layout of setRoot has no root"
196
+ },
197
+ {
198
+ "name": "tabsInTabs",
199
+ "params": ["tabsId"],
200
+ "text": "the tabs '{tabsId}' have a tab of type 'BottomTabs': tabs don't go inside tabs"
201
+ },
202
+ {
203
+ "name": "sideMenuSides",
204
+ "params": ["menuId"],
205
+ "text": "the side menu '{menuId}' takes one SideMenuCenter and at most one SideMenuLeft and one SideMenuRight"
206
+ },
207
+ {
208
+ "name": "sideChildCount",
209
+ "params": ["sideId", "menuId"],
210
+ "text": "the side '{sideId}' of the side menu '{menuId}' needs exactly one child"
211
+ },
212
+ {
213
+ "name": "sideMenuInSide",
214
+ "params": ["menuId"],
215
+ "text": "the side menu '{menuId}' has a side menu in a side: a side menu doesn't go inside a side menu"
216
+ },
217
+ {
218
+ "name": "sideOutsideMenu",
219
+ "params": ["nodeId", "type"],
220
+ "text": "the layout has a node '{nodeId}' of type '{type}' outside a side menu"
221
+ },
222
+ {
223
+ "name": "splitViewInColumn",
224
+ "params": ["splitViewId"],
225
+ "text": "the split view '{splitViewId}' has a column of type 'SplitView': a split view doesn't go inside a split view"
226
+ },
227
+ {
228
+ "name": "idGivenTwice",
229
+ "params": ["nodeId"],
230
+ "text": "the layout gives the id '{nodeId}' to two nodes"
231
+ }
232
+ ]
233
+ },
234
+ {
235
+ "title": "Options, previews, any other failure",
236
+ "texts": [
237
+ {
238
+ "name": "unreadableOption",
239
+ "params": ["path", "componentId"],
240
+ "text": "the option '{path}' of the screen '{componentId}' has a value the navigation can't read"
241
+ },
242
+ {
243
+ "name": "unreadableDefaultOption",
244
+ "params": ["path"],
245
+ "text": "the option '{path}' of the default options has a value the navigation can't read",
246
+ "doc": "An unreadable value of `setDefaultOptions`: the default options belong to no screen."
247
+ },
248
+ {
249
+ "name": "previewGone",
250
+ "params": ["previewId"],
251
+ "text": "the preview '{previewId}' went without being opened"
252
+ },
253
+ {
254
+ "name": "couldNot",
255
+ "params": ["what", "reason"],
256
+ "text": "could not {what}: {reason}",
257
+ "doc": "Any other failure: what could not be done and why, `could not <what>: <reason>`."
258
+ },
259
+ {
260
+ "name": "notDoneYet",
261
+ "params": ["method"],
262
+ "text": "could not run '{method}': the native core doesn't do it yet",
263
+ "doc": "A command whose part of the native core is not written yet."
264
+ },
265
+ {
266
+ "name": "notAnswered",
267
+ "params": ["method"],
268
+ "text": "could not run '{method}': the native core let it go without an answer",
269
+ "doc": "A command that nothing in the native core answered: what took it let it go, or nothing took it.",
270
+ "platforms": ["ios"]
271
+ }
272
+ ]
273
+ }
274
+ ]
275
+ }
@@ -254,13 +254,14 @@ export type ElementAnimation = AppearingElementAnimation | DisappearingElementAn
254
254
  /**
255
255
  * An animation of one view of a screen that moves together with the transition, with or without a counterpart on the
256
256
  * other screen. The view is found by its `nativeID`, first on the screen that goes, then on the one that comes; one
257
- * that is not found is skipped while the rest plays. The transition waits until it is found. Without an animation of
258
- * the screens of its own, the screen that comes fades in (or the one that goes fades out) in 300 ms around the
259
- * elements. When the transition ends or is cancelled, the element gets its own values back. `x` and `y` are the
260
- * position in the parent of the element on both platforms. As on a side of a screen, don't set `x` with `translationX`
261
- * or `y` with `translationY` on one element: the translation plays and the position doesn't. (Android) A view whose
262
- * parent is a React view with `removeClippedSubviews` turned on, such as a child of a clipping list, is not moved: it
263
- * counts as not found.
257
+ * that is not found is skipped while the rest plays. The transition waits until it is found. An element that fails on
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
+ * and the transition and its command go on. Without an animation of the screens of its own, the screen that comes fades
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. `x` and `y` are the position in the parent of the element on both platforms. As on
262
+ * a side of a screen, don't set `x` with `translationX` or `y` with `translationY` on one element: the translation
263
+ * plays and the position doesn't. (Android) A view whose parent is a React view with `removeClippedSubviews` turned on,
264
+ * such as a child of a clipping list, is not moved: it counts as not found.
264
265
  */
265
266
  export interface ElementTransition {
266
267
  /** The `nativeID` of the view to animate. */
@@ -288,12 +289,15 @@ export interface ElementTransition {
288
289
  }
289
290
 
290
291
  /**
291
- * A view that flies from the screen that goes to the screen that comes, changing its place, size, corners and look
292
- * on the way. A pair whose view is not found on either screen is skipped while the rest plays, and the transition
293
- * waits until the views are found. Without an animation of the screens of its own, the screen that comes fades in (or
294
- * the one that goes fades out) in 300 ms around the pair. Text keeps its proportions and changes its picture within a
295
- * quarter of the flight. (Android) A picture that doesn't load within a second drops out of the transition, and so does
296
- * a pair with a view whose parent is a React view with `removeClippedSubviews` turned on: it counts as not found.
292
+ * A view that flies from the screen that goes to the screen that comes, changing its place, size, corners and look on
293
+ * the way. A pair whose view is not found on either screen is skipped while the rest plays, and the transition waits
294
+ * until the views are found. A pair that fails on the way (an error in its start or its flight) is skipped too, with a
295
+ * warning in the log: its views show and hide with their screens, and the transition and its command go on. (iOS) So is
296
+ * 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
+ * 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. (Android) A picture that doesn't load within a
299
+ * second drops out of the transition, and so does a pair with a view whose parent is a React view with
300
+ * `removeClippedSubviews` turned on: it counts as not found.
297
301
  */
298
302
  export interface SharedElementTransition {
299
303
  /** The `nativeID` of the view on the screen that goes. */
@@ -32,9 +32,11 @@ export type OptionsModalPresentationStyle =
32
32
  * (iOS) The system transition a modal comes and goes with: `'coverVertical'` (from below), `'crossDissolve'` (a fade),
33
33
  * `'flipHorizontal'` (a flip) or `'partialCurl'`. It is read when the modal shows and doesn't change afterwards;
34
34
  * `animations.showModal` with values of its own, and the zoom of iOS 18, go over it. UIKit flips only a modal over the
35
- * whole screen (`'fullScreen'`, `'overFullScreen'`): a sheet comes in as usual and flips only on its way out, and
36
- * `'partialCurl'` is accepted by UIKit only for a full-screen modal. An unknown string means `'coverVertical'`. Android
37
- * doesn't read it.
35
+ * whole screen (`'fullScreen'`, `'overFullScreen'`): a sheet comes in as usual and flips only on its way out. UIKit
36
+ * curls only a `'fullScreen'` modal over a screen that fills the window, so `'partialCurl'` with any other
37
+ * `modalPresentationStyle` (or without one), or over a modal that doesn't fill the screen, shows as `'coverVertical'`.
38
+ * A modal shown with `'partialCurl'` can't show another modal over it: that `showModal` rejects. An unknown string
39
+ * means `'coverVertical'`. Android doesn't read it.
38
40
  */
39
41
  export type OptionsModalTransitionStyle =
40
42
  'coverVertical' | 'crossDissolve' | 'flipHorizontal' | 'partialCurl';
@@ -59,18 +61,20 @@ export type OptionsModalSheetDetent = 'medium' | 'large' | 'content' | number;
59
61
  */
60
62
  export interface OptionsModalSheet {
61
63
  /**
62
- * The stops the sheet can rest on, and the user drags it between. On Android they are sorted by height and repeats
63
- * dropped; the Material sheet has three resting places at most: the lowest stop of the list, the highest, and
64
- * `'medium'` between them when the list has both `'medium'` and `'large'`. A stop without a place is dropped. On iOS
65
- * the stops are handed to UIKit in the order given, which wants them from the lowest to the highest; a list left
66
- * empty by unsupported values gives `['large']`.
64
+ * The stops the sheet can rest on, and the user drags it between, in any order: on both platforms they are sorted by
65
+ * height and repeats dropped. On iOS `'medium'` counts as half of `'large'` there, and `'content'` takes its place by
66
+ * the height of the content, again whenever that changes; a list left empty by unsupported values gives
67
+ * `['large']`. On Android the Material sheet has three resting places at most: the lowest stop of the list, the
68
+ * highest, and `'medium'` between them when the list has both `'medium'` and `'large'`. A stop without a place is
69
+ * dropped.
67
70
  * @default ['large']
68
71
  */
69
72
  detents?: OptionsModalSheetDetent[];
70
73
  /**
71
- * The stop the sheet opens on; a new value in `mergeOptions` moves the sheet there with an animation, and doesn't
72
- * send `sheetDetentChanged`. A value that isn't among `detents` opens on the lowest stop on iOS and is ignored on
73
- * Android.
74
+ * The stop the sheet opens on; a `mergeOptions` that names it moves the sheet there with an animation, and doesn't
75
+ * send `sheetDetentChanged`. Nothing else moves the sheet off the stop it stands at, the one the user dragged it to
76
+ * included: a `mergeOptions` without it, a new layout or new content. A value that isn't among `detents` opens on
77
+ * the lowest stop on iOS and is ignored on Android.
74
78
  * Without it, the lowest stop.
75
79
  */
76
80
  selectedDetent?: OptionsModalSheetDetent;
@@ -18,8 +18,8 @@ export interface SideMenuSide {
18
18
  visible?: boolean;
19
19
  /**
20
20
  * Whether the opening or closing that `visible` asks for is animated. With `false` it happens at once and the
21
- * screens of the menu get the same appearance events in the same order, except that on Android a menu that opens at
22
- * once sends its screens DidAppear without WillAppear. It acts only together with `visible` in the same merge.
21
+ * screens of the menu get the same appearance events in the same order: WillAppear, then DidAppear. It acts only
22
+ * together with `visible` in the same merge.
23
23
  * @default true
24
24
  */
25
25
  animate?: boolean;
@@ -32,15 +32,16 @@ export interface SideMenuSide {
32
32
  enabled?: boolean;
33
33
  /**
34
34
  * The width of the menu, in points on iOS and dp on Android. It is capped at the width of the side menu (iOS) and at
35
- * that width less 64 dp (Android). On iOS a change applies at once, also to an open menu. On Android it applies the
36
- * next time a screen in the side menu appears, the center's or a menu's.
35
+ * that width less 64 dp (Android). A change in `mergeOptions` applies at once, also to an open menu. A width set by
36
+ * a screen of the center acts while that screen shows.
37
37
  * Without it, 280 points on iOS and the width of the side menu less 64 dp on Android (the least gap the Material
38
38
  * drawer leaves).
39
39
  */
40
40
  width?: number;
41
41
  /**
42
- * (Android) The height of the menu in dp; a menu lower than the container is pinned to the top. It is read only when
43
- * the side menu is created. Without it, the menu takes the full height under the status bar. iOS doesn't read it.
42
+ * (Android) The height of the menu in dp; a menu lower than the container is pinned to the top. A change in
43
+ * `mergeOptions` applies at once, also to an open menu. Without it, the menu takes the full height under the status
44
+ * bar. iOS doesn't read it.
44
45
  */
45
46
  height?: number;
46
47
  /**
@@ -177,9 +177,10 @@ export interface OptionsStatusBar {
177
177
  */
178
178
  hideWithTopBar?: boolean;
179
179
  /**
180
- * (iOS) Whether a blur shows under the status bar, drawn over the screen in the frame the status bar has when the
181
- * option applies. It applies when the screen appears and through `mergeOptions`; `false` removes it. The blur does
182
- * not follow a rotation or a change of window size.
180
+ * (iOS) Whether a blur shows under the status bar, drawn over the screen in the status bar's frame. It applies when
181
+ * the screen appears and through `mergeOptions`; `false` removes it. The blur follows the status bar's frame as it
182
+ * changes: a rotation, a new window size, the status bar hidden or shown. Android has no blur under the status bar,
183
+ * so it does nothing there.
183
184
  * @default false
184
185
  */
185
186
  blur?: boolean;