@sigx/lynx-navigation 0.1.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.
- package/LICENSE +21 -0
- package/dist/components/EdgeBackHandle.d.ts +2 -0
- package/dist/components/EdgeBackHandle.d.ts.map +1 -0
- package/dist/components/Link.d.ts +61 -0
- package/dist/components/Link.d.ts.map +1 -0
- package/dist/components/Link.js +54 -0
- package/dist/components/Link.js.map +1 -0
- package/dist/components/NavigationRoot.d.ts +37 -0
- package/dist/components/NavigationRoot.d.ts.map +1 -0
- package/dist/components/NavigationRoot.js +41 -0
- package/dist/components/NavigationRoot.js.map +1 -0
- package/dist/components/ScreenContainer.d.ts +18 -0
- package/dist/components/ScreenContainer.d.ts.map +1 -0
- package/dist/components/Stack.d.ts +21 -0
- package/dist/components/Stack.d.ts.map +1 -0
- package/dist/components/Stack.js +39 -0
- package/dist/components/Stack.js.map +1 -0
- package/dist/define-routes.d.ts +31 -0
- package/dist/define-routes.d.ts.map +1 -0
- package/dist/define-routes.js +32 -0
- package/dist/define-routes.js.map +1 -0
- package/dist/hooks/use-hardware-back.d.ts +31 -0
- package/dist/hooks/use-hardware-back.d.ts.map +1 -0
- package/dist/hooks/use-nav-internal.d.ts +37 -0
- package/dist/hooks/use-nav-internal.d.ts.map +1 -0
- package/dist/hooks/use-nav-internal.js +12 -0
- package/dist/hooks/use-nav-internal.js.map +1 -0
- package/dist/hooks/use-nav.d.ts +77 -0
- package/dist/hooks/use-nav.d.ts.map +1 -0
- package/dist/hooks/use-nav.js +11 -0
- package/dist/hooks/use-nav.js.map +1 -0
- package/dist/hooks/use-params.d.ts +19 -0
- package/dist/hooks/use-params.d.ts.map +1 -0
- package/dist/hooks/use-params.js +22 -0
- package/dist/hooks/use-params.js.map +1 -0
- package/dist/hooks/use-search.d.ts +11 -0
- package/dist/hooks/use-search.d.ts.map +1 -0
- package/dist/hooks/use-search.js +14 -0
- package/dist/hooks/use-search.js.map +1 -0
- package/dist/href.d.ts +40 -0
- package/dist/href.d.ts.map +1 -0
- package/dist/href.js +14 -0
- package/dist/href.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/screen-width.d.ts +16 -0
- package/dist/internal/screen-width.d.ts.map +1 -0
- package/dist/navigator/core.d.ts +51 -0
- package/dist/navigator/core.d.ts.map +1 -0
- package/dist/navigator/core.js +149 -0
- package/dist/navigator/core.js.map +1 -0
- package/dist/register.d.ts +38 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +2 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +162 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
- package/src/components/EdgeBackHandle.tsx +161 -0
- package/src/components/Link.tsx +113 -0
- package/src/components/NavigationRoot.tsx +85 -0
- package/src/components/ScreenContainer.tsx +101 -0
- package/src/components/Stack.tsx +99 -0
- package/src/define-routes.ts +33 -0
- package/src/hooks/use-hardware-back.ts +50 -0
- package/src/hooks/use-nav-internal.ts +47 -0
- package/src/hooks/use-nav.ts +118 -0
- package/src/hooks/use-params.ts +23 -0
- package/src/hooks/use-search.ts +15 -0
- package/src/href.ts +58 -0
- package/src/index.ts +38 -0
- package/src/internal/screen-width.ts +34 -0
- package/src/navigator/core.ts +386 -0
- package/src/register.ts +41 -0
- package/src/types.ts +171 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Andreas Ekdahl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EdgeBackHandle.d.ts","sourceRoot":"","sources":["../../src/components/EdgeBackHandle.tsx"],"names":[],"mappings":"AA+DA,eAAO,MAAM,cAAc,kEAiGzB,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { RouteId, RouteParams, RouteSearch } from '../register.js';
|
|
2
|
+
import type { RoutesWithParams } from '../hooks/use-nav.js';
|
|
3
|
+
/**
|
|
4
|
+
* Per-route conditional props for `<Link>`.
|
|
5
|
+
*
|
|
6
|
+
* Mapped over `RouteId`, then indexed by `RouteId` to flatten into a union.
|
|
7
|
+
* Each branch enforces the `params`-required-iff-route-has-schema rule:
|
|
8
|
+
*
|
|
9
|
+
* - `<Link to="profile" />` → TS error (profile requires params)
|
|
10
|
+
* - `<Link to="profile" params={...} />` → ok
|
|
11
|
+
* - `<Link to="home" />` → ok (home has no params)
|
|
12
|
+
* - `<Link to="home" params={...} />` → TS error (home accepts no params)
|
|
13
|
+
*
|
|
14
|
+
* Same per-route discrimination as `nav.push`, expressed as a JSX-friendly
|
|
15
|
+
* union rather than overloads.
|
|
16
|
+
*/
|
|
17
|
+
type LinkPropsByRoute = {
|
|
18
|
+
[K in RouteId]: K extends RoutesWithParams ? {
|
|
19
|
+
to: K;
|
|
20
|
+
params: RouteParams<K>;
|
|
21
|
+
search?: RouteSearch<K>;
|
|
22
|
+
} : {
|
|
23
|
+
to: K;
|
|
24
|
+
params?: undefined;
|
|
25
|
+
search?: RouteSearch<K>;
|
|
26
|
+
};
|
|
27
|
+
}[RouteId];
|
|
28
|
+
/**
|
|
29
|
+
* Public type for `<Link>`'s props. The conditional `LinkPropsByRoute` carries
|
|
30
|
+
* the typed `to`/`params`/`search` triple; the rest are simple optionals.
|
|
31
|
+
*
|
|
32
|
+
* `children` is declared explicitly because the public type is exposed via a
|
|
33
|
+
* type-cast (so JSX sees a function-shaped signature). The cast strips sigx's
|
|
34
|
+
* built-in `Define.Slot<'default'>` → JSX-children wiring, so we add a
|
|
35
|
+
* permissive `children?` slot ourselves.
|
|
36
|
+
*/
|
|
37
|
+
export type LinkProps = LinkPropsByRoute & {
|
|
38
|
+
/** Use `replace` instead of `push` (no new history entry). */
|
|
39
|
+
replace?: boolean;
|
|
40
|
+
/** Link content rendered inside the tappable container. */
|
|
41
|
+
children?: unknown;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Declarative navigation. Same typing as `nav.push` — pass `params` only when
|
|
45
|
+
* the route declares a schema. Wraps a `<view>` that fires `nav.push` (or
|
|
46
|
+
* `nav.replace` if `replace` is set) on tap.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* <Link to="home">Home</Link>
|
|
51
|
+
* <Link to="profile" params={{ id: '42' }}>View profile</Link>
|
|
52
|
+
* <Link to="profile" params={{ id: '42' }} search={{ tab: 'about' }}>About</Link>
|
|
53
|
+
* <Link to="settings" replace>Settings (no back)</Link>
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* The cast widens the inferred prop type from the loose impl to the strict
|
|
57
|
+
* `LinkProps` so JSX usage gets per-route discrimination. Runtime is identical.
|
|
58
|
+
*/
|
|
59
|
+
export declare const Link: (props: LinkProps) => unknown;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=Link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/components/Link.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,KAAK,gBAAgB,GAAG;KACnB,CAAC,IAAI,OAAO,GAAG,CAAC,SAAS,gBAAgB,GACpC;QAAE,EAAE,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;KAAE,GAC1D;QAAE,EAAE,EAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;KAAE;CAC/D,CAAC,OAAO,CAAC,CAAC;AAEX;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG;IACvC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAwDF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,IAAI,EAA0B,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
+
import { component } from '@sigx/lynx';
|
|
3
|
+
import { useNav } from '../hooks/use-nav.js';
|
|
4
|
+
import { useNavRoutes } from '../hooks/use-nav-internal.js';
|
|
5
|
+
const LinkImpl = component(({ props, slots }) => {
|
|
6
|
+
const nav = useNav();
|
|
7
|
+
const routes = useNavRoutes();
|
|
8
|
+
const handlePress = () => {
|
|
9
|
+
const route = props.to;
|
|
10
|
+
const routeDef = routes[route];
|
|
11
|
+
if (!routeDef) {
|
|
12
|
+
// Defensive: prop was typed against the registry, so this shouldn't
|
|
13
|
+
// happen at runtime — but if it does (e.g. a stale Link survived a
|
|
14
|
+
// route removal), surface a clear error rather than crashing on
|
|
15
|
+
// the navigator's lookup.
|
|
16
|
+
throw new Error(`[lynx-navigation] <Link to='${route}'>: route is not registered.`);
|
|
17
|
+
}
|
|
18
|
+
const hasParams = !!routeDef.params;
|
|
19
|
+
const action = props.replace ? nav.replace : nav.push;
|
|
20
|
+
// Branch on whether the route declares a params schema so positional
|
|
21
|
+
// args land correctly: routes-with-params shift everything one slot
|
|
22
|
+
// (push/replace overload signatures `(name, params, search?, options?)`
|
|
23
|
+
// vs `(name, search?, options?)`). Calling the wrong shape silently
|
|
24
|
+
// puts `search` into the `options` slot.
|
|
25
|
+
if (hasParams) {
|
|
26
|
+
action(route, props.params, props.search);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
action(route, props.search);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return () => (
|
|
33
|
+
// `bindtap` is correct here because the underlying element is a Lynx
|
|
34
|
+
// native `<view>` — sigx component-level events would use `onPress`.
|
|
35
|
+
_jsx("view", { bindtap: handlePress, children: slots.default?.() }));
|
|
36
|
+
}, { name: 'Link' });
|
|
37
|
+
/**
|
|
38
|
+
* Declarative navigation. Same typing as `nav.push` — pass `params` only when
|
|
39
|
+
* the route declares a schema. Wraps a `<view>` that fires `nav.push` (or
|
|
40
|
+
* `nav.replace` if `replace` is set) on tap.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <Link to="home">Home</Link>
|
|
45
|
+
* <Link to="profile" params={{ id: '42' }}>View profile</Link>
|
|
46
|
+
* <Link to="profile" params={{ id: '42' }} search={{ tab: 'about' }}>About</Link>
|
|
47
|
+
* <Link to="settings" replace>Settings (no back)</Link>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* The cast widens the inferred prop type from the loose impl to the strict
|
|
51
|
+
* `LinkProps` so JSX usage gets per-route discrimination. Runtime is identical.
|
|
52
|
+
*/
|
|
53
|
+
export const Link = LinkImpl;
|
|
54
|
+
//# sourceMappingURL=Link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/components/Link.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAqD5D,MAAM,QAAQ,GAAG,SAAS,CAAiB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5D,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,MAAM,WAAW,GAAG,GAAS,EAAE;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,oEAAoE;YACpE,mEAAmE;YACnE,gEAAgE;YAChE,0BAA0B;YAC1B,MAAM,IAAI,KAAK,CACX,+BAA+B,KAAK,8BAA8B,CACrE,CAAC;QACN,CAAC;QACD,MAAM,SAAS,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QACtD,qEAAqE;QACrE,oEAAoE;QACpE,wEAAwE;QACxE,oEAAoE;QACpE,yCAAyC;QACzC,IAAI,SAAS,EAAE,CAAC;YACX,MAAuD,CACpD,KAAK,EACL,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,MAAM,CACf,CAAC;QACN,CAAC;aAAM,CAAC;YACH,MAA2C,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACtE,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,GAAG,EAAE,CAAC;IACT,qEAAqE;IACrE,qEAAqE;IACrE,eAAM,OAAO,EAAE,WAAW,YAAG,KAAK,CAAC,OAAO,EAAE,EAAE,GAAQ,CACzD,CAAC;AACN,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAErB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,QAAoD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Define } from '@sigx/lynx';
|
|
2
|
+
import type { RouteId } from '../register.js';
|
|
3
|
+
import type { RouteMap } from '../types.js';
|
|
4
|
+
type NavigationRootProps = Define.Prop<'routes', RouteMap, true> & Define.Prop<'initialRoute', RouteId> & Define.Prop<'initialParams', Record<string, unknown>> & Define.Prop<'initialSearch', Record<string, unknown>>
|
|
5
|
+
/**
|
|
6
|
+
* Enable slide-from-right transitions on push/pop. Defaults to true.
|
|
7
|
+
* Tests against `@sigx/testing-lynx` (which doesn't have an MT runtime)
|
|
8
|
+
* should pass `animated={false}` so navigations commit synchronously.
|
|
9
|
+
*/
|
|
10
|
+
& Define.Prop<'animated', boolean>
|
|
11
|
+
/**
|
|
12
|
+
* Enable the iOS-style edge-swipe-back gesture. Defaults to true. Set
|
|
13
|
+
* to false if it conflicts with screen content on the leftmost 20px,
|
|
14
|
+
* or while debugging gesture issues.
|
|
15
|
+
*/
|
|
16
|
+
& Define.Prop<'edgeSwipeEnabled', boolean> & Define.Slot<'default'>;
|
|
17
|
+
/**
|
|
18
|
+
* Root of a navigator subtree.
|
|
19
|
+
*
|
|
20
|
+
* Creates a fresh `NavigatorState` from `routes` and provides it via
|
|
21
|
+
* `defineProvide`, so descendant `<Stack>` / `<Screen>` components and any
|
|
22
|
+
* `useNav()` / `useParams()` calls resolve through this instance.
|
|
23
|
+
*
|
|
24
|
+
* The bottom-of-stack entry is built from `initialRoute` (defaults to the
|
|
25
|
+
* first key in `routes`). For routes that declare a params schema, you must
|
|
26
|
+
* pass `initialParams` matching that schema.
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the install pattern of `@sigx/router` (see
|
|
29
|
+
* `packages/router/src/router.ts:519-528`), but at component scope rather than
|
|
30
|
+
* `app.use(router)` — no app-wide singleton, so multi-navigator apps and
|
|
31
|
+
* tests get isolated state for free.
|
|
32
|
+
*/
|
|
33
|
+
export declare const NavigationRoot: import("@sigx/runtime-core").ComponentFactory<NavigationRootProps, void, {
|
|
34
|
+
default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
|
|
35
|
+
}>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=NavigationRoot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavigationRoot.d.ts","sourceRoot":"","sources":["../../src/components/NavigationRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAInF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAgB,QAAQ,EAAc,MAAM,aAAa,CAAC;AAEtE,KAAK,mBAAmB,GAClB,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,GACrC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GACpC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACrD,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACvD;;;;GAIG;GACD,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;AAClC;;;;GAIG;GACD,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,GACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAE7B;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc;;EA0CzB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { component, defineProvide } from '@sigx/lynx';
|
|
2
|
+
import { createNavigatorState } from '../navigator/core.js';
|
|
3
|
+
import { useNav } from '../hooks/use-nav.js';
|
|
4
|
+
import { useNavRoutes } from '../hooks/use-nav-internal.js';
|
|
5
|
+
/**
|
|
6
|
+
* Root of a navigator subtree.
|
|
7
|
+
*
|
|
8
|
+
* Creates a fresh `NavigatorState` from `routes` and provides it via
|
|
9
|
+
* `defineProvide`, so descendant `<Stack>` / `<Screen>` components and any
|
|
10
|
+
* `useNav()` / `useParams()` calls resolve through this instance.
|
|
11
|
+
*
|
|
12
|
+
* The bottom-of-stack entry is built from `initialRoute` (defaults to the
|
|
13
|
+
* first key in `routes`). For routes that declare a params schema, you must
|
|
14
|
+
* pass `initialParams` matching that schema.
|
|
15
|
+
*
|
|
16
|
+
* Mirrors the install pattern of `@sigx/router` (see
|
|
17
|
+
* `packages/router/src/router.ts:519-528`), but at component scope rather than
|
|
18
|
+
* `app.use(router)` — no app-wide singleton, so multi-navigator apps and
|
|
19
|
+
* tests get isolated state for free.
|
|
20
|
+
*/
|
|
21
|
+
export const NavigationRoot = component(({ props, slots }) => {
|
|
22
|
+
const routes = props.routes;
|
|
23
|
+
const initialName = props.initialRoute ?? Object.keys(routes)[0];
|
|
24
|
+
if (!routes[initialName]) {
|
|
25
|
+
throw new Error(`[lynx-navigation] <NavigationRoot> initialRoute='${initialName}' is not in the routes registry.`);
|
|
26
|
+
}
|
|
27
|
+
const initialPresentation = routes[initialName].presentation ?? 'card';
|
|
28
|
+
const initial = {
|
|
29
|
+
key: 'root',
|
|
30
|
+
route: initialName,
|
|
31
|
+
params: props.initialParams ?? {},
|
|
32
|
+
search: props.initialSearch ?? {},
|
|
33
|
+
state: undefined,
|
|
34
|
+
presentation: initialPresentation,
|
|
35
|
+
};
|
|
36
|
+
const navState = createNavigatorState(routes, initial);
|
|
37
|
+
defineProvide(useNav, () => navState.nav);
|
|
38
|
+
defineProvide(useNavRoutes, () => navState.routes);
|
|
39
|
+
return () => slots.default?.();
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=NavigationRoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavigationRoot.js","sourceRoot":"","sources":["../../src/components/NavigationRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAe,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAW5D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAsB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IAC9E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,WAAW,GAAW,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACX,oDAAoD,WAAW,kCAAkC,CACpG,CAAC;IACN,CAAC;IACD,MAAM,mBAAmB,GAAiB,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,IAAI,MAAM,CAAC;IACrF,MAAM,OAAO,GAAe;QACxB,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE,KAAK,CAAC,aAAa,IAAI,EAAE;QACjC,MAAM,EAAE,KAAK,CAAC,aAAa,IAAI,EAAE;QACjC,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,mBAAmB;KACpC,CAAC;IAEF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEvD,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC1C,aAAa,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEnD,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;AACnC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ComponentFactory, type Define, type SharedValue } from '@sigx/lynx';
|
|
2
|
+
import type { RouteMap, StackEntry, TransitionKind, TransitionRole } from '../types.js';
|
|
3
|
+
type ScreenContainerProps = Define.Prop<'entry', StackEntry, true> & Define.Prop<'routes', RouteMap, true> & Define.Prop<'role', TransitionRole, true> & Define.Prop<'kind', TransitionKind, true> & Define.Prop<'progress', SharedValue<number>, true>;
|
|
4
|
+
/**
|
|
5
|
+
* Animated screen slot — absolutely positioned, MT-bound translateX driven by
|
|
6
|
+
* the navigator's progress SharedValue. Used during transitions to render the
|
|
7
|
+
* top + underneath entries together.
|
|
8
|
+
*
|
|
9
|
+
* Each instance is keyed by `${entry.key}-${role}-${kind}` in the parent so a
|
|
10
|
+
* role/kind change forces a fresh mount with a fresh `useAnimatedStyle`
|
|
11
|
+
* binding (the binding is set at setup and can't be re-keyed mid-life). State
|
|
12
|
+
* loss across transition boundaries is accepted in v0.2; persistent screen
|
|
13
|
+
* state (scroll position, input fields surviving navigations) is a polish
|
|
14
|
+
* item for Phase 0.5+.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ScreenContainer: ComponentFactory<ScreenContainerProps, void, {}>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=ScreenContainer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenContainer.d.ts","sourceRoot":"","sources":["../../src/components/ScreenContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,gBAAgB,EACrB,KAAK,MAAM,EAEX,KAAK,WAAW,EACnB,MAAM,YAAY,CAAC;AAGpB,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAuCxF,KAAK,oBAAoB,GACnB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,GACtC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,GACrC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GACzC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GACzC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,kDA+B1B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ComponentFactory } from '@sigx/lynx';
|
|
2
|
+
/**
|
|
3
|
+
* Stack navigator — renders the topmost stack entry's component at rest, or
|
|
4
|
+
* the top + underneath entries during a transition.
|
|
5
|
+
*
|
|
6
|
+
* **Idle**: just the top entry, full-bleed, no transform. The screen
|
|
7
|
+
* component mounts directly so it can use its own layout (no extra absolute
|
|
8
|
+
* positioning that would break percentage heights).
|
|
9
|
+
*
|
|
10
|
+
* **Transitioning**: two `<ScreenContainer>` instances stacked absolutely,
|
|
11
|
+
* each with an MT-driven `translateX` that reads from the navigator's
|
|
12
|
+
* progress `SharedValue`. The host's BG thread doesn't tick per frame —
|
|
13
|
+
* `useAnimatedStyle` runs the interpolation entirely on MT.
|
|
14
|
+
*
|
|
15
|
+
* `key={top.key}` keeps the idle render's component instance stable across
|
|
16
|
+
* unrelated re-renders. During transitions, composite keys
|
|
17
|
+
* (`${entry.key}-${role}-${kind}`) ensure a fresh mount per role/kind pair so
|
|
18
|
+
* the `useAnimatedStyle` binding is set with the right input/output ranges.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Stack: ComponentFactory<{}, void, unknown>;
|
|
21
|
+
//# sourceMappingURL=Stack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.d.ts","sourceRoot":"","sources":["../../src/components/Stack.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAMhF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,KAAK,qCA0EhB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
+
import { component } from '@sigx/lynx';
|
|
3
|
+
import { useNav } from '../hooks/use-nav.js';
|
|
4
|
+
import { useNavRoutes } from '../hooks/use-nav-internal.js';
|
|
5
|
+
/**
|
|
6
|
+
* Stack navigator — renders the topmost stack entry's component.
|
|
7
|
+
*
|
|
8
|
+
* v0.1 minimal slice: renders only the top entry, with no transition and no
|
|
9
|
+
* preserved-mount lower entries. Phase 0.2 extends this to mount the
|
|
10
|
+
* top-N entries (so back-swipe can show the underlying screen) and runs MTS
|
|
11
|
+
* transition drivers between them.
|
|
12
|
+
*
|
|
13
|
+
* `key={top.key}` forces unmount/remount when the active entry changes — same
|
|
14
|
+
* pattern `@sigx/router`'s `<RouterView>` uses to prevent lazy components
|
|
15
|
+
* from stacking (`packages/router/src/RouterView.tsx:97-98`).
|
|
16
|
+
*/
|
|
17
|
+
export const Stack = component(() => {
|
|
18
|
+
const nav = useNav();
|
|
19
|
+
const routes = useNavRoutes();
|
|
20
|
+
return () => {
|
|
21
|
+
const top = nav.current;
|
|
22
|
+
const route = routes[top.route];
|
|
23
|
+
if (!route) {
|
|
24
|
+
// Defensive: navigator state should never reference an unregistered
|
|
25
|
+
// route, but if it does we surface nothing rather than crash.
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const Comp = route.component;
|
|
29
|
+
if (typeof Comp !== 'function')
|
|
30
|
+
return null;
|
|
31
|
+
// Phase 0.1 only handles eager component factories. Lazy
|
|
32
|
+
// imports — `() => import(...)` — need a `lazy()` wrapper from sigx;
|
|
33
|
+
// we'll integrate that in the showcase-migration slice.
|
|
34
|
+
const ComponentFactoryRef = Comp;
|
|
35
|
+
const params = top.params;
|
|
36
|
+
return _jsx(ComponentFactoryRef, { ...params }, top.key);
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=Stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.js","sourceRoot":"","sources":["../../src/components/Stack.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAyB,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,EAAE;IAChC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,OAAO,GAAG,EAAE;QACR,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,oEAAoE;YACpE,8DAA8D;YAC9D,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;QAC7B,IAAI,OAAO,IAAI,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC;QAC5C,yDAAyD;QACzD,qEAAqE;QACrE,wDAAwD;QACxD,MAAM,mBAAmB,GAAG,IAI3B,CAAC;QACF,MAAM,MAAM,GAAG,GAAG,CAAC,MAAiC,CAAC;QACrD,OAAO,KAAC,mBAAmB,OAAmB,MAAM,IAAnB,GAAG,CAAC,GAAG,CAAgB,CAAC;IAC7D,CAAC,CAAC;AACN,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RouteMap } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Define a typed route registry.
|
|
4
|
+
*
|
|
5
|
+
* Returns the input verbatim at runtime — the function exists for TypeScript
|
|
6
|
+
* inference. The returned type is narrowed to the literal route map so that
|
|
7
|
+
* downstream APIs (`useNav`, `useParams`, `<Link>`) can extract route names
|
|
8
|
+
* and params/search schemas precisely.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { defineRoutes } from '@sigx/lynx-navigation';
|
|
13
|
+
* import { z } from 'zod';
|
|
14
|
+
*
|
|
15
|
+
* export const routes = defineRoutes({
|
|
16
|
+
* home: { component: lazy(() => import('./Home')) },
|
|
17
|
+
* profile: {
|
|
18
|
+
* params: z.object({ id: z.string() }),
|
|
19
|
+
* component: lazy(() => import('./Profile')),
|
|
20
|
+
* path: '/users/:id',
|
|
21
|
+
* },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Then in app entry:
|
|
25
|
+
* declare module '@sigx/lynx-navigation' {
|
|
26
|
+
* interface Register { routes: typeof routes }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function defineRoutes<const T extends RouteMap>(routes: T): T;
|
|
31
|
+
//# sourceMappingURL=define-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-routes.d.ts","sourceRoot":"","sources":["../src/define-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAEnE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define a typed route registry.
|
|
3
|
+
*
|
|
4
|
+
* Returns the input verbatim at runtime — the function exists for TypeScript
|
|
5
|
+
* inference. The returned type is narrowed to the literal route map so that
|
|
6
|
+
* downstream APIs (`useNav`, `useParams`, `<Link>`) can extract route names
|
|
7
|
+
* and params/search schemas precisely.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { defineRoutes } from '@sigx/lynx-navigation';
|
|
12
|
+
* import { z } from 'zod';
|
|
13
|
+
*
|
|
14
|
+
* export const routes = defineRoutes({
|
|
15
|
+
* home: { component: lazy(() => import('./Home')) },
|
|
16
|
+
* profile: {
|
|
17
|
+
* params: z.object({ id: z.string() }),
|
|
18
|
+
* component: lazy(() => import('./Profile')),
|
|
19
|
+
* path: '/users/:id',
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Then in app entry:
|
|
24
|
+
* declare module '@sigx/lynx-navigation' {
|
|
25
|
+
* interface Register { routes: typeof routes }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function defineRoutes(routes) {
|
|
30
|
+
return routes;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=define-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire the Android hardware back button to the active navigator.
|
|
3
|
+
*
|
|
4
|
+
* Listens for `hardwareBackPress` events from `@sigx/lynx-linking`'s
|
|
5
|
+
* `BackHandler` (which the native side dispatches from
|
|
6
|
+
* `MainActivity.onBackPressed`). On press:
|
|
7
|
+
*
|
|
8
|
+
* - If `nav.canGoBack` → `nav.pop()`.
|
|
9
|
+
* - Otherwise → `BackHandler.exitApp()` (Android: `moveTaskToBack(true)`,
|
|
10
|
+
* keeps the bundle warm; iOS: rejects, since iOS doesn't permit
|
|
11
|
+
* programmatic termination).
|
|
12
|
+
*
|
|
13
|
+
* Call this once in any component under `<NavigationRoot>` (typically a
|
|
14
|
+
* thin wrapper sibling to `<Stack />`). iOS doesn't fire the event so the
|
|
15
|
+
* hook is a no-op there.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const BackHandlerWiring = component(() => {
|
|
20
|
+
* useHardwareBack();
|
|
21
|
+
* return () => null;
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* <NavigationRoot routes={routes}>
|
|
25
|
+
* <BackHandlerWiring />
|
|
26
|
+
* <Stack />
|
|
27
|
+
* </NavigationRoot>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function useHardwareBack(): void;
|
|
31
|
+
//# sourceMappingURL=use-hardware-back.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-hardware-back.d.ts","sourceRoot":"","sources":["../../src/hooks/use-hardware-back.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAgBtC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type SharedValue } from '@sigx/lynx';
|
|
2
|
+
import type { RouteMap } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Internal injectable: the route registry passed into `<NavigationRoot>`.
|
|
5
|
+
* Components (Stack, Screen) read this to look up route definitions by name.
|
|
6
|
+
*
|
|
7
|
+
* Not exported from the package barrel — use `useNav()` for navigation, and
|
|
8
|
+
* the registry is implicit from `<NavigationRoot routes={...}>`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const useNavRoutes: import("@sigx/runtime-core").InjectableFunction<RouteMap>;
|
|
11
|
+
/**
|
|
12
|
+
* Internal injectable: low-level navigator handles used by the edge-back
|
|
13
|
+
* gesture. Holds the progress SharedValue (so gesture worklets can write it
|
|
14
|
+
* directly on MT) plus BG-side begin/commit/cancel functions invoked via
|
|
15
|
+
* `runOnBackground` from gesture worklets.
|
|
16
|
+
*
|
|
17
|
+
* `progress` is `null` when the navigator was created with `animated={false}`
|
|
18
|
+
* (e.g. tests). `beginBackGesture` is also a no-op in that case.
|
|
19
|
+
*/
|
|
20
|
+
export interface NavInternals {
|
|
21
|
+
/** MT-driven transition progress; null when animations are disabled. */
|
|
22
|
+
readonly progress: SharedValue<number> | null;
|
|
23
|
+
/**
|
|
24
|
+
* Set transition state for a gesture-driven pop. Does not start any
|
|
25
|
+
* automatic animation — the gesture worklet writes `progress` directly
|
|
26
|
+
* per frame, then animates to the commit/cancel endpoint on release.
|
|
27
|
+
*/
|
|
28
|
+
beginBackGesture(): void;
|
|
29
|
+
/** Commit the back gesture: pop top entry + clear transition. */
|
|
30
|
+
commitBackGesture(): void;
|
|
31
|
+
/** Cancel the back gesture: clear transition without popping. */
|
|
32
|
+
cancelBackGesture(): void;
|
|
33
|
+
/** Whether the user opted into the edge-swipe-back gesture. */
|
|
34
|
+
readonly edgeSwipeEnabled: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare const useNavInternals: import("@sigx/runtime-core").InjectableFunction<NavInternals>;
|
|
37
|
+
//# sourceMappingURL=use-nav-internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-nav-internal.d.ts","sourceRoot":"","sources":["../../src/hooks/use-nav-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,2DAIvB,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IACzB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC9C;;;;OAIG;IACH,gBAAgB,IAAI,IAAI,CAAC;IACzB,iEAAiE;IACjE,iBAAiB,IAAI,IAAI,CAAC;IAC1B,iEAAiE;IACjE,iBAAiB,IAAI,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACtC;AAED,eAAO,MAAM,eAAe,+DAI1B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineInjectable } from '@sigx/lynx';
|
|
2
|
+
/**
|
|
3
|
+
* Internal injectable: the route registry passed into `<NavigationRoot>`.
|
|
4
|
+
* Components (Stack, Screen) read this to look up route definitions by name.
|
|
5
|
+
*
|
|
6
|
+
* Not exported from the package barrel — use `useNav()` for navigation, and
|
|
7
|
+
* the registry is implicit from `<NavigationRoot routes={...}>`.
|
|
8
|
+
*/
|
|
9
|
+
export const useNavRoutes = defineInjectable(() => {
|
|
10
|
+
throw new Error('[lynx-navigation] No <NavigationRoot> found in the component tree.');
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=use-nav-internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-nav-internal.js","sourceRoot":"","sources":["../../src/hooks/use-nav-internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAW,GAAG,EAAE;IACxD,MAAM,IAAI,KAAK,CACX,oEAAoE,CACvE,CAAC;AACN,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { RegisteredRoutes, RouteId, RouteParams, RouteSearch } from '../register.js';
|
|
2
|
+
import type { PopOptions, PushOptions, RouteRequiresParams, StackEntry, TransitionState } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Subset of registered route names that declare a `params` schema (and so
|
|
5
|
+
* require a `params` argument when navigating).
|
|
6
|
+
*
|
|
7
|
+
* Computed via mapped-type filtering rather than a conditional inside the
|
|
8
|
+
* method signature: when a conditional like `RouteRequiresParams<R[K]>` is
|
|
9
|
+
* embedded inside a generic method parameter, TS evaluates it at definition
|
|
10
|
+
* time with K bound to the *whole* union of route ids — which distributes
|
|
11
|
+
* `RouteRequiresParams` over every route and collapses the result to
|
|
12
|
+
* `boolean`, breaking the conditional. Filtering once at the type level avoids
|
|
13
|
+
* the issue and produces clean overload candidates.
|
|
14
|
+
*/
|
|
15
|
+
export type RoutesWithParams = {
|
|
16
|
+
[K in RouteId]: RouteRequiresParams<RegisteredRoutes[K]> extends true ? K : never;
|
|
17
|
+
}[RouteId];
|
|
18
|
+
/** Routes that don't declare a `params` schema. */
|
|
19
|
+
export type RoutesWithoutParams = Exclude<RouteId, RoutesWithParams>;
|
|
20
|
+
/**
|
|
21
|
+
* The navigator handle returned by `useNav()`.
|
|
22
|
+
*
|
|
23
|
+
* Read access (`current`, `stack`, `canGoBack`) is reactive — these properties
|
|
24
|
+
* are getters that read from the underlying stack signal, so accessing them
|
|
25
|
+
* inside a component's render function (or inside `effect` / `computed`) takes
|
|
26
|
+
* a reactive dependency. Mutating methods (`push`, `pop`, etc.) trigger the
|
|
27
|
+
* dependents to update.
|
|
28
|
+
*
|
|
29
|
+
* `push` and `replace` are split into two overloads — one for routes without a
|
|
30
|
+
* params schema (no params arg) and one for routes with a params schema
|
|
31
|
+
* (params required). See `RoutesWithParams` above for why this isn't a single
|
|
32
|
+
* conditional return type.
|
|
33
|
+
*/
|
|
34
|
+
export interface Nav {
|
|
35
|
+
/** Push a route that has no params schema. */
|
|
36
|
+
push<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>, options?: PushOptions): void;
|
|
37
|
+
/** Push a route that requires params. */
|
|
38
|
+
push<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>, options?: PushOptions): void;
|
|
39
|
+
/** Replace the top entry — same overload pattern as push. */
|
|
40
|
+
replace<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>, options?: PushOptions): void;
|
|
41
|
+
replace<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>, options?: PushOptions): void;
|
|
42
|
+
/** Pop one or more entries off the top of the stack. */
|
|
43
|
+
pop(count?: number, options?: PopOptions): void;
|
|
44
|
+
/** Pop entries until the named route is at the top. */
|
|
45
|
+
popTo<K extends RouteId>(name: K): void;
|
|
46
|
+
/** Pop all the way to the root entry. */
|
|
47
|
+
popToRoot(): void;
|
|
48
|
+
/** Wholesale-replace the stack. */
|
|
49
|
+
reset(state: {
|
|
50
|
+
stack: ReadonlyArray<StackEntry>;
|
|
51
|
+
}): void;
|
|
52
|
+
/** Dismiss the topmost modal stack (no-op if none active). */
|
|
53
|
+
dismiss(): void;
|
|
54
|
+
/** Currently-focused entry. Reactive via property access. */
|
|
55
|
+
readonly current: StackEntry;
|
|
56
|
+
/** Full stack, top last. Reactive. */
|
|
57
|
+
readonly stack: ReadonlyArray<StackEntry>;
|
|
58
|
+
/** Whether the user can go back from the current entry. Reactive. */
|
|
59
|
+
readonly canGoBack: boolean;
|
|
60
|
+
/** Parent navigator (e.g. the Tabs above this Stack), or null at the root. */
|
|
61
|
+
readonly parent: Nav | null;
|
|
62
|
+
/**
|
|
63
|
+
* In-flight transition, or null when navigation is at rest. Reactive —
|
|
64
|
+
* `<Stack>` reads this to decide whether to render one screen or two
|
|
65
|
+
* (during a slide transition both the outgoing and incoming screens
|
|
66
|
+
* stay mounted with `useAnimatedStyle`-driven transforms).
|
|
67
|
+
*/
|
|
68
|
+
readonly transition: TransitionState | null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Access the innermost navigator. Provided by `<NavigationRoot>` via
|
|
72
|
+
* `defineProvide`. Throws when called outside a NavigationRoot subtree.
|
|
73
|
+
*
|
|
74
|
+
* Mirrors `@sigx/router`'s `useRouter` pattern (`packages/router/src/router.ts:30`).
|
|
75
|
+
*/
|
|
76
|
+
export declare const useNav: import("@sigx/runtime-core").InjectableFunction<Nav>;
|
|
77
|
+
//# sourceMappingURL=use-nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-nav.d.ts","sourceRoot":"","sources":["../../src/hooks/use-nav.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,KAAK,EACR,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,UAAU,EACV,eAAe,EAClB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG;KAC1B,CAAC,IAAI,OAAO,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;CACpF,CAAC,OAAO,CAAC,CAAC;AAEX,mDAAmD;AACnD,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,GAAG;IAChB,8CAA8C;IAC9C,IAAI,CAAC,CAAC,SAAS,mBAAmB,EAC9B,IAAI,EAAE,CAAC,EACP,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE,WAAW,GACtB,IAAI,CAAC;IACR,yCAAyC;IACzC,IAAI,CAAC,CAAC,SAAS,gBAAgB,EAC3B,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE,WAAW,GACtB,IAAI,CAAC;IAER,6DAA6D;IAC7D,OAAO,CAAC,CAAC,SAAS,mBAAmB,EACjC,IAAI,EAAE,CAAC,EACP,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE,WAAW,GACtB,IAAI,CAAC;IACR,OAAO,CAAC,CAAC,SAAS,gBAAgB,EAC9B,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE,WAAW,GACtB,IAAI,CAAC;IAER,wDAAwD;IACxD,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAEhD,uDAAuD;IACvD,KAAK,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAExC,yCAAyC;IACzC,SAAS,IAAI,IAAI,CAAC;IAElB,mCAAmC;IACnC,KAAK,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IAEzD,8DAA8D;IAC9D,OAAO,IAAI,IAAI,CAAC;IAEhB,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAE7B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAE1C,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC;IAE5B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;CAC/C;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,sDAIjB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineInjectable } from '@sigx/lynx';
|
|
2
|
+
/**
|
|
3
|
+
* Access the innermost navigator. Provided by `<NavigationRoot>` via
|
|
4
|
+
* `defineProvide`. Throws when called outside a NavigationRoot subtree.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors `@sigx/router`'s `useRouter` pattern (`packages/router/src/router.ts:30`).
|
|
7
|
+
*/
|
|
8
|
+
export const useNav = defineInjectable(() => {
|
|
9
|
+
throw new Error('[lynx-navigation] useNav() called but no <NavigationRoot> is mounted in the component tree.');
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=use-nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-nav.js","sourceRoot":"","sources":["../../src/hooks/use-nav.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6F9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAgB,CAAM,GAAG,EAAE;IAC7C,MAAM,IAAI,KAAK,CACX,6FAA6F,CAChG,CAAC;AACN,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RouteId, RouteParams } from '../register.js';
|
|
2
|
+
/**
|
|
3
|
+
* Read the typed params for the current screen, asserted against the named
|
|
4
|
+
* route from the registry.
|
|
5
|
+
*
|
|
6
|
+
* Returns the current entry's params snapshot. The `name` arg is the type
|
|
7
|
+
* discriminator at compile time; we don't currently runtime-check that the
|
|
8
|
+
* caller's route matches the active entry — the dev-mode warning lands in a
|
|
9
|
+
* later slice along with schema validation.
|
|
10
|
+
*
|
|
11
|
+
* **Reactivity**: each `nav.push` / `replace` produces a new entry with a
|
|
12
|
+
* fresh `key`. `<Stack>` keys the rendered component on `entry.key`, so the
|
|
13
|
+
* screen component fully remounts on every navigation — useParams runs again
|
|
14
|
+
* during the new mount and reads the new params. There is no "in-place params
|
|
15
|
+
* update for the same mounted screen" path in v0.1, so a snapshot at setup
|
|
16
|
+
* time is correct.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useParams<K extends RouteId>(_name: K): RouteParams<K>;
|
|
19
|
+
//# sourceMappingURL=use-params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-params.d.ts","sourceRoot":"","sources":["../../src/hooks/use-params.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAGrE"}
|