@xmachines/docs 1.0.0-beta.16 → 1.0.0-beta.18

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.
Files changed (186) hide show
  1. package/api/@xmachines/play/README.md +56 -17
  2. package/api/@xmachines/play/classes/PlayError.md +240 -0
  3. package/api/@xmachines/play/type-aliases/PlayEvent.md +4 -4
  4. package/api/@xmachines/play-actor/README.md +32 -31
  5. package/api/@xmachines/play-actor/classes/AbstractActor.md +20 -19
  6. package/api/@xmachines/play-actor/interfaces/PlaySpec.md +37 -0
  7. package/api/@xmachines/play-actor/interfaces/Routable.md +5 -4
  8. package/api/@xmachines/play-actor/interfaces/ViewMetadata.md +6 -6
  9. package/api/@xmachines/play-actor/interfaces/Viewable.md +8 -8
  10. package/api/@xmachines/play-dom/README.md +36 -0
  11. package/api/@xmachines/play-dom/classes/PlayRenderer.md +83 -0
  12. package/api/@xmachines/play-dom/functions/connectRenderer.md +51 -0
  13. package/api/@xmachines/play-dom/functions/renderSpec.md +28 -0
  14. package/api/@xmachines/play-dom/interfaces/ConnectRendererOptions.md +18 -0
  15. package/api/@xmachines/play-dom/interfaces/DomRenderContext.md +18 -0
  16. package/api/@xmachines/play-dom/interfaces/PlayDomOptions.md +14 -0
  17. package/api/@xmachines/play-dom/type-aliases/DomComponentRenderer.md +23 -0
  18. package/api/@xmachines/play-dom/type-aliases/DomRegistry.md +11 -0
  19. package/api/@xmachines/play-react/README.md +227 -305
  20. package/api/@xmachines/play-react/classes/PlayErrorBoundary.md +5 -5
  21. package/api/@xmachines/play-react/functions/defineRegistry.md +47 -0
  22. package/api/@xmachines/play-react/functions/useActor.md +13 -0
  23. package/api/@xmachines/play-react/functions/useBoundProp.md +43 -0
  24. package/api/@xmachines/play-react/functions/useSignalEffect.md +1 -1
  25. package/api/@xmachines/play-react/functions/useStateBinding.md +32 -0
  26. package/api/@xmachines/play-react/interfaces/ComponentContext.md +35 -0
  27. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryProps.md +4 -4
  28. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryState.md +3 -3
  29. package/api/@xmachines/play-react/interfaces/PlayRendererProps.md +15 -7
  30. package/api/@xmachines/play-react/type-aliases/ComponentFn.md +34 -0
  31. package/api/@xmachines/play-react/type-aliases/PlayActor.md +9 -0
  32. package/api/@xmachines/play-react/variables/PlayRenderer.md +18 -30
  33. package/api/@xmachines/play-react-router/classes/ReactRouterBridge.md +32 -32
  34. package/api/@xmachines/play-react-router/classes/RouteMap.md +5 -5
  35. package/api/@xmachines/play-react-router/functions/PlayRouterProvider.md +11 -5
  36. package/api/@xmachines/play-react-router/functions/createRouteMapFromTree.md +1 -1
  37. package/api/@xmachines/play-react-router/interfaces/PlayRouterProviderProps.md +14 -8
  38. package/api/@xmachines/play-react-router/interfaces/RouteMapping.md +3 -3
  39. package/api/@xmachines/play-router/README.md +51 -0
  40. package/api/@xmachines/play-router/classes/BaseRouteMap.md +6 -6
  41. package/api/@xmachines/play-router/classes/RouterBridgeBase.md +33 -35
  42. package/api/@xmachines/play-router/functions/buildRouteTree.md +1 -1
  43. package/api/@xmachines/play-router/functions/connectRouter.md +1 -1
  44. package/api/@xmachines/play-router/functions/crawlMachine.md +1 -1
  45. package/api/@xmachines/play-router/functions/createBrowserHistory.md +4 -1
  46. package/api/@xmachines/play-router/functions/createRouteMap.md +3 -3
  47. package/api/@xmachines/play-router/functions/createRouter.md +1 -1
  48. package/api/@xmachines/play-router/functions/detectDuplicateRoutes.md +1 -1
  49. package/api/@xmachines/play-router/functions/extractMachineRoutes.md +1 -1
  50. package/api/@xmachines/play-router/functions/extractRoute.md +1 -1
  51. package/api/@xmachines/play-router/functions/findRouteById.md +1 -1
  52. package/api/@xmachines/play-router/functions/findRouteByPath.md +1 -1
  53. package/api/@xmachines/play-router/functions/getNavigableRoutes.md +1 -1
  54. package/api/@xmachines/play-router/functions/getRoutableRoutes.md +1 -1
  55. package/api/@xmachines/play-router/functions/routeExists.md +1 -1
  56. package/api/@xmachines/play-router/functions/validateRouteFormat.md +1 -1
  57. package/api/@xmachines/play-router/functions/validateStateExists.md +1 -1
  58. package/api/@xmachines/play-router/interfaces/BaseRouteMapping.md +3 -3
  59. package/api/@xmachines/play-router/interfaces/BrowserHistory.md +19 -15
  60. package/api/@xmachines/play-router/interfaces/BrowserWindow.md +14 -14
  61. package/api/@xmachines/play-router/interfaces/ConnectRouterOptions.md +6 -6
  62. package/api/@xmachines/play-router/interfaces/PlayRouteEvent.md +6 -6
  63. package/api/@xmachines/play-router/interfaces/RouteInfo.md +8 -8
  64. package/api/@xmachines/play-router/interfaces/RouteMap.md +4 -4
  65. package/api/@xmachines/play-router/interfaces/RouteNode.md +10 -10
  66. package/api/@xmachines/play-router/interfaces/RouteObject.md +2 -2
  67. package/api/@xmachines/play-router/interfaces/RouteTree.md +4 -4
  68. package/api/@xmachines/play-router/interfaces/RouteWatcherHandle.md +55 -0
  69. package/api/@xmachines/play-router/interfaces/RouterBridge.md +3 -3
  70. package/api/@xmachines/play-router/interfaces/StateVisit.md +4 -4
  71. package/api/@xmachines/play-router/interfaces/VanillaRouter.md +4 -4
  72. package/api/@xmachines/play-router/type-aliases/RouteMetadata.md +1 -1
  73. package/api/@xmachines/play-signals/README.md +22 -10
  74. package/api/@xmachines/play-signals/functions/watchSignal.md +35 -0
  75. package/api/@xmachines/play-signals/interfaces/ComputedOptions.md +2 -2
  76. package/api/@xmachines/play-signals/interfaces/SignalComputed.md +2 -2
  77. package/api/@xmachines/play-signals/interfaces/SignalOptions.md +2 -2
  78. package/api/@xmachines/play-signals/interfaces/SignalState.md +3 -3
  79. package/api/@xmachines/play-signals/interfaces/SignalWatcher.md +4 -4
  80. package/api/@xmachines/play-signals/type-aliases/WatcherNotify.md +1 -1
  81. package/api/@xmachines/play-solid/README.md +193 -219
  82. package/api/@xmachines/play-solid/functions/defineRegistry.md +47 -0
  83. package/api/@xmachines/play-solid/functions/useActor.md +13 -0
  84. package/api/@xmachines/play-solid/functions/useStateBinding.md +23 -0
  85. package/api/@xmachines/play-solid/interfaces/ComponentContext.md +35 -0
  86. package/api/@xmachines/play-solid/interfaces/PlayRendererProps.md +15 -7
  87. package/api/@xmachines/play-solid/type-aliases/ComponentFn.md +34 -0
  88. package/api/@xmachines/play-solid/type-aliases/PlayActor.md +9 -0
  89. package/api/@xmachines/play-solid/variables/PlayRenderer.md +15 -43
  90. package/api/@xmachines/play-solid-router/README.md +56 -30
  91. package/api/@xmachines/play-solid-router/classes/RouteMap.md +6 -6
  92. package/api/@xmachines/play-solid-router/classes/SolidRouterBridge.md +37 -37
  93. package/api/@xmachines/play-solid-router/functions/PlayRouterProvider.md +11 -5
  94. package/api/@xmachines/play-solid-router/functions/createRouteMap.md +1 -1
  95. package/api/@xmachines/play-solid-router/interfaces/AbstractActor.md +18 -17
  96. package/api/@xmachines/play-solid-router/interfaces/PlayRouterProviderProps.md +14 -8
  97. package/api/@xmachines/play-solid-router/interfaces/RouteMapping.md +3 -3
  98. package/api/@xmachines/play-solid-router/type-aliases/RoutableActor.md +3 -1
  99. package/api/@xmachines/play-solid-router/type-aliases/SolidRouterHooks.md +4 -4
  100. package/api/@xmachines/play-tanstack-react-router/README.md +1 -5
  101. package/api/@xmachines/play-tanstack-react-router/classes/RouteMap.md +5 -5
  102. package/api/@xmachines/play-tanstack-react-router/classes/TanStackReactRouterBridge.md +45 -33
  103. package/api/@xmachines/play-tanstack-react-router/functions/PlayRouterProvider.md +11 -5
  104. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMap.md +2 -2
  105. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMapFromTree.md +1 -1
  106. package/api/@xmachines/play-tanstack-react-router/functions/extractParams.md +1 -1
  107. package/api/@xmachines/play-tanstack-react-router/functions/extractQueryParams.md +1 -1
  108. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouterProviderProps.md +14 -8
  109. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteMapping.md +3 -3
  110. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteNavigateEvent.md +3 -3
  111. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterInstance.md +1 -1
  112. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterLike.md +24 -4
  113. package/api/@xmachines/play-tanstack-solid-router/classes/RouteMap.md +6 -6
  114. package/api/@xmachines/play-tanstack-solid-router/classes/SolidRouterBridge.md +33 -33
  115. package/api/@xmachines/play-tanstack-solid-router/functions/PlayRouterProvider.md +11 -5
  116. package/api/@xmachines/play-tanstack-solid-router/functions/createRouteMap.md +1 -1
  117. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouterProviderProps.md +14 -8
  118. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouteMapping.md +3 -3
  119. package/api/@xmachines/play-tanstack-solid-router/type-aliases/RoutableActor.md +3 -1
  120. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterInstance.md +1 -1
  121. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterLike.md +4 -4
  122. package/api/@xmachines/play-vue/README.md +219 -209
  123. package/api/@xmachines/play-vue/functions/defineRegistry.md +32 -0
  124. package/api/@xmachines/play-vue/functions/useActor.md +13 -0
  125. package/api/@xmachines/play-vue/functions/useStateBinding.md +30 -0
  126. package/api/@xmachines/play-vue/interfaces/ComponentContext.md +35 -0
  127. package/api/@xmachines/play-vue/interfaces/PlayRendererProps.md +14 -6
  128. package/api/@xmachines/play-vue/type-aliases/ComponentEntry.md +16 -0
  129. package/api/@xmachines/play-vue/type-aliases/ComponentFn.md +33 -0
  130. package/api/@xmachines/play-vue/type-aliases/ComponentsMap.md +15 -0
  131. package/api/@xmachines/play-vue/type-aliases/DefineRegistryOptions.md +21 -0
  132. package/api/@xmachines/play-vue/type-aliases/PlayActor.md +9 -0
  133. package/api/@xmachines/play-vue/variables/PlayRenderer.md +1 -1
  134. package/api/@xmachines/play-vue-router/README.md +74 -29
  135. package/api/@xmachines/play-vue-router/classes/RouteMap.md +7 -7
  136. package/api/@xmachines/play-vue-router/classes/VueBaseRouteMap.md +7 -7
  137. package/api/@xmachines/play-vue-router/classes/VueRouterBridge.md +48 -51
  138. package/api/@xmachines/play-vue-router/functions/createRouteMap.md +1 -1
  139. package/api/@xmachines/play-vue-router/interfaces/RouteMapping.md +4 -4
  140. package/api/@xmachines/play-vue-router/type-aliases/RoutableActor.md +3 -1
  141. package/api/@xmachines/play-vue-router/variables/PlayRouterProvider.md +7 -1
  142. package/api/@xmachines/play-xstate/README.md +236 -111
  143. package/api/@xmachines/play-xstate/classes/PlayerActor.md +36 -33
  144. package/api/@xmachines/play-xstate/functions/buildRouteUrl.md +24 -18
  145. package/api/@xmachines/play-xstate/functions/composeGuards.md +1 -1
  146. package/api/@xmachines/play-xstate/functions/composeGuardsOr.md +1 -1
  147. package/api/@xmachines/play-xstate/functions/definePlayer.md +12 -61
  148. package/api/@xmachines/play-xstate/functions/deriveRoute.md +1 -1
  149. package/api/@xmachines/play-xstate/functions/eventMatches.md +1 -1
  150. package/api/@xmachines/play-xstate/functions/formatPlayRouteTransitions.md +1 -1
  151. package/api/@xmachines/play-xstate/functions/hasContext.md +1 -1
  152. package/api/@xmachines/play-xstate/functions/isAbsoluteRoute.md +1 -1
  153. package/api/@xmachines/play-xstate/functions/negateGuard.md +1 -1
  154. package/api/@xmachines/play-xstate/functions/stateMatches.md +1 -1
  155. package/api/@xmachines/play-xstate/interfaces/PlayerConfig.md +9 -13
  156. package/api/@xmachines/play-xstate/interfaces/PlayerFactoryResumeOptions.md +2 -2
  157. package/api/@xmachines/play-xstate/interfaces/PlayerOptions.md +8 -9
  158. package/api/@xmachines/play-xstate/interfaces/RouteContext.md +5 -5
  159. package/api/@xmachines/play-xstate/type-aliases/ComposedGuard.md +1 -1
  160. package/api/@xmachines/play-xstate/type-aliases/Guard.md +1 -1
  161. package/api/@xmachines/play-xstate/type-aliases/GuardArray.md +1 -1
  162. package/api/@xmachines/play-xstate/type-aliases/PlayerFactory.md +1 -1
  163. package/api/@xmachines/play-xstate/type-aliases/RouteMachineConfig.md +14 -4
  164. package/api/@xmachines/play-xstate/type-aliases/RouteStateNode.md +19 -4
  165. package/api/@xmachines/shared/functions/defineXmVitestConfig.md +2 -2
  166. package/api/@xmachines/shared/functions/xmAliases.md +1 -1
  167. package/api/README.md +2 -2
  168. package/api/llms.txt +12 -6
  169. package/examples/multi-router-integration.md +31 -19
  170. package/guides/README.md +2 -1
  171. package/guides/installation.md +1 -6
  172. package/package.json +2 -2
  173. package/api/@xmachines/play-catalog/README.md +0 -331
  174. package/api/@xmachines/play-catalog/functions/defineCatalog.md +0 -98
  175. package/api/@xmachines/play-catalog/functions/defineComponents.md +0 -134
  176. package/api/@xmachines/play-catalog/type-aliases/Catalog.md +0 -48
  177. package/api/@xmachines/play-catalog/type-aliases/ComponentsFor.md +0 -20
  178. package/api/@xmachines/play-catalog/type-aliases/InferComponentProps.md +0 -65
  179. package/api/@xmachines/play-catalog/type-aliases/NoExtraKeys.md +0 -17
  180. package/api/@xmachines/play-xstate/functions/mergeViewProps.md +0 -26
  181. package/api/@xmachines/play-xstate/functions/validateComponentBinding.md +0 -39
  182. package/api/@xmachines/play-xstate/functions/validateViewProps.md +0 -80
  183. package/api/@xmachines/play-xstate/interfaces/CatalogEntry.md +0 -16
  184. package/api/@xmachines/play-xstate/type-aliases/Catalog.md +0 -21
  185. package/api/@xmachines/play-xstate/type-aliases/ValidationResult.md +0 -17
  186. package/api/@xmachines/play-xstate/type-aliases/ViewMergeContext.md +0 -35
