@xmachines/play-react 1.0.0-beta.33 → 1.0.0-beta.34

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
@@ -41,14 +41,19 @@ without muting console output.
41
41
  - `useBoundProp` — re-exported from `@json-render/react`
42
42
  - `ComponentFn` (type) — re-exported from `@json-render/react`
43
43
  - `ComponentContext` (type) — re-exported from `@json-render/react`
44
- - `PlayRendererProps` (type)
44
+ - `ActorProvider` — escape hatch primitive (owns actor bridging, signal bridge, store lifecycle)
45
+ - `PlayUIProvider` — batteries-included composite (wraps `ActorProvider` + `JSONUIProvider`)
46
+ - `usePlayView` — hook for accessing the current view spec inside a provider tree
47
+ - `RenderErrorHandler` (type) — inner per-element error callback signature
48
+ - `ActorProviderProps` (type)
49
+ - `ViewContextValue` (type)
45
50
  - `PlayActor` (type)
46
51
 
47
52
  ## Quick Start
48
53
 
49
54
  ```tsx
50
55
  import { definePlayer, formatPlayRouteTransitions } from "@xmachines/play-xstate";
51
- import { PlayRenderer } from "@xmachines/play-react";
56
+ import { PlayUIProvider, PlayRenderer } from "@xmachines/play-react";
52
57
  import { defineCatalog } from "@json-render/core";
53
58
  import { defineRegistry } from "@xmachines/play-react";
54
59
  import type { ComponentFn } from "@xmachines/play-react";
@@ -119,12 +124,9 @@ const machine = setup({
119
124
  meta: {
120
125
  route: "/login",
121
126
  view: {
122
- component: "Login",
123
- spec: {
124
- root: "root",
125
- elements: {
126
- root: { type: "Login", props: { title: "Sign In" }, children: [] },
127
- },
127
+ root: "root",
128
+ elements: {
129
+ root: { type: "Login", props: { title: "Sign In" }, children: [] },
128
130
  },
129
131
  },
130
132
  },
@@ -134,12 +136,9 @@ const machine = setup({
134
136
  meta: {
135
137
  route: "/dashboard",
136
138
  view: {
137
- component: "Dashboard",
138
- spec: {
139
- root: "root",
140
- elements: {
141
- root: { type: "Dashboard", props: { username: "" }, children: [] },
142
- },
139
+ root: "root",
140
+ elements: {
141
+ root: { type: "Dashboard", props: { username: "" }, children: [] },
143
142
  },
144
143
  },
145
144
  },
@@ -169,31 +168,36 @@ const actor = createPlayer();
169
168
  actor.start();
170
169
 
171
170
  function App() {
172
- return <PlayRenderer actor={actor} registryResult={registryResult} />;
171
+ return (
172
+ <PlayUIProvider actor={actor} registryResult={registryResult}>
173
+ <PlayRenderer />
174
+ </PlayUIProvider>
175
+ );
173
176
  }
174
177
  ```
175
178
 
176
179
  ## API Reference
177
180
 
178
- ### `PlayRenderer`
181
+ ### `PlayUIProvider`
179
182
 
180
- Main component. Subscribes to `actor.currentView` and renders the spec.
183
+ Batteries-included composite provider. Wraps `ActorProvider` + `JSONUIProvider`. Pass `actor` and `registryResult` here, then place `<PlayRenderer />` inside as a zero-prop child.
181
184
 
182
185
  ```tsx
183
- <PlayRenderer
186
+ <PlayUIProvider
184
187
  actor={actor} // required
185
188
  registryResult={registryResult} // required
186
189
  store={myStore} // optional — controlled mode
187
190
  fallback={<p>Loading…</p>} // optional
188
- />
191
+ onError={(err, info) => Sentry.captureException(err, { extra: info })} // optional
192
+ onRenderError={(error, elementType) => console.warn(`<${elementType}> crashed:`, error)} // optional
193
+ >
194
+ <PlayRenderer />
195
+ </PlayUIProvider>
189
196
  ```
190
197
 
191
198
  **`actor`** — A `PlayerActor` (or any `AbstractActor & Viewable`). Provides the `currentView` signal.
192
199
 
193
- **`registryResult`** — Full result from `defineRegistry(catalog, { components, actions })`. Pass the entire return value — contains both the component registry and action handlers. Action handlers are real async functions dispatching to the actor, not string event-type maps.
194
-
195
- `defineRegistry` also accepts `onRenderError(error, elementType)`, which receives errors
196
- caught by `@json-render/react`'s inner element boundary before the default logger is used.
200
+ **`registryResult`** — Full result from `defineRegistry(catalog, { components, actions })`. Contains both the component registry and action handlers.
197
201
 
198
202
  **`store`** (optional) — Controls per-view UI state (form values, `$state` bindings):
199
203
 
@@ -207,31 +211,99 @@ import type { StateStore } from "@json-render/core";
207
211
 
208
212
  const store: StateStore = xstateStoreStateStore({ atom: createAtom({ username: "alice" }) });
209
213
 
210
- <PlayRenderer actor={actor} registryResult={registryResult} store={store} />;
214
+ <PlayUIProvider actor={actor} registryResult={registryResult} store={store}>
215
+ <PlayRenderer />
216
+ </PlayUIProvider>;
217
+ ```
218
+
219
+ **`fallback`** — Shown when `actor.currentView.get()` is `null` (machine in a no-view state, or during initialisation).
220
+
221
+ **`onError`** — Called when the outer `PlayErrorBoundary` catches an error. Receives `(error: Error, info: React.ErrorInfo)`. Use for observability tools (Sentry, Datadog, etc.).
222
+
223
+ **`onRenderError`** — Called when an individual catalog component throws during render. Caught by `@json-render/react`'s inner per-element boundary — 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.
224
+
225
+ ---
226
+
227
+ ### `ActorProvider`
228
+
229
+ Escape hatch primitive. Owns actor bridging, signal bridge, and store lifecycle. Use this when you need direct control over the provider layer (e.g. custom `JSONUIProvider` configuration).
230
+
231
+ ```tsx
232
+ import { ActorProvider } from "@xmachines/play-react";
233
+
234
+ <ActorProvider
235
+ actor={actor}
236
+ registryResult={registryResult}
237
+ onRenderError={(err, type) => reportError(err, type)}
238
+ >
239
+ {/* your own JSONUIProvider + PlayRenderer tree */}
240
+ </ActorProvider>;
211
241
  ```
212
242
 
213
- **Inner render errors** — You can intercept catalog component render failures without
214
- overriding the outer `PlayErrorBoundary`:
243
+ ---
244
+
245
+ ### `PlayRenderer`
246
+
247
+ Zero-prop leaf component. Must be rendered inside a `PlayUIProvider` (or `ActorProvider`) tree. Subscribes to `actor.currentView` via context and renders the current spec.
215
248
 
216
249
  ```tsx
