@xmachines/play-vue 2.0.0 → 2.1.1

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
@@ -1,22 +1,20 @@
1
1
  # `@xmachines/play-vue`
2
2
 
3
- > Vue 3 renderer for the XMachines Play Architecture passively observes actor signals and renders UI via `@xmachines/json-render-vue`.
3
+ > Vue 3 renderer for the XMachines Play Architecture. It observes the actor signals and renders the UI through `@xmachines/json-render-vue`.
4
4
 
5
- Part of the [XMachines Play monorepo](../../README.md).
6
-
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.0.0-blue)](https://www.npmjs.com/package/@xmachines/play-vue)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.1.1-blue)](https://www.npmjs.com/package/@xmachines/play-vue)
8
6
 
9
7
  ---
10
8
 
11
9
  ## Overview
12
10
 
13
- `@xmachines/play-vue` is the Vue 3 rendering layer for XMachines Play. It bridges TC39 Signals (actor state) to Vue reactivity and drives component rendering through `@xmachines/json-render-vue`.
11
+ `@xmachines/play-vue` is the Vue 3 rendering layer of XMachines Play. It connects the TC39 Signals (the actor state) to the Vue reactivity, and it renders the components through `@xmachines/json-render-vue`.
14
12
 
15
- **Architecture invariants this package upholds:**
13
+ **The architecture invariants that this package keeps:**
16
14
 
17
- - **Passive Infrastructure** — Components observe actor signals; they never decide state transitions.
18
- - **Signal-Only Reactivity** — TC39 Signals are the source of truth; Vue reactivity is used only to trigger re-renders.
19
- - **Actor Authority** — The actor controls view selection; the renderer reflects it.
15
+ - **Passive Infrastructure** — the components observe the actor signals. They never decide a state transition.
16
+ - **Signal-Only Reactivity** — the TC39 Signals are the source of truth. Vue reactivity only triggers the re-render.
17
+ - **Actor Authority** — the actor controls the view selection. The renderer reflects it.
20
18
 
21
19
  ---
22
20
 
@@ -26,7 +24,7 @@ Part of the [XMachines Play monorepo](../../README.md).
26
24
  pnpm add @xmachines/play-vue
27
25
  ```
28
26
 
29
- **Peer dependencies** (install alongside):
27
+ **Peer dependencies.** Install them with the package:
30
28
 
31
29
  ```bash
32
30
  pnpm add vue@^3.5.0 xstate@^5.31.0 @xstate/store@^3.17.0 @xmachines/json-render-vue@^0.20.0-xm.2 @xmachines/json-render-core@^0.20.0-xm.2 @xmachines/json-render-xstate@^0.20.0-xm.2
@@ -77,7 +75,7 @@ const registryResult = defineRegistry(myCatalog, {
77
75
 
78
76
  #### `<PlayUIProvider>`
79
77
 
80
- Batteries-included composite provider. Wraps `<ActorProvider>` and `JSONUIProvider` in one component. **Recommended for most apps.**
78
+ The composite provider. It wraps `<ActorProvider>` and `JSONUIProvider` in one component. **Use it in most applications.**
81
79
 
82
80
  | Prop | Type | Required | Description |
83
81
  | --------------------- | -------------------------- | -------- | ------------------------------------------- |
@@ -89,11 +87,11 @@ Batteries-included composite provider. Wraps `<ActorProvider>` and `JSONUIProvid
89
87
  | `validationFunctions` | `Record<string, Function>` | — | Custom validation functions |
90
88
  | `functions` | `Record<string, Function>` | — | Named functions for `$computed` expressions |
91
89
 
92
- **Slots:** `default` (rendered content), `fallback` (shown while actor view is `null`)
90
+ **Slots:** `default` (the rendered content), `fallback` (the content while the actor view is `null`)
93
91
 
94
92
  #### `<PlayRenderer>`
95
93
 
96
- Zero-prop leaf component. Reads the current `spec` and `registry` from the nearest `<ActorProvider>` or `<PlayUIProvider>` context and renders via `<Renderer>`. Must be placed inside one of those providers.
94
+ The leaf component without props. It reads the current `spec` and `registry` from the nearest `<ActorProvider>` or `<PlayUIProvider>` context, then renders them with `<Renderer>`. Put it inside one of those providers.
97
95
 
98
96
  ```vue
99
97
  <PlayUIProvider :actor="actor" :registryResult="registryResult">
@@ -103,7 +101,7 @@ Zero-prop leaf component. Reads the current `spec` and `registry` from the neare
103
101
 
104
102
  #### `<ActorProvider>`
105
103
 
106
- Low-level escape hatch for custom provider composition. Owns the full actor lifecycle signal subscription, per-view state store, handler resolution, and Vue context provision. Use `<PlayUIProvider>` unless you need fine-grained control.
104
+ The low-level provider for a custom provider composition. It owns the complete actor lifecycle: the signal subscription, the state store of each view, the handler resolution, and the Vue context. Use `<PlayUIProvider>` when you do not need this control.
107
105
 
108
106
  | Prop | Type | Required | Description |
109
107
  | ---------------- | -------------------------- | -------- | ------------------------------- |
@@ -118,33 +116,34 @@ Low-level escape hatch for custom provider composition. Owns the full actor life
118
116
 
119
117
  #### `defineRegistry(catalog, options)`
120
118
 
121
- Drop-in replacement for `defineRegistry` from `@xmachines/json-render-vue`. **Always import from `@xmachines/play-vue`** rather than `@xmachines/json-render-vue` when working with Vue SFCs — this wrapper automatically detects `.vue` SFCs in the `components` map and wraps them via `h()` so Vue composables (including `inject`-based ones) work correctly inside `<script setup>`.
119
+ This function is the drop-in replacement for `defineRegistry` from `@xmachines/json-render-vue`. **Always import it from `@xmachines/play-vue`** when you work with a Vue SFC, not from `@xmachines/json-render-vue`. The wrapper finds each `.vue` SFC in the `components` map, and wraps it with `h()`. A Vue composable, and also a composable that uses `inject`, then works correctly inside `<script setup>`.
122
120
 
123
121
  ```typescript
124
122
  import { defineRegistry } from "@xmachines/play-vue";
125
123
  // NOT: import { defineRegistry } from "@xmachines/json-render-vue"
126
124
 
125
+ import { myCatalog } from "./catalog.js"; // as in the Quick Start
127
126
  import LoginSFC from "./views/Login.vue";
128
127
  import DashboardSFC from "./views/Dashboard.vue";
129
128
 
130
- const registryResult = defineRegistry(catalog, {
129
+ const registryResult = defineRegistry(myCatalog, {
131
130
  components: {
132
131
  Login: LoginSFC, // .vue SFC — auto-wrapped via h()
133
132
  Dashboard: DashboardSFC,
134
133
  },
135
134
  actions: {
136
- login: async (args, setState, getState) => {
135
+ login: async (args, setState, state) => {
137
136
  /* ... */
138
137
  },
139
138
  },
140
139
  });
141
140
  ```
142
141
 
143
- Plain `ComponentFn` functions (non-SFC) also work and are passed through unchanged. Mixing SFCs and plain functions in the same registry is supported.
142
+ A plain `ComponentFn` function also works, and the wrapper passes it through without a change. One registry can hold both SFCs and plain functions.
144
143
 
145
144
  #### `useActor()`
146
145
 
147
- Vue composable for accessing the raw actor inside a `PlayRenderer` tree. Avoids prop drilling for deeply nested components.
146
+ The Vue composable that gives the raw actor inside a `PlayRenderer` tree. A deeply nested component then does not need the actor as a prop.
148
147
 
149
148
  ```typescript
150
149
  import { useActor } from "@xmachines/play-vue";
@@ -154,25 +153,27 @@ const actor = useActor();
154
153
  actor.send({ type: "SUBMIT" });
155
154
  ```
156
155
 
157
- Throws if called outside an `<ActorProvider>` or `<PlayUIProvider>` tree.
156
+ It throws when the caller is outside an `<ActorProvider>` or a `<PlayUIProvider>` tree.
158
157
 
159
- #### `getPlayViewContext()`
158
+ #### `usePlayView()`
160
159
 
161
160
  Access the current `ViewContextValue` — `{ spec, handlers, registry, store }` — from inside an `<ActorProvider>` tree.
162
161
 
163
162
  ```typescript
164
- import { getPlayViewContext } from "@xmachines/play-vue";
163
+ import { usePlayView } from "@xmachines/play-vue";
165
164
 
166
165
  // Inside setup() of a component within an ActorProvider tree:
167
- const view = getPlayViewContext();
166
+ const view = usePlayView();
168
167
  // view.spec, view.handlers, view.registry, view.store
169
168
  ```
170
169
 
170
+ > **Note:** `usePlayView` was previously named `getPlayViewContext`. The old name is still exported as a deprecated alias and will be removed in the next major.
171
+
171
172
  ---
172
173
 
173
174
  ### Re-exported from `@xmachines/json-render-vue`
174
175
 
175
- The following are re-exported so consumers import everything from `@xmachines/play-vue`:
176
+ This package re-exports the following, so that a consumer imports everything from `@xmachines/play-vue`:
176
177
 
177
178
  **Components:** `JSONUIProvider`, `StateProvider`, `ActionProvider`, `VisibilityProvider`, `ValidationProvider`, `Renderer`
178
179
 
@@ -197,7 +198,7 @@ pnpm --filter @xmachines/play-vue run test:watch
197
198
  pnpm exec vitest run --coverage --config packages/play-vue/vitest.config.ts
198
199
  ```
199
200
 
200
- Tests use [Vitest](https://vitest.dev/) with `jsdom` environment and `@vue/test-utils` for component mounting.
201
+ The tests use [Vitest](https://vitest.dev/) in a `jsdom` environment. They mount the components with `@vue/test-utils`.
201
202
 
202
203
  ---
203
204
 
@@ -1 +1 @@
1
- {"version":3,"file":"ActorProvider.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — escape-hatch primitive for the XMachines Vue render architecture.\n *\n * Owns the full actor lifecycle:\n * - Signal subscription (watchSignal) bridging TC39 Signals to Vue reactivity\n * - Per-view StateStore lifecycle (controlled/uncontrolled)\n * - Handler resolution via ActorProviderInner (must be inside StateProvider)\n * - ViewContextValue provision via ViewKey injection key\n * - ActionProvider + VisibilityProvider wrapping for downstream Renderer\n * - onRenderError injection into registry\n *\n * Library authors who need fine-grained control use this directly.\n * End users should use <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - Actor decides all state transitions via guards\n * @invariant Passive Infrastructure - Component observes signals, sends events\n * @invariant Signal-Only Reactivity - Business logic state lives in actor signals\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n} from \"vue\";\nimport type { PropType } from \"vue\";\nimport { watchSignal } from \"@xmachines/play-signals\";\nimport { attachRenderErrorHandler, createViewStoreLifecycle } from \"@xmachines/play-actor\";\nimport type { AbstractActor, Viewable, PlaySpec } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { createAtom } from \"@xstate/store\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export props type and context accessors for consumers who import from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { getPlayViewContext } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — renders inside StateProvider to call useStateStore()\n// Provides ViewContextValue + ActionProvider + VisibilityProvider for downstream Renderer.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Use shallowRef for the view context value to avoid deep reactivity overhead.\n\t\t// The Proxy below allows inject() to always read the latest value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Provide the ViewContextValue via Vue's inject/provide system.\n\t\t// Called synchronously in setup() so Vue registers it on the component instance.\n\t\t// Uses Proxy so descendants always receive the latest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() at setup() time (synchronous, before return).\n\t\t// Vue composables that use inject() must be called during setup(), not in a render function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter: handlers factory expects updater-function pattern.\n\t\t// Defined once in setup() — reads stateStore.getSnapshot/update at invocation\n\t\t// time so it always operates on the live store state without needing to be\n\t\t// recreated when stateStore identity changes across renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Memoize handlers keyed to registryResult prop identity. The getter functions\n\t\t// are stable closures capturing stateStore from setup(), so they do not\n\t\t// contribute to invalidation. Handlers are only recomputed when the registry\n\t\t// definition itself changes — not on every render triggered by view updates.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap with ActionProvider + VisibilityProvider so PlayRenderer's Renderer works\n\t\t\t// even when ActorProvider is used directly (without PlayUIProvider / JSONUIProvider)\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Unwrap actor from Vue's reactive proxy to access raw Signal objects.\n\t\t// Held in a shallowRef so the provided injection and the signal watcher\n\t\t// can follow `props.actor` when the prop swaps after mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable));\n\n\t\t// Unwrap the registryResult and mark components as raw to avoid Vue reactivity overhead\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level\n\t\t// handler). attachRenderErrorHandler clones — the caller's registry is never mutated.\n\t\t// The clone must be re-markRaw'd: markRaw's non-enumerable flag is not carried by the clone.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Provide the actor to all descendants via Vue's provide/inject mechanism.\n\t\t//\n\t\t// A stable Proxy (same pattern as ActorProviderInner's ViewKey proxy) is\n\t\t// provided instead of the raw actor so the injection tracks the CURRENT\n\t\t// `props.actor`: injectors keep the reference obtained at setup() time,\n\t\t// yet every trap resolves against the latest actor (actorRef.value) after a\n\t\t// prop swap. All relevant traps are forwarded so the proxy behaves like the\n\t\t// underlying actor for reads, writes, membership (`in`), enumeration\n\t\t// (Object.keys / spread), and prototype checks (`instanceof`). Methods are\n\t\t// bound to the current raw actor so `this` (including private fields) works\n\t\t// exactly as with a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor` — it is a\n\t\t// distinct object, hence a distinct WeakMap key. Identity-keyed consumers —\n\t\t// notably RouterBridgeBase's one-bridge-per-actor guard, which keys a\n\t\t// module-level WeakMap on actor identity — must be handed the `props.actor`\n\t\t// value itself, never this injected proxy.\n\t\t//\n\t\t// Method identity: bound methods are cached per underlying method so repeated\n\t\t// reads return the SAME function (actor.send === actor.send — allocation-free\n\t\t// hot path). A read rebinds only when the underlying method changes; the cache\n\t\t// is CLEARED on actor swap (see the watch handler below) so prototype methods\n\t\t// rebind to the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// Proxy invariant: the proxy target is an empty {}, so every key\n\t\t\t\t\t// reported via ownKeys must resolve to a configurable descriptor here\n\t\t\t\t\t// — otherwise the [[GetOwnProperty]] invariant throws (a non-existent\n\t\t\t\t\t// target property may not be reported as non-configurable). The actor's\n\t\t\t\t\t// own props are runtime-mutable anyway, so reporting configurable:true\n\t\t\t\t\t// is faithful enough for Object.keys / spread enumeration.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed initial value then subscribe — both synchronous, no scheduler gap.\n\t\t// This mirrors the atomic seed+watch pattern used in Solid (createEffect)\n\t\t// and Svelte ($effect) for cross-framework consistency.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// Store lifecycle (reseed on viewKey change, refresh /context in place\n\t\t// otherwise, actor-swap reset, guard identity cache) — the shared\n\t\t// coordinator from @xmachines/play-actor; only the reactivity wiring\n\t\t// below is Vue's.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is a SUBTREE REMOUNT key — it must bump only when the store is\n\t\t// actually reseeded, never on an in-place /context refresh, or every\n\t\t// projection update would wipe the rendered subtree.\n\t\t// (Controlled mode never reseeds, so it never bumps.)\n\t\tlet storeKey = 0;\n\n\t\t// Signal watcher for bridging TC39 Signals to Vue reactivity.\n\t\t// Re-assigned on actor swap so cleanup always releases the live watcher.\n\t\tlet unwatch = watchSignal(actorRef.value.currentView, (nextView) => {\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// React to `props.actor` swaps: unsubscribe the OLD actor's currentView,\n\t\t// re-seed the view from the NEW actor synchronously (flush: \"sync\" — no\n\t\t// scheduler gap, matching the mount-time seed+watch pattern above), and\n\t\t// subscribe the new signal. The re-seeded view is a new object identity,\n\t\t// so the internal-store branch below rebuilds the store and bumps\n\t\t// storeKey exactly like a regular view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on the actor swap — the kept\n\t\t\t\t// store must not outlive its actor.)\n\t\t\t\t// Invalidate cached bound methods so prototype methods rebind to the\n\t\t\t\t// new actor on the next read (see the injected proxy's get trap).\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchSignal(nextActor.currentView, (nextView) => {\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// No view — show fallback slot or nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store (external/controlled or internal per-viewKey) via\n\t\t\t// the shared lifecycle; children get the guarded store — /context is\n\t\t\t// read-only to the spec, and the machinery refreshes through the\n\t\t\t// unguarded reference inside the coordinator.\n\t\t\tconst resolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider so useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
1
+ {"version":3,"file":"ActorProvider.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the signal subscription (watchSignal), which connects the TC39 Signals to the Vue reactivity\n * - the StateStore lifecycle of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the signals, and it sends the events\n * @invariant Signal-Only Reactivity - the state of the business logic is in the actor signals\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n} from \"vue\";\nimport type { PropType } from \"vue\";\nimport { watchSignal } from \"@xmachines/play-signals\";\nimport { attachRenderErrorHandler, createViewStoreLifecycle } from \"@xmachines/play-actor\";\nimport type { AbstractActor, Viewable, PlaySpec } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { createAtom } from \"@xstate/store\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView, getPlayViewContext } from \"./actor-provider-context.js\"; // getPlayViewContext @deprecated\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter, because the factory of the handlers expects the pattern\n\t\t// of an updater function. The code defines it one time, in setup(). It reads\n\t\t// stateStore.getSnapshot and stateStore.update at the moment of the call. Therefore\n\t\t// it always works on the live state of the store, and it needs no new definition when\n\t\t// the identity of stateStore changes between two renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. The\n\t\t// getter functions are stable closures, and they hold the stateStore of setup().\n\t\t// Therefore they cause no new computation. The code computes the handlers again only\n\t\t// after a change of the definition of the registry, and not on each render of a view\n\t\t// update.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Take the actor out of the reactive proxy of Vue, to reach the raw Signal objects.\n\t\t// A shallowRef holds the actor. Therefore the injected value and the signal watcher\n\t\t// can follow `props.actor` when the prop changes after the mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable));\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because the reactivity of Vue costs too much here\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Put the onRenderError prop into the registry. The property is not enumerable, and\n\t\t// it replaces the handler of the defineRegistry level. attachRenderErrorHandler makes\n\t\t// a copy, and it changes the registry of the caller never.\n\t\t// The code must call markRaw on the copy again, because a copy does not carry the\n\t\t// non-enumerable flag of markRaw.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable Proxy, and not the raw actor. The pattern is the same as\n\t\t// the ViewKey proxy of ActorProviderInner. The injected value therefore follows the\n\t\t// CURRENT `props.actor`: each injector keeps the reference of the setup(), and every\n\t\t// trap resolves against the newest actor (actorRef.value) after a change of the prop.\n\t\t// The proxy forwards each relevant trap. Therefore it behaves like the actor below it\n\t\t// for a read, for a write, for a membership test (`in`), for an enumeration\n\t\t// (Object.keys and a spread), and for a prototype test (`instanceof`). Each method\n\t\t// binds to the current raw actor. Therefore `this`, and also each private field,\n\t\t// works exactly as in a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor`, because it is a\n\t\t// separate object, and therefore a separate key of a WeakMap. A consumer that uses\n\t\t// the identity as its key must receive the `props.actor` value itself, and never this\n\t\t// injected proxy. The most important such consumer is the guard of one bridge for\n\t\t// each actor in RouterBridgeBase: it uses the identity of the actor as the key of a\n\t\t// WeakMap at the module level.\n\t\t//\n\t\t// The identity of a method: the code keeps each bound method, with the method below\n\t\t// it as the key. A repeated read therefore returns the SAME function\n\t\t// (actor.send === actor.send), and the hot path allocates nothing. A read binds the\n\t\t// method again only after a change of the method below it. The watch handler below\n\t\t// CLEARS the cache on a change of the actor. Therefore each prototype method binds to\n\t\t// the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// An invariant of a Proxy: the target of this proxy is an empty {}. Therefore each\n\t\t\t\t\t// key of ownKeys must resolve to a configurable descriptor here. Without that, the\n\t\t\t\t\t// [[GetOwnProperty]] invariant throws, because a proxy must not report a property that\n\t\t\t\t\t// its target has not as non-configurable. The own props of the actor are mutable at\n\t\t\t\t\t// run time in each case. Therefore `configurable: true` is correct enough for the\n\t\t\t\t\t// enumeration of Object.keys and of a spread.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed the first value, then subscribe. Both steps are synchronous, and no scheduler\n\t\t// runs between them.\n\t\t// Solid does the same with createEffect, and Svelte does the same with $effect.\n\t\t// The pattern is therefore the same in each framework.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// The store lifecycle: it seeds the store again on a change of the viewKey, it\n\t\t// refreshes /context in place in every other case, it resets the store on a change of\n\t\t// the actor, and it guards the identity cache. The shared coordinator comes from\n\t\t// @xmachines/play-actor. Only the wiring of the reactivity below belongs to Vue.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is the key of a SUBTREE REMOUNT. Therefore it must change only after a\n\t\t// new seed of the store, and never after a refresh of /context in place. Without this\n\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t// (The controlled mode seeds the store never again. Therefore the key changes never\n\t\t// there.)\n\t\tlet storeKey = 0;\n\n\t\t// The signal watcher connects the TC39 Signals to the reactivity of Vue.\n\t\t// The code assigns it again on a change of the actor. Therefore the cleanup always\n\t\t// releases the live watcher.\n\t\tlet unwatch = watchSignal(actorRef.value.currentView, (nextView) => {\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// React to a change of `props.actor`: cancel the subscription to the currentView of\n\t\t// the OLD actor, seed the view from the NEW actor synchronously (`flush: \"sync\"`, so\n\t\t// that no scheduler runs between the steps, as in the seed and watch pattern of the\n\t\t// mount above), and subscribe to the new signal. The view of the new seed has a new\n\t\t// identity. Therefore the branch of the internal store below builds the store again,\n\t\t// and it changes storeKey, exactly like a normal view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on a change of the actor, because a store that\n\t\t\t\t// stays alive must not outlive its actor.)\n\t\t\t\t// Clear the cache of the bound methods. Each prototype method therefore binds to the\n\t\t\t\t// new actor on the next read. See the get trap of the injected proxy.\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchSignal(nextActor.currentView, (nextView) => {\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// No view: show the fallback slot, or show nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store, which is external and controlled, or internal for each\n\t\t\t// viewKey, through the shared lifecycle. The children receive the store with the\n\t\t\t// guard, because /context is read-only to the spec. The machinery refreshes the\n\t\t\t// store through the reference without a guard, inside the coordinator.\n\t\t\tconst resolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
@@ -8,22 +8,22 @@ import { createAtom } from "@xstate/store";
8
8
  import { xstateStoreStateStore } from "@xmachines/json-render-xstate";
9
9
  //#region packages/play-vue/src/ActorProvider.vue?vue&type=script&lang.ts
10
10
  /**
11
- * ActorProvider — escape-hatch primitive for the XMachines Vue render architecture.
11
+ * ActorProvider — the low-level provider of the XMachines Vue render architecture.
12
12
  *
13
- * Owns the full actor lifecycle:
14
- * - Signal subscription (watchSignal) bridging TC39 Signals to Vue reactivity
15
- * - Per-view StateStore lifecycle (controlled/uncontrolled)
16
- * - Handler resolution via ActorProviderInner (must be inside StateProvider)
17
- * - ViewContextValue provision via ViewKey injection key
18
- * - ActionProvider + VisibilityProvider wrapping for downstream Renderer
19
- * - onRenderError injection into registry
13
+ * It owns the complete actor lifecycle:
14
+ * - the signal subscription (watchSignal), which connects the TC39 Signals to the Vue reactivity
15
+ * - the StateStore lifecycle of each view, controlled and uncontrolled
16
+ * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider
17
+ * - the ViewContextValue, which it provides through the ViewKey injection key
18
+ * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below
19
+ * - the injection of onRenderError into the registry
20
20
  *
21
- * Library authors who need fine-grained control use this directly.
22
- * End users should use <PlayUIProvider> instead.
21
+ * The author of a library who needs this control uses the component directly.
22
+ * An end user takes <PlayUIProvider> instead.
23
23
  *
24
- * @invariant Actor Authority - Actor decides all state transitions via guards
25
- * @invariant Passive Infrastructure - Component observes signals, sends events
26
- * @invariant Signal-Only Reactivity - Business logic state lives in actor signals
24
+ * @invariant Actor Authority - the Actor decides each state transition, with its guards
25
+ * @invariant Passive Infrastructure - the component observes the signals, and it sends the events
26
+ * @invariant Signal-Only Reactivity - the state of the business logic is in the actor signals
27
27
  */
28
28
  var ActorProviderInner = defineComponent({
29
29
  name: "ActorProviderInner",
@@ -1 +1 @@
1
- {"version":3,"file":"ActorProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — escape-hatch primitive for the XMachines Vue render architecture.\n *\n * Owns the full actor lifecycle:\n * - Signal subscription (watchSignal) bridging TC39 Signals to Vue reactivity\n * - Per-view StateStore lifecycle (controlled/uncontrolled)\n * - Handler resolution via ActorProviderInner (must be inside StateProvider)\n * - ViewContextValue provision via ViewKey injection key\n * - ActionProvider + VisibilityProvider wrapping for downstream Renderer\n * - onRenderError injection into registry\n *\n * Library authors who need fine-grained control use this directly.\n * End users should use <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - Actor decides all state transitions via guards\n * @invariant Passive Infrastructure - Component observes signals, sends events\n * @invariant Signal-Only Reactivity - Business logic state lives in actor signals\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n} from \"vue\";\nimport type { PropType } from \"vue\";\nimport { watchSignal } from \"@xmachines/play-signals\";\nimport { attachRenderErrorHandler, createViewStoreLifecycle } from \"@xmachines/play-actor\";\nimport type { AbstractActor, Viewable, PlaySpec } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { createAtom } from \"@xstate/store\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export props type and context accessors for consumers who import from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { getPlayViewContext } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — renders inside StateProvider to call useStateStore()\n// Provides ViewContextValue + ActionProvider + VisibilityProvider for downstream Renderer.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Use shallowRef for the view context value to avoid deep reactivity overhead.\n\t\t// The Proxy below allows inject() to always read the latest value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Provide the ViewContextValue via Vue's inject/provide system.\n\t\t// Called synchronously in setup() so Vue registers it on the component instance.\n\t\t// Uses Proxy so descendants always receive the latest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() at setup() time (synchronous, before return).\n\t\t// Vue composables that use inject() must be called during setup(), not in a render function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter: handlers factory expects updater-function pattern.\n\t\t// Defined once in setup() — reads stateStore.getSnapshot/update at invocation\n\t\t// time so it always operates on the live store state without needing to be\n\t\t// recreated when stateStore identity changes across renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Memoize handlers keyed to registryResult prop identity. The getter functions\n\t\t// are stable closures capturing stateStore from setup(), so they do not\n\t\t// contribute to invalidation. Handlers are only recomputed when the registry\n\t\t// definition itself changes — not on every render triggered by view updates.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap with ActionProvider + VisibilityProvider so PlayRenderer's Renderer works\n\t\t\t// even when ActorProvider is used directly (without PlayUIProvider / JSONUIProvider)\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Unwrap actor from Vue's reactive proxy to access raw Signal objects.\n\t\t// Held in a shallowRef so the provided injection and the signal watcher\n\t\t// can follow `props.actor` when the prop swaps after mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable));\n\n\t\t// Unwrap the registryResult and mark components as raw to avoid Vue reactivity overhead\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level\n\t\t// handler). attachRenderErrorHandler clones — the caller's registry is never mutated.\n\t\t// The clone must be re-markRaw'd: markRaw's non-enumerable flag is not carried by the clone.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Provide the actor to all descendants via Vue's provide/inject mechanism.\n\t\t//\n\t\t// A stable Proxy (same pattern as ActorProviderInner's ViewKey proxy) is\n\t\t// provided instead of the raw actor so the injection tracks the CURRENT\n\t\t// `props.actor`: injectors keep the reference obtained at setup() time,\n\t\t// yet every trap resolves against the latest actor (actorRef.value) after a\n\t\t// prop swap. All relevant traps are forwarded so the proxy behaves like the\n\t\t// underlying actor for reads, writes, membership (`in`), enumeration\n\t\t// (Object.keys / spread), and prototype checks (`instanceof`). Methods are\n\t\t// bound to the current raw actor so `this` (including private fields) works\n\t\t// exactly as with a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor` — it is a\n\t\t// distinct object, hence a distinct WeakMap key. Identity-keyed consumers —\n\t\t// notably RouterBridgeBase's one-bridge-per-actor guard, which keys a\n\t\t// module-level WeakMap on actor identity — must be handed the `props.actor`\n\t\t// value itself, never this injected proxy.\n\t\t//\n\t\t// Method identity: bound methods are cached per underlying method so repeated\n\t\t// reads return the SAME function (actor.send === actor.send — allocation-free\n\t\t// hot path). A read rebinds only when the underlying method changes; the cache\n\t\t// is CLEARED on actor swap (see the watch handler below) so prototype methods\n\t\t// rebind to the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// Proxy invariant: the proxy target is an empty {}, so every key\n\t\t\t\t\t// reported via ownKeys must resolve to a configurable descriptor here\n\t\t\t\t\t// — otherwise the [[GetOwnProperty]] invariant throws (a non-existent\n\t\t\t\t\t// target property may not be reported as non-configurable). The actor's\n\t\t\t\t\t// own props are runtime-mutable anyway, so reporting configurable:true\n\t\t\t\t\t// is faithful enough for Object.keys / spread enumeration.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed initial value then subscribe — both synchronous, no scheduler gap.\n\t\t// This mirrors the atomic seed+watch pattern used in Solid (createEffect)\n\t\t// and Svelte ($effect) for cross-framework consistency.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// Store lifecycle (reseed on viewKey change, refresh /context in place\n\t\t// otherwise, actor-swap reset, guard identity cache) — the shared\n\t\t// coordinator from @xmachines/play-actor; only the reactivity wiring\n\t\t// below is Vue's.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is a SUBTREE REMOUNT key — it must bump only when the store is\n\t\t// actually reseeded, never on an in-place /context refresh, or every\n\t\t// projection update would wipe the rendered subtree.\n\t\t// (Controlled mode never reseeds, so it never bumps.)\n\t\tlet storeKey = 0;\n\n\t\t// Signal watcher for bridging TC39 Signals to Vue reactivity.\n\t\t// Re-assigned on actor swap so cleanup always releases the live watcher.\n\t\tlet unwatch = watchSignal(actorRef.value.currentView, (nextView) => {\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// React to `props.actor` swaps: unsubscribe the OLD actor's currentView,\n\t\t// re-seed the view from the NEW actor synchronously (flush: \"sync\" — no\n\t\t// scheduler gap, matching the mount-time seed+watch pattern above), and\n\t\t// subscribe the new signal. The re-seeded view is a new object identity,\n\t\t// so the internal-store branch below rebuilds the store and bumps\n\t\t// storeKey exactly like a regular view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on the actor swap — the kept\n\t\t\t\t// store must not outlive its actor.)\n\t\t\t\t// Invalidate cached bound methods so prototype methods rebind to the\n\t\t\t\t// new actor on the next read (see the injected proxy's get trap).\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchSignal(nextActor.currentView, (nextView) => {\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// No view — show fallback slot or nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store (external/controlled or internal per-viewKey) via\n\t\t\t// the shared lifecycle; children get the guarded store — /context is\n\t\t\t// read-only to the spec, and the machinery refreshes through the\n\t\t\t// unguarded reference inside the coordinator.\n\t\t\tconst resolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider so useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"ActorProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the signal subscription (watchSignal), which connects the TC39 Signals to the Vue reactivity\n * - the StateStore lifecycle of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the signals, and it sends the events\n * @invariant Signal-Only Reactivity - the state of the business logic is in the actor signals\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n} from \"vue\";\nimport type { PropType } from \"vue\";\nimport { watchSignal } from \"@xmachines/play-signals\";\nimport { attachRenderErrorHandler, createViewStoreLifecycle } from \"@xmachines/play-actor\";\nimport type { AbstractActor, Viewable, PlaySpec } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { createAtom } from \"@xstate/store\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView, getPlayViewContext } from \"./actor-provider-context.js\"; // getPlayViewContext @deprecated\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter, because the factory of the handlers expects the pattern\n\t\t// of an updater function. The code defines it one time, in setup(). It reads\n\t\t// stateStore.getSnapshot and stateStore.update at the moment of the call. Therefore\n\t\t// it always works on the live state of the store, and it needs no new definition when\n\t\t// the identity of stateStore changes between two renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. The\n\t\t// getter functions are stable closures, and they hold the stateStore of setup().\n\t\t// Therefore they cause no new computation. The code computes the handlers again only\n\t\t// after a change of the definition of the registry, and not on each render of a view\n\t\t// update.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// Take the actor out of the reactive proxy of Vue, to reach the raw Signal objects.\n\t\t// A shallowRef holds the actor. Therefore the injected value and the signal watcher\n\t\t// can follow `props.actor` when the prop changes after the mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable));\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because the reactivity of Vue costs too much here\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Put the onRenderError prop into the registry. The property is not enumerable, and\n\t\t// it replaces the handler of the defineRegistry level. attachRenderErrorHandler makes\n\t\t// a copy, and it changes the registry of the caller never.\n\t\t// The code must call markRaw on the copy again, because a copy does not carry the\n\t\t// non-enumerable flag of markRaw.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable Proxy, and not the raw actor. The pattern is the same as\n\t\t// the ViewKey proxy of ActorProviderInner. The injected value therefore follows the\n\t\t// CURRENT `props.actor`: each injector keeps the reference of the setup(), and every\n\t\t// trap resolves against the newest actor (actorRef.value) after a change of the prop.\n\t\t// The proxy forwards each relevant trap. Therefore it behaves like the actor below it\n\t\t// for a read, for a write, for a membership test (`in`), for an enumeration\n\t\t// (Object.keys and a spread), and for a prototype test (`instanceof`). Each method\n\t\t// binds to the current raw actor. Therefore `this`, and also each private field,\n\t\t// works exactly as in a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor`, because it is a\n\t\t// separate object, and therefore a separate key of a WeakMap. A consumer that uses\n\t\t// the identity as its key must receive the `props.actor` value itself, and never this\n\t\t// injected proxy. The most important such consumer is the guard of one bridge for\n\t\t// each actor in RouterBridgeBase: it uses the identity of the actor as the key of a\n\t\t// WeakMap at the module level.\n\t\t//\n\t\t// The identity of a method: the code keeps each bound method, with the method below\n\t\t// it as the key. A repeated read therefore returns the SAME function\n\t\t// (actor.send === actor.send), and the hot path allocates nothing. A read binds the\n\t\t// method again only after a change of the method below it. The watch handler below\n\t\t// CLEARS the cache on a change of the actor. Therefore each prototype method binds to\n\t\t// the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// An invariant of a Proxy: the target of this proxy is an empty {}. Therefore each\n\t\t\t\t\t// key of ownKeys must resolve to a configurable descriptor here. Without that, the\n\t\t\t\t\t// [[GetOwnProperty]] invariant throws, because a proxy must not report a property that\n\t\t\t\t\t// its target has not as non-configurable. The own props of the actor are mutable at\n\t\t\t\t\t// run time in each case. Therefore `configurable: true` is correct enough for the\n\t\t\t\t\t// enumeration of Object.keys and of a spread.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed the first value, then subscribe. Both steps are synchronous, and no scheduler\n\t\t// runs between them.\n\t\t// Solid does the same with createEffect, and Svelte does the same with $effect.\n\t\t// The pattern is therefore the same in each framework.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// The store lifecycle: it seeds the store again on a change of the viewKey, it\n\t\t// refreshes /context in place in every other case, it resets the store on a change of\n\t\t// the actor, and it guards the identity cache. The shared coordinator comes from\n\t\t// @xmachines/play-actor. Only the wiring of the reactivity below belongs to Vue.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is the key of a SUBTREE REMOUNT. Therefore it must change only after a\n\t\t// new seed of the store, and never after a refresh of /context in place. Without this\n\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t// (The controlled mode seeds the store never again. Therefore the key changes never\n\t\t// there.)\n\t\tlet storeKey = 0;\n\n\t\t// The signal watcher connects the TC39 Signals to the reactivity of Vue.\n\t\t// The code assigns it again on a change of the actor. Therefore the cleanup always\n\t\t// releases the live watcher.\n\t\tlet unwatch = watchSignal(actorRef.value.currentView, (nextView) => {\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// React to a change of `props.actor`: cancel the subscription to the currentView of\n\t\t// the OLD actor, seed the view from the NEW actor synchronously (`flush: \"sync\"`, so\n\t\t// that no scheduler runs between the steps, as in the seed and watch pattern of the\n\t\t// mount above), and subscribe to the new signal. The view of the new seed has a new\n\t\t// identity. Therefore the branch of the internal store below builds the store again,\n\t\t// and it changes storeKey, exactly like a normal view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as AbstractActor<AnyActorLogic> & Viewable),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on a change of the actor, because a store that\n\t\t\t\t// stays alive must not outlive its actor.)\n\t\t\t\t// Clear the cache of the bound methods. Each prototype method therefore binds to the\n\t\t\t\t// new actor on the next read. See the get trap of the injected proxy.\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchSignal(nextActor.currentView, (nextView) => {\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// No view: show the fallback slot, or show nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store, which is external and controlled, or internal for each\n\t\t\t// viewKey, through the shared lifecycle. The children receive the store with the\n\t\t\t// guard, because /context is read-only to the spec. The machinery refreshes the\n\t\t\t// store through the reference without a guard, inside the coordinator.\n\t\t\tconst resolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.js","names":[],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — zero-prop leaf component for the XMachines Vue render architecture.\n *\n * Reads the current view context from the nearest ActorProvider (or PlayUIProvider)\n * and renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Must be used inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - Component observes context, never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { getPlayViewContext } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject at setup() time valid Vue composition API.\n\t\t// getPlayViewContext() uses inject() which must run synchronously during setup().\n\t\t// The Proxy returned by ActorProviderInner ensures view.spec and view.registry\n\t\t// always reflect the latest values when accessed during the render function.\n\t\tconst view = getPlayViewContext();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
1
+ {"version":3,"file":"PlayRenderer.js","names":[],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — the leaf component without props of the XMachines Vue render architecture.\n *\n * It reads the current view context of the nearest ActorProvider, or of the nearest\n * PlayUIProvider. It then renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Use it inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - the component observes the context. It never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject during setup(), which the composition API of Vue permits.\n\t\t// usePlayView() uses inject(), and inject() must run synchronously during\n\t\t// setup(). The Proxy of ActorProviderInner gives view.spec and view.registry their\n\t\t// newest values on each read in the render function.\n\t\tconst view = usePlayView();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
@@ -1,14 +1,14 @@
1
- import { getPlayViewContext } from "./actor-provider-context.js";
1
+ import { usePlayView } from "./actor-provider-context.js";
2
2
  import { defineComponent, h } from "vue";
3
3
  import { Renderer } from "@xmachines/json-render-vue";
4
4
  //#region packages/play-vue/src/PlayRenderer.vue?vue&type=script&lang.ts
5
5
  /**
6
- * PlayRenderer — zero-prop leaf component for the XMachines Vue render architecture.
6
+ * PlayRenderer — the leaf component without props of the XMachines Vue render architecture.
7
7
  *
8
- * Reads the current view context from the nearest ActorProvider (or PlayUIProvider)
9
- * and renders <Renderer spec={view.spec} registry={view.registry} />.
8
+ * It reads the current view context of the nearest ActorProvider, or of the nearest
9
+ * PlayUIProvider. It then renders <Renderer spec={view.spec} registry={view.registry} />.
10
10
  *
11
- * Must be used inside <ActorProvider> or <PlayUIProvider>.
11
+ * Use it inside <ActorProvider> or <PlayUIProvider>.
12
12
  *
13
13
  * @example
14
14
  * ```ts
@@ -17,12 +17,12 @@ import { Renderer } from "@xmachines/json-render-vue";
17
17
  * </PlayUIProvider>
18
18
  * ```
19
19
  *
20
- * @invariant Passive Infrastructure - Component observes context, never decides
20
+ * @invariant Passive Infrastructure - the component observes the context. It never decides
21
21
  */
22
22
  var PlayRenderer_vue_vue_type_script_lang_default = defineComponent({
23
23
  name: "PlayRenderer",
24
24
  setup() {
25
- const view = getPlayViewContext();
25
+ const view = usePlayView();
26
26
  return () => {
27
27
  return h(Renderer, {
28
28
  spec: view.spec,
@@ -1 +1 @@
1
- {"version":3,"file":"PlayRenderer.vue_vue_type_script_lang.js","names":[],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — zero-prop leaf component for the XMachines Vue render architecture.\n *\n * Reads the current view context from the nearest ActorProvider (or PlayUIProvider)\n * and renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Must be used inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - Component observes context, never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { getPlayViewContext } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject at setup() time valid Vue composition API.\n\t\t// getPlayViewContext() uses inject() which must run synchronously during setup().\n\t\t// The Proxy returned by ActorProviderInner ensures view.spec and view.registry\n\t\t// always reflect the latest values when accessed during the render function.\n\t\tconst view = getPlayViewContext();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,IAAA,gDAAe,gBAAgB;CAC9B,MAAM;CACN,QAAQ;EAKP,MAAM,OAAO,mBAAmB;EAChC,aAAa;GACZ,OAAO,EAAE,UAAU;IAAE,MAAM,KAAK;IAAM,UAAU,KAAK;GAAS,CAAC;EAChE;CACD;AACD,CAAC"}
1
+ {"version":3,"file":"PlayRenderer.vue_vue_type_script_lang.js","names":[],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — the leaf component without props of the XMachines Vue render architecture.\n *\n * It reads the current view context of the nearest ActorProvider, or of the nearest\n * PlayUIProvider. It then renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Use it inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - the component observes the context. It never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject during setup(), which the composition API of Vue permits.\n\t\t// usePlayView() uses inject(), and inject() must run synchronously during\n\t\t// setup(). The Proxy of ActorProviderInner gives view.spec and view.registry their\n\t\t// newest values on each read in the render function.\n\t\tconst view = usePlayView();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,IAAA,gDAAe,gBAAgB;CAC9B,MAAM;CACN,QAAQ;EAKP,MAAM,OAAO,YAAY;EACzB,aAAa;GACZ,OAAO,EAAE,UAAU;IAAE,MAAM,KAAK;IAAM,UAAU,KAAK;GAAS,CAAC;EAChE;CACD;AACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlayUIProvider.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — batteries-included composite provider for actor-driven UI rendering.\n *\n * Wraps ActorProvider + JSONUIProvider (from @xmachines/json-render-vue) to provide a single\n * entry point for all actor lifecycle and UI rendering concerns.\n *\n * Standard usage:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For custom provider composition (escape hatch), use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, RenderErrorHandler } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { AbstractActor, Viewable } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { getPlayViewContext } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export props type for consumers who import from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — inner component inside ActorProvider's tree\n// Reads ViewContextValue via getPlayViewContext() and passes handlers + registry\n// to JSONUIProvider so both ActorProvider and JSONUIProvider share the same state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = getPlayViewContext();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<AbstractActor<AnyActorLogic> & Viewable>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":""}
1
+ {"version":3,"file":"PlayUIProvider.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, RenderErrorHandler } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { AbstractActor, Viewable } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export the props type, for a consumer that imports from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — the inner component inside the tree of ActorProvider\n// It reads the ViewContextValue with usePlayView(), and it gives the handlers\n// and the registry to JSONUIProvider. Therefore ActorProvider and JSONUIProvider\n// share one state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = usePlayView();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<AbstractActor<AnyActorLogic> & Viewable>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":""}
@@ -1,22 +1,23 @@
1
- import { getPlayViewContext } from "./actor-provider-context.js";
1
+ import { usePlayView } from "./actor-provider-context.js";
2
2
  import ActorProvider_default from "./ActorProvider.js";
3
3
  import { defineComponent, h } from "vue";
4
4
  import { JSONUIProvider } from "@xmachines/json-render-vue";
5
5
  //#region packages/play-vue/src/PlayUIProvider.vue?vue&type=script&lang.ts
6
6
  /**
7
- * PlayUIProvider — batteries-included composite provider for actor-driven UI rendering.
7
+ * PlayUIProvider — the composite provider of an actor-driven UI.
8
8
  *
9
- * Wraps ActorProvider + JSONUIProvider (from @xmachines/json-render-vue) to provide a single
10
- * entry point for all actor lifecycle and UI rendering concerns.
9
+ * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One
10
+ * component therefore serves the complete actor lifecycle and the complete UI
11
+ * rendering.
11
12
  *
12
- * Standard usage:
13
+ * The standard use:
13
14
  * ```ts
14
15
  * <PlayUIProvider :actor="actor" :registryResult="registryResult">
15
16
  * <PlayRenderer />
16
17
  * </PlayUIProvider>
17
18
  * ```
18
19
  *
19
- * For custom provider composition (escape hatch), use <ActorProvider> directly.
20
+ * For a custom provider composition, use <ActorProvider> directly.
20
21
  *
21
22
  * @packageDocumentation
22
23
  */
@@ -38,7 +39,7 @@ var JSONUIBridge = defineComponent({
38
39
  },
39
40
  setup(props, { slots }) {
40
41
  return () => {
41
- const view = getPlayViewContext();
42
+ const view = usePlayView();
42
43
  return h(JSONUIProvider, {
43
44
  registry: view.registry,
44
45
  handlers: view.handlers,
@@ -1 +1 @@
1
- {"version":3,"file":"PlayUIProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — batteries-included composite provider for actor-driven UI rendering.\n *\n * Wraps ActorProvider + JSONUIProvider (from @xmachines/json-render-vue) to provide a single\n * entry point for all actor lifecycle and UI rendering concerns.\n *\n * Standard usage:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For custom provider composition (escape hatch), use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, RenderErrorHandler } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { AbstractActor, Viewable } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { getPlayViewContext } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export props type for consumers who import from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — inner component inside ActorProvider's tree\n// Reads ViewContextValue via getPlayViewContext() and passes handlers + registry\n// to JSONUIProvider so both ActorProvider and JSONUIProvider share the same state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = getPlayViewContext();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<AbstractActor<AnyActorLogic> & Viewable>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwCA,IAAM,eAAe,gBAAgB;CACpC,MAAM;CACN,OAAO;EACN,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GAGN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GAMN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aAAa;GACZ,MAAM,OAAO,mBAAmB;GAChC,OAAO,EACN,gBACA;IACC,UAAU,KAAK;IACf,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;EACD;CACD;AACD,CAAC;AAMD,IAAA,kDAAe,gBAAgB;CAC9B,MAAM;CACN,OAAO;EACN,OAAO;GACN,MAAM;GACN,UAAU;EACX;EACA,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,OAAO;GACN,MAAM;GACN,SAAS,KAAA;EACV;EACA,eAAe;GACd,MAAM;GACN,SAAS,KAAA;EACV;EACA,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GACN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GACN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aACC,EACC,uBACA;GACC,OAAO,MAAM;GACb,gBAAgB,MAAM;GACtB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;GAC5C,GAAI,MAAM,gBAAgB,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;EACrE,GACA;GACC,eACC,EACC,cACA;IACC,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;GACD,UAAU,MAAM;EACjB,CACD;CACF;AACD,CAAC"}
1
+ {"version":3,"file":"PlayUIProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, RenderErrorHandler } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { AbstractActor, Viewable } from \"@xmachines/play-actor\";\nimport type { AnyActorLogic } from \"xstate\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export the props type, for a consumer that imports from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — the inner component inside the tree of ActorProvider\n// It reads the ViewContextValue with usePlayView(), and it gives the handlers\n// and the registry to JSONUIProvider. Therefore ActorProvider and JSONUIProvider\n// share one state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = usePlayView();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<AbstractActor<AnyActorLogic> & Viewable>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAM,eAAe,gBAAgB;CACpC,MAAM;CACN,OAAO;EACN,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GAGN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GAMN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aAAa;GACZ,MAAM,OAAO,YAAY;GACzB,OAAO,EACN,gBACA;IACC,UAAU,KAAK;IACf,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;EACD;CACD;AACD,CAAC;AAMD,IAAA,kDAAe,gBAAgB;CAC9B,MAAM;CACN,OAAO;EACN,OAAO;GACN,MAAM;GACN,UAAU;EACX;EACA,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,OAAO;GACN,MAAM;GACN,SAAS,KAAA;EACV;EACA,eAAe;GACd,MAAM;GACN,SAAS,KAAA;EACV;EACA,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GACN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GACN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aACC,EACC,uBACA;GACC,OAAO,MAAM;GACb,gBAAgB,MAAM;GACtB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;GAC5C,GAAI,MAAM,gBAAgB,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;EACrE,GACA;GACC,eACC,EACC,cACA;IACC,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;GACD,UAAU,MAAM;EACjB,CACD;CACF;AACD,CAAC"}
@@ -1,9 +1,10 @@
1
1
  /**
2
- * ViewContextValue and getPlayViewContext — shared context types for Vue provider architecture.
2
+ * ViewContextValue and usePlayViewthe shared context types of the Vue provider architecture.
3
3
  *
4
- * Extracted from ActorProvider.vue so TypeScript can re-export these types from index.ts.
5
- * (The vue-shim.d.ts only declares a default export from *.vue files, so named exports
6
- * from .vue SFCs are not visible to TypeScript's re-export resolution.)
4
+ * This file holds them, and not ActorProvider.vue, so that TypeScript can
5
+ * re-export the types from index.ts. (The file vue-shim.d.ts declares a default
6
+ * export of each *.vue file only. Therefore TypeScript does not see a named export
7
+ * of a .vue SFC when it resolves a re-export.)
7
8
  *
8
9
  * @packageDocumentation
9
10
  */
@@ -11,30 +12,37 @@ import type { InjectionKey } from "vue";
11
12
  import type { ComponentRegistry } from "@xmachines/json-render-vue";
12
13
  import type { BaseViewContextValue } from "@xmachines/play-actor";
13
14
  /**
14
- * Context value provided by ActorProvider and consumed by PlayRenderer (zero-prop leaf).
15
- * Accessible via getPlayViewContext() inside any ActorProvider/PlayUIProvider tree.
15
+ * The context value that ActorProvider provides and PlayRenderer, the leaf without
16
+ * props, reads. usePlayView() gives it inside every ActorProvider tree and
17
+ * PlayUIProvider tree.
16
18
  */
17
19
  export interface ViewContextValue extends BaseViewContextValue<ComponentRegistry> {
18
20
  }
19
21
  /**
20
- * Injection key for the ViewContextValue. Exported so ActorProvider.vue can use it
21
- * as the canonical key without re-declaring.
22
+ * The injection key of the ViewContextValue. This file exports it, so that
23
+ * ActorProvider.vue uses it as the canonical key and declares no second key.
22
24
  *
23
- * @internal Use getPlayViewContext() as the public API; do not inject ViewKey directly.
25
+ * @internal Use usePlayView() as the public API. Never inject ViewKey directly.
24
26
  */
25
27
  export declare const ViewKey: InjectionKey<ViewContextValue>;
26
28
  /**
27
- * Access the current ViewContextValue from inside an ActorProvider tree.
29
+ * Returns the current ViewContextValue inside an ActorProvider tree.
28
30
  *
29
- * @throws {Error} If called outside an <ActorProvider> (or <PlayUIProvider>) tree
31
+ * @throws {Error} When the caller is outside an <ActorProvider> tree or a <PlayUIProvider> tree
30
32
  *
31
33
  * @example
32
34
  * ```typescript
33
- * import { getPlayViewContext } from "@xmachines/play-vue";
35
+ * import { usePlayView } from "@xmachines/play-vue";
34
36
  *
35
- * const view = getPlayViewContext();
37
+ * const view = usePlayView();
36
38
  * // view.spec, view.handlers, view.registry
37
39
  * ```
38
40
  */
39
- export declare function getPlayViewContext(): ViewContextValue;
41
+ export declare function usePlayView(): ViewContextValue;
42
+ /**
43
+ * Access the current ViewContextValue from inside an ActorProvider tree.
44
+ *
45
+ * @deprecated Renamed to {@link usePlayView}; will be removed in the next major.
46
+ */
47
+ export declare const getPlayViewContext: typeof usePlayView;
40
48
  //# sourceMappingURL=actor-provider-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actor-provider-context.d.ts","sourceRoot":"","sources":["../src/actor-provider-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;CAAG;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAA4B,CAAC;AAEhF;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,IAAI,gBAAgB,CAErD"}
1
+ {"version":3,"file":"actor-provider-context.d.ts","sourceRoot":"","sources":["../src/actor-provider-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;CAAG;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAA4B,CAAC;AAEhF;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,oBAAc,CAAC"}