@symbiote-native/navigation 2.1.0 → 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 (234) hide show
  1. package/README.md +42 -12
  2. package/build/angular/drawer/index.js +23 -9
  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.js +20 -6
  8. package/build/angular/tabs/index.js +21 -7
  9. package/build/core/drawer-options/index.js +19 -5
  10. package/build/core/drawer-router-state/index.js +8 -2
  11. package/build/core/guards.js +3 -1
  12. package/build/core/header-bar-buttons.js +14 -4
  13. package/build/core/index.d.ts +4 -4
  14. package/build/core/index.js +2 -2
  15. package/build/core/navigator-state/index.js +12 -4
  16. package/build/core/render-drawer.js +4 -1
  17. package/build/core/render-stack.js +13 -4
  18. package/build/core/screen-options.js +1 -1
  19. package/build/core/search-bar-commands.js +1 -1
  20. package/build/core/state-persistence/index.js +6 -2
  21. package/build/core/tab-router-state/index.js +8 -2
  22. package/build/react/drawer/index.js +36 -13
  23. package/build/react/index.d.ts +7 -7
  24. package/build/react/index.js +2 -2
  25. package/build/react/stack/index.js +34 -8
  26. package/build/react/tabs/index.js +14 -4
  27. package/build/solid/drawer/index.d.ts +22 -0
  28. package/build/solid/drawer/index.js +394 -0
  29. package/build/solid/drawer-screen-props.d.ts +13 -0
  30. package/build/solid/drawer-screen-props.js +2 -0
  31. package/build/solid/host.d.ts +2 -0
  32. package/build/solid/host.js +23 -0
  33. package/build/solid/index.d.ts +19 -0
  34. package/build/solid/index.js +24 -0
  35. package/build/solid/linking.d.ts +3 -0
  36. package/build/solid/linking.js +55 -0
  37. package/build/solid/navigation-context.d.ts +13 -0
  38. package/build/solid/navigation-context.js +37 -0
  39. package/build/solid/primitives/create-focus-effect.d.ts +1 -0
  40. package/build/solid/primitives/create-focus-effect.js +30 -0
  41. package/build/solid/primitives/create-is-focused.d.ts +2 -0
  42. package/build/solid/primitives/create-is-focused.js +31 -0
  43. package/build/solid/primitives/create-navigation-state.d.ts +3 -0
  44. package/build/solid/primitives/create-navigation-state.js +30 -0
  45. package/build/solid/primitives/index.d.ts +12 -0
  46. package/build/solid/primitives/index.js +8 -0
  47. package/build/solid/primitives/use-drawer-navigation.d.ts +5 -0
  48. package/build/solid/primitives/use-drawer-navigation.js +15 -0
  49. package/build/solid/primitives/use-navigation.d.ts +8 -0
  50. package/build/solid/primitives/use-navigation.js +23 -0
  51. package/build/solid/primitives/use-route.d.ts +3 -0
  52. package/build/solid/primitives/use-route.js +14 -0
  53. package/build/solid/primitives/use-stack-navigation.d.ts +5 -0
  54. package/build/solid/primitives/use-stack-navigation.js +19 -0
  55. package/build/solid/primitives/use-tab-navigation.d.ts +5 -0
  56. package/build/solid/primitives/use-tab-navigation.js +15 -0
  57. package/build/solid/screen-props.d.ts +19 -0
  58. package/build/solid/screen-props.js +9 -0
  59. package/build/solid/screen-registry.d.ts +31 -0
  60. package/build/solid/screen-registry.js +86 -0
  61. package/build/solid/screen.d.ts +6 -0
  62. package/build/solid/screen.js +69 -0
  63. package/build/solid/stack/index.d.ts +15 -0
  64. package/build/solid/stack/index.js +348 -0
  65. package/build/solid/tab-screen-props.d.ts +13 -0
  66. package/build/solid/tab-screen-props.js +3 -0
  67. package/build/solid/tabs/index.d.ts +14 -0
  68. package/build/solid/tabs/index.js +228 -0
  69. package/build/svelte/descriptor-subtree.js +3 -1
  70. package/build/svelte/drawer/index.svelte +163 -25
  71. package/build/svelte/drawer-screen.svelte +2 -1
  72. package/build/svelte/index.d.ts +3 -3
  73. package/build/svelte/navigation-scope.svelte +4 -1
  74. package/build/svelte/runes/use-navigation.svelte.js +5 -1
  75. package/build/svelte/stack/index.svelte +43 -6
  76. package/build/svelte/stack/stack-screen.svelte +66 -9
  77. package/build/svelte/tabs/index.svelte +42 -20
  78. package/build/vue/composables/use-navigation.js +5 -1
  79. package/build/vue/drawer/index.js +30 -8
  80. package/build/vue/index.d.ts +3 -3
  81. package/build/vue/navigation-context.js +1 -1
  82. package/build/vue/stack/index.js +17 -6
  83. package/build/vue/tabs/index.js +18 -5
  84. package/build-ngc/angular/drawer/index.js +31 -11
  85. package/build-ngc/angular/drawer/index.js.map +1 -1
  86. package/build-ngc/angular/index.d.ts +4 -4
  87. package/build-ngc/angular/index.js.map +1 -1
  88. package/build-ngc/angular/injectors/inject-focus-effect.js.map +1 -1
  89. package/build-ngc/angular/injectors/inject-is-focused.js.map +1 -1
  90. package/build-ngc/angular/injectors/inject-navigation-state.js.map +1 -1
  91. package/build-ngc/angular/injectors/inject-navigation.js +1 -1
  92. package/build-ngc/angular/injectors/inject-navigation.js.map +1 -1
  93. package/build-ngc/angular/linking.js.map +1 -1
  94. package/build-ngc/angular/navigation-context.service.js.map +1 -1
  95. package/build-ngc/angular/navigation-scope.directive.js +1 -1
  96. package/build-ngc/angular/navigation-scope.directive.js.map +1 -1
  97. package/build-ngc/angular/screen.directive.js.map +1 -1
  98. package/build-ngc/angular/search-bar-ref.directive.js +1 -1
  99. package/build-ngc/angular/search-bar-ref.directive.js.map +1 -1
  100. package/build-ngc/angular/stack/index.js +26 -8
  101. package/build-ngc/angular/stack/index.js.map +1 -1
  102. package/build-ngc/angular/tab-screen.directive.js.map +1 -1
  103. package/build-ngc/angular/tabs/index.js +21 -7
  104. package/build-ngc/angular/tabs/index.js.map +1 -1
  105. package/build-ngc/core/constants.js.map +1 -1
  106. package/build-ngc/core/drawer-options/index.js +19 -5
  107. package/build-ngc/core/drawer-options/index.js.map +1 -1
  108. package/build-ngc/core/drawer-router-state/index.js +8 -2
  109. package/build-ngc/core/drawer-router-state/index.js.map +1 -1
  110. package/build-ngc/core/guards.js +3 -1
  111. package/build-ngc/core/guards.js.map +1 -1
  112. package/build-ngc/core/header-bar-buttons.js +14 -4
  113. package/build-ngc/core/header-bar-buttons.js.map +1 -1
  114. package/build-ngc/core/index.d.ts +4 -4
  115. package/build-ngc/core/index.js +2 -2
  116. package/build-ngc/core/index.js.map +1 -1
  117. package/build-ngc/core/linking-config/index.js.map +1 -1
  118. package/build-ngc/core/navigation-events/index.js.map +1 -1
  119. package/build-ngc/core/navigator-handles/index.js.map +1 -1
  120. package/build-ngc/core/navigator-state/index.js +12 -4
  121. package/build-ngc/core/navigator-state/index.js.map +1 -1
  122. package/build-ngc/core/render-drawer.js +4 -1
  123. package/build-ngc/core/render-drawer.js.map +1 -1
  124. package/build-ngc/core/render-stack.js +13 -4
  125. package/build-ngc/core/render-stack.js.map +1 -1
  126. package/build-ngc/core/render-tabs.js.map +1 -1
  127. package/build-ngc/core/screen-options.js +1 -1
  128. package/build-ngc/core/screen-options.js.map +1 -1
  129. package/build-ngc/core/search-bar-commands.js +1 -1
  130. package/build-ngc/core/search-bar-commands.js.map +1 -1
  131. package/build-ngc/core/stack-router-state/index.js.map +1 -1
  132. package/build-ngc/core/state-persistence/index.js +6 -2
  133. package/build-ngc/core/state-persistence/index.js.map +1 -1
  134. package/build-ngc/core/tab-router-state/index.js +8 -2
  135. package/build-ngc/core/tab-router-state/index.js.map +1 -1
  136. package/package.json +23 -9
  137. package/src/angular/drawer/index.ts +69 -25
  138. package/src/angular/index.ts +20 -4
  139. package/src/angular/injectors/inject-focus-effect.ts +8 -2
  140. package/src/angular/injectors/inject-is-focused.ts +6 -4
  141. package/src/angular/injectors/inject-navigation-state.ts +7 -4
  142. package/src/angular/injectors/inject-navigation.ts +12 -3
  143. package/src/angular/linking.ts +4 -1
  144. package/src/angular/navigation-context.service.ts +5 -2
  145. package/src/angular/navigation-scope.directive.ts +6 -2
  146. package/src/angular/screen.directive.ts +13 -3
  147. package/src/angular/search-bar-ref.directive.ts +10 -2
  148. package/src/angular/stack/index.ts +68 -22
  149. package/src/angular/tab-screen.directive.ts +3 -1
  150. package/src/angular/tabs/index.ts +36 -12
  151. package/src/core/constants.ts +6 -3
  152. package/src/core/drawer-options/index.ts +40 -13
  153. package/src/core/drawer-router-state/index.ts +11 -3
  154. package/src/core/guards.ts +3 -1
  155. package/src/core/header-bar-buttons.ts +41 -12
  156. package/src/core/index.ts +18 -4
  157. package/src/core/linking-config/index.ts +31 -10
  158. package/src/core/navigation-events/index.ts +8 -2
  159. package/src/core/navigator-handles/index.ts +8 -3
  160. package/src/core/navigator-props.ts +13 -4
  161. package/src/core/navigator-state/index.ts +24 -7
  162. package/src/core/render-drawer.ts +24 -9
  163. package/src/core/render-stack.ts +52 -13
  164. package/src/core/render-tabs.ts +24 -6
  165. package/src/core/screen-options.ts +15 -5
  166. package/src/core/search-bar-commands.ts +12 -3
  167. package/src/core/stack-router-state/index.ts +5 -2
  168. package/src/core/state-persistence/index.ts +13 -3
  169. package/src/core/tab-router-state/index.ts +10 -3
  170. package/src/react/drawer/index.ts +408 -344
  171. package/src/react/drawer-screen.ts +8 -2
  172. package/src/react/hooks/use-focus-effect.ts +8 -2
  173. package/src/react/hooks/use-is-focused.ts +6 -2
  174. package/src/react/hooks/use-navigation.ts +8 -2
  175. package/src/react/index.ts +37 -7
  176. package/src/react/linking.ts +4 -1
  177. package/src/react/navigation-context.ts +6 -2
  178. package/src/react/screen.ts +12 -3
  179. package/src/react/stack/index.ts +294 -231
  180. package/src/react/tab-screen.ts +3 -1
  181. package/src/react/tabs/index.ts +188 -158
  182. package/src/solid/drawer/index.ts +570 -0
  183. package/src/solid/drawer-screen-props.ts +24 -0
  184. package/src/solid/host.ts +29 -0
  185. package/src/solid/index.ts +87 -0
  186. package/src/solid/linking.ts +74 -0
  187. package/src/solid/navigation-context.ts +56 -0
  188. package/src/solid/primitives/create-focus-effect.ts +41 -0
  189. package/src/solid/primitives/create-is-focused.ts +41 -0
  190. package/src/solid/primitives/create-navigation-state.ts +44 -0
  191. package/src/solid/primitives/index.ts +12 -0
  192. package/src/solid/primitives/use-drawer-navigation.ts +25 -0
  193. package/src/solid/primitives/use-navigation.ts +44 -0
  194. package/src/solid/primitives/use-route.ts +18 -0
  195. package/src/solid/primitives/use-stack-navigation.ts +29 -0
  196. package/src/solid/primitives/use-tab-navigation.ts +25 -0
  197. package/src/solid/screen-props.ts +51 -0
  198. package/src/solid/screen-registry.ts +159 -0
  199. package/src/solid/screen.ts +80 -0
  200. package/src/solid/stack/index.ts +528 -0
  201. package/src/solid/tab-screen-props.ts +21 -0
  202. package/src/solid/tabs/index.ts +327 -0
  203. package/src/svelte/attachments.ts +3 -1
  204. package/src/svelte/descriptor-subtree.ts +3 -1
  205. package/src/svelte/drawer/index.svelte +163 -25
  206. package/src/svelte/drawer-screen-props.ts +8 -2
  207. package/src/svelte/drawer-screen.svelte +2 -1
  208. package/src/svelte/fabric-tree.test-helper.ts +37 -3
  209. package/src/svelte/index.ts +15 -3
  210. package/src/svelte/linking.svelte.ts +11 -5
  211. package/src/svelte/navigation-scope.svelte +4 -1
  212. package/src/svelte/runes/use-drawer-navigation.svelte.ts +3 -1
  213. package/src/svelte/runes/use-focus-effect.svelte.ts +8 -2
  214. package/src/svelte/runes/use-navigation-state.svelte.ts +3 -1
  215. package/src/svelte/runes/use-navigation.svelte.ts +13 -3
  216. package/src/svelte/runes/use-stack-navigation.svelte.ts +3 -1
  217. package/src/svelte/screen-props.ts +7 -2
  218. package/src/svelte/screen-registry.ts +9 -3
  219. package/src/svelte/stack/index.svelte +43 -6
  220. package/src/svelte/stack/stack-screen.svelte +66 -9
  221. package/src/svelte/svelte-compile.test-helper.ts +16 -12
  222. package/src/svelte/tab-screen-props.ts +3 -1
  223. package/src/svelte/tabs/index.svelte +42 -20
  224. package/src/vue/composables/use-navigation-state.ts +7 -4
  225. package/src/vue/composables/use-navigation.ts +13 -3
  226. package/src/vue/drawer/index.ts +122 -36
  227. package/src/vue/drawer-screen.ts +12 -5
  228. package/src/vue/index.ts +15 -3
  229. package/src/vue/linking.ts +7 -2
  230. package/src/vue/navigation-context.ts +17 -5
  231. package/src/vue/screen.ts +7 -2
  232. package/src/vue/stack/index.ts +82 -34
  233. package/src/vue/tab-screen.ts +3 -1
  234. package/src/vue/tabs/index.ts +51 -13