250
+ <PlayUIProvider actor={actor} registryResult={registryResult}>
251
+ <PlayRenderer />
252
+ </PlayUIProvider>
253
+ ```
254
+
255
+ `PlayRenderer` accepts no props — all configuration (`actor`, `registryResult`, `store`, `fallback`, `onError`, `onRenderError`) is provided by the enclosing `PlayUIProvider` or `ActorProvider`.
256
+
257
+ ## Error handling
258
+
259
+ The provider tree has two layers of error boundaries:
260
+
261
+ ### Outer boundary — `onError` and `fallback`
262
+
263
+ Wraps the entire renderer output via `PlayErrorBoundary`. Triggered when the spec or store setup throws, or when the inner boundary is not present.
264
+
265
+ ```tsx
266
+ <PlayUIProvider
267
+ actor={actor}
268
+ registryResult={registryResult}
269
+ fallback={<p>Something went wrong.</p>}
270
+ onError={(err, info) => Sentry.captureException(err, { extra: info })}
271
+ >
272
+ <PlayRenderer />
273
+ </PlayUIProvider>
274
+ ```
275
+
276
+ ### Inner boundary — `onRenderError`
277
+
278
+ Each catalog element is individually wrapped in an error boundary by `@json-render/react`. When a component throws, it is silently removed while the rest of the spec continues rendering. The outer boundary is **not** triggered.
279
+
280
+ Pass `onRenderError` to `PlayUIProvider` (or `ActorProvider`) — overrides any registry-level handler — or bake it into `defineRegistry`:
281
+
282
+ ```tsx
283
+ // via PlayUIProvider prop
284
+ <PlayUIProvider
285
+ actor={actor}
286
+ registryResult={registryResult}
287
+ onRenderError={(error, elementType) => {
288
+ console.warn(`<${elementType}> crashed:`, error);
289
+ }}
290
+ >
291
+ <PlayRenderer />
292
+ </PlayUIProvider>
293
+ ```
294
+
295
+ ```ts
296
+ // via defineRegistry — bakes the handler into the registry
217
297
  const registryResult = defineRegistry(catalog, {
218
298
  components: { Login, Dashboard },
219
- actions: {
220
- login: async (params) => {
221
- if (!params) return;
222
- actor.send({ type: "auth.login", username: params.username });
223
- },
224
- logout: async () => {
225
- actor.send({ type: "auth.logout" });
226
- },
227
- },
299
+ actions: { login: async (params) => { ... }, logout: async () => { ... } },
228
300
  onRenderError(error, elementType) {
229
301
  reportExpectedRenderError(error, elementType);
230
302
  },
231
303
  });
232
304
  ```
233
305
 
234
- **`fallback`** — Shown when `actor.currentView.get()` is `null` (machine in a no-view state, or during initialisation).
306
+ `onRenderError` is typed as `RenderErrorHandler` and exported from `@xmachines/play-react`.
235
307
 
236
308
  ---
237
309
 
@@ -249,7 +321,7 @@ function LogoutButton() {
249
321
  }
250
322
  ```
251
323
 
252
- Throws `"useActor() must be called inside <PlayRenderer>"` if called outside the tree.
324
+ Throws `NonNullableError: "useActor() must be called inside <ActorProvider> (or <PlayUIProvider>)"` if called outside the tree.
253
325
 
254
326
  ---
255
327
 
