@sigx/lynx-navigation 0.2.0 → 0.4.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 (193) hide show
  1. package/README.md +128 -8
  2. package/dist/components/EntryScope.d.ts +1 -1
  3. package/dist/components/EntryScope.d.ts.map +1 -1
  4. package/dist/components/Layer.d.ts +34 -0
  5. package/dist/components/Layer.d.ts.map +1 -0
  6. package/dist/components/Link.d.ts +2 -2
  7. package/dist/components/Link.d.ts.map +1 -1
  8. package/dist/components/NavigationRoot.d.ts +2 -2
  9. package/dist/components/NavigationRoot.d.ts.map +1 -1
  10. package/dist/components/Screen.d.ts +6 -6
  11. package/dist/components/Screen.d.ts.map +1 -1
  12. package/dist/components/Stack.d.ts +41 -16
  13. package/dist/components/Stack.d.ts.map +1 -1
  14. package/dist/components/TabBar.d.ts +19 -20
  15. package/dist/components/TabBar.d.ts.map +1 -1
  16. package/dist/components/Tabs.d.ts.map +1 -1
  17. package/dist/define-routes.d.ts +1 -1
  18. package/dist/define-routes.d.ts.map +1 -1
  19. package/dist/hooks/use-linking-nav.d.ts +3 -3
  20. package/dist/hooks/use-linking-nav.d.ts.map +1 -1
  21. package/dist/hooks/use-nav-internal.d.ts +21 -3
  22. package/dist/hooks/use-nav-internal.d.ts.map +1 -1
  23. package/dist/hooks/use-nav-serializer.d.ts +1 -1
  24. package/dist/hooks/use-nav-serializer.d.ts.map +1 -1
  25. package/dist/hooks/use-nav.d.ts +2 -2
  26. package/dist/hooks/use-nav.d.ts.map +1 -1
  27. package/dist/hooks/use-params.d.ts +1 -1
  28. package/dist/hooks/use-params.d.ts.map +1 -1
  29. package/dist/hooks/use-screen-chrome.d.ts +19 -0
  30. package/dist/hooks/use-screen-chrome.d.ts.map +1 -0
  31. package/dist/hooks/use-screen-options.d.ts +1 -1
  32. package/dist/hooks/use-screen-options.d.ts.map +1 -1
  33. package/dist/hooks/use-search.d.ts +1 -1
  34. package/dist/hooks/use-search.d.ts.map +1 -1
  35. package/dist/href.d.ts +2 -2
  36. package/dist/href.d.ts.map +1 -1
  37. package/dist/index.d.ts +33 -31
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +1160 -29
  40. package/dist/index.js.map +1 -1
  41. package/dist/internal/layer-plan.d.ts +69 -0
  42. package/dist/internal/layer-plan.d.ts.map +1 -0
  43. package/dist/internal/screen-registry.d.ts +1 -1
  44. package/dist/internal/screen-registry.d.ts.map +1 -1
  45. package/dist/internal/screen-width.d.ts +9 -7
  46. package/dist/internal/screen-width.d.ts.map +1 -1
  47. package/dist/navigator/core.d.ts +5 -4
  48. package/dist/navigator/core.d.ts.map +1 -1
  49. package/dist/register.d.ts +1 -1
  50. package/dist/register.d.ts.map +1 -1
  51. package/dist/url/index.d.ts +6 -6
  52. package/dist/url/index.d.ts.map +1 -1
  53. package/dist/url/parse.d.ts +1 -1
  54. package/dist/url/parse.d.ts.map +1 -1
  55. package/dist/url/registry.d.ts +2 -2
  56. package/dist/url/registry.d.ts.map +1 -1
  57. package/dist/url/validate.d.ts +1 -1
  58. package/dist/url/validate.d.ts.map +1 -1
  59. package/package.json +11 -10
  60. package/src/components/Drawer.d.ts +55 -0
  61. package/src/components/EdgeBackHandle.d.ts +1 -0
  62. package/src/components/EdgeBackHandle.tsx +2 -2
  63. package/{dist/components/EntryScope.js → src/components/EntryScope.d.ts} +7 -15
  64. package/src/components/EntryScope.tsx +15 -4
  65. package/src/components/Header.d.ts +6 -0
  66. package/src/components/Header.tsx +3 -3
  67. package/src/components/Layer.d.ts +33 -0
  68. package/src/components/Layer.tsx +96 -0
  69. package/src/components/Link.d.ts +60 -0
  70. package/src/components/Link.tsx +4 -4
  71. package/src/components/NavigationRoot.d.ts +36 -0
  72. package/src/components/NavigationRoot.tsx +6 -6
  73. package/src/components/Screen.d.ts +97 -0
  74. package/src/components/Screen.tsx +13 -11
  75. package/src/components/Stack.d.ts +90 -0
  76. package/src/components/Stack.tsx +142 -98
  77. package/src/components/TabBar.d.ts +38 -0
  78. package/src/components/TabBar.tsx +22 -22
  79. package/src/components/Tabs.d.ts +109 -0
  80. package/src/components/Tabs.tsx +15 -1
  81. package/{dist/define-routes.js → src/define-routes.d.ts} +2 -4
  82. package/src/define-routes.ts +1 -1
  83. package/src/hooks/use-focus.d.ts +45 -0
  84. package/src/hooks/use-focus.ts +2 -2
  85. package/src/hooks/use-hardware-back.d.ts +37 -0
  86. package/src/hooks/use-hardware-back.ts +1 -1
  87. package/src/hooks/use-linking-nav.d.ts +91 -0
  88. package/src/hooks/use-linking-nav.ts +4 -4
  89. package/src/hooks/use-nav-internal.d.ts +91 -0
  90. package/src/hooks/use-nav-internal.ts +24 -3
  91. package/src/hooks/use-nav-serializer.d.ts +82 -0
  92. package/src/hooks/use-nav-serializer.ts +3 -3
  93. package/src/hooks/use-nav.d.ts +111 -0
  94. package/src/hooks/use-nav.ts +2 -2
  95. package/{dist/hooks/use-params.js → src/hooks/use-params.d.ts} +2 -6
  96. package/src/hooks/use-params.ts +2 -2
  97. package/src/hooks/use-screen-chrome.d.ts +18 -0
  98. package/src/hooks/use-screen-chrome.ts +122 -0
  99. package/src/hooks/use-screen-options.d.ts +2 -0
  100. package/src/hooks/use-screen-options.ts +3 -3
  101. package/{dist/hooks/use-search.js → src/hooks/use-search.d.ts} +2 -6
  102. package/src/hooks/use-search.ts +2 -2
  103. package/src/href.d.ts +54 -0
  104. package/src/href.ts +6 -6
  105. package/src/index.d.ts +39 -0
  106. package/src/index.ts +33 -31
  107. package/src/internal/layer-plan.d.ts +68 -0
  108. package/src/internal/layer-plan.ts +187 -0
  109. package/{dist/internal/screen-registry.js → src/internal/screen-registry.d.ts} +21 -32
  110. package/src/internal/screen-registry.ts +1 -1
  111. package/src/internal/screen-width.d.ts +17 -0
  112. package/src/internal/screen-width.ts +22 -14
  113. package/src/navigator/core.d.ts +96 -0
  114. package/src/navigator/core.ts +17 -6
  115. package/src/register.d.ts +37 -0
  116. package/src/register.ts +1 -1
  117. package/src/types.d.ts +217 -0
  118. package/src/url/build.d.ts +15 -0
  119. package/src/url/build.ts +2 -2
  120. package/src/url/compile.d.ts +34 -0
  121. package/src/url/format.d.ts +28 -0
  122. package/src/url/index.ts +6 -6
  123. package/src/url/parse.d.ts +20 -0
  124. package/src/url/parse.ts +6 -6
  125. package/{dist/url/registry.js → src/url/registry.d.ts} +12 -28
  126. package/src/url/registry.ts +3 -3
  127. package/src/url/validate.d.ts +23 -0
  128. package/src/url/validate.ts +1 -1
  129. package/dist/components/Drawer.js +0 -74
  130. package/dist/components/Drawer.js.map +0 -1
  131. package/dist/components/EdgeBackHandle.js +0 -144
  132. package/dist/components/EdgeBackHandle.js.map +0 -1
  133. package/dist/components/EntryScope.js.map +0 -1
  134. package/dist/components/Header.js +0 -103
  135. package/dist/components/Header.js.map +0 -1
  136. package/dist/components/Link.js +0 -51
  137. package/dist/components/Link.js.map +0 -1
  138. package/dist/components/NavigationRoot.js +0 -67
  139. package/dist/components/NavigationRoot.js.map +0 -1
  140. package/dist/components/Screen.js +0 -94
  141. package/dist/components/Screen.js.map +0 -1
  142. package/dist/components/ScreenContainer.d.ts +0 -18
  143. package/dist/components/ScreenContainer.d.ts.map +0 -1
  144. package/dist/components/ScreenContainer.js +0 -77
  145. package/dist/components/ScreenContainer.js.map +0 -1
  146. package/dist/components/Stack.js +0 -221
  147. package/dist/components/Stack.js.map +0 -1
  148. package/dist/components/TabBar.js +0 -63
  149. package/dist/components/TabBar.js.map +0 -1
  150. package/dist/components/Tabs.js +0 -154
  151. package/dist/components/Tabs.js.map +0 -1
  152. package/dist/define-routes.js.map +0 -1
  153. package/dist/hooks/use-focus.js +0 -87
  154. package/dist/hooks/use-focus.js.map +0 -1
  155. package/dist/hooks/use-hardware-back.js +0 -84
  156. package/dist/hooks/use-hardware-back.js.map +0 -1
  157. package/dist/hooks/use-linking-nav.js +0 -109
  158. package/dist/hooks/use-linking-nav.js.map +0 -1
  159. package/dist/hooks/use-nav-internal.js +0 -44
  160. package/dist/hooks/use-nav-internal.js.map +0 -1
  161. package/dist/hooks/use-nav-serializer.js +0 -181
  162. package/dist/hooks/use-nav-serializer.js.map +0 -1
  163. package/dist/hooks/use-nav.js +0 -11
  164. package/dist/hooks/use-nav.js.map +0 -1
  165. package/dist/hooks/use-params.js.map +0 -1
  166. package/dist/hooks/use-screen-options.js +0 -43
  167. package/dist/hooks/use-screen-options.js.map +0 -1
  168. package/dist/hooks/use-search.js.map +0 -1
  169. package/dist/href.js +0 -57
  170. package/dist/href.js.map +0 -1
  171. package/dist/internal/screen-registry.js.map +0 -1
  172. package/dist/internal/screen-width.js +0 -30
  173. package/dist/internal/screen-width.js.map +0 -1
  174. package/dist/navigator/core.js +0 -383
  175. package/dist/navigator/core.js.map +0 -1
  176. package/dist/register.js +0 -2
  177. package/dist/register.js.map +0 -1
  178. package/dist/types.js +0 -9
  179. package/dist/types.js.map +0 -1
  180. package/dist/url/build.js +0 -30
  181. package/dist/url/build.js.map +0 -1
  182. package/dist/url/compile.js +0 -83
  183. package/dist/url/compile.js.map +0 -1
  184. package/dist/url/format.js +0 -102
  185. package/dist/url/format.js.map +0 -1
  186. package/dist/url/index.js +0 -13
  187. package/dist/url/index.js.map +0 -1
  188. package/dist/url/parse.js +0 -94
  189. package/dist/url/parse.js.map +0 -1
  190. package/dist/url/registry.js.map +0 -1
  191. package/dist/url/validate.js +0 -37
  192. package/dist/url/validate.js.map +0 -1
  193. package/src/components/ScreenContainer.tsx +0 -114
