@xmachines/docs 1.0.0-beta.26 → 1.0.0-beta.27

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 (216) hide show
  1. package/api/@xmachines/play/classes/PlayError.md +4 -4
  2. package/api/@xmachines/play/type-aliases/PlayEvent.md +2 -2
  3. package/api/@xmachines/play-actor/classes/AbstractActor.md +3 -3
  4. package/api/@xmachines/play-actor/functions/typedSpec.md +1 -1
  5. package/api/@xmachines/play-actor/interfaces/PlaySpec.md +2 -2
  6. package/api/@xmachines/play-actor/interfaces/Routable.md +3 -3
  7. package/api/@xmachines/play-actor/interfaces/ViewMetadata.md +3 -3
  8. package/api/@xmachines/play-actor/interfaces/Viewable.md +2 -2
  9. package/api/@xmachines/play-dom/README.md +24 -8
  10. package/api/@xmachines/play-dom/classes/PlayRenderer.md +4 -4
  11. package/api/@xmachines/play-dom/functions/connectRenderer.md +1 -1
  12. package/api/@xmachines/play-dom/functions/defineRegistry.md +61 -0
  13. package/api/@xmachines/play-dom/functions/renderSpec.md +29 -12
  14. package/api/@xmachines/play-dom/interfaces/ComponentContext.md +62 -0
  15. package/api/@xmachines/play-dom/interfaces/ConnectRendererOptions.md +9 -9
  16. package/api/@xmachines/play-dom/interfaces/DefineRegistryOptions.md +25 -0
  17. package/api/@xmachines/play-dom/interfaces/DefineRegistryResult.md +18 -0
  18. package/api/@xmachines/play-dom/interfaces/DomRenderContext.md +13 -10
  19. package/api/@xmachines/play-dom/interfaces/EventHandle.md +29 -0
  20. package/api/@xmachines/play-dom/interfaces/PlayDomOptions.md +5 -5
  21. package/api/@xmachines/play-dom/type-aliases/ComponentFn.md +53 -0
  22. package/api/@xmachines/play-dom/type-aliases/ComponentRegistry.md +21 -0
  23. package/api/@xmachines/play-dom/type-aliases/DomComponentRenderer.md +16 -3
  24. package/api/@xmachines/play-dom/type-aliases/DomRegistry.md +5 -2
  25. package/api/@xmachines/play-dom-router/functions/connectRouter.md +1 -1
  26. package/api/@xmachines/play-dom-router/functions/createBrowserHistory.md +1 -1
  27. package/api/@xmachines/play-dom-router/functions/createRouteMap.md +1 -1
  28. package/api/@xmachines/play-dom-router/functions/createRouter.md +1 -1
  29. package/api/@xmachines/play-dom-router/interfaces/BrowserHistory.md +14 -14
  30. package/api/@xmachines/play-dom-router/interfaces/BrowserWindow.md +14 -14
  31. package/api/@xmachines/play-dom-router/interfaces/ConnectRouterOptions.md +4 -4
  32. package/api/@xmachines/play-dom-router/interfaces/PlayRouteEvent.md +6 -6
  33. package/api/@xmachines/play-dom-router/interfaces/RouteMap.md +3 -3
  34. package/api/@xmachines/play-dom-router/interfaces/RouteMapLike.md +3 -3
  35. package/api/@xmachines/play-dom-router/interfaces/RouteMapping.md +3 -3
  36. package/api/@xmachines/play-dom-router/interfaces/RouterBridge.md +3 -3
  37. package/api/@xmachines/play-dom-router/interfaces/VanillaRouter.md +4 -4
  38. package/api/@xmachines/play-dom-router/type-aliases/RoutableActor.md +1 -1
  39. package/api/@xmachines/play-dom-router-demo/README.md +46 -51
  40. package/api/@xmachines/play-react/classes/PlayErrorBoundary.md +5 -5
  41. package/api/@xmachines/play-react/functions/useActor.md +1 -1
  42. package/api/@xmachines/play-react/functions/useSignalEffect.md +1 -1
  43. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryProps.md +4 -4
  44. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryState.md +3 -3
  45. package/api/@xmachines/play-react/interfaces/PlayRendererProps.md +7 -7
  46. package/api/@xmachines/play-react/type-aliases/PlayActor.md +1 -1
  47. package/api/@xmachines/play-react/variables/PlayRenderer.md +1 -1
  48. package/api/@xmachines/play-react-router/classes/ReactRouterBridge.md +23 -23
  49. package/api/@xmachines/play-react-router/classes/RouteMap.md +4 -4
  50. package/api/@xmachines/play-react-router/functions/PlayRouterProvider.md +1 -1
  51. package/api/@xmachines/play-react-router/functions/createRouteMapFromTree.md +1 -1
  52. package/api/@xmachines/play-react-router/interfaces/PlayRouteEvent.md +6 -6
  53. package/api/@xmachines/play-react-router/interfaces/PlayRouterProviderProps.md +5 -5
  54. package/api/@xmachines/play-react-router/interfaces/RouteMapping.md +3 -3
  55. package/api/@xmachines/play-react-router/interfaces/RouterBridge.md +3 -3
  56. package/api/@xmachines/play-router/classes/BaseRouteMap.md +4 -4
  57. package/api/@xmachines/play-router/classes/RouterBridgeBase.md +23 -23
  58. package/api/@xmachines/play-router/functions/buildPlayRouteEvent.md +1 -1
  59. package/api/@xmachines/play-router/functions/buildRouteTree.md +1 -1
  60. package/api/@xmachines/play-router/functions/createRouteMap.md +1 -1
  61. package/api/@xmachines/play-router/functions/createRouteMapFromMachine.md +1 -1
  62. package/api/@xmachines/play-router/functions/createRouteMapFromTree.md +1 -1
  63. package/api/@xmachines/play-router/functions/detectDuplicateRoutes.md +1 -1
  64. package/api/@xmachines/play-router/functions/extractMachineRoutes.md +1 -1
  65. package/api/@xmachines/play-router/functions/extractQuery.md +1 -1
  66. package/api/@xmachines/play-router/functions/extractRouteParams.md +1 -1
  67. package/api/@xmachines/play-router/functions/findRouteById.md +1 -1
  68. package/api/@xmachines/play-router/functions/findRouteByPath.md +1 -1
  69. package/api/@xmachines/play-router/functions/getNavigableRoutes.md +1 -1
  70. package/api/@xmachines/play-router/functions/getRoutableRoutes.md +1 -1
  71. package/api/@xmachines/play-router/functions/getTransitionReachableRoutes.md +1 -1
  72. package/api/@xmachines/play-router/functions/isRouteReachable.md +1 -1
  73. package/api/@xmachines/play-router/functions/machineToGraph.md +1 -1
  74. package/api/@xmachines/play-router/functions/routeExists.md +1 -1
  75. package/api/@xmachines/play-router/functions/sanitizePathname.md +1 -1
  76. package/api/@xmachines/play-router/functions/validateRouteFormat.md +1 -1
  77. package/api/@xmachines/play-router/functions/validateStateExists.md +1 -1
  78. package/api/@xmachines/play-router/interfaces/BuildPlayRouteEventOptions.md +4 -4
  79. package/api/@xmachines/play-router/interfaces/LocationLike.md +3 -3
  80. package/api/@xmachines/play-router/interfaces/MachineEdgeData.md +3 -3
  81. package/api/@xmachines/play-router/interfaces/MachineNodeData.md +5 -5
  82. package/api/@xmachines/play-router/interfaces/PlayRouteEvent.md +6 -6
  83. package/api/@xmachines/play-router/interfaces/RouteInfo.md +8 -8
  84. package/api/@xmachines/play-router/interfaces/RouteMap.md +4 -4
  85. package/api/@xmachines/play-router/interfaces/RouteMapping.md +3 -3
  86. package/api/@xmachines/play-router/interfaces/RouteMatch.md +3 -3
  87. package/api/@xmachines/play-router/interfaces/RouteNode.md +10 -10
  88. package/api/@xmachines/play-router/interfaces/RouteObject.md +2 -2
  89. package/api/@xmachines/play-router/interfaces/RouteTree.md +5 -5
  90. package/api/@xmachines/play-router/interfaces/RouteWatcherHandle.md +3 -3
  91. package/api/@xmachines/play-router/interfaces/RouterBridge.md +3 -3
  92. package/api/@xmachines/play-router/interfaces/WindowLike.md +3 -3
  93. package/api/@xmachines/play-router/type-aliases/MachineGraph.md +1 -1
  94. package/api/@xmachines/play-router/type-aliases/RouteMetadata.md +1 -1
  95. package/api/@xmachines/play-signals/functions/watchSignal.md +1 -1
  96. package/api/@xmachines/play-signals/interfaces/ComputedOptions.md +2 -2
  97. package/api/@xmachines/play-signals/interfaces/SignalComputed.md +2 -2
  98. package/api/@xmachines/play-signals/interfaces/SignalOptions.md +2 -2
  99. package/api/@xmachines/play-signals/interfaces/SignalState.md +3 -3
  100. package/api/@xmachines/play-signals/interfaces/SignalWatcher.md +4 -4
  101. package/api/@xmachines/play-signals/type-aliases/WatcherNotify.md +1 -1
  102. package/api/@xmachines/play-solid/functions/useActor.md +1 -1
  103. package/api/@xmachines/play-solid/interfaces/PlayRendererProps.md +7 -7
  104. package/api/@xmachines/play-solid/type-aliases/PlayActor.md +1 -1
  105. package/api/@xmachines/play-solid/variables/PlayRenderer.md +1 -1
  106. package/api/@xmachines/play-solid-router/classes/RouteMap.md +4 -4
  107. package/api/@xmachines/play-solid-router/classes/SolidRouterBridge.md +24 -24
  108. package/api/@xmachines/play-solid-router/functions/PlayRouterProvider.md +1 -1
  109. package/api/@xmachines/play-solid-router/functions/createRouteMap.md +1 -1
  110. package/api/@xmachines/play-solid-router/interfaces/AbstractActor.md +3 -3
  111. package/api/@xmachines/play-solid-router/interfaces/PlayRouteEvent.md +6 -6
  112. package/api/@xmachines/play-solid-router/interfaces/PlayRouterProviderProps.md +5 -5
  113. package/api/@xmachines/play-solid-router/interfaces/RouteMapping.md +3 -3
  114. package/api/@xmachines/play-solid-router/interfaces/RouterBridge.md +3 -3
  115. package/api/@xmachines/play-solid-router/type-aliases/RoutableActor.md +1 -1
  116. package/api/@xmachines/play-solid-router/type-aliases/SolidRouterHooks.md +4 -4
  117. package/api/@xmachines/play-solid-router-demo/README.md +25 -28
  118. package/api/@xmachines/play-svelte/interfaces/PlayRendererProps.md +7 -7
  119. package/api/@xmachines/play-svelte-spa-router/classes/RouteMap.md +4 -4
  120. package/api/@xmachines/play-svelte-spa-router/functions/connectRouter.md +1 -1
  121. package/api/@xmachines/play-svelte-spa-router/functions/createRouteMap.md +1 -1
  122. package/api/@xmachines/play-svelte-spa-router/interfaces/ConnectRouterOptions.md +4 -4
  123. package/api/@xmachines/play-svelte-spa-router/interfaces/PlayRouteEvent.md +6 -6
  124. package/api/@xmachines/play-svelte-spa-router/interfaces/RouteMapping.md +3 -3
  125. package/api/@xmachines/play-svelte-spa-router/interfaces/RouterBridge.md +3 -3
  126. package/api/@xmachines/play-svelte-spa-router/interfaces/WindowLike.md +3 -3
  127. package/api/@xmachines/play-svelte-spa-router/type-aliases/RoutableActor.md +1 -1
  128. package/api/@xmachines/play-svelte-spa-router-demo/README.md +119 -12
  129. package/api/@xmachines/play-sveltekit-router/classes/RouteMap.md +4 -4
  130. package/api/@xmachines/play-sveltekit-router/functions/connectRouter.md +1 -1
  131. package/api/@xmachines/play-sveltekit-router/functions/createRouteMap.md +1 -1
  132. package/api/@xmachines/play-sveltekit-router/interfaces/ConnectRouterOptions.md +4 -4
  133. package/api/@xmachines/play-sveltekit-router/interfaces/LocationLike.md +3 -3
  134. package/api/@xmachines/play-sveltekit-router/interfaces/PlayRouteEvent.md +6 -6
  135. package/api/@xmachines/play-sveltekit-router/interfaces/RouteMapping.md +3 -3
  136. package/api/@xmachines/play-sveltekit-router/interfaces/RouterBridge.md +3 -3
  137. package/api/@xmachines/play-sveltekit-router/type-aliases/RoutableActor.md +1 -1
  138. package/api/@xmachines/play-sveltekit-router-demo/README.md +120 -12
  139. package/api/@xmachines/play-tanstack-react-router/classes/RouteMap.md +4 -4
  140. package/api/@xmachines/play-tanstack-react-router/classes/TanStackReactRouterBridge.md +23 -23
  141. package/api/@xmachines/play-tanstack-react-router/functions/PlayRouterProvider.md +1 -1
  142. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMap.md +1 -1
  143. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMapFromTree.md +1 -1
  144. package/api/@xmachines/play-tanstack-react-router/functions/extractMachineRoutes.md +1 -1
  145. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouteEvent.md +6 -6
  146. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouterProviderProps.md +5 -5
  147. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteMapping.md +3 -3
  148. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteNavigateEvent.md +3 -3
  149. package/api/@xmachines/play-tanstack-react-router/interfaces/RouterBridge.md +3 -3
  150. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterInstance.md +1 -1
  151. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterLike.md +17 -3
  152. package/api/@xmachines/play-tanstack-react-router-demo/README.md +23 -29
  153. package/api/@xmachines/play-tanstack-solid-router/classes/RouteMap.md +4 -4
  154. package/api/@xmachines/play-tanstack-solid-router/classes/SolidRouterBridge.md +24 -24
  155. package/api/@xmachines/play-tanstack-solid-router/functions/PlayRouterProvider.md +1 -1
  156. package/api/@xmachines/play-tanstack-solid-router/functions/createRouteMap.md +1 -1
  157. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouteEvent.md +6 -6
  158. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouterProviderProps.md +5 -5
  159. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouteMapping.md +3 -3
  160. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouterBridge.md +3 -3
  161. package/api/@xmachines/play-tanstack-solid-router/type-aliases/RoutableActor.md +1 -1
  162. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterInstance.md +1 -1
  163. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterLike.md +3 -3
  164. package/api/@xmachines/play-tanstack-solid-router-demo/README.md +25 -26
  165. package/api/@xmachines/play-vue/functions/defineRegistry.md +1 -1
  166. package/api/@xmachines/play-vue/functions/useActor.md +1 -1
  167. package/api/@xmachines/play-vue/interfaces/PlayRendererProps.md +5 -5
  168. package/api/@xmachines/play-vue/type-aliases/ComponentEntry.md +1 -1
  169. package/api/@xmachines/play-vue/type-aliases/ComponentsMap.md +1 -1
  170. package/api/@xmachines/play-vue/type-aliases/DefineRegistryOptions.md +4 -3
  171. package/api/@xmachines/play-vue/type-aliases/PlayActor.md +1 -1
  172. package/api/@xmachines/play-vue/variables/PlayRenderer.md +1 -1
  173. package/api/@xmachines/play-vue-router/classes/RouteMap.md +4 -4
  174. package/api/@xmachines/play-vue-router/classes/VueBaseRouteMap.md +4 -4
  175. package/api/@xmachines/play-vue-router/classes/VueRouterBridge.md +24 -24
  176. package/api/@xmachines/play-vue-router/functions/createRouteMap.md +1 -1
  177. package/api/@xmachines/play-vue-router/interfaces/PlayRouteEvent.md +6 -6
  178. package/api/@xmachines/play-vue-router/interfaces/RouteMapping.md +3 -3
  179. package/api/@xmachines/play-vue-router/interfaces/RouterBridge.md +3 -3
  180. package/api/@xmachines/play-vue-router/type-aliases/RoutableActor.md +1 -1
  181. package/api/@xmachines/play-vue-router/variables/PlayRouterProvider.md +1 -1
  182. package/api/@xmachines/play-vue-router-demo/README.md +47 -40
  183. package/api/@xmachines/play-xstate/classes/PlayerActor.md +11 -11
  184. package/api/@xmachines/play-xstate/functions/buildRouteUrl.md +1 -1
  185. package/api/@xmachines/play-xstate/functions/composeGuards.md +1 -1
  186. package/api/@xmachines/play-xstate/functions/composeGuardsOr.md +1 -1
  187. package/api/@xmachines/play-xstate/functions/contextFieldMatches.md +1 -1
  188. package/api/@xmachines/play-xstate/functions/definePlayer.md +1 -1
  189. package/api/@xmachines/play-xstate/functions/deriveRoute.md +1 -1
  190. package/api/@xmachines/play-xstate/functions/eventMatches.md +1 -1
  191. package/api/@xmachines/play-xstate/functions/formatPlayRouteTransitions.md +1 -1
  192. package/api/@xmachines/play-xstate/functions/hasContext.md +1 -1
  193. package/api/@xmachines/play-xstate/functions/isAbsoluteRoute.md +1 -1
  194. package/api/@xmachines/play-xstate/functions/negateGuard.md +1 -1
  195. package/api/@xmachines/play-xstate/interfaces/PlayerConfig.md +3 -3
  196. package/api/@xmachines/play-xstate/interfaces/PlayerFactoryResumeOptions.md +2 -2
  197. package/api/@xmachines/play-xstate/interfaces/PlayerOptions.md +6 -6
  198. package/api/@xmachines/play-xstate/interfaces/RouteContext.md +5 -5
  199. package/api/@xmachines/play-xstate/type-aliases/ComposedGuard.md +1 -1
  200. package/api/@xmachines/play-xstate/type-aliases/Guard.md +1 -1
  201. package/api/@xmachines/play-xstate/type-aliases/GuardArray.md +1 -1
  202. package/api/@xmachines/play-xstate/type-aliases/PlayerFactory.md +1 -1
  203. package/api/@xmachines/play-xstate/type-aliases/RouteMachineConfig.md +4 -4
  204. package/api/@xmachines/play-xstate/type-aliases/RouteStateNode.md +4 -4
  205. package/api/@xmachines/shared/functions/defineXmVitestConfig.md +3 -7
  206. package/api/@xmachines/shared/functions/xmAliases.md +1 -1
  207. package/examples/README.md +48 -35
  208. package/examples/basic-state-machine.md +75 -31
  209. package/examples/form-validation.md +199 -127
  210. package/examples/multi-router-integration.md +312 -230
  211. package/examples/routing-patterns.md +243 -189
  212. package/examples/traffic-light.md +114 -65
  213. package/guides/README.md +29 -15
  214. package/guides/getting-started.md +224 -144
  215. package/guides/installation.md +153 -213
  216. package/package.json +2 -2
