@elaraai/east-ui 1.0.35 → 1.0.37

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 (57) hide show
  1. package/dist/src/component.d.ts +22 -0
  2. package/dist/src/component.d.ts.map +1 -1
  3. package/dist/src/component.js +22 -0
  4. package/dist/src/component.js.map +1 -1
  5. package/dist/src/index.d.ts +2 -2
  6. package/dist/src/index.d.ts.map +1 -1
  7. package/dist/src/index.js +2 -2
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/internal.d.ts +3 -2
  10. package/dist/src/internal.d.ts.map +1 -1
  11. package/dist/src/internal.js +2 -1
  12. package/dist/src/internal.js.map +1 -1
  13. package/dist/src/navigation/index.d.ts +1 -1
  14. package/dist/src/navigation/index.d.ts.map +1 -1
  15. package/dist/src/navigation/index.js +1 -1
  16. package/dist/src/navigation/index.js.map +1 -1
  17. package/dist/src/navigation/pages/index.d.ts +44 -8
  18. package/dist/src/navigation/pages/index.d.ts.map +1 -1
  19. package/dist/src/navigation/pages/index.js +44 -7
  20. package/dist/src/navigation/pages/index.js.map +1 -1
  21. package/dist/src/reactive/match.d.ts +85 -0
  22. package/dist/src/reactive/match.d.ts.map +1 -0
  23. package/dist/src/reactive/match.js +65 -0
  24. package/dist/src/reactive/match.js.map +1 -0
  25. package/dist/src/runtime/navigation/index.d.ts +1 -0
  26. package/dist/src/runtime/navigation/index.d.ts.map +1 -1
  27. package/dist/src/runtime/navigation/index.js +1 -0
  28. package/dist/src/runtime/navigation/index.js.map +1 -1
  29. package/dist/src/runtime/navigation/route.d.ts +46 -0
  30. package/dist/src/runtime/navigation/route.d.ts.map +1 -0
  31. package/dist/src/runtime/navigation/route.js +47 -0
  32. package/dist/src/runtime/navigation/route.js.map +1 -0
  33. package/dist/src/runtime/reactive/index.d.ts +1 -0
  34. package/dist/src/runtime/reactive/index.d.ts.map +1 -1
  35. package/dist/src/runtime/reactive/index.js +1 -0
  36. package/dist/src/runtime/reactive/index.js.map +1 -1
  37. package/dist/src/runtime/reactive/match.d.ts +51 -0
  38. package/dist/src/runtime/reactive/match.d.ts.map +1 -0
  39. package/dist/src/runtime/reactive/match.js +49 -0
  40. package/dist/src/runtime/reactive/match.js.map +1 -0
  41. package/dist/test/navigation/index.d.ts +1 -0
  42. package/dist/test/navigation/index.d.ts.map +1 -1
  43. package/dist/test/navigation/index.js +1 -0
  44. package/dist/test/navigation/index.js.map +1 -1
  45. package/dist/test/navigation/route.examples.d.ts +13 -0
  46. package/dist/test/navigation/route.examples.d.ts.map +1 -0
  47. package/dist/test/navigation/route.examples.js +69 -0
  48. package/dist/test/navigation/route.examples.js.map +1 -0
  49. package/dist/test/reactive/index.d.ts +7 -0
  50. package/dist/test/reactive/index.d.ts.map +1 -0
  51. package/dist/test/reactive/index.js +7 -0
  52. package/dist/test/reactive/index.js.map +1 -0
  53. package/dist/test/reactive/match.examples.d.ts +16 -0
  54. package/dist/test/reactive/match.examples.d.ts.map +1 -0
  55. package/dist/test/reactive/match.examples.js +77 -0
  56. package/dist/test/reactive/match.examples.js.map +1 -0
  57. package/package.json +3 -3
@@ -67,8 +67,8 @@ export const Navigation = {
67
67
  bind: bindNavigation,
68
68
  };
69
69
  /**
70
- * Build a `<Pages>` content-switcher from a bound nav handle + a typed page
71
- * registry.
70
+ * Shared switcher builder for `Pages` / `Route` — the two emit the same
71
+ * payload (`render` + `navKey`) under their own variant case.
72
72
  *
73
73
  * The nullary `render` reads `current()` on the **passed** handle (no internal
74
74
  * re-bind) and `match`es the active route to its page body. The bodies live in
@@ -77,11 +77,8 @@ export const Navigation = {
77
77
  * the active page (leaf-only, visible-only). The render closes over `nav`, so
78
78
  * its `current()` read subscribes to the same store the app's handle is bound
79
79
  * to (#114).
80
- *
81
- * @param input - The {@link PagesInput} (`nav` handle + `pages` registry).
82
- * @returns A `Pages` `UIComponentType` value.
83
80
  */