@@ -2,291 +2,301 @@
2
2
 
3
3
  # @xmachines/play-vue
4
4
 
5
- **Vue renderer consuming signals and UI schema with provider pattern**
5
+ **Vue 3 renderer for XMachines Play Architecture**
6
6
 
7
- Signal-driven Vue rendering layer observing actor state with zero Vue state for business logic.
7
+ Bridges TC39 Signal-driven actors to Vue's reactivity. Business logic stays in the actor; Vue is purely a rendering target.
8
8
 
9
9
  ## Overview
10
10
 
11
- `@xmachines/play-vue` provides `PlayRenderer` for building Vue 3 UIs that passively observe actor signals. This package enables framework-swappable architecture where Vue is just a rendering target subscribing to signal changes — business logic lives entirely in the actor.
11
+ `@xmachines/play-vue` provides `PlayRenderer`, a Vue component that:
12
12
 
13
- Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md), this package implements:
13
+ - Subscribes to `actor.currentView` (TC39 Signal) and re-renders on every state transition
14
+ - Renders the current view's JSON spec via `@json-render/vue`
15
+ - Routes action names from spec elements to `actor.send()` via the `actions` prop
16
+ - Manages per-view UI state in an `@xstate/store` atom (automatic or caller-supplied)
14
17
 
15
- - **Signal-Only Reactivity (INV-05):** No refs/reactive for business logic, TC39 signals only
16
- - **Passive Infrastructure (INV-04):** Components observe signals, send events to actor
18
+ Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md):
17
19
 
