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

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 (581) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +132 -0
  3. package/README.md +147 -51
  4. package/android/CLAUDE.md +78 -25
  5. package/android/CORE.md +49 -25
  6. package/android/RECIPES.md +13 -6
  7. package/android/consumer-rules.pro +6 -0
  8. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
  9. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  10. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  11. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  12. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  16. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  19. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  20. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  21. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  22. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  23. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  24. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
  26. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  27. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  28. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  29. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  30. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  31. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  32. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  33. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  34. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  35. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  37. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
  38. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
  39. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
  40. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  41. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
  42. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
  43. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  44. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
  45. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  46. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
  47. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  48. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
  49. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  50. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  51. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
  52. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  53. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
  54. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
  55. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  56. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  57. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  58. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  59. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  60. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  61. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  62. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  63. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  64. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementDefinition.kt +9 -3
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementPlanner.kt +20 -15
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  123. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  124. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  127. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  130. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  131. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  142. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  143. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  156. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  157. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  158. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  159. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  160. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  161. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  162. package/android/src/main/res/values/styles.xml +1 -1
  163. package/android/src/main/res/values-night/styles.xml +1 -1
  164. package/cli/app.js +1 -1
  165. package/cli/doctor/checks/app.js +77 -14
  166. package/cli/doctor/checks/splash.js +4 -22
  167. package/cli/migrate/native.js +18 -0
  168. package/cli/project.js +10 -2
  169. package/cli/setup/index.js +18 -0
  170. package/cli/setup/source.js +2 -1
  171. package/cli/setup/steps/appDelegate.js +66 -11
  172. package/cli/setup/steps/mainApplication.js +134 -19
  173. package/cli/setup/steps/metro.js +46 -0
  174. package/cli/setup/steps/sceneDelegate.js +108 -0
  175. package/cli/splash/index.js +3 -1
  176. package/docs-md/architecture/native-screens.md +4 -0
  177. package/docs-md/architecture/theme-and-context.md +131 -12
  178. package/docs-md/architecture/transitions.md +58 -12
  179. package/docs-md/containers/arrangement.md +17 -1
  180. package/docs-md/containers/modals.md +8 -4
  181. package/docs-md/containers/overlays.md +3 -1
  182. package/docs-md/containers/side-menu.md +19 -2
  183. package/docs-md/containers/tabs.md +5 -1
  184. package/docs-md/flows/bottom-sheets.md +4 -2
  185. package/docs-md/flows/forms-in-a-modal.md +1 -1
  186. package/docs-md/fundamentals/screens-and-props.md +9 -1
  187. package/docs-md/fundamentals/starting-the-app.md +1 -1
  188. package/docs-md/guides/cli.md +4 -3
  189. package/docs-md/guides/deep-links.md +15 -33
  190. package/docs-md/help/glossary.md +4 -4
  191. package/docs-md/help/troubleshooting.md +44 -6
  192. package/docs-md/index.json +61 -1
  193. package/docs-md/migration/from-expo-router.md +1 -1
  194. package/docs-md/migration/from-react-native-navigation.md +9 -3
  195. package/docs-md/migration/from-react-navigation.md +2 -2
  196. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  197. package/docs-md/screen-ui/bar-buttons.md +5 -5
  198. package/docs-md/screen-ui/search.md +1 -1
  199. package/docs-md/screen-ui/system-ui.md +17 -12
  200. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  201. package/docs-md/screen-ui/top-bar.md +8 -4
  202. package/docs-md/start/installation.md +21 -3
  203. package/ios/Animations/ANNFrameDriver.h +55 -15
  204. package/ios/Animations/ANNFrameDriver.mm +216 -60
  205. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  206. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  207. package/ios/Animations/ANNTransitionPlan.h +2 -2
  208. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  209. package/ios/Animations/ANNTransitionWait.mm +6 -7
  210. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  211. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  212. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  213. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  214. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  215. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  216. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  217. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  218. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  219. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  220. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  221. package/ios/CLAUDE.md +60 -24
  222. package/ios/CORE.md +44 -34
  223. package/ios/Contract/ANNCommandAnswer.h +13 -5
  224. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  225. package/ios/Contract/ANNCommandContract.h +15 -0
  226. package/ios/Contract/ANNCommandContract.mm +78 -0
  227. package/ios/Contract/ANNCommandRunner.h +10 -9
  228. package/ios/Contract/ANNCommandRunner.mm +22 -28
  229. package/ios/Contract/ANNErrorTexts.h +6 -2
  230. package/ios/Contract/ANNErrorTexts.mm +18 -10
  231. package/ios/Contract/ANNLayoutNode.h +3 -3
  232. package/ios/Contract/ANNLayoutReader.h +3 -3
  233. package/ios/Core/ANNAppDelegate.mm +0 -2
  234. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  235. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  236. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  237. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  238. package/ios/Core/ANNErrorHandler.h +9 -4
  239. package/ios/Core/ANNErrorHandler.mm +20 -2
  240. package/ios/Core/ANNEventContract.h +246 -0
  241. package/ios/Core/ANNEventContract.mm +225 -0
  242. package/ios/Core/ANNEventEmitter.h +6 -2
  243. package/ios/Core/ANNEventEmitter.mm +117 -80
  244. package/ios/Core/ANNHinge.h +6 -0
  245. package/ios/Core/ANNHinge.mm +15 -4
  246. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  247. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  248. package/ios/Core/ANNLayoutProtocol.h +5 -5
  249. package/ios/Core/ANNNavigationState.h +7 -5
  250. package/ios/Core/ANNNavigationState.mm +8 -7
  251. package/ios/Core/ANNNodeHelper.h +32 -12
  252. package/ios/Core/ANNNodeHelper.mm +100 -3
  253. package/ios/Core/ANNParking.h +5 -4
  254. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  255. package/ios/Core/ANNRenderWait.h +20 -6
  256. package/ios/Core/ANNRenderWait.mm +143 -56
  257. package/ios/Core/ANNSceneDelegate.mm +25 -15
  258. package/ios/Core/ANNSystemUI.h +3 -2
  259. package/ios/Core/ANNSystemUI.mm +7 -0
  260. package/ios/Core/ANNUtils.h +7 -0
  261. package/ios/Core/ANNUtils.mm +10 -0
  262. package/ios/Core/ApexNavigation+Internal.h +1 -1
  263. package/ios/Core/ApexNavigation.mm +7 -6
  264. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  265. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  266. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  267. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  268. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +195 -21
  269. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  270. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  271. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  272. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  273. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  274. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  275. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  276. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  277. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  278. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  279. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  280. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  281. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  282. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  283. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  284. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  285. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  286. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  287. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  288. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  289. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  290. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  291. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  292. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  293. package/ios/Layouts/Screen/ANNScreenSettling.h +34 -0
  294. package/ios/Layouts/Screen/ANNScreenSettling.mm +171 -0
  295. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  296. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  297. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  298. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  299. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  300. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  301. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  302. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  303. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  304. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  305. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  306. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  307. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  308. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  309. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  310. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  311. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  312. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  313. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  314. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  317. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  318. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  319. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  320. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  321. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  322. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  323. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  324. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  325. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  326. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  327. package/ios/Options/ANNAnimationOptions.h +2 -1
  328. package/ios/Options/ANNAnimationOptions.mm +1 -1
  329. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  330. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  331. package/ios/Options/ANNOptions.h +25 -0
  332. package/ios/Options/ANNOptions.mm +157 -1
  333. package/ios/Options/ANNOptionsCache.h +7 -6
  334. package/ios/Options/ANNOptionsReader.mm +108 -0
  335. package/ios/Options/ANNSearchBarOptions.h +4 -3
  336. package/ios/Options/ANNSheetOptions.h +4 -1
  337. package/ios/Options/ANNSideMenuOptions.h +2 -0
  338. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  339. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  340. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  341. package/ios/Options/ANNUserChoice.h +57 -0
  342. package/ios/Options/ANNUserChoice.mm +44 -0
  343. package/ios/Options/Params/ANNImageSource.h +61 -0
  344. package/ios/Options/Params/ANNImageSource.mm +101 -0
  345. package/ios/Options/Params/ANNOptionImages.h +37 -0
  346. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  347. package/ios/Options/Params/ANNParam.h +15 -0
  348. package/ios/Options/Params/ANNParam.mm +61 -0
  349. package/ios/Options/Params/Color.h +3 -0
  350. package/ios/Options/Params/Color.mm +21 -0
  351. package/ios/Options/Params/ColorParser.h +4 -3
  352. package/ios/Options/Params/ColorParser.mm +22 -4
  353. package/ios/Options/Params/Image.h +15 -2
  354. package/ios/Options/Params/Image.mm +35 -2
  355. package/ios/Options/Params/ImageParser.h +5 -5
  356. package/ios/Options/Params/ImageParser.mm +28 -46
  357. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  358. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  359. package/ios/RECIPES.md +13 -6
  360. package/ios/React/ANNReactView.mm +6 -25
  361. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  362. package/ios/React/ANNSurfaceHostingView.h +14 -0
  363. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  364. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  365. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  366. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  367. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  368. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  369. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  370. package/ios/TopBar/ANNBarAppearance.h +2 -1
  371. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  372. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  373. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  374. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  375. package/ios/TopBar/ANNBarButtons.h +14 -8
  376. package/ios/TopBar/ANNBarButtons.mm +397 -80
  377. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  378. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  379. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  380. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  381. package/ios/TopBar/ANNMainList.h +3 -0
  382. package/ios/TopBar/ANNMainList.mm +4 -0
  383. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  384. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  385. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  386. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  387. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  388. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  389. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  390. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  391. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  392. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  393. package/lib/module/ARCHITECTURE.md +40 -27
  394. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  395. package/lib/module/api/app/AppRegistry.js +14 -2
  396. package/lib/module/api/app/AppRegistry.js.map +1 -1
  397. package/lib/module/api/app/createNavigation.js +190 -66
  398. package/lib/module/api/app/createNavigation.js.map +1 -1
  399. package/lib/module/api/commands/commands.js +54 -6
  400. package/lib/module/api/commands/commands.js.map +1 -1
  401. package/lib/module/api/events/navigationEvents.js +6 -2
  402. package/lib/module/api/events/navigationEvents.js.map +1 -1
  403. package/lib/module/api/hooks/useNavigation.js +8 -3
  404. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  405. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  406. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  407. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  408. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  409. package/lib/module/api/linking/linking.js +11 -0
  410. package/lib/module/api/linking/linking.js.map +1 -1
  411. package/lib/module/api/navigation.js.map +1 -1
  412. package/lib/module/api/options/OptionsChain.js +2 -2
  413. package/lib/module/api/screens/arrangement.js +5 -2
  414. package/lib/module/api/screens/arrangement.js.map +1 -1
  415. package/lib/module/api/screens/defineScreen.js +45 -3
  416. package/lib/module/api/screens/defineScreen.js.map +1 -1
  417. package/lib/module/api/screens/nativeScreens.js +31 -6
  418. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  419. package/lib/module/api/screens/registerScreens.js +193 -35
  420. package/lib/module/api/screens/registerScreens.js.map +1 -1
  421. package/lib/module/api/theme/theme.js +5 -0
  422. package/lib/module/api/theme/theme.js.map +1 -1
  423. package/lib/module/engine/commands.js +51 -9
  424. package/lib/module/engine/commands.js.map +1 -1
  425. package/lib/module/engine/layout.js +20 -11
  426. package/lib/module/engine/layout.js.map +1 -1
  427. package/lib/module/engine/nativeScreens.js +9 -0
  428. package/lib/module/engine/nativeScreens.js.map +1 -1
  429. package/lib/module/engine/options.js +49 -15
  430. package/lib/module/engine/options.js.map +1 -1
  431. package/lib/module/engine/optionsChange.js +102 -0
  432. package/lib/module/engine/optionsChange.js.map +1 -0
  433. package/lib/module/engine/places.js +52 -7
  434. package/lib/module/engine/places.js.map +1 -1
  435. package/lib/module/engine/props.js +30 -1
  436. package/lib/module/engine/props.js.map +1 -1
  437. package/lib/module/engine/refresh.js +85 -0
  438. package/lib/module/engine/refresh.js.map +1 -0
  439. package/lib/module/engine/rememberedOptions.js +61 -1
  440. package/lib/module/engine/rememberedOptions.js.map +1 -1
  441. package/lib/module/engine/screens.js +77 -16
  442. package/lib/module/engine/screens.js.map +1 -1
  443. package/lib/module/interfaces/contract/commands.json +101 -0
  444. package/lib/module/interfaces/contract/errors.json +275 -0
  445. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  446. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  447. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  448. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  449. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  450. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  451. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  452. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  453. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  454. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  455. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  456. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  457. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  458. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  459. package/lib/typescript/api/index.d.ts +1 -1
  460. package/lib/typescript/api/index.d.ts.map +1 -1
  461. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  462. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  463. package/lib/typescript/api/linking/linking.d.ts +8 -0
  464. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  465. package/lib/typescript/api/navigation.d.ts +4 -1
  466. package/lib/typescript/api/navigation.d.ts.map +1 -1
  467. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  468. package/lib/typescript/api/screens/arrangement.d.ts +12 -2
  469. package/lib/typescript/api/screens/arrangement.d.ts.map +1 -1
  470. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  471. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  472. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  473. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  474. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  475. package/lib/typescript/api/theme/theme.d.ts +2 -0
  476. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  477. package/lib/typescript/engine/commands.d.ts +5 -0
  478. package/lib/typescript/engine/commands.d.ts.map +1 -1
  479. package/lib/typescript/engine/layout.d.ts.map +1 -1
  480. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  481. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  482. package/lib/typescript/engine/options.d.ts +5 -2
  483. package/lib/typescript/engine/options.d.ts.map +1 -1
  484. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  485. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  486. package/lib/typescript/engine/places.d.ts +7 -2
  487. package/lib/typescript/engine/places.d.ts.map +1 -1
  488. package/lib/typescript/engine/props.d.ts +8 -1
  489. package/lib/typescript/engine/props.d.ts.map +1 -1
  490. package/lib/typescript/engine/refresh.d.ts +35 -0
  491. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  492. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  493. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  494. package/lib/typescript/engine/screens.d.ts +27 -6
  495. package/lib/typescript/engine/screens.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  497. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/Events.d.ts +28 -10
  499. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/Options.d.ts +1 -1
  501. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  503. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  505. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  507. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  509. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  511. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  512. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  513. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  514. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  515. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  516. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  517. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  518. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  519. package/metro/acceptPlugin.js +57 -0
  520. package/metro/babelTransformer.js +45 -0
  521. package/metro/index.js +36 -0
  522. package/package.json +3 -1
  523. package/src/ARCHITECTURE.md +40 -27
  524. package/src/adapters/NativeANNTurboModule.ts +12 -2
  525. package/src/api/app/AppRegistry.ts +16 -2
  526. package/src/api/app/createNavigation.ts +203 -69
  527. package/src/api/commands/commands.ts +48 -7
  528. package/src/api/commands/presentation.ts +4 -3
  529. package/src/api/events/navigationEvents.ts +10 -4
  530. package/src/api/hooks/useNavigation.ts +9 -4
  531. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  532. package/src/api/index.ts +1 -0
  533. package/src/api/linking/dispatchedLinks.ts +18 -0
  534. package/src/api/linking/linking.ts +22 -1
  535. package/src/api/navigation.ts +4 -1
  536. package/src/api/options/OptionsChain.ts +2 -2
  537. package/src/api/screens/arrangement.ts +17 -4
  538. package/src/api/screens/defineScreen.ts +49 -5
  539. package/src/api/screens/nativeScreens.ts +40 -4
  540. package/src/api/screens/registerScreens.tsx +185 -42
  541. package/src/api/theme/theme.ts +5 -0
  542. package/src/engine/commands.ts +70 -13
  543. package/src/engine/layout.ts +27 -11
  544. package/src/engine/nativeScreens.ts +10 -1
  545. package/src/engine/options.ts +45 -19
  546. package/src/engine/optionsChange.ts +107 -0
  547. package/src/engine/places.ts +65 -7
  548. package/src/engine/props.ts +30 -1
  549. package/src/engine/refresh.ts +97 -0
  550. package/src/engine/rememberedOptions.ts +74 -1
  551. package/src/engine/screens.tsx +76 -21
  552. package/src/interfaces/ComponentEvents.ts +4 -4
  553. package/src/interfaces/Events.ts +29 -10
  554. package/src/interfaces/Options.ts +1 -0
  555. package/src/interfaces/contract/commands.json +101 -0
  556. package/src/interfaces/contract/errors.json +275 -0
  557. package/src/interfaces/options/animations.ts +81 -22
  558. package/src/interfaces/options/bottomTabs.ts +21 -7
  559. package/src/interfaces/options/buttons.ts +23 -15
  560. package/src/interfaces/options/modals.ts +34 -26
  561. package/src/interfaces/options/sideMenu.ts +24 -6
  562. package/src/interfaces/options/stack.ts +17 -3
  563. package/src/interfaces/options/system.ts +18 -11
  564. package/src/interfaces/options/toolbar.ts +2 -2
  565. package/src/interfaces/options/topBar.ts +68 -38
  566. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  567. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  568. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  569. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  570. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  571. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  572. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  573. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  574. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  575. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  576. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  577. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  578. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  579. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  580. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  581. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -2,7 +2,9 @@