@@ -13,7 +13,12 @@
13
13
  import { defineComponent, h, shallowRef, useId } from '@vue/runtime-core';
14
14
  import type { VNode } from '@vue/runtime-core';
15
15
  import { descriptorToVue, normalizeVueAttrs } from '@symbiote-native/vue';
16
- import { Platform, debugNodeId, dlog, isSymbioteNode } from '@symbiote-native/engine';
16
+ import {
17
+ Platform,
18
+ debugNodeId,
19
+ dlog,
20
+ isSymbioteNode,
21
+ } from '@symbiote-native/engine';
17
22
  import {
18
23
  NAVIGATION_EVENT_BLUR,
19
24
  NAVIGATION_EVENT_FOCUS,
@@ -48,7 +53,11 @@ import type {
48
53
  } from '../../core';
49
54
  import { NavigationScope, injectNavigationScope } from '../navigation-context';
50
55
  import { Screen } from '../screen';
51
- import type { IScreenOptionsArgs, IScreenProps, IVueScreenOptions } from '../screen';
56
+ import type {
57
+ IScreenOptionsArgs,
58
+ IScreenProps,
59
+ IVueScreenOptions,
60
+ } from '../screen';
52
61
 
53
62
  export type { INavigatorHandle } from '../../core';
54
63
 
@@ -62,7 +71,9 @@ export type IStackProps = {
62
71
  // backTitleVisible defaults to `true` on both platforms per the codegen spec's own default
63
72
  // (CT.WithDefault<boolean, 'true'>) - no ios/android divergence in v1 scope, so a single constant
64
73
  // stands in for the per-platform injection point ISliderPlatform-style adapters use elsewhere.
65
- const NAVIGATOR_PLATFORM: INavigatorPlatform = { defaultHeaderBackTitleVisible: true };
74
+ const NAVIGATOR_PLATFORM: INavigatorPlatform = {
75
+ defaultHeaderBackTitleVisible: true,
76
+ };
66
77
 
67
78
  type IScreenRegistryEntry = {
68
79
  component: IScreenProps['component'];
@@ -93,7 +104,9 @@ function asScreenOptionsOrResolver(value: unknown): IScreenProps['options'] {
93
104
  return asScreenOptions(value);
94
105
  }
95
106
 
96
- function collectRegistry(vnodes: readonly VNode[]): Map<string, IScreenRegistryEntry> {
107
+ function collectRegistry(
108
+ vnodes: readonly VNode[],
109
+ ): Map<string, IScreenRegistryEntry> {
97
110
  const registry = new Map<string, IScreenRegistryEntry>();
98
111
  for (const vnode of vnodes) {
99
112
  if (vnode.type !== Screen || !isRecord(vnode.props)) continue;
@@ -115,7 +128,9 @@ function resolveScreenOptions(
115
128
  screenOptions: IVueScreenOptions | undefined,
116
129
  ): IVueScreenOptions {
117
130
  const own =
118
- typeof entry.options === 'function' ? entry.options(screenOptionsArgs) : entry.options;
131
+ typeof entry.options === 'function'
132
+ ? entry.options(screenOptionsArgs)
133
+ : entry.options;
119
134
  return { ...screenOptions, ...own };
120
135
  }
121
136
 
@@ -168,7 +183,10 @@ const StackImpl = defineComponent<IStackProps>(
168
183
  });
169
184
  } else {
170
185
  initialState = createInitialNavigatorState(
171
- createRoute(initialRouteName, initialRegistry.get(initialRouteName)?.initialParams),
186
+ createRoute(
187
+ initialRouteName,
188
+ initialRegistry.get(initialRouteName)?.initialParams,
189
+ ),
172
190
  );
173
191
  }
174
192
 
@@ -193,11 +211,13 @@ const StackImpl = defineComponent<IStackProps>(
193
211
  }
194
212
 
195
213
  const handle: INavigatorHandle = {
196
- push: (name, params) => dispatch({ type: 'push', route: createRoute(name, params) }),
214
+ push: (name, params) =>
215
+ dispatch({ type: 'push', route: createRoute(name, params) }),
197
216
  pop: count => dispatch({ type: 'pop', count }),
198
217
  popToTop: () => dispatch({ type: 'popToTop' }),
199
218
  popTo: key => dispatch({ type: 'popTo', key }),
200
- replace: (name, params) => dispatch({ type: 'replace', route: createRoute(name, params) }),
219
+ replace: (name, params) =>
220
+ dispatch({ type: 'replace', route: createRoute(name, params) }),
201
221
  setParams: (params, key) => dispatch({ type: 'setParams', key, params }),
202
222
  reset: nextState => dispatch({ type: 'reset', state: nextState }),
203
223
  canGoBack: () => currentState().routes.length > 1,
@@ -215,7 +235,8 @@ const StackImpl = defineComponent<IStackProps>(
215
235
  emitterFor(route.key).emit(NAVIGATION_EVENT_STATE, current);
216
236
  }
217
237
  for (const routeKey of emitters.keys()) {
218
- if (!current.routes.some(route => route.key === routeKey)) emitters.delete(routeKey);
238
+ if (!current.routes.some(route => route.key === routeKey))
239
+ emitters.delete(routeKey);
219
240
  }
220
241
  }
221
242
 
@@ -245,9 +266,19 @@ const StackImpl = defineComponent<IStackProps>(
245
266
  return null;
246
267
  }
247
268
 
248
- const screenOptionsArgs: IScreenOptionsArgs = { route, navigation: handle };
249
- const mergedOptions = resolveScreenOptions(entry, screenOptionsArgs, screenOptions);
250
- const activityState = computeActivityState(index, current.routes.length);
269
+ const screenOptionsArgs: IScreenOptionsArgs = {
270
+ route,
271
+ navigation: handle,
272
+ };
273
+ const mergedOptions = resolveScreenOptions(
274
+ entry,
275
+ screenOptionsArgs,
276
+ screenOptions,
277
+ );
278
+ const activityState = computeActivityState(
279
+ index,
280
+ current.routes.length,
281
+ );
251
282
  // Investigation instrumentation (flicker-on-focus bug): fires on EVERY Stack render, not
252
283
  // just on transitions, so the log stream shows whether a route's activityState/index ever
253
284
  // changes outside of a push/pop dispatch. Kept behind DEBUG, never removed.
@@ -268,21 +299,30 @@ const StackImpl = defineComponent<IStackProps>(
268
299
  isAndroid: Platform.OS === 'android',
269
300
  screenPassthrough: {
270
301
  [SCREEN_ON_DISMISSED]: () => dispatch({ type: 'pop', count: 1 }),
271
- [SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () => dispatch({ type: 'pop', count: 1 }),
302
+ [SCREEN_ON_HEADER_BACK_BUTTON_CLICKED]: () =>
303
+ dispatch({ type: 'pop', count: 1 }),
272
304
  // onAppear/onDisappear are the definitive visibility boundary (post-transition-
273
305
  // animation), so 'focus'/'blur' fire exactly once per transition; onWillAppear/
274
306
  // onWillDisappear fire BEFORE the animation runs, so wiring them to emit() too would
275
307
  // double-invoke useFocusEffect per transition - they only get a debug log here.
276
308
  [SCREEN_ON_WILL_APPEAR]: () =>
277
- dlog(`Stack: route "${route.name}" will appear at t=${Date.now()}`),
309
+ dlog(
310
+ `Stack: route "${route.name}" will appear at t=${Date.now()}`,
311
+ ),
278
312
  [SCREEN_ON_APPEAR]: () => {
279
- dlog(`Stack: route "${route.name}" appeared (focus) at t=${Date.now()}`);
313
+ dlog(
314
+ `Stack: route "${route.name}" appeared (focus) at t=${Date.now()}`,
315
+ );
280
316
  routeEmitter.emit(NAVIGATION_EVENT_FOCUS);
281
317
  },
282
318
  [SCREEN_ON_WILL_DISAPPEAR]: () =>
283
- dlog(`Stack: route "${route.name}" will disappear at t=${Date.now()}`),
319
+ dlog(
320
+ `Stack: route "${route.name}" will disappear at t=${Date.now()}`,
321
+ ),
284
322
  [SCREEN_ON_DISAPPEAR]: () => {
285
- dlog(`Stack: route "${route.name}" disappeared (blur) at t=${Date.now()}`);
323
+ dlog(
324
+ `Stack: route "${route.name}" disappeared (blur) at t=${Date.now()}`,
325
+ );
286
326
  routeEmitter.emit(NAVIGATION_EVENT_BLUR);
287
327
  },
288
328
  },
@@ -309,7 +349,8 @@ const StackImpl = defineComponent<IStackProps>(
309
349
  );
310
350
  const appRef = searchBarOptions.ref;
311
351
  if (appRef === undefined) return;
312
- appRef.value = node === null ? null : buildSearchBarHandle(() => node);
352
+ appRef.value =
353
+ node === null ? null : buildSearchBarHandle(() => node);
313
354
  },
314
355
  }
315
356
  : undefined,
@@ -334,22 +375,26 @@ const StackImpl = defineComponent<IStackProps>(
334
375
  // sizing (see RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME's comment in core/constants.ts). A
335
376
  // `push` screen doesn't need it, but a `formSheet` one is otherwise left with no content
336
377
  // ever attached natively.
337
- const content = h(RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME, plan.contentWrapperProps, [
338
- h(
339
- NavigationScope,
340
- {
341
- value: {
342
- route,
343
- navigation: handle,
344
- emitter: routeEmitter,
345
- parent: ambientScopeRef?.value,
378
+ const content = h(
379
+ RNS_SCREEN_CONTENT_WRAPPER_VIEW_NAME,
380
+ plan.contentWrapperProps,
381
+ [
382
+ h(
383
+ NavigationScope,
384
+ {
385
+ value: {
386
+ route,
387
+ navigation: handle,
388
+ emitter: routeEmitter,
389
+ parent: ambientScopeRef?.value,
390
+ },
346
391
  },
347
- },
348
- // No route/navigation props: the screen reads both through composables off the
349
- // NavigationScope provided just above (useRoute / useStackNavigation).
350
- () => h(entry.component),
351
- ),
352
- ]);
392
+ // No route/navigation props: the screen reads both through composables off the
393
+ // NavigationScope provided just above (useRoute / useStackNavigation).
394
+ () => h(entry.component),
395
+ ),
396
+ ],
397
+ );
353
398
 
354
399
  // react-native-screens' own Screen.tsx swaps in a DIFFERENT Fabric component
355
400
  // ('RNSModalScreen') for a modally-presented screen - its native updateLayoutMetrics:
@@ -373,7 +418,10 @@ const StackImpl = defineComponent<IStackProps>(
373
418
  // RNSScreen.mm treats an unset/inactive nested screen as not yet pushed,
374
419
  // leaving it parked at its pre-push transition position (off past the bottom
375
420
  // edge) instead of its real, presented frame.
376
- { style: plan.innerScreenStyle, activityState: plan.activityState },
421
+ {
422
+ style: plan.innerScreenStyle,
423
+ activityState: plan.activityState,
424
+ },
377
425
  [descriptorToVue(plan.headerConfig), content],
378
426
  ),
379
427
  ]),
@@ -14,7 +14,9 @@ export type ITabScreenOptionsArgs = {
14
14
  navigation: ITabNavigatorHandle;
15
15
  };
16
16
 
17
- export type ITabScreenOptionsResolver = (props: ITabScreenOptionsArgs) => ITabOptions;
17
+ export type ITabScreenOptionsResolver = (
18
+ props: ITabScreenOptionsArgs,
19
+ ) => ITabOptions;
18
20
 
19
21
  export type ITabScreenProps = {
20
22
  name: string;
@@ -7,7 +7,14 @@
7
7
  // `symbiote-view`/`symbiote-text` primitives via the shared render fn, so there is no
8
8
  // react-native-screens ViewConfig to register here - Tab needs no `../register` import.
9
9
 
10
- import { defineComponent, h, nextTick, onUnmounted, shallowRef, useId } from '@vue/runtime-core';
10
+ import {
11
+ defineComponent,
12
+ h,
13
+ nextTick,
14
+ onUnmounted,
15
+ shallowRef,
16
+ useId,
17
+ } from '@vue/runtime-core';
11
18
  import type { VNode } from '@vue/runtime-core';
12
19
  import { descriptorToVue, normalizeVueAttrs } from '@symbiote-native/vue';
13
20
  import { dlog } from '@symbiote-native/engine';
@@ -72,7 +79,9 @@ function asTabOptionsOrResolver(value: unknown): ITabScreenProps['options'] {
72
79
  return asTabOptions(value);
73
80
  }
74
81
 
75
- function collectRegistry(vnodes: readonly VNode[]): Map<string, ITabRegistryEntry> {
82
+ function collectRegistry(
83
+ vnodes: readonly VNode[],
84
+ ): Map<string, ITabRegistryEntry> {
76
85
  const registry = new Map<string, ITabRegistryEntry>();
77
86
  for (const vnode of vnodes) {
78
87
  if (vnode.type !== TabScreen || !isRecord(vnode.props)) continue;
@@ -94,7 +103,9 @@ function resolveTabOptions(
94
103
  screenOptions: ITabOptions | undefined,
95
104
  ): ITabOptions {
96
105
  const own =
97
- typeof entry.options === 'function' ? entry.options(screenComponentProps) : entry.options;
106
+ typeof entry.options === 'function'
107
+ ? entry.options(screenComponentProps)
108
+ : entry.options;
98
109
  return { ...screenOptions, ...own };
99
110
  }
100
111
 
@@ -112,7 +123,9 @@ const TabImpl = defineComponent<ITabProps>(
112
123
  const ambientScopeRef = injectNavigationScope();
113
124
  const routeIdPrefix = useId();
114
125
 
115
- function buildRoutes(registry: Map<string, ITabRegistryEntry>): IRoute<unknown>[] {
126
+ function buildRoutes(
127
+ registry: Map<string, ITabRegistryEntry>,
128
+ ): IRoute<unknown>[] {
116
129
  return Array.from(registry.entries()).map(([name, entry]) => ({
117
130
  key: `${routeIdPrefix}-${name}`,
118
131
  name,
@@ -122,7 +135,8 @@ const TabImpl = defineComponent<ITabProps>(
122
135
 
123
136
  const initialRegistry = collectRegistry(slots.default?.() ?? []);
124
137
  const initialRoutes = buildRoutes(initialRegistry);
125
- if (initialRoutes.length === 0) dlog('Tab: no <Tab.Screen> children registered');
138
+ if (initialRoutes.length === 0)
139
+ dlog('Tab: no <Tab.Screen> children registered');
126
140
 
127
141
  // A <Tab.Screen> can appear or disappear after mount (a marker behind a v-if, a data-driven
128
142
  // screen list), so the route list is re-collected from the slot on every render and the
@@ -147,7 +161,10 @@ const TabImpl = defineComponent<ITabProps>(
147
161
  }
148
162
 
149
163
  function dispatch(action: ITabRouterAction): void {
150
- dispatchedState.value = tabRouterReducer(resolveState(latestRoutes), action);
164
+ dispatchedState.value = tabRouterReducer(
165
+ resolveState(latestRoutes),
166
+ action,
167
+ );
151
168
  }
152
169
 
153
170
  const jumpTo = (name: string, params?: unknown): void =>
@@ -215,7 +232,8 @@ const TabImpl = defineComponent<ITabProps>(
215
232
  }
216
233
 
217
234
  onUnmounted(() => {
218
- if (focusedRouteKey !== undefined) emitterFor(focusedRouteKey).emit(NAVIGATION_EVENT_BLUR);
235
+ if (focusedRouteKey !== undefined)
236
+ emitterFor(focusedRouteKey).emit(NAVIGATION_EVENT_BLUR);
219
237
  });
220
238
 
221
239
  return () => {
@@ -229,17 +247,27 @@ const TabImpl = defineComponent<ITabProps>(
229
247
  const state = resolveState(routes);
230
248
  syncFocus(state);
231
249
 
232
- const focusedRoute: IRoute<unknown> | undefined = state.routes[state.index];
250
+ const focusedRoute: IRoute<unknown> | undefined =
251
+ state.routes[state.index];
233
252
 
234
253
  const items: ITabBarItemView[] = state.routes.map((route, index) => {
235
254
  const entry = registry.get(route.name);
236
255
  const focused = isFocusedRoute(index, state.index);
237
256
  if (entry === undefined) {
238
257
  dlog(`Tab: no screen registered for route name "${route.name}"`);
239
- return { key: route.key, focused, label: route.name, passthrough: {} };
258
+ return {
259
+ key: route.key,
260
+ focused,
261
+ label: route.name,
262
+ passthrough: {},
263
+ };
240
264
  }
241
265
 
242
- const options = resolveTabOptions(entry, { route, navigation: handle }, screenOptions);
266
+ const options = resolveTabOptions(
267
+ entry,
268
+ { route, navigation: handle },
269
+ screenOptions,
270
+ );
243
271
 
244
272
  return {
245
273
  key: route.key,
@@ -257,7 +285,9 @@ const TabImpl = defineComponent<ITabProps>(
257
285
  };
258
286
  });
259
287
 
260
- const focusedEntry = focusedRoute ? registry.get(focusedRoute.name) : undefined;
288
+ const focusedEntry = focusedRoute
289
+ ? registry.get(focusedRoute.name)
290
+ : undefined;
261
291
  const focusedOptions: ITabOptions | undefined =
262
292
  focusedEntry && focusedRoute
263
293
  ? resolveTabOptions(
@@ -268,7 +298,11 @@ const TabImpl = defineComponent<ITabProps>(
268
298
  : screenOptions;
269
299
 
270
300
  const tabBar = descriptorToVue(
271
- renderTabBar({ items, style: focusedOptions?.tabBarStyle, passthrough: {} }),
301
+ renderTabBar({
302
+ items,
303
+ style: focusedOptions?.tabBarStyle,
304
+ passthrough: {},
305
+ }),
272
306
  );
273
307
 
274
308
  // Only the focused route's screen is ever mounted (unlike Stack, which keeps every pushed
@@ -294,7 +328,11 @@ const TabImpl = defineComponent<ITabProps>(
294
328
  : null;
295
329
 
296
330
  return h('symbiote-view', { style: TAB_ROOT_STYLE }, [
297
- h('symbiote-view', { style: TAB_CONTENT_STYLE }, content === null ? [] : [content]),
331
+ h(
332
+ 'symbiote-view',
333
+ { style: TAB_CONTENT_STYLE },
334
+ content === null ? [] : [content],
335
+ ),
298
336
  tabBar,
299
337
  ]);
300
338
  };