18
- **Key Principle:** Vue state is never used for business logic. Signals are the source of truth.
19
-
20
- Renderer receives actor via props (provider pattern), not children.
20
+ - **Actor Authority (INV-01):** Guards in the machine decide all state transitions
21
+ - **Passive Infrastructure (INV-04):** Vue observes signals and dispatches events — never decides
22
+ - **Signal-Only Reactivity (INV-05):** `actor.currentView` signal is the sole render trigger
21
23
 
22
24
  ## Installation
23
25
 
24
26
  ```bash
25
- npm install vue@^3.5.0
26
27
  npm install @xmachines/play-vue
28
+ npm install @json-render/vue @json-render/core # peer deps
29
+ npm install @json-render/xstate @xstate/store # store integration
27
30
  ```
28
31
 
29
32
  ## Current Exports
30
33
 
31
- - `PlayRenderer` (Vue component)
32
- - `PlayRendererProps` (TypeScript interface)
33
-
34
- **Peer dependencies:**
35
-
36
- - `vue` ^3.5.0Vue 3 runtime
34
+ - `PlayRenderer` — main renderer component (Vue SFC)
35
+ - `useActor` composable for accessing the actor inside a `PlayRenderer` tree
36
+ - `defineRegistry` — SFC-aware wrapper; auto-wraps `.vue` SFCs via `h(SFC, ctx)`
37
+ - `useStateBinding` — re-exported from `@json-render/vue`
38
+ - `ComponentFn` (type) — re-exported from `@json-render/vue`
39
+ - `ComponentContext` (type)re-exported from `@json-render/vue`
40
+ - `PlayRendererProps` (type)
41
+ - `PlayActor` (type)
37
42
 
