@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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/EdgeBackHandle.d.ts +2 -0
  3. package/dist/components/EdgeBackHandle.d.ts.map +1 -0
  4. package/dist/components/Link.d.ts +61 -0
  5. package/dist/components/Link.d.ts.map +1 -0
  6. package/dist/components/Link.js +54 -0
  7. package/dist/components/Link.js.map +1 -0
  8. package/dist/components/NavigationRoot.d.ts +37 -0
  9. package/dist/components/NavigationRoot.d.ts.map +1 -0
  10. package/dist/components/NavigationRoot.js +41 -0
  11. package/dist/components/NavigationRoot.js.map +1 -0
  12. package/dist/components/ScreenContainer.d.ts +18 -0
  13. package/dist/components/ScreenContainer.d.ts.map +1 -0
  14. package/dist/components/Stack.d.ts +21 -0
  15. package/dist/components/Stack.d.ts.map +1 -0
  16. package/dist/components/Stack.js +39 -0
  17. package/dist/components/Stack.js.map +1 -0
  18. package/dist/define-routes.d.ts +31 -0
  19. package/dist/define-routes.d.ts.map +1 -0
  20. package/dist/define-routes.js +32 -0
  21. package/dist/define-routes.js.map +1 -0
  22. package/dist/hooks/use-hardware-back.d.ts +31 -0
  23. package/dist/hooks/use-hardware-back.d.ts.map +1 -0
  24. package/dist/hooks/use-nav-internal.d.ts +37 -0
  25. package/dist/hooks/use-nav-internal.d.ts.map +1 -0
  26. package/dist/hooks/use-nav-internal.js +12 -0
  27. package/dist/hooks/use-nav-internal.js.map +1 -0
  28. package/dist/hooks/use-nav.d.ts +77 -0
  29. package/dist/hooks/use-nav.d.ts.map +1 -0
  30. package/dist/hooks/use-nav.js +11 -0
  31. package/dist/hooks/use-nav.js.map +1 -0
  32. package/dist/hooks/use-params.d.ts +19 -0
  33. package/dist/hooks/use-params.d.ts.map +1 -0
  34. package/dist/hooks/use-params.js +22 -0
  35. package/dist/hooks/use-params.js.map +1 -0
  36. package/dist/hooks/use-search.d.ts +11 -0
  37. package/dist/hooks/use-search.d.ts.map +1 -0
  38. package/dist/hooks/use-search.js +14 -0
  39. package/dist/hooks/use-search.js.map +1 -0
  40. package/dist/href.d.ts +40 -0
  41. package/dist/href.d.ts.map +1 -0
  42. package/dist/href.js +14 -0
  43. package/dist/href.js.map +1 -0
  44. package/dist/index.d.ts +21 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +15 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/internal/screen-width.d.ts +16 -0
  49. package/dist/internal/screen-width.d.ts.map +1 -0
  50. package/dist/navigator/core.d.ts +51 -0
  51. package/dist/navigator/core.d.ts.map +1 -0
  52. package/dist/navigator/core.js +149 -0
  53. package/dist/navigator/core.js.map +1 -0
  54. package/dist/register.d.ts +38 -0
  55. package/dist/register.d.ts.map +1 -0
  56. package/dist/register.js +2 -0
  57. package/dist/register.js.map +1 -0
  58. package/dist/types.d.ts +162 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +9 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +39 -0
  63. package/src/components/EdgeBackHandle.tsx +161 -0
  64. package/src/components/Link.tsx +113 -0
  65. package/src/components/NavigationRoot.tsx +85 -0
  66. package/src/components/ScreenContainer.tsx +101 -0
  67. package/src/components/Stack.tsx +99 -0
  68. package/src/define-routes.ts +33 -0
  69. package/src/hooks/use-hardware-back.ts +50 -0
  70. package/src/hooks/use-nav-internal.ts +47 -0
  71. package/src/hooks/use-nav.ts +118 -0
  72. package/src/hooks/use-params.ts +23 -0
  73. package/src/hooks/use-search.ts +15 -0
  74. package/src/href.ts +58 -0
  75. package/src/index.ts +38 -0
  76. package/src/internal/screen-width.ts +34 -0
  77. package/src/navigator/core.ts +386 -0
  78. package/src/register.ts +41 -0
  79. package/src/types.ts +171 -0
