@symbiote-native/navigation 1.0.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 (455) hide show
  1. package/LICENSE +21 -0
  2. package/build/angular/drawer/index.d.ts +76 -0
  3. package/build/angular/drawer/index.js +508 -0
  4. package/build/angular/drawer-screen.directive.d.ts +14 -0
  5. package/build/angular/drawer-screen.directive.js +87 -0
  6. package/build/angular/index.d.ts +23 -0
  7. package/build/angular/index.js +22 -0
  8. package/build/angular/injectors/index.d.ts +13 -0
  9. package/build/angular/injectors/index.js +8 -0
  10. package/build/angular/injectors/inject-drawer-navigation.d.ts +4 -0
  11. package/build/angular/injectors/inject-drawer-navigation.js +12 -0
  12. package/build/angular/injectors/inject-focus-effect.d.ts +2 -0
  13. package/build/angular/injectors/inject-focus-effect.js +29 -0
  14. package/build/angular/injectors/inject-is-focused.d.ts +2 -0
  15. package/build/angular/injectors/inject-is-focused.js +20 -0
  16. package/build/angular/injectors/inject-navigation-state.d.ts +3 -0
  17. package/build/angular/injectors/inject-navigation-state.js +35 -0
  18. package/build/angular/injectors/inject-navigation.d.ts +7 -0
  19. package/build/angular/injectors/inject-navigation.js +16 -0
  20. package/build/angular/injectors/inject-route.d.ts +3 -0
  21. package/build/angular/injectors/inject-route.js +20 -0
  22. package/build/angular/injectors/inject-stack-navigation.d.ts +4 -0
  23. package/build/angular/injectors/inject-stack-navigation.js +15 -0
  24. package/build/angular/injectors/inject-tab-navigation.d.ts +4 -0
  25. package/build/angular/injectors/inject-tab-navigation.js +11 -0
  26. package/build/angular/linking.d.ts +3 -0
  27. package/build/angular/linking.js +43 -0
  28. package/build/angular/navigation-context.service.d.ts +13 -0
  29. package/build/angular/navigation-context.service.js +105 -0
  30. package/build/angular/navigation-scope.directive.d.ts +10 -0
  31. package/build/angular/navigation-scope.directive.js +90 -0
  32. package/build/angular/screen.directive.d.ts +22 -0
  33. package/build/angular/screen.directive.js +90 -0
  34. package/build/angular/search-bar-ref.directive.d.ts +10 -0
  35. package/build/angular/search-bar-ref.directive.js +88 -0
  36. package/build/angular/stack/index.d.ts +55 -0
  37. package/build/angular/stack/index.js +386 -0
  38. package/build/angular/tab-screen.directive.d.ts +14 -0
  39. package/build/angular/tab-screen.directive.js +87 -0
  40. package/build/angular/tabs/index.d.ts +42 -0
  41. package/build/angular/tabs/index.js +263 -0
  42. package/build/core/constants.d.ts +27 -0
  43. package/build/core/constants.js +61 -0
  44. package/build/core/drawer-options/index.d.ts +64 -0
  45. package/build/core/drawer-options/index.js +200 -0
  46. package/build/core/drawer-router-state/index.d.ts +21 -0
  47. package/build/core/drawer-router-state/index.js +40 -0
  48. package/build/core/guards.d.ts +2 -0
  49. package/build/core/guards.js +22 -0
  50. package/build/core/header-bar-buttons.d.ts +9 -0
  51. package/build/core/header-bar-buttons.js +163 -0
  52. package/build/core/index.d.ts +29 -0
  53. package/build/core/index.js +32 -0
  54. package/build/core/linking-config/index.d.ts +13 -0
  55. package/build/core/linking-config/index.js +171 -0
  56. package/build/core/navigation-events/index.d.ts +16 -0
  57. package/build/core/navigation-events/index.js +57 -0
  58. package/build/core/navigator-handles/index.d.ts +30 -0
  59. package/build/core/navigator-handles/index.js +15 -0
  60. package/build/core/navigator-props.d.ts +216 -0
  61. package/build/core/navigator-props.js +7 -0
  62. package/build/core/navigator-state/index.d.ts +36 -0
  63. package/build/core/navigator-state/index.js +81 -0
  64. package/build/core/render-drawer.d.ts +13 -0
  65. package/build/core/render-drawer.js +88 -0
  66. package/build/core/render-stack.d.ts +35 -0
  67. package/build/core/render-stack.js +294 -0
  68. package/build/core/render-tabs.d.ts +20 -0
  69. package/build/core/render-tabs.js +97 -0
  70. package/build/core/screen-options.d.ts +4 -0
  71. package/build/core/screen-options.js +133 -0
  72. package/build/core/search-bar-commands.d.ts +10 -0
  73. package/build/core/search-bar-commands.js +42 -0
  74. package/build/core/state-persistence/index.d.ts +3 -0
  75. package/build/core/state-persistence/index.js +23 -0
  76. package/build/core/tab-options.d.ts +13 -0
  77. package/build/core/tab-options.js +10 -0
  78. package/build/core/tab-router-state/index.d.ts +19 -0
  79. package/build/core/tab-router-state/index.js +51 -0
  80. package/build/react/collect-registry.d.ts +4 -0
  81. package/build/react/collect-registry.js +15 -0
  82. package/build/react/drawer/index.d.ts +29 -0
  83. package/build/react/drawer/index.js +277 -0
  84. package/build/react/drawer-screen.d.ts +14 -0
  85. package/build/react/drawer-screen.js +8 -0
  86. package/build/react/hooks/index.d.ts +12 -0
  87. package/build/react/hooks/index.js +8 -0
  88. package/build/react/hooks/use-drawer-navigation.d.ts +4 -0
  89. package/build/react/hooks/use-drawer-navigation.js +12 -0
  90. package/build/react/hooks/use-focus-effect.d.ts +2 -0
  91. package/build/react/hooks/use-focus-effect.js +29 -0
  92. package/build/react/hooks/use-is-focused.d.ts +1 -0
  93. package/build/react/hooks/use-is-focused.js +22 -0
  94. package/build/react/hooks/use-navigation-state/index.d.ts +2 -0
  95. package/build/react/hooks/use-navigation-state/index.js +39 -0
  96. package/build/react/hooks/use-navigation.d.ts +7 -0
  97. package/build/react/hooks/use-navigation.js +16 -0
  98. package/build/react/hooks/use-route.d.ts +2 -0
  99. package/build/react/hooks/use-route.js +8 -0
  100. package/build/react/hooks/use-stack-navigation.d.ts +4 -0
  101. package/build/react/hooks/use-stack-navigation.js +14 -0
  102. package/build/react/hooks/use-tab-navigation.d.ts +4 -0
  103. package/build/react/hooks/use-tab-navigation.js +12 -0
  104. package/build/react/index.d.ts +24 -0
  105. package/build/react/index.js +21 -0
  106. package/build/react/linking.d.ts +3 -0
  107. package/build/react/linking.js +47 -0
  108. package/build/react/navigation-context.d.ts +10 -0
  109. package/build/react/navigation-context.js +22 -0
  110. package/build/react/screen.d.ts +22 -0
  111. package/build/react/screen.js +7 -0
  112. package/build/react/stack/index.d.ts +13 -0
  113. package/build/react/stack/index.js +202 -0
  114. package/build/react/tab-screen.d.ts +15 -0
  115. package/build/react/tab-screen.js +8 -0
  116. package/build/react/tabs/index.d.ts +12 -0
  117. package/build/react/tabs/index.js +116 -0
  118. package/build/register.d.ts +7 -0
  119. package/build/register.js +58 -0
  120. package/build/vue/composables/index.d.ts +12 -0
  121. package/build/vue/composables/index.js +8 -0
  122. package/build/vue/composables/use-drawer-navigation.d.ts +5 -0
  123. package/build/vue/composables/use-drawer-navigation.js +15 -0
  124. package/build/vue/composables/use-focus-effect.d.ts +1 -0
  125. package/build/vue/composables/use-focus-effect.js +31 -0
  126. package/build/vue/composables/use-is-focused.d.ts +2 -0
  127. package/build/vue/composables/use-is-focused.js +28 -0
  128. package/build/vue/composables/use-navigation-state.d.ts +3 -0
  129. package/build/vue/composables/use-navigation-state.js +29 -0
  130. package/build/vue/composables/use-navigation.d.ts +8 -0
  131. package/build/vue/composables/use-navigation.js +13 -0
  132. package/build/vue/composables/use-route.d.ts +3 -0
  133. package/build/vue/composables/use-route.js +9 -0
  134. package/build/vue/composables/use-stack-navigation.d.ts +5 -0
  135. package/build/vue/composables/use-stack-navigation.js +18 -0
  136. package/build/vue/composables/use-tab-navigation.d.ts +5 -0
  137. package/build/vue/composables/use-tab-navigation.js +15 -0
  138. package/build/vue/drawer/index.d.ts +19 -0
  139. package/build/vue/drawer/index.js +390 -0
  140. package/build/vue/drawer-screen.d.ts +14 -0
  141. package/build/vue/drawer-screen.js +12 -0
  142. package/build/vue/index.d.ts +21 -0
  143. package/build/vue/index.js +19 -0
  144. package/build/vue/linking.d.ts +3 -0
  145. package/build/vue/linking.js +57 -0
  146. package/build/vue/navigation-context.d.ts +16 -0
  147. package/build/vue/navigation-context.js +65 -0
  148. package/build/vue/screen.d.ts +21 -0
  149. package/build/vue/screen.js +12 -0
  150. package/build/vue/stack/index.d.ts +9 -0
  151. package/build/vue/stack/index.js +279 -0
  152. package/build/vue/tab-screen.d.ts +14 -0
  153. package/build/vue/tab-screen.js +11 -0
  154. package/build/vue/tabs/index.d.ts +10 -0
  155. package/build/vue/tabs/index.js +209 -0
  156. package/build-ngc/angular/drawer/index.d.ts +79 -0
  157. package/build-ngc/angular/drawer/index.js +479 -0
  158. package/build-ngc/angular/drawer/index.js.map +1 -0
  159. package/build-ngc/angular/drawer-screen.directive.d.ts +17 -0
  160. package/build-ngc/angular/drawer-screen.directive.js +32 -0
  161. package/build-ngc/angular/drawer-screen.directive.js.map +1 -0
  162. package/build-ngc/angular/drawer.d.ts +79 -0
  163. package/build-ngc/angular/drawer.js +475 -0
  164. package/build-ngc/angular/drawer.js.map +1 -0
  165. package/build-ngc/angular/index.d.ts +23 -0
  166. package/build-ngc/angular/index.js +23 -0
  167. package/build-ngc/angular/index.js.map +1 -0
  168. package/build-ngc/angular/injectors/index.d.ts +13 -0
  169. package/build-ngc/angular/injectors/index.js +9 -0
  170. package/build-ngc/angular/injectors/index.js.map +1 -0
  171. package/build-ngc/angular/injectors/inject-drawer-navigation.d.ts +4 -0
  172. package/build-ngc/angular/injectors/inject-drawer-navigation.js +13 -0
  173. package/build-ngc/angular/injectors/inject-drawer-navigation.js.map +1 -0
  174. package/build-ngc/angular/injectors/inject-focus-effect.d.ts +2 -0
  175. package/build-ngc/angular/injectors/inject-focus-effect.js +30 -0
  176. package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -0
  177. package/build-ngc/angular/injectors/inject-is-focused.d.ts +2 -0
  178. package/build-ngc/angular/injectors/inject-is-focused.js +22 -0
  179. package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -0
  180. package/build-ngc/angular/injectors/inject-navigation-state.d.ts +3 -0
  181. package/build-ngc/angular/injectors/inject-navigation-state.js +37 -0
  182. package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -0
  183. package/build-ngc/angular/injectors/inject-navigation.d.ts +7 -0
  184. package/build-ngc/angular/injectors/inject-navigation.js +17 -0
  185. package/build-ngc/angular/injectors/inject-navigation.js.map +1 -0
  186. package/build-ngc/angular/injectors/inject-route.d.ts +3 -0
  187. package/build-ngc/angular/injectors/inject-route.js +21 -0
  188. package/build-ngc/angular/injectors/inject-route.js.map +1 -0
  189. package/build-ngc/angular/injectors/inject-stack-navigation.d.ts +4 -0
  190. package/build-ngc/angular/injectors/inject-stack-navigation.js +16 -0
  191. package/build-ngc/angular/injectors/inject-stack-navigation.js.map +1 -0
  192. package/build-ngc/angular/injectors/inject-tab-navigation.d.ts +4 -0
  193. package/build-ngc/angular/injectors/inject-tab-navigation.js +12 -0
  194. package/build-ngc/angular/injectors/inject-tab-navigation.js.map +1 -0
  195. package/build-ngc/angular/linking.d.ts +3 -0
  196. package/build-ngc/angular/linking.js +44 -0
  197. package/build-ngc/angular/linking.js.map +1 -0
  198. package/build-ngc/angular/navigation-context.service.d.ts +16 -0
  199. package/build-ngc/angular/navigation-context.service.js +63 -0
  200. package/build-ngc/angular/navigation-context.service.js.map +1 -0
  201. package/build-ngc/angular/navigation-scope.directive.d.ts +13 -0
  202. package/build-ngc/angular/navigation-scope.directive.js +42 -0
  203. package/build-ngc/angular/navigation-scope.directive.js.map +1 -0
  204. package/build-ngc/angular/screen.directive.d.ts +25 -0
  205. package/build-ngc/angular/screen.directive.js +35 -0
  206. package/build-ngc/angular/screen.directive.js.map +1 -0
  207. package/build-ngc/angular/search-bar-ref.directive.d.ts +13 -0
  208. package/build-ngc/angular/search-bar-ref.directive.js +44 -0
  209. package/build-ngc/angular/search-bar-ref.directive.js.map +1 -0
  210. package/build-ngc/angular/stack/index.d.ts +58 -0
  211. package/build-ngc/angular/stack/index.js +406 -0
  212. package/build-ngc/angular/stack/index.js.map +1 -0
  213. package/build-ngc/angular/stack.d.ts +58 -0
  214. package/build-ngc/angular/stack.js +402 -0
  215. package/build-ngc/angular/stack.js.map +1 -0
  216. package/build-ngc/angular/tab-screen.directive.d.ts +17 -0
  217. package/build-ngc/angular/tab-screen.directive.js +32 -0
  218. package/build-ngc/angular/tab-screen.directive.js.map +1 -0
  219. package/build-ngc/angular/tabs/index.d.ts +45 -0
  220. package/build-ngc/angular/tabs/index.js +231 -0
  221. package/build-ngc/angular/tabs/index.js.map +1 -0
  222. package/build-ngc/angular/tabs.d.ts +45 -0
  223. package/build-ngc/angular/tabs.js +231 -0
  224. package/build-ngc/angular/tabs.js.map +1 -0
  225. package/build-ngc/core/constants.d.ts +27 -0
  226. package/build-ngc/core/constants.js +62 -0
  227. package/build-ngc/core/constants.js.map +1 -0
  228. package/build-ngc/core/drawer-options/index.d.ts +64 -0
  229. package/build-ngc/core/drawer-options/index.js +201 -0
  230. package/build-ngc/core/drawer-options/index.js.map +1 -0
  231. package/build-ngc/core/drawer-options.d.ts +64 -0
  232. package/build-ngc/core/drawer-options.js +201 -0
  233. package/build-ngc/core/drawer-options.js.map +1 -0
  234. package/build-ngc/core/drawer-router-state/index.d.ts +21 -0
  235. package/build-ngc/core/drawer-router-state/index.js +41 -0
  236. package/build-ngc/core/drawer-router-state/index.js.map +1 -0
  237. package/build-ngc/core/drawer-router-state.d.ts +21 -0
  238. package/build-ngc/core/drawer-router-state.js +41 -0
  239. package/build-ngc/core/drawer-router-state.js.map +1 -0
  240. package/build-ngc/core/guards.d.ts +2 -0
  241. package/build-ngc/core/guards.js +23 -0
  242. package/build-ngc/core/guards.js.map +1 -0
  243. package/build-ngc/core/header-bar-buttons.d.ts +9 -0
  244. package/build-ngc/core/header-bar-buttons.js +164 -0
  245. package/build-ngc/core/header-bar-buttons.js.map +1 -0
  246. package/build-ngc/core/href.d.ts +16 -0
  247. package/build-ngc/core/href.js +55 -0
  248. package/build-ngc/core/href.js.map +1 -0
  249. package/build-ngc/core/index.d.ts +29 -0
  250. package/build-ngc/core/index.js +33 -0
  251. package/build-ngc/core/index.js.map +1 -0
  252. package/build-ngc/core/linking-config/index.d.ts +13 -0
  253. package/build-ngc/core/linking-config/index.js +172 -0
  254. package/build-ngc/core/linking-config/index.js.map +1 -0
  255. package/build-ngc/core/linking-config.d.ts +13 -0
  256. package/build-ngc/core/linking-config.js +172 -0
  257. package/build-ngc/core/linking-config.js.map +1 -0
  258. package/build-ngc/core/navigation-events/index.d.ts +16 -0
  259. package/build-ngc/core/navigation-events/index.js +58 -0
  260. package/build-ngc/core/navigation-events/index.js.map +1 -0
  261. package/build-ngc/core/navigation-events.d.ts +16 -0
  262. package/build-ngc/core/navigation-events.js +58 -0
  263. package/build-ngc/core/navigation-events.js.map +1 -0
  264. package/build-ngc/core/navigator-handles/index.d.ts +30 -0
  265. package/build-ngc/core/navigator-handles/index.js +16 -0
  266. package/build-ngc/core/navigator-handles/index.js.map +1 -0
  267. package/build-ngc/core/navigator-handles.d.ts +30 -0
  268. package/build-ngc/core/navigator-handles.js +16 -0
  269. package/build-ngc/core/navigator-handles.js.map +1 -0
  270. package/build-ngc/core/navigator-props.d.ts +216 -0
  271. package/build-ngc/core/navigator-props.js +8 -0
  272. package/build-ngc/core/navigator-props.js.map +1 -0
  273. package/build-ngc/core/navigator-state/index.d.ts +36 -0
  274. package/build-ngc/core/navigator-state/index.js +82 -0
  275. package/build-ngc/core/navigator-state/index.js.map +1 -0
  276. package/build-ngc/core/navigator-state.d.ts +36 -0
  277. package/build-ngc/core/navigator-state.js +82 -0
  278. package/build-ngc/core/navigator-state.js.map +1 -0
  279. package/build-ngc/core/render-drawer.d.ts +13 -0
  280. package/build-ngc/core/render-drawer.js +89 -0
  281. package/build-ngc/core/render-drawer.js.map +1 -0
  282. package/build-ngc/core/render-stack.d.ts +35 -0
  283. package/build-ngc/core/render-stack.js +295 -0
  284. package/build-ngc/core/render-stack.js.map +1 -0
  285. package/build-ngc/core/render-tabs.d.ts +20 -0
  286. package/build-ngc/core/render-tabs.js +98 -0
  287. package/build-ngc/core/render-tabs.js.map +1 -0
  288. package/build-ngc/core/screen-options.d.ts +4 -0
  289. package/build-ngc/core/screen-options.js +134 -0
  290. package/build-ngc/core/screen-options.js.map +1 -0
  291. package/build-ngc/core/search-bar-commands.d.ts +10 -0
  292. package/build-ngc/core/search-bar-commands.js +43 -0
  293. package/build-ngc/core/search-bar-commands.js.map +1 -0
  294. package/build-ngc/core/search-params.d.ts +9 -0
  295. package/build-ngc/core/search-params.js +60 -0
  296. package/build-ngc/core/search-params.js.map +1 -0
  297. package/build-ngc/core/state-persistence/index.d.ts +3 -0
  298. package/build-ngc/core/state-persistence/index.js +24 -0
  299. package/build-ngc/core/state-persistence/index.js.map +1 -0
  300. package/build-ngc/core/state-persistence.d.ts +3 -0
  301. package/build-ngc/core/state-persistence.js +24 -0
  302. package/build-ngc/core/state-persistence.js.map +1 -0
  303. package/build-ngc/core/tab-options.d.ts +13 -0
  304. package/build-ngc/core/tab-options.js +11 -0
  305. package/build-ngc/core/tab-options.js.map +1 -0
  306. package/build-ngc/core/tab-router-state/index.d.ts +19 -0
  307. package/build-ngc/core/tab-router-state/index.js +52 -0
  308. package/build-ngc/core/tab-router-state/index.js.map +1 -0
  309. package/build-ngc/core/tab-router-state.d.ts +19 -0
  310. package/build-ngc/core/tab-router-state.js +52 -0
  311. package/build-ngc/core/tab-router-state.js.map +1 -0
  312. package/build-ngc/register.d.ts +7 -0
  313. package/build-ngc/register.js +59 -0
  314. package/build-ngc/register.js.map +1 -0
  315. package/codegen-specs/FullWindowOverlayNativeComponent.ts +13 -0
  316. package/codegen-specs/ModalScreenNativeComponent.ts +129 -0
  317. package/codegen-specs/NativeScreensModule.ts +8 -0
  318. package/codegen-specs/NativeScreensModule.web.ts +1 -0
  319. package/codegen-specs/ScreenContainerNativeComponent.ts +8 -0
  320. package/codegen-specs/ScreenContentWrapperNativeComponent.ts +9 -0
  321. package/codegen-specs/ScreenFooterNativeComponent.ts +6 -0
  322. package/codegen-specs/ScreenNativeComponent.ts +133 -0
  323. package/codegen-specs/ScreenNavigationContainerNativeComponent.ts +11 -0
  324. package/codegen-specs/ScreenStackHeaderConfigNativeComponent.ts +99 -0
  325. package/codegen-specs/ScreenStackHeaderSubviewNativeComponent.ts +25 -0
  326. package/codegen-specs/ScreenStackNativeComponent.ts +17 -0
  327. package/codegen-specs/SearchBarNativeComponent.ts +101 -0
  328. package/codegen-specs/codegenUtils.ts +6 -0
  329. package/codegen-specs/gamma/ScrollViewMarkerNativeComponent.ts +15 -0
  330. package/codegen-specs/gamma/modals/form-sheet/FormSheetContentWrapperNativeComponent.ts +10 -0
  331. package/codegen-specs/gamma/modals/form-sheet/FormSheetHostNativeComponent.ts +47 -0
  332. package/codegen-specs/gamma/split/SplitHostNativeComponent.ts +124 -0
  333. package/codegen-specs/gamma/split/SplitScreenNativeComponent.ts +24 -0
  334. package/codegen-specs/gamma/stack/StackHeaderConfigAndroidNativeComponent.ts +144 -0
  335. package/codegen-specs/gamma/stack/StackHeaderConfigIOSNativeComponent.ts +34 -0
  336. package/codegen-specs/gamma/stack/StackHeaderItemIOSNativeComponent.ts +47 -0
  337. package/codegen-specs/gamma/stack/StackHeaderItemSpacerIOSNativeComponent.ts +20 -0
  338. package/codegen-specs/gamma/stack/StackHeaderSubviewAndroidNativeComponent.ts +27 -0
  339. package/codegen-specs/gamma/stack/StackHostNativeComponent.ts +8 -0
  340. package/codegen-specs/gamma/stack/StackScreenNativeComponent.ts +42 -0
  341. package/codegen-specs/safe-area/SafeAreaViewNativeComponent.ts +24 -0
  342. package/codegen-specs/tabs/TabsBottomAccessoryContentNativeComponent.ts +15 -0
  343. package/codegen-specs/tabs/TabsBottomAccessoryNativeComponent.ts +19 -0
  344. package/codegen-specs/tabs/TabsHostAndroidNativeComponent.ts +69 -0
  345. package/codegen-specs/tabs/TabsHostIOSNativeComponent.ts +92 -0
  346. package/codegen-specs/tabs/TabsScreenAndroidNativeComponent.ts +112 -0
  347. package/codegen-specs/tabs/TabsScreenIOSNativeComponent.ts +171 -0
  348. package/package.json +201 -0
  349. package/react-native.config.cjs +58 -0
  350. package/src/angular/drawer/drawer.test.ts +299 -0
  351. package/src/angular/drawer/index.ts +546 -0
  352. package/src/angular/drawer-screen.directive.ts +28 -0
  353. package/src/angular/index.ts +63 -0
  354. package/src/angular/injectors/index.ts +13 -0
  355. package/src/angular/injectors/inject-drawer-navigation.ts +21 -0
  356. package/src/angular/injectors/inject-focus-effect.ts +37 -0
  357. package/src/angular/injectors/inject-is-focused.ts +28 -0
  358. package/src/angular/injectors/inject-navigation-state.ts +46 -0
  359. package/src/angular/injectors/inject-navigation.ts +26 -0
  360. package/src/angular/injectors/inject-route.ts +25 -0
  361. package/src/angular/injectors/inject-stack-navigation.ts +24 -0
  362. package/src/angular/injectors/inject-tab-navigation.ts +20 -0
  363. package/src/angular/injectors/injectors.test.ts +247 -0
  364. package/src/angular/injectors/use-typed-navigation.test.ts +229 -0
  365. package/src/angular/linking.ts +55 -0
  366. package/src/angular/navigation-context.service.ts +68 -0
  367. package/src/angular/navigation-scope.directive.ts +31 -0
  368. package/src/angular/nested-navigation.test.ts +189 -0
  369. package/src/angular/screen.directive.ts +48 -0
  370. package/src/angular/search-bar-ref.directive.ts +38 -0
  371. package/src/angular/stack/index.ts +401 -0
  372. package/src/angular/stack/stack.test.ts +419 -0
  373. package/src/angular/tab-screen.directive.ts +26 -0
  374. package/src/angular/tabs/index.ts +254 -0
  375. package/src/angular/tabs/tabs.test.ts +249 -0
  376. package/src/core/constants.ts +68 -0
  377. package/src/core/drawer-options/drawer-options.test.ts +415 -0
  378. package/src/core/drawer-options/index.ts +331 -0
  379. package/src/core/drawer-router-state/drawer-router-state.test.ts +116 -0
  380. package/src/core/drawer-router-state/index.ts +71 -0
  381. package/src/core/guards.ts +23 -0
  382. package/src/core/header-bar-buttons.ts +212 -0
  383. package/src/core/index.ts +170 -0
  384. package/src/core/linking-config/index.ts +209 -0
  385. package/src/core/linking-config/linking-config.test.ts +109 -0
  386. package/src/core/navigation-events/index.ts +94 -0
  387. package/src/core/navigation-events/navigation-events.test.ts +56 -0
  388. package/src/core/navigator-handles/index.ts +63 -0
  389. package/src/core/navigator-handles/navigator-handles.test.ts +46 -0
  390. package/src/core/navigator-props.ts +323 -0
  391. package/src/core/navigator-state/index.ts +112 -0
  392. package/src/core/navigator-state/navigator-state.test.ts +80 -0
  393. package/src/core/render-drawer.ts +123 -0
  394. package/src/core/render-stack.ts +414 -0
  395. package/src/core/render-tabs.ts +138 -0
  396. package/src/core/screen-options.ts +181 -0
  397. package/src/core/search-bar-commands.ts +57 -0
  398. package/src/core/state-persistence/index.ts +30 -0
  399. package/src/core/state-persistence/state-persistence.test.ts +42 -0
  400. package/src/core/tab-options.ts +25 -0
  401. package/src/core/tab-router-state/index.ts +75 -0
  402. package/src/core/tab-router-state/tab-router-state.test.ts +34 -0
  403. package/src/globals.d.ts +4 -0
  404. package/src/react/collect-registry.ts +19 -0
  405. package/src/react/drawer/drawer.test.tsx +472 -0
  406. package/src/react/drawer/index.ts +451 -0
  407. package/src/react/drawer-screen.ts +29 -0
  408. package/src/react/hooks/hooks.test.tsx +199 -0
  409. package/src/react/hooks/index.ts +12 -0
  410. package/src/react/hooks/use-drawer-navigation.ts +21 -0
  411. package/src/react/hooks/use-focus-effect.ts +36 -0
  412. package/src/react/hooks/use-is-focused.ts +26 -0
  413. package/src/react/hooks/use-navigation-state/index.ts +47 -0
  414. package/src/react/hooks/use-navigation-state/use-navigation-state.test.ts +85 -0
  415. package/src/react/hooks/use-navigation.ts +36 -0
  416. package/src/react/hooks/use-route.ts +11 -0
  417. package/src/react/hooks/use-stack-navigation.ts +23 -0
  418. package/src/react/hooks/use-tab-navigation.ts +21 -0
  419. package/src/react/hooks/use-typed-navigation.test.tsx +187 -0
  420. package/src/react/index.ts +52 -0
  421. package/src/react/linking.ts +59 -0
  422. package/src/react/navigation-context.ts +40 -0
  423. package/src/react/nested-navigation.test.tsx +145 -0
  424. package/src/react/screen.ts +44 -0
  425. package/src/react/stack/index.ts +323 -0
  426. package/src/react/stack/stack.test.tsx +514 -0
  427. package/src/react/tab-screen.ts +30 -0
  428. package/src/react/tabs/index.ts +204 -0
  429. package/src/react/tabs/tabs.test.tsx +256 -0
  430. package/src/register.ts +59 -0
  431. package/src/vue/composables/composables.test.ts +221 -0
  432. package/src/vue/composables/index.ts +12 -0
  433. package/src/vue/composables/use-drawer-navigation.ts +25 -0
  434. package/src/vue/composables/use-focus-effect.ts +37 -0
  435. package/src/vue/composables/use-is-focused.ts +34 -0
  436. package/src/vue/composables/use-navigation-state.ts +38 -0
  437. package/src/vue/composables/use-navigation.ts +30 -0
  438. package/src/vue/composables/use-route.ts +13 -0
  439. package/src/vue/composables/use-stack-navigation.ts +28 -0
  440. package/src/vue/composables/use-tab-navigation.ts +25 -0
  441. package/src/vue/composables/use-typed-navigation.test.ts +205 -0
  442. package/src/vue/drawer/drawer.test.ts +451 -0
  443. package/src/vue/drawer/index.ts +550 -0
  444. package/src/vue/drawer-screen.ts +32 -0
  445. package/src/vue/index.ts +70 -0
  446. package/src/vue/linking.ts +69 -0
  447. package/src/vue/navigation-context.ts +87 -0
  448. package/src/vue/nested-navigation.test.ts +155 -0
  449. package/src/vue/screen.ts +52 -0
  450. package/src/vue/stack/index.ts +376 -0
  451. package/src/vue/stack/stack.test.ts +501 -0
  452. package/src/vue/tab-screen.ts +29 -0
  453. package/src/vue/tabs/index.ts +302 -0
  454. package/src/vue/tabs/tabs.test.ts +278 -0
  455. package/symbiote-navigation.podspec +84 -0