38
43
  ## Quick Start
39
44
 
40
- ```vue
41
- <!-- App.vue -->
42
- <script setup lang="ts">
43
- import { definePlayer } from "@xmachines/play-xstate";
44
- import { defineCatalog } from "@xmachines/play-catalog";
45
- import { PlayRenderer } from "@xmachines/play-vue";
45
+ ```ts
46
+ // catalog.ts — shared contract
47
+ import { defineCatalog } from "@json-render/core";
46
48
  import { z } from "zod";
47
- import LoginForm from "./components/LoginForm.vue";
48
- import Dashboard from "./components/Dashboard.vue";
49
-
50
- // 1. Define catalog (business logic layer)
51
- const catalog = defineCatalog({
52
- LoginForm: z.object({ error: z.string().optional() }),
53
- Dashboard: z.object({
54
- userId: z.string(),
55
- username: z.string(),
56
- }),
57
- });
58
-
59
- // 2. Define component map (view layer)
60
- const components = {
61
- LoginForm,
62
- Dashboard,
63
- };
64
-
65
- // 3. Create player actor (business logic runtime)
66
- const createPlayer = definePlayer({ machine: authMachine, catalog });
67
- const actor = createPlayer();
68
- actor.start();
69
- </script>
70
49
 
71
- <template>
72
- <!-- 4. Render UI (actor via props) -->
73
- <PlayRenderer :actor="actor" :components="components">
74
- <template #fallback>
75
- <div>Loading...</div>
76
- </template>
77
- </PlayRenderer>
78
- </template>
79
- ```
80
-
81
- ## API Reference
82
-
83
- ### PlayRenderer
84
-
85
- Main renderer component subscribing to actor signals and dynamically rendering catalog components:
50
+ export const catalog = defineCatalog({
51
+ elements: {
52
+ Login: { props: z.object({ title: z.string() }), description: "Login form" },
53
+ Dashboard: { props: z.object({ username: z.string() }), description: "Dashboard" },
54
+ },
55
+ });
86
56
 
87
- ```typescript
88
- interface PlayRendererProps {
89
- actor: AbstractActor<any>;
90
- components: Record<string, Component>;
91
- }
57
+ export type Catalog = typeof catalog;
92
58
  ```
93
59
 
94
- **Props:**
95
-
96
- - `actor` - Actor instance with `currentView` signal
97
- - `components` - Map of component names to Vue components
98
-
99
- **Slots:**
100
-
101
- - `fallback` - Slot shown when `currentView` is null
102
-
103
- **Behavior:**
104
-
105
- 1. Subscribes to `actor.currentView` signal using a `Signal.subtle.Watcher` inside a Vue component
106
- 2. Looks up component from `components` map using `view.component` string
107
- 3. Renders component with props from `view.props` + `send` function via Vue's dynamic `<component :is="..."/>`
108
-
109
- **Example Component (LoginForm.vue):**
110
-
111
60
  ```vue