@@ -1,221 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
- import { component, defineProvide, effect, onUnmounted, untrack, useSharedValue, } from '@sigx/lynx';
3
- import { Suspense, isLazyComponent } from '@sigx/lynx';
4
- import { createNavigatorState } from '../navigator/core.js';
5
- import { useNav } from '../hooks/use-nav.js';
6
- import { useCurrentEntry, useNavInternals, useNavRoutes, } from '../hooks/use-nav-internal.js';
7
- import { ScreenContainer } from './ScreenContainer.js';
8
- import { EdgeBackHandle } from './EdgeBackHandle.js';
9
- import { EntryScope } from './EntryScope.js';
10
- import { useTabScreenName, useTabs } from './Tabs.js';
11
- let _nestedKeyCounter = 0;
12
- /**
13
- * Stack navigator — renders the topmost stack entry's component at rest, or
14
- * the top + underneath entries during a transition.
15
- *
16
- * Two modes:
17
- *
18
- * **Bound** (no `initialRoute`): renders the enclosing navigator's stack.
19
- * This is the shape used directly under `<NavigationRoot>` and is what
20
- * single-stack apps want.
21
- *
22
- * **Nested-owner** (`initialRoute="…"`): mints a fresh `NavigatorState` with
23
- * its own progress `SharedValue` and edge-back gesture, and provides
24
- * `useNav` / `useNavInternals` / `useNavRoutes` to its subtree. `useNav()`
25
- * inside this stack returns the nested nav; `nav.parent` points to the
26
- * enclosing one. Per-tab stacks are the canonical use case:
27
- *
28
- * ```tsx
29
- * <Tabs initialTab="trips">
30
- * <Tabs.Screen name="trips"><Stack initialRoute="tripsHome" /></Tabs.Screen>
31
- * <Tabs.Screen name="map"><Stack initialRoute="mapHome" /></Tabs.Screen>
32
- * </Tabs>
33
- * ```
34
- *
35
- * Modal/fullScreen pushes escalate up the parent chain automatically — so
36
- * `nav.push('newTrip')` from inside Trips (where `newTrip` is `modal`)
37
- * walks to root and overlays the whole UI. `replace` stays strictly local
38
- * (asymmetric with `push`) so a modal `replace` never wipes the root stack.
39
- *
40
- * **Render strategy** (same in both modes):
41
- * - **Idle**: just the top entry, full-bleed, no transform. The screen
42
- * component mounts directly so it can use its own layout (no extra
43
- * absolute positioning that would break percentage heights).
44
- * - **Transitioning**: two `<ScreenContainer>` instances stacked
45
- * absolutely, each with an MT-driven `translateX` that reads from the
46
- * navigator's progress `SharedValue`. The host's BG thread doesn't tick
47
- * per frame — `useAnimatedStyle` runs the interpolation entirely on MT.
48
- *
49
- * `key={top.key}` keeps the idle render's component instance stable across
50
- * unrelated re-renders. During transitions, composite keys
51
- * (`${entry.key}-${role}-${kind}`) ensure a fresh mount per role/kind pair
52
- * so the `useAnimatedStyle` binding is set with the right input/output
53
- * ranges.
54
- */
55
- export const Stack = component(({ props }) => {
56
- // Capture enclosing scope's nav + routes + internals BEFORE any of the
57
- // defineProvide calls below override them for descendants. These are
58
- // always the "outer" values regardless of whether this Stack is bound
59
- // or nested-owner.
60
- const parentNav = useNav();
61
- const routes = useNavRoutes();
62
- const parentInternals = useNavInternals();
63
- // Decide mode at setup. `props.initialRoute` is captured once — the
64
- // alternative (reactive switch between bound and nested-owner) would
65
- // need to dispose and recreate the inner nav, which would lose all
66
- // pushed state. Reasonable to pin it.
67
- const initialName = props.initialRoute;
68
- const isNested = typeof initialName === 'string' && initialName.length > 0;
69
- let nav;
70
- let internals;
71
- if (isNested) {
72
- if (!routes[initialName]) {
73
- throw new Error(`[lynx-navigation] <Stack initialRoute='${initialName}'>: ` +
74
- `route is not registered. Known routes: ` +
75
- `${Object.keys(routes).join(', ') || '(none)'}`);
76
- }
77
- // Host entry — the parent's current top *when this Stack mounts*.
78
- // Used by the focus chain so the nested nav is only "locally
79
- // focused" while its host entry is still the top of the parent.
80
- // Wrapped in try/catch because `<Stack initialRoute>` *may* be
81
- // placed outside an EntryScope (e.g. directly under
82
- // `<NavigationRoot>`); in that case there's no host-entry gate to
83
- // apply and we just rely on `parent.isLocallyFocused`.
84
- let hostEntryKey = null;
85
- try {
86
- hostEntryKey = useCurrentEntry().key;
87
- }
88
- catch {
89
- hostEntryKey = null;
90
- }
91
- // Enclosing tab name (if any). Lets the focus chain gate on tab
92
- // active state — Trips' inner stack reports `isLocallyFocused: false`
93
- // while the user is on the Map tab, even though it's the top of
94
- // its own stack.
95
- let tabName = null;
96
- let tabsHandle = null;
97
- try {
98
- tabName = useTabScreenName();
99
- tabsHandle = useTabs();
100
- }
101
- catch {
102
- tabName = null;
103
- tabsHandle = null;
104
- }
105
- // Inherit animation enablement from the parent — if the root was
106
- // created with `animated={false}` (tests), nested stacks should
107
- // also commit instantly so test assertions don't have to wait on
108
- // a SharedValue that won't tick.
109
- const animationsEnabled = parentInternals.progress !== null;
110
- const progressSv = useSharedValue(0);
111
- const presentation = (routes[initialName].presentation ?? 'card');
112
- // Counter-derived suffix keeps base-entry keys unique across
113
- // concurrent nested stacks in a tab app. Plain `Math.random` would
114
- // do but a counter is deterministic for test snapshots.
115
- _nestedKeyCounter += 1;
116
- const initial = {
117
- key: `nested-${initialName}-${_nestedKeyCounter}`,
118
- route: initialName,
119
- params: props.initialParams ?? {},
120
- search: props.initialSearch ?? {},
121
- state: undefined,
122
- presentation,
123
- };
124
- const navState = createNavigatorState({
125
- routes,
126
- initial,
127
- progress: animationsEnabled ? progressSv : undefined,
128
- parent: parentNav,
129
- // Start un-focused; the effect below flips this once we observe
130
- // the parent's current entry / tab-active state.
131
- initialLocallyFocused: false,
132
- });
133
- nav = navState.nav;
134
- internals = {
135
- progress: animationsEnabled ? progressSv : null,
136
- beginBackGesture: navState._gesture.beginBackGesture,
137
- commitBackGesture: navState._gesture.commitBackGesture,
138
- cancelBackGesture: navState._gesture.cancelBackGesture,
139
- edgeSwipeEnabled:
140
- // Gate on animationsEnabled too — if there's no progress
141
- // SharedValue (e.g. parent is `animated={false}`), the edge
142
- // swipe gesture would call `beginBackGesture()` with a null
143
- // progress and leave the stack in an inconsistent state.
144
- animationsEnabled && parentInternals.edgeSwipeEnabled,
145
- screens: navState._screens,
146
- };
147
- // Reactive focus chain: this nav is locally focused iff
148
- // 1. (no host entry captured) OR parent.current.key === hostEntryKey
149
- // 2. parent.isLocallyFocused
150
- // 3. (no enclosing tab) OR tabs.active === tabName
151
- // Effect re-runs on any of those changing — parent's stack
152
- // mutating, parent's own focus flipping, or the tab switching.
153
- const focusRunner = effect(() => {
154
- const hostMatch = hostEntryKey === null || parentNav.current.key === hostEntryKey;
155
- const parentFocused = parentNav.isLocallyFocused;
156
- const tabActive = tabName === null || tabsHandle === null
157
- ? true
158
- : tabsHandle.active === tabName;
159
- const focused = hostMatch && parentFocused && tabActive;
160
- // Write outside the read-tracking window — `_setLocallyFocused`
161
- // bumps a signal that no consumer in *this* setup reads, but
162
- // it's good hygiene anyway.
163
- untrack(() => navState._setLocallyFocused(focused));
164
- });
165
- onUnmounted(() => {
166
- focusRunner.stop();
167
- parentNav._children.delete(nav);
168
- });
169
- defineProvide(useNav, () => nav);
170
- defineProvide(useNavRoutes, () => routes);
171
- defineProvide(useNavInternals, () => internals);
172
- }
173
- else {
174
- nav = parentNav;
175
- internals = parentInternals;
176
- }
177
- return () => {
178
- const transition = nav.transition;
179
- const top = nav.current;
180
- if (!transition) {
181
- const route = routes[top.route];
182
- if (!route)
183
- return null;
184
- const Comp = route.component;
185
- if (typeof Comp !== 'function')
186
- return null;
187
- const params = top.params;
188
- // Wrap lazy routes that declare a `fallback` in <Suspense> so the
189
- // chunk-load shows the user-provided spinner instead of throwing
190
- // up to the nearest outer boundary (which may be wrong layer or
191
- // missing entirely).
192
- const body = isLazyComponent(Comp) && route.fallback
193
- ? (_jsx(Suspense, { fallback: route.fallback, children: _jsx(Comp, { ...params }) }))
194
- : _jsx(Comp, { ...params });
195
- // When canGoBack and edge-swipe is enabled, overlay the gesture
196
- // handle so the user can pan from the left edge to start a back
197
- // transition. `position: absolute` doesn't disturb the screen's
198
- // own layout — the handle only intercepts touches in the leftmost
199
- // 20px, and only when they pan rightward past `MIN_DISTANCE`.
200
- if (nav.canGoBack && internals.edgeSwipeEnabled) {
201
- return (_jsxs("view", { style: {
202
- position: 'relative',
203
- width: '100%',
204
- height: '100%',
205
- }, children: [_jsx(EntryScope, { entry: top, children: body }, top.key), _jsx(EdgeBackHandle, {}, "edge-back")] }));
206
- }
207
- return (_jsx(EntryScope, { entry: top, children: body }, top.key));
208
- }
209
- // Cast progress: TransitionState carries it as `unknown` to avoid
210
- // pinning the contract to `@sigx/lynx`'s SharedValue at the type
211
- // level; here at the runtime boundary we know it's a SharedValue<number>.
212
- const progress = transition.progress;
213
- return (_jsxs("view", { style: {
214
- position: 'relative',
215
- width: '100%',
216
- height: '100%',
217
- overflow: 'hidden',
218
- }, children: [_jsx(ScreenContainer, { entry: transition.underneathEntry, routes: routes, role: "underneath", kind: transition.kind, progress: progress }, `${transition.underneathEntry.key}-underneath-${transition.kind}`), _jsx(ScreenContainer, { entry: transition.topEntry, routes: routes, role: "top", kind: transition.kind, progress: progress }, `${transition.topEntry.key}-top-${transition.kind}`)] }));
219
- };
220
- });
221
- //# sourceMappingURL=Stack.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Stack.js","sourceRoot":"","sources":["../../src/components/Stack.tsx"],"names":[],"mappings":"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"}
@@ -1,63 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
- /**
3
- * `<TabBar>` — default chrome for `<Tabs>`.
4
- *
5
- * Renders a row of tab buttons reading from the enclosing `useTabs()`
6
- * navigator. Active tab is highlighted via the `active` prop on each
7
- * default button (consumers can re-style via `renderTab`).
8
- *
9
- * Customization knobs:
10
- * - `renderTab`: a function `(info, ctx) => JSX` that fully replaces the
11
- * default button rendering for each tab. `ctx.active` tells the
12
- * consumer whether this tab is currently focused; `ctx.onPress`
13
- * activates the tab.
14
- *
15
- * Accessibility:
16
- * - Each default button gets `accessibility-label` from
17
- * `info.accessibilityLabel ?? info.label ?? info.name`.
18
- * - Each default button gets `accessibility-element="true"` so screen
19
- * readers see the whole pill, not just the inner `<text>`.
20
- * - Each default button gets `accessibility-trait="button"` and a
21
- * `selected` flag on the active one so VoiceOver/TalkBack announces
22
- * focus state on tab switch.
23
- *
24
- * Placement: mount inside `<Tabs>` alongside the `<Tabs.Screen>`s. Order
25
- * matters visually (place above or below the screen bodies depending on
26
- * the layout), and `<Tabs.Screen>` bodies all stack with `display:flex` so
27
- * the TabBar should be at a deterministic position in the JSX.
28
- */
29
- import { component, } from '@sigx/lynx';
30
- import { useTabs } from './Tabs.js';
31
- /**
32
- * Default per-tab button. Plain `<view>` with a `<text>` inside, an
33
- * `accessibility-*` cluster for screen readers, and a tap handler. No
34
- * styling beyond a minimal active-state marker — consumers that want
35
- * branded chrome pass `renderTab`.
36
- */
37
- const DefaultTabButton = component(({ props }) => {
38
- return () => {
39
- const label = props.info.label ?? props.info.name;
40
- const a11y = props.info.accessibilityLabel ?? label;
41
- return (_jsxs("view", { bindtap: () => props.onPress(), "accessibility-element": true, "accessibility-label": a11y, "accessibility-trait": "button", "accessibility-status": props.active ? 'selected' : undefined, style: { opacity: props.active ? 1 : 0.6 }, children: [props.info.icon ?? null, _jsx("text", { children: label })] }));
42
- };
43
- });
44
- export const TabBar = component(({ props }) => {
45
- const nav = useTabs();
46
- return () => {
47
- // Reading `nav.tabs` and `nav.active` here ties this render to both
48
- // the registration list and the active signal — switching active or
49
- // adding/removing a `<Tabs.Screen>` updates the bar reactively.
50
- const tabs = nav.tabs;
51
- const active = nav.active;
52
- const renderer = props.renderTab;
53
- return (_jsx("view", { "accessibility-element": false, children: tabs.map((info) => {
54
- const isActive = info.name === active;
55
- const onPress = () => nav.setActive(info.name);
56
- if (renderer) {
57
- return renderer(info, { active: isActive, onPress });
58
- }
59
- return (_jsx(DefaultTabButton, { info: info, active: isActive, onPress: onPress }));
60
- }) }));
61
- };
62
- });
63
- //# sourceMappingURL=TabBar.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TabBar.js","sourceRoot":"","sources":["../../src/components/TabBar.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EACH,SAAS,GAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAgB,MAAM,WAAW,CAAC;AAalD;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,SAAS,CAIhC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACZ,OAAO,GAAG,EAAE;QACR,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,kBAAkB,IAAI,KAAK,CAAC;QACpD,OAAO,CACH,gBACI,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,2BACP,IAAI,yBACN,IAAI,yBACL,QAAQ,0BACN,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAC3D,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,aAEzC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,EACxB,yBAAO,KAAK,GAAQ,IACjB,CACV,CAAC;IACN,CAAC,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,SAAS,CAAc,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACvD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,OAAO,GAAG,EAAE;QACR,oEAAoE;QACpE,oEAAoE;QACpE,gEAAgE;QAChE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;QACjC,OAAO,CACH,wCAA6B,KAAK,YAC7B,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;gBACtC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,QAAQ,EAAE,CAAC;oBACX,OAAO,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;gBACzD,CAAC;gBACD,OAAO,CACH,KAAC,gBAAgB,IACb,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,OAAO,GAClB,CACL,CAAC;YACN,CAAC,CAAC,GACC,CACV,CAAC;IACN,CAAC,CAAC;AACN,CAAC,CAAC,CAAC"}
@@ -1,154 +0,0 @@
1
- import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
- /**
3
- * `<Tabs>` — Lynx tab navigator.
4
- *
5
- * Usage:
6
- *
7
- * ```tsx
8
- * <NavigationRoot routes={routes} initialRoute="root">
9
- * <Stack />
10
- * </NavigationRoot>
11
- *
12
- * // The route "root" component renders:
13
- * <Tabs initialTab="feed">
14
- * <Tabs.Screen name="feed" icon={<FeedIcon />} label="Feed">
15
- * <Stack initialRoute="feedHome" />
16
- * </Tabs.Screen>
17
- * <Tabs.Screen name="me" icon={<MeIcon />} label="Profile">
18
- * <Stack initialRoute="profileHome" />
19
- * </Tabs.Screen>
20
- * <TabBar />
21
- * </Tabs>
22
- * ```
23
- *
24
- * Tab bodies stay mounted across switches (the inactive ones render with
25
- * `display: 'none'`), so each tab's nested `<Stack>` keeps its history when
26
- * the user flips back to it. The active tab is reactive via `useTabs()`.
27
- *
28
- * Per-tab stacks: each `<Tabs.Screen>` can host a `<Stack initialRoute="…">`
29
- * which mints its own navigator. `useNav()` inside that subtree resolves to
30
- * the tab's stack, so `nav.push('card-route', …)` stays inside the tab.
31
- * Routes presented as `modal` / `fullScreen` / `transparent-modal` escalate
32
- * up `nav.parent` to the root navigator automatically — they overlay the
33
- * tabs UI (TabBar included) and dismiss back into the originating tab.
34
- */
35
- import { component, compound, defineInjectable, defineProvide, onUnmounted, signal, untrack, } from '@sigx/lynx';
36
- /**
37
- * Access the enclosing Tabs navigator. Throws when called outside `<Tabs>`.
38
- */
39
- export const useTabs = defineInjectable(() => {
40
- throw new Error('[lynx-navigation] useTabs() called outside of a <Tabs> component.');
41
- });
42
- const useTabsRegistrar = defineInjectable(() => {
43
- throw new Error('[lynx-navigation] <Tabs.Screen> rendered outside a <Tabs> component.');
44
- });
45
- /**
46
- * @internal
47
- * Provided by each `<Tabs.Screen>` so a nested `<Stack initialRoute>` can
48
- * discover *which* tab it's hosted by, and gate its focus state on that
49
- * tab being active. Throws when called outside a `<Tabs.Screen>` body so
50
- * the gate degrades to "always active" via the caller's try/catch.
51
- */
52
- export const useTabScreenName = defineInjectable(() => {
53
- throw new Error('[lynx-navigation] useTabScreenName() called outside a <Tabs.Screen> body.');
54
- });
55
- const _Tabs = component(({ props, slots }) => {
56
- // Tabs are stored as a deeply-reactive proxy signal so `tabs` consumers
57
- // re-render when registration changes. `activeSignal` uses the wrapped
58
- // `{value}` pattern so we can write a `string | null` without the
59
- // proxy treating the inner string as an object.
60
- const tabs = signal([]);
61
- const activeSignal = signal({
62
- value: props.initialTab ?? null,
63
- });
64
- const registrar = {
65
- register(info) {
66
- // Wrap in untrack so registration writes inside `<Tabs.Screen>`'s
67
- // setup phase don't notify the same setup effect that issued them
68
- // — sigx's setup runs in a tracked scope by default.
69
- untrack(() => {
70
- const idx = tabs.findIndex((t) => t.name === info.name);
71
- if (idx === -1)
72
- tabs.push(info);
73
- else
74
- tabs[idx] = info;
75
- if (activeSignal.value === null) {
76
- activeSignal.value = info.name;
77
- }
78
- });
79
- },
80
- unregister(name) {
81
- untrack(() => {
82
- const idx = tabs.findIndex((t) => t.name === name);
83
- if (idx !== -1)
84
- tabs.splice(idx, 1);
85
- if (activeSignal.value === name) {
86
- activeSignal.value = tabs[0]?.name ?? null;
87
- }
88
- });
89
- },
90
- tabs,
91
- activeSignal,
92
- };
93
- const nav = {
94
- get active() {
95
- // Empty-tabs state is rare in practice (no <Tabs.Screen> yet) but
96
- // possible during initial render; expose '' rather than null so
97
- // consumers can compare strings without narrowing.
98
- return activeSignal.value ?? '';
99
- },
100
- setActive(name) {
101
- // Silently ignore unknown names rather than writing them and
102
- // hiding every tab body. Surfacing as a no-op gives consumers a
103
- // predictable failure mode for typos / dynamic name sources.
104
- if (!tabs.some((t) => t.name === name))
105
- return;
106
- activeSignal.value = name;
107
- },
108
- get tabs() {
109
- return tabs;
110
- },
111
- };
112
- defineProvide(useTabs, () => nav);
113
- defineProvide(useTabsRegistrar, () => registrar);
114
- return () => slots.default?.();
115
- });
116
- const TabsScreen = component(({ props, slots }) => {
117
- const registrar = useTabsRegistrar();
118
- // Capture `name` once at setup. Props is reactive in sigx, but using a
119
- // changing `name` for an already-registered screen would be ambiguous
120
- // (rename vs re-register?) — pin it and require callers to remount on
121
- // identity change. This matches React Navigation's contract.
122
- const name = props.name;
123
- registrar.register({
124
- name,
125
- icon: props.icon,
126
- label: props.label,
127
- accessibilityLabel: props.accessibilityLabel,
128
- });
129
- onUnmounted(() => registrar.unregister(name));
130
- // Expose this screen's tab name so a nested `<Stack initialRoute>` body
131
- // can gate its locally-focused state on `tabs.active === name`.
132
- defineProvide(useTabScreenName, () => name);
133
- return () => {
134
- // `display: none` keeps the body mounted so per-tab state survives
135
- // tab switches. Read activeSignal here so re-activating triggers a
136
- // re-render with display restored.
137
- const active = registrar.activeSignal.value === name;
138
- return (_jsx("view", { style: {
139
- display: active ? 'flex' : 'none',
140
- width: '100%',
141
- height: '100%',
142
- }, children: slots.default?.() }));
143
- };
144
- });
145
- /**
146
- * Compound export. `Tabs` is the parent component; `Tabs.Screen` registers
147
- * an individual tab. Matches the `Screen` / `Screen.Header` shape used
148
- * elsewhere in this package and the daisyui `Modal` / `Modal.Header`
149
- * convention.
150
- */
151
- export const Tabs = compound(_Tabs, {
152
- Screen: TabsScreen,
153
- });
154
- //# sourceMappingURL=Tabs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../src/components/Tabs.tsx"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"define-routes.js","sourceRoot":"","sources":["../src/define-routes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,YAAY,CAA2B,MAAS;IAC5D,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -1,87 +0,0 @@
1
- import { computed, effect, onUnmounted, untrack, } from '@sigx/lynx';
2
- import { useNav } from './use-nav.js';
3
- import { useCurrentEntry } from './use-nav-internal.js';
4
- /**
5
- * Reactive "is this screen the focused entry?" signal.
6
- *
7
- * Must be called from inside a component rendered as a route by `<Stack>` (or
8
- * any other navigator that uses `<EntryScope>`); throws otherwise. The
9
- * returned `Computed` reads `nav.current.key` and compares it to the entry
10
- * the calling screen was mounted for, so any nav mutation that changes the
11
- * top entry flips the value.
12
- *
13
- * Note: screens stay mounted when something is pushed on top of them — they
14
- * just lose focus. Pop the new top off and they regain focus.
15
- *
16
- * @example
17
- * ```tsx
18
- * const Profile = component(() => {
19
- * const isFocused = useIsFocused();
20
- * return () => <text>{isFocused.value ? 'visible' : 'hidden'}</text>;
21
- * });
22
- * ```
23
- */
24
- export function useIsFocused() {
25
- const nav = useNav();
26
- // Capture the entry's key once at setup. The entry object provided
27
- // through `defineProvide` may carry reactive dependencies; we only care
28
- // about the immutable key of the entry this screen was mounted for.
29
- const myKey = useCurrentEntry().key;
30
- // AND in `nav.isLocallyFocused` so a screen in a nested stack (e.g. a
31
- // per-tab `<Stack>`) reports unfocused when its enclosing tab is
32
- // inactive, or when a modal on the root nav covers everything — even
33
- // though it's still the top of its own (paused) stack. Root nav's
34
- // `isLocallyFocused` is permanently true, so this reduces to the
35
- // previous behavior for un-nested apps.
36
- return computed(() => nav.current.key === myKey && nav.isLocallyFocused);
37
- }
38
- /**
39
- * Run `cb` whenever this screen gains focus; run the returned cleanup when it
40
- * loses focus or unmounts. Mirrors React Navigation's `useFocusEffect`.
41
- *
42
- * Lifecycle:
43
- * - cb runs immediately if the screen is already focused at mount.
44
- * - When the screen loses focus (something pushed on top), cleanup runs.
45
- * - When focus returns (the cover is popped), `cb` runs again — yielding a
46
- * fresh cleanup for the next blur.
47
- * - On unmount, cleanup runs once if still focused.
48
- *
49
- * Common uses: subscribe to a data source while visible, track an analytics
50
- * "screen view" event, start/stop a polling loop.
51
- *
52
- * @example
53
- * ```tsx
54
- * useFocusEffect(() => {
55
- * const id = setInterval(refresh, 5000);
56
- * return () => clearInterval(id);
57
- * });
58
- * ```
59
- */
60
- export function useFocusEffect(cb) {
61
- const isFocused = useIsFocused();
62
- let cleanup;
63
- const runner = effect(() => {
64
- const focused = isFocused.value;
65
- // Always tear down any previous focus session before starting a new
66
- // one (or before going dormant on blur). Wrap `cb` in `untrack` so
67
- // signals read inside the user-provided callback can't retrigger the
68
- // outer effect and stack subscriptions.
69
- if (typeof cleanup === 'function') {
70
- const fn = cleanup;
71
- cleanup = undefined;
72
- fn();
73
- }
74
- if (focused) {
75
- cleanup = untrack(() => cb());
76
- }
77
- });
78
- onUnmounted(() => {
79
- if (typeof cleanup === 'function') {
80
- const fn = cleanup;
81
- cleanup = undefined;
82
- fn();
83
- }
84
- runner.stop();
85
- });
86
- }
87
- //# sourceMappingURL=use-focus.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-focus.js","sourceRoot":"","sources":["../../src/hooks/use-focus.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,MAAM,EACN,WAAW,EACX,OAAO,GAEV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,YAAY;IACxB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC;IACpC,sEAAsE;IACtE,iEAAiE;IACjE,qEAAqE;IACrE,kEAAkE;IAClE,iEAAiE;IACjE,wCAAwC;IACxC,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,cAAc,CAAC,EAA6B;IACxD,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,IAAI,OAA4B,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,EAAE;QACvB,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;QAChC,oEAAoE;QACpE,mEAAmE;QACnE,qEAAqE;QACrE,wCAAwC;QACxC,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG,OAAO,CAAC;YACnB,OAAO,GAAG,SAAS,CAAC;YACpB,EAAE,EAAE,CAAC;QACT,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAClC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,WAAW,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG,OAAO,CAAC;YACnB,OAAO,GAAG,SAAS,CAAC;YACpB,EAAE,EAAE,CAAC;QACT,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -1,84 +0,0 @@
1
- import { onMounted } from '@sigx/lynx';
2
- import { BackHandler } from '@sigx/lynx-linking';
3
- import { useNav } from './use-nav.js';
4
- /**
5
- * Wire the Android hardware back button to the active navigator.
6
- *
7
- * Listens for `hardwareBackPress` events from `@sigx/lynx-linking`'s
8
- * `BackHandler` (which the native side dispatches from
9
- * `MainActivity.onBackPressed`). On press the handler walks to the
10
- * deepest currently-focused navigator (per-tab `<Stack>`s register with
11
- * their parent), then walks back up the `parent` chain looking for the
12
- * first nav that `canGoBack`:
13
- *
14
- * - If any nav in the chain can go back → `nav.pop()` on that nav.
15
- * - Otherwise → `BackHandler.exitApp()` (Android: `moveTaskToBack(true)`,
16
- * keeps the bundle warm; iOS: rejects, since iOS doesn't permit
17
- * programmatic termination).
18
- *
19
- * The traversal means you only need to call this once at the root — a
20
- * back press from inside a tab pops that tab's nested stack first, only
21
- * exiting the app once every level is at its base entry.
22
- *
23
- * Call this once in any component under `<NavigationRoot>` (typically a
24
- * thin wrapper sibling to `<Stack />`). iOS doesn't fire the event so the
25
- * hook is a no-op there.
26
- *
27
- * @example
28
- * ```tsx
29
- * const BackHandlerWiring = component(() => {
30
- * useHardwareBack();
31
- * return () => null;
32
- * });
33
- *
34
- * <NavigationRoot routes={routes}>
35
- * <BackHandlerWiring />
36
- * <Stack />
37
- * </NavigationRoot>
38
- * ```
39
- */
40
- export function useHardwareBack() {
41
- const nav = useNav();
42
- onMounted(() => {
43
- const sub = BackHandler.addEventListener(() => {
44
- // Walk down to the deepest focused nav. Per-tab `<Stack>`s
45
- // register themselves via `parent._children.add(nav)`; only one
46
- // child per level is `isLocallyFocused` at a time, so the
47
- // traversal is unambiguous. Falls back to the starting nav if
48
- // no nested stacks are wired up.
49
- let active = nav;
50
- // Loop instead of recursion so a deeply-nested tree doesn't blow
51
- // the stack on a synchronous back press.
52
- outer: while (active._children.size > 0) {
53
- for (const child of active._children) {
54
- if (child.isLocallyFocused) {
55
- active = child;
56
- continue outer;
57
- }
58
- }
59
- // No focused child at this level — stop drilling.
60
- break;
61
- }
62
- // Walk back up the chain looking for the first nav that has
63
- // something to pop. This is what makes "back press in trips
64
- // tab with empty inner stack" fall through to root (which might
65
- // have a modal on top) before exiting.
66
- let cur = active;
67
- while (cur) {
68
- if (cur.canGoBack) {
69
- cur.pop();
70
- return true;
71
- }
72
- cur = cur.parent;
73
- }
74
- // At the root with nothing to pop — leave the app. Promise is
75
- // fire-and-forget; we don't await because we want the back
76
- // press to feel instant (Android starts the move-to-back
77
- // transition immediately).
78
- void BackHandler.exitApp();
79
- return true;
80
- });
81
- return () => sub.remove();
82
- });
83
- }
84
- //# sourceMappingURL=use-hardware-back.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-hardware-back.js","sourceRoot":"","sources":["../../src/hooks/use-hardware-back.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAY,MAAM,cAAc,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,eAAe;IAC3B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,GAAG,EAAE;QACX,MAAM,GAAG,GAAG,WAAW,CAAC,gBAAgB,CAAC,GAAG,EAAE;YAC1C,2DAA2D;YAC3D,gEAAgE;YAChE,0DAA0D;YAC1D,8DAA8D;YAC9D,iCAAiC;YACjC,IAAI,MAAM,GAAQ,GAAG,CAAC;YACtB,iEAAiE;YACjE,yCAAyC;YACzC,KAAK,EAAE,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBACnC,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;wBACzB,MAAM,GAAG,KAAK,CAAC;wBACf,SAAS,KAAK,CAAC;oBACnB,CAAC;gBACL,CAAC;gBACD,kDAAkD;gBAClD,MAAM;YACV,CAAC;YACD,4DAA4D;YAC5D,4DAA4D;YAC5D,gEAAgE;YAChE,uCAAuC;YACvC,IAAI,GAAG,GAAe,MAAM,CAAC;YAC7B,OAAO,GAAG,EAAE,CAAC;gBACT,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;oBAChB,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,OAAO,IAAI,CAAC;gBAChB,CAAC;gBACD,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;YACrB,CAAC;YACD,8DAA8D;YAC9D,2DAA2D;YAC3D,yDAAyD;YACzD,2BAA2B;YAC3B,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC"}