@@ -0,0 +1,145 @@
1
+ // Co-located React-driven test (ADR 0025) proving the Context "parent" chain: a navigator reads
2
+ // the ambient NavigationContext BEFORE establishing its own, so when one navigator's screen
3
+ // renders ANOTHER navigator (here, a Stack screen renders a Tab), a screen deep inside the nested
4
+ // Tab can call useNavigation().getParent() to reach the enclosing Stack's handle. Mirrors
5
+ // stack.test.tsx's fixture (an injected codegen-shaped RNSScreen ViewConfig) since a real Stack is
6
+ // part of this composition; Tab needs no ViewConfig of its own (tabs.test.tsx).
7
+
8
+ import { act, createElement, createRef } from 'react';
9
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
10
+ import { mount, unmount, setNativeViewConfigSource } from '@symbiote-native/react';
11
+ import type { INativeViewConfig } from '@symbiote-native/engine';
12
+ import { installFabric, type IFakeNode } from '@symbiote-native/test-utils';
13
+ import { Stack } from './stack';
14
+ import type { INavigatorHandle } from './stack';
15
+ import { Tab } from './tabs';
16
+ import { useNavigation } from './hooks';
17
+ import type { IAnyNavigatorHandle } from './navigation-context';
18
+
19
+ const ROOT_TAG = 768;
20
+ const SCREEN_VIEW = 'RNSScreen';
21
+ const STACK_VIEW = 'RNSScreenStack';
22
+ const HEADER_CONFIG_VIEW = 'RNSScreenStackHeaderConfig';
23
+
24
+ function directEvent(registrationName: string) {
25
+ return { registrationName };
26
+ }
27
+
28
+ const VIEW_CONFIGS: Record<string, INativeViewConfig> = {
29
+ [SCREEN_VIEW]: {
30
+ directEventTypes: {
31
+ topAppear: directEvent('onAppear'),
32
+ topDisappear: directEvent('onDisappear'),
33
+ topWillAppear: directEvent('onWillAppear'),
34
+ topWillDisappear: directEvent('onWillDisappear'),
35
+ topDismissed: directEvent('onDismissed'),
36
+ topHeaderBackButtonClicked: directEvent('onHeaderBackButtonClicked'),
37
+ },
38
+ validAttributes: {
39
+ screenId: true,
40
+ activityState: true,
41
+ gestureEnabled: true,
42
+ stackAnimation: true,
43
+ stackPresentation: true,
44
+ transitionDuration: true,
45
+ },
46
+ },
47
+ [STACK_VIEW]: {
48
+ directEventTypes: { topFinishTransitioning: directEvent('onFinishTransitioning') },
49
+ validAttributes: {},
50
+ },
51
+ [HEADER_CONFIG_VIEW]: {
52
+ directEventTypes: { topPressHeaderBarButtonItem: directEvent('onPressHeaderBarButtonItem') },
53
+ validAttributes: { title: true, hidden: true, backTitle: true, backTitleVisible: true },
54
+ },
55
+ };
56
+
57
+ const fabric = installFabric();
58
+ setNativeViewConfigSource(name => VIEW_CONFIGS[name]);
59
+
60
+ beforeEach(() => fabric.reset());
61
+ afterEach(() => unmount(ROOT_TAG));
62
+
63
+ function findAllText(nodes: readonly IFakeNode[]): string[] {
64
+ const found: string[] = [];
65
+ const collect = (list: readonly IFakeNode[]): void => {
66
+ for (const node of list) {
67
+ if (node.viewName === 'RCTRawText' && typeof node.props.text === 'string') {
68
+ found.push(node.props.text);
69
+ }
70
+ collect(node.children);
71
+ }
72
+ };
73
+ collect(nodes);
74
+ return found;
75
+ }
76
+
77
+ function StackDetailsScreen(): ReturnType<typeof createElement> {
78
+ return createElement('symbiote-text', {}, 'stack-details');
79
+ }
80
+
81
+ describe('nested navigators (Context parent chain)', () => {
82
+ it("a root Stack screen's useNavigation().getParent() is undefined (no ambient navigator above it)", () => {
83
+ let capturedParent: IAnyNavigatorHandle | undefined;
84
+ let getParentCalled = false;
85
+ function RootScreen(): ReturnType<typeof createElement> {
86
+ capturedParent = useNavigation().getParent();
87
+ getParentCalled = true;
88
+ return createElement('symbiote-text', {}, 'root');
89
+ }
90
+
91
+ mount(
92
+ ROOT_TAG,
93
+ createElement(
94
+ Stack,
95
+ { initialRouteName: 'Root' },
96
+ createElement(Stack.Screen, { name: 'Root', component: RootScreen }),
97
+ ),
98
+ );
99
+
100
+ expect(getParentCalled).toBe(true);
101
+ expect(capturedParent).toBeUndefined();
102
+ });
103
+
104
+ it('useNavigation().getParent() from inside a Tab screen nested in a Stack screen reaches the enclosing Stack, and pushing through it adds a Stack route', () => {
105
+ let capturedParent: IAnyNavigatorHandle | undefined;
106
+
107
+ function NestedTabHomeScreen(): ReturnType<typeof createElement> {
108
+ capturedParent = useNavigation().getParent();
109
+ return createElement('symbiote-text', {}, 'tab-home');
110
+ }
111
+
112
+ // The Stack screen's own component: a Tab navigator, nested exactly the way a real app
113
+ // composes navigators (a Stack screen's content IS another navigator).
114
+ function RootScreenRendersTab(): ReturnType<typeof createElement> {
115
+ return createElement(
116
+ Tab,
117
+ { initialRouteName: 'TabHome' },
118
+ createElement(Tab.Screen, { name: 'TabHome', component: NestedTabHomeScreen }),
119
+ );
120
+ }
121
+
122
+ const ref = createRef<INavigatorHandle>();
123
+ mount(
124
+ ROOT_TAG,
125
+ createElement(
126
+ Stack,
127
+ { ref, initialRouteName: 'Root' },
128
+ createElement(Stack.Screen, { name: 'Root', component: RootScreenRendersTab }),
129
+ createElement(Stack.Screen, { name: 'Details', component: StackDetailsScreen }),
130
+ ),
131
+ );
132
+
133
+ expect(findAllText(fabric.committed)).toContain('tab-home');
134
+
135
+ if (!capturedParent) throw new Error('getParent() returned undefined');
136
+ if (!('push' in capturedParent)) {
137
+ throw new Error('parent handle is not a Stack handle (missing push)');
138
+ }
139
+ // capturedParent is now narrowed to INavigatorHandle by the 'push in' guard above.
140
+ act(() => capturedParent.push('Details'));
141
+
142
+ expect(findAllText(fabric.committed)).toContain('stack-details');
143
+ expect(ref.current?.canGoBack()).toBe(true);
144
+ });
145
+ });
@@ -0,0 +1,44 @@
1
+ // Stack.Screen: a declarative marker, never rendered on its own - Stack reads its props via
2
+ // React.Children to build the static name -> {component, options} registry, then mounts the
3
+ // registered component itself for each pushed route. Mirrors @react-navigation's JSX-config
4
+ // screens, minus the linking/param-list generics (v1 scope).
5
+
6
+ import type { FC, ReactElement, RefObject } from 'react';
7
+ import type { IRoute } from '../core';
8
+ import type { ISearchBarCommands, ISearchBarOptions, IScreenOptions } from '../core';
9
+ import type { INavigatorHandle } from '../core';
10
+
11
+ // The imperative ref (focus/blur/clearText/setText/cancelSearch/toggleCancelButton) carries a
12
+ // React ref type, so - per CLAUDE.md's <prop_types_split_agnostic_vs_per_adapter> - it cannot
13
+ // live in the shared, agnostic ISearchBarOptions (core/navigator-props.ts). This adapter-only
14
+ // overlay adds it on top of the agnostic field base, mirroring react-native-screens' own
15
+ // SearchBarProps.ref: React.RefObject<SearchBarCommands | null>.
16
+ export type IReactSearchBarOptions = ISearchBarOptions & {
17
+ ref?: RefObject<ISearchBarCommands | null>;
18
+ };
19
+
20
+ export type IReactScreenOptions = Omit<IScreenOptions, 'headerSearchBarOptions'> & {
21
+ headerSearchBarOptions?: IReactSearchBarOptions;
22
+ };
23
+
24
+ // The options resolver runs INSIDE the Stack while it computes a screen's options - its
25
+ // bar-button/menu onPress handlers close over the live navigator handle. This is NOT the mounted
26
+ // screen component (that one reads navigation/route via the hooks); it's a config callback with no
27
+ // lifecycle, so hooks aren't available to it and the handle arrives as an argument instead.
28
+ export type IScreenOptionsArgs = {
29
+ route: IRoute<unknown>;
30
+ navigation: INavigatorHandle;
31
+ };
32
+
33
+ export type IScreenOptionsResolver = (args: IScreenOptionsArgs) => IReactScreenOptions;
34
+
35
+ export type IScreenProps = {
36
+ name: string;
37
+ component: FC;
38
+ options?: IReactScreenOptions | IScreenOptionsResolver;
39
+ initialParams?: unknown;
40
+ };
41
+
42
+ export function Screen(_props: IScreenProps): ReactElement | null {
43
+ return null;
44
+ }
@@ -0,0 +1,323 @@
1
+ // Stack, the React lifecycle half. The route-stack transitions (navigator-state) and the
2
+ // options/props folds (screen-options, render-stack) live in @symbiote-native/navigation core,
3
+ // shared verbatim with the Vue/Angular adapters; here React supplies the lifecycle - useReducer
4
+ // for the pushed-route stack, useId + a ref counter for route-key generation, useImperativeHandle
5
+ // for the push/pop/replace navigator handle - plus the descriptor bridge for the header config
6
+ // leaf. Pushing/popping a route is an ordinary child mount/unmount: RNSScreenStack diffs its
7
+ // RNSScreen children natively, so no imperative native command is needed here at all. Neither
8
+ // this nor the Screen marker imports react-native-screens' own React components (ScreenStack.tsx
9
+ // et al - hooks, crashes a non-React adapter); the native views are driven directly through the
10
+ // ViewConfig ../register registers. See CLAUDE.md <third_party_rn_packages_are_react_only>.
11
+
12
+ import {
13
+ createElement,
14
+ forwardRef,
15
+ isValidElement,
16
+ useCallback,
17
+ useContext,
18
+ useEffect,
19
+ useId,
20
+ useImperativeHandle,
21
+ useMemo,
22
+ useReducer,
23
+ useRef,
24
+ } from 'react';
25
+ import type { ReactElement, ReactNode } from 'react';
26
+ import { descriptorToReact } from '@symbiote-native/react';
27
+ import { Platform, debugNodeId, dlog } from '@symbiote-native/engine';
28
+ import type { ISymbioteNode } from '@symbiote-native/engine';
29
+ import {
30
+ NAVIGATION_EVENT_BLUR,
31
+ NAVIGATION_EVENT_FOCUS,
32
+ NAVIGATION_EVENT_STATE,
33
+ RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME,
34
+ RNS_SCREEN_STACK_VIEW_NAME,
35
+ RNS_SCREEN_VIEW_NAME,
36
+ SCREEN_ON_APPEAR,
37
+ SCREEN_ON_DISAPPEAR,
38
+ SCREEN_ON_DISMISSED,
39
+ SCREEN_ON_HEADER_BACK_BUTTON_CLICKED,
40
+ SCREEN_ON_WILL_APPEAR,
41
+ SCREEN_ON_WILL_DISAPPEAR,
42
+ STACK_ON_FINISH_TRANSITIONING,
43
+ buildSearchBarHandle,
44
+ buildSearchBarPassthrough,
45
+ computeActivityState,
46
+ createInitialNavigatorState,
47
+ createNavigationEmitter,
48
+ navigatorReducer,
49
+ resolveScreenRenderPlan,
50
+ resolveStackProps,
51
+ } from '../../core';
52
+ import type { INavigationEmitter, INavigatorHandle, INavigatorPlatform, IRoute } from '../../core';
53
+ import { collectRegistry } from '../collect-registry';
54
+ import { NavigationContext } from '../navigation-context';
55
+ import { Screen } from '../screen';
56
+ import type { IReactScreenOptions, IScreenOptionsArgs, IScreenProps } from '../screen';
57
+
58
+ export type { INavigatorHandle } from '../../core';
59
+
60
+ export type IStackProps = {
61
+ initialRouteName?: string;
62
+ screenOptions?: IReactScreenOptions;
63
+ children?: ReactNode;
64
+ };
65
+
66
+ // backTitleVisible defaults to `true` on both platforms per the codegen spec's own default
67
+ // (CT.WithDefault<boolean, 'true'>) - no ios/android divergence in v1 scope, so a single constant
68
+ // stands in for the per-platform injection point ISliderPlatform-style adapters use elsewhere.
69
+ const NAVIGATOR_PLATFORM: INavigatorPlatform = { defaultHeaderBackTitleVisible: true };
70
+
71
+ type IScreenRegistryEntry = Omit<IScreenProps, 'name'>;
72
+
73
+ function isScreenElement(child: ReactNode): child is ReactElement<IScreenProps> {
74
+ return isValidElement(child) && child.type === Screen;
75
+ }
76
+
77
+ function resolveScreenOptions(
78
+ entry: IScreenRegistryEntry,
79
+ optionsArgs: IScreenOptionsArgs,
80
+ screenOptions: IReactScreenOptions | undefined,
81
+ ): IReactScreenOptions {
82
+ const own = typeof entry.options === 'function' ? entry.options(optionsArgs) : entry.options;
83
+ return { ...screenOptions, ...own };
84
+ }
85
+
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
+ );
124
+
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),
133
+ );
134
+ });
135
+
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
+ );
149
+
150
+ useImperativeHandle(forwardedRef, () => handle, [handle]);
151
+
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]);
164
+
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
+ });
176
+
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
+ }
183
+
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()}`,
194
+ );
195
+
196
+ const routeEmitter = emitterFor(route.key);
197
+
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
+ },
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
+ });
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);
258
+ 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()}`,
264
+ );
265
+ }
266
+
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
+ );
281
+
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.
288
+
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 },
300
+ 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,
309
+ ),
310
+ ),
311
+ )
312
+ : createElement(
313
+ plan.screenViewName,
314
+ { key: route.key, ...plan.screenProps },
315
+ descriptorToReact(plan.headerConfig),
316
+ content,
317
+ );
318
+ });
319
+
320
+ return createElement(RNS_SCREEN_STACK_VIEW_NAME, stackProps, ...children);
321
+ });
322
+
323
+ export const Stack = Object.assign(StackImpl, { Screen });