61
+ <!-- Login.vue — Vue SFC; useStateBinding works in <script setup> -->
112
62
  <script setup lang="ts">
113
- import type { AbstractActor } from "@xmachines/play-actor";
114
- import { ref } from "vue";
115
-
116
- const props = defineProps<{
117
- error?: string;
118
- send: AbstractActor<any>["send"];
119
- }>();
120
-
121
- const username = ref("");
122
-
123
- function handleSubmit() {
124
- props.send({
125
- type: "auth.login",
126
- username: username.value,
127
- });
128
- }
63
+ import { useStateBinding } from "@xmachines/play-vue";
64
+ import type { ComponentContext } from "@xmachines/play-vue";
65
+ import type { Catalog } from "./catalog.js";
66
+
67
+ const { props, emit, bindings } = defineProps<ComponentContext<Catalog, "Login">>();
68
+ const [username, setUsername] = useStateBinding<string>(bindings?.username ?? "/username");
129
69
  </script>
130
70
 
131
71
  <template>
132
- <form @submit.prevent="handleSubmit">
133
- <p v-if="error" style="color: red">{{ error }}</p>
134
- <input v-model="username" required placeholder="Username" />
135
- <button type="submit">Log In</button>
136
- </form>
72
+ <div class="view">
73
+ <h2>{{ props.title }}</h2>
74
+ <form @submit.prevent="emit('submit')">
75
+ <input id="username" v-model="username" @input="setUsername(username)" />
76
+ <button type="submit">Log In</button>
77
+ </form>
78
+ </div>
137
79
  </template>
