@apexnative/navigation 1.0.0-alpha.3 → 1.0.0-alpha.5

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 (239) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/android/CLAUDE.md +26 -9
  3. package/android/CORE.md +32 -17
  4. package/android/RECIPES.md +9 -3
  5. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +25 -9
  6. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  7. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  8. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  9. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  10. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  11. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  12. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  14. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  15. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  16. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  17. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +6 -6
  18. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  19. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  20. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +33 -22
  21. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +5 -4
  22. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  23. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +39 -20
  24. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +6 -6
  26. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +10 -5
  27. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +47 -46
  28. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +34 -7
  29. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  30. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -4
  31. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  32. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +12 -12
  33. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +4 -3
  34. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  35. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  37. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  38. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  39. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  40. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +3 -2
  41. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  42. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +25 -17
  43. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  44. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +6 -2
  45. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  46. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  47. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  48. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +5 -5
  49. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  50. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +45 -14
  51. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +25 -8
  52. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +8 -5
  53. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +8 -8
  54. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  55. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +1 -1
  56. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  57. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +61 -15
  58. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +28 -18
  59. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +25 -12
  60. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +2 -1
  61. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +85 -29
  62. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +2 -2
  63. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +7 -5
  64. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +5 -8
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +14 -11
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +56 -21
  70. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +4 -2
  71. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  72. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  73. package/cli/doctor/checks/app.js +61 -13
  74. package/cli/doctor/checks/splash.js +4 -22
  75. package/cli/migrate/native.js +18 -0
  76. package/cli/setup/source.js +2 -1
  77. package/cli/setup/steps/mainApplication.js +134 -19
  78. package/cli/splash/index.js +3 -1
  79. package/docs-md/architecture/transitions.md +6 -7
  80. package/docs-md/containers/modals.md +2 -2
  81. package/docs-md/guides/cli.md +1 -2
  82. package/docs-md/help/glossary.md +1 -1
  83. package/docs-md/help/troubleshooting.md +22 -5
  84. package/docs-md/index.json +4 -0
  85. package/docs-md/migration/from-react-native-navigation.md +8 -2
  86. package/docs-md/screen-ui/back-and-gestures.md +24 -2
  87. package/docs-md/start/installation.md +4 -2
  88. package/ios/CLAUDE.md +17 -5
  89. package/ios/CORE.md +18 -13
  90. package/ios/Contract/ANNCommandAnswer.h +9 -2
  91. package/ios/Contract/ANNCommandAnswer.mm +28 -30
  92. package/ios/Contract/ANNCommandContract.h +15 -0
  93. package/ios/Contract/ANNCommandContract.mm +78 -0
  94. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  95. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  96. package/ios/Core/ANNErrorHandler.h +1 -1
  97. package/ios/Core/ANNErrorHandler.mm +3 -1
  98. package/ios/Core/ANNEventEmitter.h +1 -1
  99. package/ios/Core/ANNEventEmitter.mm +2 -2
  100. package/ios/Core/ANNJavaScriptCalls.h +34 -0
  101. package/ios/Core/ANNJavaScriptCalls.mm +61 -0
  102. package/ios/Core/ANNNavigationState.h +7 -5
  103. package/ios/Core/ANNNavigationState.mm +8 -7
  104. package/ios/Core/ANNNodeHelper.h +32 -12
  105. package/ios/Core/ANNNodeHelper.mm +100 -3
  106. package/ios/Core/ANNRenderWait.h +15 -1
  107. package/ios/Core/ANNRenderWait.mm +119 -17
  108. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  109. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  110. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  111. package/ios/Layouts/Modal/ANNModalCoordinator.mm +55 -14
  112. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  113. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  114. package/ios/Layouts/Screen/ANNComponentViewController.h +8 -0
  115. package/ios/Layouts/Screen/ANNComponentViewController.mm +32 -5
  116. package/ios/Layouts/Screen/ANNScreenPlace.h +41 -0
  117. package/ios/Layouts/Screen/ANNScreenPlace.mm +175 -0
  118. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  119. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  120. package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -2
  121. package/ios/Layouts/Stack/ANNPreviewPush.h +5 -5
  122. package/ios/Layouts/Stack/ANNPreviewPush.mm +85 -22
  123. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  124. package/ios/Layouts/Stack/ANNStackController.mm +26 -3
  125. package/ios/Layouts/Stack/ANNStackQueue.h +3 -1
  126. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  127. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  128. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  129. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  130. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  131. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +13 -5
  132. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +2 -2
  133. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +109 -7
  134. package/ios/Options/ANNOptionsCache.h +7 -6
  135. package/ios/Options/ANNSearchBarOptions.h +4 -3
  136. package/ios/Options/ANNUserChoice.h +57 -0
  137. package/ios/Options/ANNUserChoice.mm +44 -0
  138. package/ios/Options/Params/ANNImageSource.h +61 -0
  139. package/ios/Options/Params/ANNImageSource.mm +101 -0
  140. package/ios/Options/Params/ANNOptionImages.h +37 -0
  141. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  142. package/ios/Options/Params/Image.h +11 -2
  143. package/ios/Options/Params/Image.mm +15 -2
  144. package/ios/Options/Params/ImageParser.h +5 -5
  145. package/ios/Options/Params/ImageParser.mm +28 -46
  146. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  147. package/ios/RECIPES.md +11 -5
  148. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  149. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  150. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  151. package/ios/TopBar/ANNBarButtons.h +9 -5
  152. package/ios/TopBar/ANNBarButtons.mm +211 -63
  153. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  154. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  155. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  156. package/ios/TopBar/ANNLargeTitlePresenter.mm +26 -3
  157. package/ios/TopBar/ANNSearchPresenter.mm +170 -19
  158. package/ios/TopBar/ANNTopBarPresenter.h +5 -0
  159. package/ios/TopBar/ANNTopBarPresenter.mm +60 -11
  160. package/ios/TurboModules/ANNTurboModule.mm +39 -21
  161. package/lib/module/ARCHITECTURE.md +18 -18
  162. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  163. package/lib/module/api/commands/commands.js +54 -6
  164. package/lib/module/api/commands/commands.js.map +1 -1
  165. package/lib/module/api/navigation.js.map +1 -1
  166. package/lib/module/engine/commands.js +9 -7
  167. package/lib/module/engine/commands.js.map +1 -1
  168. package/lib/module/engine/layout.js +13 -9
  169. package/lib/module/engine/layout.js.map +1 -1
  170. package/lib/module/engine/options.js +44 -11
  171. package/lib/module/engine/options.js.map +1 -1
  172. package/lib/module/engine/places.js +52 -7
  173. package/lib/module/engine/places.js.map +1 -1
  174. package/lib/module/engine/props.js +30 -1
  175. package/lib/module/engine/props.js.map +1 -1
  176. package/lib/module/engine/rememberedOptions.js +1 -1
  177. package/lib/module/engine/rememberedOptions.js.map +1 -1
  178. package/lib/module/engine/screens.js +22 -12
  179. package/lib/module/engine/screens.js.map +1 -1
  180. package/lib/module/interfaces/contract/commands.json +101 -0
  181. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +5 -2
  182. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  183. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  184. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  185. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  186. package/lib/typescript/api/events/navigationEvents.d.ts +1 -1
  187. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  188. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  189. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  190. package/lib/typescript/api/navigation.d.ts +4 -1
  191. package/lib/typescript/api/navigation.d.ts.map +1 -1
  192. package/lib/typescript/engine/commands.d.ts.map +1 -1
  193. package/lib/typescript/engine/options.d.ts +5 -2
  194. package/lib/typescript/engine/options.d.ts.map +1 -1
  195. package/lib/typescript/engine/places.d.ts +7 -2
  196. package/lib/typescript/engine/places.d.ts.map +1 -1
  197. package/lib/typescript/engine/props.d.ts +8 -1
  198. package/lib/typescript/engine/props.d.ts.map +1 -1
  199. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  200. package/lib/typescript/engine/screens.d.ts.map +1 -1
  201. package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
  202. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  203. package/lib/typescript/interfaces/Events.d.ts +19 -10
  204. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  205. package/lib/typescript/interfaces/Options.d.ts +1 -1
  206. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  207. package/lib/typescript/interfaces/options/animations.d.ts +23 -4
  208. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  209. package/lib/typescript/interfaces/options/buttons.d.ts +13 -5
  210. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  211. package/lib/typescript/interfaces/options/stack.d.ts +9 -0
  212. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  213. package/lib/typescript/interfaces/options/topBar.d.ts +22 -9
  214. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  215. package/package.json +1 -1
  216. package/src/ARCHITECTURE.md +18 -18
  217. package/src/adapters/NativeANNTurboModule.ts +5 -2
  218. package/src/api/commands/commands.ts +48 -7
  219. package/src/api/commands/presentation.ts +4 -3
  220. package/src/api/events/navigationEvents.ts +1 -1
  221. package/src/api/hooks/useNavigation.ts +1 -1
  222. package/src/api/navigation.ts +4 -1
  223. package/src/engine/commands.ts +19 -7
  224. package/src/engine/layout.ts +16 -9
  225. package/src/engine/options.ts +39 -11
  226. package/src/engine/places.ts +65 -7
  227. package/src/engine/props.ts +30 -1
  228. package/src/engine/rememberedOptions.ts +4 -1
  229. package/src/engine/screens.tsx +23 -13
  230. package/src/interfaces/ComponentEvents.ts +2 -2
  231. package/src/interfaces/Events.ts +19 -10
  232. package/src/interfaces/Options.ts +1 -0
  233. package/src/interfaces/contract/commands.json +101 -0
  234. package/src/interfaces/options/animations.ts +24 -4
  235. package/src/interfaces/options/buttons.ts +13 -5
  236. package/src/interfaces/options/stack.ts +9 -0
  237. package/src/interfaces/options/topBar.ts +22 -9
  238. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  239. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
