npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xmachines/play-vue

v2.1.0

Published

Vue renderer for XMachines Play architecture

Downloads

616

Readme

@xmachines/play-vue

Vue 3 renderer for the XMachines Play Architecture. It observes the actor signals and renders the UI through @xmachines/json-render-vue.

License: MIT Version


Overview

@xmachines/play-vue is the Vue 3 rendering layer of XMachines Play. It connects the TC39 Signals (the actor state) to the Vue reactivity, and it renders the components through @xmachines/json-render-vue.

The architecture invariants that this package keeps:

  • Passive Infrastructure — the components observe the actor signals. They never decide a state transition.
  • Signal-Only Reactivity — the TC39 Signals are the source of truth. Vue reactivity only triggers the re-render.
  • Actor Authority — the actor controls the view selection. The renderer reflects it.

Installation

pnpm add @xmachines/play-vue

Peer dependencies. Install them with the package:

pnpm add vue@^3.5.0 xstate@^5.31.0 @xstate/store@^3.17.0 @xmachines/json-render-vue@^0.20.0-xm.2 @xmachines/json-render-core@^0.20.0-xm.2 @xmachines/json-render-xstate@^0.20.0-xm.2

Quick Start

<!-- App.vue -->
<template>
	<PlayUIProvider :actor="actor" :registryResult="registryResult">
		<PlayRenderer />
	</PlayUIProvider>
</template>

<script setup lang="ts">
import { defineRegistry, PlayUIProvider, PlayRenderer } from "@xmachines/play-vue";
import { definePlayer } from "@xmachines/play-xstate";
import { myMachine } from "./machine.js";
import { myCatalog } from "./catalog.js";
import HomeSFC from "./views/Home.vue";
import LoginSFC from "./views/Login.vue";

const createPlayer = definePlayer({ machine: myMachine });
const actor = createPlayer();
actor.start();

const registryResult = defineRegistry(myCatalog, {
	components: {
		Home: HomeSFC, // .vue SFCs are auto-wrapped
		Login: LoginSFC,
	},
	actions: {
		login: async (args) => actor.send({ type: "auth.login", ...args }),
		logout: async () => actor.send({ type: "auth.logout" }),
	},
});
</script>

API Summary

Components

<PlayUIProvider>

The composite provider. It wraps <ActorProvider> and JSONUIProvider in one component. Use it in most applications.

| Prop | Type | Required | Description | | --------------------- | -------------------------- | -------- | ------------------------------------------- | | actor | AbstractActor & Viewable | ✅ | The XMachines actor instance | | registryResult | DefineRegistryResult | ✅ | Result of defineRegistry() | | store | StateStore | — | External controlled state store (optional) | | onRenderError | RenderErrorHandler | — | Error handler for render failures | | navigate | (path: string) => void | — | Link navigation function | | validationFunctions | Record<string, Function> | — | Custom validation functions | | functions | Record<string, Function> | — | Named functions for $computed expressions |

Slots: default (the rendered content), fallback (the content while the actor view is null)

<PlayRenderer>

The leaf component without props. It reads the current spec and registry from the nearest <ActorProvider> or <PlayUIProvider> context, then renders them with <Renderer>. Put it inside one of those providers.

<PlayUIProvider :actor="actor" :registryResult="registryResult">
  <PlayRenderer />
</PlayUIProvider>

<ActorProvider>

The low-level provider for a custom provider composition. It owns the complete actor lifecycle: the signal subscription, the state store of each view, the handler resolution, and the Vue context. Use <PlayUIProvider> when you do not need this control.

| Prop | Type | Required | Description | | ---------------- | -------------------------- | -------- | ------------------------------- | | actor | AbstractActor & Viewable | ✅ | The XMachines actor instance | | registryResult | DefineRegistryResult | ✅ | Result of defineRegistry() | | store | StateStore | — | External controlled state store | | onRenderError | RenderErrorHandler | — | Override render error handler |


Functions

defineRegistry(catalog, options)

This function is the drop-in replacement for defineRegistry from @xmachines/json-render-vue. Always import it from @xmachines/play-vue when you work with a Vue SFC, not from @xmachines/json-render-vue. The wrapper finds each .vue SFC in the components map, and wraps it with h(). A Vue composable, and also a composable that uses inject, then works correctly inside <script setup>.

import { defineRegistry } from "@xmachines/play-vue";
// NOT: import { defineRegistry } from "@xmachines/json-render-vue"

import { myCatalog } from "./catalog.js"; // as in the Quick Start
import LoginSFC from "./views/Login.vue";
import DashboardSFC from "./views/Dashboard.vue";

const registryResult = defineRegistry(myCatalog, {
	components: {
		Login: LoginSFC, // .vue SFC — auto-wrapped via h()
		Dashboard: DashboardSFC,
	},
	actions: {
		login: async (args, setState, state) => {
			/* ... */
		},
	},
});

A plain ComponentFn function also works, and the wrapper passes it through without a change. One registry can hold both SFCs and plain functions.

useActor()

The Vue composable that gives the raw actor inside a PlayRenderer tree. A deeply nested component then does not need the actor as a prop.

import { useActor } from "@xmachines/play-vue";

// Inside a component rendered by PlayRenderer:
const actor = useActor();
actor.send({ type: "SUBMIT" });

It throws when the caller is outside an <ActorProvider> or a <PlayUIProvider> tree.

usePlayView()

Access the current ViewContextValue{ spec, handlers, registry, store } — from inside an <ActorProvider> tree.

import { usePlayView } from "@xmachines/play-vue";

// Inside setup() of a component within an ActorProvider tree:
const view = usePlayView();
// view.spec, view.handlers, view.registry, view.store

Note: usePlayView was previously named getPlayViewContext. The old name is still exported as a deprecated alias and will be removed in the next major.


Re-exported from @xmachines/json-render-vue

This package re-exports the following, so that a consumer imports everything from @xmachines/play-vue:

Components: JSONUIProvider, StateProvider, ActionProvider, VisibilityProvider, ValidationProvider, Renderer

Composables: useBoundProp

Types: JSONUIProviderProps, StateProviderProps, ActionProviderProps, ValidationProviderProps, RendererProps, ComponentFn, ComponentContext, DefineRegistryResult


Testing

Run tests for this package in isolation:

# From the monorepo root
pnpm --filter @xmachines/play-vue test

# Watch mode
pnpm --filter @xmachines/play-vue run test:watch

# With coverage (80% threshold enforced on lines, functions, branches, statements)
pnpm exec vitest run --coverage --config packages/play-vue/vitest.config.ts

The tests use Vitest in a jsdom environment. They mount the components with @vue/test-utils.


License

MIT — see LICENSE.