138
80
  ```
139
81
 
140
- ## Examples
82
+ ```ts
83
+ // registry.ts — pass SFCs directly; defineRegistry auto-wraps them
84
+ import { defineRegistry } from "@xmachines/play-vue";
85
+ import { catalog } from "./catalog.js";
86
+ import LoginSFC from "./Login.vue";
87
+ import DashboardSFC from "./Dashboard.vue";
88
+
89
+ export const { registry } = defineRegistry(catalog, {
90
+ components: { Login: LoginSFC, Dashboard: DashboardSFC },
91
+ actions: { login: async () => {}, logout: async () => {} },
92
+ });
93
+ ```
141
94
 
142
- ### Provider Pattern
95
+ ```ts
96
+ // machine.ts
97
+ import { setup, assign } from "xstate";
98
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
99
+
100
+ export const machine = setup({
101
+ types: {
102
+ context: {} as {
103
+ isAuthenticated: boolean;
104
+ username: string | null;
105
+ routeParams: Record<string, string>;
106
+ queryParams: Record<string, string>;
107
+ },
108
+ events: {} as
109
+ | { type: "auth.login"; username: string }
110
+ | { type: "auth.logout" }
111
+ | { type: "play.route"; to: string; params?: Record<string, string> },
112
+ },
113
+ }).createMachine(
114
+ formatPlayRouteTransitions({
115
+ id: "app",
116
+ initial: "login",
117
+ context: { isAuthenticated: false, username: null, routeParams: {}, queryParams: {} },
118
+ states: {
119
+ login: {
120
+ id: "login",
121
+ meta: {
122
+ route: "/login",
123
+ view: {
124
+ component: "Login",
125
+ spec: {
126
+ root: "root",
127
+ elements: {
128
+ root: { type: "Login", props: { title: "Sign In" }, children: [] },
129
+ },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ dashboard: {
135
+ id: "dashboard",
136
+ meta: {
137
+ route: "/dashboard",
138
+ view: {
139
+ component: "Dashboard",
140
+ spec: {
141
+ root: "root",
142
+ elements: {
143
+ root: { type: "Dashboard", props: { username: "" }, children: [] },
144
+ },
145
+ },
146
+ },
147
+ },
148
+ },
149
+ },
150
+ on: {
151
+ "auth.login": {
152
+ target: ".dashboard",
153
+ guard: ({ context }) => !context.isAuthenticated,
154
+ actions: assign({ isAuthenticated: true, username: ({ event }) => event.username }),
155
+ },
156
+ "auth.logout": {
157
+ target: ".login",
158
+ guard: ({ context }) => context.isAuthenticated,
159
+ actions: assign({ isAuthenticated: false, username: null }),
160
+ },
161
+ },
162
+ }),
163
+ );
164
+ ```
143
165
 
144
166
  ```vue
145
167
  <!-- App.vue -->
146
168
  <script setup lang="ts">
147
- import { PlayVueRouterProvider } from "@xmachines/play-vue-router";
169
+ import { definePlayer } from "@xmachines/play-xstate";
148
170
  import { PlayRenderer } from "@xmachines/play-vue";
149
- import { provide } from "vue";
150
- import Header from "./components/Header.vue";
151
- import Footer from "./components/Footer.vue";
171
+ import { machine } from "./machine.js";
172
+ import { registry } from "./registry.js";
152
173
 
153
- // Provide actor to nested components like Header
154
- provide("actor", actor);
174
+ const createPlayer = definePlayer({ machine });
175
+ const actor = createPlayer();
176
+ actor.start();
155
177
  </script>
156
178
 
157
179
  <template>
158
- <PlayVueRouterProvider :actor="actor" :router="router" :routeMap="routeMap">
159
- <template #default="{ currentActor, currentRouter }">
160
- <div>
161
- <Header />
162
- <PlayRenderer :actor="currentActor" :components="components" />
163
- <Footer />
164
- </div>
165
- </template>
166
- </PlayVueRouterProvider>
180
+ <PlayRenderer
181
+ :actor="actor"
182
+ :registry="registry"
183
+ :actions="{ login: 'auth.login', logout: 'auth.logout' }"
184
+ />
167
185
  </template>
168
186
  ```
169
187
 
170
- ```vue
171
- <!-- Header.vue -->
172
- <script setup lang="ts">
173
- import { inject, ref, onMounted, onUnmounted } from "vue";
174
- import type { AbstractActor } from "@xmachines/play-actor";
175
-
176
- const actor = inject<AbstractActor<any>>("actor")!;
177
- const route = ref<string | null>(null);
178
-
179
- let watcher: any;
180
-
181
- onMounted(() => {
182
- let pending = false;
183
- watcher = new Signal.subtle.Watcher(() => {
184
- if (!pending) {
185
- pending = true;
186
- queueMicrotask(() => {
187
- pending = false;
188
- for (const s of watcher.getPending()) s.get();
189
- route.value = actor.currentRoute.get();
190
- watcher.watch(actor.currentRoute);
191
- });
192
- }
193
- });
194
- route.value = actor.currentRoute.get();
195
- watcher.watch(actor.currentRoute);
196
- });
188
+ ## API Reference
197
189
 
198
- onUnmounted(() => {
199
- if (watcher) watcher.unwatch(actor.currentRoute);
200
- });
201
- </script>
190
+ ### `PlayRenderer`
202
191
 
203
- <template>
204
- <header>
205
- <nav>Current: {{ route }}</nav>
206
- </header>
207
- </template>
192
+ Main Vue component. Subscribes to `actor.currentView` and renders the spec.
193
+
194
+ ```vue
195
+ <PlayRenderer
196
+ :actor="actor"
197
+ :registry="registry"
198
+ :actions="{ login: 'auth.login' }"
199
+ :store="myStore"
200
+ />
208
201
  ```
209
202
 
210
- ## Architecture
203
+ **`actor`** — A `PlayerActor` (or any `AbstractActor & Viewable`). Provides the `currentView` signal.
211
204
 
212
- This package implements **Signal-Only Reactivity (INV-05)** and **Passive Infrastructure (INV-04)**:
205
+ **`registry`** Built with `defineRegistry(catalog, { components, actions })` from `@xmachines/play-vue`. Pass `.vue` SFCs directly — they are auto-wrapped via `h(SFC, ctx)` so `useStateBinding` and other composables work inside `<script setup>`.
213
206
 
214
- 1. **No Business Logic in Vue:**
215
- - No ref/reactive for business state
216
- - No watch/watchEffect for business side effects
217
- - Vue only triggers renders, doesn't control state
207
+ **`actions`** — Maps json-render action names (from spec `on` bindings) to XState event type strings. Type-checked against `EventFromLogic<TLogic>["type"]` when `TLogic` is specified.
218
208
 
219
- 2. **Signals as Source of Truth:**
220
- - `actor.currentView.get()` provides UI structure
221
- - `actor.currentRoute.get()` provides navigation state
222
- - Components observe signals via explicit watcher patterns
209
+ **`store`** (optional) Controls per-view UI state (`$state` bindings, form values):
223
210
 
224
- 3. **Event Forwarding:**
225
- - Components receive `send` function via props
226
- - User actions send events to actor (e.g., `{ type: "auth.login" }`)
227
- - Actor guards validate and process events
211
+ - **Omitted (uncontrolled, default):** A fresh `@xstate/store` atom is created per view transition, seeded from `view.spec.state`.
212
+ - **Provided (controlled):** The caller owns the store; `spec.state` is ignored.
228
213
 
229
- 4. **Microtask Batching:**
230
- - `Signal.subtle.Watcher` coalesces rapid signal changes
231
- - Prevents Vue thrashing from multiple signal updates
232
- - Single Vue render per microtask batch
214
+ ```ts
215
+ import { createAtom } from "@xstate/store";
216
+ import { xstateStoreStateStore } from "@json-render/xstate";
217
+ import type { StateStore } from "@json-render/core";
233
218
 
234
- 5. **Explicit Disposal Contract:**
235
- - Component teardown calls watcher `unwatch` in `onUnmounted`
236
- - Do not rely on GC-only cleanup
219
+ const store: StateStore = xstateStoreStateStore({ atom: createAtom({ username: "" }) });
220
+ ```
237
221
 
238
- **Pattern:**
222
+ ```vue
223
+ <PlayRenderer
224
+ :actor="actor"
225
+ :registry="registry"
226
+ :store="store"
227
+ :actions="{ login: 'auth.login' }"
228
+ />
229
+ ```
239
230
 
240
- - Renderer receives actor via props (provider pattern)
241
- - Enables composition with navigation, headers, footers
242
- - Supports multiple renderers in same app
231
+ ---
243
232
 
244
- **Architectural Invariants:**
233
+ ### `useActor`
245
234
 
246
- - **Signal-Only Reactivity (INV-05):** No Vue state for business logic
247
- - **Passive Infrastructure (INV-04):** Components reflect, never decide
235
+ Vue composable for accessing the actor from inside any component rendered by `PlayRenderer`.
248
236
 
249
- ## Canonical Watcher Lifecycle
237
+ ```ts
238
+ import { useActor } from "@xmachines/play-vue";
250
239
 
251
- If you write your own custom integration, use the same watcher flow as `PlayRenderer`:
240
+ // Inside any component rendered inside PlayRenderer:
241
+ const actor = useActor();
242
+ actor.send({ type: "auth.logout" });
243
+ ```
252
244
 
253
- 1. `notify` callback runs
254
- 2. Schedule work with `queueMicrotask`
255
- 3. Drain `watcher.getPending()`
256
- 4. Read actor signals and update Vue-local ref state
257
- 5. Re-arm with `watch(...)` or `watch()`
245
+ Throws `"useActor() must be called inside <PlayRenderer>"` if called outside the tree.
258
246
 
259
- Watcher notify is one-shot. Re-arm is required for continuous observation.
247
+ ---
260
248
 
261
- ## Benefits
249
+ ## Route Parameters in Props
262
250
 
263
- - **Framework Swappable:** Business logic has zero Vue imports
264
- - **Type Safety:** Props validated against catalog schemas
265
- - **Simple Testing:** Test actors without Vue renderer
266
- - **Performance:** Microtask batching reduces unnecessary renders
267
- - **Composability:** Renderer prop enables complex layouts
251
+ When using `formatPlayRouteTransitions`, URL path parameters flow automatically into component props. Declare an `undefined` slot in the spec to opt in:
268
252
 
269
- ## Related Packages
253
+ ```ts
254
+ // spec: { section: undefined, user: "alice" }
255
+ // After play.route to /settings/profile → context.routeParams = { section: "profile" }
256
+ // Component receives: { section: "profile", user: "alice" }
257
+ ```
258
+
259
+ Priority: **route param fills `undefined` slots; explicit non-`undefined` spec props always win.**
270
260
 
271
- - **[@xmachines/play-xstate](../play-xstate/README.md)** - XState adapter providing actors
272
- - **[@xmachines/play-catalog](../play-catalog/README.md)** - UI schema validation
273
- - **[@xmachines/play-vue-router](../play-vue-router/README.md)** - Vue Router integration
274
- - **[@xmachines/play-actor](../play-actor/README.md)** - Actor base
275
- - **[@xmachines/play-signals](../play-signals/README.md)** - TC39 Signals primitives
261
+ ---
276
262
 
277
- ## License
263
+ ## Architecture Notes
278
264
 
279
- Copyright (c) 2016 [Mikael Karon](mailto:mikael@karon.se). All rights reserved.
265
+ - Vue reactivity is only used to trigger re-renders — not for business logic
266
+ - `actor.currentView` (TC39 Signal) is bridged to Vue's reactive system inside `PlayRenderer`
267
+ - Per-view UI state lives in an `@xstate/store` atom, not in Vue reactive state
268
+ - `@json-render/vue` drives rendering; `PlayRenderer` is the signal bridge — import `defineRegistry`, `ComponentFn`, `ComponentContext`, and `useStateBinding` from `@xmachines/play-vue`
269
+ - Vue views should be `.vue` SFCs using `ComponentContext<MyCatalog, "X">` — `defineRegistry` from `@xmachines/play-vue` auto-wraps them via `h(SFC, ctx)`, giving each SFC its own `setup()` context where `useStateBinding` and Vue composables work correctly
280
270
 
281
- This work is licensed under the terms of the MIT license.
282
- For a copy, see <https://opensource.org/licenses/MIT>.
271
+ @xmachines/play-vue - Vue 3 renderer for XMachines Play architecture
283
272
 
284
- @xmachines/play-vue - Vue renderer for XMachines Play architecture
273
+ Provides a thin Vue rendering layer that passively observes actor signals
274
+ and renders UI components via @json-render/vue. Vue reactivity is only used
275
+ to trigger re-renders — signals are the source of truth.
276
+
277
+ Re-exports `defineRegistry` (SFC-aware — auto-wraps `.vue` SFCs via `h()`),
278
+ `useStateBinding`, `ComponentFn`, and `ComponentContext` so consumers import
279
+ everything from `@xmachines/play-vue` rather than `@json-render/vue` directly.
285
280
 
286
281
  ## Interfaces
287
282
 
283
+ - [ComponentContext](interfaces/ComponentContext.md)
288
284
  - [PlayRendererProps](interfaces/PlayRendererProps.md)
289
285
 
286
+ ## Type Aliases
287
+
288
+ - [ComponentEntry](type-aliases/ComponentEntry.md)
289
+ - [ComponentFn](type-aliases/ComponentFn.md)
290
+ - [ComponentsMap](type-aliases/ComponentsMap.md)
291
+ - [DefineRegistryOptions](type-aliases/DefineRegistryOptions.md)
292
+ - [PlayActor](type-aliases/PlayActor.md)
293
+
290
294
  ## Variables
291
295
 
292
296
  - [PlayRenderer](variables/PlayRenderer.md)
297
+
298
+ ## Functions
299
+
300
+ - [defineRegistry](functions/defineRegistry.md)
301
+ - [useActor](functions/useActor.md)
302
+ - [useStateBinding](functions/useStateBinding.md)
@@ -0,0 +1,32 @@
1
+ [Documentation](../../../README.md) / [@xmachines/play-vue](../README.md) / defineRegistry
2
+
3
+ # Function: defineRegistry()
4
+
5
+ ```ts
6
+ function defineRegistry<C>(catalog, options): DefineRegistryResult;
7
+ ```
8
+
9
+ Defined in: [packages/play-vue/src/define-registry.ts:114](https://gitlab.com/xmachin-es/xmachines-js/-/blob/v1.0.0-beta.18/packages/play-vue/src/define-registry.ts#L114)
10
+
11
+ Create a component registry, automatically wrapping `.vue` SFCs so they work
12
+ correctly with `@json-render/vue`'s rendering pipeline.
13
+
14
+ Drop-in replacement for `defineRegistry` from `@json-render/vue`. Import from
15
+ `@xmachines/play-vue` to get SFC support for free.
16
+
17
+ ## Type Parameters
18
+
19
+ | Type Parameter |
20
+ | ------------------------------------------------------------------------------------------------------------------------------------ |
21
+ | `C` _extends_ `Catalog`\<`SchemaDefinition`\<`SchemaType`\<`string`, `unknown`\>, `SchemaType`\<`string`, `unknown`\>\>, `unknown`\> |
22
+
23
+ ## Parameters
24
+
25
+ | Parameter | Type | Description |
26
+ | --------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | `catalog` | `C` | The json-render catalog defining component prop shapes. |
28
+ | `options` | [`DefineRegistryOptions`](../type-aliases/DefineRegistryOptions.md)\<`C`\> | Registry options. `components` entries may be `.vue` SFCs (objects) or plain `ComponentFn` functions — both are handled automatically. |
29
+
30
+ ## Returns
31
+
32
+ `DefineRegistryResult`
@@ -0,0 +1,13 @@
1
+ [Documentation](../../../README.md) / [@xmachines/play-vue](../README.md) / useActor
2
+
3
+ # Function: useActor()
4
+
5
+ ```ts
6
+ function useActor(): PlayActor;
7
+ ```
8
+
9
+ Defined in: [packages/play-vue/src/useActor.ts:42](https://gitlab.com/xmachin-es/xmachines-js/-/blob/v1.0.0-beta.18/packages/play-vue/src/useActor.ts#L42)
10
+
11
+ ## Returns
12
+
13
+ [`PlayActor`](../type-aliases/PlayActor.md)
@@ -0,0 +1,30 @@
1
+ [Documentation](../../../README.md) / [@xmachines/play-vue](../README.md) / useStateBinding
2
+
3
+ # Function: useStateBinding()
4
+
5
+ ```ts
6
+ function useStateBinding<T>(path): [ComputedRef<T | undefined>, (value) => void];
7
+ ```
8
+
9
+ Composable to get and set a value from the state model by path.
10
+
11
+ This is the path-based variant for use in arbitrary composables. For
12
+ registry components that receive `bindings` from the renderer, prefer
13
+ `useBoundProp` which reads the already-resolved prop value and writes back
14
+ to the bound path.
15
+
16
+ ## Type Parameters
17
+
18
+ | Type Parameter |
19
+ | -------------- |
20
+ | `T` |
21
+
22
+ ## Parameters
23
+
24
+ | Parameter | Type |
25
+ | --------- | -------- |
26
+ | `path` | `string` |
27
+
28
+ ## Returns
29
+
30
+ \[`ComputedRef`\<`T` \| `undefined`\>, (`value`) => `void`\]
@@ -0,0 +1,35 @@
1
+ [Documentation](../../../README.md) / [@xmachines/play-vue](../README.md) / ComponentContext
2
+
3
+ # Interface: ComponentContext\<C, K\>
4
+
5
+ Context passed to component render functions
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ const Button: ComponentFn<typeof catalog, "Button"> = (ctx) => {
11
+ return h("button", { onClick: () => ctx.emit("press") }, ctx.props.label);
12
+ };
13
+ ```
14
+
15
+ ## Extends
16
+
17
+ - `BaseComponentProps`\<`InferComponentProps`\<`C`, `K`\>\>
18
+
19
+ ## Type Parameters
20
+
21
+ | Type Parameter |
22
+ | --------------------------------------------------- |
23
+ | `C` _extends_ `Catalog` |
24
+ | `K` _extends_ keyof `InferCatalogComponents`\<`C`\> |
25
+
26
+ ## Properties
27
+
28
+ | Property | Type | Description | Inherited from | Defined in |
29
+ | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ---------- |
30
+ | <a id="property-bindings"></a> `bindings?` | `Record`\<`string`, `string`\> | Two-way binding paths resolved from `$bindState` / `$bindItem` expressions. Maps prop name → absolute state path for write-back. | `BaseComponentProps.bindings` | - |
31
+ | <a id="property-children"></a> `children?` | \| `VNode`\<`RendererNode`, `RendererElement`, \{ \[`key`: `string`\]: `any`; \}\> \| `VNode`\<`RendererNode`, `RendererElement`, \{ \[`key`: `string`\]: `any`; \}\>[] | Rendered children (from the default slot) | `BaseComponentProps.children` | - |
32
+ | <a id="property-emit"></a> `emit` | (`event`) => `void` | Simple event emitter (shorthand). Fires the event and returns void. | `BaseComponentProps.emit` | - |
33
+ | <a id="property-loading"></a> `loading?` | `boolean` | - | `BaseComponentProps.loading` | - |
34
+ | <a id="property-on"></a> `on` | (`event`) => `EventHandle` | Get an event handle with metadata. Use when you need shouldPreventDefault or bound checks. | `BaseComponentProps.on` | - |
35
+ | <a id="property-props"></a> `props` | `InferComponentProps` | - | `BaseComponentProps.props` | - |