84
- function createPages({ nav, pages }) {
81
+ function createNavSwitcher(caseName, nav, pages) {
85
82
  const handlers = pages;
86
83
  // Build the match arms in host TS (outside the East block): one arm per
87
84
  // route, forwarding the typed payload + the shared handle to the page body.
@@ -97,7 +94,17 @@ function createPages({ nav, pages }) {
97
94
  const cur = $.const(nav.current());
98
95
  return cur.match(armsFor(nav));
99
96
  });
100
- return East.value(variant("Pages", { render, navKey: nav.key }), UIComponentType);
97
+ return East.value(variant(caseName, { render, navKey: nav.key }), UIComponentType);
98
+ }
99
+ /**
100
+ * Build a `<Pages>` content-switcher from a bound nav handle + a typed page
101
+ * registry.
102
+ *
103
+ * @param input - The {@link PagesInput} (`nav` handle + `pages` registry).
104
+ * @returns A `Pages` `UIComponentType` value.
105
+ */
106
+ function createPages({ nav, pages }) {
107
+ return createNavSwitcher("Pages", nav, pages);
101
108
  }
102
109
  /**
103
110
  * The `Pages` namespace — the first-class navigation content-switcher.
@@ -112,4 +119,34 @@ export const Pages = {
112
119
  /** Build a `<Pages>` content-switcher from `{ nav, pages }`. See {@link createPages}. */
113
120
  Root: createPages,
114
121
  };
