Skip to content

@xmachines/play-solid

API / @xmachines/play-solid

Solid renderer for XMachines Play architecture

License: MIT Version

The SolidJS rendering layer observes the actor signals and renders the UI components through @xmachines/json-render-solid. SolidJS reactivity only triggers the re-render. The TC39 Signals are the source of truth.

Installation

Terminal window
pnpm add @xmachines/play-solid

Peer dependencies. Install them with the package:

Terminal window
pnpm add solid-js xstate @xstate/store @xmachines/json-render-solid @xmachines/json-render-core @xmachines/json-render-xstate

Quick 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";
import { myMachine } from "./machine.js"; // your xstate machine (states carry meta.view specs)
// authCatalogDef is a plain object describing components/actions — in this repo it
// comes from the workspace-only @xmachines/play-actor-shared demo package
import { authCatalogDef } from "@xmachines/play-actor-shared";
// 1. Define a catalog
const catalog = defineCatalog(schema, authCatalogDef);
// 2. Create and start an actor
const createPlayer = definePlayer({ machine: myMachine });
const actor = createPlayer();
actor.start();
// 3. Build a component registry
const registryResult = defineRegistry(catalog, {
components: {
Home: () => <div>Welcome home!</div>,
Login: (ctx) => <div>Login {ctx.props.username && <span>{ctx.props.username}</span>}</div>,
},
actions: {
login: async (args) => actor.send({ type: "auth.login", username: args.username }),
logout: async () => actor.send({ type: "auth.logout" }),
},
});
// 4. Render
function App() {
return (
<PlayUIProvider actor={actor} registryResult={registryResult}>
<PlayRenderer />
</PlayUIProvider>
);
}

Usage

PlayUIProvider is the standard entry point. It wraps ActorProvider and JSONUIProvider into one composite provider. PlayRenderer is a leaf component without props. It reads the view context and renders the current spec.

import { PlayUIProvider, PlayRenderer, defineRegistry } from "@xmachines/play-solid";
// actor, registryResult from the Quick Start above
<PlayUIProvider
actor={actor}
registryResult={registryResult}
fallback={<div>Loading…</div>}
onError={(err) => console.error(err)}
navigate={navigateFn} // optional: your navigation callback, passed to JSONUIProvider
validationFunctions={valFns} // optional: your form validation helpers
>
<PlayRenderer />
</PlayUIProvider>;

ActorProvider (low-level)

For library authors who need direct control over provider composition:

import { ActorProvider, PlayRenderer } from "@xmachines/play-solid";
// actor, registryResult from the Quick Start above
<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

ExportDescription
PlayUIProviderThe composite provider. Use it as the standard entry point
PlayRendererThe leaf component without props. It renders the current view spec inside a provider tree
ActorProviderThe low-level provider for a custom provider composition

Hooks

ExportDescription
useActor()Returns the raw AnyPlayActor instance from the context. It throws outside a provider tree
usePlayView()Returns the current ViewContextValue (spec, handlers, registry, store). It throws outside the tree

Context

ExportDescription
ActorContextThe SolidJS context of the actor. Use ActorContext.Provider directly for a custom composition

Re-exports from @xmachines/json-render-solid

This package re-exports the complete @xmachines/json-render-solid public API, so that a consumer does 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

TypeDescription
PlayUIProviderPropsProps for PlayUIProvider
ActorProviderPropsProps for ActorProvider
ViewContextValueShape of the context value from usePlayView()
AnyPlayActorAbstractActor<AnyActorLogic> — the bare actor type that the context providers accept

Testing

Run tests for this package in isolation:

Terminal window
pnpm --filter @xmachines/play-solid test

Or from within the package directory:

Terminal window
pnpm test # single run (jsdom environment)
pnpm run test:watch # watch mode
pnpm run test:ui # interactive Vitest UI

The v8 provider collects the coverage, with a threshold of 80% for lines, functions, branches, and statements. The browser tests are in test/browser/. The default jsdom run excludes them.

License

MIT

@xmachines/play-solid - SolidJS renderer for the XMachines Play architecture

This package is the SolidJS rendering layer. It observes the actor signals and renders the UI components through @xmachines/json-render-solid. SolidJS reactivity only triggers the re-render. The signals are the source of truth.

Primary entry point:

import { PlayUIProvider, PlayRenderer, defineRegistry } from "@xmachines/play-solid";

For a custom provider composition:

import { ActorProvider, ActorContext, usePlayView } from "@xmachines/play-solid";

Interfaces

Type Aliases

Variables

Functions