@symbiote-native/navigation 2.0.3 → 2.2.0

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 (320) hide show
  1. package/README.md +42 -12
  2. package/build/angular/drawer/index.js +29 -13
  3. package/build/angular/index.d.ts +4 -4
  4. package/build/angular/injectors/inject-navigation.js +1 -1
  5. package/build/angular/navigation-scope.directive.js +1 -1
  6. package/build/angular/search-bar-ref.directive.js +1 -1
  7. package/build/angular/stack/index.d.ts +2 -0
  8. package/build/angular/stack/index.js +43 -9
  9. package/build/angular/tabs/index.d.ts +1 -1
  10. package/build/angular/tabs/index.js +40 -13
  11. package/build/core/drawer-options/index.js +19 -5
  12. package/build/core/drawer-router-state/index.js +8 -2
  13. package/build/core/guards.js +3 -1
  14. package/build/core/header-bar-buttons.js +14 -4
  15. package/build/core/index.d.ts +6 -5
  16. package/build/core/index.js +7 -3
  17. package/build/core/navigator-state/index.js +12 -4
  18. package/build/core/render-drawer.js +4 -1
  19. package/build/core/render-stack.js +13 -4
  20. package/build/core/screen-options.js +1 -1
  21. package/build/core/search-bar-commands.js +1 -1
  22. package/build/core/stack-router-state/index.d.ts +2 -0
  23. package/build/core/stack-router-state/index.js +44 -0
  24. package/build/core/state-persistence/index.js +6 -2
  25. package/build/core/tab-router-state/index.d.ts +1 -0
  26. package/build/core/tab-router-state/index.js +27 -2
  27. package/build/react/drawer/index.js +59 -26
  28. package/build/react/index.d.ts +7 -7
  29. package/build/react/index.js +2 -2
  30. package/build/react/stack/index.js +47 -10
  31. package/build/react/tabs/index.js +36 -12
  32. package/build/solid/drawer/index.d.ts +22 -0
  33. package/build/solid/drawer/index.js +394 -0
  34. package/build/solid/drawer-screen-props.d.ts +13 -0
  35. package/build/solid/drawer-screen-props.js +2 -0
  36. package/build/solid/host.d.ts +2 -0
  37. package/build/solid/host.js +23 -0
  38. package/build/solid/index.d.ts +19 -0
  39. package/build/solid/index.js +24 -0
  40. package/build/solid/linking.d.ts +3 -0
  41. package/build/solid/linking.js +55 -0
  42. package/build/solid/navigation-context.d.ts +13 -0
  43. package/build/solid/navigation-context.js +37 -0
  44. package/build/solid/primitives/create-focus-effect.d.ts +1 -0
  45. package/build/solid/primitives/create-focus-effect.js +30 -0
  46. package/build/solid/primitives/create-is-focused.d.ts +2 -0
  47. package/build/solid/primitives/create-is-focused.js +31 -0
  48. package/build/solid/primitives/create-navigation-state.d.ts +3 -0
  49. package/build/solid/primitives/create-navigation-state.js +30 -0
  50. package/build/solid/primitives/index.d.ts +12 -0
  51. package/build/solid/primitives/index.js +8 -0
  52. package/build/solid/primitives/use-drawer-navigation.d.ts +5 -0
  53. package/build/solid/primitives/use-drawer-navigation.js +15 -0
  54. package/build/solid/primitives/use-navigation.d.ts +8 -0
  55. package/build/solid/primitives/use-navigation.js +23 -0
  56. package/build/solid/primitives/use-route.d.ts +3 -0
  57. package/build/solid/primitives/use-route.js +14 -0
  58. package/build/solid/primitives/use-stack-navigation.d.ts +5 -0
  59. package/build/solid/primitives/use-stack-navigation.js +19 -0
  60. package/build/solid/primitives/use-tab-navigation.d.ts +5 -0
  61. package/build/solid/primitives/use-tab-navigation.js +15 -0
  62. package/build/solid/screen-props.d.ts +19 -0
  63. package/build/solid/screen-props.js +9 -0
  64. package/build/solid/screen-registry.d.ts +31 -0
  65. package/build/solid/screen-registry.js +86 -0
  66. package/build/solid/screen.d.ts +6 -0
  67. package/build/solid/screen.js +69 -0
  68. package/build/solid/stack/index.d.ts +15 -0
  69. package/build/solid/stack/index.js +348 -0
  70. package/build/solid/tab-screen-props.d.ts +13 -0
  71. package/build/solid/tab-screen-props.js +3 -0
  72. package/build/solid/tabs/index.d.ts +14 -0
  73. package/build/solid/tabs/index.js +228 -0
  74. package/build/svelte/attachments.d.ts +5 -0
  75. package/build/svelte/attachments.js +61 -0
  76. package/build/svelte/descriptor-subtree.d.ts +3 -0
  77. package/build/svelte/descriptor-subtree.js +39 -0
  78. package/build/svelte/drawer/drawer-props.d.ts +14 -0
  79. package/build/svelte/drawer/drawer-props.js +3 -0
  80. package/build/svelte/drawer/index.d.ts +10 -0
  81. package/build/svelte/drawer/index.js +6 -0
  82. package/build/svelte/drawer/index.svelte +559 -0
  83. package/build/svelte/drawer/index.svelte.d.ts +10 -0
  84. package/build/svelte/drawer-screen-props.d.ts +13 -0
  85. package/build/svelte/drawer-screen-props.js +4 -0
  86. package/build/svelte/drawer-screen.svelte +25 -0
  87. package/build/svelte/drawer-screen.svelte.d.ts +4 -0
  88. package/build/svelte/index.d.ts +21 -0
  89. package/build/svelte/index.js +20 -0
  90. package/build/svelte/linking.svelte.d.ts +2 -0
  91. package/build/svelte/linking.svelte.js +55 -0
  92. package/build/svelte/navigation-context.d.ts +14 -0
  93. package/build/svelte/navigation-context.js +44 -0
  94. package/build/svelte/navigation-scope.svelte +27 -0
  95. package/build/svelte/navigation-scope.svelte.d.ts +9 -0
  96. package/build/svelte/registry-host.d.ts +1 -0
  97. package/build/svelte/registry-host.js +26 -0
  98. package/build/svelte/runes/index.d.ts +12 -0
  99. package/build/svelte/runes/index.js +12 -0
  100. package/build/svelte/runes/use-drawer-navigation.svelte.d.ts +6 -0
  101. package/build/svelte/runes/use-drawer-navigation.svelte.js +19 -0
  102. package/build/svelte/runes/use-focus-effect.svelte.d.ts +1 -0
  103. package/build/svelte/runes/use-focus-effect.svelte.js +31 -0
  104. package/build/svelte/runes/use-is-focused.svelte.d.ts +3 -0
  105. package/build/svelte/runes/use-is-focused.svelte.js +34 -0
  106. package/build/svelte/runes/use-navigation-state.svelte.d.ts +4 -0
  107. package/build/svelte/runes/use-navigation-state.svelte.js +39 -0
  108. package/build/svelte/runes/use-navigation.svelte.d.ts +9 -0
  109. package/build/svelte/runes/use-navigation.svelte.js +26 -0
  110. package/build/svelte/runes/use-route.svelte.d.ts +4 -0
  111. package/build/svelte/runes/use-route.svelte.js +12 -0
  112. package/build/svelte/runes/use-stack-navigation.svelte.d.ts +6 -0
  113. package/build/svelte/runes/use-stack-navigation.svelte.js +22 -0
  114. package/build/svelte/runes/use-tab-navigation.svelte.d.ts +6 -0
  115. package/build/svelte/runes/use-tab-navigation.svelte.js +19 -0
  116. package/build/svelte/screen-props.d.ts +21 -0
  117. package/build/svelte/screen-props.js +6 -0
  118. package/build/svelte/screen-registry.d.ts +17 -0
  119. package/build/svelte/screen-registry.js +57 -0
  120. package/build/svelte/screen.svelte +28 -0
  121. package/build/svelte/screen.svelte.d.ts +4 -0
  122. package/build/svelte/stack/index.d.ts +14 -0
  123. package/build/svelte/stack/index.js +7 -0
  124. package/build/svelte/stack/index.svelte +261 -0
  125. package/build/svelte/stack/index.svelte.d.ts +15 -0
  126. package/build/svelte/stack/stack-props.d.ts +20 -0
  127. package/build/svelte/stack/stack-props.js +4 -0
  128. package/build/svelte/stack/stack-screen.svelte +205 -0
  129. package/build/svelte/stack/stack-screen.svelte.d.ts +4 -0
  130. package/build/svelte/tab-screen-props.d.ts +13 -0
  131. package/build/svelte/tab-screen-props.js +4 -0
  132. package/build/svelte/tab-screen.svelte +26 -0
  133. package/build/svelte/tab-screen.svelte.d.ts +4 -0
  134. package/build/svelte/tabs/index.d.ts +8 -0
  135. package/build/svelte/tabs/index.js +6 -0
  136. package/build/svelte/tabs/index.svelte +269 -0
  137. package/build/svelte/tabs/index.svelte.d.ts +8 -0
  138. package/build/svelte/tabs/tab-props.d.ts +7 -0
  139. package/build/svelte/tabs/tab-props.js +3 -0
  140. package/build/vue/composables/use-navigation.js +5 -1
  141. package/build/vue/drawer/index.js +36 -13
  142. package/build/vue/index.d.ts +3 -3
  143. package/build/vue/navigation-context.js +1 -1
  144. package/build/vue/stack/index.js +43 -18
  145. package/build/vue/tabs/index.js +65 -39
  146. package/build-ngc/angular/drawer/index.js +40 -18
  147. package/build-ngc/angular/drawer/index.js.map +1 -1
  148. package/build-ngc/angular/drawer-screen.directive.js +3 -3
  149. package/build-ngc/angular/index.d.ts +4 -4
  150. package/build-ngc/angular/index.js.map +1 -1
  151. package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -1
  152. package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -1
  153. package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -1
  154. package/build-ngc/angular/injectors/inject-navigation.js +1 -1
  155. package/build-ngc/angular/injectors/inject-navigation.js.map +1 -1
  156. package/build-ngc/angular/linking.js.map +1 -1
  157. package/build-ngc/angular/navigation-context.service.js +3 -3
  158. package/build-ngc/angular/navigation-context.service.js.map +1 -1
  159. package/build-ngc/angular/navigation-scope.directive.js +4 -4
  160. package/build-ngc/angular/navigation-scope.directive.js.map +1 -1
  161. package/build-ngc/angular/screen.directive.js +3 -3
  162. package/build-ngc/angular/screen.directive.js.map +1 -1
  163. package/build-ngc/angular/search-bar-ref.directive.js +4 -4
  164. package/build-ngc/angular/search-bar-ref.directive.js.map +1 -1
  165. package/build-ngc/angular/stack/index.d.ts +2 -0
  166. package/build-ngc/angular/stack/index.js +52 -14
  167. package/build-ngc/angular/stack/index.js.map +1 -1
  168. package/build-ngc/angular/tab-screen.directive.js +3 -3
  169. package/build-ngc/angular/tab-screen.directive.js.map +1 -1
  170. package/build-ngc/angular/tabs/index.d.ts +1 -1
  171. package/build-ngc/angular/tabs/index.js +43 -16
  172. package/build-ngc/angular/tabs/index.js.map +1 -1
  173. package/build-ngc/core/constants.js.map +1 -1
  174. package/build-ngc/core/drawer-options/index.js +19 -5
  175. package/build-ngc/core/drawer-options/index.js.map +1 -1
  176. package/build-ngc/core/drawer-router-state/index.js +8 -2
  177. package/build-ngc/core/drawer-router-state/index.js.map +1 -1
  178. package/build-ngc/core/guards.js +3 -1
  179. package/build-ngc/core/guards.js.map +1 -1
  180. package/build-ngc/core/header-bar-buttons.js +14 -4
  181. package/build-ngc/core/header-bar-buttons.js.map +1 -1
  182. package/build-ngc/core/index.d.ts +6 -5
  183. package/build-ngc/core/index.js +7 -3
  184. package/build-ngc/core/index.js.map +1 -1
  185. package/build-ngc/core/linking-config/index.js.map +1 -1
  186. package/build-ngc/core/navigation-events/index.js.map +1 -1
  187. package/build-ngc/core/navigator-handles/index.js.map +1 -1
  188. package/build-ngc/core/navigator-state/index.js +12 -4
  189. package/build-ngc/core/navigator-state/index.js.map +1 -1
  190. package/build-ngc/core/render-drawer.js +4 -1
  191. package/build-ngc/core/render-drawer.js.map +1 -1
  192. package/build-ngc/core/render-stack.js +13 -4
  193. package/build-ngc/core/render-stack.js.map +1 -1
  194. package/build-ngc/core/render-tabs.js.map +1 -1
  195. package/build-ngc/core/screen-options.js +1 -1
  196. package/build-ngc/core/screen-options.js.map +1 -1
  197. package/build-ngc/core/search-bar-commands.js +1 -1
  198. package/build-ngc/core/search-bar-commands.js.map +1 -1
  199. package/build-ngc/core/stack-router-state/index.d.ts +2 -0
  200. package/build-ngc/core/stack-router-state/index.js +45 -0
  201. package/build-ngc/core/stack-router-state/index.js.map +1 -0
  202. package/build-ngc/core/state-persistence/index.js +6 -2
  203. package/build-ngc/core/state-persistence/index.js.map +1 -1
  204. package/build-ngc/core/tab-router-state/index.d.ts +1 -0
  205. package/build-ngc/core/tab-router-state/index.js +27 -2
  206. package/build-ngc/core/tab-router-state/index.js.map +1 -1
  207. package/package.json +44 -16
  208. package/src/angular/drawer/index.ts +75 -29
  209. package/src/angular/index.ts +20 -4
  210. package/src/angular/injectors/inject-focus-effect.ts +8 -2
  211. package/src/angular/injectors/inject-is-focused.ts +6 -4
  212. package/src/angular/injectors/inject-navigation-state.ts +7 -4
  213. package/src/angular/injectors/inject-navigation.ts +12 -3
  214. package/src/angular/linking.ts +4 -1
  215. package/src/angular/navigation-context.service.ts +5 -2
  216. package/src/angular/navigation-scope.directive.ts +6 -2
  217. package/src/angular/screen.directive.ts +13 -3
  218. package/src/angular/search-bar-ref.directive.ts +10 -2
  219. package/src/angular/stack/index.ts +91 -24
  220. package/src/angular/tab-screen.directive.ts +3 -1
  221. package/src/angular/tabs/index.ts +54 -16
  222. package/src/core/constants.ts +6 -3
  223. package/src/core/drawer-options/index.ts +40 -13
  224. package/src/core/drawer-router-state/index.ts +11 -3
  225. package/src/core/guards.ts +3 -1
  226. package/src/core/header-bar-buttons.ts +41 -12
  227. package/src/core/index.ts +29 -5
  228. package/src/core/linking-config/index.ts +31 -10
  229. package/src/core/navigation-events/index.ts +8 -2
  230. package/src/core/navigator-handles/index.ts +8 -3
  231. package/src/core/navigator-props.ts +13 -4
  232. package/src/core/navigator-state/index.ts +24 -7
  233. package/src/core/render-drawer.ts +24 -9
  234. package/src/core/render-stack.ts +52 -13
  235. package/src/core/render-tabs.ts +24 -6
  236. package/src/core/screen-options.ts +15 -5
  237. package/src/core/search-bar-commands.ts +12 -3
  238. package/src/core/stack-router-state/index.ts +52 -0
  239. package/src/core/state-persistence/index.ts +13 -3
  240. package/src/core/tab-router-state/index.ts +35 -3
  241. package/src/react/drawer/index.ts +409 -330
  242. package/src/react/drawer-screen.ts +8 -2
  243. package/src/react/hooks/use-focus-effect.ts +8 -2
  244. package/src/react/hooks/use-is-focused.ts +6 -2
  245. package/src/react/hooks/use-navigation.ts +8 -2
  246. package/src/react/index.ts +37 -7
  247. package/src/react/linking.ts +4 -1
  248. package/src/react/navigation-context.ts +6 -2
  249. package/src/react/screen.ts +12 -3
  250. package/src/react/stack/index.ts +297 -220
  251. package/src/react/tab-screen.ts +3 -1
  252. package/src/react/tabs/index.ts +202 -139
  253. package/src/solid/drawer/index.ts +570 -0
  254. package/src/solid/drawer-screen-props.ts +24 -0
  255. package/src/solid/host.ts +29 -0
  256. package/src/solid/index.ts +87 -0
  257. package/src/solid/linking.ts +74 -0
  258. package/src/solid/navigation-context.ts +56 -0
  259. package/src/solid/primitives/create-focus-effect.ts +41 -0
  260. package/src/solid/primitives/create-is-focused.ts +41 -0
  261. package/src/solid/primitives/create-navigation-state.ts +44 -0
  262. package/src/solid/primitives/index.ts +12 -0
  263. package/src/solid/primitives/use-drawer-navigation.ts +25 -0
  264. package/src/solid/primitives/use-navigation.ts +44 -0
  265. package/src/solid/primitives/use-route.ts +18 -0
  266. package/src/solid/primitives/use-stack-navigation.ts +29 -0
  267. package/src/solid/primitives/use-tab-navigation.ts +25 -0
  268. package/src/solid/screen-props.ts +51 -0
  269. package/src/solid/screen-registry.ts +159 -0
  270. package/src/solid/screen.ts +80 -0
  271. package/src/solid/stack/index.ts +528 -0
  272. package/src/solid/tab-screen-props.ts +21 -0
  273. package/src/solid/tabs/index.ts +327 -0
  274. package/src/svelte/attachments.ts +70 -0
  275. package/src/svelte/descriptor-subtree.ts +51 -0
  276. package/src/svelte/drawer/drawer-props.ts +28 -0
  277. package/src/svelte/drawer/index.svelte +559 -0
  278. package/src/svelte/drawer/index.ts +10 -0
  279. package/src/svelte/drawer-screen-props.ts +26 -0
  280. package/src/svelte/drawer-screen.svelte +25 -0
  281. package/src/svelte/fabric-tree.test-helper.ts +95 -0
  282. package/src/svelte/index.ts +83 -0
  283. package/src/svelte/linking.svelte.ts +72 -0
  284. package/src/svelte/navigation-context.ts +62 -0
  285. package/src/svelte/navigation-scope.svelte +27 -0
  286. package/src/svelte/registry-host.ts +26 -0
  287. package/src/svelte/runes/index.ts +17 -0
  288. package/src/svelte/runes/use-drawer-navigation.svelte.ts +31 -0
  289. package/src/svelte/runes/use-focus-effect.svelte.ts +41 -0
  290. package/src/svelte/runes/use-is-focused.svelte.ts +38 -0
  291. package/src/svelte/runes/use-navigation-state.svelte.ts +48 -0
  292. package/src/svelte/runes/use-navigation.svelte.ts +49 -0
  293. package/src/svelte/runes/use-route.svelte.ts +16 -0
  294. package/src/svelte/runes/use-stack-navigation.svelte.ts +34 -0
  295. package/src/svelte/runes/use-tab-navigation.svelte.ts +29 -0
  296. package/src/svelte/screen-props.ts +50 -0
  297. package/src/svelte/screen-registry.ts +98 -0
  298. package/src/svelte/screen.svelte +28 -0
  299. package/src/svelte/stack/index.svelte +261 -0
  300. package/src/svelte/stack/index.ts +11 -0
  301. package/src/svelte/stack/stack-props.ts +31 -0
  302. package/src/svelte/stack/stack-screen.svelte +205 -0
  303. package/src/svelte/svelte-ambient.d.ts +6 -0
  304. package/src/svelte/svelte-compile.test-helper.ts +147 -0
  305. package/src/svelte/tab-screen-props.ts +22 -0
  306. package/src/svelte/tab-screen.svelte +26 -0
  307. package/src/svelte/tabs/index.svelte +269 -0
  308. package/src/svelte/tabs/index.ts +10 -0
  309. package/src/svelte/tabs/tab-props.ts +13 -0
  310. package/src/vue/composables/use-navigation-state.ts +7 -4
  311. package/src/vue/composables/use-navigation.ts +13 -3
  312. package/src/vue/drawer/index.ts +128 -41
  313. package/src/vue/drawer-screen.ts +12 -5
  314. package/src/vue/index.ts +15 -3
  315. package/src/vue/linking.ts +7 -2
  316. package/src/vue/navigation-context.ts +17 -5
  317. package/src/vue/screen.ts +7 -2
  318. package/src/vue/stack/index.ts +108 -43
  319. package/src/vue/tab-screen.ts +3 -1
  320. package/src/vue/tabs/index.ts +109 -68
