@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,323 @@
1
+ // Navigator prop types. Per CLAUDE.md <prop_types_split_agnostic_vs_per_adapter>: screen
2
+ // options (title, header styling, transition/presentation) are entirely scalar/color-typed, so
3
+ // they live here as the shared agnostic base every adapter re-exports. The Stack/Screen PUBLIC
4
+ // component props are NOT here - they carry framework children (the screen content) and a
5
+ // framework ref (the navigator handle), so each adapter declares its own flavored type over
6
+ // this base, same split as IPressableProps.
7
+
8
+ import type { IColorValue, ISymbioteEvent } from '@symbiote-native/engine';
9
+ import type { IImageSourceProp } from '@symbiote-native/components';
10
+
11
+ export type IStackAnimation =
12
+ | 'default'
13
+ | 'flip'
14
+ | 'simple_push'
15
+ | 'none'
16
+ | 'fade'
17
+ | 'slide_from_right'
18
+ | 'slide_from_left'
19
+ | 'slide_from_bottom'
20
+ | 'fade_from_bottom'
21
+ | 'ios_from_right'
22
+ | 'ios_from_left';
23
+
24
+ export type IStackPresentation =
25
+ | 'push'
26
+ | 'modal'
27
+ | 'transparentModal'
28
+ | 'fullScreenModal'
29
+ | 'formSheet'
30
+ | 'pageSheet'
31
+ | 'containedModal'
32
+ | 'containedTransparentModal';
33
+
34
+ export type IHeaderBackButtonDisplayMode = 'minimal' | 'default' | 'generic';
35
+
36
+ // react-native-screens' native chrome (the nav bar's blur/vibrancy, and - critically - an
37
+ // embedded headerSearchBarOptions search field's own backdrop) follows this OS-level trait
38
+ // rather than our individual color props; left 'unspecified', it inherits the SYSTEM appearance
39
+ // regardless of app theme, which is why a search bar on an otherwise all-dark screen still shows
40
+ // a stray light backdrop even with every color prop set. 'dark'/'light' force the whole header
41
+ // (and any embedded search bar) into that appearance outright.
42
+ export type IHeaderUserInterfaceStyle = 'unspecified' | 'light' | 'dark';
43
+
44
+ // A 3-state native boolean (RNSSearchBar's `obscureBackground`/`hideNavigationBar`): the legacy
45
+ // (Paper) architecture can't diff a `WithDefault<boolean>` against "unset" the way Fabric can, so
46
+ // react-native-screens' own codegen spec models these two props as this string enum instead of a
47
+ // plain optional boolean.
48
+ export type IOptionalBooleanNativeProp = 'undefined' | 'false' | 'true';
49
+
50
+ // RNSScreen's real sheet-detent surface (`formSheet`/`pageSheet` presentation). The compat union
51
+ // mirrors react-native-screens' own ScreenProps['sheetAllowedDetents'] - a plain fraction array,
52
+ // sorted ascending, or one of RNS's named presets; the fold to the native `sheetAllowedDetents:
53
+ // number[]` array happens in screen-options.ts, replicating RNS's own resolveSheetAllowedDetents.
54
+ export type ISheetAllowedDetents = number[] | 'fitToContents' | 'large' | 'medium' | 'all';
55
+ export type ISheetLargestUndimmedDetent = number | 'last' | 'none' | 'all' | 'large' | 'medium';
56
+ export type ISheetInitialDetent = number | 'last';
57
+
58
+ // A bar-button item's icon: SF Symbol / iOS asset-catalog name, or an image asset. Mirrors RNS's
59
+ // PlatformIconIOS union - the only icon shape RNSScreenStackHeaderConfig's bar-button items
60
+ // accept; there is no Android equivalent in the codegen spec (header bar-button items are iOS-only
61
+ // native surface).
62
+ export type IHeaderBarButtonIcon =
63
+ | { type: 'sfSymbol'; name: string }
64
+ | { type: 'xcasset'; name: string }
65
+ | { type: 'imageSource'; imageSource: IImageSourceProp }
66
+ | { type: 'templateSource'; templateSource: IImageSourceProp };
67
+
68
+ export type IHeaderBarButtonItemBadge = {
69
+ value: string;
70
+ style?: {
71
+ color?: IColorValue;
72
+ backgroundColor?: IColorValue;
73
+ fontFamily?: string;
74
+ fontSize?: number;
75
+ fontWeight?: string;
76
+ };
77
+ };
78
+
79
+ type ISharedHeaderBarButtonItem = {
80
+ index?: number;
81
+ title?: string;
82
+ titleStyle?: {
83
+ fontFamily?: string;
84
+ fontSize?: number;
85
+ fontWeight?: string;
86
+ color?: IColorValue;
87
+ };
88
+ icon?: IHeaderBarButtonIcon;
89
+ variant?: 'plain' | 'done' | 'prominent';
90
+ tintColor?: IColorValue;
91
+ disabled?: boolean;
92
+ width?: number;
93
+ hidesSharedBackground?: boolean;
94
+ sharesBackground?: boolean;
95
+ identifier?: string;
96
+ badge?: IHeaderBarButtonItemBadge;
97
+ accessibilityLabel?: string;
98
+ accessibilityHint?: string;
99
+ };
100
+
101
+ export type IHeaderBarButtonItemAction = ISharedHeaderBarButtonItem & {
102
+ type: 'button';
103
+ onPress: () => void;
104
+ selected?: boolean;
105
+ };
106
+
107
+ export type IHeaderBarButtonMenuAction = {
108
+ type: 'action';
109
+ title?: string;
110
+ subtitle?: string;
111
+ onPress: () => void;
112
+ icon?: IHeaderBarButtonIcon;
113
+ state?: 'on' | 'off' | 'mixed';
114
+ disabled?: boolean;
115
+ destructive?: boolean;
116
+ hidden?: boolean;
117
+ keepsMenuPresented?: boolean;
118
+ discoverabilityLabel?: string;
119
+ };
120
+
121
+ export type IHeaderBarButtonSubmenu = {
122
+ type: 'submenu';
123
+ title?: string;
124
+ icon?: IHeaderBarButtonIcon;
125
+ items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[];
126
+ displayInline?: boolean;
127
+ destructive?: boolean;
128
+ singleSelection?: boolean;
129
+ displayAsPalette?: boolean;
130
+ };
131
+
132
+ export type IHeaderBarButtonItemMenu = ISharedHeaderBarButtonItem & {
133
+ type: 'menu';
134
+ menu: {
135
+ title?: string;
136
+ items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[];
137
+ singleSelection?: boolean;
138
+ displayAsPalette?: boolean;
139
+ };
140
+ changesSelectionAsPrimaryAction?: boolean;
141
+ };
142
+
143
+ export type IHeaderBarButtonItemSpacing = { type: 'spacing'; spacing: number };
144
+
145
+ export type IHeaderBarButtonItem =
146
+ IHeaderBarButtonItemAction | IHeaderBarButtonItemMenu | IHeaderBarButtonItemSpacing;
147
+
148
+ export type ISearchBarAutoCapitalize =
149
+ 'systemDefault' | 'none' | 'words' | 'sentences' | 'characters';
150
+
151
+ export type ISearchBarPlacement =
152
+ 'automatic' | 'inline' | 'stacked' | 'integrated' | 'integratedButton' | 'integratedCentered';
153
+
154
+ // RNSSearchBar's full static config surface plus every event callback react-native-screens'
155
+ // own SearchBarProps exposes (types.tsx): onChangeText/onSearchButtonPress carry the current
156
+ // text, the rest are plain notifications. onClose/onOpen are Android-only upstream. The
157
+ // imperative ref (focus/blur/clearText/setText/cancelSearch/toggleCancelButton) is NOT here -
158
+ // it carries a framework ref type, so it is per-adapter (see react/screen.ts's
159
+ // IReactSearchBarOptions), same split as IPressableProps' children/ref fields.
160
+ export type ISearchBarOptions = {
161
+ placeholder?: string;
162
+ autoCapitalize?: ISearchBarAutoCapitalize;
163
+ placement?: ISearchBarPlacement;
164
+ hideWhenScrolling?: boolean;
165
+ allowToolbarIntegration?: boolean;
166
+ obscureBackground?: boolean;
167
+ hideNavigationBar?: boolean;
168
+ cancelButtonText?: string;
169
+ barTintColor?: IColorValue;
170
+ tintColor?: IColorValue;
171
+ textColor?: IColorValue;
172
+ autoFocus?: boolean;
173
+ disableBackButtonOverride?: boolean;
174
+ inputType?: string;
175
+ hintTextColor?: IColorValue;
176
+ headerIconColor?: IColorValue;
177
+ shouldShowHintSearchIcon?: boolean;
178
+ onChangeText?: (text: string) => void;
179
+ onFocus?: () => void;
180
+ onBlur?: () => void;
181
+ onCancelButtonPress?: () => void;
182
+ onSearchButtonPress?: (text: string) => void;
183
+ // Android only, per react-native-screens' own SearchBarProps comment.
184
+ onClose?: () => void;
185
+ onOpen?: () => void;
186
+ };
187
+
188
+ export type IScreenOrientation =
189
+ | 'default'
190
+ | 'all'
191
+ | 'portrait'
192
+ | 'portrait_up'
193
+ | 'portrait_down'
194
+ | 'landscape'
195
+ | 'landscape_left'
196
+ | 'landscape_right';
197
+
198
+ // The agnostic per-screen options surface: header title/appearance, transition tuning, sheet
199
+ // detents (formSheet/pageSheet), header bar-button items, the search bar, and the
200
+ // translucent/status-bar family. The gamma-line stack host remains deferred - see packages/
201
+ // navigation's README for the explicit split. `headerSearchBarOptions` folds through
202
+ // resolveSearchBarView/resolveSearchBarProps into a SEPARATE RNSSearchBar leaf, not into this
203
+ // record's own native view - see render-stack.ts.
204
+ export interface IScreenOptions {
205
+ title?: string;
206
+ headerShown?: boolean;
207
+ headerTitleColor?: IColorValue;
208
+ headerStyle?: { backgroundColor?: IColorValue };
209
+ headerTintColor?: IColorValue;
210
+ headerBackTitle?: string;
211
+ headerBackButtonDisplayMode?: IHeaderBackButtonDisplayMode;
212
+ headerLargeTitle?: boolean;
213
+ // react-native-screens tracks the large-title (scroll-edge) appearance SEPARATELY from the
214
+ // compact/collapsed one - headerStyle.backgroundColor only colors the latter. Left unset with
215
+ // headerLargeTitle: true, the expanded state falls back to the system default (white), which
216
+ // reads as a stray white band against a dark theme. Naming mirrors @react-navigation/
217
+ // native-stack's own headerLargeStyle for the same prop.
218
+ headerLargeStyle?: { backgroundColor?: IColorValue };
219
+ headerUserInterfaceStyle?: IHeaderUserInterfaceStyle;
220
+ headerTranslucent?: boolean;
221
+ headerLeftBarButtonItems?: IHeaderBarButtonItem[];
222
+ headerRightBarButtonItems?: IHeaderBarButtonItem[];
223
+ headerSearchBarOptions?: ISearchBarOptions;
224
+ gestureEnabled?: boolean;
225
+ stackAnimation?: IStackAnimation;
226
+ stackPresentation?: IStackPresentation;
227
+ transitionDuration?: number;
228
+ sheetAllowedDetents?: ISheetAllowedDetents;
229
+ sheetLargestUndimmedDetentIndex?: ISheetLargestUndimmedDetent;
230
+ sheetInitialDetentIndex?: ISheetInitialDetent;
231
+ sheetGrabberVisible?: boolean;
232
+ sheetCornerRadius?: number;
233
+ sheetExpandsWhenScrolledToEdge?: boolean;
234
+ sheetElevation?: number;
235
+ sheetShouldOverflowTopInset?: boolean;
236
+ sheetDefaultResizeAnimationEnabled?: boolean;
237
+ statusBarStyle?: 'inverted' | 'auto' | 'light' | 'dark';
238
+ statusBarHidden?: boolean;
239
+ statusBarAnimation?: 'none' | 'fade' | 'slide';
240
+ screenOrientation?: IScreenOrientation;
241
+ }
242
+
243
+ // The per-platform piece the render needs, matching ISliderPlatform's shape: a default header
244
+ // tint the host platform normally applies natively, kept explicit here so the render stays
245
+ // platform-invariant (no Platform.OS read in core).
246
+ export type INavigatorPlatform = {
247
+ defaultHeaderBackTitleVisible: boolean;
248
+ };
249
+
250
+ // Pre-resolved inputs the RNSScreen native render paints from. Only fields the fold actually
251
+ // computes are explicit (screenId, activityState, the resolved options); everything else - the
252
+ // native lifecycle/back-button event handlers - rides in `passthrough`, same convention as
253
+ // ISliderViewProps.
254
+ export type IScreenViewProps = {
255
+ screenId: string;
256
+ activityState: number;
257
+ gestureEnabled?: boolean;
258
+ stackAnimation?: IStackAnimation;
259
+ stackPresentation?: IStackPresentation;
260
+ transitionDuration?: number;
261
+ sheetAllowedDetents?: number[];
262
+ sheetLargestUndimmedDetent?: number;
263
+ sheetInitialDetent?: number;
264
+ sheetGrabberVisible?: boolean;
265
+ sheetCornerRadius?: number;
266
+ sheetExpandsWhenScrolledToEdge?: boolean;
267
+ sheetElevation?: number;
268
+ sheetShouldOverflowTopInset?: boolean;
269
+ sheetDefaultResizeAnimationEnabled?: boolean;
270
+ statusBarStyle?: 'inverted' | 'auto' | 'light' | 'dark';
271
+ statusBarHidden?: boolean;
272
+ statusBarAnimation?: 'none' | 'fade' | 'slide';
273
+ screenOrientation?: IScreenOrientation;
274
+ passthrough: Record<string, unknown>;
275
+ };
276
+
277
+ export type IHeaderConfigViewProps = {
278
+ title?: string;
279
+ hidden: boolean;
280
+ backTitle?: string;
281
+ backTitleVisible: boolean;
282
+ backButtonDisplayMode?: IHeaderBackButtonDisplayMode;
283
+ largeTitle?: boolean;
284
+ translucent?: boolean;
285
+ color?: IColorValue;
286
+ titleColor?: IColorValue;
287
+ backgroundColor?: IColorValue;
288
+ largeTitleBackgroundColor?: IColorValue;
289
+ userInterfaceStyle?: IHeaderUserInterfaceStyle;
290
+ // Already native-shaped (buttonId/menuId-tagged, colors run through processColor) - the fold
291
+ // that builds these lives in header-bar-buttons.ts, mirroring RNS's own prepareHeaderBarButtonItems.
292
+ headerLeftBarButtonItems?: unknown[];
293
+ headerRightBarButtonItems?: unknown[];
294
+ onPressHeaderBarButtonItem?: (event: ISymbioteEvent) => void;
295
+ onPressHeaderBarButtonMenuItem?: (event: ISymbioteEvent) => void;
296
+ passthrough: Record<string, unknown>;
297
+ };
298
+
299
+ export type IStackViewProps = {
300
+ passthrough: Record<string, unknown>;
301
+ };
302
+
303
+ // Pre-resolved inputs the RNSSearchBar native leaf paints from, mirroring IScreenViewProps'
304
+ // shape: derived from ISearchBarOptions since every static config field is identical - only the
305
+ // two boolean fields the native prop processor needs to see resolved (obscureBackground/
306
+ // hideNavigationBar) and the event callbacks (which ride in `passthrough`, adapter-supplied,
307
+ // instead of being called directly here) differ.
308
+ export type ISearchBarViewProps = Omit<
309
+ ISearchBarOptions,
310
+ | 'obscureBackground'
311
+ | 'hideNavigationBar'
312
+ | 'onChangeText'
313
+ | 'onFocus'
314
+ | 'onBlur'
315
+ | 'onCancelButtonPress'
316
+ | 'onSearchButtonPress'
317
+ | 'onClose'
318
+ | 'onOpen'
319
+ > & {
320
+ obscureBackground?: IOptionalBooleanNativeProp;
321
+ hideNavigationBar?: IOptionalBooleanNativeProp;
322
+ passthrough: Record<string, unknown>;
323
+ };
@@ -0,0 +1,112 @@
1
+ // Navigator: the logic half (framework-agnostic, zero render). A pure reducer over a route
2
+ // stack - push/pop/popToTop/popTo/replace - mirroring what @react-navigation/native-stack keeps
3
+ // in its router, minus the React-specific action-creator/linking machinery. Route identity
4
+ // (`key`) is generated by the CALLER (the adapter, via React's useId or an equivalent) - the
5
+ // reducer never invents identity itself, so it stays a pure (state, action) => state function.
6
+
7
+ import { SCREEN_ACTIVITY_STATE_FOCUSED, SCREEN_ACTIVITY_STATE_INACTIVE } from '../constants';
8
+ import { mergeParams } from '../guards';
9
+
10
+ export type IRoute<TParams = undefined> = Readonly<{
11
+ key: string;
12
+ name: string;
13
+ params: TParams;
14
+ }>;
15
+
16
+ type IRouteEntry = IRoute<unknown>;
17
+
18
+ export type INavigatorState = Readonly<{
19
+ routes: readonly IRouteEntry[];
20
+ }>;
21
+
22
+ export type INavigatorAction =
23
+ | { type: 'push'; route: IRouteEntry }
24
+ | { type: 'pop'; count?: number }
25
+ | { type: 'popToTop' }
26
+ | { type: 'popTo'; key: string }
27
+ | { type: 'replace'; route: IRouteEntry }
28
+ | { type: 'setParams'; key?: string; params: unknown }
29
+ | { type: 'reset'; state: INavigatorState };
30
+
31
+ export function createInitialNavigatorState(initialRoute: IRouteEntry): INavigatorState {
32
+ return { routes: [initialRoute] };
33
+ }
34
+
35
+ // The stack never pops its last route - mirrors the library refusing to pop the initial screen;
36
+ // the caller (e.g. a hardware back handler) decides what a pop-at-root means for the host app.
37
+ export function navigatorReducer(
38
+ state: INavigatorState,
39
+ action: INavigatorAction,
40
+ ): INavigatorState {
41
+ switch (action.type) {
42
+ case 'push':
43
+ return { routes: [...state.routes, action.route] };
44
+
45
+ case 'pop': {
46
+ if (state.routes.length <= 1) return state;
47
+ const count = action.count ?? 1;
48
+ const nextLength = Math.max(1, state.routes.length - count);
49
+ return { routes: state.routes.slice(0, nextLength) };
50
+ }
51
+
52
+ case 'popToTop':
53
+ return state.routes.length <= 1 ? state : { routes: state.routes.slice(0, 1) };
54
+
55
+ case 'popTo': {
56
+ const index = state.routes.findIndex(route => route.key === action.key);
57
+ if (index === -1) return state;
58
+ return { routes: state.routes.slice(0, index + 1) };
59
+ }
60
+
61
+ case 'replace': {
62
+ if (state.routes.length === 0) return { routes: [action.route] };
63
+ return { routes: [...state.routes.slice(0, -1), action.route] };
64
+ }
65
+
66
+ // Mirrors @react-navigation's CommonActions.setParams: merges onto the route matched by
67
+ // `key`, defaulting to the focused (top-of-stack) route when omitted - same shape as its
68
+ // `source`-defaults-to-focused-route behavior, minus the cross-navigator target routing this
69
+ // single-navigator reducer has no need for.
70
+ case 'setParams': {
71
+ const targetKey = action.key ?? state.routes[state.routes.length - 1]?.key;
72
+ if (targetKey === undefined) return state;
73
+ const index = state.routes.findIndex(route => route.key === targetKey);
74
+ if (index === -1) return state;
75
+ const target = state.routes[index];
76
+ const nextRoute: IRouteEntry = {
77
+ ...target,
78
+ params: mergeParams(target.params, action.params),
79
+ };
80
+ return {
81
+ routes: [...state.routes.slice(0, index), nextRoute, ...state.routes.slice(index + 1)],
82
+ };
83
+ }
84
+
85
+ // Mirrors @react-navigation's CommonActions.reset / BaseRouter's RESET handler: the payload
86
+ // state replaces the current one verbatim, no merge - full rehydration (e.g. restoring a
87
+ // persisted stack) is just a reset with the deserialized state as the payload.
88
+ case 'reset':
89
+ return action.state;
90
+
91
+ default:
92
+ return state;
93
+ }
94
+ }
95
+
96
+ // Mirrors @react-navigation/native-stack's actual algorithm (NativeStackView.native.tsx:
97
+ // `activityState={isInactive ? 0 : 2}`, where isInactive = index > state.index) - NOT a
98
+ // three-way top/one-below/rest split. A route index beyond the focused one only exists for a
99
+ // preloaded-but-not-yet-navigated-to screen, a feature this reducer doesn't implement, so the
100
+ // focused index is always routesLength - 1 (the last route) and every currently-mounted route is
101
+ // FOCUSED. This is required, not just simpler: react-native-screens' native RNSScreen.mm asserts
102
+ // an already-mounted NativeStack screen's activityState can never decrease via a plain prop
103
+ // update ("activityState can only progress in NativeStack") - since no mounted route's index ever
104
+ // exceeds routesLength - 1, this formula never produces a decrease across a push or pop.
105
+ export function computeActivityState(index: number, routesLength: number): number {
106
+ const focusedIndex = routesLength - 1;
107
+ return index > focusedIndex ? SCREEN_ACTIVITY_STATE_INACTIVE : SCREEN_ACTIVITY_STATE_FOCUSED;
108
+ }
109
+
110
+ export function isTopRoute(index: number, routesLength: number): boolean {
111
+ return index === routesLength - 1;
112
+ }
@@ -0,0 +1,80 @@
1
+ // Co-located unit test (ADR 0025) for the pure route-stack reducer, covering setParams and reset
2
+ // (the react-navigation StackRouter parity pieces) alongside the existing action shapes they sit
3
+ // next to. Push/pop/popToTop/popTo/replace are exercised end-to-end through the React lifecycle
4
+ // in stack.test.tsx already - this file targets navigatorReducer directly, framework-free.
5
+
6
+ import { describe, expect, it } from 'vitest';
7
+ import { navigatorReducer } from './index';
8
+ import type { INavigatorState } from './index';
9
+
10
+ const HOME = { key: 'home-1', name: 'Home', params: { tab: 'feed' } };
11
+ const DETAILS = { key: 'details-1', name: 'Details', params: { id: 1 } };
12
+
13
+ function twoRouteState(): INavigatorState {
14
+ return { routes: [HOME, DETAILS] };
15
+ }
16
+
17
+ describe('navigatorReducer — setParams', () => {
18
+ it('merges params onto the focused (top) route when no key is given', () => {
19
+ const next = navigatorReducer(twoRouteState(), { type: 'setParams', params: { id: 2 } });
20
+ expect(next.routes).toEqual([HOME, { ...DETAILS, params: { id: 2 } }]);
21
+ });
22
+
23
+ it('merges params onto the route matched by key, not the top route', () => {
24
+ const next = navigatorReducer(twoRouteState(), {
25
+ type: 'setParams',
26
+ key: 'home-1',
27
+ params: { tab: 'search' },
28
+ });
29
+ expect(next.routes).toEqual([{ ...HOME, params: { tab: 'search' } }, DETAILS]);
30
+ });
31
+
32
+ it('shallow-merges, keeping sibling fields the new params omit', () => {
33
+ const state: INavigatorState = {
34
+ routes: [{ key: 'r1', name: 'Home', params: { a: 1, b: 2 } }],
35
+ };
36
+ const next = navigatorReducer(state, { type: 'setParams', params: { b: 3 } });
37
+ expect(next.routes[0].params).toEqual({ a: 1, b: 3 });
38
+ });
39
+
40
+ it('replaces params outright when the existing params are not an object', () => {
41
+ const state: INavigatorState = { routes: [{ key: 'r1', name: 'Home', params: undefined }] };
42
+ const next = navigatorReducer(state, { type: 'setParams', params: { a: 1 } });
43
+ expect(next.routes[0].params).toEqual({ a: 1 });
44
+ });
45
+
46
+ it('leaves state untouched when no route matches the given key', () => {
47
+ const state = twoRouteState();
48
+ const next = navigatorReducer(state, { type: 'setParams', key: 'missing', params: { id: 9 } });
49
+ expect(next).toBe(state);
50
+ });
51
+
52
+ it('does not change route position or identity', () => {
53
+ const next = navigatorReducer(twoRouteState(), {
54
+ type: 'setParams',
55
+ key: 'home-1',
56
+ params: { tab: 'search' },
57
+ });
58
+ expect(next.routes).toHaveLength(2);
59
+ expect(next.routes[0].key).toBe('home-1');
60
+ expect(next.routes[1]).toBe(DETAILS);
61
+ });
62
+ });
63
+
64
+ describe('navigatorReducer — reset', () => {
65
+ it('replaces the whole state verbatim, mirroring CommonActions.reset', () => {
66
+ const nextState: INavigatorState = {
67
+ routes: [{ key: 'settings-1', name: 'Settings', params: undefined }],
68
+ };
69
+ const next = navigatorReducer(twoRouteState(), { type: 'reset', state: nextState });
70
+ expect(next).toBe(nextState);
71
+ });
72
+
73
+ it('supports rehydrating a persisted multi-route state', () => {
74
+ const persisted: INavigatorState = {
75
+ routes: [HOME, DETAILS, { key: 'r3', name: 'Extra', params: undefined }],
76
+ };
77
+ const next = navigatorReducer({ routes: [HOME] }, { type: 'reset', state: persisted });
78
+ expect(next.routes).toHaveLength(3);
79
+ });
80
+ });
@@ -0,0 +1,123 @@
1
+ // Drawer: the render half (framework-agnostic). Like render-stack.ts's screen content, both the
2
+ // drawer panel's content (renderDrawerContent) and the wrapped screen content are arbitrary
3
+ // framework subtrees the adapter owns - so, mirroring render-modal.ts's container-slot precedent,
4
+ // renderDrawer hands back one root Descriptor whose structural children are EMPTY placeholder
5
+ // nodes (`content` / `overlay?` / `panel`) that the adapter fills with real framework children.
6
+ // Paint order (and therefore which slot is present) is drawerType-dependent, so `drawerChildOrder`
7
+ // is exported alongside renderDrawer as the single source of truth the adapter zips its own
8
+ // children against - no adapter re-derives the ordering itself.
9
+ //
10
+ // All positioning here is STATIC (position/top/bottom/side/width) - the animated slide transform
11
+ // and overlay opacity are NOT baked into this Descriptor. They are computed once per drawerType
12
+ // via drawer-options.ts's resolveDrawerGeometry() and then driven per-frame by the adapter's own
13
+ // Animated value (Animated.View), because "how to animate a style" is a framework-lifecycle
14
+ // concern (React: Animated.View; a future Vue adapter: a reactive style binding) - see
15
+ // CLAUDE.md <adapters_stay_thin>.
16
+
17
+ import { el, type IDescriptor } from '@symbiote-native/components';
18
+ import type { IStyleProp, IViewStyle } from '@symbiote-native/engine';
19
+ import {
20
+ isDrawerOverlayVisible,
21
+ resolveDrawerPosition,
22
+ resolveDrawerType,
23
+ resolveDrawerWidth,
24
+ type IDrawerOptions,
25
+ } from './drawer-options';
26
+
27
+ export type IDrawerSlot = 'content' | 'overlay' | 'panel';
28
+
29
+ // front: content, overlay (dims it), panel (paints on top, last-sibling-on-top).
30
+ // back: panel (stationary, behind), content (slides away to reveal it) - no overlay. Both are
31
+ // absolutely positioned, so sibling order here only decides z-stacking, not screen side.
32
+ // slide: panel, overlay, content (both panel and content animate; content stays visually on top).
33
+ // permanent: NOT absolutely positioned (an ordinary flexDirection:'row' sidebar), so sibling
34
+ // order IS the left-to-right screen position - it must follow drawerPosition.
35
+ export function drawerChildOrder(options: IDrawerOptions): readonly IDrawerSlot[] {
36
+ const type = resolveDrawerType(options);
37
+ switch (type) {
38
+ case 'back':
39
+ return ['panel', 'content'];
40
+ case 'slide':
41
+ return ['panel', 'overlay', 'content'];
42
+ case 'permanent':
43
+ return resolveDrawerPosition(options) === 'left'
44
+ ? ['panel', 'content']
45
+ : ['content', 'panel'];
46
+ case 'front':
47
+ default:
48
+ return ['content', 'overlay', 'panel'];
49
+ }
50
+ }
51
+
52
+ export type IDrawerViewProps = {
53
+ overlayColor?: string;
54
+ drawerStyle?: IStyleProp<IViewStyle>;
55
+ contentPassthrough: Record<string, unknown>;
56
+ overlayPassthrough: Record<string, unknown>;
57
+ panelPassthrough: Record<string, unknown>;
58
+ };
59
+
60
+ const ROOT_STYLE: Readonly<IViewStyle> = { flex: 1 };
61
+ const CONTENT_STYLE: Readonly<IViewStyle> = { flex: 1 };
62
+ // Fabric paints later siblings on top; position:absolute + inset:0 is enough for the overlay
63
+ // (its own sibling order, not zIndex, decides whether it sits above the content).
64
+ const OVERLAY_BASE_STYLE: Readonly<IViewStyle> = {
65
+ position: 'absolute',
66
+ top: 0,
67
+ left: 0,
68
+ right: 0,
69
+ bottom: 0,
70
+ };
71
+
72
+ const DRAWER_PANEL_DEFAULT_BACKGROUND_COLOR = 'white';
73
+
74
+ function panelBaseStyle(options: IDrawerOptions): IViewStyle {
75
+ const type = resolveDrawerType(options);
76
+ const width = resolveDrawerWidth(options);
77
+ const side = resolveDrawerPosition(options);
78
+ if (type === 'permanent') {
79
+ // A sidebar: an ordinary flex child, no absolute positioning, no translate needed.
80
+ return { width, backgroundColor: DRAWER_PANEL_DEFAULT_BACKGROUND_COLOR };
81
+ }
82
+ return {
83
+ position: 'absolute',
84
+ top: 0,
85
+ bottom: 0,
86
+ width,
87
+ backgroundColor: DRAWER_PANEL_DEFAULT_BACKGROUND_COLOR,
88
+ [side]: 0,
89
+ };
90
+ }
91
+
92
+ export function renderDrawer(view: IDrawerViewProps, options: IDrawerOptions): IDescriptor {
93
+ const type = resolveDrawerType(options);
94
+ const content = el('symbiote-view', { ...view.contentPassthrough, style: CONTENT_STYLE }, []);
95
+ const panel = el(
96
+ 'symbiote-view',
97
+ { ...view.panelPassthrough, style: [panelBaseStyle(options), view.drawerStyle] },
98
+ [],
99
+ );
100
+
101
+ const slots: Partial<Record<IDrawerSlot, IDescriptor>> = { content, panel };
102
+ if (isDrawerOverlayVisible(options)) {
103
+ slots.overlay = el(
104
+ 'symbiote-view',
105
+ {
106
+ ...view.overlayPassthrough,
107
+ style: [OVERLAY_BASE_STYLE, { backgroundColor: view.overlayColor }],
108
+ },
109
+ [],
110
+ );
111
+ }
112
+
113
+ const children = drawerChildOrder(options).reduce<IDescriptor[]>((acc, slot) => {
114
+ const descriptor = slots[slot];
115
+ if (descriptor !== undefined) acc.push(descriptor);
116
+ return acc;
117
+ }, []);
118
+
119
+ const rootStyle: IViewStyle =
120
+ type === 'permanent' ? { ...ROOT_STYLE, flexDirection: 'row' } : ROOT_STYLE;
121
+
122
+ return el('symbiote-view', { style: rootStyle }, children);
123
+ }