@@ -1,167 +1,239 @@
1
- # Form Validation State Machine
1
+ <!-- generated-by: gsd-doc-writer -->
2
2
 
3
- Managing form state with validation logic using guards and conditional transitions.
3
+ # Form Validation with Typed Context
4
+
5
+ Managing login form state using `setup({ types })`, typed `assign`, guards, and `meta.view` with `$bindState`.
4
6
 
5
7
  ## Use Case
6
8
 
7
- This example demonstrates a form with idle validating valid/invalid states. It's applicable to:
9
+ This example mirrors the `authMachine` login pattern: a form state with a local state store (`$bindState` two-way binding), a guard on the submit action, and a `meta.view` spec describing the component tree. It covers:
8
10
 
9
- - Login and signup forms with validation
10
- - Multi-step form wizards
11
- - Data entry forms with complex validation rules
12
- - Any UI requiring state-driven validation feedback
11
+ - Typed context mutations with `setup.assign`
12
+ - Guards as inline functions checking context
13
+ - `meta.view` spec with `$bindState` for two-way form binding
14
+ - Sending typed domain events from the view layer
13
15
 
14
16
  ## Complete Code
15
17
 
16
18
  ```typescript
17
19
  import { setup } from "xstate";
18
-
19
- // Define context
20
- interface FormContext {
21
- // Context would store form data and validation state
20
+ import { definePlayer, formatPlayRouteTransitions } from "@xmachines/play-xstate";
21
+
22
+ // Context shape
23
+ interface LoginContext {
24
+ isAuthenticated: boolean;
25
+ username: string | null;
26
+ errorMessage: string | null;
27
+ params: Record<string, string>;
28
+ query: Record<string, string>;
22
29
  }
23
30
 
24
- // Define events
25
- type FormEvent = { type: "SUBMIT"; value: string } | { type: "RESET" };
26
-
27
- // Create machine
28
- const formMachine = setup({
31
+ // Event union — lowercase dot-separated names
32
+ type LoginEvent =
33
+ | {
34
+ type: "play.route";
35
+ to: string;
36
+ params?: Record<string, string>;
37
+ query?: Record<string, string>;
38
+ }
39
+ | { type: "auth.login"; username: string }
40
+ | { type: "auth.logout" };
41
+
42
+ // 1. Typed setup — always use setup() before createMachine()
43
+ const loginSetup = setup({
29
44
  types: {
30
- context: {} as FormContext,
31
- events: {} as FormEvent,
45
+ context: {} as LoginContext,
46
+ events: {} as LoginEvent,
47
+ input: {} as Partial<LoginContext> | undefined,
32
48
  },
33
- }).createMachine({
34
- id: "form",
35
- initial: "idle",
36
- states: {
37
- idle: {
38
- on: {
39
- SUBMIT: "validating",
49
+ });
50
+
51
+ // 2. Machine — wraps config in formatPlayRouteTransitions for play.route support
52
+ const loginMachine = loginSetup.createMachine(
53
+ formatPlayRouteTransitions({
54
+ id: "login",
55
+ initial: "idle",
56
+ context: ({ input }) => ({
57
+ isAuthenticated: input?.isAuthenticated ?? false,
58
+ username: input?.username ?? null,
59
+ errorMessage: null,
60
+ params: input?.params ?? {},
61
+ query: input?.query ?? {},
62
+ }),
63
+
64
+ // Root-level event handlers — accessible from any state
65
+ on: {
66
+ "auth.login": {
67
+ target: ".dashboard",
68
+ // Guard: allow login only when not already authenticated
69
+ guard: ({ context }) => !context.isAuthenticated,
70
+ actions: loginSetup.assign({
71
+ isAuthenticated: true,
72
+ errorMessage: null,
73
+ // Typed by the event union — TypeScript narrows event.username safely
74
+ username: ({ event }) => (event.type === "auth.login" ? event.username : null),
75
+ }),
76
+ },
77
+ "auth.logout": {
78
+ target: ".idle",
79
+ guard: ({ context }) => context.isAuthenticated,
80
+ actions: loginSetup.assign({
81
+ isAuthenticated: false,
82
+ username: null,
83
+ }),
40
84
  },
41
85
  },
42
- validating: {
43
- on: {
44
- SUBMIT: [
45
- {
46
- target: "valid",
47
- cond: (event) => event.value.length >= 3,
48
- },
49
- {
50
- target: "invalid",
86
+
87
+ states: {
88
+ idle: {
89
+ id: "idle",
90
+ meta: {
91
+ route: "/",
92
+ view: {
93
+ component: "Home",
94
+ spec: {
95
+ root: "root",
96
+ elements: {
97
+ root: { type: "Home", props: { title: "Welcome" }, children: [] },
98
+ },
99
+ },
51
100
  },
52
- ],
101
+ },
53
102
  },
54
- },
55
- valid: {
56
- on: {
57
- RESET: "idle",
58
- SUBMIT: "validating",
103
+
104
+ login: {
105
+ id: "login",
106
+ meta: {
107
+ route: "/login",
108
+ view: {
109
+ component: "Login",
110
+ spec: {
111
+ root: "root",
112
+ // Local state store — initial value shown in the form field
113
+ state: { username: "" },
114
+ elements: {
115
+ root: {
116
+ type: "Login",
117
+ props: {
118
+ title: "Sign In",
119
+ // $bindState wires the prop to the local state store (two-way)
120
+ username: { $bindState: "/username" },
121
+ },
122
+ children: [],
123
+ on: {
124
+ // emit("submit") → resolves username from $state, calls login action
125
+ submit: {
126
+ action: "login",
127
+ params: { username: { $state: "/username" } },
128
+ },
129
+ },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ },
59
135
  },
60
- },
61
- invalid: {
62
- on: {
63
- RESET: "idle",
64
- SUBMIT: "validating",
136
+
137
+ dashboard: {
138
+ id: "dashboard",
139
+ meta: {
140
+ route: "/dashboard",
141
+ view: {
142
+ component: "Dashboard",
143
+ spec: {
144
+ root: "root",
145
+ elements: {
146
+ root: {
147
+ type: "Dashboard",
148
+ props: { title: "Dashboard" },
149
+ children: [],
150
+ on: {
151
+ logout: { action: "logout" },
152
+ },
153
+ },
154
+ },
155
+ },
156
+ },
157
+ },
158
+ // always-guard: redirect to login if not authenticated
159
+ always: {
160
+ guard: ({ context }) => !context.isAuthenticated,
161
+ target: "login",
162
+ },
65
163
  },
66
164
  },
67
- },
68
- });
165
+ }),
166
+ );
69
167
 
70
- // Usage
71
- let state = formMachine.initialState;
72
- console.log(state); // 'idle'
168
+ // 3. Factory and actor
169
+ const createPlayer = definePlayer({ machine: loginMachine });
170
+ const actor = createPlayer();
171
+ actor.start();
73
172
 
74
- // Submit with invalid input
75
- state = formMachine.transition(state, { type: "SUBMIT", value: "ab" });
76
- console.log(state); // 'validating'
173
+ // 4. Navigate to login page
174
+ actor.send({ type: "play.route", to: "#login" });
175
+ console.log(actor.getSnapshot().value); // "login"
77
176
 
78
- state = formMachine.transition(state, { type: "SUBMIT", value: "ab" });
79
- console.log(state); // 'invalid' (value too short)
177
+ // 5. Login with username
178
+ actor.send({ type: "auth.login", username: "alice" });
179
+ console.log(actor.getSnapshot().value); // "dashboard"
180
+ console.log(actor.getSnapshot().context.username); // "alice"
80
181
 
81
- // Reset and try valid input
82
- state = formMachine.transition(state, { type: "RESET" });
83
- console.log(state); // 'idle'
182
+ // 6. Guard prevents re-login while authenticated
183
+ actor.send({ type: "auth.login", username: "bob" }); // guard fires, transition rejected
184
+ console.log(actor.getSnapshot().context.username); // still "alice"
84
185
 
85
- state = formMachine.transition(state, { type: "SUBMIT", value: "abc" });
86
- console.log(state); // 'validating'
186
+ // 7. Logout
187
+ actor.send({ type: "auth.logout" });
188
+ console.log(actor.getSnapshot().value); // "idle"
189
+ console.log(actor.getSnapshot().context.username); // null
87
190
 
88
- state = formMachine.transition(state, { type: "SUBMIT", value: "abc" });
89
- console.log(state); // 'valid' (meets minimum length)
191
+ actor.stop();
90
192
  ```
