@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,212 @@
1
+ // Header bar-button payload + dispatch: the native-shaped `headerLeftBarButtonItems`/
2
+ // `headerRightBarButtonItems` fold react-native-screens' own ScreenStackHeaderConfig component
3
+ // would send down, plus the buttonId/menuId -> onPress lookup that answers RNSScreenStackHeader-
4
+ // Config's `onPressHeaderBarButtonItem`/`onPressHeaderBarButtonMenuItem` events. Self-contained:
5
+ // only `resolveHeaderConfigView` (screen-options.ts) calls into this file, as a black box - the
6
+ // id-tagging scheme below is this cluster's own internal invariant, never a cross-file contract.
7
+
8
+ import { imageStatics } from '@symbiote-native/components';
9
+ import { processColor } from '@symbiote-native/engine';
10
+ import type { ISymbioteEvent } from '@symbiote-native/engine';
11
+ import type {
12
+ IHeaderBarButtonIcon,
13
+ IHeaderBarButtonItem,
14
+ IHeaderBarButtonItemAction,
15
+ IHeaderBarButtonItemMenu,
16
+ IHeaderBarButtonMenuAction,
17
+ IHeaderBarButtonSubmenu,
18
+ } from './navigator-props';
19
+
20
+ // RNS flattens `icon` into sfSymbolName/xcassetName/imageSource/templateSource at native-payload
21
+ // time (both the structured `icon` field AND the flat native keys reach native - RNS's own
22
+ // prepareHeaderBarButtonItems keeps both), and resolves image assets through the same resolver
23
+ // the Image component uses.
24
+ function prepareIcon(icon: IHeaderBarButtonIcon | undefined): Record<string, unknown> {
25
+ if (!icon) return {};
26
+ switch (icon.type) {
27
+ case 'sfSymbol':
28
+ return { sfSymbolName: icon.name };
29
+ case 'xcasset':
30
+ return { xcassetName: icon.name };
31
+ case 'imageSource':
32
+ return { imageSource: imageStatics.resolveAssetSource(icon.imageSource) };
33
+ case 'templateSource':
34
+ return { templateSource: imageStatics.resolveAssetSource(icon.templateSource) };
35
+ }
36
+ }
37
+
38
+ type ISharedItem = IHeaderBarButtonItemAction | IHeaderBarButtonItemMenu;
39
+
40
+ // The one id algorithm both the payload tagger (prepareMenuItems/prepareHeaderBarButtonItems)
41
+ // and the dispatch-lookup builder (collectMenuHandlers/collectBarButtonHandlers) call - so a
42
+ // change to the id scheme genuinely can't desync payload tagging from dispatch lookup.
43
+ function buildMenuId(path: string, index: number, side: 'left' | 'right'): string {
44
+ return `${path}-${index}-${side}`;
45
+ }
46
+
47
+ function buildButtonId(index: number, side: 'left' | 'right'): string {
48
+ return `${index}-${side}`;
49
+ }
50
+
51
+ function prepareTitleStyle(
52
+ titleStyle: ISharedItem['titleStyle'],
53
+ ): Record<string, unknown> | undefined {
54
+ if (!titleStyle) return undefined;
55
+ return {
56
+ ...titleStyle,
57
+ color: titleStyle.color === undefined ? undefined : processColor(titleStyle.color),
58
+ };
59
+ }
60
+
61
+ function prepareBadge(badge: ISharedItem['badge']): Record<string, unknown> | undefined {
62
+ if (!badge) return undefined;
63
+ return {
64
+ ...badge,
65
+ style: badge.style
66
+ ? {
67
+ ...badge.style,
68
+ color: badge.style.color === undefined ? undefined : processColor(badge.style.color),
69
+ backgroundColor:
70
+ badge.style.backgroundColor === undefined
71
+ ? undefined
72
+ : processColor(badge.style.backgroundColor),
73
+ }
74
+ : undefined,
75
+ };
76
+ }
77
+
78
+ // onPress is captured separately into the buttonId/menuId -> handler map (collectMenuHandlers/
79
+ // collectBarButtonHandlers below) and must never reach native: a function value fails Fabric's
80
+ // dynamic-value serialization, which silently drops the WHOLE headerLeftBarButtonItems/
81
+ // headerRightBarButtonItems array it's nested in - not just the one bad field - so bar buttons and
82
+ // menu actions never reached native at all, despite the buttonId/menuId dispatch wiring itself
83
+ // being entirely correct.
84
+ function excludeOnPress<T extends { onPress: unknown }>(item: T): Omit<T, 'onPress'> {
85
+ const { onPress: _onPress, ...rest } = item;
86
+ return rest;
87
+ }
88
+
89
+ // Shared fields common to the 'button' and 'menu' item variants (title/icon/tint/badge/...) - the
90
+ // 'spacing' variant carries none of these and passes through untouched.
91
+ function prepareSharedFields(
92
+ item: IHeaderBarButtonItem & { type: 'button' | 'menu' },
93
+ ): Record<string, unknown> {
94
+ return {
95
+ ...(item.type === 'button' ? excludeOnPress(item) : item),
96
+ ...prepareIcon(item.icon),
97
+ titleStyle: prepareTitleStyle(item.titleStyle),
98
+ tintColor: item.tintColor === undefined ? undefined : processColor(item.tintColor),
99
+ badge: prepareBadge(item.badge),
100
+ };
101
+ }
102
+
103
+ type IMenuLike = { items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[] };
104
+
105
+ // Recursively tags every menu action with a `menuId` derived from its tree position
106
+ // (`${path}-${index}-${side}`), mirroring RNS's own prepareMenu exactly - the id must match what
107
+ // buildHeaderBarButtonDispatch computes below, or a press silently no-ops.
108
+ function prepareMenuItems<T extends IMenuLike>(
109
+ menuLike: T,
110
+ index: number,
111
+ side: 'left' | 'right',
112
+ path = '',
113
+ ): T {
114
+ return {
115
+ ...menuLike,
116
+ items: menuLike.items.map((menuItem, menuIndex) => {
117
+ const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
118
+ const icon = prepareIcon(menuItem.icon);
119
+ if (menuItem.type === 'submenu') {
120
+ return { ...menuItem, ...icon, ...prepareMenuItems(menuItem, index, side, currentPath) };
121
+ }
122
+ return {
123
+ ...excludeOnPress(menuItem),
124
+ ...icon,
125
+ menuId: buildMenuId(currentPath, index, side),
126
+ };
127
+ }),
128
+ };
129
+ }
130
+
131
+ // Builds the native-shaped payload react-native-screens' own ScreenStackHeaderConfig component
132
+ // would send down (buttonId/menuId-tagged, colors processColor'd) - this is what
133
+ // IHeaderConfigViewProps.headerLeftBarButtonItems/headerRightBarButtonItems actually carry.
134
+ export function prepareHeaderBarButtonItems(
135
+ items: IHeaderBarButtonItem[] | undefined,
136
+ side: 'left' | 'right',
137
+ ): unknown[] | undefined {
138
+ if (!items) return undefined;
139
+ return items.map((item, index) => {
140
+ if (item.type === 'spacing') return item;
141
+ const prepared = prepareSharedFields(item);
142
+ if (item.type === 'button') return { ...prepared, buttonId: buildButtonId(index, side) };
143
+ return { ...prepared, menu: prepareMenuItems(item.menu, index, side) };
144
+ });
145
+ }
146
+
147
+ function collectMenuHandlers(
148
+ items: (IHeaderBarButtonMenuAction | IHeaderBarButtonSubmenu)[],
149
+ index: number,
150
+ side: 'left' | 'right',
151
+ path: string,
152
+ handlers: Map<string, () => void>,
153
+ ): void {
154
+ items.forEach((item, menuIndex) => {
155
+ const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
156
+ if (item.type === 'submenu') {
157
+ collectMenuHandlers(item.items, index, side, currentPath, handlers);
158
+ return;
159
+ }
160
+ handlers.set(buildMenuId(currentPath, index, side), item.onPress);
161
+ });
162
+ }
163
+
164
+ function collectBarButtonHandlers(
165
+ items: IHeaderBarButtonItem[] | undefined,
166
+ side: 'left' | 'right',
167
+ buttonHandlers: Map<string, () => void>,
168
+ menuHandlers: Map<string, () => void>,
169
+ ): void {
170
+ items?.forEach((item, index) => {
171
+ if (item.type === 'button') {
172
+ buttonHandlers.set(buildButtonId(index, side), item.onPress);
173
+ } else if (item.type === 'menu') {
174
+ collectMenuHandlers(item.menu.items, index, side, '', menuHandlers);
175
+ }
176
+ });
177
+ }
178
+
179
+ function readStringField(record: Record<string, unknown>, key: string): string | undefined {
180
+ const value = record[key];
181
+ return typeof value === 'string' ? value : undefined;
182
+ }
183
+
184
+ type IHeaderBarButtonDispatch = {
185
+ onPressHeaderBarButtonItem?: (event: ISymbioteEvent) => void;
186
+ onPressHeaderBarButtonMenuItem?: (event: ISymbioteEvent) => void;
187
+ };
188
+
189
+ // The buttonId/menuId → onPress lookup is built independently from prepareHeaderBarButtonItems'
190
+ // native payload (rather than re-parsing it back out of the `unknown[]` result), over the
191
+ // ORIGINAL typed items - but both sides call the same buildMenuId/buildButtonId, so the id
192
+ // scheme lives in one place and can't desync payload tagging from dispatch lookup.
193
+ export function buildHeaderBarButtonDispatch(
194
+ leftItems: IHeaderBarButtonItem[] | undefined,
195
+ rightItems: IHeaderBarButtonItem[] | undefined,
196
+ ): IHeaderBarButtonDispatch {
197
+ const buttonHandlers = new Map<string, () => void>();
198
+ const menuHandlers = new Map<string, () => void>();
199
+ collectBarButtonHandlers(leftItems, 'left', buttonHandlers, menuHandlers);
200
+ collectBarButtonHandlers(rightItems, 'right', buttonHandlers, menuHandlers);
201
+ if (buttonHandlers.size === 0 && menuHandlers.size === 0) return {};
202
+ return {
203
+ onPressHeaderBarButtonItem: event => {
204
+ const buttonId = readStringField(event.nativeEvent, 'buttonId');
205
+ if (buttonId !== undefined) buttonHandlers.get(buttonId)?.();
206
+ },
207
+ onPressHeaderBarButtonMenuItem: event => {
208
+ const menuId = readStringField(event.nativeEvent, 'menuId');
209
+ if (menuId !== undefined) menuHandlers.get(menuId)?.();
210
+ },
211
+ };
212
+ }
@@ -0,0 +1,170 @@
1
+ // @symbiote-native/navigation (core): the framework-agnostic half of the native stack navigator -
2
+ // a pure route-stack reducer plus the react-native-screens prop folds and native-leaf prop
3
+ // resolvers. symbiote ships zero runtime metadata for RNSScreen/RNSScreenStack/
4
+ // RNSScreenStackHeaderConfig - the engine derives their events and color processors from
5
+ // react-native-screens' own ViewConfig - so this layer is the pure JS every adapter reuses
6
+ // verbatim, supplying only its lifecycle (route-key generation, useReducer/reactive state) and
7
+ // the descriptor bridge.
8
+
9
+ export * from './constants';
10
+
11
+ export {
12
+ createInitialNavigatorState,
13
+ navigatorReducer,
14
+ computeActivityState,
15
+ isTopRoute,
16
+ } from './navigator-state';
17
+ export type { IRoute, INavigatorState, INavigatorAction } from './navigator-state';
18
+
19
+ export type {
20
+ IStackAnimation,
21
+ IStackPresentation,
22
+ IHeaderBackButtonDisplayMode,
23
+ IHeaderUserInterfaceStyle,
24
+ IOptionalBooleanNativeProp,
25
+ ISheetAllowedDetents,
26
+ ISheetLargestUndimmedDetent,
27
+ ISheetInitialDetent,
28
+ IHeaderBarButtonIcon,
29
+ IHeaderBarButtonItemBadge,
30
+ IHeaderBarButtonItemAction,
31
+ IHeaderBarButtonMenuAction,
32
+ IHeaderBarButtonSubmenu,
33
+ IHeaderBarButtonItemMenu,
34
+ IHeaderBarButtonItemSpacing,
35
+ IHeaderBarButtonItem,
36
+ ISearchBarAutoCapitalize,
37
+ ISearchBarPlacement,
38
+ ISearchBarOptions,
39
+ IScreenOrientation,
40
+ IScreenOptions,
41
+ INavigatorPlatform,
42
+ IScreenViewProps,
43
+ IHeaderConfigViewProps,
44
+ IStackViewProps,
45
+ ISearchBarViewProps,
46
+ } from './navigator-props';
47
+
48
+ export { resolveHeaderConfigView, resolveScreenView, resolveSearchBarView } from './screen-options';
49
+
50
+ export { buildSearchBarHandle } from './search-bar-commands';
51
+ export type { ISearchBarCommands } from './search-bar-commands';
52
+
53
+ export {
54
+ resolveScreenProps,
55
+ resolveStackProps,
56
+ renderHeaderConfig,
57
+ resolveSearchBarProps,
58
+ resolveScreenContentWrapperStyle,
59
+ resolveScreenViewName,
60
+ isHeaderInModal,
61
+ resolveHeaderInModalStackStyle,
62
+ resolveHeaderInModalScreenStyle,
63
+ buildSearchBarPassthrough,
64
+ resolveScreenRenderPlan,
65
+ } from './render-stack';
66
+ export type { IScreenRenderPlanInput, IScreenRenderPlan } from './render-stack';
67
+
68
+ export { serializeNavigatorState, deserializeNavigatorState } from './state-persistence';
69
+
70
+ export {
71
+ createNavigationEmitter,
72
+ diffFocusedRoute,
73
+ NAVIGATION_EVENT_FOCUS,
74
+ NAVIGATION_EVENT_BLUR,
75
+ NAVIGATION_EVENT_STATE,
76
+ NAVIGATION_EVENT_BEFORE_REMOVE,
77
+ } from './navigation-events';
78
+ export type {
79
+ INavigationEmitter,
80
+ INavigationEventListener,
81
+ INavigationEventName,
82
+ IFocusTransition,
83
+ } from './navigation-events';
84
+
85
+ // Runtime guards shared across core (and re-exported for adapters narrowing their own untyped
86
+ // inputs - vnode props, gesture/event data, persisted JSON) - see guards.ts's header for which
87
+ // call sites this consolidates and why array-exclusion is the right default everywhere it's used.
88
+ export { isRecord } from './guards';
89
+
90
+ // Bottom-tabs navigator: a FOCUSED-INDEX router (not a stack - see tab-router-state.ts) driving
91
+ // a pure-JS tab bar render, framework-agnostic and shared verbatim by every adapter.
92
+ export { createInitialTabState, tabRouterReducer, isFocusedRoute } from './tab-router-state';
93
+ export type { ITabRouterState, ITabRouterAction } from './tab-router-state';
94
+
95
+ export type { ITabBarIcon, ITabOptions } from './tab-options';
96
+
97
+ export { renderTabBarItem, renderTabBar } from './render-tabs';
98
+ export type { ITabBarItemView, ITabBarViewProps } from './render-tabs';
99
+
100
+ // Linking config: resolves a URL to a route (and back), the piece @react-navigation's
101
+ // NavigationContainer `linking` prop provides on top of the framework-agnostic Linking module.
102
+ export { resolveRouteFromUrl, resolveUrlFromRoute } from './linking-config';
103
+ export type { ILinkingConfig, IScreenLinkingConfig } from './linking-config';
104
+
105
+ // Drawer navigator: an OPEN/CLOSED-flag router over a fixed route list (see
106
+ // drawer-router-state.ts's header for why it isn't a push/pop stack), a pure swipe/geometry math
107
+ // module, and a Descriptor render fn - all framework-agnostic, shared verbatim by every adapter.
108
+ export {
109
+ createInitialDrawerRouterState,
110
+ drawerRouterReducer,
111
+ focusedDrawerRoute,
112
+ } from './drawer-router-state';
113
+ export type { IDrawerRouterState, IDrawerRouterAction } from './drawer-router-state';
114
+
115
+ export type {
116
+ IDrawerType,
117
+ IDrawerPosition,
118
+ IDrawerOptions,
119
+ IDrawerScreenOptions,
120
+ IDrawerGeometry,
121
+ ISwipeIntent,
122
+ } from './drawer-options';
123
+ export {
124
+ DRAWER_DEFAULT_TYPE,
125
+ DRAWER_DEFAULT_POSITION,
126
+ DRAWER_DEFAULT_WIDTH,
127
+ DRAWER_DEFAULT_OVERLAY_COLOR,
128
+ DRAWER_DEFAULT_SWIPE_ENABLED,
129
+ DRAWER_DEFAULT_SWIPE_EDGE_WIDTH,
130
+ DRAWER_DEFAULT_SWIPE_MIN_DISTANCE,
131
+ DRAWER_DEFAULT_SWIPE_MIN_VELOCITY,
132
+ resolveDrawerType,
133
+ resolveDrawerPosition,
134
+ resolveDrawerWidth,
135
+ isDrawerAnimated,
136
+ isDrawerOverlayVisible,
137
+ resolveDrawerGeometry,
138
+ isSwipeStartInEdge,
139
+ isHorizontalDrag,
140
+ resolveSwipeIntent,
141
+ clamp01,
142
+ startPageXOf,
143
+ resolveDragProgress,
144
+ shouldClaimDrawerSwipe,
145
+ resolveDrawerSlotInterpolation,
146
+ } from './drawer-options';
147
+ export type {
148
+ IDrawerInterpolationRange,
149
+ IDrawerContentSlotInterpolation,
150
+ IDrawerOverlaySlotInterpolation,
151
+ IDrawerPanelSlotInterpolation,
152
+ } from './drawer-options';
153
+
154
+ export { renderDrawer, drawerChildOrder } from './render-drawer';
155
+ export type { IDrawerSlot, IDrawerViewProps } from './render-drawer';
156
+
157
+ // Imperative navigator handles (Stack/Tab/Drawer): framework-agnostic, declared once here and
158
+ // re-exported verbatim by every adapter (see navigator-handles.ts's header).
159
+ export type {
160
+ INavigatorHandle,
161
+ ITabNavigatorHandle,
162
+ IDrawerNavigatorHandle,
163
+ IDrawerDescriptorMap,
164
+ IAnyNavigatorHandle,
165
+ } from './navigator-handles';
166
+ export {
167
+ isStackNavigatorHandle,
168
+ isTabNavigatorHandle,
169
+ isDrawerNavigatorHandle,
170
+ } from './navigator-handles';
@@ -0,0 +1,209 @@
1
+ // Linking config: the piece @react-navigation's `NavigationContainer`'s `linking` prop provides
2
+ // on top of the framework-agnostic `Linking` module (core/engine/src/linking) - resolving a URL
3
+ // ('myapp://user/42', '/user/42') to a route, and a route back to a URL. This is OUR OWN type,
4
+ // not imported from react-navigation, kept close to its shape (`prefixes` + `config.screens`)
5
+ // only so the DX is familiar.
6
+ //
7
+ // Why hand-rolled matching instead of react-router's `matchPath`/`generatePath` (evaluated per
8
+ // task): react-router 8's package has no subpath export for the pure `lib/router/utils.ts`
9
+ // matcher - its only general entry point (`.`) eagerly imports `./lib/dom/*`
10
+ // (BrowserRouter/ScrollRestoration/cookies) and `./lib/server-runtime/*`, code that assumes DOM
11
+ // and Node globals a Metro/Hermes RN bundle doesn't have; its `peerDependencies` also pin
12
+ // `react-dom`, which this DOM-free monorepo never installs (see CLAUDE.md
13
+ // react_native_is_an_explicit_top_level_peer - no foreign runtime singleton gets smuggled in).
14
+ // On top of the bundling risk, `matchPath`'s/`generatePath`'s param-name extraction is a
15
+ // template-literal-type trick that only fires for a compile-time LITERAL path string; our
16
+ // patterns come from a runtime config object (`Path` widens to plain `string`), so the generic
17
+ // degrades to an empty params type and using the result would force an `as` cast - forbidden by
18
+ // this project's TS conventions. A minimal `:param`-segment matcher sidesteps both problems and
19
+ // is the right size for a single flat Stack (no optional/splat segments - no nested-navigator use
20
+ // for them yet).
21
+
22
+ import { dlog } from '@symbiote-native/engine';
23
+ import type { IRoute } from '../navigator-state';
24
+ import { isRecord } from '../guards';
25
+
26
+ export type IScreenLinkingConfig =
27
+ | string
28
+ | {
29
+ path?: string;
30
+ screens?: Record<string, IScreenLinkingConfig>;
31
+ };
32
+
33
+ export type ILinkingConfig = {
34
+ prefixes: string[];
35
+ config: {
36
+ screens: Record<string, IScreenLinkingConfig>;
37
+ };
38
+ };
39
+
40
+ type IFlatRoutePattern = {
41
+ name: string;
42
+ pattern: string;
43
+ };
44
+
45
+ // Strips leading/trailing slashes so segments join predictably regardless of how the caller
46
+ // wrote a path ('feed/:sort', '/feed/:sort/', etc).
47
+ function normalizeSegment(segment: string): string {
48
+ return segment.replace(/^\/+|\/+$/g, '');
49
+ }
50
+
51
+ function joinPath(parent: string, child: string): string {
52
+ const parts = [normalizeSegment(parent), normalizeSegment(child)].filter(part => part.length > 0);
53
+ return parts.join('/');
54
+ }
55
+
56
+ // Walks `screens` recursively, accumulating the path down to each LEAF screen. Unlike
57
+ // react-navigation (which resolves nested config into nested navigation state), our navigator is
58
+ // a single flat Stack - a `screens` group with no `path` of its own is transparent (consumes no
59
+ // URL segment); a group WITH a `path` but no nested `screens` is itself a leaf using that path.
60
+ function flattenScreens(
61
+ screens: Record<string, IScreenLinkingConfig>,
62
+ parentPath: string,
63
+ out: IFlatRoutePattern[],
64
+ ): IFlatRoutePattern[] {
65
+ for (const [name, entry] of Object.entries(screens)) {
66
+ if (typeof entry === 'string') {
67
+ out.push({ name, pattern: joinPath(parentPath, entry) });
68
+ continue;
69
+ }
70
+
71
+ const nextParent = entry.path !== undefined ? joinPath(parentPath, entry.path) : parentPath;
72
+
73
+ if (entry.screens !== undefined) {
74
+ flattenScreens(entry.screens, nextParent, out);
75
+ } else if (entry.path !== undefined) {
76
+ out.push({ name, pattern: nextParent });
77
+ } else {
78
+ dlog(`linking-config: screen "${name}" has neither a path nor nested screens, skipping`);
79
+ }
80
+ }
81
+ return out;
82
+ }
83
+
84
+ function dynamicSegmentCount(pattern: string): number {
85
+ if (pattern.length === 0) return 0;
86
+ return pattern.split('/').filter(segment => segment.startsWith(':')).length;
87
+ }
88
+
89
+ function segmentCount(pattern: string): number {
90
+ return pattern.length === 0 ? 0 : pattern.split('/').length;
91
+ }
92
+
93
+ // More static segments should win over a param that would also match (e.g. a literal
94
+ // '/user/me' pattern over '/user/:id'), mirroring how react-navigation prefers exact matches.
95
+ function bySpecificity(a: IFlatRoutePattern, b: IFlatRoutePattern): number {
96
+ const dynamicDiff = dynamicSegmentCount(a.pattern) - dynamicSegmentCount(b.pattern);
97
+ if (dynamicDiff !== 0) return dynamicDiff;
98
+ return segmentCount(b.pattern) - segmentCount(a.pattern);
99
+ }
100
+
101
+ function matchPattern(pattern: string, pathname: string): Record<string, string> | null {
102
+ const patternSegments = pattern.length === 0 ? [] : pattern.split('/');
103
+ const pathSegments = pathname.length === 0 ? [] : pathname.split('/');
104
+ if (patternSegments.length !== pathSegments.length) return null;
105
+
106
+ const params: Record<string, string> = {};
107
+ for (let index = 0; index < patternSegments.length; index += 1) {
108
+ const patternSegment = patternSegments[index];
109
+ const pathSegment = pathSegments[index];
110
+ if (patternSegment.startsWith(':')) {
111
+ params[patternSegment.slice(1)] = decodeURIComponent(pathSegment);
112
+ } else if (patternSegment !== pathSegment) {
113
+ return null;
114
+ }
115
+ }
116
+ return params;
117
+ }
118
+
119
+ function stripQueryAndHash(url: string): string {
120
+ const match = /[?#]/.exec(url);
121
+ return match === null ? url : url.slice(0, match.index);
122
+ }
123
+
124
+ // Resolves a full URL down to the bare path segment string ('user/42', no leading slash) by
125
+ // stripping the longest matching configured prefix, falling back to treating the URL as an
126
+ // already-bare path when it starts with '/' (the task's second example form). Returns null when
127
+ // neither applies - an unrecognized scheme/host, not "no route matched".
128
+ function extractPathname(config: ILinkingConfig, url: string): string | null {
129
+ const withoutQuery = stripQueryAndHash(url);
130
+ const sortedPrefixes = [...config.prefixes].sort((a, b) => b.length - a.length);
131
+ for (const prefix of sortedPrefixes) {
132
+ if (withoutQuery.startsWith(prefix)) {
133
+ return normalizeSegment(withoutQuery.slice(prefix.length));
134
+ }
135
+ }
136
+ if (withoutQuery.startsWith('/')) return normalizeSegment(withoutQuery);
137
+ return null;
138
+ }
139
+
140
+ export function resolveRouteFromUrl(config: ILinkingConfig, url: string): IRoute<unknown> | null {
141
+ const pathname = extractPathname(config, url);
142
+ if (pathname === null) {
143
+ dlog(`linking-config: url "${url}" matched no configured prefix`);
144
+ return null;
145
+ }
146
+
147
+ const candidates = flattenScreens(config.config.screens, '', []).sort(bySpecificity);
148
+ for (const candidate of candidates) {
149
+ const params = matchPattern(candidate.pattern, pathname);
150
+ if (params !== null) {
151
+ dlog(`linking-config: resolved "${url}" -> ${candidate.name}`);
152
+ // `key` is not real route identity here - the navigator mints its own on push/replace
153
+ // (stack.ts's createRoute); `name` is a stable enough placeholder to satisfy IRoute's shape.
154
+ return {
155
+ key: candidate.name,
156
+ name: candidate.name,
157
+ params: Object.keys(params).length > 0 ? params : undefined,
158
+ };
159
+ }
160
+ }
161
+
162
+ dlog(`linking-config: url "${url}" (path "${pathname}") matched no configured screen`);
163
+ return null;
164
+ }
165
+
166
+ // The inverse of matchPattern: fills a pattern's ':param' segments from `params`, or returns
167
+ // null when a required param is missing (mirrors react-router's generatePath throwing, minus the
168
+ // throw - a resolver returning null reads more naturally at the call site here).
169
+ function fillPattern(pattern: string, params: unknown): string | null {
170
+ if (pattern.length === 0) return '';
171
+ const source = isRecord(params) ? params : {};
172
+ const segments: string[] = [];
173
+ for (const segment of pattern.split('/')) {
174
+ if (!segment.startsWith(':')) {
175
+ segments.push(segment);
176
+ continue;
177
+ }
178
+ const value = source[segment.slice(1)];
179
+ if (value === undefined || value === null) return null;
180
+ segments.push(encodeURIComponent(String(value)));
181
+ }
182
+ return segments.join('/');
183
+ }
184
+
185
+ export function resolveUrlFromRoute(config: ILinkingConfig, route: IRoute<unknown>): string | null {
186
+ const candidate = flattenScreens(config.config.screens, '', []).find(
187
+ entry => entry.name === route.name,
188
+ );
189
+ if (candidate === undefined) {
190
+ dlog(`linking-config: no configured screen for route name "${route.name}"`);
191
+ return null;
192
+ }
193
+
194
+ const path = fillPattern(candidate.pattern, route.params);
195
+ if (path === null) {
196
+ dlog(
197
+ `linking-config: route "${route.name}" is missing a param required by "${candidate.pattern}"`,
198
+ );
199
+ return null;
200
+ }
201
+
202
+ const prefix = config.prefixes[0];
203
+ if (prefix === undefined) return path.length > 0 ? `/${path}` : '/';
204
+
205
+ // A prefix already carrying its own trailing separator ('myapp://') must not be truncated to
206
+ // 'myapp:/' by naively slicing one char off - only add a '/' when the prefix doesn't have one.
207
+ if (path.length === 0) return prefix;
208
+ return prefix.endsWith('/') ? `${prefix}${path}` : `${prefix}/${path}`;
209
+ }