@@ -15,14 +15,19 @@
15
15
  #import "ANNRenderWait.h"
16
16
  #import "ANNShownScreens.h"
17
17
  #import "ANNStackCommands.h"
18
+ #import "ANNStackController.h"
18
19
  #import "ANNStackQueue.h"
19
20
  #import "ApexNavigation+Internal.h"
20
21
  #import "UIViewController+LayoutProtocol.h"
21
22
  #import <React/RCTLog.h>
22
23
 
23
- // The limits of the bar components of a push: title and background 1 s, buttons 0.5 s.
24
+ // The limits of the bar components of a push: title and background 1 s, buttons 0.5 s. With `waitForRender` unset they
25
+ // count from the wait's start, as a stack's push; with `true`, from the content's end.
24
26
  static const ANNBarWaitLimits ANNColumnBarLimits = {1, 0.5};
25
27
 
28
+ // How long the push's wait waits for the screen's first content when `waitForRender` is not set, as a stack's push.
29
+ static const NSTimeInterval ANNColumnRenderLimit = 0.5;
30
+
26
31
  // The split view of `node`: the node itself or the nearest of its layout parents that has columns.
27
32
  static UIViewController *ANNSplitViewOf(UIViewController *node) {
28
33
  for (UIViewController *parent = node; parent; parent = parent.layoutParent) {
@@ -45,17 +50,26 @@ static BOOL ANNIsOnScreen(UIViewController *node) {
45
50
 
46
51
  @class ANNColumnRequest;
47
52
 
53
+ // A request the newest of its column superseded: its answer and the id it resolves with, its own screen's (each
54
+ // `showInColumn` answers its own screen, as on Android).
55
+ @interface ANNSupersededRequest : NSObject
56
+ @property(nonatomic, strong) ANNCommandAnswer *answer;
57
+ @property(nonatomic, copy) NSString *value;
58
+ @end
59
+
60
+ @implementation ANNSupersededRequest
61
+ @end
62
+
48
63
  // "The last request of a column" (`showInColumn` step 2): one per split view and column. The newest request decides
49
- // what the requests it superseded answer: its id, or its rejection.
64
+ // when the requests it superseded answer; each of them resolves with its own screen's id whatever the newest one's
65
+ // outcome, as on Android.
50
66
  @interface ANNColumnRecord : NSObject
51
67
  @property(nonatomic, weak, nullable) UIViewController *splitView;
52
68
  @property(nonatomic, copy) NSString *column;
53
69
  // Weakly: what runs the newest request holds it (the waiting requests, the split view's call, the push).
54
70
  @property(nonatomic, weak, nullable) ANNColumnRequest *newest;
55
- @property(nonatomic, strong) NSMutableArray<ANNCommandAnswer *> *superseded;
71
+ @property(nonatomic, strong) NSMutableArray<ANNSupersededRequest *> *superseded;
56
72
  @property(nonatomic) BOOL ended;
57
- @property(nonatomic, copy, nullable) NSString *value;
58
- @property(nonatomic, copy, nullable) NSString *rejection;
59
73
  @end
60
74
 
61
75
  @implementation ANNColumnRecord
@@ -184,10 +198,11 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
184
198
  return record;
185
199
  }
186
200
 
187
- // Step 1, the push's wait: `waitForRender` unset waits for the bar components only, `true` for the content as long as
188
- // it takes (with the rule for content nobody knows of), then the bar components; `false` for nothing; nothing either
189
- // while the source's place isn't seen. Read from the screen's own options over the defaults: it has no place yet. With
190
- // content, the screen waits unseen in the source's window, as a layer that waits to show.
201
+ // Step 1, the push's wait, as a stack's push: `waitForRender` unset waits for the content at most 0.5 s, `true` as long
202
+ // as it takes (with the rule for content nobody knows of), then the bar components; `false` for nothing; nothing either
203
+ // while the source's place isn't seen. The content's end waits for the calls JavaScript made by then, so that the
204
+ // options of the screen's first commit are applied before it shows. Read from the screen's own options over the
205
+ // defaults: it has no place yet. The screen waits unseen in the source's window, as a layer that waits to show.
191
206
  + (void)startWaitOf:(ANNColumnRequest *)request {
192
207
  UIViewController *screen = request.screen;
193
208
  Bool *waitForRender = [screen resolveOptionsWithDefault].animations.push.waitForRender;
@@ -198,20 +213,22 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
198
213
  [self readyOnNextTurnOf:request];
199
214
  return;
200
215
  }
201
- BOOL content = waitForRender.hasValue;
216
+ BOOL bounded = !waitForRender.hasValue;
202
217
  __weak UIViewController *weakScreen = screen;
203
218
  NSArray<UIViewController *> * (^screens)(void) = ^NSArray<UIViewController *> * {
204
219
  UIViewController *waited = weakScreen;
205
220
  return waited ? waited.waitedComponentViewControllers : @[];
206
221
  };
207
- ANNRenderWaitContent waited = content ? ANNRenderWaitContentNode : ANNRenderWaitContentNone;
208
- ANNRenderWait *wait = [[ANNRenderWait alloc] initWithContent:waited
209
- node:content ? screen : nil
210
- screens:screens
211
- limit:0
212
- bar:ANNRenderWaitBarAfterContent
213
- barLimits:ANNColumnBarLimits];
214
- wait.unknownContentRule = content;
222
+ ANNRenderWait *wait =
223
+ [[ANNRenderWait alloc] initWithContent:ANNRenderWaitContentNode
224
+ node:screen
225
+ screens:screens
226
+ limit:bounded ? ANNColumnRenderLimit : 0
227
+ bar:ANNRenderWaitBarAfterContent
228
+ barLimits:ANNColumnBarLimits];
229
+ wait.unknownContentRule = !bounded;
230
+ wait.settlesThroughJavaScript = YES;
231
+ wait.barLimitsFromStart = bounded;
215
232
  __weak ANNColumnRequest *weakRequest = request;
216
233
  wait.canEnd = ^BOOL {
217
234
  ANNColumnRequest *waiting = weakRequest;
@@ -225,7 +242,7 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
225
242
  if (!ready) {
226
243
  return;
227
244
  }
228
- // Without content the screen makes it right before it shows (as a push does).
245
+ // A screen that didn't render while parked makes its content right before it shows (as a push does).
229
246
  [ANNSplitViewCommands render:ready];
230
247
  if (ready.starting) {
231
248
  [ANNSplitViewCommands readyOnNextTurnOf:ready];
@@ -233,14 +250,12 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
233
250
  [ANNSplitViewCommands readyOf:ready];
234
251
  }
235
252
  };
236
- if (content) {
237
- wait.setUp = ^{
238
- ANNColumnRequest *waiting = weakRequest;
239
- if (waiting) {
240
- [ANNSplitViewCommands park:waiting];
241
- }
242
- };
243
- }
253
+ wait.setUp = ^{
254
+ ANNColumnRequest *waiting = weakRequest;
255
+ if (waiting) {
256
+ [ANNSplitViewCommands park:waiting];
257
+ }
258
+ };
244
259
  request.wait = wait;
245
260
  request.starting = YES;
246
261
  @try {
@@ -281,6 +296,13 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
281
296
  [screen setWaitForRender:YES];
282
297
  }
283
298
  if (window) {
299
+ __weak ANNColumnRequest *placed = request;
300
+ ANNScreenPlace * (^place)(void) = ^ANNScreenPlace * {
301
+ return [ANNSplitViewCommands placeOf:placed];
302
+ };
303
+ for (ANNComponentViewController *each in ANNStackScreensOfEntry(screen)) {
304
+ each.placeWhileParked = place;
305
+ }
284
306
  request.parking = [ANNParking new];
285
307
  [request.parking park:screen inView:window];
286
308
  }
@@ -304,6 +326,34 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
304
326
  }
305
327
  }