@@ -46,14 +46,24 @@ import {
46
46
  createInitialNavigatorState,
47
47
  createNavigationEmitter,
48
48
  navigatorReducer,
49
+ reconcileStackRoutes,
49
50
  resolveScreenRenderPlan,
50
51
  resolveStackProps,
51
52
  } from '../../core';
52
- import type { INavigationEmitter, INavigatorHandle, INavigatorPlatform, IRoute } from '../../core';
53
+ import type {
54
+ INavigationEmitter,
55
+ INavigatorHandle,
56
+ INavigatorPlatform,
57
+ IRoute,
58
+ } from '../../core';
53
59
  import { collectRegistry } from '../collect-registry';
54
60
  import { NavigationContext } from '../navigation-context';
55
61
  import { Screen } from '../screen';
56
- import type { IReactScreenOptions, IScreenOptionsArgs, IScreenProps } from '../screen';
62
+ import type {
63
+ IReactScreenOptions,
64
+ IScreenOptionsArgs,
65
+ IScreenProps,
66
+ } from '../screen';
57
67
 
58
68
  export type { INavigatorHandle } from '../../core';
59
69
 
@@ -66,11 +76,15 @@ export type IStackProps = {
66
76
  // backTitleVisible defaults to `true` on both platforms per the codegen spec's own default
67
77
  // (CT.WithDefault<boolean, 'true'>) - no ios/android divergence in v1 scope, so a single constant
68
78
  // stands in for the per-platform injection point ISliderPlatform-style adapters use elsewhere.
69
- const NAVIGATOR_PLATFORM: INavigatorPlatform = { defaultHeaderBackTitleVisible: true };
79
+ const NAVIGATOR_PLATFORM: INavigatorPlatform = {
80
+ defaultHeaderBackTitleVisible: true,
81
+ };
70
82
 
71
83
  type IScreenRegistryEntry = Omit<IScreenProps, 'name'>;
72
84
 
73
- function isScreenElement(child: ReactNode): child is ReactElement<IScreenProps> {
85
+ function isScreenElement(
86
+ child: ReactNode,
87
+ ): child is ReactElement<IScreenProps> {
74
88
  return isValidElement(child) && child.type === Screen;
75
89
  }
76
90
 
@@ -79,245 +93,308 @@ function resolveScreenOptions(
79
93
  optionsArgs: IScreenOptionsArgs,
80
94
  screenOptions: IReactScreenOptions | undefined,
81
95
  ): IReactScreenOptions {
82
- const own = typeof entry.options === 'function' ? entry.options(optionsArgs) : entry.options;
96
+ const own =
97
+ typeof entry.options === 'function'
98
+ ? entry.options(optionsArgs)
99
+ : entry.options;
83
100
  return { ...screenOptions, ...own };
84
101
  }
85
102
 
86
- const StackImpl = forwardRef<INavigatorHandle, IStackProps>((props, forwardedRef) => {
87
- // Read BEFORE establishing this Stack's own Context value below - becomes the `parent` link a
88
- // nested screen's useNavigation().getParent() walks (e.g. this Stack rendered as a Tab screen's
89
- // content reaches that Tab via this value). undefined when this Stack is the nesting root.
90
- const ambientContext = useContext(NavigationContext);
91
- const registry = useMemo(
92
- () => collectRegistry(props.children, isScreenElement),
93
- [props.children],
94
- );
95
- const routeIdPrefix = useId();
96
- const routeSequence = useRef(0);
97
- // One emitter per route.key, keyed exactly like routeSequence's counter is scoped - created
98
- // lazily the first time a route is rendered, pruned once it's popped off the stack (below).
99
- const emitters = useRef(new Map<string, INavigationEmitter>()).current;
100
- // Investigation instrumentation (flicker-on-focus bug): route keys whose resolved
101
- // transition/animation-timing props have already been logged, so the once-per-mount dump below
102
- // doesn't spam on every re-render. Kept behind DEBUG, never removed.
103
- const loggedScreenPropKeys = useRef(new Set<string>()).current;
104
-
105
- const emitterFor = useCallback(
106
- (routeKey: string): INavigationEmitter => {
107
- let emitter = emitters.get(routeKey);
108
- if (!emitter) {
109
- emitter = createNavigationEmitter();
110
- emitters.set(routeKey, emitter);
111
- }
112
- return emitter;
113
- },
114
- [emitters],
115
- );
116
-
117
- const createRoute = useCallback(
118
- (name: string, params: unknown): IRoute<unknown> => {
119
- routeSequence.current += 1;
120
- return { key: `${routeIdPrefix}-${name}-${routeSequence.current}`, name, params };
121
- },
122
- [routeIdPrefix],
123
- );
103
+ const StackImpl = forwardRef<INavigatorHandle, IStackProps>(
104
+ (props, forwardedRef) => {
105
+ // Read BEFORE establishing this Stack's own Context value below - becomes the `parent` link a
106
+ // nested screen's useNavigation().getParent() walks (e.g. this Stack rendered as a Tab screen's
107
+ // content reaches that Tab via this value). undefined when this Stack is the nesting root.
108
+ const ambientContext = useContext(NavigationContext);
109
+ const registry = useMemo(
110
+ () => collectRegistry(props.children, isScreenElement),
111
+ [props.children],
112
+ );
113
+ const routeIdPrefix = useId();
114
+ const routeSequence = useRef(0);
115
+ // One emitter per route.key, keyed exactly like routeSequence's counter is scoped - created
116
+ // lazily the first time a route is rendered, pruned once it's popped off the stack (below).
117
+ const emitters = useRef(new Map<string, INavigationEmitter>()).current;
118
+ // Investigation instrumentation (flicker-on-focus bug): route keys whose resolved
119
+ // transition/animation-timing props have already been logged, so the once-per-mount dump below
120
+ // doesn't spam on every re-render. Kept behind DEBUG, never removed.
121
+ const loggedScreenPropKeys = useRef(new Set<string>()).current;
124
122
 
125
- const [state, dispatch] = useReducer(navigatorReducer, undefined, () => {
126
- const initialRouteName = props.initialRouteName ?? registry.keys().next().value;
127
- if (initialRouteName === undefined) {
128
- dlog('Stack: no <Stack.Screen> children registered');
129
- return createInitialNavigatorState({ key: routeIdPrefix, name: '', params: undefined });
130
- }
131
- return createInitialNavigatorState(
132
- createRoute(initialRouteName, registry.get(initialRouteName)?.initialParams),
123
+ const emitterFor = useCallback(
124
+ (routeKey: string): INavigationEmitter => {
125
+ let emitter = emitters.get(routeKey);
126
+ if (!emitter) {
127
+ emitter = createNavigationEmitter();
128
+ emitters.set(routeKey, emitter);
129
+ }
130
+ return emitter;
131
+ },
132
+ [emitters],
133
133
  );
134
- });
135
134
 
136
- const handle = useMemo<INavigatorHandle>(
137
- () => ({
138
- push: (name, params) => dispatch({ type: 'push', route: createRoute(name, params) }),
139
- pop: count => dispatch({ type: 'pop', count }),
140
- popToTop: () => dispatch({ type: 'popToTop' }),
141
- popTo: key => dispatch({ type: 'popTo', key }),
142
- replace: (name, params) => dispatch({ type: 'replace', route: createRoute(name, params) }),
143
- setParams: (params, key) => dispatch({ type: 'setParams', key, params }),
144
- reset: nextState => dispatch({ type: 'reset', state: nextState }),
145
- canGoBack: () => state.routes.length > 1,
146
- }),
147
- [createRoute, state.routes.length],
148
- );
135
+ const createRoute = useCallback(
136
+ (name: string, params: unknown): IRoute<unknown> => {
137
+ routeSequence.current += 1;
138
+ return {
139
+ key: `${routeIdPrefix}-${name}-${routeSequence.current}`,
140
+ name,
141
+ params,
142
+ };
143
+ },
144
+ [routeIdPrefix],
145
+ );
149
146
 
150
- useImperativeHandle(forwardedRef, () => handle, [handle]);
147
+ const registeredNames = useMemo(() => [...registry.keys()], [registry]);
151
148
 
152
- // Broadcasts the router state to every still-live route's emitter (useNavigationState's
153
- // source) after each commit, and prunes emitters for routes popped off the stack - mirroring
154
- // React's own subscribe-in-effect pattern rather than emitting mid-render, which would call a
155
- // descendant's setState while this component is still rendering.
156
- useEffect(() => {
157
- for (const route of state.routes) {
158
- emitterFor(route.key).emit(NAVIGATION_EVENT_STATE, state);
159
- }
160
- for (const routeKey of emitters.keys()) {
161
- if (!state.routes.some(route => route.key === routeKey)) emitters.delete(routeKey);
162
- }
163
- }, [state, emitterFor, emitters]);
149
+ const [dispatchedState, dispatch] = useReducer(
150
+ navigatorReducer,
151
+ undefined,
152
+ () => {
153
+ const initialRouteName =
154
+ props.initialRouteName ?? registry.keys().next().value;
155
+ if (initialRouteName === undefined) {
156
+ dlog('Stack: no <Stack.Screen> children registered');
157
+ return createInitialNavigatorState({
158
+ key: routeIdPrefix,
159
+ name: '',
160
+ params: undefined,
161
+ });
162
+ }
163
+ return createInitialNavigatorState(
164
+ createRoute(
165
+ initialRouteName,
166
+ registry.get(initialRouteName)?.initialParams,
167
+ ),
168
+ );
169
+ },
170
+ );
164
171
 
165
- // Investigation instrumentation (flicker-on-focus bug): STACK_ON_FINISH_TRANSITIONING is the
166
- // native signal that the WHOLE push/pop animation has finished (as opposed to onAppear/
167
- // onDisappear, which are per-screen) - logging it lets the per-screen appear/disappear
168
- // timestamps above be checked against the actual transition-complete moment. Kept behind
169
- // DEBUG, never removed.
170
- const stackProps = resolveStackProps({
171
- passthrough: {
172
- [STACK_ON_FINISH_TRANSITIONING]: () =>
173
- dlog(`Stack: onFinishTransitioning at t=${Date.now()}`),
174
- },
175
- });
172
+ // A <Stack.Screen> marker can unregister while its route is still in the pushed history, which
173
+ // would leave that entry with nothing to render (reconcileStackRoutes' header). Reconciling here
174
+ // rather than in an effect repairs the CURRENT paint - the call is pure and hands back the same
175
+ // reference when nothing changed, so it is safe during render; the effect below only PERSISTS
176
+ // the repair, so the next push builds on the pruned history instead of the phantom one.
177
+ const state = reconcileStackRoutes(dispatchedState, registeredNames);
176
178
 
177
- const children = state.routes.map((route, index) => {
178
- const entry = registry.get(route.name);
179
- if (!entry) {
180
- dlog(`Stack: no screen registered for route name "${route.name}"`);
181
- return null;
182
- }
179
+ useEffect(() => {
180
+ if (state !== dispatchedState) dispatch({ type: 'reset', state });
181
+ }, [state, dispatchedState]);
183
182
 
184
- const screenOptionsArgs: IScreenOptionsArgs = { route, navigation: handle };
185
- const mergedOptions = resolveScreenOptions(entry, screenOptionsArgs, props.screenOptions);
186
- const activityState = computeActivityState(index, state.routes.length);
187
- // Investigation instrumentation (flicker-on-focus bug): fires on EVERY Stack render, not just
188
- // on transitions, so the log stream shows whether a route's activityState/index ever changes
189
- // outside of a push/pop dispatch (e.g. from an unrelated re-render racing the native
190
- // transition). Kept behind DEBUG per <keep_logs_gate_behind_DEBUG> - never remove.
191
- dlog(
192
- `Stack: render route "${route.name}" index=${index}/${state.routes.length - 1} ` +
193
- `activityState=${activityState} at t=${Date.now()}`,
183
+ const handle = useMemo<INavigatorHandle>(
184
+ () => ({
185
+ push: (name, params) =>
186
+ dispatch({ type: 'push', route: createRoute(name, params) }),
187
+ pop: count => dispatch({ type: 'pop', count }),
188
+ popToTop: () => dispatch({ type: 'popToTop' }),
189
+ popTo: key => dispatch({ type: 'popTo', key }),
190
+ replace: (name, params) =>
191
+ dispatch({ type: 'replace', route: createRoute(name, params) }),
192
+ setParams: (params, key) =>
193
+ dispatch({ type: 'setParams', key, params }),
194
+ reset: nextState => dispatch({ type: 'reset', state: nextState }),
195
+ canGoBack: () => state.routes.length > 1,
196
+ }),
197
+ [createRoute, state.routes.length],
194
198
  );
195
199
 
196
- const routeEmitter = emitterFor(route.key);
200
+ useImperativeHandle(forwardedRef, () => handle, [handle]);
197
201
 
198
- const searchBarOptions = mergedOptions.headerSearchBarOptions;
199
- const plan = resolveScreenRenderPlan({
200
- screenId: route.key,
201
- index,
202
- routeCount: state.routes.length,
203
- options: mergedOptions,
204
- platform: NAVIGATOR_PLATFORM,
205
- isAndroid: Platform.OS === 'android',
206
- screenPassthrough: {
207
- [SCREEN_ON_DISMISSED]: () => dispatch({ type: 'pop', count: 1 }),
208
- [SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () => dispatch({ type: 'pop', count: 1 }),
209
- // onAppear/onDisappear are the definitive visibility boundary (post-transition-animation),
210
- // so 'focus'/'blur' fire exactly once per transition; onWillAppear/onWillDisappear fire
211
- // BEFORE the animation runs, so wiring them to emit() too would double-invoke
212
- // useFocusEffect per transition - they only get a debug log here.
213
- [SCREEN_ON_WILL_APPEAR]: () =>
214
- dlog(`Stack: route "${route.name}" will appear at t=${Date.now()}`),
215
- [SCREEN_ON_APPEAR]: () => {
216
- dlog(`Stack: route "${route.name}" appeared (focus) at t=${Date.now()}`);
217
- routeEmitter.emit(NAVIGATION_EVENT_FOCUS);
218
- },
219
- [SCREEN_ON_WILL_DISAPPEAR]: () =>
220
- dlog(`Stack: route "${route.name}" will disappear at t=${Date.now()}`),
221
- [SCREEN_ON_DISAPPEAR]: () => {
222
- dlog(`Stack: route "${route.name}" disappeared (blur) at t=${Date.now()}`);
223
- routeEmitter.emit(NAVIGATION_EVENT_BLUR);
224
- },
202
+ // Broadcasts the router state to every still-live route's emitter (useNavigationState's
203
+ // source) after each commit, and prunes emitters for routes popped off the stack - mirroring
204
+ // React's own subscribe-in-effect pattern rather than emitting mid-render, which would call a
205
+ // descendant's setState while this component is still rendering.
206
+ useEffect(() => {
207
+ for (const route of state.routes) {
208
+ emitterFor(route.key).emit(NAVIGATION_EVENT_STATE, state);
209
+ }
210
+ for (const routeKey of emitters.keys()) {
211
+ if (!state.routes.some(route => route.key === routeKey))
212
+ emitters.delete(routeKey);
213
+ }
214
+ }, [state, emitterFor, emitters]);
215
+
216
+ // Investigation instrumentation (flicker-on-focus bug): STACK_ON_FINISH_TRANSITIONING is the
217
+ // native signal that the WHOLE push/pop animation has finished (as opposed to onAppear/
218
+ // onDisappear, which are per-screen) - logging it lets the per-screen appear/disappear
219
+ // timestamps above be checked against the actual transition-complete moment. Kept behind
220
+ // DEBUG, never removed.
221
+ const stackProps = resolveStackProps({
222
+ passthrough: {
223
+ [STACK_ON_FINISH_TRANSITIONING]: () =>
224
+ dlog(`Stack: onFinishTransitioning at t=${Date.now()}`),
225
225
  },
226
- searchBarPassthrough: searchBarOptions
227
- ? {
228
- ...buildSearchBarPassthrough(searchBarOptions, message =>
229
- dlog(`Stack: route "${route.name}" ${message}`),
230
- ),
231
- // The imperative ref (SearchBarCommands): a callback ref attached straight to the
232
- // RNSSearchBar host element via `passthrough.ref` - createElement extracts `ref` from
233
- // a props object same as ScrollView/TextInput's own ref binding (see
234
- // descriptor-to-react's comment), so the host instance IS the ISymbioteNode. Built
235
- // fresh per mount/unmount, never captured eagerly (buildSearchBarHandle's own
236
- // lazy-getter contract is satisfied trivially here since `node` is already resolved).
237
- ref: (node: ISymbioteNode | null) => {
238
- // Investigation instrumentation (search-bar-ref "node not committed" bug): compare
239
- // this debugNodeId against the mirror.set/dispatchViewCommand logs in commit.ts -
240
- // same id on both sides proves the ref really does hold the committed node; a
241
- // mismatch proves a stale closure instead. Kept behind DEBUG, never removed.
242
- dlog(
243
- `Stack: search bar ref callback, node=${node === null ? 'null' : debugNodeId(node)} at t=${Date.now()}`,
244
- );
245
- const appRef = searchBarOptions.ref;
246
- if (!appRef) return;
247
- appRef.current = node === null ? null : buildSearchBarHandle(() => node);
248
- },
249
- }
250
- : undefined,
251
226
  });
252
- // Investigation instrumentation (flicker-on-focus bug): the actual timing/z-order-relevant
253
- // values resolved onto the native RNSScreen, once per route.key (not every render) - rules a
254
- // stackAnimation/transitionDuration mismatch against react-native-screens' own native default
255
- // in or out. Kept behind DEBUG, never removed.
256
- if (!loggedScreenPropKeys.has(route.key)) {
257
- loggedScreenPropKeys.add(route.key);
227
+
228
+ const children = state.routes.map((route, index) => {
229
+ const entry = registry.get(route.name);
230
+ if (!entry) {
231
+ dlog(`Stack: no screen registered for route name "${route.name}"`);
232
+ return null;
233
+ }
234
+
235
+ const screenOptionsArgs: IScreenOptionsArgs = {
236
+ route,
237
+ navigation: handle,
238
+ };
239
+ const mergedOptions = resolveScreenOptions(
240
+ entry,
241
+ screenOptionsArgs,
242
+ props.screenOptions,
243
+ );
244
+ const activityState = computeActivityState(index, state.routes.length);
245
+ // Investigation instrumentation (flicker-on-focus bug): fires on EVERY Stack render, not just
246
+ // on transitions, so the log stream shows whether a route's activityState/index ever changes
247
+ // outside of a push/pop dispatch (e.g. from an unrelated re-render racing the native
248
+ // transition). Kept behind DEBUG per <keep_logs_gate_behind_DEBUG> - never remove.
258
249
  dlog(
259
- `Stack: route "${route.name}" resolved screen props ` +
260
- `stackAnimation=${String(plan.screenProps.stackAnimation)} ` +
261
- `stackPresentation=${String(plan.screenProps.stackPresentation)} ` +
262
- `transitionDuration=${String(plan.screenProps.transitionDuration)} ` +
263
- `gestureEnabled=${String(plan.screenProps.gestureEnabled)} at t=${Date.now()}`,
250
+ `Stack: render route "${route.name}" index=${index}/${state.routes.length - 1} ` +
251
+ `activityState=${activityState} at t=${Date.now()}`,
264
252
  );
265
- }
266
253
 
267
- // Must not be flattened away (collapsable: false) - react-native-screens' native side
268
- // finds THIS specific view type by class check to register a formSheet's content for
269
- // sizing (see RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME's comment in core/constants.ts). A
270
- // `push` screen doesn't need it, but a `formSheet` one is otherwise left with no content
271
- // ever attached natively.
272
- const content = createElement(
273
- RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME,
274
- plan.contentWrapperProps,
275
- createElement(
276
- NavigationContext.Provider,
277
- { value: { route, navigation: handle, emitter: routeEmitter, parent: ambientContext } },
278
- createElement(entry.component),
279
- ),
280
- );
254
+ const routeEmitter = emitterFor(route.key);
255
+
256
+ const searchBarOptions = mergedOptions.headerSearchBarOptions;
257
+ const plan = resolveScreenRenderPlan({
258
+ screenId: route.key,
259
+ index,
260
+ routeCount: state.routes.length,
261
+ options: mergedOptions,
262
+ platform: NAVIGATOR_PLATFORM,
263
+ isAndroid: Platform.OS === 'android',
264
+ screenPassthrough: {
265
+ [SCREEN_ON_DISMISSED]: () => dispatch({ type: 'pop', count: 1 }),
266
+ [SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
267
+ dispatch({ type: 'pop', count: 1 }),
268
+ // onAppear/onDisappear are the definitive visibility boundary (post-transition-animation),
269
+ // so 'focus'/'blur' fire exactly once per transition; onWillAppear/onWillDisappear fire
270
+ // BEFORE the animation runs, so wiring them to emit() too would double-invoke
271
+ // useFocusEffect per transition - they only get a debug log here.
272
+ [SCREEN_ON_WILL_APPEAR]: () =>
273
+ dlog(`Stack: route "${route.name}" will appear at t=${Date.now()}`),
274
+ [SCREEN_ON_APPEAR]: () => {
275
+ dlog(
276
+ `Stack: route "${route.name}" appeared (focus) at t=${Date.now()}`,
277
+ );
278
+ routeEmitter.emit(NAVIGATION_EVENT_FOCUS);
279
+ },
280
+ [SCREEN_ON_WILL_DISAPPEAR]: () =>
281
+ dlog(
282
+ `Stack: route "${route.name}" will disappear at t=${Date.now()}`,
283
+ ),
284
+ [SCREEN_ON_DISAPPEAR]: () => {
285
+ dlog(
286
+ `Stack: route "${route.name}" disappeared (blur) at t=${Date.now()}`,
287
+ );
288
+ routeEmitter.emit(NAVIGATION_EVENT_BLUR);
289
+ },
290
+ },
291
+ searchBarPassthrough: searchBarOptions
292
+ ? {
293
+ ...buildSearchBarPassthrough(searchBarOptions, message =>
294
+ dlog(`Stack: route "${route.name}" ${message}`),
295
+ ),
296
+ // The imperative ref (SearchBarCommands): a callback ref attached straight to the
297
+ // RNSSearchBar host element via `passthrough.ref` - createElement extracts `ref` from
298
+ // a props object same as ScrollView/TextInput's own ref binding (see
299
+ // descriptor-to-react's comment), so the host instance IS the ISymbioteNode. Built
300
+ // fresh per mount/unmount, never captured eagerly (buildSearchBarHandle's own
301
+ // lazy-getter contract is satisfied trivially here since `node` is already resolved).
302
+ ref: (node: ISymbioteNode | null) => {
303
+ // Investigation instrumentation (search-bar-ref "node not committed" bug): compare
304
+ // this debugNodeId against the mirror.set/dispatchViewCommand logs in commit.ts -
305
+ // same id on both sides proves the ref really does hold the committed node; a
306
+ // mismatch proves a stale closure instead. Kept behind DEBUG, never removed.
307
+ dlog(
308
+ `Stack: search bar ref callback, node=${node === null ? 'null' : debugNodeId(node)} at t=${Date.now()}`,
309
+ );
310
+ const appRef = searchBarOptions.ref;
311
+ if (!appRef) return;
312
+ appRef.current =
313
+ node === null ? null : buildSearchBarHandle(() => node);
314
+ },
315
+ }
316
+ : undefined,
317
+ });
318
+ // Investigation instrumentation (flicker-on-focus bug): the actual timing/z-order-relevant
319
+ // values resolved onto the native RNSScreen, once per route.key (not every render) - rules a
320
+ // stackAnimation/transitionDuration mismatch against react-native-screens' own native default
321
+ // in or out. Kept behind DEBUG, never removed.
322
+ if (!loggedScreenPropKeys.has(route.key)) {
323
+ loggedScreenPropKeys.add(route.key);
324
+ dlog(
325
+ `Stack: route "${route.name}" resolved screen props ` +
326
+ `stackAnimation=${String(plan.screenProps.stackAnimation)} ` +
327
+ `stackPresentation=${String(plan.screenProps.stackPresentation)} ` +
328
+ `transitionDuration=${String(plan.screenProps.transitionDuration)} ` +
329
+ `gestureEnabled=${String(plan.screenProps.gestureEnabled)} at t=${Date.now()}`,
330
+ );
331
+ }
281
332
 
282
- // react-native-screens' own Screen.tsx swaps in a DIFFERENT Fabric component
283
- // ('RNSModalScreen') for a modally-presented screen - its native updateLayoutMetrics: relies on
284
- // this exact class to know it must NOT apply Yoga's computed frame (see resolveScreenViewName's
285
- // comment in core/render-stack.ts). The nested Screen isHeaderInModal adds below is always
286
- // plain 'RNSScreen': react-native-screens' own inner Screen never carries a presentation prop
287
- // either, since it exists purely to host the header, not to be modally presented itself.
333
+ // Must not be flattened away (collapsable: false) - react-native-screens' native side
334
+ // finds THIS specific view type by class check to register a formSheet's content for
335
+ // sizing (see RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME's comment in core/constants.ts). A
336
+ // `push` screen doesn't need it, but a `formSheet` one is otherwise left with no content
337
+ // ever attached natively.
338
+ const content = createElement(
339
+ RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME,
340
+ plan.contentWrapperProps,
341
+ createElement(
342
+ NavigationContext.Provider,
343
+ {
344
+ value: {
345
+ route,
346
+ navigation: handle,
347
+ emitter: routeEmitter,
348
+ parent: ambientContext,
349
+ },
350
+ },
351
+ createElement(entry.component),
352
+ ),
353
+ );
288
354
 
289
- // A modal/formSheet screen has no UINavigationController of its own on iOS - nest an inner
290
- // RNSScreenStack/RNSScreen purely to host the native header bar (see isHeaderInModal's
291
- // comment in core/render-stack.ts). Skipping this leaves RNSScreenStackHeaderConfig with no
292
- // navigation controller to attach to, so the header silently never renders.
293
- return plan.inModal
294
- ? createElement(
295
- plan.screenViewName,
296
- { key: route.key, ...plan.screenProps },
297
- createElement(
298
- RNS_SCREEN_STACK_VIEW_NAME,
299
- { style: plan.innerStackStyle },
355
+ // react-native-screens' own Screen.tsx swaps in a DIFFERENT Fabric component
356
+ // ('RNSModalScreen') for a modally-presented screen - its native updateLayoutMetrics: relies on
357
+ // this exact class to know it must NOT apply Yoga's computed frame (see resolveScreenViewName's
358
+ // comment in core/render-stack.ts). The nested Screen isHeaderInModal adds below is always
359
+ // plain 'RNSScreen': react-native-screens' own inner Screen never carries a presentation prop
360
+ // either, since it exists purely to host the header, not to be modally presented itself.
361
+
362
+ // A modal/formSheet screen has no UINavigationController of its own on iOS - nest an inner
363
+ // RNSScreenStack/RNSScreen purely to host the native header bar (see isHeaderInModal's
364
+ // comment in core/render-stack.ts). Skipping this leaves RNSScreenStackHeaderConfig with no
365
+ // navigation controller to attach to, so the header silently never renders.
366
+ return plan.inModal
367
+ ? createElement(
368
+ plan.screenViewName,
369
+ { key: route.key, ...plan.screenProps },
300
370
  createElement(
301
- RNS_SCREEN_VIEW_NAME,
302
- // activityState mirrors the outer Screen's own value - react-native-screens'
303
- // RNSScreen.mm treats an unset/inactive nested screen as not yet pushed, leaving it
304
- // parked at its pre-push transition position (off past the bottom edge) instead of
305
- // its real, presented frame.
306
- { style: plan.innerScreenStyle, activityState: plan.activityState },
307
- descriptorToReact(plan.headerConfig),
308
- content,
371
+ RNS_SCREEN_STACK_VIEW_NAME,
372
+ { style: plan.innerStackStyle },
373
+ createElement(
374
+ RNS_SCREEN_VIEW_NAME,
375
+ // activityState mirrors the outer Screen's own value - react-native-screens'
376
+ // RNSScreen.mm treats an unset/inactive nested screen as not yet pushed, leaving it
377
+ // parked at its pre-push transition position (off past the bottom edge) instead of
378
+ // its real, presented frame.
379
+ {
380
+ style: plan.innerScreenStyle,
381
+ activityState: plan.activityState,
382
+ },
383
+ descriptorToReact(plan.headerConfig),
384
+ content,
385
+ ),
309
386
  ),
310
- ),
311
- )
312
- : createElement(
313
- plan.screenViewName,
314
- { key: route.key, ...plan.screenProps },
315
- descriptorToReact(plan.headerConfig),
316
- content,
317
- );
318
- });
387
+ )
388
+ : createElement(
389
+ plan.screenViewName,
390
+ { key: route.key, ...plan.screenProps },
391
+ descriptorToReact(plan.headerConfig),
392
+ content,
393
+ );
394
+ });
319
395
 
320
- return createElement(RNS_SCREEN_STACK_VIEW_NAME, stackProps, ...children);
321
- });
396
+ return createElement(RNS_SCREEN_STACK_VIEW_NAME, stackProps, ...children);
397
+ },
398
+ );
322
399
 
323
400
  export const Stack = Object.assign(StackImpl, { Screen });
@@ -16,7 +16,9 @@ export type ITabScreenOptionsArgs = {
16
16
  navigation: ITabNavigatorHandle;
17
17
  };
18
18
 
19
- export type ITabScreenOptionsResolver = (args: ITabScreenOptionsArgs) => ITabOptions;
19
+ export type ITabScreenOptionsResolver = (
20
+ args: ITabScreenOptionsArgs,
21
+ ) => ITabOptions;
20
22
 
21
23
  export type ITabScreenProps = {
22
24
  name: string;