@xmachines/play-react 1.0.0-beta.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,178 @@
1
+ import { jsx as _jsx } 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, useMemo, createContext, useContext } from "react";
14
+ import { StateProvider, useStateStore } from "@xmachines/json-render-react";
15
+ import { createAtom } from "@xstate/store";
16
+ import { xstateStoreStateStore } from "@xmachines/json-render-xstate";
17
+ import { useSignalEffect } from "./useSignalEffect.js";
18
+ import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
19
+ import { assertNonNullable } from "@xmachines/play";
20
+ import { toAtomState, attachRenderErrorHandler, } from "@xmachines/play-actor";
21
+ import { ActorContext } from "./useActor.js";
22
+ /**
23
+ * Internal React context for ViewContextValue.
24
+ * Accessed via usePlayView() hook.
25
+ */
26
+ const ViewContext = createContext(null);
27
+ /**
28
+ * Hook to access the current view spec, handlers, and registry.
29
+ *
30
+ * Must be called inside <ActorProvider> or <PlayUIProvider>.
31
+ *
32
+ * @throws {Error} If called outside an ActorProvider/PlayUIProvider tree
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { usePlayView } from "@xmachines/play-react";
37
+ *
38
+ * function MyRenderer() {
39
+ * const view = usePlayView();
40
+ * return <Renderer spec={view.spec} registry={view.registry} />;
41
+ * }
42
+ * ```
43
+ *
44
+ * @public
45
+ */
46
+ export function usePlayView() {
47
+ return assertNonNullable(useContext(ViewContext), "ViewContext");
48
+ }
49
+ /**
50
+ * Create a StateStore backed by a fresh @xstate/store atom seeded from the given state.
51
+ * Called internally per view transition when no external store prop is provided.
52
+ */
53
+ function createViewStore(initialState) {
54
+ return xstateStoreStateStore({ atom: createAtom(initialState) });
55
+ }
56
+ /**
57
+ * Inner component that runs inside StateProvider so it can access StateStore context
58
+ * via useStateStore(). Resolves action handlers from registryResult.handlers() using
59
+ * the live StateProvider set/getSnapshot functions, then exposes them via ViewContext.
60
+ */
61
+ function ActorProviderInner({ registryResult, spec, store, children, }) {
62
+ const stateCtx = useStateStore();
63
+ // Stable refs for stateCtx methods so the useMemo below doesn't need to depend
64
+ // on stateCtx identity (useStateStore() may return a new object each render even
65
+ // when the underlying store hasn't changed). The handlers factory passes these as
66
+ // getter functions and calls them at action-execution time, not at creation time,
67
+ // so reading from a ref is always correct.
68
+ const stateCtxRef = useRef(stateCtx);
69
+ stateCtxRef.current = stateCtx;
70
+ // Build a SetState adapter: the handlers factory expects an updater-function pattern
71
+ // ((prev) => next), while stateCtx provides path-based set/update. This adapter
72
+ // bridges the two so action functions can use setState if needed.
73
+ // Stable function reference — reads stateCtxRef.current at invocation time.
74
+ const setStateAdapterRef = useRef((updater) => {
75
+ const prev = stateCtxRef.current.getSnapshot();
76
+ stateCtxRef.current.update(updater(prev));
77
+ });
78
+ // Memoize handlers keyed to registryResult identity. The getter functions are
79
+ // stable refs so they do not contribute to invalidation. Handlers are only
80
+ // recreated when the registry definition itself changes (e.g. a new defineRegistry
81
+ // call), not on every render cycle.
82
+ const handlers = useMemo(() => registryResult.handlers(() => setStateAdapterRef.current, () => stateCtxRef.current.getSnapshot()), [registryResult]);
83
+ // Memoize the context value on its actual inputs — a fresh object every
84
+ // render would re-render every usePlayView() consumer even when nothing
85
+ // changed (wasted renders).
86
+ const viewValue = useMemo(() => ({
87
+ spec,
88
+ handlers,
89
+ registry: registryResult.registry,
90
+ store,
91
+ }), [spec, handlers, registryResult.registry, store]);
92
+ return _jsx(ViewContext.Provider, { value: viewValue, children: children });
93
+ }
94
+ /**
95
+ * ActorProvider — escape hatch primitive for composing actor lifecycle with custom providers.
96
+ *
97
+ * Subscribes to actor.currentView signal, manages the per-view StateStore lifecycle,
98
+ * wraps children in StateProvider and PlayErrorBoundary, and injects onRenderError
99
+ * into the component registry.
100
+ *
101
+ * Standard usage: prefer <PlayUIProvider> unless you need to compose providers manually.
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * // Custom composition (escape hatch):
106
+ * <ActorProvider actor={actor} registryResult={registryResult}>
107
+ * <JSONUIProvider registry={registryResult.registry}>
108
+ * <PlayRenderer />
109
+ * </JSONUIProvider>
110
+ * </ActorProvider>
111
+ *
112
+ * // Standard usage: prefer PlayUIProvider
113
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
114
+ * <PlayRenderer />
115
+ * </PlayUIProvider>
116
+ * ```
117
+ *
118
+ * @public
119
+ */
120
+ export const ActorProvider = ({ actor, registryResult, store: externalStore, fallback = null, onError, onRenderError, children, }) => {
121
+ // React state for triggering re-renders (NOT business logic state)
122
+ // Signal is source of truth, useState is just React's render trigger
123
+ const [view, setView] = useState(() => actor.currentView.get());
124
+ // Internal store ref — tracks the current per-view atom store.
125
+ // Keyed to view identity: recreated whenever the view changes (new spec.state seed).
126
+ // Ignored when externalStore is provided.
127
+ const internalStoreRef = useRef(null);
128
+ const lastViewRef = useRef(null);
129
+ // Subscribe to signal changes. The [actor] dep re-creates the watcher when
130
+ // the actor prop swaps — without it the watcher keeps tracking the OLD
131
+ // actor's currentView signal and the rendered view freezes on the old actor
132
+ // while events flow to the new one.
133
+ useSignalEffect(() => {
134
+ const currentView = actor.currentView.get();
135
+ setView(currentView);
136
+ }, [actor]);
137
+ // Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level handler)
138
+ // Centralised here per D-19 — one location for all framework renderers.
139
+ // Memoized on its actual inputs: rebuilding the injected registry every render
140
+ // would churn registry identity and invalidate ActorProviderInner's handlers
141
+ // useMemo on every render (wasted work + wasted consumer re-renders).
142
+ const activeRegistryResult = useMemo(() => {
143
+ if (!onRenderError)
144
+ return registryResult;
145
+ return {
146
+ ...registryResult,
147
+ registry: attachRenderErrorHandler(registryResult.registry, onRenderError),
148
+ };
149
+ }, [registryResult, onRenderError]);
150
+ // No view in current state — render fallback INSIDE ActorContext so a
151
+ // fallback component can call useActor() (e.g. to send a retry event).
152
+ // Parity with the error-boundary fallback below and with the Solid/Svelte/Vue
153
+ // renderers, which all provide context to their null-view fallbacks.
154
+ // ViewContext is intentionally NOT provided: there is no view spec to expose.
155
+ if (!view) {
156
+ return (_jsx(ActorContext.Provider, { value: actor, children: fallback }));
157
+ }
158
+ // Resolve the store to use for StateProvider:
159
+ // - External (controlled): use as-is, caller manages lifecycle
160
+ // - Internal: create a fresh atom when the view changes (new route/state)
161
+ let store;
162
+ if (externalStore) {
163
+ store = externalStore;
164
+ }
165
+ else {
166
+ // Recreate the internal store when the view identity changes
167
+ // (view is a new object on every transition per deriveCurrentView)
168
+ if (internalStoreRef.current === null || lastViewRef.current !== view) {
169
+ // Proto-safe guard (T-37-03-01): prevents Date/Array/class-instance from being
170
+ // passed to createAtom. Replaces the weak `?? {}` guard from old code_context.
171
+ internalStoreRef.current = createViewStore(toAtomState(view.state));
172
+ lastViewRef.current = view;
173
+ }
174
+ store = internalStoreRef.current;
175
+ }
176
+ 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 }) }) }) }));
177
+ };
178
+ //# sourceMappingURL=ActorProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActorProvider.js","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAO5E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACN,WAAW,EACX,wBAAwB,GAIxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAqB,MAAM,eAAe,CAAC;AAuBhE;;;GAGG;AACH,MAAM,WAAW,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,WAAW;IAC1B,OAAO,iBAAiB,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,YAAqC;IAC7D,OAAO,qBAAqB,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,EAC3B,cAAc,EACd,IAAI,EACJ,KAAK,EACL,QAAQ,GAMR;IACA,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IAEjC,+EAA+E;IAC/E,iFAAiF;IACjF,kFAAkF;IAClF,kFAAkF;IAClF,2CAA2C;IAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IAE/B,qFAAqF;IACrF,gFAAgF;IAChF,kEAAkE;IAClE,4EAA4E;IAC5E,MAAM,kBAAkB,GAAG,MAAM,CAAW,CAAC,OAAO,EAAE,EAAE;QACvD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC/C,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,2EAA2E;IAC3E,mFAAmF;IACnF,oCAAoC;IACpC,MAAM,QAAQ,GAAG,OAAO,CACvB,GAAG,EAAE,CACJ,cAAc,CAAC,QAAQ,CACtB,GAAG,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAChC,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,CACvC,EACF,CAAC,cAAc,CAAC,CAChB,CAAC;IAEF,wEAAwE;IACxE,wEAAwE;IACxE,4BAA4B;IAC5B,MAAM,SAAS,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,CAAC;QACN,IAAI;QACJ,QAAQ;QACR,QAAQ,EAAE,cAAc,CAAC,QAAQ;QACjC,KAAK;KACL,CAAC,EACF,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAChD,CAAC;IAEF,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,SAAS,YAAG,QAAQ,GAAwB,CAAC;AAClF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC3D,KAAK,EACL,cAAc,EACd,KAAK,EAAE,aAAa,EACpB,QAAQ,GAAG,IAAI,EACf,OAAO,EACP,aAAa,EACb,QAAQ,GACR,EAAE,EAAE;IACJ,mEAAmE;IACnE,qEAAqE;IACrE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAkB,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IAEjF,+DAA+D;IAC/D,qFAAqF;IACrF,0CAA0C;IAC1C,MAAM,gBAAgB,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAC;IAElD,2EAA2E;IAC3E,uEAAuE;IACvE,4EAA4E;IAC5E,oCAAoC;IACpC,eAAe,CAAC,GAAG,EAAE;QACpB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAC5C,OAAO,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,mGAAmG;IACnG,wEAAwE;IACxE,+EAA+E;IAC/E,6EAA6E;IAC7E,sEAAsE;IACtE,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,EAAE;QACzC,IAAI,CAAC,aAAa;YAAE,OAAO,cAAc,CAAC;QAC1C,OAAO;YACN,GAAG,cAAc;YACjB,QAAQ,EAAE,wBAAwB,CAAC,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC;SAC1E,CAAC;IACH,CAAC,EAAE,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC,CAAC;IAEpC,sEAAsE;IACtE,uEAAuE;IACvE,8EAA8E;IAC9E,qEAAqE;IACrE,8EAA8E;IAC9E,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,CACN,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAqB,YAAG,QAAQ,GAAyB,CACvF,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,+DAA+D;IAC/D,0EAA0E;IAC1E,IAAI,KAAiB,CAAC;IACtB,IAAI,aAAa,EAAE,CAAC;QACnB,KAAK,GAAG,aAAa,CAAC;IACvB,CAAC;SAAM,CAAC;QACP,6DAA6D;QAC7D,mEAAmE;QACnE,IAAI,gBAAgB,CAAC,OAAO,KAAK,IAAI,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YACvE,+EAA+E;YAC/E,+EAA+E;YAC/E,gBAAgB,CAAC,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACpE,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC5B,CAAC;QACD,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,OAAO,CACN,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAqB,YAClD,KAAC,iBAAiB,IAAC,QAAQ,EAAE,QAAQ,KAAM,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC,YAClE,KAAC,aAAa,IAAC,KAAK,EAAE,KAAK,YAC1B,KAAC,kBAAkB,IAClB,cAAc,EAAE,oBAAoB,EACpC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,YAEX,QAAQ,GACW,GACN,GACG,GACG,CACxB,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * PlayErrorBoundary - React error boundary for catching catalog component render errors
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ import React from "react";
7
+ /**
8
+ * Props for PlayErrorBoundary
9
+ *
10
+ * @public
11
+ */
12
+ export interface PlayErrorBoundaryProps {
13
+ /** Fallback UI to render when a child component throws. Defaults to null. */
14
+ fallback?: React.ReactNode;
15
+ /** Child components to render */
16
+ children: React.ReactNode;
17
+ /** Optional error handler callback — forwards errors to observability tools (Sentry, etc.) */
18
+ onError?: (error: Error, info: React.ErrorInfo) => void;
19
+ }
20
+ /**
21
+ * Internal state shape for PlayErrorBoundary
22
+ *
23
+ * @public
24
+ */
25
+ export interface PlayErrorBoundaryState {
26
+ hasError: boolean;
27
+ error: Error | null;
28
+ }
29
+ /**
30
+ * React class component error boundary for catching catalog component render errors.
31
+ *
32
+ * Wraps catalog component renders so failures are caught and forwarded to standard
33
+ * React error boundary protocol. Consumers can attach the `onError` prop to forward
34
+ * errors to production observability tools (Sentry, Datadog, etc.).
35
+ *
36
+ * **React 19 safety (Phase 29):** `componentDidCatch` calls `onError` for observability
37
+ * but does NOT re-throw. `getDerivedStateFromError` already sets the fallback state —
38
+ * re-throwing from `componentDidCatch` can unmount the entire React 19 root.
39
+ *
40
+ * Per CONS-14: Class component pattern works with all React versions (18 and 19).
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * <PlayErrorBoundary fallback={<div>Something went wrong</div>} onError={Sentry.captureException}>
45
+ * <CatalogComponent {...props} />
46
+ * </PlayErrorBoundary>
47
+ * ```
48
+ */
49
+ export declare class PlayErrorBoundary extends React.Component<PlayErrorBoundaryProps, PlayErrorBoundaryState> {
50
+ constructor(props: PlayErrorBoundaryProps);
51
+ static getDerivedStateFromError(error: Error): PlayErrorBoundaryState;
52
+ componentDidCatch(error: Error, info: React.ErrorInfo): void;
53
+ render(): React.ReactNode;
54
+ }
55
+ //# sourceMappingURL=PlayErrorBoundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayErrorBoundary.d.ts","sourceRoot":"","sources":["../src/PlayErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,iCAAiC;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,8FAA8F;IAC9F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;CACxD;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,iBAAkB,SAAQ,KAAK,CAAC,SAAS,CACrD,sBAAsB,EACtB,sBAAsB,CACtB;gBACY,KAAK,EAAE,sBAAsB;IAKzC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,sBAAsB;IAI5D,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAI5D,MAAM,IAAI,KAAK,CAAC,SAAS;CAMlC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * PlayErrorBoundary - React error boundary for catching catalog component render errors
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ import React from "react";
7
+ /**
8
+ * React class component error boundary for catching catalog component render errors.
9
+ *
10
+ * Wraps catalog component renders so failures are caught and forwarded to standard
11
+ * React error boundary protocol. Consumers can attach the `onError` prop to forward
12
+ * errors to production observability tools (Sentry, Datadog, etc.).
13
+ *
14
+ * **React 19 safety (Phase 29):** `componentDidCatch` calls `onError` for observability
15
+ * but does NOT re-throw. `getDerivedStateFromError` already sets the fallback state —
16
+ * re-throwing from `componentDidCatch` can unmount the entire React 19 root.
17
+ *
18
+ * Per CONS-14: Class component pattern works with all React versions (18 and 19).
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <PlayErrorBoundary fallback={<div>Something went wrong</div>} onError={Sentry.captureException}>
23
+ * <CatalogComponent {...props} />
24
+ * </PlayErrorBoundary>
25
+ * ```
26
+ */
27
+ export class PlayErrorBoundary extends React.Component {
28
+ constructor(props) {
29
+ super(props);
30
+ this.state = { hasError: false, error: null };
31
+ }
32
+ static getDerivedStateFromError(error) {
33
+ return { hasError: true, error };
34
+ }
35
+ componentDidCatch(error, info) {
36
+ this.props.onError?.(error, info);
37
+ }
38
+ render() {
39
+ if (this.state.hasError) {
40
+ return this.props.fallback ?? null;
41
+ }
42
+ return this.props.children;
43
+ }
44
+ }
45
+ //# sourceMappingURL=PlayErrorBoundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlayErrorBoundary.js","sourceRoot":"","sources":["../src/PlayErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AA0B1B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK,CAAC,SAG5C;IACA,YAAY,KAA6B;QACxC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC3C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAEQ,iBAAiB,CAAC,KAAY,EAAE,IAAqB;QAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAEQ,MAAM;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;QACpC,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC5B,CAAC;CACD"}
@@ -1,57 +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
- * @packageDocumentation
5
- */
6
- import React from "react";
7
- import type { PlayRendererProps } from "./types.js";
8
- /**
9
- * Main renderer component that subscribes to actor signals and renders UI
10
- *
11
- * Architecture (per RESEARCH.md Pattern 1):
12
- * - Subscribes to actor.currentView signal via useSignalEffect
13
- * - Dynamically renders catalog components based on view.component string
14
- * - Forwards user events to actor via actor.send()
15
- * - React state 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-react";
24
- * import { definePlayer } from "@xmachines/play-xstate";
25
- *
26
- * const actor = definePlayer({ machine, catalog })();
27
- * actor.start();
4
+ * Must be rendered inside <ActorProvider> or <PlayUIProvider>.
5
+ * Reads view spec, handlers, and registry from usePlayView() context,
6
+ * then delegates to @xmachines/json-render-react Renderer.
28
7
  *
29
- * const components = {
30
- * Dashboard: ({ userId, send }) => <div>User: {userId}</div>,
31
- * LoginForm: ({ error, send }) => <form onSubmit={(e) => {
32
- * e.preventDefault();
33
- * send({ type: "intent", name: "login.submit", payload: {...} });
34
- * }}>...</form>
35
- * };
36
- *
37
- * <PlayRenderer actor={actor} components={components} />
8
+ * Standard usage:
9
+ * ```tsx
10
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
11
+ * <PlayRenderer />
12
+ * </PlayUIProvider>
38
13
  * ```
39
14
  *
40
- * @param props - Component props
41
- * @returns React element rendering current view from actor
42
- *
43
- * @remarks
44
- * **Component lookup:** Dynamically looks up component from `components` map
45
- * using `view.component` string from actor.currentView signal.
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
+ * ```
46
23
  *
47
- * **Event forwarding:** Injects `send` function as prop to components. Components
48
- * call `send(event)` to forward intents to actor. Actor guards decide validity.
24
+ * @packageDocumentation
25
+ */
26
+ import React from "react";
27
+ /**
28
+ * Zero-prop leaf component that renders the current actor view.
49
29
  *
50
- * **Error handling:** If component not found in catalog, logs error and shows
51
- * fallback. This indicates missing component registration, not runtime error.
30
+ * Reads the current PlaySpec, handlers, and registry from the ActorProvider
31
+ * context via usePlayView(), then renders via @xmachines/json-render-react Renderer.
52
32
  *
53
- * **CRITICAL:** Never call actor.send() during render - only in event handlers.
54
- * Calling send during render causes infinite render loops.
33
+ * @public
55
34
  */