2
2
  #import "ANNBarButtonComponentView.h"
3
3
  #import "ANNIconButtonImage.h"
4
4
  #import "ANNShowTextButton.h"
5
+ #import "ANNTabsDesign.h"
5
6
  #import "ANNUIBarButtonItem.h"
7
+ #import "ANNUserChoice.h"
6
8
  #import "UIViewController+LayoutProtocol.h"
7
9
  #import <React/RCTLog.h>
8
10
 
@@ -54,6 +56,187 @@ static void ANNSetButtonsOfSide(ANNNavigationOptions *options, ANNBarButtonsSide
54
56
  }
55
57
  }
56
58
 
59
+ static ANNButtonOptions *ANNButtonWithId(NSArray<ANNButtonOptions *> *buttons, NSString *buttonId) {
60
+ for (ANNButtonOptions *button in buttons) {
61
+ if ([[button.identifier withDefault:nil] isEqualToString:buttonId]) {
62
+ return button;
63
+ }
64
+ }
65
+ return nil;
66
+ }
67
+
68
+ // The button `buttonId` of `side` in `options` changed on a copy, in a new list; nothing when the side has no such
69
+ // button. The other buttons stay the objects they are: nothing changes them.
70
+ static void ANNChangeButton(ANNNavigationOptions *options,
71
+ ANNBarButtonsSide side,
72
+ NSString *buttonId,
73
+ void (^change)(ANNButtonOptions *changed)) {
74
+ NSArray<ANNButtonOptions *> *list = ANNButtonsOfSide(options, side);
75
+ if (!ANNButtonWithId(list, buttonId)) {
76
+ return;
77
+ }
78
+ NSMutableArray<ANNButtonOptions *> *changedList = [NSMutableArray arrayWithCapacity:list.count];
79
+ for (ANNButtonOptions *button in list) {
80
+ if ([[button.identifier withDefault:nil] isEqualToString:buttonId]) {
81
+ ANNButtonOptions *copy = [button copy];
82
+ change(copy);
83
+ [changedList addObject:copy];
84
+ } else {
85
+ [changedList addObject:button];
86
+ }
87
+ }
88
+ ANNSetButtonsOfSide(options, side, changedList);
89
+ }
90
+
91
+ #pragma mark - The user's choices
92
+
93
+ static NSString *ANNToggleChoiceKey(ANNBarButtonsSide side, NSString *buttonId) {
94
+ return [NSString stringWithFormat:@"buttons.%ld.selected.%@", (long)side, buttonId];
95
+ }
96
+
97
+ static NSString *ANNButtonMenuChoiceKey(ANNBarButtonsSide side, NSString *buttonId) {
98
+ return [NSString stringWithFormat:@"buttons.%ld.menu.%@", (long)side, buttonId];
99
+ }
100
+
101
+ // The button `buttonId` of `side` in `options`, or nil.
102
+ static ANNButtonOptions *ANNButtonIn(ANNNavigationOptions *options, ANNBarButtonsSide side,
103
+ NSString *buttonId) {
104
+ return ANNButtonWithId(ANNButtonsOfSide(options, side), buttonId);
105
+ }
106
+
107
+ // A toggle the user flipped: `selected` of the button with its id, wherever its list comes from. It goes when the
108
+ // node's resolution after a merge has no such button, or when the merge gives the button a `selected` other than the
109
+ // app had (the own button's, else the button the node resolved to before the merge), by the rules of a menu's check.
110
+ static ANNUserChoice *ANNToggleChoice(ANNBarButtonsSide side, NSString *buttonId, BOOL selected) {
111
+ return [ANNUserChoice choiceWithValue:@(selected)
112
+ apply:^(ANNNavigationOptions *options, id value) {
113
+ BOOL on = [(NSNumber *)value boolValue];
114
+ ANNChangeButton(options, side, buttonId, ^(ANNButtonOptions *changed) {
115
+ changed.selected = [Bool withValue:on];
116
+ });
117
+ }
118
+ merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
119
+ ANNNavigationOptions *before, ANNNavigationOptions *after) {
120
+ if (!ANNButtonIn(after, side, buttonId)) {
121
+ return nil;
122
+ }
123
+ ANNButtonOptions *given = ANNButtonIn(merge, side, buttonId);
124
+ if (!given.selected.hasValue) {
125
+ return value;
126
+ }
127
+ ANNButtonOptions *was = ANNButtonIn(own, side, buttonId);
128
+ if (!was.selected.hasValue) {
129
+ was = ANNButtonIn(before, side, buttonId);
130
+ }
131
+ BOOL same = [given.selected withDefault:NO] == [was.selected withDefault:NO];
132
+ return same ? value : nil;
133
+ }];
134
+ }
135
+
136
+ // The items of the level (a menu's or a submenu's own list, without its submenus) that holds `itemId`, at any depth;
137
+ // nil when no level holds it.
138
+ static NSArray<ANNMenuItemOptions *> *ANNLevelOf(NSArray<ANNMenuItemOptions *> *items,
139
+ NSString *itemId) {
140
+ NSMutableArray<ANNMenuItemOptions *> *level = [NSMutableArray new];
141
+ BOOL holds = NO;
142
+ for (ANNMenuItemOptions *item in items) {
143
+ NSString *leafId = item.items.count ? nil : [item.identifier withDefault:nil];
144
+ if (leafId) {
145
+ [level addObject:item];
146
+ holds = holds || [leafId isEqualToString:itemId];
147
+ }
148
+ }
149
+ if (holds) {
150
+ return level;
151
+ }
152
+ for (ANNMenuItemOptions *item in items) {
153
+ if (item.items.count) {
154
+ NSArray<ANNMenuItemOptions *> *found = ANNLevelOf(item.items, itemId);
155
+ if (found) {
156
+ return found;
157
+ }
158
+ }
159
+ }
160
+ return nil;
161
+ }
162
+
163
+ // The ids of the items in the level that holds `itemId`: the neighbors one pick unchecks.
164
+ static NSArray<NSString *> *ANNNeighborsOf(NSArray<ANNMenuItemOptions *> *items, NSString *itemId) {
165
+ NSMutableArray<NSString *> *ids = [NSMutableArray new];
166
+ for (ANNMenuItemOptions *item in ANNLevelOf(items, itemId)) {
167
+ [ids addObject:[item.identifier withDefault:@""]];
168
+ }
169
+ return ids;
170
+ }
171
+
172
+ // The checked items of the level that holds `itemId` in `menu`: the field a merge gives that level. Nil when `menu`
173
+ // doesn't hold the item.
174
+ static NSSet<NSString *> *ANNCheckedInLevel(ANNMenuOptions *menu, NSString *itemId) {
175
+ NSArray<ANNMenuItemOptions *> *level = menu ? ANNLevelOf(menu.items, itemId) : nil;
176
+ if (!level) {
177
+ return nil;
178
+ }
179
+ NSMutableSet<NSString *> *checked = [NSMutableSet new];
180
+ for (ANNMenuItemOptions *item in level) {
181
+ if ([item.checked withDefault:NO]) {
182
+ [checked addObject:[item.identifier withDefault:@""]];
183
+ }
184
+ }
185
+ return checked;
186
+ }
187
+
188
+ // A menu that has items, or nil: a merge without items gives no menu.
189
+ static ANNMenuOptions *ANNMenuWithItems(ANNMenuOptions *menu) {
190
+ return menu.items ? menu : nil;
191
+ }
192
+
193
+ // The picks of single-selection levels in one menu, in the order made: the resolution plays them again on a copy of
194
+ // the menu it has, so a new menu from the app keeps the check where its items have the same ids. As on Android
195
+ // (`UserChoices.yieldTo`), at each merge into the node a pick goes when the node's resolution after it no longer has
196
+ // the item, or when the merge gives the menu with other checks in the pick's level than the app had there (the own
197
+ // options' menu, else the menu the node resolved to before the merge); the picks of the other levels stay.
198
+ typedef ANNMenuOptions *_Nullable (^ANNMenuOf)(ANNNavigationOptions *options);
199
+ typedef void (^ANNSetMenu)(ANNNavigationOptions *options, ANNMenuOptions *menu);
200
+
201
+ static ANNUserChoice *ANNMenuChoice(NSArray<NSString *> *picks,
202
+ ANNMenuOf menuOf,
203
+ ANNSetMenu setMenu) {
204
+ return [ANNUserChoice choiceWithValue:picks
205
+ apply:^(ANNNavigationOptions *options, id value) {
206
+ ANNMenuOptions *menu = menuOf(options);
207
+ if (menu.items.count == 0) {
208
+ return;
209
+ }
210
+ ANNMenuOptions *copy = [ANNBarButtons deepCopyOfMenu:menu];
211
+ for (NSString *itemId in (NSArray<NSString *> *)value) {
212
+ [copy itemPicked:itemId];
213
+ }
214
+ setMenu(options, copy);
215
+ }
216
+ merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
217
+ ANNNavigationOptions *before, ANNNavigationOptions *after) {
218
+ ANNMenuOptions *now = ANNMenuWithItems(menuOf(after));
219
+ ANNMenuOptions *given = ANNMenuWithItems(menuOf(merge));
220
+ ANNMenuOptions *was = ANNMenuWithItems(menuOf(own)) ?: ANNMenuWithItems(menuOf(before));
221
+ NSArray<NSString *> *made = value;
222
+ NSMutableArray<NSString *> *kept = [NSMutableArray new];
223
+ for (NSString *itemId in made) {
224
+ BOOL gone = !now || !ANNLevelOf(now.items, itemId);
225
+ NSSet<NSString *> *givenChecks = given ? ANNCheckedInLevel(given, itemId) : nil;
226
+ NSSet<NSString *> *wasChecks = ANNCheckedInLevel(was, itemId);
227
+ BOOL same = givenChecks == wasChecks || [givenChecks isEqualToSet:wasChecks];
228
+ BOOL changed = given && !same;
229
+ if (!gone && !changed) {
230
+ [kept addObject:itemId];
231
+ }
232
+ }
233
+ if (kept.count == 0) {
234
+ return nil;
235
+ }
236
+ return kept.count == made.count ? value : kept;
237
+ }];
238
+ }
239
+
57
240
  static UIColor *ANNColorOf(Color *color) {
58
241
  if (!color.hasValue || color.isNoColor) {
59
242
  return nil;
@@ -119,6 +302,27 @@ static BOOL ANNHasComponent(ANNButtonOptions *button) {
119
302
  [button.component.componentId withDefault:nil].length > 0;
120
303
  }
121
304
 
305
+ // The image an icon loads, for telling builds apart (NSNull without one): a source of a file, data or Metro's server
306
+ // loads through the shared cache, which gives the same image until the file at its path changes or a failed load
307
+ // succeeds. An SF Symbol is the system's: its name in the options says it all.
308
+ static id ANNLoadedImageOf(Image *icon) {
309
+ ANNImageSource *source = icon.source;
310
+ if (!icon.hasValue || (source && source.kind == ANNImageSourceKindSymbol)) {
311
+ return NSNull.null;
312
+ }
313
+ return [icon withDefault:nil] ?: NSNull.null;
314
+ }
315
+
316
+ // The images the items of a menu load (an item with `sfSymbol` shows the symbol), at any depth.
317
+ static void ANNAddMenuImages(NSArray<ANNMenuItemOptions *> *items, NSMutableArray *loaded) {
318
+ for (ANNMenuItemOptions *item in items) {
319
+ if (!item.sfSymbol.hasValue) {
320
+ [loaded addObject:ANNLoadedImageOf(item.icon)];
321
+ }
322
+ ANNAddMenuImages(item.items, loaded);
323
+ }
324
+ }
325
+
122
326
  // The image button's background: its own `iconBackground.color`, else (only for an image icon) the side's.
123
327
  static UIColor *ANNIconBackgroundOf(ANNButtonOptions *button, Color *sideBackground) {
124
328
  UIColor *own = ANNColorOf(button.iconBackground.color);
@@ -212,6 +416,60 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
212
416
  @implementation ANNButtonPress
213
417
  @end
214
418
 
419
+ // The same objects, one by one: what a build read by identity (a loaded image, a React button's slot) and what it put
420
+ // on the navigation item. A string (the item's customization id) by its value.
421
+ static BOOL ANNSameObjects(NSArray *a, NSArray *b) {
422
+ if (a.count != b.count) {
423
+ return NO;
424
+ }
425
+ for (NSUInteger index = 0; index < a.count; index++) {
426
+ id mine = a[index];
427
+ id theirs = b[index];
428
+ if (mine != theirs && !([mine isKindOfClass:NSString.class] && [mine isEqual:theirs])) {
429
+ return NO;
430
+ }
431
+ }
432
+ return YES;
433
+ }
434
+
435
+ // Everything the build of one side reads: the side's buttons, its colors and the customization id of the middle by
436
+ // value; the images it loads and the slots of its React buttons by identity (a file written again at its path loads as
437
+ // another image, a reload gives other roots); the traits it builds under (a text button's font follows the text size,
438
+ // a drawn image the scale and the style).
439
+ @interface ANNSideInputs : NSObject
440
+ @property(nonatomic, strong, nullable) NSArray<ANNButtonOptions *> *buttons;
441
+ @property(nonatomic, strong, nullable) Color *color;
442
+ @property(nonatomic, strong, nullable) Color *disabledColor;
443
+ @property(nonatomic, strong, nullable) Color *background;
444
+ @property(nonatomic, strong, nullable) Text *customizationId;
445
+ @property(nonatomic, copy) NSArray *loaded;
446
+ @property(nonatomic, copy) NSArray *traits;
447
+ @end
448
+
449
+ @implementation ANNSideInputs
450
+
451
+ - (BOOL)isSameAs:(ANNSideInputs *)other {
452
+ return ANNOptionValuesSame(_buttons, other.buttons) &&
453
+ ANNOptionValuesSame(_color, other.color) &&
454
+ ANNOptionValuesSame(_disabledColor, other.disabledColor) &&
455
+ ANNOptionValuesSame(_background, other.background) &&
456
+ ANNOptionValuesSame(_customizationId, other.customizationId) &&
457
+ ANNSameObjects(_loaded, other.loaded) && [_traits isEqualToArray:other.traits];
458
+ }
459
+
460
+ @end
461
+
462
+ // The last build of one side: what it read and what the navigation item held right after it.
463
+ @interface ANNSideBuild : NSObject
464
+ @property(nonatomic, strong) ANNSideInputs *inputs;
465
+ // The side went in as groups (`leadingItemGroups`, …), not as a list of items.
466
+ @property(nonatomic) BOOL grouped;
467
+ @property(nonatomic, copy) NSArray *placed;
468
+ @end
469
+
470
+ @implementation ANNSideBuild
471
+ @end
472
+
215
473
  @implementation ANNBarButtons {
216
474
  __weak UIViewController *_screen;
217
475
  ANNReactComponentRegistry *_registry;
@@ -220,6 +478,8 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
220
478
  NSMutableDictionary<NSString *, NSNumber *> *_selected;
221
479
  // What a press of each sender (an item, a button of an item) means.
222
480
  NSMapTable<id, ANNButtonPress *> *_presses;
481
+ // The last build of each side, by the side.
482
+ NSMutableDictionary<NSNumber *, ANNSideBuild *> *_builds;
223
483
  }
224
484
 
225
485
  - (instancetype)initWithScreen:(UIViewController *)screen
@@ -230,12 +490,16 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
230
490
  _slots = [NSMutableDictionary new];
231
491
  _selected = [NSMutableDictionary new];
232
492
  _presses = [NSMapTable weakToStrongObjectsMapTable];
493
+ _builds = [NSMutableDictionary new];
233
494
  }
234
495
  return self;
235
496
  }
236
497
 
237
498
  #pragma mark - The sides
238
499
 
500
+ // From iOS 26 UIKit animates any change of the bar's items, also to equal ones and with `animated:NO`: new items on
501
+ // each appearance would morph, close an open menu and drop a pressed state. So a side is built again only when what
502
+ // its build reads changed, or when the item no longer holds what the last build put there.
239
503
  - (void)applySide:(ANNBarButtonsSide)side
240
504
  options:(ANNNavigationOptions *)options
241
505
  animated:(BOOL)animated {
@@ -244,12 +508,92 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
244
508
  return;
245
509
  }
246
510
  UINavigationItem *navigationItem = screen.navigationItem;
511
+ ANNSideInputs *inputs = [self inputsOfSide:side options:options];
512
+ ANNSideBuild *last = _builds[@(side)];
513
+ if (last && [last.inputs isSameAs:inputs]) {
514
+ NSArray *placed = [self placedOf:side grouped:last.grouped item:navigationItem];
515
+ if (ANNSameObjects(last.placed, placed)) {
516
+ return;
517
+ }
518
+ }
519
+ ANNSideBuild *build = [ANNSideBuild new];
520
+ build.inputs = inputs;
521
+ build.grouped = [self placeSide:side options:options item:navigationItem animated:animated];
522
+ build.placed = [self placedOf:side grouped:build.grouped item:navigationItem];
523
+ _builds[@(side)] = build;
524
+ }
525
+
526
+ - (ANNSideInputs *)inputsOfSide:(ANNBarButtonsSide)side options:(ANNNavigationOptions *)options {
527
+ ANNTopBarOptions *topBar = options.topBar;
528
+ ANNSideInputs *inputs = [ANNSideInputs new];
529
+ inputs.buttons = ANNButtonsOfSide(options, side);
530
+ inputs.color = ANNSideColor(topBar, side);
531
+ inputs.disabledColor = ANNSideDisabledColor(topBar, side);
532
+ inputs.background = ANNSideBackgroundColor(topBar, side);
533
+ inputs.customizationId = side == ANNBarButtonsSideCenter ? topBar.customizationId : nil;
534
+ NSMutableArray *loaded = [NSMutableArray new];
535
+ for (ANNButtonOptions *button in inputs.buttons ?: @[]) {
536
+ if (ANNHasComponent(button)) {
537
+ [loaded addObject:[self slotFor:button] ?: NSNull.null];
538
+ }
539
+ [loaded addObject:ANNLoadedImageOf(button.icon)];
540
+ ANNAddMenuImages(button.menu.items, loaded);
541
+ }
542
+ inputs.loaded = loaded;
543
+ UITraitCollection *traits = UITraitCollection.currentTraitCollection;
544
+ inputs.traits = @[
545
+ @(traits.userInterfaceStyle), @(traits.displayScale),
546
+ traits.preferredContentSizeCategory ?: @"", @(traits.legibilityWeight)
547
+ ];
548
+ return inputs;
549
+ }
550
+
551
+ // What the navigation item holds of `side` now, as the side's build put it there.
552
+ - (NSArray *)placedOf:(ANNBarButtonsSide)side
553
+ grouped:(BOOL)grouped
554
+ item:(UINavigationItem *)navigationItem {
555
+ NSMutableArray *placed = [NSMutableArray new];
556
+ BOOL left = side == ANNBarButtonsSideLeft;
557
+ switch (side) {
558
+ case ANNBarButtonsSideLeft:
559
+ case ANNBarButtonsSideRight: {
560
+ NSArray *shown =
561
+ left ? navigationItem.leftBarButtonItems : navigationItem.rightBarButtonItems;
562
+ if (@available(iOS 16.0, *)) {
563
+ if (grouped) {
564
+ shown = left ? navigationItem.leadingItemGroups
565
+ : navigationItem.trailingItemGroups;
566
+ }
567
+ if (!left) {
568
+ [placed addObject:navigationItem.pinnedTrailingGroup ?: NSNull.null];
569
+ }
570
+ }
571
+ [placed addObjectsFromArray:shown ?: @[]];
572
+ break;
573
+ }
574
+ case ANNBarButtonsSideCenter:
575
+ if (@available(iOS 16.0, *)) {
576
+ [placed addObjectsFromArray:navigationItem.centerItemGroups ?: @[]];
577
+ [placed addObject:navigationItem.customizationIdentifier ?: NSNull.null];
578
+ }
579
+ break;
580
+ case ANNBarButtonsSideToolbar:
581
+ break;
582
+ }
583
+ return placed;
584
+ }
585
+
586
+ // Builds `side` whole and puts it on the item; YES when it went in as groups.
587
+ - (BOOL)placeSide:(ANNBarButtonsSide)side
588
+ options:(ANNNavigationOptions *)options
589
+ item:(UINavigationItem *)navigationItem
590
+ animated:(BOOL)animated {
247
591
  NSArray<ANNBuiltButton *> *built = [self buildSide:side options:options];
248
592
  if (side == ANNBarButtonsSideCenter) {
249
593
  if (@available(iOS 16.0, *)) {
250
594
  [self setCenter:built options:options item:navigationItem];
251
595
  }
252
- return;
596
+ return YES;
253
597
  }
254
598
  NSMutableArray<ANNBuiltButton *> *placed = [built mutableCopy];
255
599
  if (side == ANNBarButtonsSideRight) {
@@ -258,26 +602,28 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
258
602
  }
259
603
  }
