@xmachines/play-dom 1.0.0-beta.30 → 1.0.0-beta.32

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/README.md CHANGED
@@ -12,38 +12,61 @@ npm install @xmachines/play-dom
12
12
 
13
13
  ## Key Exports
14
14
 
15
- - `connectRenderer({ actor, registry, container })` — connect actor view signal to DOM
16
- - `defineRegistry(catalog, { components, actions })` — build a catalog-typed `DomRegistry`
15
+ - `connectRenderer({ actor, registry, container, handlers })` — connect actor view signal to DOM
16
+ - `defineRegistry(catalog, { components, actions })` — build a catalog-typed `DomRegistry` with real async action handlers
17
+ - `schema` — DOM schema for use with `defineCatalog` (mirrors `@json-render/react/schema` shape)
17
18
  - `PlayRenderer` — class-based renderer (connect/disconnect lifecycle)
18
19
  - `ComponentFn<C, K>` — catalog-typed DOM component function type
19
20
  - `ComponentContext<C, K>` — context passed to each `ComponentFn` (props, emit, on, children, bindings)
20
- - `renderSpec(spec, store, registry, send, actorActions)` — pure Spec → DOM renderer
21
+ - `renderSpec(spec, store, registry, send, handlers)` — pure Spec → DOM renderer
21
22
 
22
23
  ## Usage
23
24
 
24
25
  ```ts
25
26
  import { definePlayer } from "@xmachines/play-xstate";
26
- import { connectRenderer, defineRegistry } from "@xmachines/play-dom";
27
- import { authMachine, authCatalog, type AuthCatalog } from "@xmachines/play-actor-shared";
27
+ import { connectRenderer, defineRegistry, schema } from "@xmachines/play-dom";
28
+ import { defineCatalog } from "@json-render/core";
29
+ import { authCatalogDef, type AuthActor } from "@xmachines/play-actor-shared";
28
30
  import type { ComponentFn } from "@xmachines/play-dom";
29
31
 
32
+ // 1. Build catalog with DOM schema
33
+ const authCatalog = defineCatalog(schema, authCatalogDef);
34
+ type AuthCatalog = typeof authCatalog;
35
+
36
+ // 2. Implement catalog components
30
37
  const Home: ComponentFn<AuthCatalog, "Home"> = ({ props }) => {
31
38
  const el = document.createElement("section");
32
39
  el.textContent = props.title;
33
40
  return el;
34
41
  };
35
42
 
36
- const { registry } = defineRegistry(authCatalog, {
43
+ // 3. Build registry with real async action handlers
44
+ const registryResult = defineRegistry(authCatalog, {
37
45
  components: { Home /* ... */ },
38
- actions: { login: "auth.login", logout: "auth.logout" },
46
+ actions: {
47
+ login: async (params) => {
48
+ if (!params) return;
49
+ actor.send({ type: "auth.login", username: params.username });
50
+ },
51
+ logout: async () => actor.send({ type: "auth.logout" }),
52
+ },
39
53
  });
40
54
 
41
- const createPlayer = definePlayer({ machine: authMachine });
42
- const actor = createPlayer();
55
+ // 4. Resolve handlers and connect
56
+ const actor = definePlayer({ machine: authMachine })();
43
57
  actor.start();
44
58
 
59
+ const handlers = registryResult.handlers(
60
+ () => undefined,
61
+ () => ({}),
62
+ );
45
63
  const container = document.getElementById("app")!;
46
- const disconnect = connectRenderer({ actor, registry, container });
64
+ const disconnect = connectRenderer({
65
+ actor,
66
+ registry: registryResult.registry,
67
+ container,
68
+ handlers,
69
+ });
47
70
  ```
48
71
 
49
72
  ## Learn More
@@ -17,14 +17,16 @@ import type { PlayDomOptions } from "./xm-types.js";
17
17
  *
18
18
  * Usage:
19
19
  * ```typescript
20
- * const renderer = new PlayRenderer(container, actor, registry, { actions: { ... } });
20
+ * const { registry, handlers } = defineRegistry(catalog, { components, actions });
21
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
22
+ * const renderer = new PlayRenderer(container, actor, registry, { handlers: resolvedHandlers });
21
23
  * renderer.connect();
22
24
  *
23
25
  * // Controlled mode — bring your own store:
24
26
  * import { createAtom } from "@xstate/store";
25
27
  * import { xstateStoreStateStore } from "@json-render/xstate";
26
28
  * const store = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
27
- * const renderer = new PlayRenderer(container, actor, registry, { store, actions: { ... } });
29
+ * const renderer = new PlayRenderer(container, actor, registry, { store, handlers: resolvedHandlers });
28
30
  *
29
31
  * // Later:
30
32
  * renderer.disconnect();
@@ -41,7 +43,7 @@ export declare class PlayRenderer {
41
43
  * @param container - The `HTMLElement` to render into. Cleared and repopulated on every view transition.
42
44
  * @param actor - Actor instance providing the `currentView` signal (must implement `Viewable`).
43
45
  * @param registry - Map of component type names to `DomComponentRenderer` functions.
44
- * @param options - Optional configuration: `actions` map (action name → XState event type) and
46
+ * @param options - Optional configuration: `handlers` map (action name → async handler) and
45
47
  * optional external `store` (controlled mode — when omitted, a fresh `@xstate/store` atom is
46
48
  * created per view transition seeded from `spec.state`).
47
49
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAgB,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAY;IAavB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAfzB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,iBAAiB,CAA6B;IAEtD;;;;;;;OAOG;gBAEe,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,cAAmB;IAG9C;;;OAGG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB,OAAO,CAAC,OAAO;CA2Bf"}
1
+ {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAgB,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAoBpD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,YAAY;IAavB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAfzB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,iBAAiB,CAA6B;IAEtD;;;;;;;OAOG;gBAEe,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,cAAmB;IAG9C;;;OAGG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB,OAAO,CAAC,OAAO;CA8Bf"}
@@ -12,19 +12,38 @@ import { watchSignal } from "@xmachines/play-signals";
12
12
  import { createAtom } from "@xstate/store";
13
13
  import { xstateStoreStateStore } from "@json-render/xstate";
14
14
  import { renderSpec } from "./json-render/renderer.js";
15
+ /**
16
+ * Safely coerce a spec's `state` field to a plain object for `createAtom`.
17
+ *
18
+ * `spec.state` is typed as `unknown` in `ViewMetadata`. At runtime it can be
19
+ * `null`, `undefined`, a primitive, or a plain object depending on what the
20
+ * machine author put in the view spec. `createAtom` requires a plain object as
21
+ * its initial value — anything else produces a broken store at runtime.
22
+ *
23
+ * Returns the value unchanged when it is a non-null object; falls back to `{}`
24
+ * for all other cases (null, undefined, string, number, array, etc.).
25
+ */
26
+ function toAtomState(state) {
27
+ if (state !== null && typeof state === "object" && !Array.isArray(state)) {
28
+ return state;
29
+ }
30
+ return {};
31
+ }
15
32
  /**
16
33
  * PlayRenderer connects an actor's currentView signal to the DOM renderer.
17
34
  *
18
35
  * Usage:
19
36
  * ```typescript
