@symbiote-native/navigation 2.0.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/README.md +42 -12
  2. package/build/angular/drawer/index.js +29 -13
  3. package/build/angular/index.d.ts +4 -4
  4. package/build/angular/injectors/inject-navigation.js +1 -1
  5. package/build/angular/navigation-scope.directive.js +1 -1
  6. package/build/angular/search-bar-ref.directive.js +1 -1
  7. package/build/angular/stack/index.d.ts +2 -0
  8. package/build/angular/stack/index.js +43 -9
  9. package/build/angular/tabs/index.d.ts +1 -1
  10. package/build/angular/tabs/index.js +40 -13
  11. package/build/core/drawer-options/index.js +19 -5
  12. package/build/core/drawer-router-state/index.js +8 -2
  13. package/build/core/guards.js +3 -1
  14. package/build/core/header-bar-buttons.js +14 -4
  15. package/build/core/index.d.ts +6 -5
  16. package/build/core/index.js +7 -3
  17. package/build/core/navigator-state/index.js +12 -4
  18. package/build/core/render-drawer.js +4 -1
  19. package/build/core/render-stack.js +13 -4
  20. package/build/core/screen-options.js +1 -1
  21. package/build/core/search-bar-commands.js +1 -1
  22. package/build/core/stack-router-state/index.d.ts +2 -0
  23. package/build/core/stack-router-state/index.js +44 -0
  24. package/build/core/state-persistence/index.js +6 -2
  25. package/build/core/tab-router-state/index.d.ts +1 -0
  26. package/build/core/tab-router-state/index.js +27 -2
  27. package/build/react/drawer/index.js +59 -26
  28. package/build/react/index.d.ts +7 -7
  29. package/build/react/index.js +2 -2
  30. package/build/react/stack/index.js +47 -10
  31. package/build/react/tabs/index.js +36 -12
  32. package/build/solid/drawer/index.d.ts +22 -0
  33. package/build/solid/drawer/index.js +394 -0
  34. package/build/solid/drawer-screen-props.d.ts +13 -0
  35. package/build/solid/drawer-screen-props.js +2 -0
  36. package/build/solid/host.d.ts +2 -0
  37. package/build/solid/host.js +23 -0
  38. package/build/solid/index.d.ts +19 -0
  39. package/build/solid/index.js +24 -0
  40. package/build/solid/linking.d.ts +3 -0
  41. package/build/solid/linking.js +55 -0
  42. package/build/solid/navigation-context.d.ts +13 -0
  43. package/build/solid/navigation-context.js +37 -0
  44. package/build/solid/primitives/create-focus-effect.d.ts +1 -0
  45. package/build/solid/primitives/create-focus-effect.js +30 -0
  46. package/build/solid/primitives/create-is-focused.d.ts +2 -0
  47. package/build/solid/primitives/create-is-focused.js +31 -0
  48. package/build/solid/primitives/create-navigation-state.d.ts +3 -0
  49. package/build/solid/primitives/create-navigation-state.js +30 -0
  50. package/build/solid/primitives/index.d.ts +12 -0
  51. package/build/solid/primitives/index.js +8 -0
  52. package/build/solid/primitives/use-drawer-navigation.d.ts +5 -0
  53. package/build/solid/primitives/use-drawer-navigation.js +15 -0
  54. package/build/solid/primitives/use-navigation.d.ts +8 -0
  55. package/build/solid/primitives/use-navigation.js +23 -0
  56. package/build/solid/primitives/use-route.d.ts +3 -0
  57. package/build/solid/primitives/use-route.js +14 -0
  58. package/build/solid/primitives/use-stack-navigation.d.ts +5 -0
  59. package/build/solid/primitives/use-stack-navigation.js +19 -0
  60. package/build/solid/primitives/use-tab-navigation.d.ts +5 -0
  61. package/build/solid/primitives/use-tab-navigation.js +15 -0
  62. package/build/solid/screen-props.d.ts +19 -0
  63. package/build/solid/screen-props.js +9 -0
  64. package/build/solid/screen-registry.d.ts +31 -0
  65. package/build/solid/screen-registry.js +86 -0
  66. package/build/solid/screen.d.ts +6 -0
  67. package/build/solid/screen.js +69 -0
  68. package/build/solid/stack/index.d.ts +15 -0
  69. package/build/solid/stack/index.js +348 -0
  70. package/build/solid/tab-screen-props.d.ts +13 -0
  71. package/build/solid/tab-screen-props.js +3 -0
  72. package/build/solid/tabs/index.d.ts +14 -0
  73. package/build/solid/tabs/index.js +228 -0
  74. package/build/svelte/attachments.d.ts +5 -0
  75. package/build/svelte/attachments.js +61 -0
  76. package/build/svelte/descriptor-subtree.d.ts +3 -0
  77. package/build/svelte/descriptor-subtree.js +39 -0
  78. package/build/svelte/drawer/drawer-props.d.ts +14 -0
  79. package/build/svelte/drawer/drawer-props.js +3 -0
  80. package/build/svelte/drawer/index.d.ts +10 -0
  81. package/build/svelte/drawer/index.js +6 -0
  82. package/build/svelte/drawer/index.svelte +559 -0
  83. package/build/svelte/drawer/index.svelte.d.ts +10 -0
  84. package/build/svelte/drawer-screen-props.d.ts +13 -0
  85. package/build/svelte/drawer-screen-props.js +4 -0
  86. package/build/svelte/drawer-screen.svelte +25 -0
  87. package/build/svelte/drawer-screen.svelte.d.ts +4 -0
  88. package/build/svelte/index.d.ts +21 -0
  89. package/build/svelte/index.js +20 -0
  90. package/build/svelte/linking.svelte.d.ts +2 -0
  91. package/build/svelte/linking.svelte.js +55 -0
  92. package/build/svelte/navigation-context.d.ts +14 -0
  93. package/build/svelte/navigation-context.js +44 -0
  94. package/build/svelte/navigation-scope.svelte +27 -0
  95. package/build/svelte/navigation-scope.svelte.d.ts +9 -0
  96. package/build/svelte/registry-host.d.ts +1 -0
  97. package/build/svelte/registry-host.js +26 -0
  98. package/build/svelte/runes/index.d.ts +12 -0
  99. package/build/svelte/runes/index.js +12 -0
  100. package/build/svelte/runes/use-drawer-navigation.svelte.d.ts +6 -0
  101. package/build/svelte/runes/use-drawer-navigation.svelte.js +19 -0
  102. package/build/svelte/runes/use-focus-effect.svelte.d.ts +1 -0
  103. package/build/svelte/runes/use-focus-effect.svelte.js +31 -0
  104. package/build/svelte/runes/use-is-focused.svelte.d.ts +3 -0
  105. package/build/svelte/runes/use-is-focused.svelte.js +34 -0
  106. package/build/svelte/runes/use-navigation-state.svelte.d.ts +4 -0
  107. package/build/svelte/runes/use-navigation-state.svelte.js +39 -0
  108. package/build/svelte/runes/use-navigation.svelte.d.ts +9 -0
  109. package/build/svelte/runes/use-navigation.svelte.js +26 -0
  110. package/build/svelte/runes/use-route.svelte.d.ts +4 -0
  111. package/build/svelte/runes/use-route.svelte.js +12 -0
  112. package/build/svelte/runes/use-stack-navigation.svelte.d.ts +6 -0
  113. package/build/svelte/runes/use-stack-navigation.svelte.js +22 -0
  114. package/build/svelte/runes/use-tab-navigation.svelte.d.ts +6 -0
  115. package/build/svelte/runes/use-tab-navigation.svelte.js +19 -0
  116. package/build/svelte/screen-props.d.ts +21 -0
  117. package/build/svelte/screen-props.js +6 -0
  118. package/build/svelte/screen-registry.d.ts +17 -0
  119. package/build/svelte/screen-registry.js +57 -0
  120. package/build/svelte/screen.svelte +28 -0
  121. package/build/svelte/screen.svelte.d.ts +4 -0
  122. package/build/svelte/stack/index.d.ts +14 -0
  123. package/build/svelte/stack/index.js +7 -0
  124. package/build/svelte/stack/index.svelte +261 -0
  125. package/build/svelte/stack/index.svelte.d.ts +15 -0
  126. package/build/svelte/stack/stack-props.d.ts +20 -0
  127. package/build/svelte/stack/stack-props.js +4 -0
  128. package/build/svelte/stack/stack-screen.svelte +205 -0
  129. package/build/svelte/stack/stack-screen.svelte.d.ts +4 -0
  130. package/build/svelte/tab-screen-props.d.ts +13 -0
  131. package/build/svelte/tab-screen-props.js +4 -0
  132. package/build/svelte/tab-screen.svelte +26 -0
  133. package/build/svelte/tab-screen.svelte.d.ts +4 -0
  134. package/build/svelte/tabs/index.d.ts +8 -0
  135. package/build/svelte/tabs/index.js +6 -0
  136. package/build/svelte/tabs/index.svelte +269 -0
  137. package/build/svelte/tabs/index.svelte.d.ts +8 -0
  138. package/build/svelte/tabs/tab-props.d.ts +7 -0
  139. package/build/svelte/tabs/tab-props.js +3 -0
  140. package/build/vue/composables/use-navigation.js +5 -1
  141. package/build/vue/drawer/index.js +36 -13
  142. package/build/vue/index.d.ts +3 -3
  143. package/build/vue/navigation-context.js +1 -1
  144. package/build/vue/stack/index.js +43 -18
  145. package/build/vue/tabs/index.js +65 -39
  146. package/build-ngc/angular/drawer/index.js +40 -18
  147. package/build-ngc/angular/drawer/index.js.map +1 -1
  148. package/build-ngc/angular/drawer-screen.directive.js +3 -3
  149. package/build-ngc/angular/index.d.ts +4 -4
  150. package/build-ngc/angular/index.js.map +1 -1
  151. package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -1
  152. package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -1
  153. package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -1
  154. package/build-ngc/angular/injectors/inject-navigation.js +1 -1
  155. package/build-ngc/angular/injectors/inject-navigation.js.map +1 -1
  156. package/build-ngc/angular/linking.js.map +1 -1
  157. package/build-ngc/angular/navigation-context.service.js +3 -3
  158. package/build-ngc/angular/navigation-context.service.js.map +1 -1
  159. package/build-ngc/angular/navigation-scope.directive.js +4 -4
  160. package/build-ngc/angular/navigation-scope.directive.js.map +1 -1
  161. package/build-ngc/angular/screen.directive.js +3 -3
  162. package/build-ngc/angular/screen.directive.js.map +1 -1
  163. package/build-ngc/angular/search-bar-ref.directive.js +4 -4
  164. package/build-ngc/angular/search-bar-ref.directive.js.map +1 -1
  165. package/build-ngc/angular/stack/index.d.ts +2 -0
  166. package/build-ngc/angular/stack/index.js +52 -14
  167. package/build-ngc/angular/stack/index.js.map +1 -1
  168. package/build-ngc/angular/tab-screen.directive.js +3 -3
  169. package/build-ngc/angular/tab-screen.directive.js.map +1 -1
  170. package/build-ngc/angular/tabs/index.d.ts +1 -1
  171. package/build-ngc/angular/tabs/index.js +43 -16
  172. package/build-ngc/angular/tabs/index.js.map +1 -1
  173. package/build-ngc/core/constants.js.map +1 -1
  174. package/build-ngc/core/drawer-options/index.js +19 -5
  175. package/build-ngc/core/drawer-options/index.js.map +1 -1
  176. package/build-ngc/core/drawer-router-state/index.js +8 -2
  177. package/build-ngc/core/drawer-router-state/index.js.map +1 -1
  178. package/build-ngc/core/guards.js +3 -1
  179. package/build-ngc/core/guards.js.map +1 -1
  180. package/build-ngc/core/header-bar-buttons.js +14 -4
  181. package/build-ngc/core/header-bar-buttons.js.map +1 -1
  182. package/build-ngc/core/index.d.ts +6 -5
  183. package/build-ngc/core/index.js +7 -3
  184. package/build-ngc/core/index.js.map +1 -1
  185. package/build-ngc/core/linking-config/index.js.map +1 -1
  186. package/build-ngc/core/navigation-events/index.js.map +1 -1
  187. package/build-ngc/core/navigator-handles/index.js.map +1 -1
  188. package/build-ngc/core/navigator-state/index.js +12 -4
  189. package/build-ngc/core/navigator-state/index.js.map +1 -1
  190. package/build-ngc/core/render-drawer.js +4 -1
  191. package/build-ngc/core/render-drawer.js.map +1 -1
  192. package/build-ngc/core/render-stack.js +13 -4
  193. package/build-ngc/core/render-stack.js.map +1 -1
  194. package/build-ngc/core/render-tabs.js.map +1 -1
  195. package/build-ngc/core/screen-options.js +1 -1
  196. package/build-ngc/core/screen-options.js.map +1 -1
  197. package/build-ngc/core/search-bar-commands.js +1 -1
  198. package/build-ngc/core/search-bar-commands.js.map +1 -1
  199. package/build-ngc/core/stack-router-state/index.d.ts +2 -0
  200. package/build-ngc/core/stack-router-state/index.js +45 -0
  201. package/build-ngc/core/stack-router-state/index.js.map +1 -0
  202. package/build-ngc/core/state-persistence/index.js +6 -2
  203. package/build-ngc/core/state-persistence/index.js.map +1 -1
  204. package/build-ngc/core/tab-router-state/index.d.ts +1 -0
  205. package/build-ngc/core/tab-router-state/index.js +27 -2
  206. package/build-ngc/core/tab-router-state/index.js.map +1 -1
  207. package/package.json +44 -16
  208. package/src/angular/drawer/index.ts +75 -29
  209. package/src/angular/index.ts +20 -4
  210. package/src/angular/injectors/inject-focus-effect.ts +8 -2
  211. package/src/angular/injectors/inject-is-focused.ts +6 -4
  212. package/src/angular/injectors/inject-navigation-state.ts +7 -4
  213. package/src/angular/injectors/inject-navigation.ts +12 -3
  214. package/src/angular/linking.ts +4 -1
  215. package/src/angular/navigation-context.service.ts +5 -2
  216. package/src/angular/navigation-scope.directive.ts +6 -2
  217. package/src/angular/screen.directive.ts +13 -3
  218. package/src/angular/search-bar-ref.directive.ts +10 -2
  219. package/src/angular/stack/index.ts +91 -24
  220. package/src/angular/tab-screen.directive.ts +3 -1
  221. package/src/angular/tabs/index.ts +54 -16
  222. package/src/core/constants.ts +6 -3
  223. package/src/core/drawer-options/index.ts +40 -13
  224. package/src/core/drawer-router-state/index.ts +11 -3
  225. package/src/core/guards.ts +3 -1
  226. package/src/core/header-bar-buttons.ts +41 -12
  227. package/src/core/index.ts +29 -5
  228. package/src/core/linking-config/index.ts +31 -10
  229. package/src/core/navigation-events/index.ts +8 -2
  230. package/src/core/navigator-handles/index.ts +8 -3
  231. package/src/core/navigator-props.ts +13 -4
  232. package/src/core/navigator-state/index.ts +24 -7
  233. package/src/core/render-drawer.ts +24 -9
  234. package/src/core/render-stack.ts +52 -13
  235. package/src/core/render-tabs.ts +24 -6
  236. package/src/core/screen-options.ts +15 -5
  237. package/src/core/search-bar-commands.ts +12 -3
  238. package/src/core/stack-router-state/index.ts +52 -0
  239. package/src/core/state-persistence/index.ts +13 -3
  240. package/src/core/tab-router-state/index.ts +35 -3
  241. package/src/react/drawer/index.ts +409 -330
  242. package/src/react/drawer-screen.ts +8 -2
  243. package/src/react/hooks/use-focus-effect.ts +8 -2
  244. package/src/react/hooks/use-is-focused.ts +6 -2
  245. package/src/react/hooks/use-navigation.ts +8 -2
  246. package/src/react/index.ts +37 -7
  247. package/src/react/linking.ts +4 -1
  248. package/src/react/navigation-context.ts +6 -2
  249. package/src/react/screen.ts +12 -3
  250. package/src/react/stack/index.ts +297 -220
  251. package/src/react/tab-screen.ts +3 -1
  252. package/src/react/tabs/index.ts +202 -139
  253. package/src/solid/drawer/index.ts +570 -0
  254. package/src/solid/drawer-screen-props.ts +24 -0
  255. package/src/solid/host.ts +29 -0
  256. package/src/solid/index.ts +87 -0
  257. package/src/solid/linking.ts +74 -0
  258. package/src/solid/navigation-context.ts +56 -0
  259. package/src/solid/primitives/create-focus-effect.ts +41 -0
  260. package/src/solid/primitives/create-is-focused.ts +41 -0
  261. package/src/solid/primitives/create-navigation-state.ts +44 -0
  262. package/src/solid/primitives/index.ts +12 -0
  263. package/src/solid/primitives/use-drawer-navigation.ts +25 -0
  264. package/src/solid/primitives/use-navigation.ts +44 -0
  265. package/src/solid/primitives/use-route.ts +18 -0
  266. package/src/solid/primitives/use-stack-navigation.ts +29 -0
  267. package/src/solid/primitives/use-tab-navigation.ts +25 -0
  268. package/src/solid/screen-props.ts +51 -0
  269. package/src/solid/screen-registry.ts +159 -0
  270. package/src/solid/screen.ts +80 -0
  271. package/src/solid/stack/index.ts +528 -0
  272. package/src/solid/tab-screen-props.ts +21 -0
  273. package/src/solid/tabs/index.ts +327 -0
  274. package/src/svelte/attachments.ts +70 -0
  275. package/src/svelte/descriptor-subtree.ts +51 -0
  276. package/src/svelte/drawer/drawer-props.ts +28 -0
  277. package/src/svelte/drawer/index.svelte +559 -0
  278. package/src/svelte/drawer/index.ts +10 -0
  279. package/src/svelte/drawer-screen-props.ts +26 -0
  280. package/src/svelte/drawer-screen.svelte +25 -0
  281. package/src/svelte/fabric-tree.test-helper.ts +95 -0
  282. package/src/svelte/index.ts +83 -0
  283. package/src/svelte/linking.svelte.ts +72 -0
  284. package/src/svelte/navigation-context.ts +62 -0
  285. package/src/svelte/navigation-scope.svelte +27 -0
  286. package/src/svelte/registry-host.ts +26 -0
  287. package/src/svelte/runes/index.ts +17 -0
  288. package/src/svelte/runes/use-drawer-navigation.svelte.ts +31 -0
  289. package/src/svelte/runes/use-focus-effect.svelte.ts +41 -0
  290. package/src/svelte/runes/use-is-focused.svelte.ts +38 -0
  291. package/src/svelte/runes/use-navigation-state.svelte.ts +48 -0
  292. package/src/svelte/runes/use-navigation.svelte.ts +49 -0
  293. package/src/svelte/runes/use-route.svelte.ts +16 -0
  294. package/src/svelte/runes/use-stack-navigation.svelte.ts +34 -0
  295. package/src/svelte/runes/use-tab-navigation.svelte.ts +29 -0
  296. package/src/svelte/screen-props.ts +50 -0
  297. package/src/svelte/screen-registry.ts +98 -0
  298. package/src/svelte/screen.svelte +28 -0
  299. package/src/svelte/stack/index.svelte +261 -0
  300. package/src/svelte/stack/index.ts +11 -0
  301. package/src/svelte/stack/stack-props.ts +31 -0
  302. package/src/svelte/stack/stack-screen.svelte +205 -0
  303. package/src/svelte/svelte-ambient.d.ts +6 -0
  304. package/src/svelte/svelte-compile.test-helper.ts +147 -0
  305. package/src/svelte/tab-screen-props.ts +22 -0
  306. package/src/svelte/tab-screen.svelte +26 -0
  307. package/src/svelte/tabs/index.svelte +269 -0
  308. package/src/svelte/tabs/index.ts +10 -0
  309. package/src/svelte/tabs/tab-props.ts +13 -0
  310. package/src/vue/composables/use-navigation-state.ts +7 -4
  311. package/src/vue/composables/use-navigation.ts +13 -3
  312. package/src/vue/drawer/index.ts +128 -41
  313. package/src/vue/drawer-screen.ts +12 -5
  314. package/src/vue/index.ts +15 -3
  315. package/src/vue/linking.ts +7 -2
  316. package/src/vue/navigation-context.ts +17 -5
  317. package/src/vue/screen.ts +7 -2
  318. package/src/vue/stack/index.ts +108 -43
  319. package/src/vue/tab-screen.ts +3 -1
  320. package/src/vue/tabs/index.ts +109 -68
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  A native stack/tab/drawer navigator for [SymbioteNative](../../README.md), built directly on
4
4
  [`react-native-screens`](https://github.com/software-mansion/react-native-screens)' native view
5
5
  primitives (`RNSScreen`/`RNSScreenStack`/`RNSScreenStackHeaderConfig`/`RNSSearchBar`) — reachable
6
- from **every** adapter: React, Vue, and Angular. Unlike the third-party-view wrappers
6
+ from **every** adapter: React, Vue, Svelte, Solid, and Angular. Unlike the third-party-view wrappers
7
7
  ([`@symbiote-native/slider`](../slider), [`@symbiote-native/splash-screen`](../splash-screen)),
8
8
  there is no upstream React component to route around here at all — `react-navigation`'s own
9
9
  navigator UI is itself React-only (it calls hooks off the React dispatcher), so wrapping it was
@@ -38,14 +38,16 @@ src/
38
38
  │ react-native-screens' own React components)
39
39
  ├── react/ @symbiote-native/navigation/react — Stack/Tab/Drawer + hooks
40
40
  ├── vue/ @symbiote-native/navigation/vue — Stack/Tab/Drawer + composables
41
+ ├── svelte/ @symbiote-native/navigation/svelte — Stack/Tab/Drawer + runes
42
+ ├── solid/ @symbiote-native/navigation/solid — Stack/Tab/Drawer + primitives
41
43
  └── angular/ @symbiote-native/navigation/angular — Stack/Tab/Drawer + directives + inject*
42
44
  ```
43
45
 
44
46
  Each adapter entry imports `../register` first (so every native view's `ViewConfig` is registered
45
47
  before a screen ever mounts), then exposes `Stack`, `Tab`, and `Drawer`. The router/reducer logic
46
48
  and every `react-native-screens` prop fold are written once in `core/` and shared verbatim; each
47
- adapter supplies only its own lifecycle (hooks / composables / `inject*` functions) and the
48
- descriptor bridge.
49
+ adapter supplies only its own lifecycle (hooks / composables / runes / primitives / `inject*`
50
+ functions) and the descriptor bridge.
49
51
 
50
52
  ## Use it
51
53
 
@@ -65,8 +67,16 @@ function App() {
65
67
 
66
68
  return (
67
69
  <Stack ref={setStackHandle} initialRouteName="Menu">
68
- <Stack.Screen name="Menu" component={MenuScreen} options={{ title: 'Navigation Demos' }} />
69
- <Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Details' }} />
70
+ <Stack.Screen
71
+ name="Menu"
72
+ component={MenuScreen}
73
+ options={{ title: 'Navigation Demos' }}
74
+ />
75
+ <Stack.Screen
76
+ name="Details"
77
+ component={DetailsScreen}
78
+ options={{ title: 'Details' }}
79
+ />
70
80
  </Stack>
71
81
  );
72
82
  }
@@ -84,8 +94,16 @@ const stackHandle = ref<INavigatorHandle | null>(null);
84
94
 
85
95
  <template>
86
96
  <Stack ref="stackHandle" initial-route-name="Menu">
87
- <Screen name="Menu" :component="MenuScreen" :options="{ title: 'Navigation Demos' }" />
88
- <Screen name="Details" :component="DetailsScreen" :options="{ title: 'Details' }" />
97
+ <Screen
98
+ name="Menu"
99
+ :component="MenuScreen"
100
+ :options="{ title: 'Navigation Demos' }"
101
+ />
102
+ <Screen
103
+ name="Details"
104
+ :component="DetailsScreen"
105
+ :options="{ title: 'Details' }"
106
+ />
89
107
  </Stack>
90
108
  </template>
91
109
  ```
@@ -100,8 +118,18 @@ import { Stack, ScreenDirective } from '@symbiote-native/navigation/angular';
100
118
  imports: [Stack, ScreenDirective],
101
119
  template: `
102
120
  <Stack #nav initialRouteName="Menu">
103
- <ng-template symbioteScreen name="Menu" [component]="menuScreen" [options]="menuOptions"></ng-template>
104
- <ng-template symbioteScreen name="Details" [component]="detailsScreen" [options]="detailsOptions"></ng-template>
121
+ <ng-template
122
+ symbioteScreen
123
+ name="Menu"
124
+ [component]="menuScreen"
125
+ [options]="menuOptions"
126
+ ></ng-template>
127
+ <ng-template
128
+ symbioteScreen
129
+ name="Details"
130
+ [component]="detailsScreen"
131
+ [options]="detailsOptions"
132
+ ></ng-template>
105
133
  </Stack>
106
134
  `,
107
135
  })