@@ -0,0 +1,22 @@
1
+ import { useNav } from './use-nav.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 function useParams(_name) {
19
+ const nav = useNav();
20
+ return nav.current.params;
21
+ }
22
+ //# sourceMappingURL=use-params.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-params.js","sourceRoot":"","sources":["../../src/hooks/use-params.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAoB,KAAQ;IACjD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,OAAO,GAAG,CAAC,OAAO,CAAC,MAAwB,CAAC;AAChD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { RouteId, RouteSearch } from '../register.js';
2
+ /**
3
+ * Read the typed search/query params for the current screen, asserted against
4
+ * the named route from the registry.
5
+ *
6
+ * Returns the current entry's search snapshot. See `useParams` for the
7
+ * reactivity story — each navigation triggers a remount via the entry-keyed
8
+ * Stack, so a setup-time snapshot is sufficient.
9
+ */
10
+ export declare function useSearch<K extends RouteId>(_name: K): RouteSearch<K>;
11
+ //# sourceMappingURL=use-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-search.d.ts","sourceRoot":"","sources":["../../src/hooks/use-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG3D;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAGrE"}
@@ -0,0 +1,14 @@
1
+ import { useNav } from './use-nav.js';
2
+ /**
3
+ * Read the typed search/query params for the current screen, asserted against
4
+ * the named route from the registry.
5
+ *
6
+ * Returns the current entry's search snapshot. See `useParams` for the
7
+ * reactivity story — each navigation triggers a remount via the entry-keyed
8
+ * Stack, so a setup-time snapshot is sufficient.
9
+ */
10
+ export function useSearch(_name) {
11
+ const nav = useNav();
12
+ return nav.current.search;
13
+ }
14
+ //# sourceMappingURL=use-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-search.js","sourceRoot":"","sources":["../../src/hooks/use-search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAoB,KAAQ;IACjD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,OAAO,GAAG,CAAC,OAAO,CAAC,MAAwB,CAAC;AAChD,CAAC"}
package/dist/href.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { RouteId, RouteParams, RouteSearch } from './register.js';
2
+ import type { RoutesWithoutParams, RoutesWithParams } from './hooks/use-nav.js';
3
+ /**
4
+ * A typed reference to a navigation target — what `<Link to={...}>` consumes
5
+ * and what `hrefFor()` produces.
6
+ *
7
+ * Holds both the typed pieces (route name, params, search) and the serialized
8
+ * URL form (when the route declares a `path` template). Either side can drive
9
+ * navigation — typed for in-app links, URL for deep links / sharing.
10
+ */
11
+ export interface Href<K extends RouteId = RouteId> {
12
+ readonly route: K;
13
+ readonly params: RouteParams<K>;
14
+ readonly search: RouteSearch<K>;
15
+ /** URL form. `null` when the route declares no `path` template. */
16
+ readonly url: string | null;
17
+ }
18
+ /**
19
+ * Build a typed Href for a given route. Validates params against the route's
20
+ * schema at runtime; type-checks them at compile time.
21
+ *
22
+ * Overloaded the same way as `nav.push` — one signature for routes without a
23
+ * params schema, one for routes that require params. See `RoutesWithParams`
24
+ * in `./hooks/use-nav.js` for why this isn't expressed as a single conditional.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * hrefFor('profile', { id: '42' }); // → { route, params, search: {}, url: '/users/42' }
29
+ * hrefFor('profile', { id: '42' }, { tab: 'about' });
30
+ * hrefFor('home'); // params arg omitted (no schema)
31
+ * ```
32
+ */
33
+ export declare function hrefFor<K extends RoutesWithoutParams>(name: K, search?: RouteSearch<K>): Href<K>;
34
+ export declare function hrefFor<K extends RoutesWithParams>(name: K, params: RouteParams<K>, search?: RouteSearch<K>): Href<K>;
35
+ /**
36
+ * Parse a URL string into a typed Href against the registered routes.
37
+ * Returns `null` if no route's `path` template matches.
38
+ */
39
+ export declare function parseHref(url: string): Href | null;
40
+ //# sourceMappingURL=href.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"href.d.ts","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO;IAC7C,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,mBAAmB,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAClG,wBAAgB,OAAO,CAAC,CAAC,SAAS,gBAAgB,EAC9C,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GACxB,IAAI,CAAC,CAAC,CAAC,CAAC;AASX;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAKlD"}
package/dist/href.js ADDED
@@ -0,0 +1,14 @@
1
+ export function hrefFor(name, ..._args) {
2
+ void name;
3
+ void _args;
4
+ throw new Error('hrefFor() runtime is not implemented yet — this is the type spike.');
5
+ }
6
+ /**
7
+ * Parse a URL string into a typed Href against the registered routes.
8
+ * Returns `null` if no route's `path` template matches.
9
+ */
10
+ export function parseHref(url) {
11
+ void url;
12
+ throw new Error('parseHref() runtime is not implemented yet — this is the type spike.');
13
+ }
14
+ //# sourceMappingURL=href.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"href.js","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"AAwCA,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAG,KAAgB;IACrD,KAAK,IAAI,CAAC;IACV,KAAK,KAAK,CAAC;IACX,MAAM,IAAI,KAAK,CACX,oEAAoE,CACvE,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACjC,KAAK,GAAG,CAAC;IACT,MAAM,IAAI,KAAK,CACX,sEAAsE,CACzE,CAAC;AACN,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @sigx/lynx-navigation — type-first native stack router.
3
+ *
4
+ * Phase 0.1 (current): typed registry, stack runtime, NavigationRoot + Stack.
5
+ * Coming next: Screen with slot-based header API, MTS transitions, Tabs.
6
+ */
7
+ export { defineRoutes } from './define-routes.js';
8
+ export type { Register, RegisteredRoutes, RouteId, RouteParams, RouteSearch } from './register.js';
9
+ export { useNav } from './hooks/use-nav.js';
10
+ export type { Nav, RoutesWithoutParams, RoutesWithParams } from './hooks/use-nav.js';
11
+ export { useParams } from './hooks/use-params.js';
12
+ export { useSearch } from './hooks/use-search.js';
13
+ export { useHardwareBack } from './hooks/use-hardware-back.js';
14
+ export { hrefFor, parseHref } from './href.js';
15
+ export type { Href } from './href.js';
16
+ export { NavigationRoot } from './components/NavigationRoot.js';
17
+ export { Stack } from './components/Stack.js';
18
+ export { Link } from './components/Link.js';
19
+ export type { LinkProps } from './components/Link.js';
20
+ export type { ComponentLike, EmptyParams, InferOutput, ParamsOf, PopOptions, Presentation, PushOptions, RouteDefinition, RouteMap, RouteRequiresParams, SearchOf, StackEntry, StandardSchemaV1, TransitionKind, TransitionRole, TransitionState, } from './types.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EACR,aAAa,EACb,WAAW,EACX,WAAW,EACX,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,QAAQ,EACR,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,GAClB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @sigx/lynx-navigation — type-first native stack router.
3
+ *
4
+ * Phase 0.1 (current): typed registry, stack runtime, NavigationRoot + Stack.
5
+ * Coming next: Screen with slot-based header API, MTS transitions, Tabs.
6
+ */
7
+ export { defineRoutes } from './define-routes.js';
8
+ export { useNav } from './hooks/use-nav.js';
9
+ export { useParams } from './hooks/use-params.js';
10
+ export { useSearch } from './hooks/use-search.js';
11
+ export { hrefFor, parseHref } from './href.js';
12
+ export { NavigationRoot } from './components/NavigationRoot.js';
13
+ export { Stack } from './components/Stack.js';
14
+ export { Link } from './components/Link.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Logical screen width (in dp) read from `lynx.SystemInfo` at module load.
3
+ * Falls back to 400 (typical phone) if SystemInfo isn't available — module
4
+ * load happens BG-side after the bundle initializes, by which time
5
+ * `lynx.SystemInfo` is populated, so the fallback only fires in tests / SSR /
6
+ * non-Lynx hosts.
7
+ *
8
+ * Used by:
9
+ * - `<ScreenContainer>` for the slide-from-right transform output range.
10
+ * - `<EdgeBackHandle>` for the gesture commit threshold (`dx / width`).
11
+ *
12
+ * Both must agree, otherwise the commit threshold and the animation
13
+ * geometry won't line up. Single shared constant avoids drift.
14
+ */
15
+ export declare const SCREEN_WIDTH: number;
16
+ //# sourceMappingURL=screen-width.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-width.d.ts","sourceRoot":"","sources":["../../src/internal/screen-width.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAoBH,eAAO,MAAM,YAAY,QAAoB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { type SharedValue } from '@sigx/lynx';
2
+ import type { Nav } from '../hooks/use-nav.js';
3
+ import type { RouteMap, StackEntry } from '../types.js';
4
+ /**
5
+ * The reactive backing state for one navigator instance.
6
+ *
7
+ * Two reactive signals drive the public surface:
8
+ * - `stack` is the entry array (read via `nav.stack` / `nav.current`).
9
+ * - `transition` is non-null only while a push/pop animation is in flight;
10
+ * `<Stack>` reads it to decide whether to render one screen or two.
11
+ *
12
+ * Pop is committed *after* its slide animation completes — `nav.canGoBack`
13
+ * stays true during the slide, then flips when the entry actually leaves the
14
+ * stack. Push commits its stack mutation immediately and animates the new
15
+ * entry in.
16
+ */
17
+ export interface NavigatorState {
18
+ readonly nav: Nav;
19
+ readonly routes: RouteMap;
20
+ /**
21
+ * Internal: BG-side gesture-back controller used by `<EdgeBackHandle>`.
22
+ * The `progress` SharedValue is wired here so a gesture worklet can write
23
+ * it directly on MT; the begin/commit/cancel methods set the transition
24
+ * state appropriately without driving their own auto-animation (the
25
+ * gesture worklet is in charge of that).
26
+ */
27
+ readonly _gesture: {
28
+ beginBackGesture(): void;
29
+ commitBackGesture(): void;
30
+ cancelBackGesture(): void;
31
+ };
32
+ }
33
+ export interface CreateNavigatorOptions {
34
+ routes: RouteMap;
35
+ initial: StackEntry;
36
+ /**
37
+ * SharedValue driving push/pop transition progress. Created in
38
+ * `<NavigationRoot>` setup via `useSharedValue(0)` so the bridge
39
+ * plumbing is wired (SharedValue is an MT-bridged ref). When undefined,
40
+ * navigations are instant — used by tests against `@sigx/testing-lynx`
41
+ * that don't have an MT runtime.
42
+ */
43
+ progress?: SharedValue<number>;
44
+ }
45
+ /**
46
+ * Create a navigator. Returns the public `nav` handle plus the routes map.
47
+ * The transition signal lives on `nav` (via `nav.transition`) so `<Stack>`
48
+ * can subscribe to it.
49
+ */
50
+ export declare function createNavigatorState(opts: CreateNavigatorOptions): NavigatorState;
51
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/navigator/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,WAAW,EACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAIR,QAAQ,EACR,UAAU,EAEb,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE;QACf,gBAAgB,IAAI,IAAI,CAAC;QACzB,iBAAiB,IAAI,IAAI,CAAC;QAC1B,iBAAiB,IAAI,IAAI,CAAC;KAC7B,CAAC;CACL;AAsDD,MAAM,WAAW,sBAAsB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,sBAAsB,GAAG,cAAc,CA4QjF"}
@@ -0,0 +1,149 @@
1
+ import { signal } from '@sigx/lynx';
2
+ let entryKeyCounter = 0;
3
+ function nextEntryKey() {
4
+ entryKeyCounter += 1;
5
+ return `entry-${entryKeyCounter}-${Math.random().toString(36).slice(2, 8)}`;
6
+ }
7
+ /**
8
+ * Build a StackEntry from a navigation call.
9
+ *
10
+ * Defaults applied here (rather than at call site) keep the shape consistent
11
+ * regardless of which overload was used.
12
+ */
13
+ function makeEntry(name, params, search, options, routes) {
14
+ const route = routes[name];
15
+ const presentation = options?.presentation ?? route?.presentation ?? 'card';
16
+ return {
17
+ key: nextEntryKey(),
18
+ route: name,
19
+ params: (params ?? {}),
20
+ search: (search ?? {}),
21
+ state: options?.state,
22
+ presentation,
23
+ };
24
+ }
25
+ /**
26
+ * Disambiguate `nav.push` / `replace` arguments at runtime.
27
+ *
28
+ * The two overloads differ in arity:
29
+ * - `push(name, search?, options?)` — for routes with no params schema
30
+ * - `push(name, params, search?, options?)` — for routes with a params schema
31
+ *
32
+ * At runtime we read the route definition to decide which shape was used.
33
+ */
34
+ function unpackArgs(name, args, routes) {
35
+ const route = routes[name];
36
+ const requiresParams = !!route?.params;
37
+ if (requiresParams) {
38
+ const [params, search, options] = args;
39
+ return { params, search, options };
40
+ }
41
+ const [search, options] = args;
42
+ return { params: undefined, search, options };
43
+ }
44
+ /**
45
+ * Create a navigator backed by a sigx signal of stack entries.
46
+ *
47
+ * `initial` is the bottom-of-stack entry that's mounted before any user
48
+ * navigation. Apps usually pass the `initialRoute` of the app (e.g. 'home').
49
+ */
50
+ export function createNavigatorState(routes, initial) {
51
+ // `signal(arrayObj)` returns the deeply-reactive array itself plus `$set`
52
+ // for atomic full-replacement (`packages/reactivity/src/types.ts:31`). The
53
+ // proxy *is* the array — read indices/length directly; use `$set` to
54
+ // replace.
55
+ const stackSignal = signal([initial]);
56
+ function getStack() {
57
+ return stackSignal;
58
+ }
59
+ function setStack(next) {
60
+ stackSignal.$set(next);
61
+ }
62
+ const push = ((name, ...args) => {
63
+ const { params, search, options } = unpackArgs(name, args, routes);
64
+ if (!routes[name]) {
65
+ throw new Error(`[lynx-navigation] push('${name}'): route is not registered. ` +
66
+ `Known routes: ${Object.keys(routes).join(', ') || '(none)'}`);
67
+ }
68
+ const entry = makeEntry(name, params, search, options, routes);
69
+ setStack([...getStack(), entry]);
70
+ });
71
+ const replace = ((name, ...args) => {
72
+ const { params, search, options } = unpackArgs(name, args, routes);
73
+ if (!routes[name]) {
74
+ throw new Error(`[lynx-navigation] replace('${name}'): route is not registered.`);
75
+ }
76
+ const entry = makeEntry(name, params, search, options, routes);
77
+ const cur = getStack();
78
+ setStack([...cur.slice(0, cur.length - 1), entry]);
79
+ });
80
+ function pop(count = 1) {
81
+ const cur = getStack();
82
+ // Always preserve at least the root entry — popping past the root is a no-op.
83
+ const target = Math.max(1, cur.length - Math.max(1, count));
84
+ if (target === cur.length)
85
+ return;
86
+ setStack(cur.slice(0, target));
87
+ }
88
+ function popTo(name) {
89
+ const cur = getStack();
90
+ // Find the topmost matching route (search from the top down).
91
+ for (let i = cur.length - 1; i >= 0; i--) {
92
+ if (cur[i].route === name) {
93
+ if (i === cur.length - 1)
94
+ return;
95
+ setStack(cur.slice(0, i + 1));
96
+ return;
97
+ }
98
+ }
99
+ // No matching entry — leave the stack alone.
100
+ }
101
+ function popToRoot() {
102
+ const cur = getStack();
103
+ if (cur.length <= 1)
104
+ return;
105
+ setStack([cur[0]]);
106
+ }
107
+ function reset(state) {
108
+ if (state.stack.length === 0) {
109
+ throw new Error('[lynx-navigation] reset() called with empty stack.');
110
+ }
111
+ setStack([...state.stack]);
112
+ }
113
+ function dismiss() {
114
+ // Pop entries from the top while they're modal-presented. This pops
115
+ // an entire modal stack (which may contain its own pushed cards) at
116
+ // once, mirroring iOS UIViewController dismiss behavior.
117
+ const cur = getStack();
118
+ let i = cur.length - 1;
119
+ while (i > 0 && cur[i].presentation !== 'card') {
120
+ i--;
121
+ }
122
+ if (i < cur.length - 1) {
123
+ setStack(cur.slice(0, i + 1));
124
+ }
125
+ }
126
+ const nav = {
127
+ push,
128
+ replace,
129
+ pop,
130
+ popTo,
131
+ popToRoot,
132
+ reset,
133
+ dismiss,
134
+ get current() {
135
+ return stackSignal[stackSignal.length - 1];
136
+ },
137
+ get stack() {
138
+ return stackSignal;
139
+ },
140
+ get canGoBack() {
141
+ return stackSignal.length > 1;
142
+ },
143
+ get parent() {
144
+ return null;
145
+ },
146
+ };
147
+ return { nav, routes };
148
+ }
149
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/navigator/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ParamsOf, RouteMap, SearchOf } from './types.js';
2
+ /**
3
+ * Module-augmentation surface for the user's typed route map.
4
+ *
5
+ * Apps register their routes by augmenting this interface — the rest of the
6
+ * library's typed APIs (useNav, useParams, useSearch, <Link>) read from
7
+ * `RegisteredRoutes` so all inference is global.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // In your app's main.ts (or a routes.ts that's imported early):
12
+ * import type { routes } from './routes';
13
+ *
14
+ * declare module '@sigx/lynx-navigation' {
15
+ * interface Register { routes: typeof routes }
16
+ * }
17
+ * ```
18
+ *
19
+ * If `Register.routes` is not augmented the library falls back to a permissive
20
+ * `RouteMap` so non-augmented usage still type-checks (just without precise
21
+ * inference). The recommended pattern is always to augment.
22
+ */
23
+ export interface Register {
24
+ }
25
+ /**
26
+ * The user's registered route map, or a permissive fallback when not
27
+ * augmented. All higher-level types derive from this.
28
+ */
29
+ export type RegisteredRoutes = Register extends {
30
+ routes: infer R;
31
+ } ? R : RouteMap;
32
+ /** Union of registered route names (string literal union when registered). */
33
+ export type RouteId = keyof RegisteredRoutes & string;
34
+ /** Params type for a registered route name. */
35
+ export type RouteParams<K extends RouteId> = ParamsOf<RegisteredRoutes[K]>;
36
+ /** Search type for a registered route name. */
37
+ export type RouteSearch<K extends RouteId> = SearchOf<RegisteredRoutes[K]>;
38
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,QAAQ;CAExB;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,QAAQ,CAAC;AAEnF,8EAA8E;AAC9E,MAAM,MAAM,OAAO,GAAG,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtD,+CAA+C;AAC/C,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3E,+CAA+C;AAC/C,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":""}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Core types for @sigx/lynx-navigation.
3
+ *
4
+ * The type machinery here is the differentiating DX: route names, params, and
5
+ * search are all inferred end-to-end from the user's `defineRoutes` call so
6
+ * `nav.push('profile', { id: 42 })` is a TS error if `id` is typed as string.
7
+ */
8
+ /**
9
+ * Minimal Standard Schema spec subset — see https://standardschema.dev.
10
+ * Inlined so we don't depend on `@standard-schema/spec` for the type spike.
11
+ * Compatible with Zod, Valibot, ArkType, etc.
12
+ */
13
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
14
+ readonly '~standard': {
15
+ readonly version: 1;
16
+ readonly vendor: string;
17
+ readonly types?: {
18
+ readonly input: Input;
19
+ readonly output: Output;
20
+ };
21
+ };
22
+ }
23
+ /**
24
+ * Infer the validated output type of a Standard Schema, falling back to
25
+ * `unknown` for non-schema values.
26
+ */
27
+ export type InferOutput<S> = S extends StandardSchemaV1<unknown, infer O> ? O : unknown;
28
+ /** Empty record — what `ParamsOf` returns when a route declares no schema. */
29
+ export type EmptyParams = Record<string, never>;
30
+ /**
31
+ * How a route entry is presented on the stack.
32
+ * `card` is the default push; `modal`/`fullScreen` slide up; `transparent-modal`
33
+ * preserves the underlying screen visible (e.g. for popovers).
34
+ */
35
+ export type Presentation = 'card' | 'modal' | 'fullScreen' | 'transparent-modal';
36
+ /**
37
+ * A route definition entry.
38
+ *
39
+ * Users construct this via `defineRoutes({...})`. The `params` and `search`
40
+ * schemas drive runtime validation AND TS inference for `useParams`,
41
+ * `useSearch`, `nav.push`, `<Link>`, etc.
42
+ *
43
+ * `component` accepts an eager component factory or a lazy import — both shapes
44
+ * resolve through sigx's `<Suspense>` boundary at render time.
45
+ */
46
+ export interface RouteDefinition<Params extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined, Search extends StandardSchemaV1 | undefined = StandardSchemaV1 | undefined> {
47
+ /** Component factory or lazy importer. */
48
+ component: ComponentLike;
49
+ /** Standard-Schema validator for path params. Optional. */
50
+ params?: Params;
51
+ /** Standard-Schema validator for query/search params. Optional. */
52
+ search?: Search;
53
+ /** Optional URL pattern for deep-link serialization (e.g. `/users/:id`). */
54
+ path?: string;
55
+ /** Default presentation when this route is pushed. */
56
+ presentation?: Presentation;
57
+ /** Nested routes — share the URL/path namespace and may inherit options. */
58
+ children?: Record<string, RouteDefinition>;
59
+ }
60
+ /**
61
+ * The component shape we accept on a route. Kept structural so we don't pull
62
+ * `ComponentFactory` from sigx at type level (avoids a hard dep on sigx purely
63
+ * for types in the spike). Refined to a real ComponentFactory in Phase 0.1
64
+ * runtime work.
65
+ */
66
+ export type ComponentLike = ((...args: any[]) => unknown) | (() => Promise<{
67
+ default: (...args: any[]) => unknown;
68
+ }>);
69
+ /**
70
+ * Map of route definitions, as returned by `defineRoutes`. Keys are route
71
+ * names; values are typed RouteDefinitions.
72
+ */
73
+ export type RouteMap = Record<string, RouteDefinition>;
74
+ /**
75
+ * Extract params type from a single RouteDefinition.
76
+ * Falls back to `EmptyParams` when the route declares no schema.
77
+ *
78
+ * We use a structural `params: infer S` match (without an `extends
79
+ * StandardSchemaV1` constraint on `S`) because TS conditional types treat the
80
+ * generic-defaulted `StandardSchemaV1<unknown, unknown>` as invariant in this
81
+ * position — a schema typed `StandardSchemaV1<{id:string}>` does not match
82
+ * `extends StandardSchemaV1` reliably under `<const T>` inference. `InferOutput`
83
+ * gracefully handles non-schema `S` by returning `unknown`.
84
+ */
85
+ export type ParamsOf<R> = R extends {
86
+ params: infer S;
87
+ } ? InferOutput<S> : EmptyParams;
88
+ /**
89
+ * Extract search type from a single RouteDefinition.
90
+ * Falls back to `EmptyParams` when the route declares no schema.
91
+ */
92
+ export type SearchOf<R> = R extends {
93
+ search: infer S;
94
+ } ? InferOutput<S> : EmptyParams;
95
+ /**
96
+ * Whether a route requires a `params` argument when calling `nav.push` etc.
97
+ * True iff the route definition has a `params` field.
98
+ */
99
+ export type RouteRequiresParams<R> = R extends {
100
+ params: object;
101
+ } ? true : false;
102
+ /**
103
+ * Per-entry state stored on the stack signal.
104
+ *
105
+ * `key` is unique per entry — needed because the same route can appear more
106
+ * than once (e.g. profile A → message → profile A again). Focus state and
107
+ * scroll position are keyed by `key`, not by route name.
108
+ */
109
+ export interface StackEntry<R extends string = string, P = unknown, S = unknown> {
110
+ readonly key: string;
111
+ readonly route: R;
112
+ readonly params: P;
113
+ readonly search: S;
114
+ /** User state — survives suspend/restore. */
115
+ state: unknown;
116
+ readonly presentation: Presentation;
117
+ }
118
+ /** Options accepted by `nav.push` / `nav.replace`. */
119
+ export interface PushOptions {
120
+ /** Override the route's default presentation for this navigation. */
121
+ presentation?: Presentation;
122
+ /** User state to attach to the new entry. Survives suspend/restore. */
123
+ state?: unknown;
124
+ /**
125
+ * Skip the slide animation (instant swap). Defaults to true on platforms
126
+ * where `useAnimatedStyle` isn't available (test renderer); defaults to
127
+ * false on real Lynx. Tests can force `false` to keep assertions
128
+ * deterministic.
129
+ */
130
+ animated?: boolean;
131
+ }
132
+ /** Options accepted by `nav.pop`. */
133
+ export interface PopOptions {
134
+ /** Skip the slide animation (instant swap). See `PushOptions.animated`. */
135
+ animated?: boolean;
136
+ }
137
+ /**
138
+ * Direction of an in-flight transition.
139
+ * - `push`: a new entry is animating in (progress 0 → 1).
140
+ * - `pop`: the current top is animating out (progress 0 → 1, then committed).
141
+ */
142
+ export type TransitionKind = 'push' | 'pop';
143
+ /** Role of a screen during a transition — determines its transform formula. */
144
+ export type TransitionRole = 'top' | 'underneath';
145
+ /**
146
+ * Snapshot of an in-flight transition. Stored on the navigator state so the
147
+ * `<Stack>` component knows to render two entries (`topEntry` above
148
+ * `underneathEntry`) and bind their transforms to `progress`.
149
+ *
150
+ * `progress` is a `SharedValue<number>` (re-exported as `unknown` here to
151
+ * avoid a hard dep on `@sigx/lynx`'s SharedValue type at the contract level —
152
+ * the runtime `<Stack>` casts as needed). The value runs 0 → 1 in both push
153
+ * and pop, with the role/kind pair determining the visual direction.
154
+ */
155
+ export interface TransitionState {
156
+ readonly kind: TransitionKind;
157
+ readonly topEntry: StackEntry;
158
+ readonly underneathEntry: StackEntry;
159
+ /** Animation progress signal — typed loosely; cast at the runtime boundary. */
160
+ readonly progress: unknown;
161
+ }
162
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core types for @sigx/lynx-navigation.
3
+ *
4
+ * The type machinery here is the differentiating DX: route names, params, and
5
+ * search are all inferred end-to-end from the user's `defineRoutes` call so
6
+ * `nav.push('profile', { id: 42 })` is a TS error if `id` is typed as string.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}