@sigx/lynx-navigation 0.1.0 → 0.1.1
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.
- package/LICENSE +1 -1
- package/README.md +355 -0
- package/dist/components/Drawer.d.ts +58 -0
- package/dist/components/Drawer.d.ts.map +1 -0
- package/dist/components/Drawer.js +76 -0
- package/dist/components/Drawer.js.map +1 -0
- package/dist/components/EdgeBackHandle.js +144 -0
- package/dist/components/EdgeBackHandle.js.map +1 -0
- package/dist/components/EntryScope.d.ts +26 -0
- package/dist/components/EntryScope.d.ts.map +1 -0
- package/dist/components/EntryScope.js +33 -0
- package/dist/components/EntryScope.js.map +1 -0
- package/dist/components/Header.d.ts +7 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +103 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/Link.js +1 -4
- package/dist/components/Link.js.map +1 -1
- package/dist/components/NavigationRoot.d.ts +1 -1
- package/dist/components/NavigationRoot.d.ts.map +1 -1
- package/dist/components/NavigationRoot.js +29 -3
- package/dist/components/NavigationRoot.js.map +1 -1
- package/dist/components/Screen.d.ts +98 -0
- package/dist/components/Screen.d.ts.map +1 -0
- package/dist/components/Screen.js +94 -0
- package/dist/components/Screen.js.map +1 -0
- package/dist/components/ScreenContainer.d.ts.map +1 -1
- package/dist/components/ScreenContainer.js +77 -0
- package/dist/components/ScreenContainer.js.map +1 -0
- package/dist/components/Stack.d.ts.map +1 -1
- package/dist/components/Stack.js +60 -24
- package/dist/components/Stack.js.map +1 -1
- package/dist/components/TabBar.d.ts +40 -0
- package/dist/components/TabBar.d.ts.map +1 -0
- package/dist/components/TabBar.js +63 -0
- package/dist/components/TabBar.js.map +1 -0
- package/dist/components/Tabs.d.ts +101 -0
- package/dist/components/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs.js +135 -0
- package/dist/components/Tabs.js.map +1 -0
- package/dist/hooks/use-focus.d.ts +46 -0
- package/dist/hooks/use-focus.d.ts.map +1 -0
- package/dist/hooks/use-focus.js +77 -0
- package/dist/hooks/use-focus.js.map +1 -0
- package/dist/hooks/use-hardware-back.js +50 -0
- package/dist/hooks/use-hardware-back.js.map +1 -0
- package/dist/hooks/use-linking-nav.d.ts +92 -0
- package/dist/hooks/use-linking-nav.d.ts.map +1 -0
- package/dist/hooks/use-linking-nav.js +109 -0
- package/dist/hooks/use-linking-nav.js.map +1 -0
- package/dist/hooks/use-nav-internal.d.ts +38 -1
- package/dist/hooks/use-nav-internal.d.ts.map +1 -1
- package/dist/hooks/use-nav-internal.js +32 -0
- package/dist/hooks/use-nav-internal.js.map +1 -1
- package/dist/hooks/use-nav-serializer.d.ts +83 -0
- package/dist/hooks/use-nav-serializer.d.ts.map +1 -0
- package/dist/hooks/use-nav-serializer.js +181 -0
- package/dist/hooks/use-nav-serializer.js.map +1 -0
- package/dist/hooks/use-nav.js.map +1 -1
- package/dist/hooks/use-screen-options.d.ts +3 -0
- package/dist/hooks/use-screen-options.d.ts.map +1 -0
- package/dist/hooks/use-screen-options.js +43 -0
- package/dist/hooks/use-screen-options.js.map +1 -0
- package/dist/href.d.ts +16 -1
- package/dist/href.d.ts.map +1 -1
- package/dist/href.js +50 -7
- package/dist/href.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/screen-registry.d.ts +49 -0
- package/dist/internal/screen-registry.d.ts.map +1 -0
- package/dist/internal/screen-registry.js +59 -0
- package/dist/internal/screen-registry.js.map +1 -0
- package/dist/internal/screen-width.js +30 -0
- package/dist/internal/screen-width.js.map +1 -0
- package/dist/navigator/core.d.ts +20 -1
- package/dist/navigator/core.d.ts.map +1 -1
- package/dist/navigator/core.js +231 -36
- package/dist/navigator/core.js.map +1 -1
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/url/build.d.ts +16 -0
- package/dist/url/build.d.ts.map +1 -0
- package/dist/url/build.js +30 -0
- package/dist/url/build.js.map +1 -0
- package/dist/url/compile.d.ts +35 -0
- package/dist/url/compile.d.ts.map +1 -0
- package/dist/url/compile.js +83 -0
- package/dist/url/compile.js.map +1 -0
- package/dist/url/format.d.ts +26 -0
- package/dist/url/format.d.ts.map +1 -0
- package/dist/url/format.js +99 -0
- package/dist/url/format.js.map +1 -0
- package/dist/url/index.d.ts +13 -0
- package/dist/url/index.d.ts.map +1 -0
- package/dist/url/index.js +13 -0
- package/dist/url/index.js.map +1 -0
- package/dist/url/parse.d.ts +21 -0
- package/dist/url/parse.d.ts.map +1 -0
- package/dist/url/parse.js +90 -0
- package/dist/url/parse.js.map +1 -0
- package/dist/url/registry.d.ts +41 -0
- package/dist/url/registry.d.ts.map +1 -0
- package/dist/url/registry.js +56 -0
- package/dist/url/registry.js.map +1 -0
- package/dist/url/validate.d.ts +24 -0
- package/dist/url/validate.d.ts.map +1 -0
- package/dist/url/validate.js +37 -0
- package/dist/url/validate.js.map +1 -0
- package/package.json +44 -15
- package/src/components/Drawer.tsx +121 -0
- package/src/components/EdgeBackHandle.tsx +1 -1
- package/src/components/EntryScope.tsx +38 -0
- package/src/components/Header.tsx +124 -0
- package/src/components/NavigationRoot.tsx +9 -1
- package/src/components/Screen.tsx +116 -0
- package/src/components/ScreenContainer.tsx +14 -1
- package/src/components/Stack.tsx +21 -2
- package/src/components/TabBar.tsx +103 -0
- package/src/components/Tabs.tsx +212 -0
- package/src/hooks/use-focus.ts +77 -0
- package/src/hooks/use-linking-nav.ts +159 -0
- package/src/hooks/use-nav-internal.ts +48 -1
- package/src/hooks/use-nav-serializer.ts +239 -0
- package/src/hooks/use-screen-options.ts +48 -0
- package/src/href.ts +68 -11
- package/src/index.ts +29 -0
- package/src/internal/screen-registry.ts +89 -0
- package/src/navigator/core.ts +86 -4
- package/src/types.ts +56 -0
- package/src/url/build.ts +35 -0
- package/src/url/compile.ts +109 -0
- package/src/url/format.ts +92 -0
- package/src/url/index.ts +18 -0
- package/src/url/parse.ts +97 -0
- package/src/url/registry.ts +69 -0
- package/src/url/validate.ts +67 -0
package/LICENSE
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# @sigx/lynx-navigation
|
|
2
|
+
|
|
3
|
+
Type-first native navigator for [SignalX](https://github.com/signalxjs) on
|
|
4
|
+
Lynx. Define routes once with `defineRoutes`, augment the `Register`
|
|
5
|
+
interface, and every navigator API — `useNav`, `useParams`, `useSearch`,
|
|
6
|
+
`<Link>`, `<Tabs.Screen>`, `<Drawer>` — picks up precise per-route
|
|
7
|
+
param/search inference.
|
|
8
|
+
|
|
9
|
+
The navigator ships native UI primitives (Stack, Tabs, Drawer, modal
|
|
10
|
+
presentation), focus hooks, deep-link integration, lazy routes, screen
|
|
11
|
+
options, and persistence — all reactive via sigx signals, all typed.
|
|
12
|
+
|
|
13
|
+
> **Status — 1.0 candidate.** Public surface is frozen; every export below
|
|
14
|
+
> is locked by the test suite in `__tests__/public-surface.test.ts`. The
|
|
15
|
+
> remaining work before flipping `private: false` is benchmarks against
|
|
16
|
+
> the legacy switch-based pattern and the publish flow.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @sigx/lynx-navigation
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Peer-deps: `@sigx/lynx`, `@sigx/lynx-motion`. Optional but recommended:
|
|
25
|
+
[`@sigx/lynx-linking`](../lynx-linking) for deep-link wiring,
|
|
26
|
+
[`@sigx/lynx-storage`](../lynx-storage) for stack persistence.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// src/routes.ts
|
|
32
|
+
import { defineRoutes } from '@sigx/lynx-navigation';
|
|
33
|
+
import { z } from 'zod';
|
|
34
|
+
import { Home } from './screens/Home';
|
|
35
|
+
import { Profile } from './screens/Profile';
|
|
36
|
+
|
|
37
|
+
export const routes = defineRoutes({
|
|
38
|
+
home: { component: Home },
|
|
39
|
+
profile: {
|
|
40
|
+
component: Profile,
|
|
41
|
+
params: z.object({ id: z.string() }),
|
|
42
|
+
path: '/users/:id',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
declare module '@sigx/lynx-navigation' {
|
|
47
|
+
interface Register { routes: typeof routes }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// src/App.tsx
|
|
53
|
+
import { NavigationRoot, Stack } from '@sigx/lynx-navigation';
|
|
54
|
+
import { routes } from './routes';
|
|
55
|
+
|
|
56
|
+
export const App = () => (
|
|
57
|
+
<NavigationRoot routes={routes} initialRoute="home">
|
|
58
|
+
<Stack />
|
|
59
|
+
</NavigationRoot>
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`<NavigationRoot>` creates a fresh navigator instance and provides it via
|
|
64
|
+
sigx's `defineProvide`, so multiple roots (or tests) get isolated state.
|
|
65
|
+
`<Stack>` renders the top entry, and during a push/pop the previous entry
|
|
66
|
+
too — driven by an MT-side `SharedValue` so per-frame interpolation never
|
|
67
|
+
crosses to BG.
|
|
68
|
+
|
|
69
|
+
## API reference
|
|
70
|
+
|
|
71
|
+
### `defineRoutes(routes)`
|
|
72
|
+
|
|
73
|
+
Locks in a typed route map. Each entry is a `RouteDefinition`:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
interface RouteDefinition<P = unknown, S = unknown> {
|
|
77
|
+
component: ComponentLike; // sigx component or lazy(...)
|
|
78
|
+
params?: StandardSchemaV1<P>; // zod / valibot / arktype / etc.
|
|
79
|
+
search?: StandardSchemaV1<S>;
|
|
80
|
+
path?: string; // for deep-link parsing
|
|
81
|
+
presentation?: Presentation; // 'card' (default) | 'modal' | 'fullScreen' | 'transparent-modal'
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Augment `Register.routes` once with the return value of `defineRoutes`
|
|
86
|
+
and every other API gets typed.
|
|
87
|
+
|
|
88
|
+
### `<NavigationRoot>`
|
|
89
|
+
|
|
90
|
+
| Prop | Default | Notes |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `routes` | required | Output of `defineRoutes(...)`. |
|
|
93
|
+
| `initialRoute` | first key | Starting route at the bottom of the stack. |
|
|
94
|
+
| `initialParams` / `initialSearch` | `{}` | Required when `initialRoute` declares a schema. |
|
|
95
|
+
| `animated` | `true` | Disable in tests so navigations commit synchronously. |
|
|
96
|
+
| `edgeSwipeEnabled` | `true` | iOS edge-swipe-back. |
|
|
97
|
+
|
|
98
|
+
### `<Stack>`
|
|
99
|
+
|
|
100
|
+
Renders the topmost stack entry plus the entry beneath it during
|
|
101
|
+
transitions. No props — driven entirely by the navigator state.
|
|
102
|
+
|
|
103
|
+
### `<Screen>`
|
|
104
|
+
|
|
105
|
+
Per-route slot container. Lets a screen declare its header / tab-bar item
|
|
106
|
+
JSX inline alongside its body:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const Profile = component(() => () => (
|
|
110
|
+
<Screen>
|
|
111
|
+
<Screen.Header>
|
|
112
|
+
<view><text>Custom header</text></view>
|
|
113
|
+
</Screen.Header>
|
|
114
|
+
<Screen.HeaderRight>
|
|
115
|
+
<text bindtap={save}>Save</text>
|
|
116
|
+
</Screen.HeaderRight>
|
|
117
|
+
<Screen.TabBarItem>
|
|
118
|
+
{({ active }) => <text style={{ opacity: active ? 1 : 0.6 }}>Me</text>}
|
|
119
|
+
</Screen.TabBarItem>
|
|
120
|
+
|
|
121
|
+
<view><text>profile body</text></view>
|
|
122
|
+
</Screen>
|
|
123
|
+
));
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
All sub-slots are optional. Anything not declared falls back to the
|
|
127
|
+
navigator's default chrome.
|
|
128
|
+
|
|
129
|
+
### `<Header>`
|
|
130
|
+
|
|
131
|
+
Default navigator header. Reads the focused entry's `<Screen.Header>`
|
|
132
|
+
slot if set, otherwise renders `headerLeft | title | headerRight` with a
|
|
133
|
+
back button as the default `headerLeft` when `nav.canGoBack` is true.
|
|
134
|
+
Pulls `title` / `headerShown` / `gestureEnabled` from the focused
|
|
135
|
+
screen's `useScreenOptions(...)` registration.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<NavigationRoot routes={routes} initialRoute="home">
|
|
139
|
+
<Header />
|
|
140
|
+
<Stack />
|
|
141
|
+
</NavigationRoot>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `<Tabs>` + `<Tabs.Screen>` + `<TabBar>`
|
|
145
|
+
|
|
146
|
+
Persistent tab navigator. Each tab keeps its own stack across switches.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<Tabs initialTab="home">
|
|
150
|
+
<Tabs.Screen name="home" component={HomeStack} label="Home" />
|
|
151
|
+
<Tabs.Screen name="profile" component={ProfileStack} label="Me"
|
|
152
|
+
accessibilityLabel="Profile tab" />
|
|
153
|
+
<TabBar />
|
|
154
|
+
</Tabs>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`<TabBar>` is the default chrome — kebab-case `accessibility-*` props for
|
|
158
|
+
screen readers, opacity-based active marker, tap to switch. Pass
|
|
159
|
+
`renderTab={(info, ctx) => <view bindtap={ctx.onPress}>…</view>}` to
|
|
160
|
+
fully override per-item rendering.
|
|
161
|
+
|
|
162
|
+
`useTabs()` returns `{ active, setActive, tabs }` — reactive.
|
|
163
|
+
|
|
164
|
+
### `<Drawer>`
|
|
165
|
+
|
|
166
|
+
Off-canvas sidebar navigator.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<Drawer sidebar={() => <view><text>Menu</text></view>}>
|
|
170
|
+
<Stack />
|
|
171
|
+
</Drawer>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`useDrawer()` returns `{ isOpen, open(), close(), toggle() }`. The
|
|
175
|
+
sidebar is laid out absolutely on the left and toggled via `display`.
|
|
176
|
+
Gesture-driven open and slide-in animation are deferred to apps — wrap
|
|
177
|
+
your sidebar JSX in a motion component if you want it.
|
|
178
|
+
|
|
179
|
+
### `useNav()`
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const nav = useNav();
|
|
183
|
+
// readonly + reactive
|
|
184
|
+
nav.current // top StackEntry
|
|
185
|
+
nav.stack // StackEntry[]
|
|
186
|
+
nav.canGoBack // boolean
|
|
187
|
+
|
|
188
|
+
// mutators
|
|
189
|
+
nav.push('profile', { id: 'alice' });
|
|
190
|
+
nav.push('profile', { id: 'alice' }, { tab: 'about' });
|
|
191
|
+
nav.replace('home');
|
|
192
|
+
nav.pop();
|
|
193
|
+
nav.pop(2);
|
|
194
|
+
nav.popTo('home');
|
|
195
|
+
nav.popToRoot();
|
|
196
|
+
nav.reset([{ name: 'home', params: {}, search: {} }]);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Per-route overloaded — `params` is required iff the route declares a
|
|
200
|
+
`params` schema, and the value is type-checked against it.
|
|
201
|
+
|
|
202
|
+
### `<Link>`
|
|
203
|
+
|
|
204
|
+
JSX flavor of `nav.push`:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
<Link to="profile" params={{ id: 'alice' }} search={{ tab: 'about' }}>
|
|
208
|
+
Open Alice
|
|
209
|
+
</Link>
|
|
210
|
+
<Link to="home" replace>Reset</Link>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Same per-route conditional typing as `nav.push`.
|
|
214
|
+
|
|
215
|
+
### `useParams(name)` / `useSearch(name)`
|
|
216
|
+
|
|
217
|
+
Typed accessors for the *currently-mounted* route. Calling with the wrong
|
|
218
|
+
route name is a TS error.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const { id } = useParams('profile'); // { id: string }
|
|
222
|
+
const { tab } = useSearch('profile'); // { tab: 'posts' | 'about' }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `useFocusEffect(handler)` / `useIsFocused()`
|
|
226
|
+
|
|
227
|
+
`useIsFocused()` is a reactive boolean — `true` while this screen is the
|
|
228
|
+
visible top of its navigator. `useFocusEffect(() => () => cleanup)` runs
|
|
229
|
+
`handler` on focus and the returned function on blur. Use these to mount
|
|
230
|
+
side-effects (analytics, subscriptions, video playback) only while the
|
|
231
|
+
screen is visible.
|
|
232
|
+
|
|
233
|
+
### `useHardwareBack(handler)`
|
|
234
|
+
|
|
235
|
+
Subscribe to Android system-back / iOS edge-swipe. Return `true` to
|
|
236
|
+
swallow the press, `false`/`undefined` to let the navigator handle it.
|
|
237
|
+
|
|
238
|
+
### `useScreenOptions(options | () => options)`
|
|
239
|
+
|
|
240
|
+
Imperatively merge `ScreenOptions` (`title`, `headerShown`,
|
|
241
|
+
`gestureEnabled`) for the current screen. Pass a plain object for a
|
|
242
|
+
one-time merge; pass a function and every signal touched inside it is
|
|
243
|
+
tracked, so the options re-merge on change.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
const Profile = component(() => {
|
|
247
|
+
const { id } = useParams('profile');
|
|
248
|
+
useScreenOptions(() => ({ title: `User ${id}` }));
|
|
249
|
+
return () => <view><text>profile</text></view>;
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `useLinkingNav(options?)`
|
|
254
|
+
|
|
255
|
+
Bridges `@sigx/lynx-linking` URL events into the navigator. Call once
|
|
256
|
+
inside a `<NavigationRoot>` subtree. Options:
|
|
257
|
+
|
|
258
|
+
| Key | Notes |
|
|
259
|
+
|---|---|
|
|
260
|
+
| `prefixes` | Schemes to strip before parsing (`'myapp://'`, `'https://myapp.com'`). |
|
|
261
|
+
| `onURL(url, nav)` | Intercept before default dispatch. Call `nav.push` yourself to handle. |
|
|
262
|
+
| `onUnmatched(url)` | Fired for URLs no route matches. Default: silent. |
|
|
263
|
+
| `replaceInitial` | Use `replace` for cold-start URLs (default `true`). |
|
|
264
|
+
|
|
265
|
+
### `useNavSerializer(options)`
|
|
266
|
+
|
|
267
|
+
Persist the navigator's stack across launches. Adapter is yours to
|
|
268
|
+
implement — `@sigx/lynx-storage`, MMKV, AsyncStorage, anything.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
useNavSerializer({
|
|
272
|
+
storage: {
|
|
273
|
+
async load() { return JSON.parse(await Storage.get('nav')); },
|
|
274
|
+
async save(snap) { await Storage.set('nav', JSON.stringify(snap)); },
|
|
275
|
+
},
|
|
276
|
+
debounceMs: 250,
|
|
277
|
+
onRestored: (snap) => console.log('restored', snap.stack.length, 'entries'),
|
|
278
|
+
onRestoreError: (reason, err) => console.warn('restore failed', reason, err),
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Snapshots carry a `version` field (`NAV_SNAPSHOT_VERSION`) — bump it when
|
|
283
|
+
the schema changes and `onRestoreError` fires `'version'`.
|
|
284
|
+
|
|
285
|
+
### `hrefFor(name, params?, search?)` / `parseHref(input, routes)`
|
|
286
|
+
|
|
287
|
+
Build and parse path-style URLs declared by each route's `path` template:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
const href = hrefFor('profile', { id: 'alice' }, { tab: 'posts' });
|
|
291
|
+
// → "/users/alice?tab=posts"
|
|
292
|
+
|
|
293
|
+
const parsed = parseHref('/users/bob?tab=about', routes);
|
|
294
|
+
// → { name: 'profile', params: { id: 'bob' }, search: { tab: 'about' } }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Lazy routes
|
|
298
|
+
|
|
299
|
+
Routes can pass a `lazy(...)` component from `@sigx/lynx` (re-exports
|
|
300
|
+
`@sigx/runtime-core`'s `lazy` + `<Suspense>`). The navigator calls
|
|
301
|
+
`.preload()` on push so the chunk is fetched before the screen mounts:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
import { lazy } from '@sigx/lynx';
|
|
305
|
+
|
|
306
|
+
export const routes = defineRoutes({
|
|
307
|
+
home: { component: Home },
|
|
308
|
+
profile: { component: lazy(() => import('./screens/Profile')) },
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Wrap your `<Stack>` in `<Suspense fallback={…}>` to show a fallback while
|
|
313
|
+
the chunk loads. The bundler (rspeedy/rspack) needs to produce
|
|
314
|
+
Lynx-loadable chunks for the layered MT-bundle — see the `examples/`
|
|
315
|
+
folder for a working setup.
|
|
316
|
+
|
|
317
|
+
## Modal presentation
|
|
318
|
+
|
|
319
|
+
Set `presentation: 'modal' | 'fullScreen' | 'transparent-modal'` on a
|
|
320
|
+
route definition. Modals ship as stack entries with a different
|
|
321
|
+
transition (bottom-sheet style) — there's no separate `<Modal>`
|
|
322
|
+
navigator. Use `nav.pop()` to dismiss.
|
|
323
|
+
|
|
324
|
+
## Testing
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
import { render, act } from '@sigx/lynx-testing';
|
|
328
|
+
|
|
329
|
+
render(
|
|
330
|
+
<NavigationRoot routes={routes} initialRoute="home" animated={false}>
|
|
331
|
+
<Stack />
|
|
332
|
+
</NavigationRoot>,
|
|
333
|
+
);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Pass `animated={false}` so navigations commit synchronously — `lynx-testing`
|
|
337
|
+
has no MT runtime so the slide-from-right transition never completes
|
|
338
|
+
otherwise. Then `act(() => nav.push(...))` immediately re-renders.
|
|
339
|
+
|
|
340
|
+
## Runtime gotchas
|
|
341
|
+
|
|
342
|
+
- **`useMainThreadRef` will crash on BG.** Refs returned by sigx that bind
|
|
343
|
+
to MT-only host nodes blow up if you read them outside `runOnMainThread`.
|
|
344
|
+
- **`runOnBackground` closure capture.** Variables captured in the body
|
|
345
|
+
are snapshot at call time. Read signals via `.value` *inside* the body,
|
|
346
|
+
not at definition.
|
|
347
|
+
- **`SharedValue` writes must come from MT worklets.** The transition
|
|
348
|
+
layer enforces this — pushing to a `SharedValue` from BG silently no-ops.
|
|
349
|
+
- **Lynx has no `z-index`.** Layering is document-order. The navigator
|
|
350
|
+
renders the underneath entry first, then the top entry — overlap them
|
|
351
|
+
via `position: absolute` and an explicit offset.
|
|
352
|
+
|
|
353
|
+
## License
|
|
354
|
+
|
|
355
|
+
MIT
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Drawer>` — minimal off-canvas drawer navigator.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <NavigationRoot routes={routes}>
|
|
8
|
+
* <Drawer
|
|
9
|
+
* sidebar={() => <view><text>Menu</text></view>}
|
|
10
|
+
* >
|
|
11
|
+
* <Stack />
|
|
12
|
+
* </Drawer>
|
|
13
|
+
* </NavigationRoot>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* `useDrawer()` from inside any descendant gives `{ isOpen, open(), close(),
|
|
17
|
+
* toggle() }`. The sidebar is laid out absolutely on the left and is
|
|
18
|
+
* visible whenever `isOpen` is true.
|
|
19
|
+
*
|
|
20
|
+
* Scope: this slice ships the state primitive + the bare-bones layout.
|
|
21
|
+
* Gesture-driven open (edge swipe from the left) and MTS slide-in are out
|
|
22
|
+
* of scope — the app shell can wrap its sidebar JSX in its own transition.
|
|
23
|
+
*
|
|
24
|
+
* Design note: the sidebar is passed as a render function via the
|
|
25
|
+
* `sidebar` slot prop rather than a `<Drawer.Sidebar>` child. Mixing
|
|
26
|
+
* "register-yourself-as-a-fill" children with the parent's own visible
|
|
27
|
+
* layout creates a feedback loop in sigx's reactive scope (the parent's
|
|
28
|
+
* render reads the fill, child's setup writes it, parent re-renders,
|
|
29
|
+
* child re-mounts, …). A scoped slot avoids that entirely and the API
|
|
30
|
+
* is identical at the call site.
|
|
31
|
+
*
|
|
32
|
+
* `default` slot is the main content (almost always a `<Stack>`).
|
|
33
|
+
*/
|
|
34
|
+
import { type Define } from '@sigx/lynx';
|
|
35
|
+
/** Reactive controller returned by `useDrawer()`. */
|
|
36
|
+
export interface DrawerNav {
|
|
37
|
+
/** True when the drawer is currently visible. Reactive. */
|
|
38
|
+
readonly isOpen: boolean;
|
|
39
|
+
/** Opens the drawer. */
|
|
40
|
+
open(): void;
|
|
41
|
+
/** Closes the drawer. */
|
|
42
|
+
close(): void;
|
|
43
|
+
/** Toggles between open and closed. */
|
|
44
|
+
toggle(): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Access the enclosing Drawer navigator. Throws when called outside
|
|
48
|
+
* `<Drawer>`.
|
|
49
|
+
*/
|
|
50
|
+
export declare const useDrawer: import("@sigx/runtime-core").InjectableFunction<DrawerNav>;
|
|
51
|
+
type DrawerProps = Define.Prop<'initialOpen', boolean> & Define.Slot<'sidebar'> & Define.Slot<'default'>;
|
|
52
|
+
export declare const Drawer: import("@sigx/runtime-core").ComponentFactory<DrawerProps, void, {
|
|
53
|
+
sidebar: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
|
|
54
|
+
} & {
|
|
55
|
+
default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
|
|
56
|
+
}>;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=Drawer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../src/components/Drawer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAKH,KAAK,MAAM,EAEd,MAAM,YAAY,CAAC;AAEpB,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,wBAAwB;IACxB,IAAI,IAAI,IAAI,CAAC;IACb,yBAAyB;IACzB,KAAK,IAAI,IAAI,CAAC;IACd,uCAAuC;IACvC,MAAM,IAAI,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,4DAIpB,CAAC;AAEH,KAAK,WAAW,GACV,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GACnC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GACtB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAE7B,eAAO,MAAM,MAAM;;;;EAmDjB,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `<Drawer>` — minimal off-canvas drawer navigator.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <NavigationRoot routes={routes}>
|
|
9
|
+
* <Drawer
|
|
10
|
+
* sidebar={() => <view><text>Menu</text></view>}
|
|
11
|
+
* >
|
|
12
|
+
* <Stack />
|
|
13
|
+
* </Drawer>
|
|
14
|
+
* </NavigationRoot>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* `useDrawer()` from inside any descendant gives `{ isOpen, open(), close(),
|
|
18
|
+
* toggle() }`. The sidebar is laid out absolutely on the left and is
|
|
19
|
+
* visible whenever `isOpen` is true.
|
|
20
|
+
*
|
|
21
|
+
* Scope: this slice ships the state primitive + the bare-bones layout.
|
|
22
|
+
* Gesture-driven open (edge swipe from the left) and MTS slide-in are out
|
|
23
|
+
* of scope — the app shell can wrap its sidebar JSX in its own transition.
|
|
24
|
+
*
|
|
25
|
+
* Design note: the sidebar is passed as a render function via the
|
|
26
|
+
* `sidebar` slot prop rather than a `<Drawer.Sidebar>` child. Mixing
|
|
27
|
+
* "register-yourself-as-a-fill" children with the parent's own visible
|
|
28
|
+
* layout creates a feedback loop in sigx's reactive scope (the parent's
|
|
29
|
+
* render reads the fill, child's setup writes it, parent re-renders,
|
|
30
|
+
* child re-mounts, …). A scoped slot avoids that entirely and the API
|
|
31
|
+
* is identical at the call site.
|
|
32
|
+
*
|
|
33
|
+
* `default` slot is the main content (almost always a `<Stack>`).
|
|
34
|
+
*/
|
|
35
|
+
import { component, defineInjectable, defineProvide, signal, } from '@sigx/lynx';
|
|
36
|
+
/**
|
|
37
|
+
* Access the enclosing Drawer navigator. Throws when called outside
|
|
38
|
+
* `<Drawer>`.
|
|
39
|
+
*/
|
|
40
|
+
export const useDrawer = defineInjectable(() => {
|
|
41
|
+
throw new Error('[lynx-navigation] useDrawer() called outside of a <Drawer> component.');
|
|
42
|
+
});
|
|
43
|
+
export const Drawer = component(({ props, slots }) => {
|
|
44
|
+
// `isOpenSig` uses the `{value}` wrapper pattern — sigx's `signal()` of
|
|
45
|
+
// a primitive returns a proxy that requires `.value` reads; wrapping in
|
|
46
|
+
// an object makes the proxy carry a mutable boolean.
|
|
47
|
+
const isOpenSig = signal({
|
|
48
|
+
value: props.initialOpen === true,
|
|
49
|
+
});
|
|
50
|
+
const nav = {
|
|
51
|
+
get isOpen() {
|
|
52
|
+
return isOpenSig.value;
|
|
53
|
+
},
|
|
54
|
+
open() {
|
|
55
|
+
isOpenSig.value = true;
|
|
56
|
+
},
|
|
57
|
+
close() {
|
|
58
|
+
isOpenSig.value = false;
|
|
59
|
+
},
|
|
60
|
+
toggle() {
|
|
61
|
+
isOpenSig.value = !isOpenSig.value;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
defineProvide(useDrawer, () => nav);
|
|
65
|
+
return () => {
|
|
66
|
+
const open = isOpenSig.value;
|
|
67
|
+
return (_jsxs("view", { style: { width: '100%', height: '100%' }, children: [_jsx("view", { style: { width: '100%', height: '100%' }, children: slots.default?.() }), _jsx("view", { style: {
|
|
68
|
+
position: 'absolute',
|
|
69
|
+
left: 0,
|
|
70
|
+
top: 0,
|
|
71
|
+
bottom: 0,
|
|
72
|
+
display: open ? 'flex' : 'none',
|
|
73
|
+
}, children: slots.sidebar?.() })] }));
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=Drawer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Drawer.js","sourceRoot":"","sources":["../../src/components/Drawer.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EACH,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,MAAM,GAGT,MAAM,YAAY,CAAC;AAcpB;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAY,GAAG,EAAE;IACtD,MAAM,IAAI,KAAK,CACX,uEAAuE,CAC1E,CAAC;AACN,CAAC,CAAC,CAAC;AAOH,MAAM,CAAC,MAAM,MAAM,GAAG,SAAS,CAAc,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IAC9D,wEAAwE;IACxE,wEAAwE;IACxE,qDAAqD;IACrD,MAAM,SAAS,GAA+B,MAAM,CAAC;QACjD,KAAK,EAAE,KAAK,CAAC,WAAW,KAAK,IAAI;KACpC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAc;QACnB,IAAI,MAAM;YACN,OAAO,SAAS,CAAC,KAAK,CAAC;QAC3B,CAAC;QACD,IAAI;YACA,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,KAAK;YACD,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;QAC5B,CAAC;QACD,MAAM;YACF,SAAS,CAAC,KAAK,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC;QACvC,CAAC;KACJ,CAAC;IAEF,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAEpC,OAAO,GAAG,EAAE;QACR,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC;QAC7B,OAAO,CACH,gBAAM,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAE1C,eAAM,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YACzC,KAAK,CAAC,OAAO,EAAE,EAAE,GACf,EAKP,eACI,KAAK,EAAE;wBACH,QAAQ,EAAE,UAAU;wBACpB,IAAI,EAAE,CAAC;wBACP,GAAG,EAAE,CAAC;wBACN,MAAM,EAAE,CAAC;wBACT,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;qBAClC,YAEA,KAAK,CAAC,OAAO,EAAE,EAAE,GACf,IACJ,CACV,CAAC;IACN,CAAC,CAAC;AACN,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
+
import { component, Gesture, runOnBackground, useGestureDetector, useMainThreadRef, } from '@sigx/lynx';
|
|
3
|
+
import { withTiming } from '@sigx/lynx-motion';
|
|
4
|
+
import { useNavInternals } from '../hooks/use-nav-internal.js';
|
|
5
|
+
import { SCREEN_WIDTH } from '../internal/screen-width.js';
|
|
6
|
+
/**
|
|
7
|
+
* Edge-pan recognizer for iOS-style swipe-back. Mounts as an absolutely-
|
|
8
|
+
* positioned 20px-wide strip on the left edge of the active screen; only
|
|
9
|
+
* exists when `nav.canGoBack && !transition`.
|
|
10
|
+
*
|
|
11
|
+
* `Gesture.Pan().minDistance(MIN_DISTANCE)` lets quick taps pass through to
|
|
12
|
+
* whatever's behind the strip (back button, screen header, etc.). Only
|
|
13
|
+
* horizontal drags past the threshold activate the gesture.
|
|
14
|
+
*
|
|
15
|
+
* MT/BG split:
|
|
16
|
+
* - All gesture handlers run on MT. They write `progress.current.value`
|
|
17
|
+
* directly per frame (no per-frame bridge crossing) and dispatch
|
|
18
|
+
* `runOnBackground(...)` only at start/commit/cancel — three BG hops
|
|
19
|
+
* per gesture max.
|
|
20
|
+
* - The transition state machine on BG mounts the underneath
|
|
21
|
+
* `<ScreenContainer>` once `beginBackGesture` lands; the gesture's
|
|
22
|
+
* in-flight progress writes are picked up the moment the binding
|
|
23
|
+
* registers (Phase 0.5 polish: pre-mount underneath when canGoBack to
|
|
24
|
+
* eliminate the brief pre-mount latency).
|
|
25
|
+
*
|
|
26
|
+
* Implementation notes (matching `<Draggable>`):
|
|
27
|
+
* - Single `useMainThreadRef` holding an object — primitive refs don't
|
|
28
|
+
* survive worklet capture cleanly in some Lynx versions, while object
|
|
29
|
+
* refs do (the worklet runtime resolves the ref via the
|
|
30
|
+
* `_workletRefMap`).
|
|
31
|
+
* - `e: any` rather than `e: unknown` — type annotations are erased, but
|
|
32
|
+
* SWC's worklet transform has been observed to behave better with the
|
|
33
|
+
* looser annotation. Keeps us aligned with Draggable verbatim.
|
|
34
|
+
* - Empty `onBegin`: load-bearing on iOS — without a registered onBegin
|
|
35
|
+
* callback, `LynxPanGestureHandler` skips the begin path and onStart/
|
|
36
|
+
* onEnd never fire (per Draggable's notes).
|
|
37
|
+
*/
|
|
38
|
+
/** Fraction of screen width past which a release commits the back nav. */
|
|
39
|
+
const COMMIT_TRANSLATION = 0.33;
|
|
40
|
+
/** px/sec horizontal speed past which a release commits, regardless of distance. */
|
|
41
|
+
const COMMIT_VELOCITY = 300;
|
|
42
|
+
/** Width of the touchable strip on the left edge of every screen. */
|
|
43
|
+
const EDGE_ZONE_WIDTH = 20;
|
|
44
|
+
/** Minimum movement before the gesture activates (lets taps pass through). */
|
|
45
|
+
const MIN_DISTANCE = 8;
|
|
46
|
+
const SNAP_DURATION_SEC = 0.18;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-computed milliseconds for the BG-side `setTimeout`. Module-level so
|
|
49
|
+
* it's in scope for both the MT worklet (`withTiming` argument) and the BG
|
|
50
|
+
* callback wrapped by `runOnBackground` (`setTimeout` argument). Locals
|
|
51
|
+
* declared inside an MT worklet body are MT-only — the BG callback's
|
|
52
|
+
* closure can't see them, hence "ReferenceError: snapMs is not defined".
|
|
53
|
+
*/
|
|
54
|
+
const SNAP_DURATION_MS = Math.round(SNAP_DURATION_SEC * 1000);
|
|
55
|
+
export const EdgeBackHandle = component(() => {
|
|
56
|
+
const ref = useMainThreadRef(null);
|
|
57
|
+
// Per-gesture transient state — captured as a plain closure object
|
|
58
|
+
// rather than a `useMainThreadRef`. Lynx's SWC worklet transform deep-
|
|
59
|
+
// copies plain objects into `_c` once at register time; mutations on MT
|
|
60
|
+
// persist across calls because the same `_c` is bound for the lifetime
|
|
61
|
+
// of the gesture registration. Using a `useMainThreadRef` here was
|
|
62
|
+
// crashing on iOS with `cannot read property 'current' of undefined`
|
|
63
|
+
// — the resolved-ref capture path looked up an empty
|
|
64
|
+
// `_workletRefMap` entry under a race I haven't fully tracked down.
|
|
65
|
+
// Plain object avoids that path entirely.
|
|
66
|
+
const state = {
|
|
67
|
+
startPageX: 0,
|
|
68
|
+
prevPageX: 0,
|
|
69
|
+
prevTime: 0,
|
|
70
|
+
velocity: 0,
|
|
71
|
+
};
|
|
72
|
+
const internals = useNavInternals();
|
|
73
|
+
const progress = internals.progress;
|
|
74
|
+
const beginBackGesture = internals.beginBackGesture;
|
|
75
|
+
const commitBackGesture = internals.commitBackGesture;
|
|
76
|
+
const cancelBackGesture = internals.cancelBackGesture;
|
|
77
|
+
const pan = Gesture.Pan()
|
|
78
|
+
.minDistance(MIN_DISTANCE)
|
|
79
|
+
.onBegin(() => {
|
|
80
|
+
'main thread';
|
|
81
|
+
})
|
|
82
|
+
.onStart((e) => {
|
|
83
|
+
'main thread';
|
|
84
|
+
const p = e && e.params;
|
|
85
|
+
const pageX = (p && p.pageX) || 0;
|
|
86
|
+
state.startPageX = pageX;
|
|
87
|
+
state.prevPageX = pageX;
|
|
88
|
+
state.prevTime = Date.now();
|
|
89
|
+
state.velocity = 0;
|
|
90
|
+
runOnBackground(() => {
|
|
91
|
+
beginBackGesture();
|
|
92
|
+
})();
|
|
93
|
+
})
|
|
94
|
+
.onUpdate((e) => {
|
|
95
|
+
'main thread';
|
|
96
|
+
if (!progress)
|
|
97
|
+
return;
|
|
98
|
+
const p = e && e.params;
|
|
99
|
+
const pageX = (p && p.pageX) || 0;
|
|
100
|
+
const dx = pageX - state.startPageX;
|
|
101
|
+
const prog = Math.max(0, Math.min(1, dx / SCREEN_WIDTH));
|
|
102
|
+
progress.current.value = prog;
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
const dt = now - state.prevTime;
|
|
105
|
+
if (dt > 0) {
|
|
106
|
+
state.velocity =
|
|
107
|
+
((pageX - state.prevPageX) / dt) * 1000;
|
|
108
|
+
}
|
|
109
|
+
state.prevPageX = pageX;
|
|
110
|
+
state.prevTime = now;
|
|
111
|
+
})
|
|
112
|
+
.onEnd((e) => {
|
|
113
|
+
'main thread';
|
|
114
|
+
if (!progress)
|
|
115
|
+
return;
|
|
116
|
+
const p = e && e.params;
|
|
117
|
+
const pageX = (p && p.pageX) || 0;
|
|
118
|
+
const dx = pageX - state.startPageX;
|
|
119
|
+
const fraction = dx / SCREEN_WIDTH;
|
|
120
|
+
const commit = fraction > COMMIT_TRANSLATION ||
|
|
121
|
+
state.velocity > COMMIT_VELOCITY;
|
|
122
|
+
if (commit) {
|
|
123
|
+
withTiming(progress, 1, { duration: SNAP_DURATION_SEC });
|
|
124
|
+
runOnBackground(() => {
|
|
125
|
+
setTimeout(() => commitBackGesture(), SNAP_DURATION_MS);
|
|
126
|
+
})();
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
withTiming(progress, 0, { duration: SNAP_DURATION_SEC });
|
|
130
|
+
runOnBackground(() => {
|
|
131
|
+
setTimeout(() => cancelBackGesture(), SNAP_DURATION_MS);
|
|
132
|
+
})();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
useGestureDetector(ref, pan);
|
|
136
|
+
return () => (_jsx("view", { "main-thread:ref": ref, style: {
|
|
137
|
+
position: 'absolute',
|
|
138
|
+
top: '0',
|
|
139
|
+
left: '0',
|
|
140
|
+
width: `${EDGE_ZONE_WIDTH}px`,
|
|
141
|
+
bottom: '0',
|
|
142
|
+
} }));
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=EdgeBackHandle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EdgeBackHandle.js","sourceRoot":"","sources":["../../src/components/EdgeBackHandle.tsx"],"names":[],"mappings":"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"}
|