56
- export declare const PlayRenderer: React.FC<PlayRendererProps>;
35
+ export declare const PlayRenderer: React.FC<Record<string, never>>;
57
36
  //# sourceMappingURL=PlayRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA2CpD,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,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAGxD,CAAC"}
@@ -1,87 +1,42 @@
1
- import { Fragment as _Fragment, jsx as _jsx } 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
- * @packageDocumentation
6
- */
7
- import React, { useState } from "react";
8
- import { useSignalEffect } from "./useSignalEffect.js";
9
- /**
10
- * Main renderer component that subscribes to actor signals and renders UI
11
- *
12
- * Architecture (per RESEARCH.md Pattern 1):
13
- * - Subscribes to actor.currentView signal via useSignalEffect
14
- * - Dynamically renders catalog components based on view.component string
15
- * - Forwards user events to actor via actor.send()
16
- * - React state only for triggering renders, NOT business logic
17
- *
18
- * Invariant: Actor Authority - Actor decides all state transitions via guards.
19
- * Invariant: Passive Infrastructure - Component observes signals and sends events.
20
- * Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.
21
- *
22
- * @example
23
- * ```typescript
24
- * import { PlayRenderer } from "@xmachines/play-react";
25
- * import { definePlayer } from "@xmachines/play-xstate";
26
- *
27
- * const actor = definePlayer({ machine, catalog })();
28
- * actor.start();
5
+ * Must be rendered inside <ActorProvider> or <PlayUIProvider>.
6
+ * Reads view spec, handlers, and registry from usePlayView() context,
7
+ * then delegates to @xmachines/json-render-react Renderer.
29
8
  *
30
- * const components = {
31
- * Dashboard: ({ userId, send }) => <div>User: {userId}</div>,
32
- * LoginForm: ({ error, send }) => <form onSubmit={(e) => {
33
- * e.preventDefault();
34
- * send({ type: "intent", name: "login.submit", payload: {...} });
35
- * }}>...</form>
36
- * };
37
- *
38
- * <PlayRenderer actor={actor} components={components} />
9
+ * Standard usage:
10
+ * ```tsx
11
+ * <PlayUIProvider actor={actor} registryResult={registryResult}>
12
+ * <PlayRenderer />
13
+ * </PlayUIProvider>
39
14
  * ```
40
15
  *
41
- * @param props - Component props
42
- * @returns React element rendering current view from actor
43
- *
44
- * @remarks
45
- * **Component lookup:** Dynamically looks up component from `components` map
46
- * using `view.component` string from actor.currentView signal.
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
+ * ```
47
24
  *
48
- * **Event forwarding:** Injects `send` function as prop to components. Components
49
- * call `send(event)` to forward intents to actor. Actor guards decide validity.
25
+ * @packageDocumentation
26
+ */
27
+ import React from "react";
28
+ import { Renderer } from "@xmachines/json-render-react";
29
+ import { usePlayView } from "./ActorProvider.js";
30
+ /**
31
+ * Zero-prop leaf component that renders the current actor view.
50
32
  *
51
- * **Error handling:** If component not found in catalog, logs error and shows
52
- * fallback. This indicates missing component registration, not runtime error.
33
+ * Reads the current PlaySpec, handlers, and registry from the ActorProvider
34
+ * context via usePlayView(), then renders via @xmachines/json-render-react Renderer.
53
35
  *
54
- * **CRITICAL:** Never call actor.send() during render - only in event handlers.
55
- * Calling send during render causes infinite render loops.
36
+ * @public
56
37
  */
