@xmachines/docs 1.0.0-beta.10

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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/api/@xmachines/play/README.md +130 -0
  4. package/api/@xmachines/play/type-aliases/PlayEvent.md +81 -0
  5. package/api/@xmachines/play-actor/README.md +247 -0
  6. package/api/@xmachines/play-actor/classes/AbstractActor.md +520 -0
  7. package/api/@xmachines/play-actor/interfaces/Routable.md +29 -0
  8. package/api/@xmachines/play-actor/interfaces/ViewMetadata.md +17 -0
  9. package/api/@xmachines/play-actor/interfaces/Viewable.md +12 -0
  10. package/api/@xmachines/play-catalog/README.md +331 -0
  11. package/api/@xmachines/play-catalog/functions/defineCatalog.md +98 -0
  12. package/api/@xmachines/play-catalog/functions/defineComponents.md +134 -0
  13. package/api/@xmachines/play-catalog/type-aliases/Catalog.md +48 -0
  14. package/api/@xmachines/play-catalog/type-aliases/ComponentsFor.md +20 -0
  15. package/api/@xmachines/play-catalog/type-aliases/InferComponentProps.md +65 -0
  16. package/api/@xmachines/play-catalog/type-aliases/NoExtraKeys.md +17 -0
  17. package/api/@xmachines/play-react/README.md +423 -0
  18. package/api/@xmachines/play-react/classes/PlayErrorBoundary.md +613 -0
  19. package/api/@xmachines/play-react/functions/useSignalEffect.md +68 -0
  20. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryProps.md +15 -0
  21. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryState.md +14 -0
  22. package/api/@xmachines/play-react/interfaces/PlayRendererProps.md +15 -0
  23. package/api/@xmachines/play-react/variables/PlayRenderer.md +64 -0
  24. package/api/@xmachines/play-react-router/README.md +198 -0
  25. package/api/@xmachines/play-react-router/classes/ReactRouterBridge.md +321 -0
  26. package/api/@xmachines/play-react-router/classes/RouteMap.md +137 -0
  27. package/api/@xmachines/play-react-router/functions/PlayRouterProvider.md +19 -0
  28. package/api/@xmachines/play-react-router/functions/createRouteMapFromTree.md +35 -0
  29. package/api/@xmachines/play-react-router/interfaces/PlayRouteEvent.md +119 -0
  30. package/api/@xmachines/play-react-router/interfaces/PlayRouterProviderProps.md +14 -0
  31. package/api/@xmachines/play-react-router/interfaces/RouteMapping.md +17 -0
  32. package/api/@xmachines/play-react-router/interfaces/RouterBridge.md +104 -0
  33. package/api/@xmachines/play-react-router-demo/README.md +137 -0
  34. package/api/@xmachines/play-router/README.md +502 -0
  35. package/api/@xmachines/play-router/classes/BaseRouteMap.md +142 -0
  36. package/api/@xmachines/play-router/classes/RouterBridgeBase.md +300 -0
  37. package/api/@xmachines/play-router/functions/buildRouteTree.md +27 -0
  38. package/api/@xmachines/play-router/functions/connectRouter.md +67 -0
  39. package/api/@xmachines/play-router/functions/crawlMachine.md +92 -0
  40. package/api/@xmachines/play-router/functions/createBrowserHistory.md +47 -0
  41. package/api/@xmachines/play-router/functions/createRouteMap.md +53 -0
  42. package/api/@xmachines/play-router/functions/createRouter.md +76 -0
  43. package/api/@xmachines/play-router/functions/detectDuplicateRoutes.md +32 -0
  44. package/api/@xmachines/play-router/functions/extractMachineRoutes.md +64 -0
  45. package/api/@xmachines/play-router/functions/extractRoute.md +45 -0
  46. package/api/@xmachines/play-router/functions/findRouteById.md +37 -0
  47. package/api/@xmachines/play-router/functions/findRouteByPath.md +39 -0
  48. package/api/@xmachines/play-router/functions/getNavigableRoutes.md +35 -0
  49. package/api/@xmachines/play-router/functions/getRoutableRoutes.md +39 -0
  50. package/api/@xmachines/play-router/functions/routeExists.md +26 -0
  51. package/api/@xmachines/play-router/functions/validateRouteFormat.md +29 -0
  52. package/api/@xmachines/play-router/functions/validateStateExists.md +29 -0
  53. package/api/@xmachines/play-router/interfaces/BaseRouteMapping.md +27 -0
  54. package/api/@xmachines/play-router/interfaces/BrowserHistory.md +172 -0
  55. package/api/@xmachines/play-router/interfaces/BrowserWindow.md +69 -0
  56. package/api/@xmachines/play-router/interfaces/ConnectRouterOptions.md +13 -0
  57. package/api/@xmachines/play-router/interfaces/PlayRouteEvent.md +119 -0
  58. package/api/@xmachines/play-router/interfaces/RouteInfo.md +19 -0
  59. package/api/@xmachines/play-router/interfaces/RouteMap.md +56 -0
  60. package/api/@xmachines/play-router/interfaces/RouteNode.md +21 -0
  61. package/api/@xmachines/play-router/interfaces/RouteObject.md +21 -0
  62. package/api/@xmachines/play-router/interfaces/RouteTree.md +20 -0
  63. package/api/@xmachines/play-router/interfaces/RouterBridge.md +104 -0
  64. package/api/@xmachines/play-router/interfaces/StateVisit.md +15 -0
  65. package/api/@xmachines/play-router/interfaces/VanillaRouter.md +28 -0
  66. package/api/@xmachines/play-router/type-aliases/RouteMetadata.md +11 -0
  67. package/api/@xmachines/play-router-demo/README.md +137 -0
  68. package/api/@xmachines/play-signals/README.md +176 -0
  69. package/api/@xmachines/play-signals/interfaces/ComputedOptions.md +34 -0
  70. package/api/@xmachines/play-signals/interfaces/SignalComputed.md +49 -0
  71. package/api/@xmachines/play-signals/interfaces/SignalOptions.md +35 -0
  72. package/api/@xmachines/play-signals/interfaces/SignalState.md +68 -0
  73. package/api/@xmachines/play-signals/interfaces/SignalWatcher.md +97 -0
  74. package/api/@xmachines/play-signals/namespaces/Signal/README.md +22 -0
  75. package/api/@xmachines/play-signals/namespaces/Signal/classes/Computed.md +52 -0
  76. package/api/@xmachines/play-signals/namespaces/Signal/classes/State.md +72 -0
  77. package/api/@xmachines/play-signals/namespaces/Signal/interfaces/Options.md +19 -0
  78. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/README.md +21 -0
  79. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/classes/Watcher.md +85 -0
  80. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/currentComputed.md +13 -0
  81. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSinks.md +19 -0
  82. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSources.md +19 -0
  83. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSinks.md +19 -0
  84. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSources.md +19 -0
  85. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/untrack.md +25 -0
  86. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/unwatched.md +9 -0
  87. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/watched.md +9 -0
  88. package/api/@xmachines/play-signals/namespaces/Signal/variables/isComputed.md +19 -0
  89. package/api/@xmachines/play-signals/namespaces/Signal/variables/isState.md +19 -0
  90. package/api/@xmachines/play-signals/namespaces/Signal/variables/isWatcher.md +19 -0
  91. package/api/@xmachines/play-signals/type-aliases/WatcherNotify.md +32 -0
  92. package/api/@xmachines/play-solid/README.md +311 -0
  93. package/api/@xmachines/play-solid/interfaces/PlayRendererProps.md +15 -0
  94. package/api/@xmachines/play-solid/variables/PlayRenderer.md +70 -0
  95. package/api/@xmachines/play-solid-router/README.md +666 -0
  96. package/api/@xmachines/play-solid-router/classes/RouteMap.md +150 -0
  97. package/api/@xmachines/play-solid-router/classes/SolidRouterBridge.md +347 -0
  98. package/api/@xmachines/play-solid-router/functions/PlayRouterProvider.md +19 -0
  99. package/api/@xmachines/play-solid-router/functions/createRouteMap.md +32 -0
  100. package/api/@xmachines/play-solid-router/interfaces/AbstractActor.md +486 -0
  101. package/api/@xmachines/play-solid-router/interfaces/PlayRouteEvent.md +119 -0
  102. package/api/@xmachines/play-solid-router/interfaces/PlayRouterProviderProps.md +14 -0
  103. package/api/@xmachines/play-solid-router/interfaces/RouteMapping.md +14 -0
  104. package/api/@xmachines/play-solid-router/interfaces/RouterBridge.md +104 -0
  105. package/api/@xmachines/play-solid-router/type-aliases/RoutableActor.md +9 -0
  106. package/api/@xmachines/play-solid-router/type-aliases/SolidRouterHooks.md +51 -0
  107. package/api/@xmachines/play-solid-router-demo/README.md +127 -0
  108. package/api/@xmachines/play-tanstack-react-router/README.md +226 -0
  109. package/api/@xmachines/play-tanstack-react-router/classes/RouteMap.md +137 -0
  110. package/api/@xmachines/play-tanstack-react-router/classes/TanStackReactRouterBridge.md +348 -0
  111. package/api/@xmachines/play-tanstack-react-router/functions/PlayRouterProvider.md +19 -0
  112. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMap.md +53 -0
  113. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMapFromTree.md +35 -0
  114. package/api/@xmachines/play-tanstack-react-router/functions/extractParams.md +38 -0
  115. package/api/@xmachines/play-tanstack-react-router/functions/extractQueryParams.md +33 -0
  116. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouteEvent.md +119 -0
  117. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouterProviderProps.md +14 -0
  118. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteMapping.md +17 -0
  119. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteNavigateEvent.md +26 -0
  120. package/api/@xmachines/play-tanstack-react-router/interfaces/RouterBridge.md +104 -0
  121. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterInstance.md +9 -0
  122. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterLike.md +78 -0
  123. package/api/@xmachines/play-tanstack-react-router/variables/extractMachineRoutes.md +64 -0
  124. package/api/@xmachines/play-tanstack-react-router-demo/README.md +126 -0
  125. package/api/@xmachines/play-tanstack-solid-router/README.md +285 -0
  126. package/api/@xmachines/play-tanstack-solid-router/classes/RouteMap.md +150 -0
  127. package/api/@xmachines/play-tanstack-solid-router/classes/SolidRouterBridge.md +343 -0
  128. package/api/@xmachines/play-tanstack-solid-router/functions/PlayRouterProvider.md +19 -0
  129. package/api/@xmachines/play-tanstack-solid-router/functions/createRouteMap.md +32 -0
  130. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouteEvent.md +119 -0
  131. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouterProviderProps.md +14 -0
  132. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouteMapping.md +23 -0
  133. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouterBridge.md +104 -0
  134. package/api/@xmachines/play-tanstack-solid-router/type-aliases/RoutableActor.md +9 -0
  135. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterInstance.md +9 -0
  136. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterLike.md +78 -0
  137. package/api/@xmachines/play-tanstack-solid-router-demo/README.md +126 -0
  138. package/api/@xmachines/play-vue/README.md +292 -0
  139. package/api/@xmachines/play-vue/interfaces/PlayRendererProps.md +14 -0
  140. package/api/@xmachines/play-vue/variables/PlayRenderer.md +9 -0
  141. package/api/@xmachines/play-vue-router/README.md +604 -0
  142. package/api/@xmachines/play-vue-router/classes/RouteMap.md +209 -0
  143. package/api/@xmachines/play-vue-router/classes/VueBaseRouteMap.md +201 -0
  144. package/api/@xmachines/play-vue-router/classes/VueRouterBridge.md +360 -0
  145. package/api/@xmachines/play-vue-router/functions/createRouteMap.md +19 -0
  146. package/api/@xmachines/play-vue-router/interfaces/PlayRouteEvent.md +119 -0
  147. package/api/@xmachines/play-vue-router/interfaces/RouteMapping.md +15 -0
  148. package/api/@xmachines/play-vue-router/interfaces/RouterBridge.md +104 -0
  149. package/api/@xmachines/play-vue-router/type-aliases/RoutableActor.md +9 -0
  150. package/api/@xmachines/play-vue-router/variables/PlayRouterProvider.md +67 -0
  151. package/api/@xmachines/play-vue-router-demo/README.md +133 -0
  152. package/api/@xmachines/play-xstate/README.md +512 -0
  153. package/api/@xmachines/play-xstate/classes/PlayerActor.md +527 -0
  154. package/api/@xmachines/play-xstate/functions/buildRouteUrl.md +43 -0
  155. package/api/@xmachines/play-xstate/functions/composeGuards.md +79 -0
  156. package/api/@xmachines/play-xstate/functions/composeGuardsOr.md +67 -0
  157. package/api/@xmachines/play-xstate/functions/definePlayer.md +127 -0
  158. package/api/@xmachines/play-xstate/functions/deriveRoute.md +109 -0
  159. package/api/@xmachines/play-xstate/functions/eventMatches.md +40 -0
  160. package/api/@xmachines/play-xstate/functions/formatPlayRouteTransitions.md +54 -0
  161. package/api/@xmachines/play-xstate/functions/hasContext.md +42 -0
  162. package/api/@xmachines/play-xstate/functions/isAbsoluteRoute.md +41 -0
  163. package/api/@xmachines/play-xstate/functions/mergeViewProps.md +26 -0
  164. package/api/@xmachines/play-xstate/functions/negateGuard.md +61 -0
  165. package/api/@xmachines/play-xstate/functions/stateMatches.md +25 -0
  166. package/api/@xmachines/play-xstate/functions/validateComponentBinding.md +39 -0
  167. package/api/@xmachines/play-xstate/functions/validateViewProps.md +80 -0
  168. package/api/@xmachines/play-xstate/interfaces/CatalogEntry.md +16 -0
  169. package/api/@xmachines/play-xstate/interfaces/PlayerConfig.md +24 -0
  170. package/api/@xmachines/play-xstate/interfaces/PlayerOptions.md +26 -0
  171. package/api/@xmachines/play-xstate/interfaces/RouteContext.md +22 -0
  172. package/api/@xmachines/play-xstate/type-aliases/Catalog.md +21 -0
  173. package/api/@xmachines/play-xstate/type-aliases/ComposedGuard.md +14 -0
  174. package/api/@xmachines/play-xstate/type-aliases/Guard.md +34 -0
  175. package/api/@xmachines/play-xstate/type-aliases/GuardArray.md +20 -0
  176. package/api/@xmachines/play-xstate/type-aliases/PlayerFactory.md +29 -0
  177. package/api/@xmachines/play-xstate/type-aliases/RouteMachineConfig.md +45 -0
  178. package/api/@xmachines/play-xstate/type-aliases/RouteStateNode.md +51 -0
  179. package/api/@xmachines/play-xstate/type-aliases/ValidationResult.md +17 -0
  180. package/api/@xmachines/play-xstate/type-aliases/ViewMergeContext.md +35 -0
  181. package/api/@xmachines/shared/README.md +379 -0
  182. package/api/@xmachines/shared/functions/defineXmVitestConfig.md +29 -0
  183. package/api/@xmachines/shared/functions/xmAliases.md +24 -0
  184. package/api/README.md +25 -0
  185. package/api/llms.txt +26 -0
  186. package/examples/README.md +63 -0
  187. package/examples/basic-state-machine.md +70 -0
  188. package/examples/form-validation.md +167 -0
  189. package/examples/multi-router-integration.md +277 -0
  190. package/examples/routing-patterns.md +260 -0
  191. package/examples/traffic-light.md +99 -0
  192. package/guides/README.md +29 -0
  193. package/guides/getting-started.md +223 -0
  194. package/guides/installation.md +323 -0
  195. package/index.d.ts +3 -0
  196. package/index.js +4 -0
  197. package/package.json +54 -0
