@xmachines/play-solid
v2.0.0
Published
Solid renderer for XMachines Play architecture
Maintainers
Readme
@xmachines/play-solid
Solid renderer for XMachines Play architecture
SolidJS rendering layer that passively observes actor signals and renders UI components via @xmachines/json-render-solid. SolidJS reactivity is used solely to trigger re-renders — TC39 Signals are the source of truth.
Part of the xmachines-js monorepo.
Installation
pnpm add @xmachines/play-solidPeer dependencies — install alongside the package:
pnpm add solid-js xstate @xstate/store @xmachines/json-render-solid @xmachines/json-render-core @xmachines/json-render-xstateQuick Start
import { PlayUIProvider, PlayRenderer, defineRegistry } from "@xmachines/play-solid";
import { definePlayer } from "@xmachines/play-xstate";
import { defineCatalog } from "@xmachines/json-render-core";
import { schema } from "@xmachines/json-render-solid/schema";
// 1. Define a catalog (authCatalogDef is a plain object describing components/actions)
const catalog = defineCatalog(schema, authCatalogDef);
// 2. Build a component registry
const registryResult = defineRegistry(catalog, {
components: {
Home: () => <div>Welcome home!</div>,
Login: (ctx) => <div>Login {ctx.props.error && <span>{ctx.props.error}</span>}</div>,
},
actions: {
login: async (args) => actor.send({ type: "auth.login", username: args.username }),
logout: async () => actor.send({ type: "auth.logout" }),
},
});
// 3. Create and start an actor
const createPlayer = definePlayer({ machine: myMachine });
const actor = createPlayer();
actor.start();
// 4. Render
function App() {
return (
<PlayUIProvider actor={actor} registryResult={registryResult}>
<PlayRenderer />
</PlayUIProvider>
);
}Usage
PlayUIProvider + PlayRenderer (recommended)
PlayUIProvider is the batteries-included entry point. It wraps ActorProvider and JSONUIProvider into a single composite provider. PlayRenderer is a zero-prop leaf component that reads view context and renders the current spec.
import { PlayUIProvider, PlayRenderer, defineRegistry } from "@xmachines/play-solid";
<PlayUIProvider
actor={actor}
registryResult={registryResult}
fallback={<div>Loading…</div>}
onError={(err) => console.error(err)}
navigate={navigateFn} // optional: passed to JSONUIProvider
validationFunctions={valFns} // optional: form validation helpers
>
<PlayRenderer />
</PlayUIProvider>;ActorProvider (escape hatch)
For library authors who need direct control over provider composition:
import { ActorProvider, PlayRenderer } from "@xmachines/play-solid";
<ActorProvider actor={actor} registryResult={registryResult}>
<PlayRenderer />
</ActorProvider>;useActor hook
Access the raw actor instance anywhere inside an ActorProvider or PlayUIProvider tree:
import { useActor } from "@xmachines/play-solid";
function SubmitButton() {
const actor = useActor();
return <button onClick={() => actor.send({ type: "SUBMIT" })}>Submit</button>;
}usePlayView hook
Access the resolved view context (spec, handlers, registry, store) from within the provider tree:
import { usePlayView } from "@xmachines/play-solid";
import { Renderer } from "@xmachines/json-render-solid";
const MyRenderer = () => {
const view = usePlayView();
return <Renderer spec={view.spec} registry={view.registry} />;
};API Summary
Components
| Export | Description |
| ---------------- | ------------------------------------------------------------------------------ |
| PlayUIProvider | Batteries-included composite provider (recommended entry point) |
| PlayRenderer | Zero-prop leaf component; renders the current view spec inside a provider tree |
| ActorProvider | Lower-level smart provider for escape-hatch composition |
Hooks
| Export | Description |
| --------------- | --------------------------------------------------------------------------------------------- |
| useActor() | Returns the raw AnyPlayActor instance from context; throws outside a provider tree |
| usePlayView() | Returns the current ViewContextValue (spec, handlers, registry, store); throws outside tree |
Context
| Export | Description |
| -------------- | -------------------------------------------------------------------------------------- |
| ActorContext | SolidJS context for the actor; use ActorContext.Provider directly as an escape hatch |
Re-exports from @xmachines/json-render-solid
This package re-exports the full @xmachines/json-render-solid public API so consumers do not need a direct dependency:
import {
// Providers
JSONUIProvider,
StateProvider,
ActionProvider,
VisibilityProvider,
ValidationProvider,
// Renderer
Renderer,
// Registry factory + hooks
defineRegistry,
useBoundProp,
useStateBinding,
useStateValue,
useStateStore,
useActions,
useAction,
useIsVisible,
useFieldValidation,
useOptionalValidation,
useVisibility,
} from "@xmachines/play-solid";Key Types
| Type | Description |
| --------------------- | ------------------------------------------------------------------------------ |
| PlayUIProviderProps | Props for PlayUIProvider |
| ActorProviderProps | Props for ActorProvider |
| ViewContextValue | Shape of the context value from usePlayView() |
| AnyPlayActor | AbstractActor<AnyActorLogic> — bare actor type accepted by context providers |
Testing
Run tests for this package in isolation:
pnpm --filter @xmachines/play-solid testOr from within the package directory:
pnpm test # single run (jsdom environment)
pnpm run test:watch # watch mode
pnpm run test:ui # interactive Vitest UICoverage is collected with v8 (80% threshold for lines, functions, branches, and statements). Browser-specific tests live in test/browser/ and are excluded from the default jsdom run.
License
MIT