57
- export const PlayRenderer = ({ actor, components, fallback = null, }) => {
58
- // React state for triggering re-renders (NOT business logic state)
59
- // Signal is source of truth, useState is just React's render trigger
60
- const [view, setView] = useState(() => actor.currentView.get());
61
- // Subscribe to signal changes
62
- useSignalEffect(() => {
63
- const currentView = actor.currentView.get();
64
- setView(currentView);
65
- });
66
- // No view in current state
67
- if (!view) {
68
- return _jsx(_Fragment, { children: fallback });
69
- }
70
- // Handle null/undefined components catalog gracefully
71
- if (!components) {
72
- console.error(`Components catalog is ${components === null ? "null" : "undefined"}. ` +
73
- `Cannot render component "${view.component}".`);
74
- return _jsx(_Fragment, { children: fallback });
75
- }
76
- // Look up component from catalog
77
- const Component = components[view.component];
78
- if (!Component) {
79
- console.error(`Component "${view.component}" not found in catalog. ` +
80
- `Available components: ${Object.keys(components).join(", ")}`);
81
- return _jsx(_Fragment, { children: fallback });
82
- }
83
- // Render with props from actor + send function
84
- // bind(actor) ensures 'this' context is correct when components call send()
85
- return _jsx(Component, { ...view.props, send: actor.send.bind(actor) });
38
+ export const PlayRenderer = () => {
39
+ const view = usePlayView();
40
+ return _jsx(Renderer, { spec: view.spec, registry: view.registry });
86
41
  };
87
42
  //# sourceMappingURL=PlayRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAIvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACzD,KAAK,EACL,UAAU,EACV,QAAQ,GAAG,IAAI,GACf,EAAE,EAAE;IACJ,mEAAmE;IACnE,qEAAqE;IACrE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IAErF,8BAA8B;IAC9B,eAAe,CAAC,GAAG,EAAE;QACpB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAC5C,OAAO,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACZ,yBAAyB,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI;YACtE,4BAA4B,IAAI,CAAC,SAAS,IAAI,CAC/C,CAAC;QACF,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,iCAAiC;IACjC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE7C,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CACZ,cAAc,IAAI,CAAC,SAAS,0BAA0B;YACrD,yBAAyB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;QACF,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,+CAA+C;IAC/C,4EAA4E;IAC5E,OAAO,KAAC,SAAS,OAAK,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAI,CAAC;AACpE,CAAC,CAAC"}
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,8BAA8B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAoC,GAAG,EAAE;IACjE,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 @xmachines/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 "@xmachines/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,8BAA8B,CAAC;AACxF,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"}