91
193
 
92
- ## Code Explanation
194
+ ## `$bindState` and `$state` Pattern
93
195
 
94
- 1. **Guards (conditional transitions)** - The `cond` property defines a function that determines which transition to take. If the condition returns `true`, that transition is used; otherwise, the next transition in the array is tried.
196
+ `meta.view.spec` uses the `@json-render/core` spec format. Two special directives wire the component to a local per-state state store:
95
197
 
96
- 2. **Event payloads** - Events can carry data (`value: string`), allowing validation logic to inspect the actual input being validated.
198
+ | Directive | Direction | Usage |
199
+ | ----------------------------- | --------- | ----------------------------------------------------------- |
200
+ | `{ $bindState: "/username" }` | Two-way | Prop reads and writes the state store key `/username` |
201
+ | `{ $state: "/username" }` | Read-only | Reads the current value from the state store at `/username` |
97
202
 
98
- 3. **Multiple transitions per event** - When an event can lead to different states based on conditions, use an array of transition objects with guards.
99
-
100
- 4. **Validation logic** - Business rules (like minimum length) are encoded as guard functions, keeping validation logic co-located with state definitions.
101
-
102
- ## Key Concepts
103
-
104
- - **Guards**: Functions that conditionally allow or prevent transitions based on event data or current state
105
- - **Event payloads**: Events can carry data beyond just the event type
106
- - **Conditional transitions**: Array of transitions where the first matching guard is taken
107
- - **State-driven UI**: UI can render different feedback based on state (loading spinner in `validating`, error message in `invalid`)
108
-
109
- ## Advanced Pattern: Multiple Validation Rules
203
+ The `state:` object in the spec sets the initial values for the local store. When the user types in the form field, the renderer keeps the store in sync. On submit, action params read the final value via `$state`.
110
204
 