20
- * const renderer = new PlayRenderer(container, actor, registry, { actions: { ... } });
37
+ * const { registry, handlers } = defineRegistry(catalog, { components, actions });
38
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
39
+ * const renderer = new PlayRenderer(container, actor, registry, { handlers: resolvedHandlers });
21
40
  * renderer.connect();
22
41
  *
23
42
  * // Controlled mode — bring your own store:
24
43
  * import { createAtom } from "@xstate/store";
25
44
  * import { xstateStoreStateStore } from "@json-render/xstate";
26
45
  * const store = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
27
- * const renderer = new PlayRenderer(container, actor, registry, { store, actions: { ... } });
46
+ * const renderer = new PlayRenderer(container, actor, registry, { store, handlers: resolvedHandlers });
28
47
  *
29
48
  * // Later:
30
49
  * renderer.disconnect();
@@ -41,7 +60,7 @@ export class PlayRenderer {
41
60
  * @param container - The `HTMLElement` to render into. Cleared and repopulated on every view transition.
42
61
  * @param actor - Actor instance providing the `currentView` signal (must implement `Viewable`).
43
62
  * @param registry - Map of component type names to `DomComponentRenderer` functions.
44
- * @param options - Optional configuration: `actions` map (action name → XState event type) and
63
+ * @param options - Optional configuration: `handlers` map (action name → async handler) and
45
64
  * optional external `store` (controlled mode — when omitted, a fresh `@xstate/store` atom is
46
65
  * created per view transition seeded from `spec.state`).
47
66
  */
@@ -76,17 +95,20 @@ export class PlayRenderer {
76
95
  this.container.replaceChildren();
77
96
  if (!view)
78
97
  return;
79
- // Resolve the store: external (controlled) or fresh per-view atom
98
+ // Resolve the store: external (controlled) or fresh per-view atom.
99
+ // `spec.state` carries the machine's initial state for this view.
100
+ // Guard that it is a plain object before seeding createAtom — a non-object
101
+ // value (null, string, number) would silently produce a broken store.
80
102
  const store = this.options.store
81
103
  ? this.options.store
82
104
  : xstateStoreStateStore({
83
- atom: createAtom(view.spec.state ?? {}),
105
+ atom: createAtom(toAtomState(view.spec.state)),
84
106
  });
85
107
  const send = this.actor.send.bind(this.actor);
86
- const actorActions = this.options.actions ?? {};
108
+ const handlers = this.options.handlers ?? {};
87
109
  const rerender = () => {
88
110
  this.container.replaceChildren();
89
- const node = renderSpec(view.spec, store, this.registry, send, actorActions);
111
+ const node = renderSpec(view.spec, store, this.registry, send, handlers);
90
112
  if (node)
91
113
  this.container.appendChild(node);
92
114
  };
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAIvD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,YAAY;IAaN;IACA;IACA;IACA;IAfV,QAAQ,GAAwB,IAAI,CAAC;IACrC,iBAAiB,GAAwB,IAAI,CAAC;IAEtD;;;;;;;OAOG;IACH,YACkB,SAAsB,EACtB,KAA8C,EAC9C,QAAqB,EACrB,UAA0B,EAAE;QAH5B,cAAS,GAAT,SAAS,CAAa;QACtB,UAAK,GAAL,KAAK,CAAyC;QAC9C,aAAQ,GAAR,QAAQ,CAAa;QACrB,YAAO,GAAP,OAAO,CAAqB;IAC3C,CAAC;IAEJ;;;OAGG;IACH,OAAO;QACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACnF,CAAC;IAED;;OAEG;IACH,UAAU;QACT,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;IAClC,CAAC;IAEO,OAAO,CAAC,IAAyB;QACxC,2DAA2D;QAC3D,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAE9B,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,kEAAkE;QAClE,MAAM,KAAK,GAAe,IAAI,CAAC,OAAO,CAAC,KAAK;YAC3C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK;YACpB,CAAC,CAAC,qBAAqB,CAAC;gBACtB,IAAI,EAAE,UAAU,CAAE,IAAI,CAAC,IAAI,CAAC,KAAiC,IAAI,EAAE,CAAC;aACpE,CAAC,CAAC;QAEL,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAG,GAAS,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;YAC7E,IAAI,IAAI;gBAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnD,QAAQ,EAAE,CAAC;IACZ,CAAC;CACD"}
1
+ {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"connect-renderer.d.ts","sourceRoot":"","sources":["../src/connect-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAiB3E"}
1
+ {"version":3,"file":"connect-renderer.d.ts","sourceRoot":"","sources":["../src/connect-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAkB,MAAM,eAAe,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,IAAI,CA0B3E"}
@@ -41,13 +41,24 @@ import { PlayRenderer } from "./PlayRenderer.js";
41
41
  * ```
42
42
  */
43
43
  export function connectRenderer(options) {
44
- const playDomOptions = options.actions ? { actions: options.actions } : {};
44
+ const playDomOptions = {};
45
+ if (options.handlers)
46
+ playDomOptions.handlers = options.handlers;
47
+ if (options.store)
48
+ playDomOptions.store = options.store;
45
49
  const renderer = new PlayRenderer(options.container, options.actor, options.registry, playDomOptions);
46
50
  renderer.connect();
47
- // Handle fallback for null view (backward compat)
48
- // If container is empty after initial render, append fallback
49
- if (options.fallback && options.container.children.length === 0) {
50
- options.container.appendChild(options.fallback);
51
+ // Handle fallback for null view (backward compat).
52
+ // Defer to next microtask: PlayRenderer's signal-driven initial render fires
53
+ // asynchronously via watchSignal, so the container is always empty at this
54
+ // synchronous point. Checking after one microtask gives the renderer a chance
55
+ // to populate the container before we decide to append the fallback.
56
+ if (options.fallback) {
57
+ queueMicrotask(() => {
58
+ if (options.container.children.length === 0) {
59
+ options.container.appendChild(options.fallback);
60
+ }
61
+ });
51
62
  }
52
63
  return () => renderer.disconnect();
53
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"connect-renderer.js","sourceRoot":"","sources":["../src/connect-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC9D,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,QAAQ,GAAG,IAAI,YAAY,CAChC,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,QAAQ,EAChB,cAAc,CACd,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE,CAAC;IAEnB,kDAAkD;IAClD,8DAA8D;IAC9D,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjE,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"connect-renderer.js","sourceRoot":"","sources":["../src/connect-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC9D,MAAM,cAAc,GAAmB,EAAE,CAAC;IAC1C,IAAI,OAAO,CAAC,QAAQ;QAAE,cAAc,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACjE,IAAI,OAAO,CAAC,KAAK;QAAE,cAAc,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,YAAY,CAChC,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,QAAQ,EAChB,cAAc,CACd,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE,CAAC;IAEnB,mDAAmD;IACnD,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,qEAAqE;IACrE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,cAAc,CAAC,GAAG,EAAE;YACnB,IAAI,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7C,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,QAAS,CAAC,CAAC;YAClD,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;AACpC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -24,6 +24,6 @@
24
24
  export { connectRenderer } from "./connect-renderer.js";
25
25
  export { PlayRenderer } from "./PlayRenderer.js";
26
26
  export type { ConnectRendererOptions, PlayDomOptions } from "./xm-types.js";
27
- export { defineRegistry, renderSpec } from "./json-render/index.js";
28
- export type { EventHandle, DomRenderContext, DomComponentRenderer, ComponentContext, ComponentFn, ComponentRegistry, DefineRegistryOptions, DefineRegistryResult, DomRegistry, } from "./json-render/index.js";
27
+ export { defineRegistry, renderSpec, schema } from "./json-render/index.js";
28
+ export type { EventHandle, DomRenderContext, DomComponentRenderer, ComponentContext, ComponentFn, ComponentRegistry, Actions, ActionFn, DefineRegistryOptions, DefineRegistryResult, DomRegistry, DomSchema, } from "./json-render/index.js";
29
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,YAAY,EACX,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,GACX,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACX,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,SAAS,GACT,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -25,5 +25,5 @@
25
25
  export { connectRenderer } from "./connect-renderer.js";
26
26
  export { PlayRenderer } from "./PlayRenderer.js";
27
27
  // json-render/dom layer (re-exported for consumer convenience)
28
- export { defineRegistry, renderSpec } from "./json-render/index.js";
28
+ export { defineRegistry, renderSpec, schema } from "./json-render/index.js";
29
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,+DAA+D;AAC/D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,+DAA+D;AAC/D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
@@ -13,5 +13,7 @@
13
13
  */
14
14
  export { renderSpec } from "./renderer.js";
15
15
  export { defineRegistry } from "./types.js";
16
- export type { EventHandle, DomRenderContext, DomComponentRenderer, ComponentContext, ComponentFn, ComponentRegistry, DefineRegistryOptions, DefineRegistryResult, DomRegistry, } from "./types.js";
16
+ export { schema } from "./schema.js";
17
+ export type { DomSchema } from "./schema.js";
18
+ export type { EventHandle, DomRenderContext, DomComponentRenderer, ComponentContext, ComponentFn, ComponentRegistry, Actions, ActionFn, DefineRegistryOptions, DefineRegistryResult, DomRegistry, } from "./types.js";
17
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/json-render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EACX,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,GACX,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/json-render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EACX,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,GACX,MAAM,YAAY,CAAC"}
@@ -13,4 +13,5 @@
13
13
  */
14
14
  export { renderSpec } from "./renderer.js";
15
15
  export { defineRegistry } from "./types.js";
16
+ export { schema } from "./schema.js";
16
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/json-render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/json-render/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
@@ -35,18 +35,17 @@ import type { DomRegistry, DomRenderContext } from "./types.js";
35
35
  * @param store - Live `StateStore` bound to `spec.state`.
36
36
  * @param registry - Map of element type names → `DomComponentRenderer`.
37
37
  * @param send - Dispatcher for interaction events (e.g. actor.send).
38
- * @param actorActions - Map of catalog action names → event type strings.
38
+ * @param handlers - Map of catalog action names → async ActionHandler functions.
39
39
  * @returns The root DOM `Node`, or `null` if the root is invisible
40
40
  * or has no registered renderer.
41
41
  *
42
42
  * @example
43
43
  * ```ts
44
- * const node = renderSpec(spec, store, registry, actor.send.bind(actor), {
45
- * login: "auth.login",
46
- * logout: "auth.logout",
47
- * });
44
+ * const { registry, handlers } = defineRegistry(catalog, { components, actions });
45
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
46
+ * const node = renderSpec(spec, store, registry, actor.send.bind(actor), resolvedHandlers);
48
47
  * if (node) container.appendChild(node);
49
48
  * ```
50
49
  */
51
- export declare function renderSpec(spec: Spec, store: StateStore, registry: DomRegistry, send: DomRenderContext["send"], actorActions: Record<string, string>): Node | null;
50
+ export declare function renderSpec(spec: Spec, store: StateStore, registry: DomRegistry, send: DomRenderContext["send"], handlers: Record<string, import("@json-render/core").ActionHandler>): Node | null;
52
51
  //# sourceMappingURL=renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/json-render/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAa,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,IAAI,GAAG,IAAI,CAyDb"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/json-render/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAa,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAC,GACjE,IAAI,GAAG,IAAI,CAyDb"}
@@ -34,20 +34,19 @@ import { evaluateVisibility, resolveBindings, resolveElementProps } from "@json-
34
34
  * @param store - Live `StateStore` bound to `spec.state`.
35
35
  * @param registry - Map of element type names → `DomComponentRenderer`.
36
36
  * @param send - Dispatcher for interaction events (e.g. actor.send).
37
- * @param actorActions - Map of catalog action names → event type strings.
37
+ * @param handlers - Map of catalog action names → async ActionHandler functions.
38
38
  * @returns The root DOM `Node`, or `null` if the root is invisible
39
39
  * or has no registered renderer.
40
40
  *
41
41
  * @example
42
42
  * ```ts
43
- * const node = renderSpec(spec, store, registry, actor.send.bind(actor), {
44
- * login: "auth.login",
45
- * logout: "auth.logout",
46
- * });
43
+ * const { registry, handlers } = defineRegistry(catalog, { components, actions });
44
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
45
+ * const node = renderSpec(spec, store, registry, actor.send.bind(actor), resolvedHandlers);
47
46
  * if (node) container.appendChild(node);
48
47
  * ```
49
48
  */
50
- export function renderSpec(spec, store, registry, send, actorActions) {
49
+ export function renderSpec(spec, store, registry, send, handlers) {
51
50
  function renderElement(key) {
52
51
  const element = spec.elements[key];
53
52
  if (!element)
@@ -78,7 +77,7 @@ export function renderSpec(spec, store, registry, send, actorActions) {
78
77
  spec,
79
78
  store,
80
79
  send,
81
- actorActions,
80
+ handlers,
82
81
  elementBindings,
83
82
  renderChildren: (keys) => keys.flatMap((k) => {
84
83
  const n = renderElement(k);
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/json-render/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAI7F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,UAAU,CACzB,IAAU,EACV,KAAiB,EACjB,QAAqB,EACrB,IAA8B,EAC9B,YAAoC;IAEpC,SAAS,aAAa,CAAC,GAAW;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE1B,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAEvC,yEAAyE;QACzE,mEAAmE;QACnE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;QAC3B,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAErC,wEAAwE;QACxE,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,eAAe,GAAG,eAAe,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,IAAI,SAAS,CAAC;QAE/E,yEAAyE;QACzE,oEAAoE;QACpE,kEAAkE;QAClE,uDAAuD;QACvD,yEAAyE;QACzE,MAAM,aAAa,GAAG,mBAAmB,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAEpE,yEAAyE;QACzE,8DAA8D;QAC9D,iEAAiE;QACjE,MAAM,GAAG,GAAqB;YAC7B,IAAI;YACJ,KAAK;YACL,IAAI;YACJ,YAAY;YACZ,eAAe;YACf,cAAc,EAAE,CAAC,IAAc,EAAE,EAAE,CAClC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBAClB,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,CAAC,CAAC;SACH,CAAC;QAEF,yEAAyE;QACzE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,CAAC,mDAAmD;QAE/E,yEAAyE;QACzE,2EAA2E;QAC3E,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,eAAe,GAAc,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QACxE,OAAO,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/json-render/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAI7F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,UAAU,CACzB,IAAU,EACV,KAAiB,EACjB,QAAqB,EACrB,IAA8B,EAC9B,QAAmE;IAEnE,SAAS,aAAa,CAAC,GAAW;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE1B,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAEvC,yEAAyE;QACzE,mEAAmE;QACnE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;QAC3B,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAErC,wEAAwE;QACxE,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,eAAe,GAAG,eAAe,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,IAAI,SAAS,CAAC;QAE/E,yEAAyE;QACzE,oEAAoE;QACpE,kEAAkE;QAClE,uDAAuD;QACvD,yEAAyE;QACzE,MAAM,aAAa,GAAG,mBAAmB,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAEpE,yEAAyE;QACzE,8DAA8D;QAC9D,iEAAiE;QACjE,MAAM,GAAG,GAAqB;YAC7B,IAAI;YACJ,KAAK;YACL,IAAI;YACJ,QAAQ;YACR,eAAe;YACf,cAAc,EAAE,CAAC,IAAc,EAAE,EAAE,CAClC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBAClB,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,CAAC,CAAC;SACH,CAAC;QAEF,yEAAyE;QACzE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,CAAC,mDAAmD;QAE/E,yEAAyE;QACzE,2EAA2E;QAC3E,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,eAAe,GAAc,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QACxE,OAAO,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Schema for @json-render/dom (vanilla DOM renderer).
3
+ *
4
+ * Defines the spec and catalog shapes used by defineRegistry() and defineCatalog().
5
+ * Mirrors the structure of @json-render/react/schema — same flat element tree spec,
6
+ * same catalog definition — adapted for the vanilla DOM rendering target.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ /**
11
+ * The schema for @xmachines/play-dom
12
+ *
13
+ * Defines:
14
+ * - Spec: A flat tree of elements with keys, types, props, children, and on-bindings
15
+ * - Catalog: Components with props schemas, and optional actions with param schemas
16
+ */
17
+ export declare const schema: import("@json-render/core").Schema<{
18
+ spec: import("@json-render/core").SchemaType<"object", {
19
+ /** Root element key */
20
+ root: import("@json-render/core").SchemaType<"string", unknown>;
21
+ /** Flat map of elements by key */
22
+ elements: import("@json-render/core").SchemaType<"record", import("@json-render/core").SchemaType<"object", {
23
+ /** Component type from catalog */
24
+ type: import("@json-render/core").SchemaType<"ref", string>;
25
+ /** Component props — resolved from catalog prop schema */
26
+ props: import("@json-render/core").SchemaType<"propsOf", string>;
27
+ /** Child element keys */
28
+ children: import("@json-render/core").SchemaType<"array", import("@json-render/core").SchemaType<"string", unknown>>;
29
+ /** Visibility condition */
30
+ visible: import("@json-render/core").SchemaType<"any", unknown>;
31
+ }>>;
32
+ }>;
33
+ catalog: import("@json-render/core").SchemaType<"object", {
34
+ /** Component definitions */
35
+ components: import("@json-render/core").SchemaType<"map", {
36
+ /** Zod schema for component props */
37
+ props: import("@json-render/core").SchemaType<"zod", unknown>;
38
+ /** Slots for this component */
39
+ slots: import("@json-render/core").SchemaType<"array", import("@json-render/core").SchemaType<"string", unknown>>;
40
+ /** Description for AI generation hints */
41
+ description: import("@json-render/core").SchemaType<"string", unknown>;
42
+ /** Example prop values */
43
+ example: import("@json-render/core").SchemaType<"any", unknown>;
44
+ }>;
45
+ /** Action definitions (optional) */
46
+ actions: import("@json-render/core").SchemaType<"map", {
47
+ /** Zod schema for action params */
48
+ params: import("@json-render/core").SchemaType<"zod", unknown>;
49
+ /** Description for AI generation hints */
50
+ description: import("@json-render/core").SchemaType<"string", unknown>;
51
+ }>;
52
+ }>;
53
+ }>;
54
+ export type DomSchema = typeof schema;
55
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/json-render/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;QAEjB,uBAAuB;;QAEvB,kCAAkC;;YAGhC,kCAAkC;;YAElC,0DAA0D;;YAE1D,yBAAyB;;YAEzB,2BAA2B;;;;;QAM7B,4BAA4B;;YAE3B,qCAAqC;;YAErC,+BAA+B;;YAE/B,0CAA0C;;YAE1C,0BAA0B;;;QAG3B,oCAAoC;;YAEnC,mCAAmC;;YAEnC,0CAA0C;;;;EAI1C,CAAC;AAEJ,MAAM,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Schema for @json-render/dom (vanilla DOM renderer).
3
+ *
4
+ * Defines the spec and catalog shapes used by defineRegistry() and defineCatalog().
5
+ * Mirrors the structure of @json-render/react/schema — same flat element tree spec,
6
+ * same catalog definition — adapted for the vanilla DOM rendering target.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import { defineSchema } from "@json-render/core";
11
+ /**
12
+ * The schema for @xmachines/play-dom
13
+ *
14
+ * Defines:
15
+ * - Spec: A flat tree of elements with keys, types, props, children, and on-bindings
16
+ * - Catalog: Components with props schemas, and optional actions with param schemas
17
+ */
18
+ export const schema = defineSchema((s) => ({
19
+ spec: s.object({
20
+ /** Root element key */
21
+ root: s.string(),
22
+ /** Flat map of elements by key */
23
+ elements: s.record(s.object({
24
+ /** Component type from catalog */
25
+ type: s.ref("catalog.components"),
26
+ /** Component props — resolved from catalog prop schema */
27
+ props: s.propsOf("catalog.components"),
28
+ /** Child element keys */
29
+ children: s.array(s.string()),
30
+ /** Visibility condition */
31
+ visible: s.any(),
32
+ })),
33
+ }),
34
+ catalog: s.object({
35
+ /** Component definitions */
36
+ components: s.map({
37
+ /** Zod schema for component props */
38
+ props: s.zod(),
39
+ /** Slots for this component */
40
+ slots: s.array(s.string()),
41
+ /** Description for AI generation hints */
42
+ description: s.string(),
43
+ /** Example prop values */
44
+ example: s.any(),
45
+ }),
46
+ /** Action definitions (optional) */
47
+ actions: s.map({
48
+ /** Zod schema for action params */
49
+ params: s.zod(),
50
+ /** Description for AI generation hints */
51
+ description: s.string(),
52
+ }),
53
+ }),
54
+ }));
55
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/json-render/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,uBAAuB;QACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,kCAAkC;QAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,CACjB,CAAC,CAAC,MAAM,CAAC;YACR,kCAAkC;YAClC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC;YACjC,0DAA0D;YAC1D,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC;YACtC,yBAAyB;YACzB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7B,2BAA2B;YAC3B,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE;SAChB,CAAC,CACF;KACD,CAAC;IACF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QACjB,4BAA4B;QAC5B,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC;YACjB,qCAAqC;YACrC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE;YACd,+BAA+B;YAC/B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC1B,0CAA0C;YAC1C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;YACvB,0BAA0B;YAC1B,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE;SAChB,CAAC;QACF,oCAAoC;QACpC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC;YACd,mCAAmC;YACnC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE;YACf,0CAA0C;YAC1C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;SACvB,CAAC;KACF,CAAC;CACF,CAAC,CAAC,CAAC"}
@@ -9,35 +9,19 @@
9
9
  * - `defineRegistry(catalog, options)` — build a catalog-typed DomRegistry
10
10
  *
11
11
  * Key difference from framework renderers: `ComponentFn` returns
12
- * `HTMLElement | Text | null` instead of a framework node, and
13
- * `actions` is a `Record<string, string>` event-type map instead of
14
- * async handler functions (because DOM dispatches directly via `send`).
12
+ * `HTMLElement | Text | null` instead of a framework node.
15
13
  *
16
14
  * @packageDocumentation
17
15
  */
18
- import type { Catalog, InferCatalogActions, InferCatalogComponents, InferComponentProps, Spec, StateStore, UIElement } from "@json-render/core";
16
+ import type { ActionHandler, Catalog, InferActionParams, InferCatalogActions, InferCatalogComponents, InferComponentProps, StateModel, Spec, StateStore, UIElement } from "@json-render/core";
19
17
  /**
20
18
  * Handle returned by `ComponentContext.on(eventName)`.
21
- *
22
- * Matches the `EventHandle` interface from @json-render/react, /solid, /svelte, /vue.
23
- *
24
- * @example
25
- * ```ts
26
- * const handle = on("submit");
27
- * if (handle.bound) {
28
- * btn.addEventListener("click", (e) => {
29
- * if (handle.shouldPreventDefault) e.preventDefault();
30
- * handle.emit();
31
- * });
32
- * }
33
- * ```
34
19
  */
35
20
  export interface EventHandle {
36
21
  /** Fire the bound action, resolving params from the current state store. */
37
22
  emit: () => void;
38
23
  /**
39
24
  * Whether any binding for this event has `preventDefault: true`.
40
- * Use to call `e.preventDefault()` on the triggering DOM event.
41
25
  */
42
26
  shouldPreventDefault: boolean;
43
27
  /** `true` if an `on` binding exists for this event name; `false` otherwise. */
@@ -45,9 +29,6 @@ export interface EventHandle {
45
29
  }
46
30
  /**
47
31
  * Low-level render context passed to each `DomComponentRenderer`.
48
- *
49
- * This is the raw renderer-level interface. Most component authors should use
50
- * the higher-level `ComponentContext<C, K>` provided by `defineRegistry`.
51
32
  */
52
33
  export interface DomRenderContext {
53
34
  /** Full spec tree for this render pass. */
@@ -58,207 +39,92 @@ export interface DomRenderContext {
58
39
  send: (event: {
59
40
  type: string;
60
41
  } & Record<string, unknown>) => void;
61
- /** Map of json-render catalog action names → dispatch event type strings. */
62
- actorActions: Record<string, string>;
42
+ /** Map of json-render catalog action names → async ActionHandler functions. */
43
+ handlers: Record<string, ActionHandler>;
63
44
  /** Render a list of child element keys into DOM nodes. */
64
45
  renderChildren: (keys: string[]) => Node[];
65
46
  /**
66
47
  * Pre-computed two-way binding paths for this element's props.
67
- * Resolved from raw props before `resolveElementProps` runs — the resolved
68
- * props no longer contain `$bindState`/`$bindItem` expressions.
69
- * `undefined` when no binding expressions were found.
70
48
  */
71
49
  elementBindings?: Record<string, string> | undefined;
72
50
  }
73
- /**
74
- * Raw DOM component renderer function.
75
- *
76
- * Receives a resolved `UIElement` and a `DomRenderContext`, and returns a DOM
77
- * node or `null`. Prefer using `ComponentFn<C, K>` via `defineRegistry` for
78
- * catalog-typed, framework-consistent components.
79
- *
80
- * @example
81
- * ```ts
82
- * const myRenderer: DomComponentRenderer = (element, ctx) => {
83
- * const el = document.createElement("div");
84
- * el.textContent = String(element.props.title ?? "");
85
- * return el;
86
- * };
87
- * ```
88
- */
89
51
  export type DomComponentRenderer = (element: UIElement, ctx: DomRenderContext) => HTMLElement | Text | null;
90
- /**
91
- * Catalog-typed context passed to each DOM component function.
92
- *
93
- * Mirrors the `ComponentContext<C, K>` shape from @json-render/react, /solid,
94
- * /svelte, /vue with three DOM-specific adaptations:
95
- *
96
- * - `children` is `Node[]` instead of a framework node/snippet/slot
97
- * - `bindings` is `Record<string, string> | undefined` (path strings for DOM
98
- * consumers that implement their own two-way binding, e.g. input value ↔ store)
99
- * - `ctx` (low-level `DomRenderContext`) is exposed for advanced use cases
100
- * (framework renderers do not expose this)
101
- *
102
- * @example
103
- * ```ts
104
- * const Login: ComponentFn<AuthCatalog, "Login"> = ({ props, emit, on, bindings }) => {
105
- * const section = document.createElement("section");
106
- *
107
- * const input = document.createElement("input");
108
- * input.value = props.username ?? "";
109
- *
110
- * // Two-way binding: write back to state store when input changes
111
- * if (bindings?.username) {
112
- * input.addEventListener("input", () => {
113
- * // bindings.username contains the store path e.g. "/username"
114
- * });
115
- * }
116
- *
117
- * const btn = document.createElement("button");
118
- * const handle = on("submit");
119
- * btn.addEventListener("click", (e) => {
120
- * if (handle.shouldPreventDefault) e.preventDefault();
121
- * handle.emit();
122
- * });
123
- *
124
- * section.append(input, btn);
125
- * return section;
126
- * };
127
- * ```
128
- */
129
52
  export interface ComponentContext<C extends Catalog, K extends keyof InferCatalogComponents<C>> {
130
53
  /** Catalog-typed, store-resolved props for this component. */
131
54
  props: InferComponentProps<C, K>;
132
55
  /**
133
56
  * Rendered child nodes from the spec's `children` list.
134
- * Append these into the returned element where children should appear.
135
57
  */
136
58
  children: Node[];
137
59
  /**
138
60
  * Two-way binding paths resolved from `$bindState` / `$bindItem` prop expressions.
139
- *
140
- * Keys match prop names that had `$bindState`/`$bindItem` expressions in the spec;
141
- * values are the absolute state-store paths to write back to on user input.
142
- *
143
- * `undefined` when no bindings were found for this element.
144
61
  */
145
62
  bindings: Record<string, string> | undefined;
146
63
  /**
147
64
  * Dispatch a named event defined in the spec's `on` map.
148
- *
149
- * Resolves the catalog action binding, applies param expressions against the
150
- * current state store, and calls `send()` with the mapped XState event type.
151
- *
152
- * @example
153
- * ```ts
154
- * btn.addEventListener("click", () => emit("submit"));
155
- * ```
156
65
  */
157
66
  emit: (event: string) => void;
158
67
  /**
159
68
  * Get an `EventHandle` for a named event from the spec's `on` map.
160
- *
161
- * Use when you need `shouldPreventDefault` or want to check whether an `on`
162
- * binding exists before attaching a listener.
163
- *
164
- * @example
165
- * ```ts
166
- * const handle = on("submit");
167
- * if (handle.bound) {
168
- * form.addEventListener("submit", (e) => {
169
- * if (handle.shouldPreventDefault) e.preventDefault();
170
- * handle.emit();
171
- * });
172
- * }
173
- * ```
174
69
  */
175
70
  on: (event: string) => EventHandle;
176
71
  /**
177
72
  * Low-level render context.
178
- *
179
- * Exposes `send`, `store`, `actorActions`, and `renderChildren` for advanced
180
- * use cases. Framework renderers do not expose this field — prefer `emit`/`on`
181
- * for event dispatch and `children` for child rendering.
182
73
  */
183
74
  ctx: DomRenderContext;
184
75
  }
185
- /**
186
- * Catalog-typed DOM component function.
187
- *
188
- * The DOM equivalent of `ComponentFn<C, K>` from @json-render/react, /solid,
189
- * /svelte, /vue. The only structural difference is the return type:
190
- * `HTMLElement | Text | null` instead of a framework node.
191
- *
192
- * Pass implementations to `defineRegistry` — do not call directly.
193
- *
194
- * @example
195
- * ```ts
196
- * import type { ComponentFn } from "@xmachines/play-dom";
197
- * import type { AuthCatalog } from "@xmachines/play-actor-shared";
198
- *
199
- * export const Home: ComponentFn<AuthCatalog, "Home"> = ({ props, children }) => {
200
- * const section = document.createElement("section");
201
- * section.setAttribute("data-page", "home");
202
- *
203
- * const h2 = document.createElement("h2");
204
- * h2.textContent = props.title;
205
- * section.appendChild(h2);
206
- *
207
- * children.forEach((child) => section.appendChild(child));
208
- * return section;
209
- * };
210
- * ```
211
- */
212
76
  export type ComponentFn<C extends Catalog, K extends keyof InferCatalogComponents<C>> = (ctx: ComponentContext<C, K>) => HTMLElement | Text | null;
213
- /**
214
- * Catalog-keyed map of `ComponentFn` implementations.
215
- *
216
- * Used as the `components` field in `DefineRegistryOptions`.
217
- * TypeScript enforces that every component key declared in the catalog has
218
- * a matching implementation.
219
- */
220
77
  export type ComponentRegistry<C extends Catalog> = {
221
78
  [K in keyof InferCatalogComponents<C>]: ComponentFn<C, K>;
222
79
  };
80
+ export type DomRegistry = Record<string, DomComponentRenderer>;
223
81
  /**
224
- * Raw registry of `DomComponentRenderer` functions keyed by element type.
225
- *
226
- * Passed to `connectRenderer` or `PlayRenderer`. Build with `defineRegistry`
227
- * to get catalog-typed component functions automatically wrapped.
82
+ * Catalog-typed action function — mirrors `ActionFn<C, K>` from @json-render/react, /solid, /vue.
83
+ * `params` is typed to the exact param schema defined in the catalog, or `undefined` if no spec
84
+ * provided params. The handler must guard against undefined before accessing params.
228
85
  */
229
- export type DomRegistry = Record<string, DomComponentRenderer>;
86
+ export type ActionFn<C extends Catalog, K extends keyof InferCatalogActions<C>> = (params: InferActionParams<C, K> | undefined) => Promise<void>;
87
+ /**
88
+ * Map of catalog-typed action handler functions.
89
+ * Each key is a catalog action name; each value is an `ActionFn<C, K>` for that action.
90
+ */
91
+ export type Actions<C extends Catalog> = {
92
+ [K in keyof InferCatalogActions<C>]: ActionFn<C, K>;
93
+ };
230
94
  /**
231
95
  * Options for `defineRegistry`.
232
96
  *
233
- * Mirrors `DefineRegistryOptions<C>` from @json-render/react, /solid, /svelte, /vue
234
- * with one intentional difference: `actions` is a `Record<string, string>` event-type
235
- * map rather than async handler functions, because the DOM renderer dispatches events
236
- * directly via `send()` to an XState actor instead of calling framework action handlers.
97
+ * Mirrors `DefineRegistryOptions<C>` from @json-render/react, /solid, /svelte, /vue.
98
+ * `actions` accepts catalog-typed async handler functions — params are fully typed.
237
99
  */
238
100
  export interface DefineRegistryOptions<C extends Catalog> {
239
101
  /**
240
102
  * Catalog-typed component implementations.
241
- * Each key must match a component declared in the catalog.
242
103
  */
243
104
  components?: ComponentRegistry<C>;
244
105
  /**
245
- * Map of catalog action name → XState event type string.
106
+ * Map of catalog action name → catalog-typed async handler function.
246
107
  *
247
- * When a spec element fires `emit("login")`, the DOM renderer looks up
248
- * `actions.login` (e.g. `"auth.login"`) and calls `send({ type: "auth.login", ...params })`.
108
+ * Each handler receives params typed to the action's schema (or `undefined`).
109
+ * Guard against undefined before accessing params:
249
110
  *
250
- * In the framework renderers this field holds async handler functions. In the DOM
251
- * renderer it is a simpler string map because routing to the actor is handled by
252
- * the XMachines play-dom layer rather than inside the json-render action system.
111
+ * @example
112
+ * ```ts
113
+ * actions: {
114
+ * login: async (params) => {
115
+ * if (!params) return;
116
+ * actor.send({ type: 'auth.login', username: params.username });
117
+ * },
118
+ * }
119
+ * ```
253
120
  */
254
- actions?: InferCatalogActions<C> extends Record<string, never> ? Record<string, string> : Record<keyof InferCatalogActions<C>, string>;
121
+ actions?: Actions<C>;
255
122
  }
256
123
  /**
257
124
  * Result returned by `defineRegistry`.
258
125
  *
259
- * Mirrors the `{ registry }` field from @json-render/react, /solid, /svelte, /vue.
260
- * The DOM result also exposes `actorActions` — the resolved event-type map — so
261
- * callers can pass it directly to `connectRenderer` or `PlayRenderer`.
126
+ * Matches `DefineRegistryResult` from @json-render/react, /solid, /svelte, /vue —
127
+ * returns `{ registry, handlers }` instead of the old `{ registry, actorActions }`.
262
128
  */
263
129
  export interface DefineRegistryResult {
264
130
  /**
@@ -266,45 +132,33 @@ export interface DefineRegistryResult {
266
132
  */
267
133
  registry: DomRegistry;
268
134
  /**
269
- * Resolved map of catalog action name → XState event type string.
270
- *
271
- * Pass to `connectRenderer({ ..., actions: actorActions })` or
272
- * `new PlayRenderer(container, actor, registry, { actions: actorActions })`.
135
+ * Create ActionProvider-compatible handlers.
136
+ * Accepts getter functions so handlers always read the latest state.
137
+ * For DOM rendering, pass `() => undefined, () => ({})` since DOM actions
138
+ * dispatch directly to actor without needing setState.
273
139
  */
274
- actorActions: Record<string, string>;
140
+ handlers: (getSetState: () => unknown, getState: () => StateModel) => Record<string, ActionHandler>;
275
141
  }
276
142
  /**
277
143
  * Build a `DomRegistry` from a catalog and component/action options.
278
144
  *
279
- * Mirrors the `defineRegistry(catalog, options)` API from @json-render/react,
280
- * /solid, /svelte, /vue. The catalog parameter is used for TypeScript inference
281
- * only (the same as in the framework renderers — it is not used at runtime).
282
- *
283
- * Each component in `options.components` is wrapped in a `DomComponentRenderer`
284
- * adapter that:
285
- * - Resolves props and two-way binding paths via `@json-render/core`
286
- * - Builds `emit(event)` and `on(event)` closures over the element's `on` map
287
- * - Renders child elements via `ctx.renderChildren`
288
- * - Passes the assembled `ComponentContext` to your `ComponentFn`
289
- *
290
- * The `actions` map is passed through as `actorActions` so the caller does not
291
- * need to manage it separately.
292
- *
293
145
  * @example
294
146
  * ```ts
295
147
  * import { defineRegistry } from "@xmachines/play-dom";
296
148
  * import { authCatalog } from "@xmachines/play-actor-shared";
297
- * import { Home, Login, Dashboard } from "./components/index.js";
298
149
  *
299
- * const { registry, actorActions } = defineRegistry(authCatalog, {
150
+ * const registryResult = defineRegistry(authCatalog, {
300
151
  * components: { Home, Login, Dashboard, ... },
301
152
  * actions: {
302
- * login: "auth.login",
303
- * logout: "auth.logout",
153
+ * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
154
+ * logout: async () => actor.send({ type: 'auth.logout' }),
155
+ * route: async ({ to, params }) => actor.send({ type: 'play.route', to, params }),
304
156
  * },
305
157
  * });
306
158
  *
307
- * connectRenderer({ actor, registry, container, actions: actorActions });
159
+ * const { registry, handlers } = registryResult;
160
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
161
+ * connectRenderer({ actor, registry, container, handlers: resolvedHandlers });
308
162
  * ```
309
163
  */
310
164
  export declare function defineRegistry<C extends Catalog>(_catalog: C, options: DefineRegistryOptions<C>): DefineRegistryResult;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/json-render/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/json-render/types.ts"],"names":[],"mappings":"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"}
@@ -9,9 +9,7 @@
9
9
  * - `defineRegistry(catalog, options)` — build a catalog-typed DomRegistry
10
10
  *
11
11
  * Key difference from framework renderers: `ComponentFn` returns
12
- * `HTMLElement | Text | null` instead of a framework node, and
13
- * `actions` is a `Record<string, string>` event-type map instead of
14
- * async handler functions (because DOM dispatches directly via `send`).
12
+ * `HTMLElement | Text | null` instead of a framework node.
15
13
  *
16
14
  * @packageDocumentation
17
15
  */
@@ -19,61 +17,53 @@ import { resolveActionParam } from "@json-render/core";
19
17
  /**
20
18
  * Build a `DomRegistry` from a catalog and component/action options.
21
19
  *
22
- * Mirrors the `defineRegistry(catalog, options)` API from @json-render/react,
23
- * /solid, /svelte, /vue. The catalog parameter is used for TypeScript inference
24
- * only (the same as in the framework renderers — it is not used at runtime).
25
- *
26
- * Each component in `options.components` is wrapped in a `DomComponentRenderer`
27
- * adapter that:
28
- * - Resolves props and two-way binding paths via `@json-render/core`
29
- * - Builds `emit(event)` and `on(event)` closures over the element's `on` map
30
- * - Renders child elements via `ctx.renderChildren`
31
- * - Passes the assembled `ComponentContext` to your `ComponentFn`
32
- *
33
- * The `actions` map is passed through as `actorActions` so the caller does not
34
- * need to manage it separately.
35
- *
36
20
  * @example
37
21
  * ```ts
38
22
  * import { defineRegistry } from "@xmachines/play-dom";
39
23
  * import { authCatalog } from "@xmachines/play-actor-shared";
40
- * import { Home, Login, Dashboard } from "./components/index.js";
41
24
  *
42
- * const { registry, actorActions } = defineRegistry(authCatalog, {
25
+ * const registryResult = defineRegistry(authCatalog, {
43
26
  * components: { Home, Login, Dashboard, ... },
44
27
  * actions: {
45
- * login: "auth.login",
46
- * logout: "auth.logout",
28
+ * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
29
+ * logout: async () => actor.send({ type: 'auth.logout' }),
30
+ * route: async ({ to, params }) => actor.send({ type: 'play.route', to, params }),
47
31
  * },
48
32
  * });
49
33
  *
50
- * connectRenderer({ actor, registry, container, actions: actorActions });
34
+ * const { registry, handlers } = registryResult;
35
+ * const resolvedHandlers = handlers(() => undefined, () => ({}));
36
+ * connectRenderer({ actor, registry, container, handlers: resolvedHandlers });
51
37
  * ```
52
38
  */
53
39
  export function defineRegistry(_catalog, options) {
54
40
  const components = (options.components ?? {});
55
- const actorActions = (options.actions ?? {});
41
+ const actionDefs = (options.actions ?? {});
56
42
  const registry = {};
57
43
  for (const key of Object.keys(components)) {
58
44
  const fn = components[key];
59
45
  registry[key] = (element, ctx) => {
60
46
  const onBindings = element.on ?? {};
61
- const stateModel = ctx.store.getSnapshot();
62
47
  // ── emit ──────────────────────────────────────────────────────────
63
48
  const emit = (eventName) => {
64
49
  const binding = onBindings[eventName];
65
50
  if (!binding)
66
51
  return;
52
+ // Read stateModel fresh on each emit so $state params resolve
53
+ // the latest store value (e.g. after the user has typed in an input).
54
+ const stateModel = ctx.store.getSnapshot();
67
55
  const bindings = Array.isArray(binding) ? binding : [binding];
68
56
  for (const b of bindings) {
69
- const xstateType = ctx.actorActions[b.action] ?? b.action;
70
- const params = {};
71
- if (b.params) {
72
- for (const [k, v] of Object.entries(b.params)) {
73
- params[k] = resolveActionParam(v, { stateModel });
57
+ const handler = ctx.handlers[b.action];
58
+ if (handler) {
59
+ const params = {};
60
+ if (b.params) {
61
+ for (const [k, v] of Object.entries(b.params)) {
62
+ params[k] = resolveActionParam(v, { stateModel });
63
+ }
74
64
  }
65
+ void handler(params);
75
66
  }
76
- ctx.send({ type: xstateType, ...params });
77
67
  }
78
68
  };
79
69
  // ── on ────────────────────────────────────────────────────────────
@@ -85,20 +75,11 @@ export function defineRegistry(_catalog, options) {
85
75
  const bindings = Array.isArray(binding) ? binding : [binding];
86
76
  return {
87
77
  emit: () => emit(eventName),
88
- // truthy check — matches @json-render/react and /solid
89
78
  shouldPreventDefault: bindings.some((b) => b.preventDefault),
90
79
  bound: true,
91
80
  };
92
81
  };
93
- // ── bindings ──────────────────────────────────────────────────────
94
- // Pre-computed by renderSpec on the raw (unresolved) props before
95
- // resolveElementProps ran — $bindState/$bindItem expressions are
96
- // no longer present in element.props at this point.
97
82
  const bindings = ctx.elementBindings;
98
- // ── children ──────────────────────────────────────────────────────
99
- // Render children here (inside the wrapper) and pass them to the
100
- // component. The outer renderSpec does NOT append children again —
101
- // child rendering is solely the component's responsibility.
102
83
  const children = ctx.renderChildren(element.children ?? []);
103
84
  const componentCtx = {
104
85
  props: element.props,
@@ -111,6 +92,10 @@ export function defineRegistry(_catalog, options) {
111
92
  return fn(componentCtx);
112
93
  };
113
94
  }
114
- return { registry, actorActions };
95
+ // handlers factory — same pattern as framework renderers
96
+ const handlers = (_getSetState, _getState) => {
97
+ return { ...actionDefs };
98
+ };
99
+ return { registry, handlers };
115
100
  }
116
101
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/json-render/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/json-render/types.ts"],"names":[],"mappings":"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"}
@@ -8,14 +8,17 @@
8
8
  */
9
9
  import type { AbstractActor, Viewable } from "@xmachines/play-actor";
10
10
  import type { AnyActorLogic } from "xstate";
11
- import type { StateStore } from "@json-render/core";
11
+ import type { ActionHandler, StateStore } from "@json-render/core";
12
12
  import type { DomRegistry } from "./json-render/types.js";
13
13
  /**
14
14
  * Options for PlayRenderer.
15
15
  */
16
16
  export interface PlayDomOptions {
17
- /** Map of json-render actionName → XState event type */
18
- actions?: Record<string, string>;
17
+ /**
18
+ * Map of catalog action name → async ActionHandler function.
19
+ * Replaces the old `actions: Record<string, string>` string-map approach.
20
+ */
21
+ handlers?: Record<string, ActionHandler>;
19
22
  /**
20
23
  * Optional external StateStore (e.g. from `xstateStoreStateStore` in @json-render/xstate).
21
24
  * When provided, PlayRenderer operates in controlled mode — spec.state is ignored and
@@ -37,8 +40,11 @@ export interface ConnectRendererOptions {
37
40
  container: HTMLElement;
38
41
  /** Optional element shown when currentView is null (defaults to nothing — clears container) */
39
42
  fallback?: HTMLElement | null;
40
- /** Map of json-render actionName → XState event type */
41
- actions?: Record<string, string>;
43
+ /**
44
+ * Map of catalog action name → async ActionHandler function.
45
+ * Replaces the old `actions: Record<string, string>` string-map approach.
46
+ */
47
+ handlers?: Record<string, ActionHandler>;
42
48
  /**
43
49
  * Optional external StateStore (e.g. from `xstateStoreStateStore` in @json-render/xstate).
44
50
  * When provided, PlayRenderer operates in controlled mode — spec.state is ignored.
@@ -1 +1 @@
1
- {"version":3,"file":"xm-types.d.ts","sourceRoot":"","sources":["../src/xm-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,4EAA4E;IAC5E,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;IAE/C,sEAAsE;IACtE,QAAQ,EAAE,WAAW,CAAC;IAEtB,uCAAuC;IACvC,SAAS,EAAE,WAAW,CAAC;IAEvB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAE9B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACnB"}
1
+ {"version":3,"file":"xm-types.d.ts","sourceRoot":"","sources":["../src/xm-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAEzC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,4EAA4E;IAC5E,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;IAE/C,sEAAsE;IACtE,QAAQ,EAAE,WAAW,CAAC;IAEtB,uCAAuC;IACvC,SAAS,EAAE,WAAW,CAAC;IAEvB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAEzC;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmachines/play-dom",
3
- "version": "1.0.0-beta.30",
3
+ "version": "1.0.0-beta.32",
4
4
  "description": "Vanilla DOM renderer for XMachines Play architecture with signal-driven rendering",
5
5
  "keywords": [
6
6
  "actor",
@@ -36,33 +36,33 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc --build",
39
- "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__ node_modules/.vite*",
39
+ "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__",
40
40
  "lint": "oxlint .",
41
41
  "format": "oxfmt .",
42
42
  "test": "vitest",
43
43
  "prepublishOnly": "npm run build"
44
44
  },
45
45
  "dependencies": {
46
- "@xmachines/play": "1.0.0-beta.30",
47
- "@xmachines/play-actor": "1.0.0-beta.30",
48
- "@xmachines/play-signals": "1.0.0-beta.30"
46
+ "@xmachines/play": "1.0.0-beta.32",
47
+ "@xmachines/play-actor": "1.0.0-beta.32",
48
+ "@xmachines/play-signals": "1.0.0-beta.32"
49
49
  },
50
50
  "devDependencies": {
51
- "@json-render/core": "^0.16.0",
52
- "@json-render/xstate": "^0.16.0",
53
- "@types/node": "^25.5.0",
54
- "@xmachines/shared": "1.0.0-beta.30",
55
- "@xstate/store": ">=3.17.0",
56
- "oxfmt": "^0.43.0",
57
- "oxlint": "^1.57.0",
58
- "typescript": "^5.9.3 || ^6.0.2",
59
- "vitest": "^4.1.2",
51
+ "@json-render/core": "^0.18.0",
52
+ "@json-render/xstate": "^0.18.0",
53
+ "@types/node": "^25.6.0",
54
+ "@xmachines/shared": "1.0.0-beta.32",
55
+ "@xstate/store": "^3.17.0",
56
+ "oxfmt": "^0.45.0",
57
+ "oxlint": "^1.60.0",
58
+ "typescript": "^5.9.3 || ^6.0.3",
59
+ "vitest": "^4.1.4",
60
60
  "xstate": "^5.30.0"
61
61
  },
62
62
  "peerDependencies": {
63
- "@json-render/core": "^0.16.0",
64
- "@json-render/xstate": "^0.16.0",
65
- "@xstate/store": ">=3.17.0",
63
+ "@json-render/core": "^0.18.0",
64
+ "@json-render/xstate": "^0.18.0",
65
+ "@xstate/store": "^3.17.0",
66
66
  "xstate": "^5.30.0"
67
67
  }
68
68
  }