@xmachines/play-react 1.0.0-beta.9 → 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.
- package/LICENSE +21 -0
- package/README.md +130 -332
- package/dist/ActorProvider.d.ts +82 -0
- package/dist/ActorProvider.d.ts.map +1 -0
- package/dist/ActorProvider.js +178 -0
- package/dist/ActorProvider.js.map +1 -0
- package/dist/PlayErrorBoundary.d.ts +10 -2
- package/dist/PlayErrorBoundary.d.ts.map +1 -1
- package/dist/PlayErrorBoundary.js +4 -1
- package/dist/PlayErrorBoundary.js.map +1 -1
- package/dist/PlayRenderer.d.ts +26 -47
- package/dist/PlayRenderer.d.ts.map +1 -1
- package/dist/PlayRenderer.js +31 -77
- package/dist/PlayRenderer.js.map +1 -1
- package/dist/PlayUIProvider.d.ts +67 -0
- package/dist/PlayUIProvider.d.ts.map +1 -0
- package/dist/PlayUIProvider.js +73 -0
- package/dist/PlayUIProvider.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +6 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/useActor.d.ts +27 -0
- package/dist/useActor.d.ts.map +1 -0
- package/dist/useActor.js +27 -0
- package/dist/useActor.js.map +1 -0
- package/dist/useSignalEffect.d.ts +30 -15
- package/dist/useSignalEffect.d.ts.map +1 -1
- package/dist/useSignalEffect.js +43 -43
- package/dist/useSignalEffect.js.map +1 -1
- package/package.json +35 -14
|
@@ -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":"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"}
|
|
@@ -17,7 +17,12 @@ export interface PlayErrorBoundaryProps {
|
|
|
17
17
|
/** Optional error handler callback — forwards errors to observability tools (Sentry, etc.) */
|
|
18
18
|
onError?: (error: Error, info: React.ErrorInfo) => void;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Internal state shape for PlayErrorBoundary
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export interface PlayErrorBoundaryState {
|
|
21
26
|
hasError: boolean;
|
|
22
27
|
error: Error | null;
|
|
23
28
|
}
|
|
@@ -28,6 +33,10 @@ interface PlayErrorBoundaryState {
|
|
|
28
33
|
* React error boundary protocol. Consumers can attach the `onError` prop to forward
|
|
29
34
|
* errors to production observability tools (Sentry, Datadog, etc.).
|
|
30
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
|
+
*
|
|
31
40
|
* Per CONS-14: Class component pattern works with all React versions (18 and 19).
|
|
32
41
|
*
|
|
33
42
|
* @example
|
|
@@ -43,5 +52,4 @@ export declare class PlayErrorBoundary extends React.Component<PlayErrorBoundary
|
|
|
43
52
|
componentDidCatch(error: Error, info: React.ErrorInfo): void;
|
|
44
53
|
render(): React.ReactNode;
|
|
45
54
|
}
|
|
46
|
-
export {};
|
|
47
55
|
//# sourceMappingURL=PlayErrorBoundary.d.ts.map
|
|
@@ -1 +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,
|
|
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"}
|
|
@@ -11,6 +11,10 @@ import React from "react";
|
|
|
11
11
|
* React error boundary protocol. Consumers can attach the `onError` prop to forward
|
|
12
12
|
* errors to production observability tools (Sentry, Datadog, etc.).
|
|
13
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
|
+
*
|
|
14
18
|
* Per CONS-14: Class component pattern works with all React versions (18 and 19).
|
|
15
19
|
*
|
|
16
20
|
* @example
|
|
@@ -29,7 +33,6 @@ export class PlayErrorBoundary extends React.Component {
|
|
|
29
33
|
return { hasError: true, error };
|
|
30
34
|
}
|
|
31
35
|
componentDidCatch(error, info) {
|
|
32
|
-
console.error("[PlayErrorBoundary] Component render error:", error, info);
|
|
33
36
|
this.props.onError?.(error, info);
|
|
34
37
|
}
|
|
35
38
|
render() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayErrorBoundary.js","sourceRoot":"","sources":["../src/PlayErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
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"}
|
package/dist/PlayRenderer.d.ts
CHANGED
|
@@ -1,57 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PlayRenderer -
|
|
2
|
+
* PlayRenderer — zero-prop leaf component for rendering the current actor view.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
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
|
-
*
|
|
48
|
-
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
import React from "react";
|
|
27
|
+
/**
|
|
28
|
+
* Zero-prop leaf component that renders the current actor view.
|
|
49
29
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
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
|
-
*
|
|
54
|
-
* Calling send during render causes infinite render loops.
|
|
33
|
+
* @public
|
|
55
34
|
*/
|
|
56
|
-
export declare const PlayRenderer: React.FC<
|
|
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
|
|
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"}
|
package/dist/PlayRenderer.js
CHANGED
|
@@ -1,88 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* PlayRenderer -
|
|
3
|
+
* PlayRenderer — zero-prop leaf component for rendering the current actor view.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import { useSignalEffect } from "./useSignalEffect.js";
|
|
9
|
-
import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
|
|
10
|
-
/**
|
|
11
|
-
* Main renderer component that subscribes to actor signals and renders UI
|
|
12
|
-
*
|
|
13
|
-
* Architecture (per RESEARCH.md Pattern 1):
|
|
14
|
-
* - Subscribes to actor.currentView signal via useSignalEffect
|
|
15
|
-
* - Dynamically renders catalog components based on view.component string
|
|
16
|
-
* - Forwards user events to actor via actor.send()
|
|
17
|
-
* - React state only for triggering renders, NOT business logic
|
|
18
|
-
*
|
|
19
|
-
* Invariant: Actor Authority - Actor decides all state transitions via guards.
|
|
20
|
-
* Invariant: Passive Infrastructure - Component observes signals and sends events.
|
|
21
|
-
* Invariant: Signal-Only Reactivity - Business logic state lives in actor signals.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* import { PlayRenderer } from "@xmachines/play-react";
|
|
26
|
-
* import { definePlayer } from "@xmachines/play-xstate";
|
|
27
|
-
*
|
|
28
|
-
* const actor = definePlayer({ machine, catalog })();
|
|
29
|
-
* 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.
|
|
30
8
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* }}>...</form>
|
|
37
|
-
* };
|
|
38
|
-
*
|
|
39
|
-
* <PlayRenderer actor={actor} components={components} />
|
|
9
|
+
* Standard usage:
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <PlayUIProvider actor={actor} registryResult={registryResult}>
|
|
12
|
+
* <PlayRenderer />
|
|
13
|
+
* </PlayUIProvider>
|
|
40
14
|
* ```
|
|
41
15
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
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
|
+
* ```
|
|
48
24
|
*
|
|
49
|
-
*
|
|
50
|
-
|
|
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.
|
|
51
32
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
33
|
+
* Reads the current PlaySpec, handlers, and registry from the ActorProvider
|
|
34
|
+
* context via usePlayView(), then renders via @xmachines/json-render-react Renderer.
|
|
54
35
|
*
|
|
55
|
-
*
|
|
56
|
-
* Calling send during render causes infinite render loops.
|
|
36
|
+
* @public
|
|
57
37
|
*/
|
|
58
|
-
export const PlayRenderer = (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const [view, setView] = useState(() => actor.currentView.get());
|
|
62
|
-
// Subscribe to signal changes
|
|
63
|
-
useSignalEffect(() => {
|
|
64
|
-
const currentView = actor.currentView.get();
|
|
65
|
-
setView(currentView);
|
|
66
|
-
});
|
|
67
|
-
// No view in current state
|
|
68
|
-
if (!view) {
|
|
69
|
-
return _jsx(_Fragment, { children: fallback });
|
|
70
|
-
}
|
|
71
|
-
// Handle null/undefined components catalog gracefully
|
|
72
|
-
if (!components) {
|
|
73
|
-
console.error(`Components catalog is ${components === null ? "null" : "undefined"}. ` +
|
|
74
|
-
`Cannot render component "${view.component}".`);
|
|
75
|
-
return _jsx(_Fragment, { children: fallback });
|
|
76
|
-
}
|
|
77
|
-
// Look up component from catalog
|
|
78
|
-
const Component = components[view.component];
|
|
79
|
-
if (!Component) {
|
|
80
|
-
console.error(`Component "${view.component}" not found in catalog. ` +
|
|
81
|
-
`Available components: ${Object.keys(components).join(", ")}`);
|
|
82
|
-
return _jsx(_Fragment, { children: fallback });
|
|
83
|
-
}
|
|
84
|
-
// Render with props from actor + send function
|
|
85
|
-
// bind(actor) ensures 'this' context is correct when components call send()
|
|
86
|
-
return (_jsx(PlayErrorBoundary, { fallback: fallback, children: _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 });
|
|
87
41
|
};
|
|
88
42
|
//# sourceMappingURL=PlayRenderer.js.map
|
package/dist/PlayRenderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":";AAAA
|
|
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"}
|
|
@@ -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 @xmachines/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 "@xmachines/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,8BAA8B,CAAC;AACxF,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/errors.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Error class for renderer-level errors in the Play architecture.
|
|
4
|
+
*
|
|
5
|
+
* **Note (Phase 29):** `PlayErrorBoundary.componentDidCatch()` no longer throws
|
|
6
|
+
* this error. Re-throwing from `componentDidCatch` can unmount the entire React 19
|
|
7
|
+
* root. `RendererError` is retained for programmatic use in custom error handlers
|
|
8
|
+
* and parent boundaries — it is no longer emitted by the built-in boundary itself.
|
|
9
|
+
*
|
|
10
|
+
* **Error code:** `PLAY_REACT_RENDER_ERROR`
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { RendererError } from "@xmachines/play-react/errors";
|
|
15
|
+
*
|
|
16
|
+
* // Create a RendererError programmatically in a custom boundary:
|
|
17
|
+
* throw new RendererError("Custom render failure", { cause: originalError });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class RendererError extends PlayError {
|
|
21
|
+
constructor(message: string, options?: ErrorOptions);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAc,SAAQ,SAAS;gBAC/B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAInD"}
|