260
604
  if (@available(iOS 26.0, *)) {
261
- if ([self hasGroupOfSeveral:placed]) {
605
+ if (ANNTabsDesign.isGlass && [self hasGroupOfSeveral:placed]) {
262
606
  NSArray<UIBarButtonItemGroup *> *groups = [self groupsOf:placed];
263
607
  if (side == ANNBarButtonsSideLeft) {
264
608
  navigationItem.leadingItemGroups = groups;
265
609
  } else {
266
610
  navigationItem.trailingItemGroups = groups.reverseObjectEnumerator.allObjects;
267
611
  }
268
- return;
612
+ return YES;
269
613
  }
270
614
  }
271
615
  NSMutableArray<UIBarButtonItem *> *items = [NSMutableArray new];
272
616
  for (ANNBuiltButton *button in placed) {
273
617
  if (@available(iOS 26.0, *)) {
274
618
  // Each button its own capsule: a zero-width space between neighbours, and the right ones never share the
275
- // capsule of "•••".
276
- if (items.count > 0) {
277
- [items addObject:[UIBarButtonItem fixedSpaceItemOfWidth:0]];
278
- }
279
- if (side == ANNBarButtonsSideRight) {
280
- button.item.sharesBackground = NO;
619
+ // capsule of "•••". The compatibility mode has no capsules.
620
+ if (ANNTabsDesign.isGlass) {
621
+ if (items.count > 0) {
622
+ [items addObject:[UIBarButtonItem fixedSpaceItemOfWidth:0]];
623
+ }
624
+ if (side == ANNBarButtonsSideRight) {
625
+ button.item.sharesBackground = NO;
626
+ }
281
627
  }
282
628
  }
283
629
  [items addObject:button.item];
@@ -287,6 +633,7 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
287
633
  } else {
288
634
  [navigationItem setRightBarButtonItems:items animated:animated];
289
635
  }
636
+ return NO;
290
637
  }
291
638
 
292
639
  - (NSArray<ANNBuiltButton *> *)buildSide:(ANNBarButtonsSide)side
@@ -377,7 +724,7 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
377
724
  NSMutableArray<UIBarButtonItem *> *items = [NSMutableArray new];
378
725
  for (ANNBuiltButton *button in run) {
379
726
  if (@available(iOS 26.0, *)) {
380
- if (run.count == 1) {
727
+ if (run.count == 1 && ANNTabsDesign.isGlass) {
381
728
  button.item.sharesBackground = NO;
382
729
  }
383
730
  }
@@ -438,11 +785,12 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
438
785
  }
439
786
  UIMenu *built = [current menuWithPickHandler:^(NSString *itemId) {
440
787
  [weakSelf menuItemPicked:itemId
441
- menuOf:^ANNMenuOptions *(ANNNavigationOptions *resolved) {
442
- return resolved.topBar.overflowMenu;
788
+ choiceKey:@"topBar.overflowMenu"
789
+ menuOf:^ANNMenuOptions *(ANNNavigationOptions *options) {
790
+ return options.topBar.overflowMenu;
443
791
  }
444
- setMenu:^(ANNNavigationOptions *own, ANNMenuOptions *copy) {
445
- own.topBar.overflowMenu = copy;
792
+ setMenu:^(ANNNavigationOptions *options, ANNMenuOptions *copy) {
793
+ options.topBar.overflowMenu = copy;
446
794
  }];
447
795
  }];
448
796
  UIMenu *section = [UIMenu menuWithTitle:built.title
@@ -484,7 +832,7 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
484
832
  BOOL icon = kind == ANNBarButtonKindSymbol || kind == ANNBarButtonKindImage ||
485
833
  kind == ANNBarButtonKindImageButton || kind == ANNBarButtonKindShowText;
486
834
  NSString *group = icon ? [button.group withDefault:nil] : nil;
487
- if (@available(iOS 26.0, *)) {
835
+ if (ANNTabsDesign.isGlass) {
488
836
  // Only icons of one group share a capsule (the toolbar has no groups): any other neighbours get a
489
837
  // zero-width space, unless a space of the options is there already.
490
838
  BOOL sameGroup = group.length > 0 && [group isEqualToString:previousIconGroup];
@@ -652,10 +1000,12 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
652
1000
  }
653
1001
  BOOL prominent = [[button.style withDefault:nil] isEqualToString:@"prominent"];
654
1002
  if (prominent) {
1003
+ // The capsule of the glass; the design before it (and its compatibility mode) has the bold `done` style.
1004
+ item.style = UIBarButtonItemStyleDone;
655
1005
  if (@available(iOS 26.0, *)) {
656
- item.style = UIBarButtonItemStyleProminent;
657
- } else {
658
- item.style = UIBarButtonItemStyleDone;
1006
+ if (ANNTabsDesign.isGlass) {
1007
+ item.style = UIBarButtonItemStyleProminent;
1008
+ }
659
1009
  }
660
1010
  }
661
1011
  // The color: the tint, and for a plain button also the text's; `prominent` takes it only into the tint, and a font
@@ -838,9 +1188,11 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
838
1188
  kind:(ANNBarButtonKind)kind
839
1189
  to:(UIBarButtonItem *)item {
840
1190
  if (@available(iOS 26.0, *)) {
841
- BOOL ownBackground =
842
- kind == ANNBarButtonKindComponent || kind == ANNBarButtonKindImageButton;
843
- item.hidesSharedBackground = [button.hideSharedBackground withDefault:ownBackground];
1191
+ if (ANNTabsDesign.isGlass) {
1192
+ BOOL ownBackground =
1193
+ kind == ANNBarButtonKindComponent || kind == ANNBarButtonKindImageButton;
1194
+ item.hidesSharedBackground = [button.hideSharedBackground withDefault:ownBackground];
1195
+ }
844
1196
  }
845
1197
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270000
846
1198
  if (@available(iOS 27.0, *)) {
@@ -880,16 +1232,14 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
880
1232
  __weak ANNBarButtons *weakSelf = self;
881
1233
  item.menu = [menu menuWithPickHandler:^(NSString *itemId) {
882
1234
  [weakSelf menuItemPicked:itemId
1235
+ choiceKey:ANNButtonMenuChoiceKey(side, buttonId)
883
1236
  menuOf:^ANNMenuOptions *(ANNNavigationOptions *options) {
884
- return [ANNBarButtons buttonWithId:buttonId in:ANNButtonsOfSide(options, side)].menu;
1237
+ return ANNButtonWithId(ANNButtonsOfSide(options, side), buttonId).menu;
885
1238
  }
886
- setMenu:^(ANNNavigationOptions *own, ANNMenuOptions *copy) {
887
- [weakSelf changeButton:buttonId
888
- side:side
889
- inOwn:own
890
- change:^(ANNButtonOptions *changed) {
891
- changed.menu = copy;
892
- }];
1239
+ setMenu:^(ANNNavigationOptions *options, ANNMenuOptions *copy) {
1240
+ ANNChangeButton(options, side, buttonId, ^(ANNButtonOptions *changed) {
1241
+ changed.menu = copy;
1242
+ });
893
1243
  }];
894
1244
  }];
895
1245
  if (![button.menuOnLongPress withDefault:NO]) {
@@ -948,22 +1298,15 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
948
1298
  [screen.eventEmitter sendOnNavigationButtonPressed:componentId buttonId:press.buttonId];
949
1299
  return;
950
1300
  }
951
- // A toggle flips, the options keep the new state, then the event tells it.
1301
+ // A toggle flips, the user layer keeps the new state, then the event tells it.
952
1302
  ANNUIBarButtonItem *item = press.item;
953
1303
  BOOL selected = !item.selected;
954
1304
  item.selected = selected;
955
1305
  _selected[press.buttonId] = @(selected);
956
- __weak ANNBarButtons *weakSelf = self;
957
1306
  NSString *buttonId = press.buttonId;
958
1307
  ANNBarButtonsSide side = press.side;
959
- [screen changeOwnOptions:^(ANNNavigationOptions *own) {
960
- [weakSelf changeButton:buttonId
961
- side:side
962
- inOwn:own
963
- change:^(ANNButtonOptions *changed) {
964
- changed.selected = [Bool withValue:selected];
965
- }];
966
- }];
1308
+ [screen setUserChoice:ANNToggleChoice(side, buttonId, selected)
1309
+ forKey:ANNToggleChoiceKey(side, buttonId)];
967
1310
  [screen.eventEmitter sendOnNavigationButtonPressed:componentId
968
1311
  buttonId:buttonId
969
1312
  selected:@(selected)];
@@ -971,46 +1314,15 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
971
1314
 
972
1315
  + (nullable ANNButtonOptions *)buttonWithId:(NSString *)buttonId
973
1316
  in:(NSArray<ANNButtonOptions *> *)buttons {
974
- for (ANNButtonOptions *button in buttons) {
975
- if ([[button.identifier withDefault:nil] isEqualToString:buttonId]) {
976
- return button;
977
- }
978
- }
979
- return nil;
980
- }
981
-
982
- // The button `buttonId` of `side` in the own options, changed on a copy: the own list when it has the button, else the
983
- // list the screen shows (from its stack or the defaults), copied into the own options first. Lists are new arrays.
984
- - (void)changeButton:(NSString *)buttonId
985
- side:(ANNBarButtonsSide)side
986
- inOwn:(ANNNavigationOptions *)own
987
- change:(void (^)(ANNButtonOptions *changed))change {
988
- NSArray<ANNButtonOptions *> *list = ANNButtonsOfSide(own, side);
989
- if (![ANNBarButtons buttonWithId:buttonId in:list]) {
990
- list = ANNButtonsOfSide([_screen resolveOptionsWithDefault], side);
991
- }
992
- if (![ANNBarButtons buttonWithId:buttonId in:list]) {
993
- return;
994
- }
995
- NSMutableArray<ANNButtonOptions *> *changedList = [NSMutableArray arrayWithCapacity:list.count];
996
- for (ANNButtonOptions *button in list) {
997
- ANNButtonOptions *copy = [button copy];
998
- if (button.menu.items.count > 0) {
999
- copy.menu = [ANNBarButtons deepCopyOfMenu:button.menu];
1000
- }
1001
- if ([[button.identifier withDefault:nil] isEqualToString:buttonId]) {
1002
- change(copy);
1003
- }
1004
- [changedList addObject:copy];
1005
- }
1006
- ANNSetButtonsOfSide(own, side, changedList);
1317
+ return ANNButtonWithId(buttons, buttonId);
1007
1318
  }
1008
1319
 
1009
1320
  #pragma mark - Menus
1010
1321
 
1011
1322
  - (void)menuItemPicked:(NSString *)itemId
1323
+ choiceKey:(NSString *)choiceKey
1012
1324
  menuOf:(ANNMenuOptions *_Nullable (^)(ANNNavigationOptions *options))menuOf
1013
- setMenu:(void (^)(ANNNavigationOptions *own, ANNMenuOptions *menu))setMenu {
1325
+ setMenu:(void (^)(ANNNavigationOptions *options, ANNMenuOptions *menu))setMenu {
1014
1326
  UIViewController *screen = _screen;
1015
1327
  NSString *componentId = screen.layoutInfo.componentId;
1016
1328
  if (!screen || componentId.length == 0) {
@@ -1021,13 +1333,18 @@ static UIBarButtonSystemItem ANNSystemItemOf(NSString *name) {
1021
1333
  if (!menu || ![ANNBarButtons menu:menu hasSingleSelectionOf:itemId]) {
1022
1334
  return;
1023
1335
  }
1024
- // The check lands on the screen's own copy, which shares nothing with the menus of the stack, the defaults or
1025
- // other screens.
1026
- ANNMenuOptions *copy = [ANNBarButtons deepCopyOfMenu:menu];
1027
- [copy itemPicked:itemId];
1028
- [screen changeOwnOptions:^(ANNNavigationOptions *own) {
1029
- setMenu(own, copy);
1030
- }];
1336
+ // The new pick goes last; the earlier picks of its own list go, so a pick the app takes away later doesn't bring
1337
+ // back one the user replaced.
1338
+ NSArray<NSString *> *made = [screen userChoiceForKey:choiceKey].value ?: @[];
1339
+ NSArray<NSString *> *neighbors = ANNNeighborsOf(menu.items, itemId);
1340
+ NSMutableArray<NSString *> *picks = [NSMutableArray new];
1341
+ for (NSString *pick in made) {
1342
+ if (![neighbors containsObject:pick]) {
1343
+ [picks addObject:pick];
1344
+ }
1345
+ }
1346
+ [picks addObject:itemId];
1347
+ [screen setUserChoice:ANNMenuChoice(picks, menuOf, setMenu) forKey:choiceKey];
1031
1348
  }
1032
1349
 
1033
1350
  + (BOOL)menu:(ANNMenuOptions *)menu hasSingleSelectionOf:(NSString *)itemId {
@@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
13
13
 
14
14
  /// `tint` colors the icon (nil: its own colors); `background` fills the rectangle of `size` (zero: the icon's size)
15
15
  /// rounded by `cornerRadius`; `insets` pad the icon. Colors may be dynamic: each variant resolves them.
16
+ /// An icon that can't be drawn so (no room, an exception while drawing) comes back as it is.
16
17
  + (UIImage *)imageWithIcon:(UIImage *)icon
17
18
  tint:(nullable UIColor *)tint
18
19
  background:(nullable UIColor *)background