111
205
  ```typescript
112
- const advancedFormMachine = createMachine<FormState, FormEvent>({
113
- id: "advancedForm",
114
- initial: "idle",
115
- states: {
116
- idle: {
117
- on: { SUBMIT: "validating" },
118
- },
119
- validating: {
120
- on: {
121
- SUBMIT: [
122
- {
123
- target: "valid",
124
- cond: (event) => {
125
- const value = event.value;
126
- return (
127
- value.length >= 3 &&
128
- value.length <= 20 &&
129
- /^[a-zA-Z0-9]+$/.test(value)
130
- );
131
- },
132
- },
133
- { target: "invalid" },
134
- ],
135
- },
136
- },
137
- valid: {
138
- on: {
139
- RESET: "idle",
140
- SUBMIT: "validating",
141
- },
142
- },
143
- invalid: {
144
- on: {
145
- RESET: "idle",
146
- SUBMIT: "validating",
147
- },
148
- },
149
- },
150
- });
206
+ // In the machine spec — the renderer handles the rest:
207
+ spec: {
208
+ root: "root",
209
+ state: { username: "" }, // initial store value
210
+ elements: {
211
+ root: {
212
+ type: "Login",
213
+ props: {
214
+ username: { $bindState: "/username" }, // two-way binding
215
+ },
216
+ on: {
217
+ submit: {
218
+ action: "login",
219
+ params: { username: { $state: "/username" } }, // read on submit
220
+ },
221
+ },
222
+ },
223
+ },
224
+ }
151
225
  ```
