@xmachines/play-solid-demo
Examples / @xmachines/play-solid-demo
Solid renderer demo for @xmachines/play-solid — actor + PlayRenderer without a router.
What This Demonstrates
- Shared auth machine reused without framework-specific business logic
PlayRendererrendering actor-projected views with a typeddefineRegistrycatalog- Auth machine states drive view switching via
auth.login/auth.logoutevents only — no URL routing - Canonical atoms lifecycle integrated with Solid’s fine-grained reactivity
- Non-browser invariant tests plus browser renderer coverage
- Stately inspector attached at creation via
options.inspect— the debug panel’s Show Inspector button opens the live machine in its own window - json-render 0.20 showcase pages driven purely by spec:
- Overview — two data planes side by side:
/context/tasks(machine context via the read-only/contextprojection;repeat+key,$item-filtered lists, per-row actions sending inspectable machine events) next to ephemeral store state (pushState/removeState/setStatebuilt-ins driving filter chips and toggles that survive context updates) - Stats — nested repeats (
repeat.statePath: { $item: "members" }) over/context/teams - Settings — declarative field validation, the
validateFormbuilt-in, a confirm-gatedresetFormhost action, andonSuccess/onErrorchains - Contact — a chained named action: submit validates, then routes home on success or writes
"$error.message"to state on failure
- Overview — two data planes side by side:
Running the Demo
From the repository root:
pnpm installpnpm --filter @xmachines/play-solid-demo run devThen open http://localhost:3002.
Step-by-Step Code Flow
Use this order to understand the implementation:
src/main.tsxmounts<App />to the DOM root via Solid’srender.src/App.tsxcreates the page’s inspector withcreateDemoInspector(), then at module scope callsdefinePlayer({ machine: authMachine, options: { inspect: inspector.inspect }, actor: compose(PlayerActor, withRouting, withView) }), invokes the returned factory to produce the actor, and starts it.defineRegistry(authCatalog, { components, actions })builds the typedregistryResultinsidecreateMemo— real async action handlers dispatching toactor.send().<PlayUIProvider actor={actor} registryResult={registryResult()}><PlayRenderer /></PlayUIProvider>observesactor.currentViewand renders the active spec.- A
NavBarcomponent observesactoratoms directly for nav visibility. <DebugPanel actor={actor} inspector={inspector} />shows live state, auth status, and current route, plus the Show Inspector button.- Browser tests in
test/browser/validate startup and interaction behavior.
// src/main.tsx (shape)render(() => <App />, document.getElementById("app")!);// src/App.tsx (shape)const inspector = createDemoInspector();const createPlayer = definePlayer({ machine: authMachine, options: { inspect: inspector.inspect }, actor: compose(PlayerActor, withRouting, withView),});const actor = createPlayer();actor.start();
export function App() { const registryResult = createMemo(() => defineRegistry(authCatalog, { components: demoComponents, // one shared map — Home…NavBar plus the 0.20 Panel/Field/Button leaves actions: createAuthActionHandlers(actor), // login/logout/route + task events + form actions }), );
return ( <div class="demo-app" data-demo-shell> <header class="demo-header"> <h1 class="demo-title">XMachines Play Solid Demo</h1> <NavBar actor={actor} /> </header> <main class="demo-content" data-demo-content> <PlayUIProvider actor={actor} registryResult={registryResult()}> <PlayRenderer /> </PlayUIProvider> </main> <DebugPanel actor={actor} inspector={inspector} /> </div> );}Key Files
src/main.tsx- Vite bootstrap that mounts<App />via Solid’srendersrc/App.tsx- actor lifecycle, registry construction, andPlayUIProvider+PlayRenderercompositionsrc/components/- demo view components bound to catalog component keys (Home, Login, Dashboard, Profile, etc.)test/library-pattern.test.ts- architecture boundary and invariant assertionstest/browser/renderer-demo.browser.test.tsx- browser-mode renderer coverage
State Machine & Architecture Details
The demo utilizes XMachines architectural invariants:
- Actor Authority: View components dispatch
auth.loginandauth.logoutevents to the actor. The actor evaluates guards and transitions — Solid never decides which view to render. - Passive Infrastructure:
PlayRendererobservesactor.currentViewatoms only. It holds no business state and makes no routing decisions. - Atom-Only Reactivity: Instead of React-like re-renders, Solid uses fine-grained
createEffectinternally within the renderer to react precisely when actor atoms update.
Watcher Lifecycle and Cleanup Contract
This demo follows the canonical watcher lifecycle used across all @xmachines framework adapters:
- The atom notifies the subscription, synchronously, from the
setthat changed it watchAtomqueues one microtask, and it drops each duplicate notification of that batch- The microtask reads the actor atoms and projects Solid-local render state
One subscription lives for the whole watch, and no caller arms a watcher again. Cleanup is explicit and lifecycle-bound: Solid teardown uses onCleanup, and PlayRenderer handles internal watcher teardown natively on disposal.
Adapter Boundaries
PlayRenderer and defineRegistry stay passive infrastructure. Business validity remains actor-owned. The registry maps catalog component keys to Solid component implementations — the actor owns which key is active. The demo intentionally omits URL routing to isolate the renderer contract.
Available Scripts
These commands are defined in package.json:
| Command | Description |
|---|---|
pnpm --filter @xmachines/play-solid-demo run dev | Start Vite dev server (http://localhost:3002/) |
pnpm --filter @xmachines/play-solid-demo run build | Build production bundle |
pnpm --filter @xmachines/play-solid-demo run preview | Preview built bundle |
pnpm --filter @xmachines/play-solid-demo run test | Run Vitest test suite |
pnpm --filter @xmachines/play-solid-demo run test:browser | Run browser-focused Vitest suite |
Learn More
Type Aliases
Variables
- About
- authCatalog
- Button
- Contact
- Dashboard
- DebugPanel
- demoComponents
- Field
- Home
- Login
- NavBar
- NavBarView
- Navigation
- Overview
- Panel
- Profile
- Settings
- Shell
- Stats