@@ -276,7 +348,7 @@ function NavBar({ actor }: { actor: ReturnType<typeof createPlayer> }) {
276
348
 
277
349
  ### `PlayErrorBoundary`
278
350
 
279
- Class error boundary that wraps the rendered output. Catches errors thrown during component render and logs them without crashing the full page. `PlayRenderer` wraps its own output in this boundary automatically.
351
+ Class error boundary that wraps the rendered output. `PlayRenderer` wraps its own output in this boundary automatically use this directly only if you need to wrap other content or nest boundaries manually.
280
352
 
281
353
  `componentDidCatch` invokes the `onError` prop (for observability tools) but does **not** re-throw — re-throwing from `componentDidCatch` can unmount the entire React 19 root. `getDerivedStateFromError` handles fallback state transition instead.
282
354
 
@@ -287,7 +359,9 @@ import { PlayErrorBoundary } from "@xmachines/play-react";
287
359
  fallback={<p>Something went wrong.</p>}
288
360
  onError={(err, info) => Sentry.captureException(err, { extra: info })}
289
361
  >
290
- <PlayRenderer actor={actor} registryResult={registryResult} />
362
+ <PlayUIProvider actor={actor} registryResult={registryResult}>
363
+ <PlayRenderer />
364
+ </PlayUIProvider>
291
365
  </PlayErrorBoundary>;
292
366
  ```
293
367
 
@@ -309,10 +383,10 @@ Priority: **route param fills `undefined` slots; explicit non-`undefined` spec p
309
383
 
310
384
  ## Error Handling
311
385
 
312
- | Error | Cause | Fix |
313
- | ------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------- |
314
- | `useActor() must be called inside <PlayRenderer>` | Hook called outside the tree | Move inside a component rendered by `PlayRenderer` |
315
- | Component render error | Component throws | `PlayErrorBoundary` catches it; inspect component implementation |
386
+ | Error | Cause | Fix |
387
+ | ------------------------------------------------------------------------ | ---------------------------- | ---------------------------------------------------------------- |
388
+ | `useActor() must be called inside <ActorProvider> (or <PlayUIProvider>)` | Hook called outside the tree | Wrap with `<PlayUIProvider>` or `<ActorProvider>` |
389
+ | Component render error | Component throws | `PlayErrorBoundary` catches it; inspect component implementation |
316
390
 
317
391
  ---
318
392
 
@@ -0,0 +1,82 @@
1
+ /**
2
+ * ActorProvider — escape hatch primitive for actor lifecycle management.
3
+ *
4
+ * Owns: actor bridging, signal subscription (useSignalEffect), per-view StateStore
5
+ * lifecycle (controlled/uncontrolled), handler resolution via inner component pattern
6
+ * (uses useStateStore()), StateProvider wrap, PlayErrorBoundary wrap, onRenderError injection.
7
+ *
8
+ * Standard usage: prefer <PlayUIProvider> unless you need to compose providers manually.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import React from "react";
13
+ import type { DefineRegistryResult, ComponentRegistry } from "@json-render/react";
14
+ import type { BaseActorProviderProps, BaseViewContextValue } from "@xmachines/play-actor";
15
+ /**
16
+ * Props for the ActorProvider component.
17
+ *
18
+ * @public
19
+ */
20
+ export interface ActorProviderProps extends BaseActorProviderProps<DefineRegistryResult> {
21
+ /** Optional component shown when currentView is null or a catalog component throws */
22
+ fallback?: React.ReactNode;
23
+ /** Optional error handler callback invoked when a catalog component throws during render */
24
+ onError?: (error: Error, info: React.ErrorInfo) => void;
25
+ /** Child components to render inside the provider tree */
26
+ children: React.ReactNode;
27
+ }
28
+ /**
29
+ * Value provided by ViewContext (accessible via usePlayView()).
30
+ *
31
+ * @public
32
+ */
33
+ export interface ViewContextValue extends BaseViewContextValue<ComponentRegistry> {
34
+ }
35
+ /**
36
+ * Hook to access the current view spec, handlers, and registry.
37
+ *
38
+ * Must be called inside <ActorProvider> or <PlayUIProvider>.
39
+ *
40
+ * @throws {Error} If called outside an ActorProvider/PlayUIProvider tree
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { usePlayView } from "@xmachines/play-react";
45
+ *
46
+ * function MyRenderer() {
47
+ * const view = usePlayView();
48
+ * return <Renderer spec={view.spec} registry={view.registry} />;
49
+ * }
50
+ * ```
51
+ *
52
+ * @public
53
+ */
54
+ export declare function usePlayView(): ViewContextValue;
55
+ /**
56
+ * ActorProvider — escape hatch primitive for composing actor lifecycle with custom providers.
57
+ *
58
+ * Subscribes to actor.currentView signal, manages the per-view StateStore lifecycle,
59
+ * wraps children in StateProvider and PlayErrorBoundary, and injects onRenderError
60
+ * into the component registry.
61
+ *
62
+ * Standard usage: prefer <PlayUIProvider> unless you need to compose providers manually.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * // Custom composition (escape hatch):
67
+ * <ActorProvider actor={actor} registryResult={registryResult}>
68
+ * <JSONUIProvider registry={registryResult.registry}>
69
+ * <PlayRenderer />
70
+ * </JSONUIProvider>
71
+ * </ActorProvider>
72
+ *
73
+ * // Standard usage: prefer PlayUIProvider
74
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
75
+ * <PlayRenderer />
76
+ * </PlayUIProvider>
77
+ * ```
78
+ *
79
+ * @public
80
+ */
81
+ export declare const ActorProvider: React.FC<ActorProviderProps>;
82
+ //# sourceMappingURL=ActorProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActorProvider.d.ts","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAsD,MAAM,OAAO,CAAC;AAE3E,OAAO,KAAK,EAAE,oBAAoB,EAAY,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5F,OAAO,KAAK,EAAY,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAIpG;;;;GAIG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB,CAAC,oBAAoB,CAAC;IACvF,sFAAsF;IACtF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IACxD,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;CAAG;AAQpF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAmDD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqFtD,CAAC"}
@@ -0,0 +1,166 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * ActorProvider — escape hatch primitive for actor lifecycle management.
4
+ *
5
+ * Owns: actor bridging, signal subscription (useSignalEffect), per-view StateStore
6
+ * lifecycle (controlled/uncontrolled), handler resolution via inner component pattern
7
+ * (uses useStateStore()), StateProvider wrap, PlayErrorBoundary wrap, onRenderError injection.
8
+ *
9
+ * Standard usage: prefer <PlayUIProvider> unless you need to compose providers manually.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import React, { useState, useRef, createContext, useContext } from "react";
14
+ import { StateProvider, useStateStore } from "@json-render/react";
15
+ import { createAtom } from "@xstate/store";
16
+ import { xstateStoreStateStore } from "@json-render/xstate";
17
+ import { useSignalEffect } from "./useSignalEffect.js";
18
+ import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
19
+ import { assertNonNullable } from "@xmachines/play";
20
+ import { ActorContext } from "./useActor.js";
21
+ /**
22
+ * Internal React context for ViewContextValue.
23
+ * Accessed via usePlayView() hook.
24
+ */
25
+ const ViewContext = createContext(null);
26
+ /**
27
+ * Hook to access the current view spec, handlers, and registry.
28
+ *
29
+ * Must be called inside <ActorProvider> or <PlayUIProvider>.
30
+ *
31
+ * @throws {Error} If called outside an ActorProvider/PlayUIProvider tree
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { usePlayView } from "@xmachines/play-react";
36
+ *
37
+ * function MyRenderer() {
38
+ * const view = usePlayView();
39
+ * return <Renderer spec={view.spec} registry={view.registry} />;
40
+ * }
41
+ * ```
42
+ *
43
+ * @public
44
+ */
45
+ export function usePlayView() {
46
+ return assertNonNullable(useContext(ViewContext), "ViewContext");
47
+ }
48
+ /**
49
+ * Create a StateStore backed by a fresh @xstate/store atom seeded from the given state.
50
+ * Called internally per view transition when no external store prop is provided.
51
+ */
52
+ function createViewStore(initialState) {
53
+ return xstateStoreStateStore({ atom: createAtom(initialState) });
54
+ }
55
+ /**
56
+ * Inner component that runs inside StateProvider so it can access StateStore context
57
+ * via useStateStore(). Resolves action handlers from registryResult.handlers() using
58
+ * the live StateProvider set/getSnapshot functions, then exposes them via ViewContext.
59
+ */
60
+ function ActorProviderInner({ registryResult, spec, store, children, }) {
61
+ const stateCtx = useStateStore();
62
+ // Build a SetState adapter: the handlers factory expects an updater-function pattern
63
+ // ((prev) => next), while stateCtx provides path-based set/update. This adapter
64
+ // bridges the two so action functions can use setState if needed.
65
+ const setStateAdapter = (updater) => {
66
+ const prev = stateCtx.getSnapshot();
67
+ stateCtx.update(updater(prev));
68
+ };
69
+ const handlers = registryResult.handlers(() => setStateAdapter, () => stateCtx.getSnapshot());
70
+ const viewValue = {
71
+ spec,
72
+ handlers,
73
+ registry: registryResult.registry,
74
+ store,
75
+ };
76
+ return _jsx(ViewContext.Provider, { value: viewValue, children: children });
77
+ }
78
+ /**
79
+ * ActorProvider — escape hatch primitive for composing actor lifecycle with custom providers.
80
+ *
81
+ * Subscribes to actor.currentView signal, manages the per-view StateStore lifecycle,
82
+ * wraps children in StateProvider and PlayErrorBoundary, and injects onRenderError
83
+ * into the component registry.
84
+ *
85
+ * Standard usage: prefer <PlayUIProvider> unless you need to compose providers manually.
86
+ *
87
+ * @example
88
+ * ```tsx
89
+ * // Custom composition (escape hatch):
90
+ * <ActorProvider actor={actor} registryResult={registryResult}>
91
+ * <JSONUIProvider registry={registryResult.registry}>
92
+ * <PlayRenderer />
93
+ * </JSONUIProvider>
94
+ * </ActorProvider>
95
+ *
96
+ * // Standard usage: prefer PlayUIProvider
97
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
98
+ * <PlayRenderer />
99
+ * </PlayUIProvider>
100
+ * ```
101
+ *
102
+ * @public
103
+ */
104
+ export const ActorProvider = ({ actor, registryResult, store: externalStore, fallback = null, onError, onRenderError, children, }) => {
105
+ // React state for triggering re-renders (NOT business logic state)
106
+ // Signal is source of truth, useState is just React's render trigger
107
+ const [view, setView] = useState(() => actor.currentView.get());
108
+ // Internal store ref — tracks the current per-view atom store.
109
+ // Keyed to view identity: recreated whenever the view changes (new spec.state seed).
110
+ // Ignored when externalStore is provided.
111
+ const internalStoreRef = useRef(null);
112
+ const lastViewRef = useRef(null);
113
+ // Subscribe to signal changes
114
+ useSignalEffect(() => {
115
+ const currentView = actor.currentView.get();
116
+ setView(currentView);
117
+ });
118
+ // Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level handler)
119
+ // Centralised here per D-19 — one location for all framework renderers
120
+ const activeRegistryResult = onRenderError
121
+ ? {
122
+ ...registryResult,
123
+ registry: (() => {
124
+ const r = { ...registryResult.registry };
125
+ Object.defineProperty(r, "onRenderError", {
126
+ value: onRenderError,
127
+ enumerable: false,
128
+ configurable: true,
129
+ });
130
+ return r;
131
+ })(),
132
+ }
133
+ : registryResult;
134
+ // No view in current state — render fallback
135
+ if (!view) {
136
+ return _jsx(_Fragment, { children: fallback });
137
+ }
138
+ // Resolve the store to use for StateProvider:
139
+ // - External (controlled): use as-is, caller manages lifecycle
140
+ // - Internal: create a fresh atom when the view changes (new route/state)
141
+ let store;
142
+ if (externalStore) {
143
+ store = externalStore;
144
+ }
145
+ else {
146
+ // Recreate the internal store when the view identity changes
147
+ // (view is a new object on every transition per deriveCurrentView)
148
+ if (internalStoreRef.current === null || lastViewRef.current !== view) {
149
+ // Proto-safe guard (T-37-03-01): prevents Date/Array/class-instance from being
150
+ // passed to createAtom. Replaces the weak `?? {}` guard from old code_context.
151
+ const rawState = view.state;
152
+ const initialState = rawState !== null &&
153
+ rawState !== undefined &&
154
+ typeof rawState === "object" &&
155
+ !Array.isArray(rawState) &&
156
+ Object.getPrototypeOf(rawState) === Object.prototype
157
+ ? rawState
158
+ : {};
159
+ internalStoreRef.current = createViewStore(initialState);
160
+ lastViewRef.current = view;
161
+ }
162
+ store = internalStoreRef.current;
163
+ }
164
+ return (_jsx(ActorContext.Provider, { value: actor, children: _jsx(PlayErrorBoundary, { fallback: fallback, ...(onError && { onError }), children: _jsx(StateProvider, { store: store, children: _jsx(ActorProviderInner, { registryResult: activeRegistryResult, spec: view, store: store, children: children }) }) }) }));
165
+ };
166
+ //# sourceMappingURL=ActorProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActorProvider.js","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"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"}
@@ -1,55 +1,36 @@
1
1
  /**
2
- * PlayRenderer - Main React renderer component for XMachines Play architecture
2
+ * PlayRenderer — zero-prop leaf component for rendering the current actor view.
3
3
  *
4
- * Backed by @json-render/react for spec-driven UI rendering.
4
+ * Must be rendered inside <ActorProvider> or <PlayUIProvider>.
5
+ * Reads view spec, handlers, and registry from usePlayView() context,
6
+ * then delegates to @json-render/react Renderer.
7
+ *
8
+ * Standard usage:
9
+ * ```tsx
10
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
11
+ * <PlayRenderer />
12
+ * </PlayUIProvider>
13
+ * ```
14
+ *
15
+ * For custom provider composition, use <ActorProvider> (escape hatch):
16
+ * ```tsx
17
+ * <ActorProvider actor={actor} registryResult={registryResult}>
18
+ * <JSONUIProvider registry={registryResult.registry}>
19
+ * <PlayRenderer />
20
+ * </JSONUIProvider>
21
+ * </ActorProvider>
22
+ * ```
5
23
  *
6
24
  * @packageDocumentation
7
25
  */
8
26
  import React from "react";
9
- import type { PlayRendererProps } from "./types.js";
10
27
  /**
11
- * Main renderer component that subscribes to actor signals and renders UI
12
- * via @json-render/react Renderer.
13
- *
14
- * Architecture:
15
- * - Subscribes to actor.currentView signal via useSignalEffect
16
- * - Renders view.spec via StateProvider → ActionProvider → VisibilityProvider → Renderer
17
- * - Routes actions via registryResult.handlers() — real async functions dispatching to actor.
18
- * - State store: uses external `store` prop if provided (controlled mode); otherwise
19
- * creates a fresh @xstate/store atom per view transition seeded from spec.state.
20
- * The atom resets automatically when the actor transitions to a new view, mirroring
21
- * the actor's currentView lifecycle.
28
+ * Zero-prop leaf component that renders the current actor view.
22
29
  *
23
- * Invariant: Actor Authority - Actor decides all state transitions via guards.
24
- * Invariant: Passive Infrastructure - Component observes signals and sends events.
25
- * Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.
26
- *
27
- * @example
28
- * ```typescript
29
- * import { PlayRenderer } from "@xmachines/play-react";
30
- * import { defineRegistry } from "@json-render/react";
31
- *
32
- * const registryResult = defineRegistry(catalog, {
33
- * components: { Login, Dashboard },
34
- * actions: {
35
- * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
36
- * logout: async () => actor.send({ type: 'auth.logout' }),
37
- * route: async ({ to, params }) => actor.send({ type: 'play.route', to, params }),
38
- * },
39
- * });
40
- *
41
- * // Uncontrolled — fresh atom created per view, seeded from spec.state:
42
- * <PlayRenderer actor={actor} registryResult={registryResult} />
43
- *
44
- * // Controlled — caller provides and owns the store:
45
- * import { createAtom } from "@xstate/store";
46
- * import { xstateStoreStateStore } from "@json-render/xstate";
47
- * const store = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
48
- * <PlayRenderer actor={actor} registryResult={registryResult} store={store} />
49
- * ```
30
+ * Reads the current PlaySpec, handlers, and registry from the ActorProvider
31
+ * context via usePlayView(), then renders via @json-render/react Renderer.
50
32
  *
51
- * @param props - Component props
52
- * @returns React element rendering current view from actor
33
+ * @public
53
34
  */
54
- export declare const PlayRenderer: React.FC<PlayRendererProps>;
35
+ export declare const PlayRenderer: React.FC;
55
36
  //# sourceMappingURL=PlayRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA2B,MAAM,OAAO,CAAC;AAchD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAiDpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA2EpD,CAAC"}
1
+ {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAGhC,CAAC"}
@@ -1,136 +1,42 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /**
3
- * PlayRenderer - Main React renderer component for XMachines Play architecture
3
+ * PlayRenderer — zero-prop leaf component for rendering the current actor view.
4
4
  *
5
- * Backed by @json-render/react for spec-driven UI rendering.
5
+ * Must be rendered inside <ActorProvider> or <PlayUIProvider>.
6
+ * Reads view spec, handlers, and registry from usePlayView() context,
7
+ * then delegates to @json-render/react Renderer.
8
+ *
9
+ * Standard usage:
10
+ * ```tsx
11
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
12
+ * <PlayRenderer />
13
+ * </PlayUIProvider>
14
+ * ```
15
+ *
16
+ * For custom provider composition, use <ActorProvider> (escape hatch):
17
+ * ```tsx
18
+ * <ActorProvider actor={actor} registryResult={registryResult}>
19
+ * <JSONUIProvider registry={registryResult.registry}>
20
+ * <PlayRenderer />
21
+ * </JSONUIProvider>
22
+ * </ActorProvider>
23
+ * ```
6
24
  *
7
25
  * @packageDocumentation
8
26
  */
9
- import React, { useState, useRef } from "react";
10
- import { Renderer, StateProvider, ActionProvider, VisibilityProvider, useStateStore, } from "@json-render/react";
11
- import { createAtom } from "@xstate/store";
12
- import { xstateStoreStateStore } from "@json-render/xstate";
13
- import { useSignalEffect } from "./useSignalEffect.js";
14
- import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
15
- import { ActorContext } from "./useActor.js";
16
- /**
17
- * Create a StateStore backed by a fresh @xstate/store atom seeded from the given state.
18
- * Called internally per view transition when no external store prop is provided.
19
- */
20
- function createViewStore(initialState) {
21
- return xstateStoreStateStore({ atom: createAtom(initialState) });
22
- }
23
- /**
24
- * Inner component that runs inside StateProvider so it can access StateStore context
25
- * via useStateStore(). Resolves action handlers from registryResult.handlers() using
26
- * the live StateProvider set/getSnapshot functions, then renders ActionProvider.
27
- */
28
- function PlayRendererInner({ registryResult, spec, }) {
29
- const stateCtx = useStateStore();
30
- // Build a SetState adapter: the handlers factory expects an updater-function pattern
31
- // ((prev) => next), while stateCtx provides path-based set/update. This adapter
32
- // bridges the two so action functions can use setState if needed.
33
- const setStateAdapter = (updater) => {
34
- const prev = stateCtx.getSnapshot();
35
- stateCtx.update(updater(prev));
36
- };
37
- const handlers = registryResult.handlers(() => setStateAdapter, () => stateCtx.getSnapshot());
38
- return (_jsx(ActionProvider, { handlers: handlers, children: _jsx(VisibilityProvider, { children: _jsx(Renderer, { spec: spec, registry: registryResult.registry }) }) }));
39
- }
27
+ import React from "react";
28
+ import { Renderer } from "@json-render/react";
29
+ import { usePlayView } from "./ActorProvider.js";
40
30
  /**
41
- * Main renderer component that subscribes to actor signals and renders UI
42
- * via @json-render/react Renderer.
43
- *
44
- * Architecture:
45
- * - Subscribes to actor.currentView signal via useSignalEffect
46
- * - Renders view.spec via StateProvider → ActionProvider → VisibilityProvider → Renderer
47
- * - Routes actions via registryResult.handlers() — real async functions dispatching to actor.
48
- * - State store: uses external `store` prop if provided (controlled mode); otherwise
49
- * creates a fresh @xstate/store atom per view transition seeded from spec.state.
50
- * The atom resets automatically when the actor transitions to a new view, mirroring
51
- * the actor's currentView lifecycle.
52
- *
53
- * Invariant: Actor Authority - Actor decides all state transitions via guards.
54
- * Invariant: Passive Infrastructure - Component observes signals and sends events.
55
- * Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.
56
- *
57
- * @example
58
- * ```typescript
59
- * import { PlayRenderer } from "@xmachines/play-react";
60
- * import { defineRegistry } from "@json-render/react";
31
+ * Zero-prop leaf component that renders the current actor view.
61
32
  *
62
- * const registryResult = defineRegistry(catalog, {
63
- * components: { Login, Dashboard },
64
- * actions: {
65
- * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
66
- * logout: async () => actor.send({ type: 'auth.logout' }),
67
- * route: async ({ to, params }) => actor.send({ type: 'play.route', to, params }),
68
- * },
69
- * });
70
- *
71
- * // Uncontrolled — fresh atom created per view, seeded from spec.state:
72
- * <PlayRenderer actor={actor} registryResult={registryResult} />
73
- *
74
- * // Controlled — caller provides and owns the store:
75
- * import { createAtom } from "@xstate/store";
76
- * import { xstateStoreStateStore } from "@json-render/xstate";
77
- * const store = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
78
- * <PlayRenderer actor={actor} registryResult={registryResult} store={store} />
79
- * ```
33
+ * Reads the current PlaySpec, handlers, and registry from the ActorProvider
34
+ * context via usePlayView(), then renders via @json-render/react Renderer.
80
35
  *
81
- * @param props - Component props
82
- * @returns React element rendering current view from actor
36
+ * @public
83
37
  */
84
- export const PlayRenderer = ({ actor, registryResult, store: externalStore, fallback = null, onError, onRenderError, }) => {
85
- // React state for triggering re-renders (NOT business logic state)
86
- // Signal is source of truth, useState is just React's render trigger
87
- const [view, setView] = useState(() => actor.currentView.get());
88
- // Internal store ref — tracks the current per-view atom store.
89
- // Keyed to view identity: recreated whenever the view changes (new spec.state seed).
90
- // Ignored when externalStore is provided.
91
- const internalStoreRef = useRef(null);
92
- const lastViewRef = useRef(null);
93
- // Subscribe to signal changes
94
- useSignalEffect(() => {
95
- const currentView = actor.currentView.get();
96
- setView(currentView);
97
- });
98
- // No view in current state — render fallback
99
- if (!view) {
100
- return _jsx(_Fragment, { children: fallback });
101
- }
102
- // Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level handler)
103
- const activeRegistryResult = onRenderError
104
- ? {
105
- ...registryResult,
106
- registry: (() => {
107
- const r = { ...registryResult.registry };
108
- Object.defineProperty(r, "onRenderError", {
109
- value: onRenderError,
110
- enumerable: false,
111
- configurable: true,
112
- });
113
- return r;
114
- })(),
115
- }
116
- : registryResult;
117
- // Resolve the store to use for StateProvider:
118
- // - External (controlled): use as-is, caller manages lifecycle
119
- // - Internal: create a fresh atom when the view changes (new route/state)
120
- let store;
121
- if (externalStore) {
122
- store = externalStore;
123
- }
124
- else {
125
- // Recreate the internal store when the view identity changes
126
- // (view is a new object on every transition per deriveCurrentView)
127
- if (internalStoreRef.current === null || lastViewRef.current !== view) {
128
- const initialState = view.spec?.state ?? {};
129
- internalStoreRef.current = createViewStore(initialState);
130
- lastViewRef.current = view;
131
- }
132
- store = internalStoreRef.current;
133
- }
134
- return (_jsx(ActorContext.Provider, { value: actor, children: _jsx(PlayErrorBoundary, { fallback: fallback, ...(onError && { onError }), children: _jsx(StateProvider, { store: store, children: _jsx(PlayRendererInner, { registryResult: activeRegistryResult, spec: view.spec ?? null }) }) }) }));
38
+ export const PlayRenderer = () => {
39
+ const view = usePlayView();
40
+ return _jsx(Renderer, { spec: view.spec, registry: view.registry });
135
41
  };
136
42
  //# sourceMappingURL=PlayRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAa,GAAG,EAAE;IAC1C,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,OAAO,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,GAAI,CAAC;AAC/D,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * PlayUIProvider — batteries-included composite provider for actor-driven UI rendering.
3
+ *
4
+ * Wraps ActorProvider + JSONUIProvider (from @json-render/react) to provide a single
5
+ * entry point for all actor lifecycle and UI rendering concerns.
6
+ *
7
+ * Standard usage:
8
+ * ```tsx
9
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
10
+ * <PlayRenderer />
11
+ * </PlayUIProvider>
12
+ * ```
13
+ *
14
+ * For custom provider composition (escape hatch), use <ActorProvider> directly.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+ import React from "react";
19
+ import { type JSONUIProviderProps } from "@json-render/react";
20
+ import { type ActorProviderProps } from "./ActorProvider.js";
21
+ type JSONUIForwardedProps = Pick<JSONUIProviderProps, "validationFunctions" | "navigate" | "functions">;
22
+ /**
23
+ * Props for PlayUIProvider — all ActorProvider props plus JSONUIProvider's own props.
24
+ *
25
+ * @public
26
+ */
27
+ export interface PlayUIProviderProps extends ActorProviderProps, Partial<JSONUIForwardedProps> {
28
+ }
29
+ /**
30
+ * PlayUIProvider — batteries-included entry point for actor-driven UI rendering.
31
+ *
32
+ * Combines actor lifecycle management (ActorProvider) with full UI provider setup
33
+ * (JSONUIProvider including ActionProvider, ValidationProvider, VisibilityProvider,
34
+ * StateProvider, and ConfirmDialogManager).
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * import { PlayUIProvider, PlayRenderer } from "@xmachines/play-react";
39
+ *
40
+ * const registryResult = defineRegistry(catalog, {
41
+ * components: { Login, Dashboard },
42
+ * actions: {
43
+ * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
44
+ * logout: async () => actor.send({ type: 'auth.logout' }),
45
+ * },
46
+ * });
47
+ *
48
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
49
+ * <PlayRenderer />
50
+ * </PlayUIProvider>
51
+ *
52
+ * // With JSONUIProvider options:
53
+ * <PlayUIProvider
54
+ * actor={actor}
55
+ * registryResult={registryResult}
56
+ * navigate={(path) => router.push(path)}
57
+ * validationFunctions={{ isEmail: (v) => /^.+@.+$/.test(String(v)) }}
58
+ * >
59
+ * <PlayRenderer />
60
+ * </PlayUIProvider>
61
+ * ```
62
+ *
63
+ * @public
64
+ */
65
+ export declare const PlayUIProvider: React.FC<PlayUIProviderProps>;
66
+ export {};
67
+ //# sourceMappingURL=PlayUIProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayUIProvider.d.ts","sourceRoot":"","sources":["../src/PlayUIProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAA8B,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGzF,KAAK,oBAAoB,GAAG,IAAI,CAC/B,mBAAmB,EACnB,qBAAqB,GAAG,UAAU,GAAG,WAAW,CAChD,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB,EAAE,OAAO,CAAC,oBAAoB,CAAC;CAAG;AAgCjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAiBxD,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * PlayUIProvider — batteries-included composite provider for actor-driven UI rendering.
4
+ *
5
+ * Wraps ActorProvider + JSONUIProvider (from @json-render/react) to provide a single
6
+ * entry point for all actor lifecycle and UI rendering concerns.
7
+ *
8
+ * Standard usage:
9
+ * ```tsx
10
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
11
+ * <PlayRenderer />
12
+ * </PlayUIProvider>
13
+ * ```
14
+ *
15
+ * For custom provider composition (escape hatch), use <ActorProvider> directly.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import React from "react";
20
+ import { JSONUIProvider } from "@json-render/react";
21
+ import { ActorProvider, usePlayView } from "./ActorProvider.js";
22
+ /**
23
+ * Inner bridge component — reads ViewContext (usePlayView) to get the resolved handlers,
24
+ * registry, and store, then passes them to JSONUIProvider. The store is passed explicitly
25
+ * so JSONUIProvider's internal StateProvider uses the same store ActorProvider set up —
26
+ * without this, JSONUIProvider would create a fresh empty store, shadowing the seeded one.
27
+ *
28
+ * Must be inside ActorProvider's tree so usePlayView() has access to ViewContextValue.
29
+ */
30
+ function JSONUIBridge({ validationFunctions, navigate, functions, children, }) {
31
+ const view = usePlayView();
32
+ return (_jsx(JSONUIProvider, { registry: view.registry, handlers: view.handlers, store: view.store, ...(validationFunctions && { validationFunctions }), ...(navigate && { navigate }), ...(functions && { functions }), children: children }));
33
+ }
34
+ /**
35
+ * PlayUIProvider — batteries-included entry point for actor-driven UI rendering.
36
+ *
37
+ * Combines actor lifecycle management (ActorProvider) with full UI provider setup
38
+ * (JSONUIProvider including ActionProvider, ValidationProvider, VisibilityProvider,
39
+ * StateProvider, and ConfirmDialogManager).
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * import { PlayUIProvider, PlayRenderer } from "@xmachines/play-react";
44
+ *
45
+ * const registryResult = defineRegistry(catalog, {
46
+ * components: { Login, Dashboard },
47
+ * actions: {
48
+ * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
49
+ * logout: async () => actor.send({ type: 'auth.logout' }),
50
+ * },
51
+ * });
52
+ *
53
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
54
+ * <PlayRenderer />
55
+ * </PlayUIProvider>
56
+ *
57
+ * // With JSONUIProvider options:
58
+ * <PlayUIProvider
59
+ * actor={actor}
60
+ * registryResult={registryResult}
61
+ * navigate={(path) => router.push(path)}
62
+ * validationFunctions={{ isEmail: (v) => /^.+@.+$/.test(String(v)) }}
63
+ * >
64
+ * <PlayRenderer />
65
+ * </PlayUIProvider>
66
+ * ```
67
+ *
68
+ * @public
69
+ */
70
+ export const PlayUIProvider = ({ validationFunctions, navigate, functions, ...actorProps }) => {
71
+ return (_jsx(ActorProvider, { ...actorProps, children: _jsx(JSONUIBridge, { ...(validationFunctions && { validationFunctions }), ...(navigate && { navigate }), ...(functions && { functions }), children: actorProps.children }) }));
72
+ };
73
+ //# sourceMappingURL=PlayUIProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayUIProvider.js","sourceRoot":"","sources":["../src/PlayUIProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAA4B,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,WAAW,EAA2B,MAAM,oBAAoB,CAAC;AAezF;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,EACrB,mBAAmB,EACnB,QAAQ,EACR,SAAS,EACT,QAAQ,GACuD;IAC/D,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAE3B,OAAO,CACN,KAAC,cAAc,IACd,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,KAAK,EAAE,IAAI,CAAC,KAAK,KACb,CAAC,mBAAmB,IAAI,EAAE,mBAAmB,EAAE,CAAC,KAChD,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC,KAC1B,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC,YAE/B,QAAQ,GACO,CACjB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkC,CAAC,EAC7D,mBAAmB,EACnB,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACb,EAAE,EAAE;IACJ,OAAO,CACN,KAAC,aAAa,OAAK,UAAU,YAC5B,KAAC,YAAY,OACR,CAAC,mBAAmB,IAAI,EAAE,mBAAmB,EAAE,CAAC,KAChD,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC,KAC1B,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC,YAE/B,UAAU,CAAC,QAAQ,GACN,GACA,CAChB,CAAC;AACH,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @xmachines/play-react - React renderer for XMachines Play architecture
3
3
  *
4
- * Provides a thin React rendering layer that passively observes actor signals
4
+ * Provides a provider-based React rendering layer that passively observes actor signals
5
5
  * and renders UI components via @json-render/react. This package enables
6
6
  * framework-swappable architecture where React is just a rendering target
7
7
  * that subscribes to signal changes.
@@ -9,20 +9,38 @@
9
9
  * **Key principle:** React state is NEVER used for business logic—only for
10
10
  * triggering React's render cycle. Signals are the source of truth.
11
11
  *
12
- * Re-exports `defineRegistry`, `useBoundProp`, `ComponentFn`, and
13
- * `ComponentContext` from `@json-render/react` so consumers import everything
14
- * from `@xmachines/play-react` rather than `@json-render/react` directly.
12
+ * **Standard usage:**
13
+ * ```tsx
14
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
15
+ * <PlayRenderer />
16
+ * </PlayUIProvider>
17
+ * ```
18
+ *
19
+ * **Escape hatch (custom composition):**
20
+ * ```tsx
21
+ * <ActorProvider actor={actor} registryResult={registryResult}>
22
+ * <JSONUIProvider registry={registryResult.registry}>
23
+ * <PlayRenderer />
24
+ * </JSONUIProvider>
25
+ * </ActorProvider>
26
+ * ```
15
27
  *
16
28
  * @packageDocumentation
17
29
  * @module @xmachines/play-react
18
30
  */
19
31
  export { PlayRenderer } from "./PlayRenderer.js";
32
+ export { ActorProvider } from "./ActorProvider.js";
33
+ export type { ActorProviderProps, ViewContextValue } from "./ActorProvider.js";
34
+ export { usePlayView } from "./ActorProvider.js";
35
+ export { PlayUIProvider } from "./PlayUIProvider.js";
36
+ export type { PlayUIProviderProps } from "./PlayUIProvider.js";
20
37
  export { useSignalEffect } from "./useSignalEffect.js";
21
38
  export { PlayErrorBoundary } from "./PlayErrorBoundary.js";
22
39
  export { useActor } from "./useActor.js";
23
- export { defineRegistry, useBoundProp } from "@json-render/react";
24
- export type { ComponentFn, ComponentContext } from "@json-render/react";
25
- export type { PlayRendererProps, RenderErrorHandler } from "./types.js";
26
- export type { PlayErrorBoundaryProps, PlayErrorBoundaryState } from "./PlayErrorBoundary.js";
27
40
  export type { PlayActor } from "./useActor.js";
41
+ export { defineRegistry, useBoundProp, JSONUIProvider, StateProvider, ActionProvider, VisibilityProvider, ValidationProvider, Renderer, } from "@json-render/react";
42
+ export type { ComponentFn, ComponentContext, JSONUIProviderProps, StateProviderProps, ActionProviderProps, VisibilityProviderProps, ValidationProviderProps, RendererProps, } from "@json-render/react";
43
+ export type { ActorProviderProps as PlayRendererProps } from "./ActorProvider.js";
44
+ export type { RenderErrorHandler } from "./types.js";
45
+ export type { PlayErrorBoundaryProps, PlayErrorBoundaryState } from "./PlayErrorBoundary.js";
28
46
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGxE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EACN,cAAc,EACd,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,GACR,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACX,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,aAAa,GACb,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,kBAAkB,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAClF,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @xmachines/play-react - React renderer for XMachines Play architecture
3
3
  *
4
- * Provides a thin React rendering layer that passively observes actor signals
4
+ * Provides a provider-based React rendering layer that passively observes actor signals
5
5
  * and renders UI components via @json-render/react. This package enables
6
6
  * framework-swappable architecture where React is just a rendering target
7
7
  * that subscribes to signal changes.
@@ -9,19 +9,33 @@
9
9
  * **Key principle:** React state is NEVER used for business logic—only for
10
10
  * triggering React's render cycle. Signals are the source of truth.
11
11
  *
12
- * Re-exports `defineRegistry`, `useBoundProp`, `ComponentFn`, and
13
- * `ComponentContext` from `@json-render/react` so consumers import everything
14
- * from `@xmachines/play-react` rather than `@json-render/react` directly.
12
+ * **Standard usage:**
13
+ * ```tsx
14
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
15
+ * <PlayRenderer />
16
+ * </PlayUIProvider>
17
+ * ```
18
+ *
19
+ * **Escape hatch (custom composition):**
20
+ * ```tsx
21
+ * <ActorProvider actor={actor} registryResult={registryResult}>
22
+ * <JSONUIProvider registry={registryResult.registry}>
23
+ * <PlayRenderer />
24
+ * </JSONUIProvider>
25
+ * </ActorProvider>
26
+ * ```
15
27
  *
16
28
  * @packageDocumentation
17
29
  * @module @xmachines/play-react
18
30
  */
19
31
  // Main exports
20
32
  export { PlayRenderer } from "./PlayRenderer.js";
33
+ export { ActorProvider } from "./ActorProvider.js";
34
+ export { usePlayView } from "./ActorProvider.js";
35
+ export { PlayUIProvider } from "./PlayUIProvider.js";
21
36
  export { useSignalEffect } from "./useSignalEffect.js";
22
37
  export { PlayErrorBoundary } from "./PlayErrorBoundary.js";
23
38
  export { useActor } from "./useActor.js";
24
- // Re-export from @json-render/react so consumers import everything from @xmachines/play-react.
25
- // React's useContext works anywhere in the call tree no wrapper needed.
26
- export { defineRegistry, useBoundProp } from "@json-render/react";
39
+ // Re-exports from @json-render/react (per D-14)
40
+ export { defineRegistry, useBoundProp, JSONUIProvider, StateProvider, ActionProvider, VisibilityProvider, ValidationProvider, Renderer, } from "@json-render/react";
27
41
  //# 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;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,+FAA+F;AAC/F,0EAA0E;AAC1E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,gDAAgD;AAChD,OAAO,EACN,cAAc,EACd,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,GACR,MAAM,oBAAoB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,80 +1,12 @@
1
1
  /**
2
2
  * TypeScript type definitions for play-react
3
3
  *
4
- * @packageDocumentation
5
- */
6
- import type { DefineRegistryResult, RenderErrorHandler } from "@json-render/react";
7
- import type { StateStore } from "@json-render/core";
8
- import type { AbstractActor, Viewable } from "@xmachines/play-actor";
9
- import type React from "react";
10
- import type { AnyActorLogic } from "xstate";
11
- /**
12
- * Props for PlayRenderer component
4
+ * PlayRendererProps has been removed — use ActorProviderProps or PlayUIProviderProps instead.
5
+ * See ActorProvider.tsx and PlayUIProvider.tsx.
13
6
  *
14
- * @typeParam TLogic - The XState actor logic type. Defaults to `AnyActorLogic` for
15
- * non-generic usage.
16
- *
17
- * @property actor - Actor instance with currentView signal (requires Viewable capability)
18
- * @property registryResult - Full result from defineRegistry() in @json-render/react.
19
- * Contains both the component registry and the action handlers factory. Action handlers
20
- * are real async functions dispatching to the actor (not string-mapped event types).
21
- * @property store - Optional external StateStore (controlled mode).
22
- * @property fallback - Optional component shown when currentView is null
23
- * @property onError - Optional callback invoked when a catalog component throws during render.
7
+ * @packageDocumentation
24
8
  */
25
- export interface PlayRendererProps<TLogic extends AnyActorLogic = AnyActorLogic> {
26
- /** Actor instance with currentView signal (requires Viewable capability) */
27
- actor: AbstractActor<TLogic> & Viewable;
28
- /**
29
- * Full result from defineRegistry() — contains component registry and action handlers.
30
- * Action handlers are async functions that dispatch to the actor (not string-mapped
31
- * event type stubs). Replaces the old `registry` + `actions` prop pair.
32
- *
33
- * @example
34
- * ```tsx
35
- * const registryResult = defineRegistry(catalog, {
36
- * components: { Login, Dashboard },
37
- * actions: {
38
- * login: async ({ username }) => actor.send({ type: 'auth.login', username }),
39
- * logout: async () => actor.send({ type: 'auth.logout' }),
40
- * },
41
- * });
42
- * <PlayRenderer actor={actor} registryResult={registryResult} />
43
- * ```
44
- */
45
- registryResult: DefineRegistryResult;
46
- /**
47
- * Optional external StateStore (e.g. from `xstateStoreStateStore` in @json-render/xstate).
48
- * When provided, PlayRenderer operates in controlled mode — spec.state is ignored and
49
- * this store is the single source of truth for UI state (form values, etc.).
50
- * When omitted, a fresh @xstate/store atom is created internally per view transition,
51
- * seeded from spec.state.
52
- */
53
- store?: StateStore;
54
- /** Optional component shown when currentView is null or a catalog component throws */
55
- fallback?: React.ReactNode;
56
- /**
57
- * Optional error handler callback invoked when a catalog component throws during render.
58
- * Forwarded directly to the internal `PlayErrorBoundary` — use to integrate with
59
- * production observability tools (Sentry, Datadog, etc.).
60
- *
61
- * @example
62
- * ```tsx
63
- * <PlayRenderer actor={actor} registryResult={registryResult} onError={Sentry.captureException} />
64
- * ```
65
- */
66
- onError?: (error: Error, info: React.ErrorInfo) => void;
67
- /**
68
- * Called when an individual catalog component throws during render.
69
- *
70
- * Caught by the inner error boundary inside each rendered element — the failed
71
- * component is silently removed while the rest of the spec continues rendering.
72
- * Unlike `onError`, this does not receive a reset callback.
73
- * Takes precedence over any `onRenderError` set via `defineRegistry`.
74
- *
75
- * When not provided, `@json-render/react` logs the error to `console.error`.
76
- */
77
- onRenderError?: RenderErrorHandler;
78
- }
79
- export type { RenderErrorHandler };
9
+ export type { ActorProviderProps } from "./ActorProvider.js";
10
+ export type { PlayUIProviderProps } from "./PlayUIProvider.js";
11
+ export type { RenderErrorHandler } from "@json-render/react";
80
12
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,iBAAiB,CAAC,MAAM,SAAS,aAAa,GAAG,aAAa;IAC9E,4EAA4E;IAC5E,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC;IAExC;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,EAAE,oBAAoB,CAAC;IAErC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IAExD;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAED,YAAY,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/types.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * TypeScript type definitions for play-react
3
3
  *
4
+ * PlayRendererProps has been removed — use ActorProviderProps or PlayUIProviderProps instead.
5
+ * See ActorProvider.tsx and PlayUIProvider.tsx.
6
+ *
4
7
  * @packageDocumentation
5
8
  */
6
9
  export {};
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -4,7 +4,7 @@
4
4
  * Components rendered inside PlayRenderer can call useActor() to get direct
5
5
  * access to the actor instance without prop drilling.
6
6
  *
7
- * @throws {Error} If called outside a PlayRenderer tree
7
+ * @throws {NonNullableError} If called outside an ActorProvider/PlayUIProvider tree
8
8
  *
9
9
  * @example
10
10
  * ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"useActor.d.ts","sourceRoot":"","sources":["../src/useActor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AAErD,eAAO,MAAM,YAAY,2CAAwC,CAAC;AAElE,wBAAgB,QAAQ,IAAI,SAAS,CAIpC"}
1
+ {"version":3,"file":"useActor.d.ts","sourceRoot":"","sources":["../src/useActor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AAErD,eAAO,MAAM,YAAY,2CAAwC,CAAC;AAElE,wBAAgB,QAAQ,IAAI,SAAS,CAEpC"}
package/dist/useActor.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Components rendered inside PlayRenderer can call useActor() to get direct
5
5
  * access to the actor instance without prop drilling.
6
6
  *
7
- * @throws {Error} If called outside a PlayRenderer tree
7
+ * @throws {NonNullableError} If called outside an ActorProvider/PlayUIProvider tree
8
8
  *
9
9
  * @example
10
10
  * ```typescript
@@ -19,11 +19,9 @@
19
19
  * @packageDocumentation
20
20
  */
21
21
  import { createContext, useContext } from "react";
22
+ import { assertNonNullable } from "@xmachines/play";
22
23
  export const ActorContext = createContext(null);
23
24
  export function useActor() {
24
- const actor = useContext(ActorContext);
25
- if (!actor)
26
- throw new Error("useActor() must be called inside <PlayRenderer>");
27
- return actor;
25
+ return assertNonNullable(useContext(ActorContext), "ActorContext");
28
26
  }
29
27
  //# sourceMappingURL=useActor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useActor.js","sourceRoot":"","sources":["../src/useActor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMlD,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAmB,IAAI,CAAC,CAAC;AAElE,MAAM,UAAU,QAAQ;IACvB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC/E,OAAO,KAAK,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"useActor.js","sourceRoot":"","sources":["../src/useActor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMpD,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAmB,IAAI,CAAC,CAAC;AAElE,MAAM,UAAU,QAAQ;IACvB,OAAO,iBAAiB,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,cAAc,CAAC,CAAC;AACpE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmachines/play-react",
3
- "version": "1.0.0-beta.33",
3
+ "version": "1.0.0-beta.34",
4
4
  "description": "React renderer for XMachines Play architecture with signal-driven rendering",
5
5
  "keywords": [
6
6
  "actor",
@@ -45,9 +45,9 @@
45
45
  "prepublishOnly": "npm run build"
46
46
  },
47
47
  "dependencies": {
48
- "@xmachines/play": "1.0.0-beta.33",
49
- "@xmachines/play-actor": "1.0.0-beta.33",
50
- "@xmachines/play-signals": "1.0.0-beta.33"
48
+ "@xmachines/play": "1.0.0-beta.34",
49
+ "@xmachines/play-actor": "1.0.0-beta.34",
50
+ "@xmachines/play-signals": "1.0.0-beta.34"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@json-render/core": "^0.18.0",
@@ -58,7 +58,7 @@
58
58
  "@types/node": "^25.6.0",
59
59
  "@types/react": "^19.2.14",
60
60
  "@types/react-dom": "^19.2.3",
61
- "@xmachines/shared": "1.0.0-beta.33",
61
+ "@xmachines/shared": "1.0.0-beta.34",
62
62
  "@xstate/store": "^3.17.0",
63
63
  "jsdom": "^29.0.2",
64
64
  "oxfmt": "^0.45.0",