@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,666 @@
1
+ [Documentation](../../README.md) / @xmachines/play-solid-router
2
+
3
+ # @xmachines/play-solid-router
4
+
5
+ **SolidJS Router adapter for XMachines Universal Player Architecture**
6
+
7
+ SolidJS Router adapter using `RouterBridgeBase` for consistent actor↔router sync.
8
+
9
+ ## Overview
10
+
11
+ `@xmachines/play-solid-router` provides seamless integration between SolidJS Router and XMachines state machines. Built on Solid's reactive primitives, it enables zero-adaptation signals synchronization.
12
+
13
+ Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md), this package implements:
14
+
15
+ - **Actor Authority (INV-01):** State machine controls navigation, router reflects decisions
16
+ - **Passive Infrastructure (INV-04):** Router observes `actor.currentRoute` signal
17
+ - **Signal-Only Reactivity (INV-05):** TC39 watcher lifecycle + Solid reactive owner integration
18
+
19
+ **Key Benefits:**
20
+
21
+ - **Bridge-first:** Extends shared `RouterBridgeBase` policy used by other adapters
22
+ - **Automatic tracking:** Uses Solid reactivity for router→actor while base class handles actor→router watcher lifecycle
23
+ - **Fine-grained reactivity:** Updates only affected components
24
+ - **Logic-driven navigation:** Business logic in state machines, not components
25
+ - **Type-safe parameters:** Route params flow through state machine context
26
+
27
+ **Framework Compatibility:**
28
+
29
+ - SolidJS 1.8.4+ (signals-native architecture)
30
+ - @solidjs/router 0.13.0+ (modern routing primitives)
31
+ - TC39 Signals polyfill integration
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install @solidjs/router@^0.13.0 solid-js@^1.8.0 @xmachines/play-solid-router @xmachines/play-solid
37
+ ```
38
+
39
+ **Peer dependencies:**
40
+
41
+ - `@solidjs/router` ^0.13.0 — SolidJS Router library
42
+ - `solid-js` ^1.8.0 — SolidJS runtime
43
+ - `@xmachines/play-solid` — Solid renderer (`PlayRenderer`)
44
+ - `@xmachines/play-actor` — Actor base
45
+ - `@xmachines/play-router` — Route extraction
46
+ - `@xmachines/play-signals` — TC39 Signals primitives
47
+
48
+ ## Quick Start
49
+
50
+ ```typescript
51
+ import { Router, Route, useNavigate, useLocation, useParams } from '@solidjs/router';
52
+ import { onCleanup } from 'solid-js';
53
+ import { SolidRouterBridge, createRouteMap } from '@xmachines/play-solid-router';
54
+ import { definePlayer } from '@xmachines/play-xstate';
55
+
56
+ function App() {
57
+ // 1. Get SolidJS Router hooks (MUST be inside component)
58
+ const navigate = useNavigate();
59
+ const location = useLocation();
60
+ const params = useParams();
61
+
62
+ // 2. Create route mapping from machine routes
63
+ const routeMap = createRouteMap(authMachine);
64
+
65
+ // 3. Create player with state machine
66
+ const createPlayer = definePlayer({
67
+ machine: authMachine,
68
+ catalog: componentCatalog
69
+ });
70
+ const actor = createPlayer();
71
+ actor.start();
72
+
73
+ // 4. Create bridge to sync actor and router
74
+ const bridge = new SolidRouterBridge(
75
+ navigate,
76
+ location,
77
+ params,
78
+ actor,
79
+ routeMap
80
+ );
81
+
82
+ // 5. Start synchronization
83
+ bridge.connect();
84
+
85
+ // 6. Cleanup on component disposal
86
+ onCleanup(() => {
87
+ bridge.disconnect();
88
+ });
89
+
90
+ return (
91
+ <Router>
92
+ <Route path="/" component={HomeView} />
93
+ <Route path="/profile/:userId" component={ProfileView} />
94
+ <Route path="/settings/:section?" component={SettingsView} />
95
+ </Router>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ## API Reference
101
+
102
+ ### `SolidRouterBridge`
103
+
104
+ Router adapter implementing the `RouterBridge` protocol for SolidJS Router.
105
+
106
+ **Type Signature:**
107
+
108
+ ```typescript
109
+ class SolidRouterBridge {
110
+ constructor(
111
+ navigate: ReturnType<typeof useNavigate>,
112
+ location: ReturnType<typeof useLocation>,
113
+ params: ReturnType<typeof useParams>,
114
+ actor: AbstractActor<any>,
115
+ routeMap: RouteMap,
116
+ );
117
+ dispose(): void;
118
+ }
119
+ ```
120
+
121
+ **Constructor Parameters:**
122
+
123
+ - `navigate` - Function from `useNavigate()` hook (signals-aware navigation)
124
+ - `location` - Object from `useLocation()` hook (reactive pathname, search, hash)
125
+ - `params` - Object from `useParams()` hook (reactive route parameters)
126
+ - `actor` - XMachines actor instance (from `definePlayer().actor`)
127
+ - `routeMap` - Bidirectional state ID ↔ path mapping
128
+
129
+ **Methods:**
130
+
131
+ - `connect()` - Start bidirectional synchronization.
132
+ - `disconnect()` - Stop synchronization and cleanup bridge resources.
133
+ - `dispose()` - Alias of `disconnect()`.
134
+
135
+ **Internal Behavior:**
136
+
137
+ - Uses `RouterBridgeBase` TC39 watcher lifecycle for actor→router synchronization
138
+ - Updates SolidJS Router via `navigate(path)` when actor state changes
139
+ - Uses `createEffect(on(...))` to watch `location.pathname` signal
140
+ - Sends `play.route` events to actor when user navigates
141
+ - Prevents circular updates with path tracking and processing flags
142
+
143
+ ### `RouteMap`
144
+
145
+ Bidirectional mapping between XMachines state IDs and SolidJS Router paths with pattern matching support.
146
+
147
+ `RouteMap` extends `BaseRouteMap` from `@xmachines/play-router`, inheriting bucket-indexed
148
+ bidirectional route matching. No routing logic lives in the adapter itself.
149
+
150
+ ```typescript
151
+ interface RouteMapping {
152
+ readonly stateId: string;
153
+ readonly path: string;
154
+ }
155
+
156
+ // RouteMap is a thin subclass of BaseRouteMap — no extra methods
157
+ class RouteMap extends BaseRouteMap {}
158
+
159
+ // Inherited API:
160
+ routeMap.getStateIdByPath(path: string): string | null
161
+ routeMap.getPathByStateId(stateId: string): string | null
162
+ ```
163
+
164
+ `getStateIdByPath` and `getPathByStateId` both return `null` (not `undefined`) for misses.
165
+
166
+ **Constructor Parameters:**
167
+
168
+ - `mappings` - Array of `{ stateId, path }` entries:
169
+ - `stateId` — State machine state ID (e.g., `'#profile'`)
170
+ - `path` — SolidJS Router path pattern (e.g., `'/profile/:userId'`)
171
+
172
+ **Methods:**
173
+
174
+ - `getPathByStateId(stateId)` — Find path pattern from state ID
175
+ - `getStateIdByPath(path)` — Find state ID from path with pattern matching (supports `:param` and `:param?` syntax)
176
+
177
+ **Pattern Matching:**
178
+
179
+ Uses bucket-indexed RegExp matching for dynamic routes:
180
+
181
+ ```typescript
182
+ const routeMap = new RouteMap([{ stateId: "#settings", path: "/settings/:section?" }]);
183
+
184
+ routeMap.getStateIdByPath("/settings"); // '#settings'
185
+ routeMap.getStateIdByPath("/settings/account"); // '#settings'
186
+ routeMap.getStateIdByPath("/settings/privacy"); // '#settings'
187
+ routeMap.getStateIdByPath("/other"); // null
188
+ ```
189
+
190
+ ## Examples
191
+
192
+ ### Basic Usage: Simple 2-3 Route Setup
193
+
194
+ ```typescript
195
+ import { Router, Route } from '@solidjs/router';
196
+ import { createSignal } from 'solid-js';
197
+ import { defineCatalog } from '@xmachines/play-catalog';
198
+
199
+ // State machine with 3 states
200
+ const appMachine = setup({
201
+ types: {
202
+ events: {} as PlayRouteEvent
203
+ }
204
+ }).createMachine({
205
+ id: 'app',
206
+ initial: 'home',
207
+ states: {
208
+ home: {
209
+ meta: { route: '/', view: { component: 'Home' } }
210
+ },
211
+ about: {
212
+ meta: { route: '/about', view: { component: 'About' } }
213
+ },
214
+ contact: {
215
+ meta: { route: '/contact', view: { component: 'Contact' } }
216
+ }
217
+ }
218
+ });
219
+
220
+ const catalog = defineCatalog({
221
+ Home,
222
+ About,
223
+ Contact,
224
+ });
225
+
226
+ // Component setup
227
+ function App() {
228
+ const navigate = useNavigate();
229
+ const location = useLocation();
230
+ const params = useParams();
231
+
232
+ const routeMap = createRouteMap(appMachine);
233
+
234
+ const createPlayer = definePlayer({ machine: appMachine, catalog });
235
+ const actor = createPlayer();
236
+ actor.start();
237
+ const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
238
+
239
+ onCleanup(() => bridge.dispose());
240
+
241
+ return (
242
+ <Router>
243
+ <Route path="/" component={Home} />
244
+ <Route path="/about" component={About} />
245
+ <Route path="/contact" component={Contact} />
246
+ </Router>
247
+ );
248
+ }
249
+ ```
250
+
251
+ ### Parameter Handling: Dynamic Routes with `:param` Syntax
252
+
253
+ ```typescript
254
+ // State machine with parameter routes
255
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
256
+ import { defineCatalog } from "@xmachines/play-catalog";
257
+
258
+ const machineConfig = {
259
+ id: 'app',
260
+ context: {},
261
+ states: {
262
+ profile: {
263
+ meta: {
264
+ route: '/profile/:userId',
265
+ view: { component: 'Profile' },
266
+ },
267
+ },
268
+ settings: {
269
+ meta: {
270
+ route: '/settings/:section?',
271
+ view: { component: 'Settings' },
272
+ },
273
+ }
274
+ }
275
+ };
276
+
277
+ const appMachine = setup({
278
+ types: {
279
+ context: {} as { userId?: string; section?: string },
280
+ events: {} as PlayRouteEvent
281
+ }
282
+ }).createMachine(formatPlayRouteTransitions(machineConfig));
283
+
284
+ const catalog = defineCatalog({
285
+ Profile,
286
+ Settings,
287
+ });
288
+
289
+ // Router with dynamic routes
290
+ function App() {
291
+ const navigate = useNavigate();
292
+ const location = useLocation();
293
+ const params = useParams();
294
+
295
+ const routeMap = createRouteMap(appMachine);
296
+
297
+ const createPlayer = definePlayer({ machine: appMachine, catalog });
298
+ const actor = createPlayer();
299
+ actor.start();
300
+ const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
301
+
302
+ onCleanup(() => bridge.dispose());
303
+
304
+ return (
305
+ <Router>
306
+ <Route path="/profile/:userId" component={Profile} />
307
+ <Route path="/settings/:section?" component={Settings} />
308
+ </Router>
309
+ );
310
+ }
311
+ ```
312
+
313
+ **Usage in component:**
314
+
315
+ ```tsx
316
+ function ProfileButton(props: { userId: string }) {
317
+ return (
318
+ <button
319
+ onClick={() =>
320
+ props.actor.send({
321
+ type: "play.route",
322
+ to: "#profile",
323
+ params: { userId: props.userId },
324
+ })
325
+ }
326
+ >
327
+ View Profile
328
+ </button>
329
+ );
330
+ }
331
+ ```
332
+
333
+ ### Query Parameters: Search/Filters via Query Strings
334
+
335
+ ```typescript
336
+ // State machine with query param handling
337
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
338
+ import { defineCatalog } from "@xmachines/play-catalog";
339
+
340
+ const machineConfig = {
341
+ context: { query: '', filters: {} },
342
+ states: {
343
+ search: {
344
+ meta: {
345
+ route: '/search',
346
+ view: { component: 'Search' },
347
+ },
348
+ }
349
+ }
350
+ };
351
+
352
+ const searchMachine = setup({
353
+ types: {
354
+ context: {} as { query: string; filters: Record<string, string> },
355
+ events: {} as PlayRouteEvent
356
+ }
357
+ }).createMachine(formatPlayRouteTransitions(machineConfig));
358
+
359
+ const catalog = defineCatalog({
360
+ Search,
361
+ });
362
+
363
+ const player = definePlayer({ machine: searchMachine, catalog });
364
+
365
+ // Component sends query params
366
+ function SearchBar(props) {
367
+ const [searchTerm, setSearchTerm] = createSignal('');
368
+
369
+ function handleSearch() {
370
+ props.actor.send({
371
+ type: 'play.route',
372
+ to: '#search',
373
+ query: { q: searchTerm(), tag: 'typescript' }
374
+ });
375
+ }
376
+
377
+ return (
378
+ <div>
379
+ <input
380
+ value={searchTerm()}
381
+ onInput={(e) => setSearchTerm(e.target.value)}
382
+ />
383
+ <button onClick={handleSearch}>Search</button>
384
+ </div>
385
+ );
386
+ }
387
+ ```
388
+
389
+ **SolidJS Router automatically reflects query params in URL:**
390
+
391
+ - `/search?q=xmachines&tag=typescript`
392
+
393
+ ### Protected Routes: Authentication Guards
394
+
395
+ ```typescript
396
+ // State machine with auth guards
397
+ import { defineCatalog } from "@xmachines/play-catalog";
398
+
399
+ const authMachine = setup({
400
+ types: {
401
+ context: {} as { isAuthenticated: boolean },
402
+ events: {} as PlayRouteEvent | { type: "login" } | { type: "logout" },
403
+ },
404
+ }).createMachine({
405
+ context: { isAuthenticated: false },
406
+ initial: "home",
407
+ states: {
408
+ home: {
409
+ meta: { route: "/", view: { component: "Home" } },
410
+ },
411
+ login: {
412
+ meta: { route: "/login", view: { component: "Login" } },
413
+ on: {
414
+ login: {
415
+ target: "dashboard",
416
+ actions: assign({ isAuthenticated: true }),
417
+ },
418
+ },
419
+ },
420
+ dashboard: {
421
+ meta: { route: "/dashboard", view: { component: "Dashboard" } },
422
+ always: {
423
+ guard: ({ context }) => !context.isAuthenticated,
424
+ target: "login",
425
+ },
426
+ },
427
+ },
428
+ });
429
+
430
+ const catalog = defineCatalog({
431
+ Home,
432
+ Login,
433
+ Dashboard,
434
+ });
435
+
436
+ const player = definePlayer({ machine: authMachine, catalog });
437
+ ```
438
+
439
+ **Guard behavior:**
440
+
441
+ - User navigates to `/dashboard`
442
+ - Bridge sends `play.route` event to actor
443
+ - Actor's `always` guard checks `isAuthenticated`
444
+ - If `false`, actor transitions to `login` state
445
+ - Bridge detects state change via `createEffect`, redirects to `/login`
446
+ - Actor Authority principle enforced
447
+
448
+ ### Cleanup: Proper Disposal on Component Unmount
449
+
450
+ ```tsx
451
+ import { onCleanup } from "solid-js";
452
+ import { SolidRouterBridge } from "@xmachines/play-solid-router";
453
+
454
+ function App() {
455
+ const navigate = useNavigate();
456
+ const location = useLocation();
457
+ const params = useParams();
458
+ const actor = useContext(ActorContext);
459
+ const routeMap = useContext(RouteMapContext);
460
+
461
+ const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
462
+
463
+ // CRITICAL: Cleanup effects
464
+ onCleanup(() => {
465
+ bridge.dispose();
466
+ });
467
+
468
+ return <Router>...</Router>;
469
+ }
470
+ ```
471
+
472
+ **Why cleanup matters:**
473
+
474
+ - `createEffect` subscriptions continue after disposal (memory leak)
475
+ - Multiple bridge instances send duplicate events
476
+ - Tests fail with "Cannot send to stopped actor" errors
477
+ - Solid's fine-grained reactivity tracks disposed components
478
+
479
+ ## Architecture
480
+
481
+ ### Bidirectional Sync (Actor ↔ Router)
482
+
483
+ **Actor → Router (Signal-driven via createEffect):**
484
+
485
+ 1. Actor transitions to new state with `meta.route`
486
+ 2. `actor.currentRoute` signal updates
487
+ 3. `createEffect(on(...))` fires with new route value
488
+ 4. Bridge extracts state ID from signal
489
+ 5. Bridge looks up path via `routeMap.getPathByStateId(stateId)`
490
+ 6. Bridge calls `navigate(path)`
491
+ 7. SolidJS Router updates URL and renders component
492
+
493
+ **Router → Actor (Location tracking via createEffect):**
494
+
495
+ 1. User clicks link or browser back button
496
+ 2. `location.pathname` signal updates
497
+ 3. `createEffect(on(...))` fires with new pathname
498
+ 4. Bridge looks up state ID via `routeMap.getStateIdByPath(pathname)`
499
+ 5. Bridge extracts params from `useParams()` reactive object
500
+ 6. Bridge sends `play.route` event to actor
501
+ 7. Actor validates navigation (guards, transitions)
502
+ 8. If accepted: Actor transitions, signal updates, URL stays
503
+ 9. If rejected: Actor redirects, bridge corrects URL via `navigate()`
504
+
505
+ ### Circular Update Prevention
506
+
507
+ **Multi-layer guards prevent infinite loops:**
508
+
509
+ 1. **`lastSyncedPath` tracking:** Stores last synchronized path, skips if unchanged
510
+ 2. **`isProcessingNavigation` flag:** Set during navigation processing, prevents concurrent syncs
511
+ 3. **Effect timing:** Solid's batched updates and `defer: true` option prevent rapid cycles
512
+
513
+ **Signals-native pattern:**
514
+
515
+ ```typescript
516
+ // Actor → Router
517
+ createEffect(
518
+ on(
519
+ () => this.actor.currentRoute.get(),
520
+ (route) => {
521
+ if (!route || route === this.lastSyncedPath || this.isProcessingNavigation) {
522
+ return;
523
+ }
524
+ this.lastSyncedPath = route;
525
+ this.navigate(route);
526
+ },
527
+ { defer: true },
528
+ ),
529
+ );
530
+
531
+ // Router → Actor
532
+ createEffect(
533
+ on(
534
+ () => this.location.pathname,
535
+ (pathname) => {
536
+ if (pathname === this.lastSyncedPath || this.isProcessingNavigation) {
537
+ return;
538
+ }
539
+ this.isProcessingNavigation = true;
540
+ this.actor.send({ type: "play.route", to: stateId, params });
541
+ this.isProcessingNavigation = false;
542
+ },
543
+ { defer: true },
544
+ ),
545
+ );
546
+ ```
547
+
548
+ ### Relationship to Other Packages
549
+
550
+ **Package Dependencies:**
551
+
552
+ - `@xmachines/play` - Protocol interfaces (`PlayRouteEvent`, `RouterBridge`)
553
+ - `@xmachines/play-actor` - Actor base class with signal protocol
554
+ - `@xmachines/play-router` - Route extraction and pattern matching
555
+ - `@xmachines/play-signals` - TC39 Signals polyfill for reactivity
556
+ - `@xmachines/play-xstate` - XState integration via `definePlayer()`
557
+
558
+ **Architecture Layers:**
559
+
560
+ ```
561
+ ┌─────────────────────────────────────┐
562
+ │ Solid Components (View Layer) │
563
+ │ - Props include actor reference │
564
+ │ - Sends play.route events │
565
+ └─────────────────────────────────────┘
566
+
567
+ ┌─────────────────────────────────────┐
568
+ │ SolidRouterBridge (Adapter) │
569
+ │ - createEffect(actor.currentRoute) │
570
+ │ - createEffect(location.pathname) │
571
+ └─────────────────────────────────────┘
572
+ ↕ ↕
573
+ ┌─────────────┐ ┌──────────────────┐
574
+ │ SolidJS │ │ XMachines Actor │
575
+ │ Router │ │ (Business Logic) │
576
+ │ (Infra) │ │ │
577
+ └─────────────┘ └──────────────────┘
578
+ ```
579
+
580
+ ### Signals Integration (SolidJS-Specific)
581
+
582
+ **Why signals-native matters:**
583
+
584
+ - **Zero adaptation:** Solid signals and TC39 Signals share reactive primitives
585
+ - **Automatic tracking:** `createEffect(on(...))` tracks dependencies without manual Watcher setup
586
+ - **Fine-grained updates:** Only affected components re-render (not full tree)
587
+ - **Batched updates:** Solid batches multiple signal changes in single render cycle
588
+
589
+ **Hook context requirement (Pitfall 2):**
590
+
591
+ SolidJS hooks (`useNavigate`, `useLocation`, `useParams`) **MUST** be called inside component tree:
592
+
593
+ ```tsx
594
+ // ❌ WRONG: Bridge created outside component
595
+ const navigate = useNavigate(); // ERROR: No reactive context
596
+ const bridge = new SolidRouterBridge(navigate, ...);
597
+
598
+ // ✅ CORRECT: Bridge created inside component
599
+ function App() {
600
+ const navigate = useNavigate();
601
+ const location = useLocation();
602
+ const params = useParams();
603
+ const bridge = new SolidRouterBridge(navigate, location, params, actor, routeMap);
604
+ onCleanup(() => bridge.dispose());
605
+ return <Router>...</Router>;
606
+ }
607
+ ```
608
+
609
+ **Why:** Solid's reactivity system requires reactive ownership context. Hooks create tracked scopes that exist only within component lifecycle.
610
+
611
+ ### Pattern Matching for Dynamic Routes
612
+
613
+ **Bucket-indexed matching via `BaseRouteMap`:**
614
+
615
+ Routes are grouped by their first path segment into buckets. On each lookup only the
616
+ relevant bucket (plus the wildcard `*` bucket for `:param`-first routes) is scanned —
617
+ typically far fewer than all registered routes.
618
+
619
+ **Supported syntax:**
620
+
621
+ - `:param` - Required parameter (e.g., `/profile/:userId` matches `/profile/123`)
622
+ - `:param?` - Optional parameter (e.g., `/settings/:section?` matches `/settings` and `/settings/account`)
623
+ - Wildcards via `*` (future enhancement)
624
+
625
+ **Example:**
626
+
627
+ ```typescript
628
+ const routeMap = new RouteMap([
629
+ { stateId: "#profile", path: "/profile/:userId" },
630
+ { stateId: "#settings", path: "/settings/:section?" },
631
+ ]);
632
+
633
+ routeMap.getStateIdByPath("/profile/123"); // '#profile'
634
+ routeMap.getStateIdByPath("/settings"); // '#settings'
635
+ routeMap.getStateIdByPath("/settings/privacy"); // '#settings'
636
+ ```
637
+
638
+ ## License
639
+
640
+ Copyright (c) 2016 [Mikael Karon](mailto:mikael@karon.se). All rights reserved.
641
+
642
+ This work is licensed under the terms of the MIT license.
643
+ For a copy, see <https://opensource.org/licenses/MIT>.
644
+
645
+ ## Classes
646
+
647
+ - [RouteMap](classes/RouteMap.md)
648
+ - [SolidRouterBridge](classes/SolidRouterBridge.md)
649
+
650
+ ## Interfaces
651
+
652
+ - [AbstractActor](interfaces/AbstractActor.md)
653
+ - [PlayRouteEvent](interfaces/PlayRouteEvent.md)
654
+ - [PlayRouterProviderProps](interfaces/PlayRouterProviderProps.md)
655
+ - [RouteMapping](interfaces/RouteMapping.md)
656
+ - [RouterBridge](interfaces/RouterBridge.md)
657
+
658
+ ## Type Aliases
659
+
660
+ - [RoutableActor](type-aliases/RoutableActor.md)
661
+ - [SolidRouterHooks](type-aliases/SolidRouterHooks.md)
662
+
663
+ ## Functions
664
+
665
+ - [createRouteMap](functions/createRouteMap.md)
666
+ - [PlayRouterProvider](functions/PlayRouterProvider.md)