@xmachines/docs 1.0.0-beta.25 → 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.
- package/api/@xmachines/play/classes/PlayError.md +10 -4
- package/api/@xmachines/play/type-aliases/PlayEvent.md +2 -2
- package/api/@xmachines/play-actor/README.md +4 -0
- package/api/@xmachines/play-actor/classes/AbstractActor.md +49 -92
- package/api/@xmachines/play-actor/functions/typedSpec.md +57 -0
- package/api/@xmachines/play-actor/interfaces/PlaySpec.md +9 -18
- package/api/@xmachines/play-actor/interfaces/Routable.md +5 -21
- package/api/@xmachines/play-actor/interfaces/ViewMetadata.md +6 -6
- package/api/@xmachines/play-actor/interfaces/Viewable.md +5 -6
- package/api/@xmachines/play-dom/README.md +24 -8
- package/api/@xmachines/play-dom/classes/PlayRenderer.md +4 -4
- package/api/@xmachines/play-dom/functions/connectRenderer.md +1 -1
- package/api/@xmachines/play-dom/functions/defineRegistry.md +61 -0
- package/api/@xmachines/play-dom/functions/renderSpec.md +29 -12
- package/api/@xmachines/play-dom/interfaces/ComponentContext.md +62 -0
- package/api/@xmachines/play-dom/interfaces/ConnectRendererOptions.md +9 -9
- package/api/@xmachines/play-dom/interfaces/DefineRegistryOptions.md +25 -0
- package/api/@xmachines/play-dom/interfaces/DefineRegistryResult.md +18 -0
- package/api/@xmachines/play-dom/interfaces/DomRenderContext.md +13 -10
- package/api/@xmachines/play-dom/interfaces/EventHandle.md +29 -0
- package/api/@xmachines/play-dom/interfaces/PlayDomOptions.md +5 -5
- package/api/@xmachines/play-dom/type-aliases/ComponentFn.md +53 -0
- package/api/@xmachines/play-dom/type-aliases/ComponentRegistry.md +21 -0
- package/api/@xmachines/play-dom/type-aliases/DomComponentRenderer.md +16 -3
- package/api/@xmachines/play-dom/type-aliases/DomRegistry.md +5 -2
- package/api/@xmachines/play-dom-router/README.md +10 -0
- package/api/@xmachines/play-dom-router/functions/connectRouter.md +18 -46
- package/api/@xmachines/play-dom-router/functions/createBrowserHistory.md +1 -1
- package/api/@xmachines/play-dom-router/functions/createRouteMap.md +38 -0
- package/api/@xmachines/play-dom-router/functions/createRouter.md +1 -1
- package/api/@xmachines/play-dom-router/interfaces/BrowserHistory.md +16 -16
- package/api/@xmachines/play-dom-router/interfaces/BrowserWindow.md +16 -16
- package/api/@xmachines/play-dom-router/interfaces/ConnectRouterOptions.md +6 -6
- package/api/@xmachines/play-dom-router/interfaces/PlayRouteEvent.md +119 -0
- package/api/@xmachines/play-dom-router/interfaces/RouteMap.md +114 -0
- package/api/@xmachines/play-dom-router/interfaces/RouteMapLike.md +50 -0
- package/api/@xmachines/play-dom-router/interfaces/RouteMapping.md +27 -0
- package/api/@xmachines/play-dom-router/interfaces/RouterBridge.md +104 -0
- package/api/@xmachines/play-dom-router/interfaces/VanillaRouter.md +6 -6
- package/api/@xmachines/play-dom-router/type-aliases/RoutableActor.md +9 -0
- package/api/@xmachines/play-dom-router-demo/README.md +46 -51
- package/api/@xmachines/play-react/README.md +4 -4
- package/api/@xmachines/play-react/classes/PlayErrorBoundary.md +31 -5
- package/api/@xmachines/play-react/functions/defineRegistry.md +2 -0
- package/api/@xmachines/play-react/functions/useActor.md +1 -1
- package/api/@xmachines/play-react/functions/useBoundProp.md +2 -0
- package/api/@xmachines/play-react/functions/useSignalEffect.md +1 -1
- package/api/@xmachines/play-react/functions/useStateBinding.md +2 -0
- package/api/@xmachines/play-react/interfaces/ComponentContext.md +2 -0
- package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryProps.md +4 -4
- package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryState.md +3 -3
- package/api/@xmachines/play-react/interfaces/PlayRendererProps.md +7 -7
- package/api/@xmachines/play-react/type-aliases/ComponentFn.md +2 -0
- package/api/@xmachines/play-react/type-aliases/PlayActor.md +1 -1
- package/api/@xmachines/play-react/variables/PlayRenderer.md +1 -1
- package/api/@xmachines/play-react-router/README.md +5 -1
- package/api/@xmachines/play-react-router/classes/ReactRouterBridge.md +102 -25
- package/api/@xmachines/play-react-router/classes/RouteMap.md +17 -33
- package/api/@xmachines/play-react-router/functions/PlayRouterProvider.md +8 -1
- package/api/@xmachines/play-react-router/functions/createRouteMapFromTree.md +21 -11
- package/api/@xmachines/play-react-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-react-router/interfaces/PlayRouterProviderProps.md +7 -7
- package/api/@xmachines/play-react-router/interfaces/RouteMapping.md +18 -8
- package/api/@xmachines/play-react-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-router/README.md +42 -5
- package/api/@xmachines/play-router/classes/BaseRouteMap.md +12 -19
- package/api/@xmachines/play-router/classes/RouterBridgeBase.md +100 -25
- package/api/@xmachines/play-router/functions/buildPlayRouteEvent.md +1 -1
- package/api/@xmachines/play-router/functions/buildRouteTree.md +1 -1
- package/api/@xmachines/play-router/functions/createRouteMap.md +1 -1
- package/api/@xmachines/play-router/functions/createRouteMapFromMachine.md +38 -0
- package/api/@xmachines/play-router/functions/createRouteMapFromTree.md +45 -0
- package/api/@xmachines/play-router/functions/detectDuplicateRoutes.md +1 -1
- package/api/@xmachines/play-router/functions/extractMachineRoutes.md +1 -1
- package/api/@xmachines/play-router/functions/extractQuery.md +1 -1
- package/api/@xmachines/play-router/functions/extractRouteParams.md +46 -0
- package/api/@xmachines/play-router/functions/findRouteById.md +1 -1
- package/api/@xmachines/play-router/functions/findRouteByPath.md +1 -1
- package/api/@xmachines/play-router/functions/getNavigableRoutes.md +1 -1
- package/api/@xmachines/play-router/functions/getRoutableRoutes.md +1 -1
- package/api/@xmachines/play-router/functions/getTransitionReachableRoutes.md +1 -1
- package/api/@xmachines/play-router/functions/isRouteReachable.md +1 -1
- package/api/@xmachines/play-router/functions/machineToGraph.md +1 -1
- package/api/@xmachines/play-router/functions/routeExists.md +1 -1
- package/api/@xmachines/play-router/functions/sanitizePathname.md +1 -1
- package/api/@xmachines/play-router/functions/validateRouteFormat.md +1 -1
- package/api/@xmachines/play-router/functions/validateStateExists.md +1 -1
- package/api/@xmachines/play-router/interfaces/BuildPlayRouteEventOptions.md +4 -4
- package/api/@xmachines/play-router/interfaces/LocationLike.md +27 -0
- package/api/@xmachines/play-router/interfaces/MachineEdgeData.md +3 -3
- package/api/@xmachines/play-router/interfaces/MachineNodeData.md +5 -5
- package/api/@xmachines/play-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-router/interfaces/RouteInfo.md +8 -8
- package/api/@xmachines/play-router/interfaces/RouteMap.md +4 -4
- package/api/@xmachines/play-router/interfaces/{BaseRouteMapping.md → RouteMapping.md} +5 -5
- package/api/@xmachines/play-router/interfaces/RouteMatch.md +5 -5
- package/api/@xmachines/play-router/interfaces/RouteNode.md +12 -12
- package/api/@xmachines/play-router/interfaces/RouteObject.md +2 -2
- package/api/@xmachines/play-router/interfaces/RouteTree.md +5 -5
- package/api/@xmachines/play-router/interfaces/RouteWatcherHandle.md +3 -3
- package/api/@xmachines/play-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-router/interfaces/WindowLike.md +65 -0
- package/api/@xmachines/play-router/type-aliases/MachineGraph.md +1 -1
- package/api/@xmachines/play-router/type-aliases/RouteMetadata.md +1 -1
- package/api/@xmachines/play-signals/functions/watchSignal.md +1 -1
- package/api/@xmachines/play-signals/interfaces/ComputedOptions.md +2 -2
- package/api/@xmachines/play-signals/interfaces/SignalComputed.md +2 -2
- package/api/@xmachines/play-signals/interfaces/SignalOptions.md +2 -2
- package/api/@xmachines/play-signals/interfaces/SignalState.md +3 -3
- package/api/@xmachines/play-signals/interfaces/SignalWatcher.md +4 -4
- package/api/@xmachines/play-signals/namespaces/Signal/classes/Computed.md +6 -0
- package/api/@xmachines/play-signals/namespaces/Signal/classes/State.md +8 -0
- package/api/@xmachines/play-signals/namespaces/Signal/interfaces/Options.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/classes/Watcher.md +10 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/currentComputed.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSinks.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSources.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSinks.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSources.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/untrack.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/unwatched.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/watched.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/variables/isComputed.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/variables/isState.md +2 -0
- package/api/@xmachines/play-signals/namespaces/Signal/variables/isWatcher.md +2 -0
- package/api/@xmachines/play-signals/type-aliases/WatcherNotify.md +1 -1
- package/api/@xmachines/play-solid/README.md +4 -4
- package/api/@xmachines/play-solid/functions/defineRegistry.md +2 -0
- package/api/@xmachines/play-solid/functions/useActor.md +1 -1
- package/api/@xmachines/play-solid/functions/useStateBinding.md +2 -0
- package/api/@xmachines/play-solid/interfaces/ComponentContext.md +2 -0
- package/api/@xmachines/play-solid/interfaces/PlayRendererProps.md +7 -7
- package/api/@xmachines/play-solid/type-aliases/ComponentFn.md +2 -0
- package/api/@xmachines/play-solid/type-aliases/PlayActor.md +1 -1
- package/api/@xmachines/play-solid/variables/PlayRenderer.md +1 -1
- package/api/@xmachines/play-solid-router/README.md +2 -2
- package/api/@xmachines/play-solid-router/classes/RouteMap.md +13 -26
- package/api/@xmachines/play-solid-router/classes/SolidRouterBridge.md +121 -46
- package/api/@xmachines/play-solid-router/functions/PlayRouterProvider.md +1 -1
- package/api/@xmachines/play-solid-router/functions/createRouteMap.md +15 -9
- package/api/@xmachines/play-solid-router/interfaces/AbstractActor.md +47 -92
- package/api/@xmachines/play-solid-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-solid-router/interfaces/PlayRouterProviderProps.md +5 -5
- package/api/@xmachines/play-solid-router/interfaces/RouteMapping.md +19 -6
- package/api/@xmachines/play-solid-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-solid-router/type-aliases/RoutableActor.md +1 -1
- package/api/@xmachines/play-solid-router/type-aliases/SolidRouterHooks.md +21 -18
- package/api/@xmachines/play-solid-router-demo/README.md +25 -28
- package/api/@xmachines/play-svelte/README.md +28 -0
- package/api/@xmachines/play-svelte/functions/defineRegistry.md +2 -0
- package/api/@xmachines/play-svelte/interfaces/BaseComponentProps.md +2 -0
- package/api/@xmachines/play-svelte/interfaces/ComponentContext.md +2 -0
- package/api/@xmachines/play-svelte/interfaces/PlayRendererProps.md +9 -9
- package/api/@xmachines/play-svelte/type-aliases/ComponentFn.md +2 -0
- package/api/@xmachines/play-svelte/type-aliases/PlayRenderer.md +2 -0
- package/api/@xmachines/play-svelte/variables/PlayRenderer.md +2 -0
- package/api/@xmachines/play-svelte-spa-router/README.md +1 -0
- package/api/@xmachines/play-svelte-spa-router/classes/RouteMap.md +13 -26
- package/api/@xmachines/play-svelte-spa-router/functions/connectRouter.md +14 -1
- package/api/@xmachines/play-svelte-spa-router/functions/createRouteMap.md +23 -4
- package/api/@xmachines/play-svelte-spa-router/interfaces/ConnectRouterOptions.md +6 -5
- package/api/@xmachines/play-svelte-spa-router/interfaces/PlayRouteEvent.md +10 -10
- package/api/@xmachines/play-svelte-spa-router/interfaces/RouteMapping.md +20 -5
- package/api/@xmachines/play-svelte-spa-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-svelte-spa-router/interfaces/WindowLike.md +65 -0
- package/api/@xmachines/play-svelte-spa-router/type-aliases/RoutableActor.md +1 -1
- package/api/@xmachines/play-svelte-spa-router-demo/README.md +119 -12
- package/api/@xmachines/play-sveltekit-router/README.md +2 -1
- package/api/@xmachines/play-sveltekit-router/classes/RouteMap.md +46 -24
- package/api/@xmachines/play-sveltekit-router/functions/connectRouter.md +14 -1
- package/api/@xmachines/play-sveltekit-router/functions/createRouteMap.md +23 -4
- package/api/@xmachines/play-sveltekit-router/interfaces/ConnectRouterOptions.md +6 -5
- package/api/@xmachines/play-sveltekit-router/interfaces/LocationLike.md +27 -0
- package/api/@xmachines/play-sveltekit-router/interfaces/PlayRouteEvent.md +10 -10
- package/api/@xmachines/play-sveltekit-router/interfaces/RouteMapping.md +20 -5
- package/api/@xmachines/play-sveltekit-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-sveltekit-router/type-aliases/RoutableActor.md +1 -1
- package/api/@xmachines/play-sveltekit-router-demo/README.md +120 -12
- package/api/@xmachines/play-tanstack-react-router/README.md +5 -3
- package/api/@xmachines/play-tanstack-react-router/classes/RouteMap.md +17 -33
- package/api/@xmachines/play-tanstack-react-router/classes/TanStackReactRouterBridge.md +93 -25
- package/api/@xmachines/play-tanstack-react-router/functions/PlayRouterProvider.md +1 -1
- package/api/@xmachines/play-tanstack-react-router/functions/createRouteMap.md +1 -1
- package/api/@xmachines/play-tanstack-react-router/functions/createRouteMapFromTree.md +21 -11
- package/api/@xmachines/play-tanstack-react-router/functions/extractMachineRoutes.md +1 -1
- package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouterProviderProps.md +5 -5
- package/api/@xmachines/play-tanstack-react-router/interfaces/RouteMapping.md +18 -8
- package/api/@xmachines/play-tanstack-react-router/interfaces/RouteNavigateEvent.md +3 -3
- package/api/@xmachines/play-tanstack-react-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterInstance.md +1 -1
- package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterLike.md +13 -19
- package/api/@xmachines/play-tanstack-react-router-demo/README.md +23 -29
- package/api/@xmachines/play-tanstack-solid-router/README.md +8 -8
- package/api/@xmachines/play-tanstack-solid-router/classes/RouteMap.md +13 -26
- package/api/@xmachines/play-tanstack-solid-router/classes/SolidRouterBridge.md +101 -36
- package/api/@xmachines/play-tanstack-solid-router/functions/PlayRouterProvider.md +1 -1
- package/api/@xmachines/play-tanstack-solid-router/functions/createRouteMap.md +15 -9
- package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouterProviderProps.md +5 -5
- package/api/@xmachines/play-tanstack-solid-router/interfaces/RouteMapping.md +13 -9
- package/api/@xmachines/play-tanstack-solid-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-tanstack-solid-router/type-aliases/RoutableActor.md +1 -1
- package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterInstance.md +1 -1
- package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterLike.md +23 -24
- package/api/@xmachines/play-tanstack-solid-router-demo/README.md +25 -26
- package/api/@xmachines/play-vue/README.md +4 -4
- package/api/@xmachines/play-vue/functions/defineRegistry.md +1 -1
- package/api/@xmachines/play-vue/functions/useActor.md +1 -1
- package/api/@xmachines/play-vue/functions/useStateBinding.md +2 -0
- package/api/@xmachines/play-vue/interfaces/ComponentContext.md +2 -0
- package/api/@xmachines/play-vue/interfaces/PlayRendererProps.md +5 -5
- package/api/@xmachines/play-vue/type-aliases/ComponentEntry.md +1 -1
- package/api/@xmachines/play-vue/type-aliases/ComponentFn.md +2 -0
- package/api/@xmachines/play-vue/type-aliases/ComponentsMap.md +1 -1
- package/api/@xmachines/play-vue/type-aliases/DefineRegistryOptions.md +4 -3
- package/api/@xmachines/play-vue/type-aliases/PlayActor.md +1 -1
- package/api/@xmachines/play-vue/variables/PlayRenderer.md +1 -1
- package/api/@xmachines/play-vue-router/README.md +2 -2
- package/api/@xmachines/play-vue-router/classes/RouteMap.md +18 -108
- package/api/@xmachines/play-vue-router/classes/VueBaseRouteMap.md +44 -104
- package/api/@xmachines/play-vue-router/classes/VueRouterBridge.md +127 -62
- package/api/@xmachines/play-vue-router/functions/createRouteMap.md +1 -1
- package/api/@xmachines/play-vue-router/interfaces/PlayRouteEvent.md +8 -8
- package/api/@xmachines/play-vue-router/interfaces/RouteMapping.md +19 -7
- package/api/@xmachines/play-vue-router/interfaces/RouterBridge.md +3 -3
- package/api/@xmachines/play-vue-router/type-aliases/RoutableActor.md +1 -1
- package/api/@xmachines/play-vue-router/variables/PlayRouterProvider.md +1 -1
- package/api/@xmachines/play-vue-router-demo/README.md +47 -40
- package/api/@xmachines/play-xstate/README.md +15 -15
- package/api/@xmachines/play-xstate/classes/PlayerActor.md +46 -30
- package/api/@xmachines/play-xstate/functions/buildRouteUrl.md +20 -15
- package/api/@xmachines/play-xstate/functions/composeGuards.md +1 -1
- package/api/@xmachines/play-xstate/functions/composeGuardsOr.md +1 -1
- package/api/@xmachines/play-xstate/functions/contextFieldMatches.md +1 -1
- package/api/@xmachines/play-xstate/functions/definePlayer.md +1 -1
- package/api/@xmachines/play-xstate/functions/deriveRoute.md +1 -1
- package/api/@xmachines/play-xstate/functions/eventMatches.md +1 -1
- package/api/@xmachines/play-xstate/functions/formatPlayRouteTransitions.md +2 -2
- package/api/@xmachines/play-xstate/functions/hasContext.md +1 -1
- package/api/@xmachines/play-xstate/functions/isAbsoluteRoute.md +1 -1
- package/api/@xmachines/play-xstate/functions/negateGuard.md +1 -1
- package/api/@xmachines/play-xstate/interfaces/PlayerConfig.md +3 -3
- package/api/@xmachines/play-xstate/interfaces/PlayerFactoryResumeOptions.md +2 -2
- package/api/@xmachines/play-xstate/interfaces/PlayerOptions.md +6 -6
- package/api/@xmachines/play-xstate/interfaces/RouteContext.md +14 -12
- package/api/@xmachines/play-xstate/type-aliases/ComposedGuard.md +1 -1
- package/api/@xmachines/play-xstate/type-aliases/Guard.md +1 -1
- package/api/@xmachines/play-xstate/type-aliases/GuardArray.md +1 -1
- package/api/@xmachines/play-xstate/type-aliases/PlayerFactory.md +1 -1
- package/api/@xmachines/play-xstate/type-aliases/RouteMachineConfig.md +4 -4
- package/api/@xmachines/play-xstate/type-aliases/RouteStateNode.md +4 -4
- package/api/@xmachines/shared/functions/defineXmVitestConfig.md +3 -7
- package/api/@xmachines/shared/functions/xmAliases.md +1 -1
- package/api/README.md +4 -4
- package/api/llms.txt +3 -3
- package/examples/README.md +50 -32
- package/examples/basic-state-machine.md +75 -31
- package/examples/form-validation.md +199 -127
- package/examples/multi-router-integration.md +312 -230
- package/examples/routing-patterns.md +243 -187
- package/examples/traffic-light.md +114 -65
- package/guides/README.md +29 -15
- package/guides/getting-started.md +224 -144
- package/guides/installation.md +153 -213
- package/package.json +2 -2
- package/api/@xmachines/play-tanstack-react-router/functions/extractParams.md +0 -38
- package/api/@xmachines/play-tanstack-react-router/functions/extractQueryParams.md +0 -33
|
@@ -1,167 +1,239 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- generated-by: gsd-doc-writer -->
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
//
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
31
|
-
events: {} as
|
|
45
|
+
context: {} as LoginContext,
|
|
46
|
+
events: {} as LoginEvent,
|
|
47
|
+
input: {} as Partial<LoginContext> | undefined,
|
|
32
48
|
},
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
168
|
+
// 3. Factory and actor
|
|
169
|
+
const createPlayer = definePlayer({ machine: loginMachine });
|
|
170
|
+
const actor = createPlayer();
|
|
171
|
+
actor.start();
|
|
73
172
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
console.log(
|
|
173
|
+
// 4. Navigate to login page
|
|
174
|
+
actor.send({ type: "play.route", to: "#login" });
|
|
175
|
+
console.log(actor.getSnapshot().value); // "login"
|
|
77
176
|
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
//
|
|
82
|
-
|
|
83
|
-
console.log(
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
|
|
89
|
-
console.log(state); // 'valid' (meets minimum length)
|
|
191
|
+
actor.stop();
|
|
90
192
|
```
|
|
91
193
|
|
|
92
|
-
##
|
|
194
|
+
## `$bindState` and `$state` Pattern
|
|
93
195
|
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
##
|
|
154
|
-
|
|
155
|
-
For production forms, you might add:
|
|
227
|
+
## Key Concepts
|
|
156
228
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
- **
|
|
160
|
-
-
|
|
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)**
|
|
165
|
-
- **[
|
|
166
|
-
- **[
|
|
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
|