306
328
 
329
+ // Where the parked screen will show, as far as it is known now: the column's stack (whose screens it replaces), the
330
+ // navigation controller UIKit keeps a column that is a screen alone in, or the source's stack while the split view
331
+ // shows as one stack. Nil without one: the screen lays out with its view's own safe area.
332
+ + (nullable ANNScreenPlace *)placeOf:(ANNColumnRequest *)request {
333
+ UIViewController *screen = request.screen;
334
+ UIViewController *source = request.source;
335
+ if (!screen || !source) {
336
+ return nil;
337
+ }
338
+ UIViewController *splitView = ANNSplitViewOf(source);
339
+ UINavigationController *stack = nil;
340
+ if (splitView && !ANNIsCollapsedIntoCompact(splitView)) {
341
+ UIViewController *columnNode =
342
+ [(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
343
+ stack = [columnNode isKindOfClass:UINavigationController.class]
344
+ ? (UINavigationController *)columnNode
345
+ : columnNode.navigationController;
346
+ } else {
347
+ stack = [ANNStackCommands stackOf:source].shownNavigationController;
348
+ }
349
+ if (!stack) {
350
+ return nil;
351
+ }
352
+ return [ANNScreenPlace placeOfEntry:screen
353
+ inStack:stack
354
+ options:[ANNStackOptionsScreen(screen) resolveOptionsWithDefault]];
355
+ }
356
+
307
357
  // The screen leaves its place and the waiting requests; UIKit ends its departure from the window here (it shows in
308
358
  // this turn, or goes).
309
359
  + (void)leaveWaitingPlace:(ANNColumnRequest *)request {
@@ -353,18 +403,23 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
353
403
  [self request:request endedWithValue:nil rejection:text];
354
404
  }
355
405
 
356
- // Superseded at its readiness: its screen goes without having shown (no events), and its answer is the newest
357
- // request's, at once when that answered.
406
+ // Superseded at its readiness: its screen goes without having shown (no events). It answers when the newest request
407
+ // does, at once when that answered, with its own screen's id: the newest one's rejection (a container for a stack
408
+ // column, a split view that went) is about that request only.
358
409
  + (void)supersede:(ANNColumnRequest *)request {
359
410
  [self leaveWaitingPlace:request];
360
411
  request.done = YES;
412
+ NSString *value = ANNStackAnswerIdOf(request.screen, ANNStackAnswerCommandShowInColumn);
361
413
  [request.screen destroy];
362
414
  ANNColumnRecord *record = request.record;
363
415
  if (record.ended) {
364
- [self answer:request.answer value:record.value rejection:record.rejection];
416
+ [request.answer resolve:value];
365
417
  return;
366
418
  }
367
- [record.superseded addObject:request.answer];
419
+ ANNSupersededRequest *superseded = [ANNSupersededRequest new];
420
+ superseded.answer = request.answer;
421
+ superseded.value = value;
422
+ [record.superseded addObject:superseded];
368
423
  }
369
424
 
370
425
  // (a) The split view shows the screen in the column: a stack column's screens are replaced without an animation and
@@ -373,14 +428,26 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
373
428
  // `DidDisappear` of the screens that left, `DidAppear` of the new one, the state, then the answer.
374
429
  + (void)show:(ANNColumnRequest *)request inSplitView:(UIViewController *)splitView {
375
430
  UIViewController *screen = request.screen;
431
+ UIViewController *columnNode =
432
+ [(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
433
+ // A stack column takes what a stack takes, a screen or a pair; any other layout rejects `columnIsStack`, as on
434
+ // Android. A column that is a screen alone takes any layout in its place.
435
+ if ([columnNode isKindOfClass:UINavigationController.class] &&
436
+ [ANNLayoutValidator checkStackChild:request.layout
437
+ stackId:columnNode.layoutInfo.componentId ?: @""]) {
438
+ [self leaveWaitingPlace:request];
439
+ [screen destroy];
440
+ [self request:request
441
+ endedWithValue:nil
442
+ rejection:[ANNErrorTexts columnIsStack:request.componentId column:request.column]];
443
+ return;
444
+ }
376
445
  // Before the parking lets go of it, so that UIKit's calls stay silent until the end.
377
446
  [ANNAppearanceDispatcher driveAppearanceOf:@[ screen ]];
378
447
  request.driven = YES;
379
448
  [self leaveWaitingPlace:request];
380
449
  // A screen alone in a column has the split view as its parent by the layout (UIKit puts it into a navigation
381
450
  // controller of its own); a stack column's stack is its parent.
382
- UIViewController *columnNode =
383
- [(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
384
451
  if (columnNode && ![columnNode isKindOfClass:UINavigationController.class]) {
385
452
  [screen setExplicitLayoutParent:splitView];
386
453
  }
@@ -485,7 +552,8 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
485
552
 
486
553
  #pragma mark - The answers
487
554
 
488
- // The request answers once; when it is the newest of its column, the requests it superseded answer the same.
555
+ // The request answers once; when it is the newest of its column, the requests it superseded answer then, each with its
556
+ // own screen's id.
489
557
  + (void)request:(ANNColumnRequest *)request
490
558
  endedWithValue:(NSString *)value
491
559
  rejection:(NSString *)rejection {
@@ -499,13 +567,11 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
499
567
  return;
500
568
  }
501
569
  record.ended = YES;
502
- record.value = value;
503
- record.rejection = rejection;
504
570
  record.newest = nil;
505
- NSArray<ANNCommandAnswer *> *superseded = [record.superseded copy];
571
+ NSArray<ANNSupersededRequest *> *superseded = [record.superseded copy];
506
572
  [record.superseded removeAllObjects];
507
- for (ANNCommandAnswer *answer in superseded) {
508
- [self answer:answer value:value rejection:rejection];
573
+ for (ANNSupersededRequest *each in superseded) {
574
+ [each.answer resolve:each.value];
509
575
  }
510
576
  // A request that begins from now on starts a record of its own.
511
577
  UIViewController *splitView = record.splitView;
@@ -214,19 +214,21 @@ static UISplitViewControllerColumn ANNSplitViewColumn(NSString *name) {
214
214
  completion:(ANNTransitionCompletionBlock)completion
215
215
  rejection:(ANNTransitionRejectionBlock)rejection {
216
216
  UIViewController *previous = _columns[column];
217
- NSString *fromId = fromViewController.layoutInfo.componentId;
217
+ NSString *fromId = fromViewController.layoutInfo.componentId ?: @"";
218
218
  if (!previous) {
219
219
  rejection([ANNErrorTexts noSuchColumn:fromId column:column], nil);
220
220
  return;
221
221
  }
222
222
  if ([previous isKindOfClass:UINavigationController.class]) {
223
- // UIKit does not take a navigation controller among the screens of another.
223
+ // UIKit does not take a navigation controller among the screens of another. The core rejects every layout a
224
+ // stack doesn't take before it asks; this guards the module's own call.
224
225
  if ([screen isKindOfClass:UINavigationController.class]) {
225
226
  rejection([ANNErrorTexts columnIsStack:fromId column:column], nil);
226
227
  return;
227
228
  }
228
229
  // In place, as a column of UIKit apps changes; UIKit animates a column it brings on top.
229
230
  [(UINavigationController *)previous setStackChildren:@[ screen ]
231
+ inColumn:column
230
232
  fromViewController:fromViewController
231
233
  animated:NO
232
234
  completion:^{
@@ -6,11 +6,11 @@
6
6
  NS_ASSUME_NONNULL_BEGIN
7
7
 
8
8
  /// The preview of a push (`usePreview`): a push that waits for a tap on its preview. Its screen is made and renders
9
- /// unseen, out of the stack, its key kept; the view with `preview.nativeID` is looked for on the source screen at once
10
- /// and on the next frames, 30 tries in all; found, the preview module (`ANNPreviewInteraction`) shows the screen from
11
- /// it on a long press. A tap that commits pushes the screen without an animation and without a wait, or goes back to
12
- /// the entry with its key; a preview that goes without being opened destroys its screen and rejects the push. Main
13
- /// queue.
9
+ /// unseen, out of the stack, its key kept; the view with `preview.nativeID` is looked for on the source screen at once,
10
+ /// then at each mount of the source's content (on each frame for a slot screen), for at most 0.5 s; found, the preview module (`ANNPreviewInteraction`)
11
+ /// shows the screen from it on a long press. A tap that commits pushes the screen without an animation and without a
12
+ /// wait, or goes back to the entry with its key; a preview that goes without being opened destroys its screen and
13
+ /// rejects the push. Main queue.
14
14
  @interface ANNPreviewPush : NSObject
15
15
 
16
16
  - (instancetype)init NS_UNAVAILABLE;
@@ -6,14 +6,16 @@
6
6
  #import "ANNPopoverPresenter.h"
7
7
  #import "ANNPreviewInteraction.h"
8
8
  #import "ANNReloadCoordinator.h"
9
+ #import "ANNSlotScreenView.h"
9
10
  #import "ANNStackCommands.h"
10
11
  #import "ANNStackController.h"
11
12
  #import "ApexNavigation+Internal.h"
12
13
  #import "UIViewController+LayoutProtocol.h"
13
14
 
14
- // The view of a component mounts a frame or so after the command that rendered it: it is looked for this many times,
15
- // a frame apart.
16
- static const NSUInteger ANNPreviewSearchTries = 30;
15
+ // The view of a component mounts a frame or so after the command that rendered it: it is looked for at each mount of
16
+ // the source's content until this limit (30 frames), then the preview goes, as with a `nativeID` no view has.
17
+ static const NSTimeInterval ANNPreviewSearchLimit = 30.0 / 60;
18
+ // Where the source's mounts can't be heard, a frame apart.
17
19
  static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
18
20
 
19
21
  // One preview from its push to its end: the tap took it, or it went.
@@ -28,7 +30,8 @@ static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
28
30
  @property(nonatomic, copy) NSString *componentId;
29
31
  @property(nonatomic, copy) NSString *what;
30
32
  @property(nonatomic) NSUInteger generation;
31
- @property(nonatomic) NSUInteger tries;
33
+ // The content whose mounts the search hears, while it looks.
34
+ @property(nonatomic, weak, nullable) UIView<ANNComponentProtocol> *watched;
32
35
  @property(nonatomic) BOOL attached;
33
36
  @property(nonatomic) BOOL done;
34
37
  // The screen's unseen place in the main window, at its preview size, until UIKit takes its view for the menu.
@@ -84,7 +87,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
84
87
  [screen destroy];
85
88
  @throw;
86
89
  }
87
- [self search:record];
90
+ [self startSearch:record];
88
91
  }
89
92
 
90
93
  // The screen renders as now: its view waits unseen in the main window, at the size of the preview, so that its content
@@ -110,41 +113,99 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
110
113
 
111
114
  #pragma mark - The search
112
115
 
113
- // Each try asks first whether the preview still lives: a source that went makes it go, a reload stops it silently.
114
- + (void)search:(ANNPreviewRecord *)record {
115
- if (record.done || record.attached) {
116
+ // The view is looked for at once; else again at each mount of the source's content, where it comes with one of them,
117
+ // and a last time at the limit, when the preview goes. Both later steps keep the generation they were made with: after
118
+ // a reload they do nothing.
119
+ + (void)startSearch:(ANNPreviewRecord *)record {
120
+ if ([self search:record last:NO]) {
116
121
  return;
117
122
  }
123
+ UIViewController *source = record.source;
124
+ // A source that is a container (a stack) is heard through the screen it shows.
125
+ UIView<ANNComponentProtocol> *content =
126
+ source.reactView ?: source.presentedComponentViewController.reactView;
127
+ __weak ANNPreviewRecord *weakRecord = record;
128
+ NSUInteger generation = record.generation;
129
+ // A slot screen hears only the first mount of its slot, not those deeper in it, and a container may show no React
130
+ // content yet: there the view is looked for on each frame until the limit.
131
+ if (!content || [content isKindOfClass:ANNSlotScreenView.class]) {
132
+ [self searchNextFrame:record];
133
+ } else {
134
+ record.watched = content;
135
+ [content setContentDidMount:^{
136
+ ANNPreviewRecord *searching = weakRecord;
137
+ if (searching && generation == ANNReloadCoordinator.generation) {
138
+ [ANNPreviewPush search:searching last:NO];
139
+ }
140
+ }
141
+ forKey:[self mountKeyOf:record]];
142
+ }
143
+ int64_t delay = (int64_t)(ANNPreviewSearchLimit * NSEC_PER_SEC);
144
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), ^{
145
+ ANNPreviewRecord *searching = weakRecord;
146
+ if (searching && generation == ANNReloadCoordinator.generation) {
147
+ [ANNPreviewPush search:searching last:YES];
148
+ }
149
+ });
150
+ }
151
+
152
+ // One more search on the next frame, and so on until the view is found or the preview goes; after a reload, none.
153
+ + (void)searchNextFrame:(ANNPreviewRecord *)record {
154
+ __weak ANNPreviewRecord *weakRecord = record;
155
+ NSUInteger generation = record.generation;
156
+ int64_t delay = (int64_t)(ANNPreviewSearchInterval * NSEC_PER_SEC);
157
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), ^{
158
+ ANNPreviewRecord *searching = weakRecord;
159
+ if (searching && generation == ANNReloadCoordinator.generation &&
160
+ ![ANNPreviewPush search:searching last:NO]) {
161
+ [ANNPreviewPush searchNextFrame:searching];
162
+ }
163
+ });
164
+ }
165
+
166
+ // YES when the search is over: the view was found, or the preview went or stopped. Each search asks first whether the
167
+ // preview still lives: a source that went makes it go, a reload stops it silently. The last one, not finding the view,
168
+ // makes the preview go.
169
+ + (BOOL)search:(ANNPreviewRecord *)record last:(BOOL)last {
170
+ if (record.done || record.attached) {
171
+ return YES;
172
+ }
118
173
  if (record.generation != ANNReloadCoordinator.generation) {
119
- return;
174
+ return YES;
120
175
  }
121
176
  UIViewController *source = record.source;
122
177
  if (!source || source.nodeHelper.destroyed) {
123
178
  [self gone:record];
124
- return;
179
+ return YES;
125
180
  }
126
181
  // Read only: the view is found by its `nativeID`, and its tag is its current Fabric tag.
127
182
  UIView *view = [ANNPopoverPresenter viewWithNativeID:record.nativeID in:source.viewIfLoaded];
128
183
  if (view) {
129
184
  [self attach:record toView:view source:source];
130
- return;
185
+ return YES;
131
186
  }
132
- if (++record.tries >= ANNPreviewSearchTries) {
187
+ if (last) {
133
188
  [self gone:record];
134
- return;
189
+ return YES;
135
190
  }
136
- __weak ANNPreviewRecord *weakRecord = record;
137
- int64_t delay = (int64_t)(ANNPreviewSearchInterval * NSEC_PER_SEC);
138
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), ^{
139
- ANNPreviewRecord *searching = weakRecord;
140
- if (searching) {
141
- [ANNPreviewPush search:searching];
142
- }
143
- });
191
+ return NO;
192
+ }
193
+
194
+ // The key of the search's mount handler: one per preview, so that two previews of one source don't replace each other.
195
+ + (NSString *)mountKeyOf:(ANNPreviewRecord *)record {
196
+ return [@"preview." stringByAppendingString:record.previewId];
197
+ }
198
+
199
+ // The search stops hearing the mounts: only its own handler goes.
200
+ + (void)stopWatching:(ANNPreviewRecord *)record {
201
+ UIView<ANNComponentProtocol> *content = record.watched;
202
+ record.watched = nil;
203
+ [content setContentDidMount:nil forKey:[self mountKeyOf:record]];
144
204
  }
145
205
 
146
206
  + (void)attach:(ANNPreviewRecord *)record toView:(UIView *)view source:(UIViewController *)source {
147
207
  record.attached = YES;
208
+ [self stopWatching:record];
148
209
  __weak ANNPreviewRecord *weakRecord = record;
149
210
  BOOL (^commit)(void) = ^BOOL {
150
211
  return [ANNPreviewPush commit:weakRecord];
@@ -231,9 +292,10 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
231
292
  [record.answer reject:[ANNErrorTexts previewGone:record.previewId]];
232
293
  }
233
294
 
234
- // The record is done: the screen leaves its unseen place, the table forgets it.
295
+ // The record is done: the search stops, the screen leaves its unseen place, the table forgets it.
235
296
  + (void)finish:(ANNPreviewRecord *)record {
236
297
  record.done = YES;
298
+ [self stopWatching:record];
237
299
  [self unpark:record];
238
300
  if (ANNPreviewRecords()[record.previewId] == record) {
239
301
  [ANNPreviewRecords() removeObjectForKey:record.previewId];
@@ -286,6 +348,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
286
348
  NSMutableArray<UIViewController *> *screens = [NSMutableArray new];
287
349
  for (ANNPreviewRecord *record in ANNPreviewRecords().allValues) {
288
350
  record.done = YES;
351
+ [self stopWatching:record];
289
352
  [self unpark:record];
290
353
  if (!record.attached) {
291
354
  [screens addObject:record.screen];
@@ -274,6 +274,7 @@
274
274
  if (target == stack.queue.entries.lastObject) {
275
275
  [stack.queue noneWithValue:componentId
276
276
  answer:answer
277
+ what:what
277
278
  componentId:componentId
278
279
  source:target];
279
280
  return;
@@ -1102,6 +1102,11 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
1102
1102
  if (change == ANNStackChangePush && animated) {
1103
1103
  lowerBarBottom = [self lowerBarBottomOf:navigation leaving:coveredTop];
1104
1104
  }
1105
+ // The large title of a screen that comes with its content takes its place for the transition before UIKit's push.
1106
+ if (change == ANNStackChangePush && animated) {
1107
+ UIViewController *arriving = ANNStackOptionsScreen(entries.lastObject);
1108
+ [[ANNTopBarPresenter presenterOfScreen:arriving] arrivesByPushOn:navigation];
1109
+ }
1105
1110
  // The revealed screen's large title takes its place for the transition before UIKit lays the screen out for it.
1106
1111
  if (change == ANNStackChangePop && animated) {
1107
1112
  [self popReveals:entries.lastObject leaving:coveredTop on:navigation];
@@ -1428,10 +1433,28 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
1428
1433
 
1429
1434
  // The screen waits in the window at the stack's size, under UIKit's container view ( `ANNParking`): it isn't a child of
1430
1435
  // anything there, gets no touches, is hidden from accessibility, and its appearance is driven, so UIKit's callbacks
1431
- // report nothing for it. Each path that ends the wait gives the view back as it was; UIKit's push of the entry
1432
- // re-parents it in the same turn, so its departure is not ended here.
1436
+ // report nothing for it. UIKit gives such a view no safe area: its screens lay out with that of their place on top of
1437
+ // the stack meanwhile (`ANNScreenPlace`). Each path that ends the wait gives the view back as it was; UIKit's push of
1438
+ // the entry re-parents it in the same turn, so its departure is not ended here.
1433
1439
  - (void)stackPark:(UIViewController *)entry {
1434
- [_parking park:entry inView:self.shownNavigationController.view];
1440
+ UINavigationController *navigation = self.shownNavigationController;
1441
+ // Its screens lay out as on top of the stack, with the bar and the toolbar the entry shows there.
1442
+ __weak UIViewController *weakEntry = entry;
1443
+ __weak UINavigationController *weakNavigation = navigation;
1444
+ ANNScreenPlace * (^place)(void) = ^ANNScreenPlace * {
1445
+ UIViewController *parked = weakEntry;
1446
+ UINavigationController *stack = weakNavigation;
1447
+ if (!parked || !stack) {
1448
+ return nil;
1449
+ }
1450
+ return [ANNScreenPlace placeOfEntry:parked
1451
+ inStack:stack
1452
+ options:[ANNStackOptionsScreen(parked) resolveOptionsWithDefault]];
1453
+ };
1454
+ for (ANNComponentViewController *screen in ANNStackScreensOfEntry(entry)) {
1455
+ screen.placeWhileParked = place;
1456
+ }
1457
+ [_parking park:entry inView:navigation.view];
1435
1458
  }
1436
1459
 
1437
1460
  - (void)stackUnpark:(UIViewController *)entry {
@@ -166,9 +166,11 @@ typedef NS_ENUM(NSInteger, ANNStackChange) {
166
166
  completion:(nullable dispatch_block_t)completion
167
167
  rejection:(nullable ANNTransitionRejectionBlock)rejection;
168
168
 
169
- /// A command that moves nothing (`popTo` of the top) answers `value` in its turn.
169
+ /// A command that moves nothing (`popTo` of the top) answers `value` in its turn; a failure meanwhile rejects with the
170
+ /// command's own `what`.
170
171
  - (void)noneWithValue:(id)value
171
172
  answer:(ANNCommandAnswer *)answer
173
+ what:(NSString *)what
172
174
  componentId:(NSString *)componentId
173
175
  source:(nullable UIViewController *)source;
174
176