@@ -125,8 +153,10 @@ swipeable drawer navigator (`Drawer`/`Drawer.Screen`, built on `PanResponder`/`A
125
153
  codebase doesn't depend on `react-native-gesture-handler`/`react-native-reanimated` — see
126
154
  [Known gaps](#known-gaps-drawer-parity) below), the full `useNavigation`/`useRoute`/
127
155
  `useIsFocused`/`useFocusEffect`/`useNavigationState` hook family (narrowed per navigator as
128
- `useStackNavigation`/`useTabNavigation`/`useDrawerNavigation`, with Vue composable and Angular
129
- `inject*` twins of all of them), header/search-bar screen options (bar buttons, menus,
156
+ `useStackNavigation`/`useTabNavigation`/`useDrawerNavigation`, with Vue composable, Svelte rune,
157
+ Solid primitive and Angular `inject*` twins of all of them — Solid spells the three that own state
158
+ `createIsFocused`/`createFocusEffect`/`createNavigationState`, since it reserves `use*` for reading
159
+ an existing context), header/search-bar screen options (bar buttons, menus,
130
160
  `formSheet`/modal presentation, `sheetAllowedDetents`), a `resolveRouteFromUrl`/
131
161
  `useLinkingIntegration` deep-linking layer, and `serializeNavigatorState`/
132
162
  `deserializeNavigatorState` for state persistence. See the docs-site navigation section
@@ -153,7 +183,7 @@ horizontal `ScrollView` hijacking the swipe), `useDrawerProgress` as a UI-thread
153
183
  ## Test it
154
184
 
155
185
  Headless tests live next to each adapter entry and the shared core
156
- (`src/{core,react,vue,angular}/**/*.test.{ts,tsx}`) and drive the same reducers/prop folds every
186
+ (`src/{core,react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`) and drive the same reducers/prop folds every
157
187
  adapter shares, plus per-adapter component tests against a fake `nativeFabricUIManager` slot.
158
188
  Native rendering (the real `RNSScreenStack` push/pop transitions, header/search-bar chrome,
159
189
  `formSheet` detents) is verified on-device (see the parent [README](../../README.md) for the
@@ -92,7 +92,10 @@ let Drawer = (() => {
92
92
  @for (slot of slotOrder(); track slot) {
93
93
  @switch (slot) {
94
94
  @case ('content') {
95
- <AnimatedView [style]="contentStyle()" [animatedProps]="slotAnimatedProps('content')">
95
+ <AnimatedView
96
+ [style]="contentStyle()"
97
+ [animatedProps]="slotAnimatedProps('content')"
98
+ >
96
99
  @if (focusedRoute(); as route) {
97
100
  @if (componentForRoute(route); as component) {
98
101
  <ng-container
@@ -113,7 +116,10 @@ let Drawer = (() => {
113
116
  />
114
117
  }
115
118
  @case ('panel') {
116
- <AnimatedView [style]="panelStyle()" [animatedProps]="slotAnimatedProps('panel')">
119
+ <AnimatedView
120
+ [style]="panelStyle()"
121
+ [animatedProps]="slotAnimatedProps('panel')"
122
+ >
117
123
  @if (drawerContentTemplate) {
118
124
  <ng-container
119
125
  *ngTemplateOutlet="
@@ -214,7 +220,8 @@ let Drawer = (() => {
214
220
  swipeEdgeWidth = (__runInitializers(this, _swipeEnabled_extraInitializers), __runInitializers(this, _swipeEdgeWidth_initializers, void 0));
215
221
  swipeMinDistance = (__runInitializers(this, _swipeEdgeWidth_extraInitializers), __runInitializers(this, _swipeMinDistance_initializers, void 0));
216
222
  swipeMinVelocity = (__runInitializers(this, _swipeMinDistance_extraInitializers), __runInitializers(this, _swipeMinVelocity_initializers, void 0));
217
- windowDimensions = (__runInitializers(this, _swipeMinVelocity_extraInitializers), inject(WindowDimensionsService).dimensions);
223
+ windowDimensions = (__runInitializers(this, _swipeMinVelocity_extraInitializers), inject(WindowDimensionsService)
224
+ .dimensions);
218
225
  routeIdPrefix = `drawer-${(drawerInstanceCounter += 1)}`;
219
226
  // Keyed by name -> the LIVE DrawerScreenDirective instance - see stack.ts's matching comment
220
227
  // for why a snapshot copy would go stale on an in-place `[options]`/`[component]` change.
@@ -243,12 +250,14 @@ let Drawer = (() => {
243
250
  this.dispatch({ type: 'toggleDrawer' });
244
251
  };
245
252
  jumpTo = (name) => {
246
- // Captured BEFORE dispatch, mirroring vue/drawer/index.ts's jumpTo: a signal (like Vue's ref)
247
- // mutates synchronously inside dispatch, so reading isOpen after it would already see the
248
- // reducer's own isOpen: false and never animate the panel closed.
253
+ // Both sides of the dispatch, mirroring vue/drawer/index.ts's jumpTo: an unregistered name is
254
+ // a documented reducer no-op that hands the SAME state back, so animating off the pre-dispatch
255
+ // snapshot alone would slide the panel shut while the router still says isOpen. The signal is
256
+ // set synchronously inside dispatch, so the second read is already the reducer's own answer.
249
257
  const wasOpen = this.stateSignal()?.isOpen ?? false;
250
258
  this.dispatch({ type: 'jumpTo', name });
251
- if (wasOpen)
259
+ const isOpenNow = this.stateSignal()?.isOpen ?? false;
260
+ if (wasOpen && !isOpenNow)
252
261
  this.animateProgressTo(false);
253
262
  };
254
263
  panResponder = PanResponder.create({
@@ -276,9 +285,10 @@ let Drawer = (() => {
276
285
  ngAfterContentInit() {
277
286
  this.rebuildRegistry();
278
287
  this.initializeState();
279
- this.drawerScreenChildrenSubscription = this.drawerScreenChildren.changes.subscribe(() => {
280
- this.rebuildRegistry();
281
- });
288
+ this.drawerScreenChildrenSubscription =
289
+ this.drawerScreenChildren.changes.subscribe(() => {
290
+ this.rebuildRegistry();
291
+ });
282
292
  }
283
293
  ngOnDestroy() {
284
294
  this.drawerScreenChildrenSubscription?.unsubscribe();
@@ -363,7 +373,9 @@ let Drawer = (() => {
363
373
  overlayColor: this.optionsSnapshot().overlayColor ?? DRAWER_DEFAULT_OVERLAY_COLOR,
364
374
  drawerStyle: this.drawerStyleSnapshot(),
365
375
  contentPassthrough: {},
366
- overlayPassthrough: this.isAnimated() ? this.overlayResponderPassthrough() : {},
376
+ overlayPassthrough: this.isAnimated()
377
+ ? this.overlayResponderPassthrough()
378
+ : {},
367
379
  panelPassthrough: {},
368
380
  }, this.optionsSnapshot()));
369
381
  slotsMap = computed(() => {
@@ -398,7 +410,9 @@ let Drawer = (() => {
398
410
  }
399
411
  slotStyle(slot, animatedStyle) {
400
412
  const base = this.slotsMap().get(slot)?.props.style;
401
- return this.isAnimated() ? flattenStyle([base, animatedStyle()]) : flattenStyle(base);
413
+ return this.isAnimated()
414
+ ? flattenStyle([base, animatedStyle()])
415
+ : flattenStyle(base);
402
416
  }
403
417
  contentStyle() {
404
418
  return this.slotStyle('content', () => {
@@ -500,7 +514,9 @@ let Drawer = (() => {
500
514
  navigation: this,
501
515
  };
502
516
  }
503
- return { $implicit: { state: currentState, descriptors, navigation: this } };
517
+ return {
518
+ $implicit: { state: currentState, descriptors, navigation: this },
519
+ };
504
520
  }
505
521
  };
506
522
  return Drawer = _classThis;
@@ -3,7 +3,7 @@ export { Stack } from './stack';
3
3
  export type { INavigatorHandle } from './stack';
4
4
  export { ScreenDirective } from './screen.directive';
5
5
  export type { IAngularScreenOptions, IAngularSearchBarOptions, IScreenOptionsArgs, IScreenOptionsResolver, } from './screen.directive';
6
- export type { IScreenOptions, IStackAnimation, IStackPresentation } from '../core';
6
+ export type { IScreenOptions, IStackAnimation, IStackPresentation, } from '../core';
7
7
  export { injectNavigation, injectStackNavigation, injectTabNavigation, injectDrawerNavigation, injectRoute, injectIsFocused, injectFocusEffect, injectNavigationState, } from './injectors';
8
8
  export type { INavigationHandle, IStackNavigationHandle, ITabNavigationHandle, IDrawerNavigationHandle, IFocusEffectCallback, } from './injectors';
9
9
  export { NavigationContextService } from './navigation-context.service';
@@ -14,10 +14,10 @@ export type { ILinkingConfig, IScreenLinkingConfig } from '../core';
14
14
  export { Tab } from './tabs';
15
15
  export type { ITabNavigatorHandle } from './tabs';
16
16
  export { TabScreenDirective } from './tab-screen.directive';
17
- export type { ITabScreenOptionsArgs, ITabScreenOptionsResolver } from './tab-screen.directive';
17
+ export type { ITabScreenOptionsArgs, ITabScreenOptionsResolver, } from './tab-screen.directive';
18
18
  export type { ITabOptions, ITabBarIcon } from '../core';
19
19
  export { Drawer } from './drawer';
20
- export type { IDrawerNavigatorHandle, IDrawerDescriptorMap, IDrawerContentContext } from './drawer';
20
+ export type { IDrawerNavigatorHandle, IDrawerDescriptorMap, IDrawerContentContext, } from './drawer';
21
21
  export { DrawerScreenDirective } from './drawer-screen.directive';
22
22
  export type { IDrawerScreenOptionsArgs, IDrawerScreenOptionsResolver, } from './drawer-screen.directive';
23
- export type { IDrawerOptions, IDrawerScreenOptions, IDrawerType, IDrawerPosition } from '../core';
23
+ export type { IDrawerOptions, IDrawerScreenOptions, IDrawerType, IDrawerPosition, } from '../core';
@@ -5,7 +5,7 @@
5
5
  // that route's own emitter - mirrors @react-navigation's `navigation.addListener('focus', cb)`
6
6
  // surface. All pub/sub logic lives in ../../core/navigation-events; this function only reads
7
7
  // NavigationContextService and binds identity.
8
- import { requireNavigationContext } from '../navigation-context.service.js';
8
+ import { requireNavigationContext, } from '../navigation-context.service.js';
9
9
  export function injectNavigation() {
10
10
  const context = requireNavigationContext('injectNavigation');
11
11
  return {
@@ -41,7 +41,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
41
41
  return useValue ? value : void 0;
42
42
  };
43
43
  import { Directive, Input, inject } from '@angular/core';
44
- import { NavigationContextService } from './navigation-context.service.js';
44
+ import { NavigationContextService, } from './navigation-context.service.js';
45
45
  let NavigationScopeDirective = (() => {
46
46
  let _classDecorators = [Directive({
47
47
  selector: '[symbioteNavigationScope]',
@@ -40,7 +40,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
40
40
  }
41
41
  return useValue ? value : void 0;
42
42
  };
43
- import { Directive, Input, inject, ElementRef } from '@angular/core';
43
+ import { Directive, Input, inject, ElementRef, } from '@angular/core';
44
44
  import { isSymbioteNode, dlog, debugNodeId } from '@symbiote-native/engine';
45
45
  import { buildSearchBarHandle } from '../core/index.js';
46
46
  let SearchBarRefDirective = (() => {
@@ -32,9 +32,11 @@ export declare class Stack implements AfterContentInit, OnDestroy, INavigatorHan
32
32
  ngAfterContentInit(): void;
33
33
  ngOnDestroy(): void;
34
34
  private rebuildRegistry;
35
+ private reconcileWithRegistry;
35
36
  private initializeState;
36
37
  private createRoute;
37
38
  private dispatch;
39
+ private commitState;
38
40
  emitterFor(routeKey: string): INavigationEmitter;
39
41
  private mergedOptionsFor;
40
42
  componentFor(route: IRoute<unknown>): Type<unknown> | null;
@@ -35,7 +35,7 @@
35
35
  // self-registers instead: `adapters/angular/babel-register-composed.cjs` (a Metro babel preset
36
36
  // applied bundle-wide, not scoped to adapters/angular) scans this package's own AOT-compiled
37
37
  // (`ngc`) `ɵɵngDeclareComponent({selector: 'Stack', ...})` output and auto-calls
38
- // `registerComposedComponent('Stack')` at bundle time - same mechanism `.examples/angular`
38
+ // `registerComposedComponent('Stack')` at bundle time - same mechanism `examples/angular`
39
39
  // navigation-demo screens and `@symbiote-native/slider`'s `Slider` rely on for their own composed
40
40
  // components mounted statically or via `NgComponentOutlet`. Unregistered, `createElement('Stack')`
41
41
  // falls through to a real `createNode` call and RN paints its own "Unimplemented component"
@@ -81,13 +81,15 @@ import { ChangeDetectionStrategy, Component, ContentChildren, Input, NO_ERRORS_S
81
81
  import { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
82
82
  import { SymbioteHostPropsDirective } from '@symbiote-native/angular';
83
83
  import { Platform, dlog } from '@symbiote-native/engine';
84
- import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, NAVIGATION_EVENT_STATE, RNS_MODAL_SCREEN_VIEW_NAME, SCREEN_ON_APPEAR, SCREEN_ON_DISAPPEAR, SCREEN_ON_DISMISSED, SCREEN_ON_HEADER_BACK_BUTTON_CLICKED, STACK_ON_FINISH_TRANSITIONING, buildSearchBarPassthrough, createInitialNavigatorState, createNavigationEmitter, navigatorReducer, resolveHeaderInModalStackStyle, resolveScreenRenderPlan, resolveStackProps, } from '../../core/index.js';
84
+ import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, NAVIGATION_EVENT_STATE, RNS_MODAL_SCREEN_VIEW_NAME, SCREEN_ON_APPEAR, SCREEN_ON_DISAPPEAR, SCREEN_ON_DISMISSED, SCREEN_ON_HEADER_BACK_BUTTON_CLICKED, STACK_ON_FINISH_TRANSITIONING, buildSearchBarPassthrough, createInitialNavigatorState, createNavigationEmitter, navigatorReducer, reconcileStackRoutes, resolveHeaderInModalStackStyle, resolveScreenRenderPlan, resolveStackProps, } from '../../core/index.js';
85
85
  import { NavigationScopeDirective } from '../navigation-scope.directive.js';
86
86
  import { SearchBarRefDirective } from '../search-bar-ref.directive.js';
87
87
  import { ScreenDirective } from '../screen.directive.js';
88
88
  // backTitleVisible defaults to `true` on both platforms per the codegen spec's own default - no
89
89
  // ios/android divergence in v1 scope (mirrors react/stack.ts's own constant exactly).
90
- const NAVIGATOR_PLATFORM = { defaultHeaderBackTitleVisible: true };
90
+ const NAVIGATOR_PLATFORM = {
91
+ defaultHeaderBackTitleVisible: true,
92
+ };
91
93
  let stackInstanceCounter = 0;
92
94
  let Stack = (() => {
93
95
  let _classDecorators = [Component({
@@ -151,7 +153,9 @@ let Stack = (() => {
151
153
  </ng-template>
152
154
 
153
155
  <ng-template #headerAndContentTpl let-route let-index="index">
154
- <RNSScreenStackHeaderConfig [symbioteHostProps]="headerConfigProps(route, index)">
156
+ <RNSScreenStackHeaderConfig
157
+ [symbioteHostProps]="headerConfigProps(route, index)"
158
+ >
155
159
  @if (hasSearchBar(route)) {
156
160
  <RNSScreenStackHeaderSubview [symbioteHostProps]="headerSubviewProps">
157
161
  <RNSSearchBar
@@ -161,7 +165,9 @@ let Stack = (() => {
161
165
  </RNSScreenStackHeaderSubview>
162
166
  }
163
167
  </RNSScreenStackHeaderConfig>
164
- <RNSScreenContentWrapper [symbioteHostProps]="contentWrapperProps(route, index)">
168
+ <RNSScreenContentWrapper
169
+ [symbioteHostProps]="contentWrapperProps(route, index)"
170
+ >
165
171
  <ng-container
166
172
  [symbioteNavigationScope]="route"
167
173
  [navigation]="this"
@@ -246,6 +252,21 @@ let Stack = (() => {
246
252
  for (const screen of this.screenChildren) {
247
253
  this.registry.set(screen.name, screen);
248
254
  }
255
+ this.reconcileWithRegistry();
256
+ }
257
+ // A `<ng-template symbioteScreen>` marker can leave the @ContentChildren query (a marker behind
258
+ // an `@if`, a data-driven screen list) while its route is still in the pushed history, which
259
+ // would leave that entry with nothing for componentFor() to mount (reconcileStackRoutes' header).
260
+ // The signal write lives HERE, in the query-change callback, and never in a computed/template
261
+ // accessor - reconciliation is a reaction to the registry changing, not a derivation of it.
262
+ reconcileWithRegistry() {
263
+ const current = this.stateSignal();
264
+ if (current === undefined)
265
+ return;
266
+ const next = reconcileStackRoutes(current, [...this.registry.keys()]);
267
+ if (next === current)
268
+ return;
269
+ this.commitState(next);
249
270
  }
250
271
  initializeState() {
251
272
  if (this.stateSignal() !== undefined)
@@ -253,20 +274,33 @@ let Stack = (() => {
253
274
  const initialRouteName = this.initialRouteName ?? this.registry.keys().next().value;
254
275
  if (initialRouteName === undefined) {
255
276
  dlog('Stack: no <ng-template symbioteScreen> children registered');
256
- this.stateSignal.set(createInitialNavigatorState({ key: this.routeIdPrefix, name: '', params: undefined }));
277
+ this.stateSignal.set(createInitialNavigatorState({
278
+ key: this.routeIdPrefix,
279
+ name: '',
280
+ params: undefined,
281
+ }));
257
282
  return;
258
283
  }
259
284
  this.stateSignal.set(createInitialNavigatorState(this.createRoute(initialRouteName, this.registry.get(initialRouteName)?.initialParams)));
260
285
  }
261
286
  createRoute(name, params) {
262
287
  this.routeSequence += 1;
263
- return { key: `${this.routeIdPrefix}-${name}-${this.routeSequence}`, name, params };
288
+ return {
289
+ key: `${this.routeIdPrefix}-${name}-${this.routeSequence}`,
290
+ name,
291
+ params,
292
+ };
264
293
  }
265
294
  dispatch(action) {
266
295
  const current = this.stateSignal();
267
296
  if (current === undefined)
268
297
  return;
269
- const next = navigatorReducer(current, action);
298
+ this.commitState(navigatorReducer(current, action));
299
+ }
300
+ // The one write path into stateSignal, shared by a dispatched action and a registry-driven
301
+ // reconciliation: both invalidate the plan cache, broadcast to every still-live route, and prune
302
+ // the emitters of routes that are gone.
303
+ commitState(next) {
270
304
  this.planCache.clear();
271
305
  this.stateSignal.set(next);
272
306
  const liveRouteKeys = new Set(next.routes.map(route => route.key));
@@ -350,7 +384,7 @@ let Stack = (() => {
350
384
  return plan;
351
385
  }
352
386
  outerScreenIsModal(route, index) {
353
- return this.planFor(route, index).screenViewName === RNS_MODAL_SCREEN_VIEW_NAME;
387
+ return (this.planFor(route, index).screenViewName === RNS_MODAL_SCREEN_VIEW_NAME);
354
388
  }
355
389
  isInModal(route, index) {
356
390
  return this.planFor(route, index).inModal;
@@ -32,7 +32,7 @@ export declare class Tab implements AfterContentInit, OnDestroy, ITabNavigatorHa
32
32
  ngOnDestroy(): void;
33
33
  private rebuildRegistry;
34
34
  private routesFromRegistry;
35
- private initializeState;
35
+ private syncRegistry;
36
36
  private dispatch;
37
37
  private resolveTabOptions;
38
38
  focusedRoute(): IRoute<unknown> | undefined;
@@ -53,7 +53,7 @@ import { ChangeDetectionStrategy, Component, ContentChildren, Input, QueryList,
53
53
  import { NgComponentOutlet } from '@angular/common';
54
54
  import { dlog } from '@symbiote-native/engine';
55
55
  import { DescriptorOutlet, View } from '@symbiote-native/angular';
56
- import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, createInitialTabState, createNavigationEmitter, diffFocusedRoute, isFocusedRoute, renderTabBar, tabRouterReducer, } from '../../core/index.js';
56
+ import { NAVIGATION_EVENT_BLUR, NAVIGATION_EVENT_FOCUS, createInitialTabState, createNavigationEmitter, diffFocusedRoute, isFocusedRoute, reconcileTabRoutes, renderTabBar, tabRouterReducer, } from '../../core/index.js';
57
57
  import { NavigationScopeDirective } from '../navigation-scope.directive.js';
58
58
  import { TabScreenDirective } from '../tab-screen.directive.js';
59
59
  const TAB_ROOT_STYLE = { flex: 1 };
@@ -63,7 +63,12 @@ let Tab = (() => {
63
63
  let _classDecorators = [Component({
64
64
  selector: 'Tab',
65
65
  standalone: true,
66
- imports: [NgComponentOutlet, NavigationScopeDirective, DescriptorOutlet, View],
66
+ imports: [
67
+ NgComponentOutlet,
68
+ NavigationScopeDirective,
69
+ DescriptorOutlet,
70
+ View,
71
+ ],
67
72
  changeDetection: ChangeDetectionStrategy.OnPush,
68
73
  template: `
69
74
  <View [style]="rootStyle">
@@ -128,11 +133,11 @@ let Tab = (() => {
128
133
  jumpTo = (name, params) => this.dispatch({ type: 'jumpTo', name, params });
129
134
  setParams = (params, key) => this.dispatch({ type: 'setParams', key, params });
130
135
  ngAfterContentInit() {
131
- this.rebuildRegistry();
132
- this.initializeState();
133
- this.tabScreenChildrenSubscription = this.tabScreenChildren.changes.subscribe(() => {
134
- this.rebuildRegistry();
135
- });
136
+ this.syncRegistry();
137
+ this.tabScreenChildrenSubscription =
138
+ this.tabScreenChildren.changes.subscribe(() => {
139
+ this.syncRegistry();
140
+ });
136
141
  }
137
142
  ngOnDestroy() {
138
143
  this.tabScreenChildrenSubscription?.unsubscribe();
@@ -152,12 +157,26 @@ let Tab = (() => {
152
157
  params: entry.initialParams,
153
158
  }));
154
159
  }
155
- initializeState() {
156
- if (this.stateSignal() !== undefined)
157
- return;
160
+ // A <ng-template symbioteTabScreen> can appear or disappear after mount (a marker behind an
161
+ // @if, a data-driven screen list), so the route list follows the LIVE query instead of staying
162
+ // frozen at whatever ngAfterContentInit first saw: reconcileTabRoutes (core) keeps each
163
+ // surviving route's key and accumulated params and moves focus only when the focused route is
164
+ // the one that left. Runs from the query's own `changes` subscription - an ordinary imperative
165
+ // callback, deliberately not a computed, since this writes the state signal.
166
+ syncRegistry() {
167
+ this.rebuildRegistry();
158
168
  const routes = this.routesFromRegistry();
159
169
  if (routes.length === 0)
160
170
  dlog('Tab: no <ng-template symbioteTabScreen> children registered');
171
+ const current = this.stateSignal();
172
+ if (current !== undefined) {
173
+ this.stateSignal.set(reconcileTabRoutes(current, routes));
174
+ return;
175
+ }
176
+ // Seeding an empty list would resolve initialRouteName against nothing and lose it once the
177
+ // markers do arrive, so the state stays unseeded until at least one has registered.
178
+ if (routes.length === 0)
179
+ return;
161
180
  this.stateSignal.set(createInitialTabState(routes, this.initialRouteName));
162
181
  }
163
182
  dispatch(action) {
@@ -168,7 +187,9 @@ let Tab = (() => {
168
187
  }
169
188
  resolveTabOptions(entry, route) {
170
189
  const props = { route, navigation: this };
171
- const own = typeof entry.options === 'function' ? entry.options(props) : entry.options;
190
+ const own = typeof entry.options === 'function'
191
+ ? entry.options(props)
192
+ : entry.options;
172
193
  return { ...this.screenOptions, ...own };
173
194
  }
174
195
  focusedRoute() {
@@ -251,11 +272,17 @@ let Tab = (() => {
251
272
  };
252
273
  });
253
274
  const focusedRoute = this.focusedRoute();
254
- const focusedEntry = focusedRoute ? this.registry.get(focusedRoute.name) : undefined;
275
+ const focusedEntry = focusedRoute
276
+ ? this.registry.get(focusedRoute.name)
277
+ : undefined;
255
278
  const focusedOptions = focusedEntry && focusedRoute
256
279
  ? this.resolveTabOptions(focusedEntry, focusedRoute)
257
280
  : this.screenOptions;
258
- return renderTabBar({ items, style: focusedOptions?.tabBarStyle, passthrough: {} });
281
+ return renderTabBar({
282
+ items,
283
+ style: focusedOptions?.tabBarStyle,
284
+ passthrough: {},
285
+ });
259
286
  }
260
287
  };
261
288
  return Tab = _classThis;
@@ -85,25 +85,37 @@ export function resolveDrawerSlotInterpolation(geometry, slot) {
85
85
  return {
86
86
  translateX: {
87
87
  inputRange: DRAWER_PROGRESS_INPUT_RANGE,
88
- outputRange: [geometry.contentTranslateXClosed, geometry.contentTranslateXOpen],
88
+ outputRange: [
89
+ geometry.contentTranslateXClosed,
90
+ geometry.contentTranslateXOpen,
91
+ ],
89
92
  },
90
93
  };
91
94
  case 'overlay':
92
95
  return {
93
96
  opacity: {
94
97
  inputRange: DRAWER_PROGRESS_INPUT_RANGE,
95
- outputRange: [geometry.overlayOpacityClosed, geometry.overlayOpacityOpen],
98
+ outputRange: [
99
+ geometry.overlayOpacityClosed,
100
+ geometry.overlayOpacityOpen,
101
+ ],
96
102
  },
97
103
  translateX: {
98
104
  inputRange: DRAWER_PROGRESS_INPUT_RANGE,
99
- outputRange: [geometry.contentTranslateXClosed, geometry.contentTranslateXOpen],
105
+ outputRange: [
106
+ geometry.contentTranslateXClosed,
107
+ geometry.contentTranslateXOpen,
108
+ ],
100
109
  },
101
110
  };
102
111
  case 'panel':
103
112
  return {
104
113
  translateX: {
105
114
  inputRange: DRAWER_PROGRESS_INPUT_RANGE,
106
- outputRange: [geometry.panelTranslateXClosed, geometry.panelTranslateXOpen],
115
+ outputRange: [
116
+ geometry.panelTranslateXClosed,
117
+ geometry.panelTranslateXOpen,
118
+ ],
107
119
  },
108
120
  };
109
121
  }
@@ -154,7 +166,9 @@ export function clamp01(value) {
154
166
  return Math.min(1, Math.max(0, value));
155
167
  }
156
168
  function toFiniteNumber(value) {
157
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
169
+ return typeof value === 'number' && Number.isFinite(value)
170
+ ? value
171
+ : undefined;
158
172
  }
159
173
  // The touch's real starting page-X, read off the raw event rather than gestureState.x0: the
160
174
  // engine's capture phase (core/engine/src/pan-responder/index.ts's
@@ -11,7 +11,11 @@ export function createInitialDrawerRouterState(routes, initialRouteName) {
11
11
  return { routes, index: INITIAL_FOCUSED_INDEX, isOpen: false };
12
12
  }
13
13
  const index = routes.findIndex(route => route.name === initialRouteName);
14
- return { routes, index: index === -1 ? INITIAL_FOCUSED_INDEX : index, isOpen: false };
14
+ return {
15
+ routes,
16
+ index: index === -1 ? INITIAL_FOCUSED_INDEX : index,
17
+ isOpen: false,
18
+ };
15
19
  }
16
20
  // Mirrors @react-navigation/drawer's DrawerActions: jumpTo focuses a route by NAME (TabRouter's
17
21
  // own convention, not the stack's by-key popTo) AND closes the drawer - selecting a destination
@@ -23,7 +27,9 @@ export function drawerRouterReducer(state, action) {
23
27
  const index = state.routes.findIndex(route => route.name === action.name);
24
28
  if (index === -1)
25
29
  return state;
26
- return index === state.index && !state.isOpen ? state : { ...state, index, isOpen: false };
30
+ return index === state.index && !state.isOpen
31
+ ? state
32
+ : { ...state, index, isOpen: false };
27
33
  }
28
34
  case 'openDrawer':
29
35
  return state.isOpen ? state : { ...state, isOpen: true };
@@ -18,5 +18,7 @@ export function isRecord(value) {
18
18
  // navigator-state.ts (Stack) and tab-router-state.ts (Tabs) so the two reducers can't drift on
19
19
  // this rule independently.
20
20
  export function mergeParams(current, incoming) {
21
- return isRecord(current) && isRecord(incoming) ? { ...current, ...incoming } : incoming;
21
+ return isRecord(current) && isRecord(incoming)
22
+ ? { ...current, ...incoming }
23
+ : incoming;
22
24
  }
@@ -21,7 +21,9 @@ function prepareIcon(icon) {
21
21
  case 'imageSource':
22
22
  return { imageSource: imageStatics.resolveAssetSource(icon.imageSource) };
23
23
  case 'templateSource':
24
- return { templateSource: imageStatics.resolveAssetSource(icon.templateSource) };
24
+ return {
25
+ templateSource: imageStatics.resolveAssetSource(icon.templateSource),
26
+ };
25
27
  }
26
28
  }
27
29
  // The one id algorithm both the payload tagger (prepareMenuItems/prepareHeaderBarButtonItems)
@@ -38,7 +40,9 @@ function prepareTitleStyle(titleStyle) {
38
40
  return undefined;
39
41
  return {
40
42
  ...titleStyle,
41
- color: titleStyle.color === undefined ? undefined : processColor(titleStyle.color),
43
+ color: titleStyle.color === undefined
44
+ ? undefined
45
+ : processColor(titleStyle.color),
42
46
  };
43
47
  }
44
48
  function prepareBadge(badge) {
@@ -49,7 +53,9 @@ function prepareBadge(badge) {
49
53
  style: badge.style
50
54
  ? {
51
55
  ...badge.style,
52
- color: badge.style.color === undefined ? undefined : processColor(badge.style.color),
56
+ color: badge.style.color === undefined
57
+ ? undefined
58
+ : processColor(badge.style.color),
53
59
  backgroundColor: badge.style.backgroundColor === undefined
54
60
  ? undefined
55
61
  : processColor(badge.style.backgroundColor),
@@ -88,7 +94,11 @@ function prepareMenuItems(menuLike, index, side, path = '') {
88
94
  const currentPath = path ? `${path}.${menuIndex}` : `${menuIndex}`;
89
95
  const icon = prepareIcon(menuItem.icon);
90
96
  if (menuItem.type === 'submenu') {
91
- return { ...menuItem, ...icon, ...prepareMenuItems(menuItem, index, side, currentPath) };
97
+ return {
98
+ ...menuItem,
99
+ ...icon,
100
+ ...prepareMenuItems(menuItem, index, side, currentPath),
101
+ };
92
102
  }
93
103
  return {
94
104
  ...excludeOnPress(menuItem),