@xmachines/play-solid 1.0.0-beta.4 → 1.0.0-beta.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mikael Karon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,110 +1,344 @@
1
1
  # @xmachines/play-solid
2
2
 
3
- SolidJS renderer for XMachines Play architecture. Enables catalog-driven view rendering with actor-owned business state.
3
+ **Solid renderer for XMachines Play Architecture**
4
+
5
+ Bridges TC39 Signal-driven actors to Solid's fine-grained reactivity. Business logic stays in the actor; Solid is purely a rendering target.
6
+
7
+ ## Overview
8
+
9
+ `@xmachines/play-solid` provides `PlayRenderer`, a Solid component that:
10
+
11
+ - Subscribes to `actor.currentView` (TC39 Signal) and re-renders on every state transition
12
+ - Renders the current view's JSON spec via `@json-render/solid`
13
+ - Routes action names from spec elements to `actor.send()` via the `actions` prop
14
+ - Manages per-view UI state in an `@xstate/store` atom (automatic or caller-supplied)
15
+
16
+ Per [Play RFC](../docs/rfc/play.md):
17
+
18
+ - **Actor Authority (INV-01):** Guards in the machine decide all state transitions
19
+ - **Passive Infrastructure (INV-04):** Solid observes signals and dispatches events — never decides
20
+ - **Signal-Only Reactivity (INV-05):** `actor.currentView` signal is the sole render trigger
4
21
 
5
22
  ## Installation
6
23
 
7
24
  ```bash
8
- npm install @xmachines/play-solid solid-js
25
+ npm install @xmachines/play-solid
26
+ npm install @json-render/solid @json-render/core # peer deps
27
+ npm install @json-render/xstate @xstate/store # store integration
9
28
  ```
10
29
 
11
- ## Current Exports
12
-
13
- - `PlayRenderer`
14
- - `PlayRendererProps` (type)
15
-
16
- ## Usage
30
+ In this monorepo, the root install applies a `patch-package` patch to `@json-render/solid`
31
+ so `defineRegistry(..., { onRenderError })` can intercept inner element-boundary errors
32
+ without muting console output.
17
33
 
18
- ```typescript
19
- import { PlayRenderer } from '@xmachines/play-solid';
20
- import { definePlayer } from '@xmachines/play-xstate';
21
- import { defineCatalog } from '@xmachines/play-catalog';
34
+ ## Current Exports
22
35
 
23
- // Define catalog
36
+ - `PlayRenderer` — main renderer component
37
+ - `useActor` — hook for accessing the actor inside a `PlayRenderer` tree
38
+ - `defineRegistry` — re-exported from `@json-render/solid`
39
+ - `useBoundProp` — re-exported from `@json-render/solid`
40
+ - `ComponentFn` (type) — re-exported from `@json-render/solid`
41
+ - `ComponentContext` (type) — re-exported from `@json-render/solid`
42
+ - `ActorProvider` — escape hatch primitive (owns actor bridging, signal bridge, store lifecycle)
43
+ - `PlayUIProvider` — batteries-included composite (wraps `ActorProvider` + `JSONUIProvider`)
44
+ - `usePlayView` — hook for accessing the current view spec inside a provider tree
45
+ - `RenderErrorHandler` (type) — inner per-element error callback signature
46
+ - `ActorProviderProps` (type)
47
+ - `ViewContextValue` (type)
48
+ - `PlayActor` (type)
49
+
50
+ ## Quick Start
51
+
52
+ ```tsx
53
+ import { definePlayer, formatPlayRouteTransitions } from "@xmachines/play-xstate";
54
+ import { PlayRenderer } from "@xmachines/play-solid";
55
+ import { defineCatalog } from "@json-render/core";
56
+ import { defineRegistry } from "@xmachines/play-solid";
57
+ import type { ComponentFn } from "@xmachines/play-solid";
58
+ import { setup, assign } from "xstate";
59
+ import { z } from "zod";
60
+
61
+ // 1. Define catalog — the contract between machine spec and UI components
24
62
  const catalog = defineCatalog({
25
- Home: { component: 'Home', props: {} },
26
- Login: { component: 'Login', props: { error: { type: 'string' } } }
63
+ elements: {
64
+ Login: { props: z.object({ title: z.string() }), description: "Login form" },
65
+ Dashboard: { props: z.object({ username: z.string() }), description: "Dashboard" },
66
+ },
27
67
  });
28
68
 