@@ -0,0 +1,167 @@
1
+ # Form Validation State Machine
2
+
3
+ Managing form state with validation logic using guards and conditional transitions.
4
+
5
+ ## Use Case
6
+
7
+ This example demonstrates a form with idle → validating → valid/invalid states. It's applicable to:
8
+
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
13
+
14
+ ## Complete Code
15
+
16
+ ```typescript
17
+ import { setup } from "xstate";
18
+
19
+ // Define context
20
+ interface FormContext {
21
+ // Context would store form data and validation state
22
+ }
23
+
24
+ // Define events
25
+ type FormEvent = { type: "SUBMIT"; value: string } | { type: "RESET" };
26
+
27
+ // Create machine
28
+ const formMachine = setup({
29
+ types: {
30
+ context: {} as FormContext,
31
+ events: {} as FormEvent,
32
+ },
33
+ }).createMachine({
34
+ id: "form",
35
+ initial: "idle",
36
+ states: {
37
+ idle: {
38
+ on: {
39
+ SUBMIT: "validating",
40
+ },
41
+ },
42
+ validating: {
43
+ on: {
44
+ SUBMIT: [
45
+ {
46
+ target: "valid",
47
+ cond: (event) => event.value.length >= 3,
48
+ },
49
+ {
50
+ target: "invalid",
51
+ },
52
+ ],
53
+ },
54
+ },
55
+ valid: {
56
+ on: {
57
+ RESET: "idle",
58
+ SUBMIT: "validating",
59
+ },
60
+ },
61
+ invalid: {
62
+ on: {
63
+ RESET: "idle",
64
+ SUBMIT: "validating",
65
+ },
66
+ },
67
+ },
68
+ });
69
+
70
+ // Usage
71
+ let state = formMachine.initialState;
72
+ console.log(state); // 'idle'
73
+
74
+ // Submit with invalid input
75
+ state = formMachine.transition(state, { type: "SUBMIT", value: "ab" });
76
+ console.log(state); // 'validating'
77
+
78
+ state = formMachine.transition(state, { type: "SUBMIT", value: "ab" });
79
+ console.log(state); // 'invalid' (value too short)
80
+
81
+ // Reset and try valid input
82
+ state = formMachine.transition(state, { type: "RESET" });
83
+ console.log(state); // 'idle'
84
+
85
+ state = formMachine.transition(state, { type: "SUBMIT", value: "abc" });
86
+ console.log(state); // 'validating'
87
+
88
+ state = formMachine.transition(state, { type: "SUBMIT", value: "abc" });
89
+ console.log(state); // 'valid' (meets minimum length)
90
+ ```
91
+
92
+ ## Code Explanation
93
+
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.
95
+
96
+ 2. **Event payloads** - Events can carry data (`value: string`), allowing validation logic to inspect the actual input being validated.
97
+
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
110
+
111
+ ```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
+ });
151
+ ```
152
+
153
+ ## Extending for Real Forms
154
+
155
+ For production forms, you might add:
156
+
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
161
+
162
+ ## Next Steps
163
+
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](/docs/api/xmachines/play/readme)** - Learn about context, actions, and nested states
167
+ - **[Architecture Guides](/docs/api/guides/core-concepts)** - Understand design patterns and best practices
@@ -0,0 +1,277 @@
1
+ # Multi-Router Integration - Renderer Prop Pattern
2
+
3
+ Learn how to integrate Play Architecture with three router modes using the unified renderer prop pattern introduced in
4
+
5
+ ## Overview
6
+
7
+ introduces a unified multi-router architecture supporting three integration modes with consistent API:
8
+
9
+ 1. **TanStack Router** - React + TanStack Router with full feature set
10
+ 2. **Vanilla Router** - JSX frameworks (Preact, Solid, Vue) with framework-agnostic router
11
+ 3. **Pure Browser** - Manual integration for jQuery, Alpine, vanilla JS
12
+
13
+ All modes use the **renderer prop pattern** where providers receive an `actor` and `router`, then pass a `renderer` function (not children).
14
+
15
+ ## Key Concepts
16
+
17
+ ### 1. Renderer Prop Pattern
18
+
19
+ All providers use a `renderer` prop that receives the actor and returns a ReactNode:
20
+
21
+ ```typescript
22
+ <PlayTanStackRouterProvider
23
+ actor={actor}
24
+ router={router}
25
+ renderer={(actor) => <PlayRenderer actor={actor} components={components} />}
26
+ />
27
+ ```
28
+
29
+ **Why renderer prop instead of children?**
30
+
31
+ - Explicit dependency injection (actor passed to renderer function)
32
+ - Type-safe integration (renderer function signature enforced)
33
+ - Consistent pattern across all three modes
34
+
35
+ ### 2. RouteMap as Explicit Prop
36
+
37
+ All providers require `routeMap` as an explicit prop. Routers fundamentally don't know about Play state IDs — the map bridges the gap:
38
+
39
+ ```typescript
40
+ const routeTree = createPlayRouter({ machine });
41
+ const router = createRouter({ routeTree, history: createMemoryHistory() });
42
+
43
+ <PlayTanStackRouterProvider
44
+ actor={actor}
45
+ router={router}
46
+ routeMap={routeMap} // Explicit mapping
47
+ renderer={(actor) => <PlayRenderer actor={actor} components={components} />}
48
+ />
49
+ ```
50
+
51
+ ### 3. Provider Composition Pattern
52
+
53
+ Providers wrap external providers (like TanStack's `RouterProvider`) and add Play integration layer:
54
+
55
+ ```typescript
56
+ // Provider wraps TanStack RouterProvider
57
+ <RouterProvider router={router}>
58
+ {/* Play integration layer */}
59
+ {renderer(actor)}
60
+ </RouterProvider>
61
+ ```
62
+
63
+ ## Mode 1: TanStack Router (React)
64
+
65
+ Complete integration with React and TanStack Router.
66
+
67
+ See [multi-router-example.ts](./src/multi-router-example.ts) for runnable example.
68
+
69
+ ```typescript
70
+ import { StrictMode } from 'react';
71
+ import { createRoot } from 'react-dom/client';
72
+ import { createRouter, createMemoryHistory } from '@tanstack/react-router';
73
+ import { createPlayRouter, PlayTanStackRouterProvider } from '@xmachines/play-tanstack-react-router';
74
+ import { PlayRenderer } from '@xmachines/play-react';
75
+ import { definePlayer } from '@xmachines/play-xstate';
76
+
77
+ // 1. Create actor
78
+ const createPlayer = definePlayer({ machine, catalog });
79
+ const actor = createPlayer();
80
+
81
+ // 2. Create router from machine
82
+ const routeTree = createPlayRouter({ machine });
83
+ const router = createRouter({
84
+ routeTree,
85
+ history: createMemoryHistory()
86
+ });
87
+
88
+ // 3. Define React components
89
+ const components = {
90
+ HomeView: ({ send }) => (
91
+ <div>
92
+ <h1>Home</h1>
93
+ <button onClick={() => send({ type: 'play.route', to: '/about' })}>
94
+ Go to About
95
+ </button>
96
+ </div>
97
+ ),
98
+ AboutView: ({ send }) => (
99
+ <div>
100
+ <h1>About</h1>
101
+ <button onClick={() => send({ type: 'play.route', to: '/' })}>
102
+ Go to Home
103
+ </button>
104
+ </div>
105
+ )
106
+ };
107
+
108
+ // 4. Render with provider + renderer prop
109
+ function App() {
110
+ return (
111
+ <PlayTanStackRouterProvider
112
+ actor={actor}
113
+ router={router}
114
+ renderer={(actor) => <PlayRenderer actor={actor} components={components} />}
115
+ />
116
+ );
117
+ }
118
+
119
+ const root = createRoot(document.getElementById('app')!);
120
+ root.render(<StrictMode><App /></StrictMode>);
121
+ ```
122
+
123
+ ### Benefits
124
+
125
+ - Full React ecosystem support
126
+ - Type-safe routing with TanStack Router
127
+ - Browser history integration automatic
128
+ - Signal reactivity via `PlayRenderer`
129
+
130
+ ## Mode 2: Vanilla Router (Preact, Solid, Vue)
131
+
132
+ Framework-agnostic router for JSX-based frameworks.
133
+
134
+ ```typescript
135
+ import { createPlayRouter, connectRouter } from '@xmachines/play-router';
136
+ import { definePlayer } from '@xmachines/play-xstate';
137
+
138
+ // 1. Create actor
139
+ const createPlayer = definePlayer({ machine, catalog });
140
+ const actor = createPlayer();
141
+
142
+ // 2. Create framework-agnostic router
143
+ const router = createPlayRouter({ machine });
144
+
145
+ // 3. Connect router with manual integration
146
+ const disconnect = connectRouter(actor, {
147
+ onNavigate: (path) => {
148
+ // Update your framework's router
149
+ myFrameworkRouter.push(path);
150
+ }
151
+ });
152
+
153
+ // 4. Framework-specific rendering
154
+ // Preact:
155
+ import { h } from 'preact';
156
+ const view = actor.currentView.get();
157
+ render(h(components[view.component], viewProps), container);
158
+
159
+ // Solid:
160
+ import { Dynamic } from 'solid-js/web';
161
+ <Dynamic component={components[view.component]} {...viewProps} />
162
+
163
+ // Vue 3:
164
+ import { h, resolveComponent } from 'vue';
165
+ h(resolveComponent(view.component), viewProps)
166
+ ```
167
+
168
+ ### Benefits
169
+
170
+ - Works with any JSX framework
171
+ - Manual control over routing integration
172
+ - No React dependency
173
+ - Same actor/signal API
174
+
175
+ ## Mode 3: Pure Browser (jQuery, Alpine, Vanilla JS)
176
+
177
+ Manual browser integration with no framework.
178
+
179
+ ```typescript
180
+ import { createPlayRouter, connectRouter } from "@xmachines/play-router";
181
+
182
+ // 1. Create actor
183
+ const actor = createPlayer();
184
+
185
+ // 2. Connect router with browser integration
186
+ const disconnect = connectRouter(actor, {
187
+ onNavigate: (path) => {
188
+ // Update browser history
189
+ window.history.pushState({}, "", path);
190
+ renderView();
191
+ },
192
+ });
193
+
194
+ // 3. Manual rendering
195
+ function renderView() {
196
+ const view = actor.currentView.get();
197
+
198
+ // Vanilla JS rendering
199
+ if (view.component === "HomeView") {
200
+ document.getElementById("app").innerHTML = `
201
+ <h1>Home</h1>
202
+ <button onclick="navigateToAbout()">Go to About</button>
203
+ `;
204
+ } else if (view.component === "AboutView") {
205
+ document.getElementById("app").innerHTML = `
206
+ <h1>About</h1>
207
+ <button onclick="navigateToHome()">Go to Home</button>
208
+ `;
209
+ }
210
+ }
211
+
212
+ // 4. Listen to browser back/forward
213
+ window.addEventListener("popstate", () => {
214
+ const path = window.location.pathname;
215
+ actor.send({ type: "play.route", to: path });
216
+ });
217
+
218
+ // 5. Manual event handlers
219
+ function navigateToAbout() {
220
+ actor.send({ type: "play.route", to: "/about" });
221
+ }
222
+
223
+ function navigateToHome() {
224
+ actor.send({ type: "play.route", to: "/" });
225
+ }
226
+
227
+ // Start
228
+ actor.start();
229
+ renderView();
230
+ ```
231
+
232
+ ### Benefits
233
+
234
+ - No framework dependency at all
235
+ - Maximum control and flexibility
236
+ - Works with jQuery, Alpine.js, HTMX, etc.
237
+ - Signals available via `actor.currentView.get()`
238
+
239
+ ## Provider API Parallelism
240
+
241
+ All three modes follow the same pattern:
242
+
243
+ | Concept | TanStack Mode | Vanilla Mode | Pure Browser Mode |
244
+ | ----------- | ---------------------------------- | ------------------------------------ | -------------------------- |
245
+ | Actor | `createPlayer()` | `createPlayer()` | `createPlayer()` |
246
+ | Router | `createRouter()` (TanStack) | `createPlayRouter()` | `connectRouter()` |
247
+ | Integration | `<PlayTanStackRouterProvider>` | Manual via `onNavigate` callback | Manual + `window.popstate` |
248
+ | Rendering | `<PlayRenderer>` via renderer prop | Framework-specific (h, Dynamic, etc) | `innerHTML` or DOM API |
249
+ | Events | Component `onClick` → `send()` | Same | Same |
250
+ | Signals | Observed by `useSignalEffect` | Manual `actor.currentView.get()` | Same |
251
+
252
+ The API parallelism ensures consistent patterns regardless of mode.
253
+
254
+ ## Architectural Invariants
255
+
256
+ All three modes preserve the 5 architectural invariants:
257
+
258
+ 1. **Actor Authority (INV-01):** Guards validate all navigation across all modes
259
+ 2. **Strict Separation (INV-02):** Business logic (machine) has zero framework imports
260
+ 3. **Signal-Only Reactivity (INV-05):** TC39 Signals work identically in all modes
261
+ 4. **Passive Infrastructure (INV-04):** Router observes actor, never decides
262
+ 5. **State-Driven Reset (INV-03):** Browser back/forward sends events to actor
263
+
264
+ ## Next Steps
265
+
266
+ - **[Routing Patterns](./routing-patterns.md)** - Learn play.route events with parameters
267
+ - **[Integration Example](./src/integration-example.ts)** - Complete authentication flow
268
+ - **[React + TanStack Router Demo](../../packages/play-tanstack-react-router/examples/demo-app/)** - Production example using TanStack mode
269
+ - **[Vue Router Demo](../../packages/play-vue-router/examples/demo/)** - Vue Composition API integration
270
+ - **[SolidJS Router Demo](../../packages/play-solidjs-router/examples/demo/)** - Solid signals integration
271
+
272
+ ## Learn More
273
+
274
+ - [play-tanstack-router README](../../packages/play-tanstack-react-router/README.md) - TanStack integration details
275
+ - [play-react README](../../packages/play-react/README.md) - React renderer documentation
276
+ - [play-router README](../../packages/play-router/README.md) - Framework-agnostic routing
277
+ - [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md) - Complete specification
@@ -0,0 +1,260 @@
1
+ # Routing Patterns - Play Architecture
2
+
3
+ Learn how to implement parameter-aware navigation using routing patterns with `meta.route` URL patterns and `play.route` events.
4
+
5
+ ## Overview
6
+
7
+ introduces enhanced routing capabilities that allow state machines to handle dynamic routes with parameters while maintaining Actor Authority (INV-01). The router observes actor state changes and syncs the browser URL, but the actor decides which routes are valid through guards.
8
+
9
+ ## Key Concepts
10
+
11
+ ### Route Marker
12
+
13
+ States with `meta.route` property are routable - they can receive `play.route` events and be navigated to by URL. States without `meta.route` are internal machine states that don't correspond to URLs.
14
+
15
+ ```typescript
16
+ states: {
17
+ dashboard: {
18
+ meta: {
19
+ route: '/dashboard', // Marks state as routable
20
+ view: { component: 'Dashboard' }
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ ### Play.route Events with Parameters
27
+
28
+ Use `play.route` events to navigate with parameters. Unlike `xstate.route` (which doesn't support parameters), `play.route` allows passing data alongside navigation:
29
+
30
+ ```typescript
31
+ // Navigate to profile with userId parameter
32
+ actor.send({
33
+ type: "play.route",
34
+ to: "/profile/user123",
35
+ params: { userId: "user123" },
36
+ });
37
+ ```
38
+
39
+ ### Parameter Patterns in meta.route
40
+
41
+ Define URL patterns with `:param` syntax for required parameters and `:param?` for optional ones:
42
+
43
+ ```typescript
44
+ meta: {
45
+ route: '/profile/:userId', // Required parameter
46
+ route: '/settings/:section?', // Optional parameter
47
+ }
48
+ ```
49
+
50
+ ## Complete Example
51
+
52
+ See [routing-example.ts](./src/routing-example.ts) for a complete runnable example demonstrating all patterns.
53
+
54
+ ### Machine Configuration
55
+
56
+ ```typescript
57
+ import { setup } from "xstate";
58
+ import { definePlayer } from "@xmachines/play-xstate";
59
+
60
+ const authMachine = setup({
61
+ types: {
62
+ context: {} as {
63
+ isAuthenticated: boolean;
64
+ userId: string;
65
+ routeParams: Record<string, string>;
66
+ },
67
+ events: {} as
68
+ | { type: "play.route"; to: string; params?: Record<string, string> }
69
+ | { type: "auth.login"; userId: string },
70
+ },
71
+ }).createMachine({
72
+ initial: "login",
73
+ context: {
74
+ isAuthenticated: false,
75
+ userId: "",
76
+ routeParams: {},
77
+ },
78
+ states: {
79
+ login: {
80
+ id: "login",
81
+ meta: {
82
+ route: "/login",
83
+ view: { component: "LoginView" },
84
+ },
85
+ on: {
86
+ "auth.login": {
87
+ target: "profile",
88
+ actions: ({ context, event }) => {
89
+ context.isAuthenticated = true;
90
+ context.userId = event.userId;
91
+ },
92
+ },
93
+ },
94
+ },
95
+
96
+ profile: {
97
+ id: "profile",
98
+ meta: {
99
+ route: "/profile/:userId",
100
+ view: {
101
+ component: "ProfileView",
102
+ userId: (ctx) => ctx.routeParams.userId || ctx.userId,
103
+ },
104
+ },
105
+ always: [
106
+ {
107
+ target: "login",
108
+ guard: ({ context }) => !context.isAuthenticated,
109
+ // Redirect to login if not authenticated
110
+ },
111
+ ],
112
+ on: {
113
+ "play.route": {
114
+ actions: ({ context, event }) => {
115
+ if (event.params?.userId) {
116
+ context.routeParams = { userId: event.params.userId };
117
+ }
118
+ },
119
+ },
120
+ },
121
+ },
122
+ },
123
+ });
124
+
125
+ const createPlayer = definePlayer({ machine: authMachine });
126
+ ```
127
+
128
+ ### Using the Actor
129
+
130
+ ```typescript
131
+ // Create and start actor
132
+ const actor = createPlayer();
133
+ actor.start();
134
+
135
+ // Login (transitions to profile)
136
+ actor.send({ type: "auth.login", userId: "user123" });
137
+
138
+ // Navigate to different profile with parameters
139
+ actor.send({
140
+ type: "play.route",
141
+ to: "/profile/user456",
142
+ params: { userId: "user456" },
143
+ });
144
+
145
+ // Parameter extracted and available in view
146
+ const view = actor.currentView.get();
147
+ console.log(view.userId); // 'user456'
148
+ ```
149
+
150
+ ## Pattern Matching for Dynamic Routes
151
+
152
+ Routes with parameters use pattern matching to resolve URL paths:
153
+
154
+ - `/profile/:userId` matches `/profile/user123`, `/profile/alice`, etc.
155
+ - `/settings/:section?` matches `/settings` (no section) or `/settings/privacy`
156
+
157
+ The router extracts parameters from the URL and passes them in `play.route` events, which the machine stores in context for view projection.
158
+
159
+ ## Guard Placement Architecture
160
+
161
+ **Core Principle:** Guards check if you can BE in a state (state entry), not if you can TAKE an event (event handlers).
162
+
163
+ ### Pattern 1: Using formatPlayRouteTransitions (RECOMMENDED)
164
+
165
+ ```typescript
166
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
167
+
168
+ const machineConfig = {
169
+ initial: "home",
170
+ context: { isAuthenticated: false },
171
+ states: {
172
+ home: { id: "home", meta: { route: "/" } },
173
+ profile: {
174
+ id: "profile",
175
+ meta: { route: "/profile/:userId" },
176
+ // Always-guard validates state entry
177
+ always: [
178
+ {
179
+ target: "login",
180
+ guard: ({ context }) => !context.isAuthenticated,
181
+ },
182
+ ],
183
+ },
184
+ },
185
+ };
186
+
187
+ // Utility handles routing infrastructure
188
+ const machine = createMachine(formatPlayRouteTransitions(machineConfig));
189
+ ```
190
+
191
+ **Why this works:**
192
+
193
+ - `formatPlayRouteTransitions` adds routing infrastructure (event.to matching)
194
+ - Always-guards handle business logic (authentication, authorization)
195
+ - Clear separation: routing layer (infrastructure) vs validation layer (business logic)
196
+
197
+ ### Pattern 2: Manual Always-Guards (Advanced)
198
+
199
+ For advanced users who need full control:
200
+
201
+ ```typescript
202
+ const machine = createMachine({
203
+ context: { intendedRoute: null, isAuthenticated: false },
204
+ on: {
205
+ "play.route": {
206
+ actions: assign({
207
+ intendedRoute: ({ event }) => event.to,
208
+ }),
209
+ },
210
+ },
211
+ always: [
212
+ {
213
+ target: "profile",
214
+ guard: ({ context }) => context.intendedRoute === "#profile" && context.isAuthenticated,
215
+ reenter: true,
216
+ },
217
+ {
218
+ target: "login",
219
+ guard: ({ context }) =>
220
+ context.intendedRoute === "#profile" && !context.isAuthenticated,
221
+ },
222
+ ],
223
+ });
224
+ ```
225
+
226
+ ### Anti-Pattern: Guards on Events
227
+
228
+ **NEVER do this:**
229
+
230
+ ```typescript
231
+ // ❌ WRONG - Guard on event checking event property
232
+ on: {
233
+ 'play.route': [
234
+ {
235
+ guard: ({ event }) => event.to === "#dashboard",
236
+ target: "dashboard"
237
+ }
238
+ ]
239
+ }
240
+ ```
241
+
242
+ **Why this is wrong:** The state doesn't care HOW it was entered (which event triggered it). Guards should validate state invariants: "Can I BE in this state given current context?" not "Can I TAKE this event?"
243
+
244
+ **Correct approach:** Use `formatPlayRouteTransitions` for routing infrastructure, use always-guards for state validation.
245
+
246
+ ### Actor Authority in Action
247
+
248
+ This demonstrates **Actor Authority (INV-01)** — the state machine controls navigation through guards, not the router. If a guard returns `false`, the transition is rejected and the URL doesn't change.
249
+
250
+ ## Next Steps
251
+
252
+ - **[Multi-Router Integration](./multi-router-integration.md)** - Learn about renderer prop pattern
253
+ - **[Integration Example](./src/integration-example.ts)** - See complete authentication flow with all patterns
254
+ - **[React + TanStack Router Demo](../../packages/play-tanstack-react-router/examples/demo-app/)** - Production example with all 5 architectural invariants
255
+
256
+ ## Learn More
257
+
258
+ - [XState Routes Documentation](https://stately.ai/docs/routes) - Official Stately routing patterns
259
+ - [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md) - Complete architectural specification
260
+ - [play-router README](../../packages/play-router/README.md) - Route extraction and tree building