122
+ /**
123
+ * Build a `<Route>` hosting slot from a bound nav handle + a typed route
124
+ * registry — `<Pages>` generalized to any slot.
125
+ *
126
+ * Renders only the active route's body and remounts it on navigation, but is
127
+ * placeable anywhere (a header widget, a sidebar, a drawer body). The body
128
+ * `<Pages>` and any number of `<Route>` slots bind the **same** `nav` handle,
129
+ * so they stay in lockstep and each remounts *its own* slot on navigation.
130
+ *
131
+ * @param input - The {@link RouteInput} (`nav` handle + `routes` registry).
132
+ * @returns A `Route` `UIComponentType` value.
133
+ */
134
+ function createRoute({ nav, routes }) {
135
+ return createNavSwitcher("Route", nav, routes);
136
+ }
137
+ /**
138
+ * The `Route` namespace — the nav-typed hosting slot.
139
+ *
140
+ * @remarks
141
+ * Authored as the `<Route nav={…} routes={{…}} />` tag; `Route.Root({ nav,
142
+ * routes })` is the underlying factory. Use it to swap a **stateful**
143
+ * component (its own `<Reactive>` / binds) in any slot by route: each case is
144
+ * a self-contained component built with the existing binds, torn down and
145
+ * rebuilt fresh when the route changes. For a non-route key (a `State`-bound
146
+ * mode, a tagged selection), use `<Match on cases>` instead.
147
+ */
148
+ export const Route = {
149
+ /** Build a `<Route>` hosting slot from `{ nav, routes }`. See {@link createRoute}. */
150
+ Root: createRoute,
151
+ };
115
152
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/navigation/pages/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/navigation/pages/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * `Match` — the hosting slot over a variant (#333): the component-level twin
7
+ * of `variant.match`.
8
+ *
9
+ * A plain `variant.match(…)` selecting between mounted components reconciles
10
+ * same-shape nodes, so swapping component A → B at one slot keeps A mounted —
11
+ * its nested `Reactive` / bind / scroll / open state persists and the content
12
+ * goes stale. `Match` host-mounts only the active case and **remounts on tag
13
+ * change**: each case is a normal, self-contained component built with the
14
+ * existing binds, torn down and rebuilt fresh per key. Same-tag payload/data
15
+ * churn re-renders without losing mounted state.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import { type BlockBuilder, type EastType, type ExprType, type SubtypeExprOrValue, type VariantType } from "@elaraai/east";
20
+ import { UIComponentType } from "../component.js";
21
+ /**
22
+ * The case registry: one body per variant case, receiving `($, payload)` —
23
+ * the inner block builder and that case's typed payload. Typed from the `on`
24
+ * variant so a wrong payload arg is a compile error; every case must be
25
+ * handled (exhaustive), exactly like `variant.match`.
26
+ */
27
+ export type MatchCases<C extends {
28
+ [K in string]: EastType;
29
+ }> = {
30
+ [K in keyof C]: ($: BlockBuilder<typeof UIComponentType>, payload: ExprType<C[K]>) => SubtypeExprOrValue<typeof UIComponentType>;
31
+ };
32
+ /**
33
+ * The input to the `<Match>` hosting slot: the variant expression selecting
34
+ * the active case, plus the typed case registry.
35
+ *
36
+ * @remarks
37
+ * Taking a **variant** (not a bare string/number key) is what lets the case
38
+ * map be typed + exhaustive — model the choice as a variant (a `State`-bound
39
+ * mode, a selection tagged as a variant) to get it. `C` is fixed by `on`, so
40
+ * every `cases` handler is contextually typed.
41
+ */
42
+ export interface MatchInput<C extends {
43
+ [K in string]: EastType;
44
+ }> {
45
+ /** The variant expression selecting the active case — its reads are the reactive subscription. */
46
+ on: ExprType<VariantType<C>>;
47
+ /** One body per case — see {@link MatchCases}. `C` is fixed by `on`, so the handlers are contextually typed. */
48
+ cases: MatchCases<NoInfer<C>>;
49
+ }
50
+ /**
51
+ * Build a `<Match>` hosting slot from a variant expression + a typed case
52
+ * registry.
53
+ *
54
+ * The nullary `render` re-reads `on` and `match`es the active case to its
55
+ * body. The bodies live in the match arms (in the IR), so the manifest walk
56
+ * collects every case's binds (the union) while only the matched arm executes
57
+ * — the renderer mounts just the active case. The `tag` closure re-reads `on`
58
+ * and yields the active case name; the renderer keys the mounted subtree by
59
+ * it, so the active case remounts exactly on tag change.
60
+ *
61
+ * @param input - The {@link MatchInput} (`on` variant + `cases` registry).
62
+ * @returns A `Match` `UIComponentType` value.
63
+ */
64
+ declare function createMatch<C extends {
65
+ [K in string]: EastType;
66
+ }>({ on, cases }: MatchInput<C>): ExprType<typeof UIComponentType>;
67
+ /**
68
+ * The `Match` namespace — the general hosting slot over a variant.
69
+ *
70
+ * @remarks
71
+ * Authored as the `<Match on={…} cases={{…}} />` tag; `Match.Root({ on,
72
+ * cases })` is the underlying factory. Use it to swap a **stateful**
73
+ * component (its own `<Reactive>` / binds) at one slot by a reactive key:
74
+ * the active case remounts on tag change. Where the key is a nav route, use
75
+ * `<Route nav routes>` instead — it pins the case map to the
76
+ * `Navigation.config` and hands each body the route payload + nav. For
77
+ * selecting a plain *value* by key (a label, a count), use `variant.match`
78
+ * directly — only mounted subtrees need the hosting slot.
79
+ */
80
+ export declare const Match: {
81
+ /** Build a `<Match>` hosting slot from `{ on, cases }`. See {@link createMatch}. */
82
+ readonly Root: typeof createMatch;
83
+ };
84
+ export {};
85
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../../src/reactive/match.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIH,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS;KAAG,CAAC,IAAI,MAAM,GAAG,QAAQ;CAAE,IAAI;KAC3D,CAAC,IAAI,MAAM,CAAC,GAAG,CACZ,CAAC,EAAE,YAAY,CAAC,OAAO,eAAe,CAAC,EACvC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KACtB,kBAAkB,CAAC,OAAO,eAAe,CAAC;CAClD,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS;KAAG,CAAC,IAAI,MAAM,GAAG,QAAQ;CAAE;IAC7D,kGAAkG;IAClG,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,gHAAgH;IAChH,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,iBAAS,WAAW,CAAC,CAAC,SAAS;KAAG,CAAC,IAAI,MAAM,GAAG,QAAQ;CAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,eAAe,CAAC,CAY1H;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,KAAK;IACd,oFAAoF;;CAE9E,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * `Match` — the hosting slot over a variant (#333): the component-level twin
7
+ * of `variant.match`.
8
+ *
9
+ * A plain `variant.match(…)` selecting between mounted components reconciles
10
+ * same-shape nodes, so swapping component A → B at one slot keeps A mounted —
11
+ * its nested `Reactive` / bind / scroll / open state persists and the content
12
+ * goes stale. `Match` host-mounts only the active case and **remounts on tag
13
+ * change**: each case is a normal, self-contained component built with the
14
+ * existing binds, torn down and rebuilt fresh per key. Same-tag payload/data
15
+ * churn re-renders without losing mounted state.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import { East, StringType, variant, } from "@elaraai/east";
20
+ import { UIComponentType } from "../component.js";
21
+ /**
22
+ * Build a `<Match>` hosting slot from a variant expression + a typed case
23
+ * registry.
24
+ *
25
+ * The nullary `render` re-reads `on` and `match`es the active case to its
26
+ * body. The bodies live in the match arms (in the IR), so the manifest walk
27
+ * collects every case's binds (the union) while only the matched arm executes
28
+ * — the renderer mounts just the active case. The `tag` closure re-reads `on`
29
+ * and yields the active case name; the renderer keys the mounted subtree by
30
+ * it, so the active case remounts exactly on tag change.
31
+ *
32
+ * @param input - The {@link MatchInput} (`on` variant + `cases` registry).
33
+ * @returns A `Match` `UIComponentType` value.
34
+ */
35
+ function createMatch({ on, cases }) {
36
+ // The handlers receive ($, payload) — the exact `variant.match` arm shape —
37
+ // so the registry passes straight through as the match arms.
38
+ const render = East.function([], UIComponentType, ($) => {
39
+ const cur = $.const(on);
40
+ return cur.match(cases);
41
+ });
42
+ const tag = East.function([], StringType, ($) => {
43
+ const cur = $.const(on);
44
+ return cur.getTag();
45
+ });
46
+ return East.value(variant("Match", { render, tag }), UIComponentType);
47
+ }
48
+ /**
49
+ * The `Match` namespace — the general hosting slot over a variant.
50
+ *
51
+ * @remarks
52
+ * Authored as the `<Match on={…} cases={{…}} />` tag; `Match.Root({ on,
53
+ * cases })` is the underlying factory. Use it to swap a **stateful**
54
+ * component (its own `<Reactive>` / binds) at one slot by a reactive key:
55
+ * the active case remounts on tag change. Where the key is a nav route, use
56
+ * `<Route nav routes>` instead — it pins the case map to the
57
+ * `Navigation.config` and hands each body the route payload + nav. For
58
+ * selecting a plain *value* by key (a label, a count), use `variant.match`
59
+ * directly — only mounted subtrees need the hosting slot.
60
+ */
61
+ export const Match = {
62
+ /** Build a `<Match>` hosting slot from `{ on, cases }`. See {@link createMatch}. */
63
+ Root: createMatch,
64
+ };
65
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../../src/reactive/match.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACH,IAAI,EACJ,UAAU,EACV,OAAO,GAMV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAgClD;;;;;;;;;;;;;GAaG;AACH,SAAS,WAAW,CAAwC,EAAE,EAAE,EAAE,KAAK,EAAiB;IACpF,4EAA4E;IAC5E,6DAA6D;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxB,OAAQ,GAA0E,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;QAC5C,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxB,OAAQ,GAAqD,CAAC,MAAM,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACjB,oFAAoF;IACpF,IAAI,EAAE,WAAW;CACX,CAAC"}
@@ -6,4 +6,5 @@
6
6
  export { Breadcrumb } from "./breadcrumb.js";
7
7
  export { NavList } from "./nav-list.js";
8
8
  export { Pages } from "./pages.js";
9
+ export { Route } from "./route.js";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -6,4 +6,5 @@
6
6
  export { Breadcrumb } from "./breadcrumb.js";
7
7
  export { NavList } from "./nav-list.js";
8
8
  export { Pages } from "./pages.js";
9
+ export { Route } from "./route.js";
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /** Navigation `<Route>` tag — the nav-typed hosting slot (#333). */
6
+ import { type RouteInput } from "../../navigation/pages/index.js";
7
+ import type { NavRoutes } from "../../navigation/pages/types.js";
8
+ import type { UIElement } from "../runtime.js";
9
+ /**
10
+ * Nav-typed hosting slot — `<Pages>` generalized to any slot: renders only the
11
+ * active route's body and **remounts it on navigation**, but is placeable
12
+ * anywhere (a header widget, a sidebar, a drawer body). Bind the nav handle
13
+ * once in the enclosing `<Reactive>` and share it between the body `<Pages>`,
14
+ * the chrome, and any number of `<Route>` slots — they stay in lockstep and
15
+ * each remounts *its own* slot on navigation. Route keys are typed +
16
+ * exhaustive against the `Navigation.config`; each body receives the route's
17
+ * payload + the nav handle. For a non-route key (a `State`-bound mode, a
18
+ * tagged selection), use `<Match on cases>` instead.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // .tsx file with the `@jsxImportSource @elaraai/east-ui` pragma
23
+ * import { East, NullType, UIComponentType } from "@elaraai/east";
24
+ * import { Navigation, Route, Reactive, Text } from "@elaraai/east-ui";
25
+ *
26
+ * const widget = East.function([], UIComponentType, _$ => {
27
+ * const routes = Navigation.config({ overview: { value: NullType, label: "Overview" } });
28
+ * return (
29
+ * <Reactive>{$ => {
30
+ * const nav = $.let(Navigation.bind(routes, "app.nav", [routes.Page.overview()]));
31
+ * return <Route nav={nav} routes={{ overview: () => <Text>Overview widget</Text> }} />;
32
+ * }}</Reactive>
33
+ * );
34
+ * });
35
+ * ```
36
+ *
37
+ * @remarks
38
+ * Desugars to `Route.Root({ nav, routes })`. A generic function declaration
39
+ * (merged with the `Route` namespace) so it is a valid generic JSX component.
40
+ */
41
+ export declare function Route<R extends NavRoutes>(props: RouteInput<R>): UIElement;
42
+ export declare namespace Route {
43
+ /** The underlying factory: `Route.Root({ nav, routes })`. */
44
+ const Root: <R extends NavRoutes>({ nav, routes }: RouteInput<R>) => import("@elaraai/east").ExprType<typeof import("../../component.js").UIComponentType>;
45
+ }
46
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../src/runtime/navigation/route.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oEAAoE;AAEpE,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAE1E;AAGD,yBAAiB,KAAK,CAAC;IACnB,6DAA6D;IACtD,MAAM,IAAI,gJAAoB,CAAC;CACzC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /** Navigation `<Route>` tag — the nav-typed hosting slot (#333). */
6
+ import { Route as RouteFactory } from "../../navigation/pages/index.js";
7
+ /**
8
+ * Nav-typed hosting slot — `<Pages>` generalized to any slot: renders only the
9
+ * active route's body and **remounts it on navigation**, but is placeable
10
+ * anywhere (a header widget, a sidebar, a drawer body). Bind the nav handle
11
+ * once in the enclosing `<Reactive>` and share it between the body `<Pages>`,
12
+ * the chrome, and any number of `<Route>` slots — they stay in lockstep and
13
+ * each remounts *its own* slot on navigation. Route keys are typed +
14
+ * exhaustive against the `Navigation.config`; each body receives the route's
15
+ * payload + the nav handle. For a non-route key (a `State`-bound mode, a
16
+ * tagged selection), use `<Match on cases>` instead.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // .tsx file with the `@jsxImportSource @elaraai/east-ui` pragma
21
+ * import { East, NullType, UIComponentType } from "@elaraai/east";
22
+ * import { Navigation, Route, Reactive, Text } from "@elaraai/east-ui";
23
+ *
24
+ * const widget = East.function([], UIComponentType, _$ => {
25
+ * const routes = Navigation.config({ overview: { value: NullType, label: "Overview" } });
26
+ * return (
27
+ * <Reactive>{$ => {
28
+ * const nav = $.let(Navigation.bind(routes, "app.nav", [routes.Page.overview()]));
29
+ * return <Route nav={nav} routes={{ overview: () => <Text>Overview widget</Text> }} />;
30
+ * }}</Reactive>
31
+ * );
32
+ * });
33
+ * ```
34
+ *
35
+ * @remarks
36
+ * Desugars to `Route.Root({ nav, routes })`. A generic function declaration
37
+ * (merged with the `Route` namespace) so it is a valid generic JSX component.
38
+ */
39
+ export function Route(props) {
40
+ return RouteFactory.Root(props);
41
+ }
42
+ // eslint-disable-next-line @typescript-eslint/no-namespace
43
+ (function (Route) {
44
+ /** The underlying factory: `Route.Root({ nav, routes })`. */
45
+ Route.Root = RouteFactory.Root;
46
+ })(Route || (Route = {}));
47
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../src/runtime/navigation/route.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oEAAoE;AAEpE,OAAO,EAAE,KAAK,IAAI,YAAY,EAAmB,MAAM,iCAAiC,CAAC;AAIzF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,KAAK,CAAsB,KAAoB;IAC3D,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAc,CAAC;AACjD,CAAC;AAED,2DAA2D;AAC3D,WAAiB,KAAK;IAClB,6DAA6D;IAChD,UAAI,GAAG,YAAY,CAAC,IAAI,CAAC;AAC1C,CAAC,EAHgB,KAAK,KAAL,KAAK,QAGrB"}
@@ -5,4 +5,5 @@
5
5
  /** Reactive JSX tag. Mirrors `src/reactive/`. */
6
6
  export { Reactive } from "./reactive.js";
7
7
  export type { ReactiveRender } from "./reactive.js";
8
+ export { Match } from "./match.js";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/reactive/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/runtime/reactive/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -4,4 +4,5 @@
4
4
  */
5
5
  /** Reactive JSX tag. Mirrors `src/reactive/`. */
6
6
  export { Reactive } from "./reactive.js";
7
+ export { Match } from "./match.js";
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/reactive/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/runtime/reactive/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /** The `<Match>` hosting-slot tag (#333). */
6
+ import type { EastType } from "@elaraai/east";
7
+ import { type MatchInput } from "../../reactive/match.js";
8
+ import type { UIElement } from "../runtime.js";
9
+ /**
10
+ * Hosting slot over a variant — the component-level twin of `variant.match`:
11
+ * host-mounts only the active case and **remounts it on tag change**, so a
12
+ * stateful component (its own `<Reactive>` / binds) swapped at one slot is
13
+ * torn down and rebuilt fresh per key instead of keeping the previous case's
14
+ * mounted state. Same-tag payload/data churn re-renders without remounting.
15
+ * `cases` are keyed by the variant's case names, exhaustive, and each handler
16
+ * receives that case's typed payload — exactly like `variant.match`. Where
17
+ * the key is a nav route, use `<Route nav routes>` instead; for selecting a
18
+ * plain *value* by key, use `variant.match` directly.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // .tsx file with the `@jsxImportSource @elaraai/east-ui` pragma
23
+ * import { East, NullType, StringType, UIComponentType, VariantType } from "@elaraai/east";
24
+ * import { Match, Reactive, State, Text } from "@elaraai/east-ui";
25
+ *
26
+ * const ModeType = VariantType({ list: NullType, detail: StringType });
27
+ *
28
+ * const slot = East.function([], UIComponentType, _$ => (
29
+ * <Reactive>{$ => {
30
+ * const modeBind = $.let(State.bind([ModeType], "app.mode", East.value(variant("list", null), ModeType)));
31
+ * const mode = $.let(modeBind.read());
32
+ * return <Match on={mode} cases={{
33
+ * list: (_$) => <Text>All items</Text>,
34
+ * detail: (_$, id) => <Text>{East.str`Item ${id}`}</Text>,
35
+ * }} />;
36
+ * }}</Reactive>
37
+ * ));
38
+ * ```
39
+ *
40
+ * @remarks
41
+ * Desugars to `Match.Root({ on, cases })`. A generic function declaration
42
+ * (merged with the `Match` namespace) so it is a valid generic JSX component.
43
+ */
44
+ export declare function Match<C extends {
45
+ [K in string]: EastType;
46
+ }>(props: MatchInput<C>): UIElement;
47
+ export declare namespace Match {
48
+ /** The underlying factory: `Match.Root({ on, cases })`. */
49
+ const Root: <C extends { [K in string]: EastType; }>({ on, cases }: MatchInput<C>) => import("@elaraai/east").ExprType<typeof import("../../component.js").UIComponentType>;
50
+ }
51
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../../../src/runtime/reactive/match.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,6CAA6C;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS;KAAG,CAAC,IAAI,MAAM,GAAG,QAAQ;CAAE,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAE5F;AAGD,yBAAiB,KAAK,CAAC;IACnB,2DAA2D;IACpD,MAAM,IAAI,iKAAoB,CAAC;CACzC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import { Match as MatchFactory } from "../../reactive/match.js";
6
+ /**
7
+ * Hosting slot over a variant — the component-level twin of `variant.match`:
8
+ * host-mounts only the active case and **remounts it on tag change**, so a
9
+ * stateful component (its own `<Reactive>` / binds) swapped at one slot is
10
+ * torn down and rebuilt fresh per key instead of keeping the previous case's
11
+ * mounted state. Same-tag payload/data churn re-renders without remounting.
12
+ * `cases` are keyed by the variant's case names, exhaustive, and each handler
13
+ * receives that case's typed payload — exactly like `variant.match`. Where
14
+ * the key is a nav route, use `<Route nav routes>` instead; for selecting a
15
+ * plain *value* by key, use `variant.match` directly.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // .tsx file with the `@jsxImportSource @elaraai/east-ui` pragma
20
+ * import { East, NullType, StringType, UIComponentType, VariantType } from "@elaraai/east";
21
+ * import { Match, Reactive, State, Text } from "@elaraai/east-ui";
22
+ *
23
+ * const ModeType = VariantType({ list: NullType, detail: StringType });
24
+ *
25
+ * const slot = East.function([], UIComponentType, _$ => (
26
+ * <Reactive>{$ => {
27
+ * const modeBind = $.let(State.bind([ModeType], "app.mode", East.value(variant("list", null), ModeType)));
28
+ * const mode = $.let(modeBind.read());
29
+ * return <Match on={mode} cases={{
30
+ * list: (_$) => <Text>All items</Text>,
31
+ * detail: (_$, id) => <Text>{East.str`Item ${id}`}</Text>,
32
+ * }} />;
33
+ * }}</Reactive>
34
+ * ));
35
+ * ```
36
+ *
37
+ * @remarks
38
+ * Desugars to `Match.Root({ on, cases })`. A generic function declaration
39
+ * (merged with the `Match` namespace) so it is a valid generic JSX component.
40
+ */
41
+ export function Match(props) {
42
+ return MatchFactory.Root(props);
43
+ }
44
+ // eslint-disable-next-line @typescript-eslint/no-namespace
45
+ (function (Match) {
46
+ /** The underlying factory: `Match.Root({ on, cases })`. */
47
+ Match.Root = MatchFactory.Root;
48
+ })(Match || (Match = {}));
49
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../../../src/runtime/reactive/match.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,IAAI,YAAY,EAAmB,MAAM,yBAAyB,CAAC;AAGjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,KAAK,CAAwC,KAAoB;IAC7E,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAc,CAAC;AACjD,CAAC;AAED,2DAA2D;AAC3D,WAAiB,KAAK;IAClB,2DAA2D;IAC9C,UAAI,GAAG,YAAY,CAAC,IAAI,CAAC;AAC1C,CAAC,EAHgB,KAAK,KAAL,KAAK,QAGrB"}
@@ -6,4 +6,5 @@
6
6
  export * from "./breadcrumb.examples.js";
7
7
  export * from "./nav-list.examples.js";
8
8
  export * from "./pages.examples.js";
9
+ export * from "./route.examples.js";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../test/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+EAA+E;AAE/E,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../test/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+EAA+E;AAE/E,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
@@ -6,4 +6,5 @@
6
6
  export * from "./breadcrumb.examples.js";
7
7
  export * from "./nav-list.examples.js";
8
8
  export * from "./pages.examples.js";
9
+ export * from "./route.examples.js";
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../test/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+EAA+E;AAE/E,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../test/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+EAA+E;AAE/E,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `<Route>` is `<Pages>` generalized to any slot: renders only the active
3
+ * route's body and remounts it on navigation, but placeable anywhere. Here a
4
+ * single Route slot hosts a per-route widget driven by the bound nav handle.
5
+ */
6
+ export declare const routeBasic: import("@elaraai/east").ExampleDef<[], any>;
7
+ /**
8
+ * The body `<Pages>` and a sidebar `<Route>` bind the **same** nav handle, so
9
+ * they stay in lockstep and each remounts *its own* slot on navigation — the
10
+ * behaviour `<Pages>` had for the page body, now available for any slot.
11
+ */
12
+ export declare const routeSidebarSlot: import("@elaraai/east").ExampleDef<[], any>;
13
+ //# sourceMappingURL=route.examples.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.examples.d.ts","sourceRoot":"","sources":["../../../test/navigation/route.examples.tsx"],"names":[],"mappings":"AASA;;;;GAIG;AACH,eAAO,MAAM,UAAU,6CAgCrB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6CA4C3B,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@elaraai/east-ui/jsx-runtime";
2
+ /**
3
+ * Copyright (c) 2025 Elara AI Pty Ltd
4
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
5
+ */
6
+ /** @jsxImportSource @elaraai/east-ui */
7
+ import { East, NullType, StringType, IntegerType, StructType, example } from "@elaraai/east";
8
+ import { UIComponentType } from "@elaraai/east-ui";
9
+ import { Navigation, Route, Pages, Reactive, VStack, HStack, Box, Text, Button } from "@elaraai/east-ui";
10
+ /**
11
+ * `<Route>` is `<Pages>` generalized to any slot: renders only the active
12
+ * route's body and remounts it on navigation, but placeable anywhere. Here a
13
+ * single Route slot hosts a per-route widget driven by the bound nav handle.
14
+ */
15
+ export const routeBasic = example({
16
+ keywords: ["Route", "Navigation", "nav", "routes", "hosting slot", "remount", "navigate", "widget"],
17
+ description: "A Route slot hosts a per-route widget — typed payload per route, remounts on navigation",
18
+ fn: East.function([], UIComponentType, (_$) => {
19
+ const ItemRow = StructType({ id: StringType, value: IntegerType });
20
+ const routes = Navigation.config({
21
+ overview: { value: NullType, label: "Overview" },
22
+ detail: { value: ItemRow, label: "Item" },
23
+ });
24
+ return (_jsx(Reactive, { children: $ => {
25
+ const nav = $.let(Navigation.bind(routes, "route.basic", [routes.Page.overview()]));
26
+ const open = $.const(East.function([], NullType, $ => {
27
+ $(nav.go.detail(East.value({ id: "item-1", value: 42n }, ItemRow)));
28
+ }));
29
+ const back = $.const(East.function([], NullType, $ => { $(nav.pop()); }));
30
+ return (_jsxs(VStack, { gap: "3", align: "stretch", children: [_jsxs(HStack, { gap: "2", children: [_jsx(Button, { onClick: open, children: "Open item-1" }), _jsx(Button, { onClick: back, children: "\u2190 Back" })] }), _jsx(Route, { nav: nav, routes: {
31
+ overview: () => _jsx(Text, { children: "Overview widget" }),
32
+ detail: (_$, row) => _jsx(Text, { children: East.str `Item ${row.id} — value ${East.print(row.value)}` }),
33
+ } })] }));
34
+ } }));
35
+ }),
36
+ inputs: [],
37
+ });
38
+ /**
39
+ * The body `<Pages>` and a sidebar `<Route>` bind the **same** nav handle, so
40
+ * they stay in lockstep and each remounts *its own* slot on navigation — the
41
+ * behaviour `<Pages>` had for the page body, now available for any slot.
42
+ */
43
+ export const routeSidebarSlot = example({
44
+ keywords: ["Route", "Pages", "Navigation", "sidebar", "slot", "lockstep", "app shell", "remount"],
45
+ description: "A sidebar Route slot beside the body Pages — one nav handle drives both, each remounts its own slot on navigation",
46
+ fn: East.function([], UIComponentType, (_$) => {
47
+ const DetailRow = StructType({ id: StringType, group: StringType });
48
+ const routes = Navigation.config({
49
+ overview: { value: NullType, label: "Overview" },
50
+ detail: { value: DetailRow, label: "Item" },
51
+ });
52
+ return (_jsx(Reactive, { children: $ => {
53
+ const nav = $.let(Navigation.bind(routes, "route.shell", [routes.Page.overview()]));
54
+ const open = $.const(East.function([], NullType, $ => {
55
+ $(nav.go.detail(East.value({ id: "item-7", group: "B" }, DetailRow)));
56
+ }));
57
+ const back = $.const(East.function([], NullType, $ => { $(nav.pop()); }));
58
+ return (_jsxs(HStack, { gap: "4", align: "stretch", children: [_jsx(Box, { padding: "3", children: _jsx(Route, { nav: nav, routes: {
59
+ overview: () => _jsx(Text, { children: "No selection" }),
60
+ detail: (_$, row) => _jsx(Text, { children: East.str `Selected: ${row.id} · ${row.group}` }),
61
+ } }) }), _jsx(Pages, { nav: nav, pages: {
62
+ overview: () => (_jsxs(VStack, { gap: "2", align: "stretch", children: [_jsx(Text, { children: "Overview \u2014 item list" }), _jsx(Button, { onClick: open, children: "Open item-7" })] })),
63
+ detail: (_$, row) => (_jsxs(VStack, { gap: "2", align: "stretch", children: [_jsx(Text, { children: East.str `Item ${row.id} · group ${row.group}` }), _jsx(Button, { onClick: back, children: "\u2190 Back" })] })),
64
+ } })] }));
65
+ } }));
66
+ }),
67
+ inputs: [],
68
+ });
69
+ //# sourceMappingURL=route.examples.js.map