29
- // Create player
30
- const createPlayer = definePlayer({
31
- machine: authMachine,
32
- catalog
69
+ // 2. Implement components using ComponentFn — typed against catalog entries
70
+ const Login: ComponentFn<typeof catalog, "Login"> = ({ props, emit }) => (
71
+ <div class="view">
72
+ <h2>{props.title}</h2>
73
+ <form
74
+ onSubmit={(e) => {
75
+ e.preventDefault();
76
+ emit("submit");
77
+ }}
78
+ >
79
+ <button type="submit">Log In</button>
80
+ </form>
81
+ </div>
82
+ );
83
+
84
+ const Dashboard: ComponentFn<typeof catalog, "Dashboard"> = ({ props }) => (
85
+ <div class="view">Welcome, {props.username}!</div>
86
+ );
87
+
88
+ // 3. Build registry
89
+ const registryResult = defineRegistry(catalog, {
90
+ components: { Login, Dashboard },
91
+ actions: {
92
+ login: async (params) => {
93
+ if (!params) return;
94
+ actor.send({ type: "auth.login", username: params.username });
95
+ },
96
+ logout: async (params) => {
97
+ actor.send({ type: "auth.logout" });
98
+ },
99
+ },
33
100
  });
34
101
 
102
+ // 4. Define machine with view metadata
103
+ const machine = setup({
104
+ types: {
105
+ context: {} as {
106
+ isAuthenticated: boolean;
107
+ username: string | null;
108
+ params: Record<string, string>;
109
+ query: Record<string, string>;
110
+ },
111
+ events: {} as
112
+ | { type: "auth.login"; username: string }
113
+ | { type: "auth.logout" }
114
+ | { type: "play.route"; to: string; params?: Record<string, string> },
115
+ },
116
+ }).createMachine(
117
+ formatPlayRouteTransitions({
118
+ id: "app",
119
+ initial: "login",
120
+ context: { isAuthenticated: false, username: null, params: {}, query: {} },
121
+ states: {
122
+ login: {
123
+ id: "login",
124
+ meta: {
125
+ route: "/login",
126
+ view: {
127
+ root: "root",
128
+ elements: {
129
+ root: { type: "Login", props: { title: "Sign In" }, children: [] },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ dashboard: {
135
+ id: "dashboard",
136
+ meta: {
137
+ route: "/dashboard",
138
+ view: {
139
+ root: "root",
140
+ elements: {
141
+ root: { type: "Dashboard", props: { username: "" }, children: [] },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ },
147
+ on: {
148
+ "auth.login": {
149
+ target: ".dashboard",
150
+ guard: ({ context }) => !context.isAuthenticated,
151
+ actions: assign({ isAuthenticated: true, username: ({ event }) => event.username }),
152
+ },
153
+ "auth.logout": {
154
+ target: ".login",
155
+ guard: ({ context }) => context.isAuthenticated,
156
+ actions: assign({ isAuthenticated: false, username: null }),
157
+ },
158
+ },
159
+ }),
160
+ );
161
+
162
+ // 5. Create actor and render
163
+ const createPlayer = definePlayer({ machine });
35
164
  const actor = createPlayer();
36
165
  actor.start();
37
166
 
38
- // Define components
39
- const components = {
40
- Home: (props) => <div>Home</div>,
41
- Login: (props) => (
42
- <form onSubmit={(e) => {
43
- e.preventDefault();
44
- props.send({ type: 'auth.login', payload: {...} });
45
- }}>
46
- {props.error && <p>{props.error}</p>}
47
- <input type="text" name="username" />
48
- <button type="submit">Login</button>
49
- </form>
50
- )
51
- };
52
-
53
- // Render
54
- <PlayRenderer actor={actor} components={components} />
167
+ function App() {
168
+ return (
169
+ <PlayUIProvider actor={actor} registryResult={registryResult}>
170
+ <PlayRenderer />
171
+ </PlayUIProvider>
172
+ );
173
+ }
174
+ ```
175
+
176
+ ## API Reference
177
+
178
+ ### `PlayUIProvider`
179
+
180
+ Batteries-included composite provider. Wraps `ActorProvider` + `JSONUIProvider`. Pass `actor` and `registryResult` here, then place `<PlayRenderer />` inside as a zero-prop child.
181
+
182
+ ```tsx
183
+ <PlayUIProvider
184
+ actor={actor}
185
+ registryResult={registryResult}
186
+ store={myStore}
187
+ fallback={<p>Loading…</p>}
188
+ onError={(err) => Sentry.captureException(err)}
189
+ onRenderError={(error, elementType) => console.warn(`<${elementType}> crashed:`, error)}
190
+ >
191
+ <PlayRenderer />
192
+ </PlayUIProvider>
193
+ ```
194
+
195
+ **`actor`** — A `PlayerActor` (or any `AbstractActor & Viewable`). Provides the `currentView` signal.
196
+
197
+ **`registryResult`** — The full `DefineRegistryResult` returned by `defineRegistry(catalog, { components, actions })` from `@xmachines/play-solid`.
198
+
199
+ **`store`** (optional) — Controls per-view UI state (`$state` bindings, form values):
200
+
201
+ - **Omitted (uncontrolled, default):** A fresh `@xstate/store` atom is created per view transition, seeded from `view.spec.state`.
202
+ - **Provided (controlled):** The caller owns the store; `spec.state` is ignored.
203
+
204
+ ```tsx
205
+ import { createAtom } from "@xstate/store";
206
+ import { xstateStoreStateStore } from "@json-render/xstate";
207
+ import type { StateStore } from "@json-render/core";
208
+
209
+ const store: StateStore = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
210
+
211
+ <PlayUIProvider actor={actor} registryResult={registryResult} store={store}>
212
+ <PlayRenderer />
213
+ </PlayUIProvider>;
214
+ ```
215
+
216
+ **`fallback`** — Shown when `actor.currentView.get()` is `null`.
217
+
218
+ **`onError`** — Called when the outer `ErrorBoundary` catches an error. Receives `(error: unknown)`. Use for observability tools.
219
+
220
+ **`onRenderError`** — Called when an individual catalog component throws during render. Caught by `@json-render/solid`'s inner per-element `ErrorBoundary` — the failed component is silently removed while the rest of the spec continues rendering. `onError` / `fallback` are **not** triggered. When both `onRenderError` on `PlayUIProvider` and on `defineRegistry` are set, the prop wins.
221
+
222
+ ---
223
+
224
+ ### `ActorProvider`
225
+
226
+ Escape hatch primitive. Owns actor bridging, signal bridge, and store lifecycle. Use this when you need direct control over the provider layer.
227
+
228
+ ```tsx
229
+ import { ActorProvider } from "@xmachines/play-solid";
230
+
231
+ <ActorProvider
232
+ actor={actor}
233
+ registryResult={registryResult}
234
+ onRenderError={(err, type) => reportError(err, type)}
235
+ >
236
+ {/* your own JSONUIProvider + PlayRenderer tree */}
237
+ </ActorProvider>;
238
+ ```
239
+
240
+ ---
241
+
242
+ ### `PlayRenderer`
243
+
244
+ Zero-prop leaf component. Must be rendered inside a `PlayUIProvider` (or `ActorProvider`) tree. Subscribes to `actor.currentView` via context and renders the current spec.
245
+
246
+ ```tsx
247
+ <PlayUIProvider actor={actor} registryResult={registryResult}>
248
+ <PlayRenderer />
249
+ </PlayUIProvider>
55
250
  ```
56
251
 
57
- ## API
252
+ `PlayRenderer` accepts no props — all configuration (`actor`, `registryResult`, `store`, `fallback`, `onError`, `onRenderError`) is provided by the enclosing `PlayUIProvider` or `ActorProvider`.
253
+
254
+ ## Error handling
255
+
256
+ The provider tree has two layers of error boundaries:
257
+
258
+ ### Outer boundary — `onError` and `fallback`
259
+
260
+ Wraps the entire renderer via a SolidJS `ErrorBoundary`. Triggered when the spec or store setup throws, or when the inner boundary is not present.
261
+
262
+ ```tsx
263
+ <PlayUIProvider
264
+ actor={actor}
265
+ registryResult={registryResult}
266
+ fallback={<p>Something went wrong.</p>}
267
+ onError={(err) => Sentry.captureException(err)}
268
+ >
269
+ <PlayRenderer />
270
+ </PlayUIProvider>
271
+ ```
58
272
 
59
- ### PlayRenderer
273
+ ### Inner boundary — `onRenderError`
60
274
 
61
- Component that observes `actor.currentView` signal and renders the appropriate component from the catalog.
275
+ Each catalog element is individually wrapped in a SolidJS `ErrorBoundary` by `@json-render/solid`. When a component throws, it is silently removed while the rest of the spec continues rendering. The outer boundary is **not** triggered.
62
276
 
63
- **Props:**
277
+ Pass `onRenderError` to `PlayUIProvider` (or `ActorProvider`) — overrides any registry-level handler — or bake it into `defineRegistry`:
64
278
 
65
- - `actor: AbstractActor & Viewable` - Actor instance with currentView signal
66
- - `components: Record<string, Component<any>>` - Map of component names to SolidJS components
67
- - `fallback?: JSX.Element` - Optional fallback to show when currentView is null
279
+ ```tsx
280
+ // via PlayUIProvider prop
281
+ <PlayUIProvider
282
+ actor={actor}
283
+ registryResult={registryResult}
284
+ onRenderError={(error, elementType) => {
285
+ console.warn(`<${elementType}> crashed:`, error);
286
+ }}
287
+ >
288
+ <PlayRenderer />
289
+ </PlayUIProvider>
290
+ ```
68
291
 
69
- **Features:**
292
+ ```ts
293
+ // via defineRegistry — bakes the handler into the registry
294
+ const registryResult = defineRegistry(catalog, {
295
+ components: { Login, Dashboard },
296
+ actions: { login: async (params) => { ... }, logout: async () => { ... } },
297
+ onRenderError(error, elementType) {
298
+ reportExpectedRenderError(error, elementType);
299
+ },
300
+ });
301
+ ```
70
302
 
71
- - Automatically bridges TC39 Signals to SolidJS reactivity
72
- - Passes `send` function to components for event forwarding
73
- - Handles missing components gracefully with error logging
74
- - Uses one-shot watcher re-watch pattern for proper signal observation
303
+ `onRenderError` is typed as `RenderErrorHandler` and exported from `@xmachines/play-solid`.
75
304
 
76
- ## Canonical Watcher Lifecycle
305
+ ---
77
306
 
78
- Use the same watcher flow as React/Vue/router packages:
307
+ ### `useActor`
79
308
 
80
- 1. `notify`
81
- 2. `queueMicrotask`
82
- 3. `getPending()`
83
- 4. read actor signals and update framework-local render trigger
84
- 5. re-arm with `watch(...)` or `watch()`
309
+ Solid hook for accessing the actor from inside any component rendered by `PlayRenderer`. No prop drilling needed.
85
310
 
86
- Watcher notifications are one-shot, so re-arm is mandatory.
311
+ ```tsx
312
+ import { useActor } from "@xmachines/play-solid";
87
313
 
88
- ## Cleanup Contract
314
+ // Inside any component rendered inside PlayRenderer:
315
+ function LogoutButton() {
316
+ const actor = useActor();
317
+ return <button onClick={() => actor.send({ type: "auth.logout" })}>Log Out</button>;
318
+ }
319
+ ```
89
320
 
90
- Solid integrations must perform explicit teardown:
321
+ Throws `NonNullableError: "useActor() must be called inside <ActorProvider> (or <PlayUIProvider>)"` if called outside the tree.
91
322
 
92
- - Use `onCleanup` for lifecycle teardown.
93
- - Call `unwatch(...)` on teardown, not only reference nulling.
94
- - Keep adapters/renderers passive; state validity remains actor-owned.
323
+ ---
95
324
 
96
- ## Architecture
325
+ ## Route Parameters in Props
97
326
 
98
- PlayRenderer follows the XMachines Play architecture:
327
+ When using `formatPlayRouteTransitions`, URL path parameters flow automatically into component props. Declare an `undefined` slot in the spec to opt in:
99
328
 
100
- - **Actor Authority**: Actor controls all state transitions via guards
101
- - **Passive Infrastructure**: Renderer observes signals, sends events
102
- - **Signal-Only Reactivity**: Business logic state lives in actor signals
329
+ ```ts
330
+ // spec: { section: undefined, user: "alice" }
331
+ // After play.route to /settings/profile context.params = { section: "profile" }
332
+ // Component receives: { section: "profile", user: "alice" }
333
+ ```
103
334
 
104
- The renderer bridges TC39 Signals (used by XMachines actors) to SolidJS's reactivity system using `Signal.subtle.Watcher` with a one-shot re-watch pattern.
335
+ Priority: **route param fills `undefined` slots; explicit non-`undefined` spec props always win.**
105
336
 
106
- Signals remain observation plumbing, not an alternate mutation channel.
337
+ ---
107
338
 
108
- ## License
339
+ ## Architecture Notes
109
340
 
110
- MIT
341
+ - SolidJS signals are only used to trigger re-renders — not for business logic
342
+ - `actor.currentView` (TC39 Signal) is bridged into a SolidJS `createSignal` inside `PlayRenderer`
343
+ - Per-view UI state lives in an `@xstate/store` atom, not in SolidJS reactive state
344
+ - `@json-render/solid` drives rendering; `PlayRenderer` is the signal bridge — import `defineRegistry`, `ComponentFn`, `ComponentContext`, and `useBoundProp` from `@xmachines/play-solid`
@@ -0,0 +1,94 @@
1
+ import { ActorContext as e } from "./useActor.js";
2
+ import { createComponent as t } from "solid-js/web";
3
+ import { StateProvider as n, useStateStore as r } from "@json-render/solid";
4
+ import { ErrorBoundary as i, createContext as a, createEffect as o, createMemo as s, createSignal as c, onCleanup as l, useContext as u } from "solid-js";
5
+ import { createAtom as d } from "@xstate/store";
6
+ import { xstateStoreStateStore as f } from "@json-render/xstate";
7
+ import { watchSignal as p } from "@xmachines/play-signals";
8
+ import { assertNonNullable as m } from "@xmachines/play";
9
+ //#region src/ActorProvider.tsx
10
+ var h = a(null);
11
+ function g() {
12
+ return m(u(h), "ViewContext");
13
+ }
14
+ var _ = (e) => {
15
+ let n = r(), i = (e) => {
16
+ let t = n.getSnapshot();
17
+ n.update(e(t));
18
+ }, a = e.registryResult.handlers(() => i, () => n.getSnapshot()), o = {
19
+ spec: e.spec,
20
+ handlers: a,
21
+ registry: e.registryResult.registry,
22
+ store: e.store
23
+ };
24
+ return t(h.Provider, {
25
+ value: o,
26
+ get children() {
27
+ return e.children;
28
+ }
29
+ });
30
+ }, v = (r) => {
31
+ let [a, u] = c(null), m = s(() => {
32
+ if (!r.onRenderError) return r.registryResult;
33
+ let e = { ...r.registryResult.registry };
34
+ return Object.defineProperty(e, "onRenderError", {
35
+ value: r.onRenderError,
36
+ enumerable: !1,
37
+ configurable: !0
38
+ }), {
39
+ ...r.registryResult,
40
+ registry: e
41
+ };
42
+ }), h = null, g = null;
43
+ return o(() => {
44
+ let e = (e) => u(e);
45
+ e(r.actor.currentView.get());
46
+ let t = p(r.actor.currentView, (t) => {
47
+ e(t);
48
+ });
49
+ l(() => t());
50
+ }), t(e.Provider, {
51
+ get value() {
52
+ return r.actor;
53
+ },
54
+ get children() {
55
+ return t(i, {
56
+ fallback: (e) => (r.onError?.(e), r.fallback ?? null),
57
+ get children() {
58
+ return (() => {
59
+ let e = a();
60
+ if (!e) return r.fallback ?? null;
61
+ let i;
62
+ if (r.store) i = r.store;
63
+ else {
64
+ if (h === null || g !== e) {
65
+ let t = e.state;
66
+ h = f({ atom: d(typeof t == "object" && t && !Array.isArray(t) && (Object.getPrototypeOf(t) === Object.prototype || Object.getPrototypeOf(t) === null) ? t : {}) }), g = e;
67
+ }
68
+ i = h;
69
+ }
70
+ return t(n, {
71
+ store: i,
72
+ get children() {
73
+ return t(_, {
74
+ get registryResult() {
75
+ return m();
76
+ },
77
+ spec: e,
78
+ store: i,
79
+ get children() {
80
+ return r.children;
81
+ }
82
+ });
83
+ }
84
+ });
85
+ })();
86
+ }
87
+ });
88
+ }
89
+ });
90
+ };
91
+ //#endregion
92
+ export { v as ActorProvider, g as usePlayView };
93
+
94
+ //# sourceMappingURL=ActorProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActorProvider.js","names":["createSignal","createEffect","createMemo","onCleanup","createContext","useContext","ErrorBoundary","Component","JSX","StateProvider","useStateStore","DefineRegistryResult","SetState","StateStore","ComponentRegistry","createAtom","xstateStoreStateStore","watchSignal","assertNonNullable","PlaySpec","BaseActorProviderProps","BaseViewContextValue","ActorContext","PlayActor","ViewContextValue","ViewContext","usePlayView","ActorProviderProps","fallback","Element","onError","error","children","ActorProviderInner","registryResult","spec","store","innerProps","stateCtx","setStateAdapter","updater","prev","getSnapshot","update","handlers","viewValue","registry","_$createComponent","Provider","value","ActorProvider","props","view","setView","resolvedRegistryResult","onRenderError","r","Object","defineProperty","enumerable","configurable","internalStore","lastView","nextView","actor","currentView","get","unwatch","err","rawState","state","initialState","Array","isArray","getPrototypeOf","prototype","Record","atom"],"sources":["../src/ActorProvider.tsx"],"sourcesContent":["/**\n * ActorProvider — Smart SolidJS provider component for the XMachines Play actor lifecycle.\n *\n * Escape hatch primitive for library authors who need direct control. Most users should\n * use PlayUIProvider (batteries-included composite) instead.\n *\n * This component:\n * - Subscribes to actor.currentView signal via watchSignal (in component body per Phase 29)\n * - Manages per-view StateStore lifecycle (controlled/uncontrolled)\n * - Resolves action handlers via inner component pattern (inside StateProvider)\n * - Injects onRenderError into registry if provided\n * - Provides ActorContext (actor) and ViewContext (spec + handlers + registry) to children\n * - Wraps render path in SolidJS ErrorBoundary\n *\n * Per D-11: The old `ActorProvider = ActorContext.Provider` alias is removed. This new smart\n * component takes the name. Use `ActorContext.Provider` directly for escape-hatch access.\n *\n * @packageDocumentation\n */\n\nimport {\n\tcreateSignal,\n\tcreateEffect,\n\tcreateMemo,\n\tonCleanup,\n\tcreateContext,\n\tuseContext,\n\tErrorBoundary,\n} from \"solid-js\";\nimport type { Component, JSX } from \"solid-js\";\nimport { StateProvider, useStateStore } from \"@json-render/solid\";\nimport type { DefineRegistryResult, SetState } from \"@json-render/solid\";\nimport type { StateStore } from \"@json-render/core\";\nimport type { ComponentRegistry } from \"@json-render/solid\";\nimport { createAtom } from \"@xstate/store\";\nimport { xstateStoreStateStore } from \"@json-render/xstate\";\nimport { watchSignal } from \"@xmachines/play-signals\";\nimport { assertNonNullable } from \"@xmachines/play\";\nimport type { PlaySpec, BaseActorProviderProps, BaseViewContextValue } from \"@xmachines/play-actor\";\nimport { ActorContext, type PlayActor } from \"./useActor.js\";\n\n// ---------------------------------------------------------------------------\n// ViewContextValue — shape of the context value provided by ActorProvider\n// ---------------------------------------------------------------------------\n\n/**\n * Value provided by ActorProvider's ViewContext.\n * Access via usePlayView() inside the ActorProvider tree.\n */\nexport interface ViewContextValue extends BaseViewContextValue<ComponentRegistry> {}\n\nconst ViewContext = createContext<ViewContextValue | null>(null);\n\n/**\n * Hook to access the current view context inside an ActorProvider tree.\n *\n * @throws {Error} If called outside an ActorProvider (or PlayUIProvider) tree\n *\n * @example\n * ```tsx\n * import { usePlayView } from \"@xmachines/play-solid\";\n *\n * const MyRenderer: Component = () => {\n * const view = usePlayView();\n * return <Renderer spec={view.spec} registry={view.registry} />;\n * };\n * ```\n */\nexport function usePlayView(): ViewContextValue {\n\treturn assertNonNullable(useContext(ViewContext), \"ViewContext\");\n}\n\n// ---------------------------------------------------------------------------\n// ActorProviderProps\n// ---------------------------------------------------------------------------\n\n/**\n * Props for ActorProvider — the escape hatch primitive.\n *\n * For batteries-included usage, prefer PlayUIProvider which wraps ActorProvider\n * with JSONUIProvider and all required sub-providers.\n */\nexport interface ActorProviderProps extends BaseActorProviderProps<DefineRegistryResult> {\n\t/** Optional fallback element shown when currentView is null or ErrorBoundary catches */\n\tfallback?: JSX.Element;\n\n\t/** Optional callback invoked when SolidJS ErrorBoundary catches an error */\n\tonError?: (error: unknown) => void;\n\n\t/** Children — required; must include <PlayRenderer /> (or use PlayUIProvider shorthand) */\n\tchildren: JSX.Element;\n}\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — resolves handlers inside StateProvider tree\n// ---------------------------------------------------------------------------\n\n/**\n * Inner component that runs inside StateProvider so it can call useStateStore()\n * to get live set/getSnapshot for handler resolution.\n */\nconst ActorProviderInner: Component<{\n\tregistryResult: DefineRegistryResult;\n\tspec: PlaySpec;\n\tstore: StateStore;\n\tchildren: JSX.Element;\n}> = (innerProps) => {\n\tconst stateCtx = useStateStore();\n\n\t// Build SetState adapter bridging stateCtx.update/getSnapshot\n\tconst setStateAdapter: SetState = (updater) => {\n\t\tconst prev = stateCtx.getSnapshot();\n\t\tstateCtx.update(updater(prev));\n\t};\n\n\tconst handlers = innerProps.registryResult.handlers(\n\t\t() => setStateAdapter,\n\t\t() => stateCtx.getSnapshot(),\n\t);\n\n\tconst viewValue: ViewContextValue = {\n\t\tspec: innerProps.spec,\n\t\thandlers,\n\t\tregistry: innerProps.registryResult.registry,\n\t\tstore: innerProps.store,\n\t};\n\n\treturn <ViewContext.Provider value={viewValue}>{innerProps.children}</ViewContext.Provider>;\n};\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the smart component (per D-11 takes the ActorProvider name)\n// ---------------------------------------------------------------------------\n\n/**\n * Smart ActorProvider component — owns actor bridging, signal subscription,\n * StateStore lifecycle, handler resolution, and error boundary.\n *\n * Per D-11: Replaces the old raw alias `ActorProvider = ActorContext.Provider`.\n * Consumers who previously used `<ActorProvider value={actor}>` should now use\n * `<ActorContext.Provider value={actor}>` for raw provider access, or migrate to\n * this smart component / PlayUIProvider.\n *\n * @example\n * ```tsx\n * import { ActorProvider, PlayRenderer } from \"@xmachines/play-solid\";\n *\n * <ActorProvider actor={myActor} registryResult={registryResult}>\n * <PlayRenderer />\n * </ActorProvider>\n * ```\n */\nexport const ActorProvider: Component<ActorProviderProps> = (props) => {\n\t// SolidJS signal for current view (PlaySpec | null)\n\tconst [view, setView] = createSignal<PlaySpec | null>(null);\n\n\t// Inject onRenderError into registry if provided (non-enumerable override).\n\t// Memoized so that creating a new object on every reactive evaluation does not\n\t// cause unnecessary re-renders of child components that receive this as a prop.\n\tconst resolvedRegistryResult = createMemo(() => {\n\t\tif (!props.onRenderError) return props.registryResult;\n\t\tconst r = { ...props.registryResult.registry };\n\t\tObject.defineProperty(r, \"onRenderError\", {\n\t\t\tvalue: props.onRenderError,\n\t\t\tenumerable: false,\n\t\t\tconfigurable: true,\n\t\t});\n\t\treturn { ...props.registryResult, registry: r };\n\t});\n\n\t// Per-view internal store — recreated on each view transition (uncontrolled mode)\n\tlet internalStore: StateStore | null = null;\n\tlet lastView: PlaySpec | null = null;\n\n\t// Bridge TC39 Signal to SolidJS signal — seed AND watch atomically inside a single\n\t// createEffect to eliminate the race window between .get() and watcher registration.\n\t// If the TC39 signal changes between the initial .get() and first watcher notification,\n\t// the update function captures the latest value without missing it.\n\tcreateEffect(() => {\n\t\tconst update = (nextView: PlaySpec | null) => setView(nextView);\n\t\tupdate(props.actor.currentView.get() as PlaySpec | null);\n\t\tconst unwatch = watchSignal(props.actor.currentView, (nextView) => {\n\t\t\tupdate(nextView as PlaySpec | null);\n\t\t});\n\t\tonCleanup(() => unwatch());\n\t});\n\n\treturn (\n\t\t<ActorContext.Provider value={props.actor as PlayActor}>\n\t\t\t<ErrorBoundary\n\t\t\t\tfallback={(err: unknown) => {\n\t\t\t\t\tprops.onError?.(err);\n\t\t\t\t\treturn props.fallback ?? null;\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{(() => {\n\t\t\t\t\tconst currentView = view();\n\t\t\t\t\tif (!currentView) return props.fallback ?? null;\n\n\t\t\t\t\t// Resolve store: external (controlled) or internal per-view atom\n\t\t\t\t\tlet store: StateStore;\n\t\t\t\t\tif (props.store) {\n\t\t\t\t\t\tstore = props.store;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (internalStore === null || lastView !== currentView) {\n\t\t\t\t\t\t\t// Proto-safe guard: spec.state must be a plain object (T-37-05-02)\n\t\t\t\t\t\t\tconst rawState = currentView.state;\n\t\t\t\t\t\t\tconst initialState =\n\t\t\t\t\t\t\t\trawState !== null &&\n\t\t\t\t\t\t\t\ttypeof rawState === \"object\" &&\n\t\t\t\t\t\t\t\t!Array.isArray(rawState) &&\n\t\t\t\t\t\t\t\t(Object.getPrototypeOf(rawState) === Object.prototype ||\n\t\t\t\t\t\t\t\t\tObject.getPrototypeOf(rawState) === null)\n\t\t\t\t\t\t\t\t\t? (rawState as Record<string, unknown>)\n\t\t\t\t\t\t\t\t\t: {};\n\t\t\t\t\t\t\tinternalStore = xstateStoreStateStore({\n\t\t\t\t\t\t\t\tatom: createAtom(initialState),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlastView = currentView;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstore = internalStore;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<StateProvider store={store}>\n\t\t\t\t\t\t\t<ActorProviderInner\n\t\t\t\t\t\t\t\tregistryResult={resolvedRegistryResult()}\n\t\t\t\t\t\t\t\tspec={currentView}\n\t\t\t\t\t\t\t\tstore={store}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{props.children}\n\t\t\t\t\t\t\t</ActorProviderInner>\n\t\t\t\t\t\t</StateProvider>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\t\t\t</ErrorBoundary>\n\t\t</ActorContext.Provider>\n\t);\n};\n"],"mappings":";;;;;;;;;AAmDA,IAAMyB,IAAcrB,EAAuC,KAAK;AAiBhE,SAAgBsB,IAAgC;AAC/C,QAAOR,EAAkBb,EAAWoB,EAAY,EAAE,cAAc;;AAgCjE,IAAMQ,KAKAI,MAAe;CACpB,IAAMC,IAAW5B,GAAe,EAG1B6B,KAA6BC,MAAY;EAC9C,IAAMC,IAAOH,EAASI,aAAa;AACnCJ,IAASK,OAAOH,EAAQC,EAAK,CAAC;IAGzBG,IAAWP,EAAWH,eAAeU,eACpCL,SACAD,EAASI,aAChB,CAAC,EAEKG,IAA8B;EACnCV,MAAME,EAAWF;EACjBS;EACAE,UAAUT,EAAWH,eAAeY;EACpCV,OAAOC,EAAWD;EAClB;AAED,QAAAW,EAAQtB,EAAYuB,UAAQ;EAACC,OAAOJ;EAAS,IAAAb,WAAA;AAAA,UAAGK,EAAWL;;EAAQ,CAAA;GAyBvDkB,KAAgDC,MAAU;CAEtE,IAAM,CAACC,GAAMC,KAAWrD,EAA8B,KAAK,EAKrDsD,IAAyBpD,QAAiB;AAC/C,MAAI,CAACiD,EAAMI,cAAe,QAAOJ,EAAMjB;EACvC,IAAMsB,IAAI,EAAE,GAAGL,EAAMjB,eAAeY,UAAU;AAM9C,SALAW,OAAOC,eAAeF,GAAG,iBAAiB;GACzCP,OAAOE,EAAMI;GACbI,YAAY;GACZC,cAAc;GACd,CAAC,EACK;GAAE,GAAGT,EAAMjB;GAAgBY,UAAUU;GAAG;GAC9C,EAGEK,IAAmC,MACnCC,IAA4B;AAehC,QATA7D,QAAmB;EAClB,IAAM0C,KAAUoB,MAA8BV,EAAQU,EAAS;AAC/DpB,IAAOQ,EAAMa,MAAMC,YAAYC,KAAK,CAAoB;EACxD,IAAMC,IAAUlD,EAAYkC,EAAMa,MAAMC,cAAcF,MAAa;AAClEpB,KAAOoB,EAA4B;IAClC;AACF5D,UAAgBgE,GAAS,CAAC;GACzB,EAEFpB,EACEzB,EAAa0B,UAAQ;EAAA,IAACC,QAAK;AAAA,UAAEE,EAAMa;;EAAkB,IAAAhC,WAAA;AAAA,UAAAe,EACpDzC,GAAa;IACbsB,WAAWwC,OACVjB,EAAMrB,UAAUsC,EAAI,EACbjB,EAAMvB,YAAY;IACzB,IAAAI,WAAA;AAAA,mBAEO;MACP,IAAMiC,IAAcb,GAAM;AAC1B,UAAI,CAACa,EAAa,QAAOd,EAAMvB,YAAY;MAG3C,IAAIQ;AACJ,UAAIe,EAAMf,MACTA,KAAQe,EAAMf;WACR;AACN,WAAIyB,MAAkB,QAAQC,MAAaG,GAAa;QAEvD,IAAMI,IAAWJ,EAAYK;AAY7BR,QAHAD,IAAgB7C,EAAsB,EACrC6D,MAAM9D,EAPN,OAAOsD,KAAa,YADpBA,KAEA,CAACG,MAAMC,QAAQJ,EAAS,KACvBZ,OAAOiB,eAAeL,EAAS,KAAKZ,OAAOkB,aAC3ClB,OAAOiB,eAAeL,EAAS,KAAK,QACjCA,IACD,EAAE,CAEwB,EAC7B,CAAC,EACFP,IAAWG;;AAEZ7B,WAAQyB;;AAGT,aAAAd,EACEtC,GAAa;OAAQ2B;OAAK,IAAAJ,WAAA;AAAA,eAAAe,EACzBd,GAAkB;SAAA,IAClBC,iBAAc;AAAA,iBAAEoB,GAAwB;;SACxCnB,MAAM8B;SACC7B;SAAK,IAAAJ,WAAA;AAAA,iBAEXmB,EAAMnB;;SAAQ,CAAA;;OAAA,CAAA;SAIf;;IAAA,CAAA;;EAAA,CAAA"}
@@ -1,31 +1,19 @@
1
- import { Dynamic as e, createComponent as t, insert as n, memo as r, mergeProps as i, template as a } from "solid-js/web";
2
- import { createSignal as o, onMount as s } from "solid-js";
3
- import { Signal as c } from "@xmachines/play-signals";
1
+ import { usePlayView as e } from "./ActorProvider.js";
2
+ import { createComponent as t } from "solid-js/web";
3
+ import { Renderer as n } from "@json-render/solid";
4
4
  //#region src/PlayRenderer.tsx
5
- var l = /* @__PURE__ */ a("<div class=play-renderer-error>Component \"<!>\" not found in catalog. Available: "), u = (a) => {
6
- let [u, d] = o(a.actor.currentView.get());
7
- s(() => {
8
- let e = new c.subtle.Watcher(() => {
9
- queueMicrotask(() => {
10
- e.getPending(), d(a.actor.currentView.get()), e.watch(a.actor.currentView);
11
- });
12
- });
13
- e.watch(a.actor.currentView);
5
+ var r = () => {
6
+ let r = e();
7
+ return t(n, {
8
+ get spec() {
9
+ return r.spec;
10
+ },
11
+ get registry() {
12
+ return r.registry;
13
+ }
14
14
  });
15
- let f = a.actor.send.bind(a.actor);
16
- return [
17
- r(() => r(() => !u())() && (a.fallback || null)),
18
- r(() => r(() => !!(u() && !a.components))() && (console.error(`Components catalog is ${a.components === null ? "null" : "undefined"}. Cannot render component "${u().component}".`), a.fallback || null)),
19
- r(() => r(() => !!(u() && a.components && !a.components[u().component]))() && (console.error(`Component "${u().component}" not found in catalog. Available components: ${Object.keys(a.components).join(", ")}`), (() => {
20
- var e = l(), t = e.firstChild.nextSibling;
21
- return t.nextSibling, n(e, () => u().component, t), n(e, () => Object.keys(a.components).join(", "), null), e;
22
- })())),
23
- r(() => r(() => !!(u() && a.components && a.components[u().component]))() && t(e, i({ get component() {
24
- return a.components[u().component];
25
- } }, () => u().props, { send: f })))
26
- ];
27
15
  };
28
16
  //#endregion
29
- export { u as PlayRenderer };
17
+ export { r as PlayRenderer };
30
18
 
31
19
  //# sourceMappingURL=PlayRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","names":["createSignal","onMount","Component","Dynamic","Signal","PlayRendererProps","SolidView","PlayRenderer","props","view","setView","actor","currentView","get","watcher","subtle","Watcher","queueMicrotask","getPending","watch","sendBound","send","bind","_$memo","fallback","components","console","error","component","Object","keys","join","_el$","_tmpl$","_el$2","firstChild","_el$5","nextSibling","_el$3","_$insert","_$createComponent","_$mergeProps"],"sources":["../src/PlayRenderer.tsx"],"sourcesContent":["/**\n * PlayRenderer - Main SolidJS renderer component for XMachines Play architecture\n *\n * @packageDocumentation\n */\n\nimport { createSignal, onMount, type Component } from \"solid-js\";\nimport { Dynamic } from \"solid-js/web\";\nimport { Signal } from \"@xmachines/play-signals\";\nimport type { PlayRendererProps, SolidView } from \"./types.js\";\n\n/**\n * Main renderer component that subscribes to actor signals and renders UI\n *\n * Architecture (per XMachines Play patterns):\n * - Subscribes to actor.currentView signal via TC39 Signal.subtle.Watcher\n * - Dynamically renders catalog components based on view.component string\n * - Forwards user events to actor via actor.send()\n * - SolidJS signal only for triggering renders, NOT business logic\n *\n * Invariant: Actor Authority - Actor decides all state transitions via guards.\n * Invariant: Passive Infrastructure - Component observes signals and sends events.\n * Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.\n *\n * @example\n * ```typescript\n * import { PlayRenderer } from \"@xmachines/play-solidjs\";\n * import { definePlayer } from \"@xmachines/play-xstate\";\n *\n * const actor = definePlayer({ machine, catalog })();\n * actor.start();\n *\n * const components = {\n * Dashboard: (props) => <div>User: {props.userId}</div>,\n * LoginForm: (props) => (\n * <form onSubmit={(e) => {\n * e.preventDefault();\n * props.send({ type: \"auth.login\", payload: {...} });\n * }}>...</form>\n * )\n * };\n *\n * <PlayRenderer actor={actor} components={components} />\n * ```\n *\n * @param props - Component props\n * @returns SolidJS element rendering current view from actor\n *\n * @remarks\n * **Component lookup:** Dynamically looks up component from `components` map\n * using `view.component` string from actor.currentView signal.\n *\n * **Event forwarding:** Injects `send` function as prop to components. Components\n * call `send(event)` to forward intents to actor. Actor guards decide validity.\n *\n * **Error handling:** If component not found in catalog, logs error and shows\n * fallback. This indicates missing component registration, not runtime error.\n *\n * **Signal bridge:** Uses one-shot re-watch pattern. TC39 Signal watchers stop\n * watching after notification, so watcher.watch() must be called in microtask\n * after getPending() to re-arm for next notification.\n *\n * **CRITICAL:** Never call actor.send() during render - only in event handlers.\n * Calling send during render causes infinite render loops.\n */\nexport const PlayRenderer: Component<PlayRendererProps> = (props) => {\n\t// Create SolidJS signal for view\n\t// Signal is NOT business logic state - it's just SolidJS's render trigger\n\tconst [view, setView] = createSignal<SolidView>(props.actor.currentView.get() as SolidView);\n\n\t// Bridge TC39 Signal to SolidJS signal\n\t// Uses one-shot re-watch pattern (must re-watch after each notification)\n\tonMount(() => {\n\t\tconst watcher = new Signal.subtle.Watcher(() => {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\t// Acknowledge the notification\n\t\t\t\twatcher.getPending();\n\n\t\t\t\t// Update SolidJS signal (triggers SolidJS reactivity)\n\t\t\t\tsetView(props.actor.currentView.get() as SolidView);\n\n\t\t\t\t// Re-watch for next notification (one-shot pattern)\n\t\t\t\t// TC39 Signal watchers stop watching after notification\n\t\t\t\twatcher.watch(props.actor.currentView);\n\t\t\t});\n\t\t});\n\n\t\t// Watch actor.currentView for changes\n\t\twatcher.watch(props.actor.currentView);\n\n\t\t// Note: TC39 Signal watchers don't have explicit disposal\n\t\t// The watcher will be garbage collected when the component unmounts\n\t});\n\n\t// Bind send function (ensures correct 'this' context)\n\tconst sendBound = props.actor.send.bind(props.actor);\n\n\treturn (\n\t\t<>\n\t\t\t{/* No view - show fallback */}\n\t\t\t{!view() && (props.fallback || null)}\n\n\t\t\t{/* Handle null/undefined components catalog gracefully */}\n\t\t\t{view() &&\n\t\t\t\t!props.components &&\n\t\t\t\t(() => {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Components catalog is ${props.components === null ? \"null\" : \"undefined\"}. ` +\n\t\t\t\t\t\t\t`Cannot render component \"${view()!.component}\".`,\n\t\t\t\t\t);\n\t\t\t\t\treturn props.fallback || null;\n\t\t\t\t})()}\n\n\t\t\t{/* View exists but component not found */}\n\t\t\t{view() &&\n\t\t\t\tprops.components &&\n\t\t\t\t!props.components[view()!.component] &&\n\t\t\t\t(() => {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Component \"${view()!.component}\" not found in catalog. ` +\n\t\t\t\t\t\t\t`Available components: ${Object.keys(props.components).join(\", \")}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div class=\"play-renderer-error\">\n\t\t\t\t\t\t\tComponent \"{view()!.component}\" not found in catalog. Available:{\" \"}\n\t\t\t\t\t\t\t{Object.keys(props.components).join(\", \")}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})()}\n\n\t\t\t{/* Render matched component dynamically */}\n\t\t\t{view() && props.components && props.components[view()!.component] && (\n\t\t\t\t<Dynamic\n\t\t\t\t\tcomponent={props.components[view()!.component]}\n\t\t\t\t\t{...view()!.props}\n\t\t\t\t\tsend={sendBound}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n"],"mappings":";;;;iHAiEaO,KAA8CC,MAAU;CAGpE,IAAM,CAACC,GAAMC,KAAWV,EAAwBQ,EAAMG,MAAMC,YAAYC,KAAK,CAAc;AAI3FZ,SAAc;EACb,IAAMa,IAAU,IAAIV,EAAOW,OAAOC,cAAc;AAC/CC,wBAAqB;AASpBH,IAPAA,EAAQI,YAAY,EAGpBR,EAAQF,EAAMG,MAAMC,YAAYC,KAAK,CAAc,EAInDC,EAAQK,MAAMX,EAAMG,MAAMC,YAAY;KACrC;IACD;AAGFE,IAAQK,MAAMX,EAAMG,MAAMC,YAAY;GAIrC;CAGF,IAAMQ,IAAYZ,EAAMG,MAAMU,KAAKC,KAAKd,EAAMG,MAAM;AAEpD,QAAA;EAAAY,QAGGA,QAAA,CAACd,GAAM,CAAA,EAAA,KAAKD,EAAMgB,YAAY,MAAK;EAAAD,QAGnCA,QAAA,CAAA,EAAAd,GAAM,IACN,CAACD,EAAMiB,YAAU,EAAA,KAEhBC,QAAQC,MACP,yBAAyBnB,EAAMiB,eAAe,OAAO,SAAS,YAAW,6BAC5ChB,GAAM,CAAEmB,UAAS,IAC9C,EACMpB,EAAMgB,YAAY,MACtB;EAAAD,QAGJA,QAAA,CAAA,EAAAd,GAAM,IACND,EAAMiB,cACN,CAACjB,EAAMiB,WAAWhB,GAAM,CAAEmB,YAAU,EAAA,KAEnCF,QAAQC,MACP,cAAclB,GAAM,CAAEmB,UAAS,gDACLC,OAAOC,KAAKtB,EAAMiB,WAAW,CAACM,KAAK,KAAK,GAClE,SACD;GAAA,IAAAC,IAAAC,GAAA,EAAAG,IAAAJ,EAAAG,WAAAE;AAG2C,UAH3CD,EAAAC,aAAAE,EAAAP,SAEcvB,GAAM,CAAEmB,WAASQ,EAAA,EAAAG,EAAAP,SAC5BH,OAAOC,KAAKtB,EAAMiB,WAAW,CAACM,KAAK,KAAK,EAAA,KAAA,EAAAC;MAAA,EAGxC;EAAAT,QAGJA,QAAA,CAAA,EAAAd,GAAM,IAAID,EAAMiB,cAAcjB,EAAMiB,WAAWhB,GAAM,CAAEmB,YAAU,EAAA,IAAAY,EAChErC,GAAOsC,EAAA,EAAA,IACPb,YAAS;AAAA,UAAEpB,EAAMiB,WAAWhB,GAAM,CAAEmB;KAAU,QAC1CnB,GAAM,CAAED,OAAK,EACjBa,MAAMD,GAAS,CAAA,CAEhB,CAAA;EAAA"}
1
+ {"version":3,"file":"PlayRenderer.js","names":["Component","Renderer","usePlayView","PlayRenderer","view","_$createComponent","spec","registry"],"sources":["../src/PlayRenderer.tsx"],"sourcesContent":["/**\n * PlayRenderer - Zero-prop leaf component for XMachines Play SolidJS architecture.\n *\n * Reads view context from the enclosing ActorProvider (or PlayUIProvider) via\n * usePlayView() and renders the spec using @json-render/solid's Renderer.\n *\n * Standard usage:\n * ```tsx\n * <PlayUIProvider actor={myActor} registryResult={registryResult}>\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Component } from \"solid-js\";\nimport { Renderer } from \"@json-render/solid\";\nimport { usePlayView } from \"./ActorProvider.js\";\n\n/**\n * Zero-prop leaf renderer. Must be placed inside an ActorProvider or PlayUIProvider tree.\n *\n * Reads ViewContextValue (spec, handlers, registry) from the enclosing provider\n * via usePlayView() and renders the spec via @json-render/solid's Renderer.\n */\nexport const PlayRenderer: Component = () => {\n\tconst view = usePlayView();\n\treturn <Renderer spec={view.spec} registry={view.registry} />;\n};\n"],"mappings":";;;;AA0BA,IAAaG,UAAgC;CAC5C,IAAMC,IAAOF,GAAa;AAC1B,QAAAG,EAAQJ,GAAQ;EAAA,IAACK,OAAI;AAAA,UAAEF,EAAKE;;EAAI,IAAEC,WAAQ;AAAA,UAAEH,EAAKG;;EAAQ,CAAA"}
@@ -0,0 +1,35 @@
1
+ import { ActorProvider as e, usePlayView as t } from "./ActorProvider.js";
2
+ import { createComponent as n, mergeProps as r } from "solid-js/web";
3
+ import { JSONUIProvider as i } from "@json-render/solid";
4
+ //#region src/PlayUIProvider.tsx
5
+ var a = (e) => {
6
+ let a = t();
7
+ return n(i, r({
8
+ get registry() {
9
+ return a.registry;
10
+ },
11
+ get handlers() {
12
+ return a.handlers;
13
+ },
14
+ get store() {
15
+ return a.store;
16
+ }
17
+ }, () => e.validationFunctions !== void 0 && { validationFunctions: e.validationFunctions }, () => e.navigate !== void 0 && { navigate: e.navigate }, () => e.functions !== void 0 && { functions: e.functions }, { get children() {
18
+ return e.children;
19
+ } }));
20
+ }, o = (t) => n(e, r({
21
+ get actor() {
22
+ return t.actor;
23
+ },
24
+ get registryResult() {
25
+ return t.registryResult;
26
+ }
27
+ }, () => t.store !== void 0 && { store: t.store }, () => t.fallback !== void 0 && { fallback: t.fallback }, () => t.onError !== void 0 && { onError: t.onError }, () => t.onRenderError !== void 0 && { onRenderError: t.onRenderError }, { get children() {
28
+ return n(a, r(() => t.validationFunctions !== void 0 && { validationFunctions: t.validationFunctions }, () => t.navigate !== void 0 && { navigate: t.navigate }, () => t.functions !== void 0 && { functions: t.functions }, { get children() {
29
+ return t.children;
30
+ } }));
31
+ } }));
32
+ //#endregion
33
+ export { o as PlayUIProvider };
34
+
35
+ //# sourceMappingURL=PlayUIProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayUIProvider.js","names":["Component","JSX","JSONUIProvider","JSONUIProviderProps","ActorProvider","usePlayView","ActorProviderProps","JSONUIForwardedProps","Pick","PlayUIProviderProps","Partial","JSONUIBridge","children","Element","bridgeProps","view","_$createComponent","_$mergeProps","registry","handlers","store","validationFunctions","undefined","navigate","functions","PlayUIProvider","props","actor","registryResult","fallback","onError","onRenderError"],"sources":["../src/PlayUIProvider.tsx"],"sourcesContent":["/**\n * PlayUIProvider — Batteries-included SolidJS provider for XMachines Play.\n *\n * Wraps ActorProvider + JSONUIProvider into a single composite provider.\n * This is the recommended entry point for most users.\n *\n * Standard usage:\n * ```tsx\n * import { PlayUIProvider, PlayRenderer, defineRegistry } from \"@xmachines/play-solid\";\n *\n * const registryResult = defineRegistry(myCatalog, { components, actions });\n *\n * <PlayUIProvider actor={myActor} registryResult={registryResult}>\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For full control (library authors), use ActorProvider directly.\n *\n * @packageDocumentation\n */\n\nimport type { Component, JSX } from \"solid-js\";\nimport { JSONUIProvider, type JSONUIProviderProps } from \"@json-render/solid\";\nimport { ActorProvider, usePlayView, type ActorProviderProps } from \"./ActorProvider.js\";\n\n// Pick only the forwarded props from JSONUIProviderProps (per D-16)\ntype JSONUIForwardedProps = Pick<\n\tJSONUIProviderProps,\n\t\"validationFunctions\" | \"navigate\" | \"functions\"\n>;\n\n/**\n * Props for PlayUIProvider — all ActorProvider props plus JSONUIProvider's forwarded props.\n */\nexport interface PlayUIProviderProps extends ActorProviderProps, Partial<JSONUIForwardedProps> {}\n\n/**\n * Inner bridge component — must be inside ActorProvider's tree so usePlayView() has\n * access to the resolved ViewContextValue. Reads handlers and registry from the view\n * context and passes them to JSONUIProvider.\n *\n * This bridge pattern mirrors the React implementation (JSONUIBridge in play-react).\n */\nconst JSONUIBridge: Component<Partial<JSONUIForwardedProps> & { children: JSX.Element }> = (\n\tbridgeProps,\n) => {\n\tconst view = usePlayView();\n\n\treturn (\n\t\t<JSONUIProvider\n\t\t\tregistry={view.registry}\n\t\t\thandlers={view.handlers}\n\t\t\tstore={view.store}\n\t\t\t{...(bridgeProps.validationFunctions !== undefined && {\n\t\t\t\tvalidationFunctions: bridgeProps.validationFunctions,\n\t\t\t})}\n\t\t\t{...(bridgeProps.navigate !== undefined && { navigate: bridgeProps.navigate })}\n\t\t\t{...(bridgeProps.functions !== undefined && { functions: bridgeProps.functions })}\n\t\t>\n\t\t\t{bridgeProps.children}\n\t\t</JSONUIProvider>\n\t);\n};\n\n/**\n * Batteries-included composite provider: ActorProvider + JSONUIProvider.\n *\n * Provides the full JSON render context stack:\n * - ActorContext (actor instance via ActorProvider)\n * - ViewContext (spec, handlers, registry via ActorProvider)\n * - StateProvider + ActionProvider + VisibilityProvider + ValidationProvider (via JSONUIProvider)\n * - ConfirmDialogManager (via JSONUIProvider)\n *\n * @example\n * ```tsx\n * <PlayUIProvider actor={myActor} registryResult={registryResult} navigate={navigate}>\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n */\nexport const PlayUIProvider: Component<PlayUIProviderProps> = (props) => {\n\treturn (\n\t\t<ActorProvider\n\t\t\tactor={props.actor}\n\t\t\tregistryResult={props.registryResult}\n\t\t\t{...(props.store !== undefined && { store: props.store })}\n\t\t\t{...(props.fallback !== undefined && { fallback: props.fallback })}\n\t\t\t{...(props.onError !== undefined && { onError: props.onError })}\n\t\t\t{...(props.onRenderError !== undefined && { onRenderError: props.onRenderError })}\n\t\t>\n\t\t\t<JSONUIBridge\n\t\t\t\t{...(props.validationFunctions !== undefined && {\n\t\t\t\t\tvalidationFunctions: props.validationFunctions,\n\t\t\t\t})}\n\t\t\t\t{...(props.navigate !== undefined && { navigate: props.navigate })}\n\t\t\t\t{...(props.functions !== undefined && { functions: props.functions })}\n\t\t\t>\n\t\t\t\t{props.children}\n\t\t\t</JSONUIBridge>\n\t\t</ActorProvider>\n\t);\n};\n"],"mappings":";;;;AA4CA,IAAMW,KACLG,MACI;CACJ,IAAMC,IAAOV,GAAa;AAE1B,QAAAW,EACEd,GAAce,EAAA;EAAA,IACdC,WAAQ;AAAA,UAAEH,EAAKG;;EAAQ,IACvBC,WAAQ;AAAA,UAAEJ,EAAKI;;EAAQ,IACvBC,QAAK;AAAA,UAAEL,EAAKK;;EAAK,QACZN,EAAYO,wBAAwBC,KAAAA,KAAa,EACrDD,qBAAqBP,EAAYO,qBACjC,QACIP,EAAYS,aAAaD,KAAAA,KAAa,EAAEC,UAAUT,EAAYS,UAAU,QACxET,EAAYU,cAAcF,KAAAA,KAAa,EAAEE,WAAWV,EAAYU,WAAW,EAAA,EAAA,IAAAZ,WAAA;AAAA,SAE/EE,EAAYF;IAAQ,CAAA,CAAA;GAqBXa,KAAkDC,MAC9DV,EACEZ,GAAaa,EAAA;CAAA,IACbU,QAAK;AAAA,SAAED,EAAMC;;CAAK,IAClBC,iBAAc;AAAA,SAAEF,EAAME;;CAAc,QAC/BF,EAAMN,UAAUE,KAAAA,KAAa,EAAEF,OAAOM,EAAMN,OAAO,QACnDM,EAAMG,aAAaP,KAAAA,KAAa,EAAEO,UAAUH,EAAMG,UAAU,QAC5DH,EAAMI,YAAYR,KAAAA,KAAa,EAAEQ,SAASJ,EAAMI,SAAS,QACzDJ,EAAMK,kBAAkBT,KAAAA,KAAa,EAAES,eAAeL,EAAMK,eAAe,EAAA,EAAA,IAAAnB,WAAA;AAAA,QAAAI,EAE/EL,GAAYM,QACPS,EAAML,wBAAwBC,KAAAA,KAAa,EAC/CD,qBAAqBK,EAAML,qBAC3B,QACIK,EAAMH,aAAaD,KAAAA,KAAa,EAAEC,UAAUG,EAAMH,UAAU,QAC5DG,EAAMF,cAAcF,KAAAA,KAAa,EAAEE,WAAWE,EAAMF,WAAW,EAAA,EAAA,IAAAZ,WAAA;AAAA,SAEnEc,EAAMd;IAAQ,CAAA,CAAA;GAAA,CAAA,CAAA"}
package/dist/index.js CHANGED
@@ -1,2 +1,6 @@
1
- import { PlayRenderer as e } from "./PlayRenderer.js";
2
- export { e as PlayRenderer };
1
+ import { ActorContext as e, useActor as t } from "./useActor.js";
2
+ import { ActorProvider as n, usePlayView as r } from "./ActorProvider.js";
3
+ import { PlayRenderer as i } from "./PlayRenderer.js";
4
+ import { PlayUIProvider as a } from "./PlayUIProvider.js";
5
+ import { ActionProvider as o, JSONUIProvider as s, Renderer as c, StateProvider as l, ValidationProvider as u, VisibilityProvider as d, defineRegistry as f, useAction as p, useActions as m, useBoundProp as h, useFieldValidation as g, useIsVisible as _, useOptionalValidation as v, useStateBinding as y, useStateStore as b, useStateValue as x, useVisibility as S } from "@json-render/solid";
6
+ export { o as ActionProvider, e as ActorContext, n as ActorProvider, s as JSONUIProvider, i as PlayRenderer, a as PlayUIProvider, c as Renderer, l as StateProvider, u as ValidationProvider, d as VisibilityProvider, f as defineRegistry, p as useAction, m as useActions, t as useActor, h as useBoundProp, g as useFieldValidation, _ as useIsVisible, v as useOptionalValidation, r as usePlayView, y as useStateBinding, b as useStateStore, x as useStateValue, S as useVisibility };
@@ -0,0 +1,11 @@
1
+ import { createContext as e, useContext as t } from "solid-js";
2
+ import { assertNonNullable as n } from "@xmachines/play";
3
+ //#region src/useActor.ts
4
+ var r = e(null);
5
+ function i() {
6
+ return n(t(r), "ActorContext");
7
+ }
8
+ //#endregion
9
+ export { r as ActorContext, i as useActor };
10
+
11
+ //# sourceMappingURL=useActor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useActor.js","names":[],"sources":["../src/useActor.ts"],"sourcesContent":["/**\n * useActor — SolidJS hook for accessing the raw actor inside an ActorProvider tree.\n *\n * Components rendered inside ActorProvider (or PlayUIProvider) can call useActor()\n * to get direct access to the actor instance without prop drilling.\n *\n * @throws {Error} If called outside an ActorProvider tree\n *\n * @example\n * ```typescript\n * import { useActor } from \"@xmachines/play-solid\";\n *\n * function MyComponent() {\n * const actor = useActor();\n * return <button onClick={() => actor.send({ type: \"SUBMIT\" })}>Submit</button>;\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { createContext, useContext } from \"solid-js\";\nimport { assertNonNullable } from \"@xmachines/play\";\nimport type { AbstractActor } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\n\nexport type PlayActor = AbstractActor<AnyActorLogic>;\n\n/**\n * SolidJS context for the actor — exported so consumers can use ActorContext.Provider\n * directly as an escape hatch (per D-11). The smart ActorProvider component takes\n * the name \"ActorProvider\" and is the recommended entry point.\n */\nexport const ActorContext = createContext<PlayActor | null>(null);\n\nexport function useActor(): PlayActor {\n\treturn assertNonNullable(useContext(ActorContext), \"ActorContext\");\n}\n"],"mappings":";;;AAiCA,IAAa,IAAe,EAAgC,KAAK;AAEjE,SAAgB,IAAsB;AACrC,QAAO,EAAkB,EAAW,EAAa,EAAE,eAAe"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xmachines/play-solid",
3
- "version": "1.0.0-beta.4",
4
- "description": "SolidJS renderer for XMachines Play architecture",
3
+ "version": "1.0.0-beta.41",
4
+ "description": "Solid renderer for XMachines Play architecture",
5
5
  "keywords": [
6
6
  "catalog",
7
7
  "play",
@@ -20,6 +20,7 @@
20
20
  "type": "module",
21
21
  "exports": {
22
22
  ".": {
23
+ "source": "./src/index.ts",
23
24
  "types": "./dist/index.d.ts",
24
25
  "default": "./dist/index.js"
25
26
  }
@@ -29,29 +30,44 @@
29
30
  },
30
31
  "scripts": {
31
32
  "build": "vite build && tsc --build",
32
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
33
- "typecheck": "tsc --noEmit",
34
- "test": "vitest run",
33
+ "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__ node_modules/.svelte2tsx-*",
34
+ "lint": "oxlint .",
35
+ "format": "oxfmt .",
36
+ "test": "vitest",
35
37
  "test:watch": "vitest",
36
38
  "test:ui": "vitest --ui",
37
39
  "prepublishOnly": "npm run build"
38
40
  },
39
41
  "dependencies": {
40
- "@xmachines/play-actor": "1.0.0-beta.4",
41
- "@xmachines/play-catalog": "1.0.0-beta.4",
42
- "@xmachines/play-signals": "1.0.0-beta.4"
42
+ "@xmachines/play": "1.0.0-beta.41",
43
+ "@xmachines/play-actor": "1.0.0-beta.41",
44
+ "@xmachines/play-signals": "1.0.0-beta.41"
43
45
  },
44
46
  "devDependencies": {
47
+ "@json-render/core": "^0.18.0",
48
+ "@json-render/solid": "^0.18.0",
49
+ "@json-render/xstate": "^0.18.0",
45
50
  "@solidjs/testing-library": "^0.8.10",
46
- "@types/node": "^25.5.0",
47
- "@xmachines/shared": "1.0.0-beta.4",
48
- "solid-js": "^1.9.11",
49
- "typescript": "^5.9.3",
51
+ "@testing-library/jest-dom": "^6.9.1",
52
+ "@types/node": "^25.6.0",
53
+ "@xmachines/shared": "1.0.0-beta.41",
54
+ "@xstate/store": "^3.17.0",
55
+ "jsdom": "^29.0.2",
56
+ "oxfmt": "^0.45.0",
57
+ "oxlint": "^1.60.0",
58
+ "solid-js": "^1.9.12",
59
+ "typescript": "^5.9.3 || ^6.0.3",
50
60
  "vite": "^8.0.0",
51
61
  "vite-plugin-solid": "^2.11.11",
52
- "vitest": "^4.1.0"
62
+ "vitest": "^4.1.4",
63
+ "xstate": "^5.30.0"
53
64
  },
54
65
  "peerDependencies": {
55
- "solid-js": "^1.8.0 || ^1.9.0"
66
+ "@json-render/core": "^0.18.0",
67
+ "@json-render/solid": "^0.18.0",
68
+ "@json-render/xstate": "^0.18.0",
69
+ "@xstate/store": "^3.17.0",
70
+ "solid-js": "^1.8.0",
71
+ "xstate": "^5.30.0"
56
72
  }
57
73
  }
@@ -1,63 +0,0 @@
1
- /**
2
- * PlayRenderer - Main SolidJS renderer component for XMachines Play architecture
3
- *
4
- * @packageDocumentation
5
- */
6
- import { type Component } from "solid-js";
7
- import type { PlayRendererProps } from "./types.js";
8
- /**
9
- * Main renderer component that subscribes to actor signals and renders UI
10
- *
11
- * Architecture (per XMachines Play patterns):
12
- * - Subscribes to actor.currentView signal via TC39 Signal.subtle.Watcher
13
- * - Dynamically renders catalog components based on view.component string
14
- * - Forwards user events to actor via actor.send()
15
- * - SolidJS signal only for triggering renders, NOT business logic
16
- *
17
- * Invariant: Actor Authority - Actor decides all state transitions via guards.
18
- * Invariant: Passive Infrastructure - Component observes signals and sends events.
19
- * Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.
20
- *
21
- * @example
22
- * ```typescript
23
- * import { PlayRenderer } from "@xmachines/play-solidjs";
24
- * import { definePlayer } from "@xmachines/play-xstate";
25
- *
26
- * const actor = definePlayer({ machine, catalog })();
27
- * actor.start();
28
- *
29
- * const components = {
30
- * Dashboard: (props) => <div>User: {props.userId}</div>,
31
- * LoginForm: (props) => (
32
- * <form onSubmit={(e) => {
33
- * e.preventDefault();
34
- * props.send({ type: "auth.login", payload: {...} });
35
- * }}>...</form>
36
- * )
37
- * };
38
- *
39
- * <PlayRenderer actor={actor} components={components} />
40
- * ```
41
- *
42
- * @param props - Component props
43
- * @returns SolidJS element rendering current view from actor
44
- *
45
- * @remarks
46
- * **Component lookup:** Dynamically looks up component from `components` map
47
- * using `view.component` string from actor.currentView signal.
48
- *
49
- * **Event forwarding:** Injects `send` function as prop to components. Components
50
- * call `send(event)` to forward intents to actor. Actor guards decide validity.
51
- *
52
- * **Error handling:** If component not found in catalog, logs error and shows
53
- * fallback. This indicates missing component registration, not runtime error.
54
- *
55
- * **Signal bridge:** Uses one-shot re-watch pattern. TC39 Signal watchers stop
56
- * watching after notification, so watcher.watch() must be called in microtask
57
- * after getPending() to re-arm for next notification.
58
- *
59
- * **CRITICAL:** Never call actor.send() during render - only in event handlers.
60
- * Calling send during render causes infinite render loops.
61
- */
62
- export declare const PlayRenderer: Component<PlayRendererProps>;
63
- //# sourceMappingURL=PlayRenderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjE,OAAO,KAAK,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,CAAC,iBAAiB,CA2ErD,CAAC"}
package/dist/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * SolidJS renderer for XMachines Play architecture
3
- *
4
- * @packageDocumentation
5
- */
6
- export { PlayRenderer } from "./PlayRenderer.js";
7
- export type { PlayRendererProps } from "./types.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
package/dist/types.d.ts DELETED
@@ -1,28 +0,0 @@
1
- /**
2
- * TypeScript type definitions for play-solidjs
3
- *
4
- * @packageDocumentation
5
- */
6
- import type { AbstractActor, Viewable } from "@xmachines/play-actor";
7
- import type { JSX, ValidComponent } from "solid-js";
8
- import type { AnyActorLogic } from "xstate";
9
- export type SolidView = {
10
- component: string;
11
- props: Record<string, unknown>;
12
- } | null;
13
- /**
14
- * Props for PlayRenderer component
15
- *
16
- * @property actor - Actor instance with currentView signal (requires Viewable capability)
17
- * @property components - Map of component names to SolidJS components
18
- * @property fallback - Optional element shown when currentView is null
19
- */
20
- export interface PlayRendererProps {
21
- /** Actor instance with currentView signal (requires Viewable capability) */
22
- actor: AbstractActor<AnyActorLogic> & Viewable;
23
- /** Map of component names to SolidJS components */
24
- components: Record<string, ValidComponent>;
25
- /** Optional element shown when currentView is null */
26
- fallback?: JSX.Element;
27
- }
28
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC;AAErF;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IACjC,4EAA4E;IAC5E,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;IAE/C,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAE3C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB"}