152
226
 
153
- ## Extending for Real Forms
154
-
155
- For production forms, you might add:
227
+ ## Key Concepts
156
228
 
157
- - **Context**: Store error messages and validation details
158
- - **Actions**: Side effects like API calls or analytics tracking
159
- - **Nested states**: Break down `validating` into `checkingFormat`, `checkingUniqueness`, etc.
160
- - **History states**: Return to the last valid/invalid state after interruption
229
+ - **`setup({ types })`**: Always declare context, events, and input types before `createMachine`.
230
+ - **`setup.assign(...)`**: Use the scoped `assign` from your `setup` instance, not the bare one from `xstate`. This provides full type inference.
231
+ - **Guards as inline functions**: `({ context }) => !context.isAuthenticated` — guards check state invariants ("can I BE in this state?"), not event details.
232
+ - **`always` transitions**: Entry guards on states. Used for protected routes — if the guard fires, the machine redirects before the state is fully entered.
233
+ - **Lowercase dot-separated event types**: `"auth.login"`, `"auth.logout"`, `"play.route"` — not `SCREAMING_SNAKE_CASE`.
161
234
 
162
235
  ## Next Steps
163
236
 
164
- - **[Basic State Machine](basic-state-machine.md)** - Review foundational concepts
165
- - **[Traffic Light Example](traffic-light.md)** - See cyclic state transitions
166
- - **[API Documentation](../api/@xmachines/play/README.md)** - Learn about context, actions, and nested states
167
- - **[API Reference](../api/README.md)** - Understand design patterns and best practices
237
+ - **[Basic State Machine](basic-state-machine.md)** Foundational concepts without a view layer
238
+ - **[Routing Patterns](routing-patterns.md)** Parameter routes, relative routes, and `always` auth guards
239
+ - **[play-router README](../api/@xmachines/play-router/README.md)** Route extraction and tree building