### Setup Robot Hooks Tests
Source: https://github.com/matthewp/robot/blob/main/packages/robot-hooks/test/test.html
Initializes QUnit and imports the test file. Ensure this runs before QUnit starts.
```javascript
QUnit.config.autostart = false; { "imports": { "haunted": "../../../node_modules/haunted/lib/haunted.js", "lit": "../../../node_modules/lit/index.js", "lit/async-directive.js": "../../../node_modules/lit/async-directive.js", "lit/directive.js": "../../../node_modules/lit/directive.js", "@lit/reactive-element": "../../../node_modules/@lit/reactive-element/reactive-element.js", "lit-html": "../../../node_modules/lit-html/lit-html.js", "lit-html/async-directive.js": "../../../node_modules/lit-html/async-directive.js", "lit-html/directive.js": "../../../node_modules/lit-html/directive.js", "lit-html/is-server.js": "../../../node_modules/lit-html/is-server.js", "lit-element/lit-element.js": "../../../node_modules/lit-element/lit-element.js", "robot3": "../../../node_modules/robot3/machine.js" } } import './test.js'; QUnit.start();
```
--------------------------------
### Install react-robot with npm
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/react-robot.md
Install the `react-robot` package using npm.
```bash
npm install react-robot --save
```
--------------------------------
### Install react-robot with Yarn
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/react-robot.md
Install the `react-robot` package using Yarn.
```bash
yarn add react-robot
```
--------------------------------
### Complete Robot Machine Example
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/core-concepts.md
Use this example to see how states, transitions, guards, actions, and interpretation work together. It sets up a machine with idle, loading, loaded, and error states, and demonstrates triggering transitions.
```javascript
import { createMachine, state, transition, guard, action, interpret } from 'robot3';
// Actions
const setUser = action((ctx, event) => ({ ...ctx, user: event.data }));
const clearError = action((ctx) => ({ ...ctx, error: null }));
const setError = action((ctx, event) => ({ ...ctx, error: event.error }));
// Guards
const isValid = guard((ctx, event) => event.data && event.data.email);
// Machine definition
const machine = createMachine({
idle: state(
transition('fetch', 'loading', clearError)
),
loading: state(
transition('success', 'loaded',
guard(isValid),
setUser
),
transition('failure', 'error', setError)
),
loaded: state(
transition('refresh', 'loading')
),
error: state(
transition('retry', 'loading', clearError)
)
}, {
user: null,
error: null
});
// Create and use service
const service = interpret(machine, () => {
console.log('Current state:', service.machine.current);
console.log('Context:', service.context);
});
// Trigger transitions
service.send('fetch');
service.send({ type: 'success', data: { email: 'user@example.com' } });
```
--------------------------------
### Install preact-robot using Yarn
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/preact-robot.md
Install the preact-robot package using Yarn.
```bash
yarn add preact-robot
```
--------------------------------
### Install robot3 and Integrations
Source: https://context7.com/matthewp/robot/llms.txt
Install the core robot3 library and any desired framework-specific integration packages using npm.
```bash
npm install robot3
# Integrations (install the ones you need)
npm install react-robot
npm install preact-robot
npm install haunted-robot
npm install lit-robot
npm install robot-hooks
```
--------------------------------
### Install lit-robot with npm
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/lit-robot.md
Install the lit-robot package using npm.
```bash
npm install lit-robot --save
```
--------------------------------
### Install lit-robot with Yarn
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/lit-robot.md
Install the lit-robot package using Yarn.
```bash
yarn add lit-robot
```
--------------------------------
### Install preact-robot using npm
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/preact-robot.md
Install the preact-robot package using npm.
```bash
npm install preact-robot --save
```
--------------------------------
### Create a Haunted Component with Robot Hooks
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/robot-hooks.md
This example demonstrates how to create a custom element using Haunted, integrating it with Robot hooks to manage the state of a simple machine. It shows the setup for `createUseMachine` and its usage within a functional component.
```javascript
import { createMachine, state, transition } from 'robot3';
import { component, useEffect, useState, html } from 'haunted';
import { createUseMachine } from 'robot-hooks';
const useMachine = createUseMachine(useEffect, useState);
const machine = createMachine({
idle: state(
transition('click', 'active')
),
active: state()
});
function App() {
const [current, send] = useMachine(machine);
return html`
`;
}
customElements.define('my-app', component(App));
```
--------------------------------
### Install svelte-robot-factory
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/svelte-robot-factory.md
Install the svelte-robot-factory and robot3 packages using npm or yarn.
```bash
npm install svelte-robot-factory robot3 --save
```
```bash
yarn add svelte-robot-factory robot3
```
--------------------------------
### Create a Basic Machine with Transitions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/composition.md
Define a machine with states and transitions that update context. This example shows a simple form field pattern.
```javascript
import { createMachine, state, reduce, transition } from 'robot3';
const machine = createMachine({
form: state(
transition('first', 'form',
reduce((ctx, ev) => ({ ...ctx, first: ev.event.target.value }))
),
transition('last', 'form',
reduce((ctx, ev) => ({ ...ctx, last: ev.event.target.value }))
)
)
});
```
--------------------------------
### Import and Setup for Preact Robot Tests
Source: https://github.com/matthewp/robot/blob/main/packages/preact-robot/test/test.html
This snippet shows the necessary imports and QUnit configuration for running tests with preact-robot. Ensure all paths are correct for your project structure.
```javascript
QUnit.config.autostart = false; { "imports": { "htm": "../../../node_modules/htm/dist/htm.module.js", "htm/preact": "../../../node_modules/htm/preact/index.module.js", "preact/hooks": "../../../node_modules/preact/hooks/dist/hooks.module.js", "preact": "../../../node_modules/preact/dist/preact.module.js", "robot3": "../../core/machine.js", "robot-hooks": "../../robot-hooks/machine.js" } } import './test.js'; QUnit.start();
```
--------------------------------
### Set Initial State (Explicit)
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-state.md
You can explicitly specify which state the machine should start in by providing the initial state name as the first argument to `createMachine`.
```javascript
const machine = createMachine('active', {
idle: state(),
active: state() // Machine starts here
});
```
--------------------------------
### Install haunted-robot via Yarn
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/haunted-robot.md
Install the haunted-robot package using Yarn for use in your project.
```bash
yarn add haunted-robot
```
--------------------------------
### Setup Haunted Robot Tests with QUnit
Source: https://github.com/matthewp/robot/blob/main/packages/haunted-robot/test/test.html
Configures QUnit for testing and imports necessary modules for haunted-robot. Ensure QUnit is available globally.
```javascript
QUnit.config.autostart = false;
{ "imports": { "haunted": "../../../node_modules/haunted/lib/haunted.js", "lit": "../../../node_modules/lit/index.js", "lit/async-directive.js": "../../../node_modules/lit/async-directive.js", "lit/directive.js": "../../../node_modules/lit/directive.js", "@lit/reactive-element": "../../../node_modules/@lit/reactive-element/reactive-element.js", "lit-html": "../../../node_modules/lit-html/lit-html.js", "lit-html/async-directive.js": "../../../node_modules/lit-html/async-directive.js", "lit-html/directive.js": "../../../node_modules/lit-html/directive.js", "lit-html/is-server.js": "../../../node_modules/lit-html/is-server.js", "lit-element/lit-element.js": "../../../node_modules/lit-element/lit-element.js", "robot3": "../../../node_modules/robot3/machine.js", "robot-hooks": "../../../node_modules/robot-hooks/machine.js" } }
import './test.js';
QUnit.start();
```
--------------------------------
### Install haunted-robot via npm
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/haunted-robot.md
Install the haunted-robot package using npm for use in your project.
```bash
npm install haunted-robot --save
```
--------------------------------
### Action Execution Order Example
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Demonstrates the sequence of guards and actions during a transition. Guards are checked first, followed by actions in the order they are defined. The context is updated sequentially by each action.
```javascript
const machine = createMachine({
idle: state(
transition('submit', 'processing',
guard((ctx) => ctx.isValid), // 1. Guard checks
action((ctx) => { // 2. First action
console.log('First:', ctx.count);
return { ...ctx, count: 1 };
}),
action((ctx) => { // 3. Second action
console.log('Second:', ctx.count);
return { ...ctx, count: 2 };
})
)
),
processing: state() // 4. New state with count: 2
}, () => ({ count: 0, isValid: true }));
```
--------------------------------
### Deterministic Transition Example
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
In a given state, a specific event should always lead to the same target state. This ensures predictable behavior.
```javascript
loading: state(
// From 'loading', the 'done' event ALWAYS goes to 'loaded'
transition('done', 'loaded')
)
```
--------------------------------
### Astro Project Commands
Source: https://github.com/matthewp/robot/blob/main/docs/README.md
Common commands for managing an Astro project, including installation, development, building, and previewing.
```bash
npm install
```
```bash
npm run dev
```
```bash
npm run build
```
```bash
npm run preview
```
```bash
npm run astro ...
```
```bash
npm run astro -- --help
```
--------------------------------
### Install Robot Hooks and Robot3
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/robot-hooks.md
Install the robot-hooks and robot3 packages using npm or Yarn. These are the core dependencies for using Robot hooks with your state machines.
```bash
npm install robot-hooks robot3 --save
```
```bash
yarn add robot-hooks robot3
```
--------------------------------
### Dispatching an event with action
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/action.md
Use action to run a function during a transition. This example dispatches a 'toggled' event on an element when transitioning to the 'off' state.
```javascript
import { createMachine, action, state, transition } from 'robot3';
function dispatchOn(ctx) {
const { element } = ctx;
element.dispatchEvent(new CustomEvent('toggled'));
}
const machine = createMachine({
on: state(
transition('toggle', 'off')
),
off: state(
transition('toggle', 'on',
action(dispatchOn)
)
)
}, () => ({
element: document.querySelector('#toggler')
}));
```
--------------------------------
### Basic React Robot Hook Usage
Source: https://github.com/matthewp/robot/blob/main/packages/react-robot/readme.md
Demonstrates how to integrate Robot state machines with React using the `useMachine` hook. This example shows setting up a simple machine and rendering a button that updates its state based on machine transitions.
```javascript
import { useMachine } from 'react-robot';
import React from 'react';
import { createMachine, state, transition } from 'robot3';
const machine = createMachine({
one: state(
transition('next', 'two')
),
two: state()
});
function App() {
const [current, send] = useMachine(machine);
return html`
`;
}
```
--------------------------------
### Use useMachine Hook with Preact
Source: https://github.com/matthewp/robot/blob/main/packages/preact-robot/readme.md
Demonstrates how to use the `useMachine` hook from `preact-robot` to manage a Robot state machine within a Preact component. This example shows setting up a simple machine and interacting with it via a button click.
```javascript
import { useMachine } from 'preact-robot';
import { h } from 'preact';
import { html } from 'htm/prect';
import { createMachine, state, transition } from 'robot3';
const machine = createMachine({
one: state(
transition('next', 'two')
),
two: state()
});
function App() {
const [current, send] = useMachine(machine);
return html`
`;
}
```
--------------------------------
### Use Robot Hooks with Initial Context
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/robot-hooks.md
This example shows how to use the `useMachine` hook with an initial context object. The context is merged with any derived values from reducers, and its properties can be accessed from the `current.context` object.
```javascript
const context = initialContext => ({
...initialContext,
page: 23
});
const machine = createMachine({
one: state(
transition('go', 'two')
),
two: state()
}, context);
// ... later
function App() {
const [current, send] = useMachine(machine, { foo: 'bar' });
const { page } = current.context;
console.log(current.name); // "one"
console.log(page); // 23
}
```
--------------------------------
### Preventing Invalid State Changes (FSM Example)
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
Shows how explicit transitions in a state machine restrict state changes to defined paths, ensuring validity.
```javascript
// With FSM - only valid transitions allowed ✅
const machine = createMachine({
idle: state(
transition('fetch', 'loading')
// Can't go directly to 'loaded' or 'error' from 'idle'
),
loading: state(
transition('success', 'loaded'),
transition('error', 'error')
)
});
```
--------------------------------
### Implement Login Form with reduce
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/reduce.md
Use `reduce` to update the `login` and `password` properties in the machine's context when 'login' or 'password' events are triggered. This example demonstrates setting form field values directly into the context.
```javascript
import { createMachine, reduce, state, transition } from 'robot3';
const machine = createMachine({
idle: state(
transition('login', 'idle',
reduce((ctx, ev) => ({ ...ctx, login: ev.target.value }))
),
transition('password', 'idle',
reduce((ctx, ev) => ({ ...ctx, password: ev.target.value }))
),
transition('submit', 'complete')
),
complete: state()
});
```
--------------------------------
### Robot Composition Pattern for Reusable Transitions
Source: https://context7.com/matthewp/robot/llms.txt
Leverage reusable transition factories to eliminate boilerplate and keep machines DRY. This example shows a `field` factory for form inputs that saves values to context.
```javascript
import { createMachine, guard, reduce, state, transition } from 'robot3';
import { interpret } from 'robot3';
// Reusable factory: a form field that saves its value to context
const field = (name, destinationState, ...extra) =>
transition(name, destinationState,
reduce((ctx, ev) => ({ ...ctx, [name]: ev.target.value })),
...extra
);
// Compose a machine from reusable pieces
const machine = createMachine({
form: state(
field('username', 'form'),
field('email', 'form'),
field('password', 'form',
guard((ctx) => ctx.password?.length >= 8) // extra guard for password
),
transition('submit', 'submitting',
guard((ctx) => ctx.username && ctx.email && ctx.password)
)
),
submitting: state(
transition('done', 'success'),
transition('error', 'form')
),
success: state()
}, () => ({ username: '', email: '', password: '' }));
const service = interpret(machine, (s) => console.log(s.machine.current));
service.send({ type: 'username', target: { value: 'alice' } });
service.send({ type: 'email', target: { value: 'alice@example.com' } });
service.send({ type: 'password', target: { value: 'hunter2!' } });
service.send('submit');
// → submitting
```
--------------------------------
### Define States and Transitions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/state.md
Use the `state` and `transition` functions to define states and their transitions within a Robot3 state machine. This example shows a basic machine with 'idle' and 'input' states.
```javascript
import { createMachine, state, transition } from 'robot3';
const machine = createMachine({
idle: state(
transition('first', 'input')
),
input: state(
immediate('idle',
reduce((ctx, ev) => ({ ...ctx, first: ev.target.value }))
)
)
});
```
--------------------------------
### Permission Guards for Access Control
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Demonstrates using guards to check user permissions before allowing specific actions. This example restricts 'edit' to admins and 'delete' to the resource owner.
```javascript
const isAdmin = (ctx) => ctx.user.role === 'admin';
const isOwner = (ctx, ev) => ctx.user.id === ev.resourceOwnerId;
const hasEditAccess = (ctx) => ctx.user.permissions.includes('edit');
const machine = createMachine({
viewing: state(
transition('edit', 'editing',
guard(isAdmin) // Only admins can edit
),
transition('delete', 'deleting',
guard(isOwner) // Only owner can delete
)
),
editing: state(),
deleting: state()
});
```
--------------------------------
### Synchronous Context Update with Actions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Use actions for immediate, synchronous updates to the machine's context based on event data. This example shows updating a 'value' property.
```javascript
idle: state(
transition('update', 'idle',
reduce((ctx, ev) => ({ ...ctx, value: ev.value }))
)
)
```
--------------------------------
### Self-Documenting State Flow Example
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
A state machine definition with explicit transitions serves as a clear map of all possible states and their transitions, making the application's flow self-documenting.
```javascript
const authMachine = createMachine({
loggedOut: state(
transition('login', 'authenticating')
),
authenticating: state(
transition('success', 'loggedIn'),
transition('failure', 'loggedOut'),
transition('timeout', 'loggedOut')
),
loggedIn: state(
transition('logout', 'loggingOut')
),
loggingOut: state(
transition('done', 'loggedOut')
)
});
```
--------------------------------
### Preventing Invalid State Changes (Imperative Example)
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
Illustrates how state can change unpredictably in traditional imperative code without explicit state management.
```javascript
// Without FSM - state can change anywhere ❌
let currentState = 'idle';
function someFunction() {
currentState = 'loaded'; // Can this happen from 'idle'? 🤔
}
function anotherFunction() {
currentState = 'error'; // Should this be possible? 🤔
}
```
--------------------------------
### Use useMachine Hook with Haunted and Robot
Source: https://github.com/matthewp/robot/blob/main/packages/haunted-robot/readme.md
This example demonstrates how to use the `useMachine` hook from `haunted-robot` to integrate a Robot state machine with a Haunted web component. It sets up a simple two-state machine and a button to transition between states, displaying the current state's name.
```javascript
import { useMachine } from 'haunted-robot';
import { html, component } from 'haunted';
import { createMachine, state, transition } from 'robot3';
const machine = createMachine({
one: state(
transition('next', 'two')
),
two: state()
});
function App() {
const [current, send] = useMachine(machine);
return html`
`;
}
customElements.define('my-app', component(App));
```
--------------------------------
### Define Haunted Component with Robot State Machine
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/haunted-robot.md
This example demonstrates how to define a Haunted component that uses the `useMachine` hook to manage state with a Robot state machine. It includes necessary imports for Robot, Haunted, and Lit-HTML.
```js
import { createMachine, state, transition } from 'robot3';
import { component } from 'haunted';
import { html } from 'lit-html';
import { useMachine } from 'haunted-robot';
const machine = createMachine({
off: state(
transition('toggle', 'on')
),
on: state(
transition('toggle', 'off')
)
});
function App() {
const [current, send] = useMachine(machine);
return html`
State: ${current.name}
`;
}
customElements.define('my-app', component(App));
```
--------------------------------
### Create Astro Project with Basics Template
Source: https://github.com/matthewp/robot/blob/main/docs/README.md
Use this command to initialize a new Astro project with the Basics starter kit.
```sh
npm create astro@latest -- --template basics
```
--------------------------------
### Create a Basic Machine with States and Context
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/createMachine.md
Defines a machine with 'idle' and 'input' states and initializes context with 'first' and 'last' properties.
```javascript
import { createMachine, state } from 'robot3';
const context = () => ({
first: 'Wilbur',
last: 'Phillips'
});
const machine = createMachine({
idle: state(),
input: state()
}, context);
```
--------------------------------
### Run Core Tests Server
Source: https://github.com/matthewp/robot/blob/main/contributing.md
Launch the test server for the core package. Load http://localhost:1965/test/test.html in a browser to run tests.
```shell
npm run --workspace=packages/core server
```
--------------------------------
### Guard for Validation Check
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
An example of using guards for validation. This guard checks if the context contains both an email and a password before allowing the 'submit' transition.
```javascript
// ✅ Good use of guards
idle: state(
transition('submit', 'processing',
guard((ctx) => ctx.email && ctx.password) // Validation
)
)
```
--------------------------------
### Enable Robot3 Logging
Source: https://context7.com/matthewp/robot/llms.txt
Import `robot3/logging` to log state transition details to the console. Each transition logs the destination state and a group containing the machine, current context, previous context, and triggering event.
```javascript
import 'robot3/logging';
import { createMachine, state, transition } from 'robot3';
import { interpret } from 'robot3';
const machine = createMachine({
idle: state(transition('fetch', 'loading')),
loading: state(transition('done', 'idle'))
});
const service = interpret(machine, () => {});
service.send('fetch');
// Console output:
// Enter state loading
// ▶ Details:
// Machine
// Current state
// Previous state
// Event "fetch"
```
--------------------------------
### Configure Test Environment for React Robot
Source: https://github.com/matthewp/robot/blob/main/packages/react-robot/test/test.html
Sets up the testing environment by disabling autostart for QUnit and enabling the React Act environment. Includes module imports for react, robot3, and robot-hooks.
```javascript
QUnit.config.autostart = false; self.IS_REACT_ACT_ENVIRONMENT = true; { "imports": { "react": "./react.js", "robot3": "../../../node_modules/robot3/machine.js", "robot-hooks": "../../../node_modules/robot-hooks/machine.js" } } import './test.js'; QUnit.start();
```
--------------------------------
### Define Machine with States and Transitions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
Define a state machine with multiple states and transitions between them. Imports required: 'createMachine', 'state', 'transition'.
```javascript
import { createMachine, state, transition } from 'robot3';
const machine = createMachine({
idle: state(
transition('fetch', 'loading')
),
loading: state(
transition('success', 'loaded'),
transition('error', 'error')
),
loaded: state(),
error: state(
transition('retry', 'loading')
)
});
```
--------------------------------
### Rate Limiting Guard
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
An example of a rate limiting guard that prevents actions if they occur too frequently. This guard checks the time since the last request.
```javascript
const notRateLimited = (ctx) => {
const now = Date.now();
const timeSinceLastRequest = now - ctx.lastRequestTime;
return timeSinceLastRequest > 1000; // 1 second between requests
};
const machine = createMachine({
idle: state(
transition('fetch', 'loading',
guard(notRateLimited)
)
),
loading: state()
}, () => ({
lastRequestTime: 0
}));
```
--------------------------------
### Using `reduce` Helper for Context Updates
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Demonstrates the `reduce` helper as a concise alternative to `action` for context-updating functions. It achieves the same result as a standard action but with less boilerplate.
```js
import { reduce } from 'robot3';
// Using action
const increment = action((ctx) => ({ ...ctx, count: ctx.count + 1 }));
// Using reduce (same thing, less verbose)
const increment = reduce((ctx) => ({ ...ctx, count: ctx.count + 1 }));
// Common usage
idle: state(
transition('increment', 'idle',
reduce((ctx) => ({ ...ctx, count: ctx.count + 1 }))
)
)
```
--------------------------------
### Defining a Simple Logging Action
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Shows how to define a custom action using the `action` function to log transition events. This action logs the event and returns the context unchanged.
```js
import { createMachine, state, transition, action } from 'robot3';
const logTransition = action((ctx, event) => {
console.log('Transitioning with:', event);
return ctx; // Return unchanged context
});
const machine = createMachine({
idle: state(
transition('start', 'running', logTransition)
),
running: state()
});
```
--------------------------------
### Set Initial State (Default)
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-state.md
By default, the first state defined in your machine configuration is set as the initial state. No explicit configuration is needed if this is desired.
```javascript
const machine = createMachine({
idle: state(), // This is the initial state
active: state()
});
```
--------------------------------
### Add a Changeset for Release Automation
Source: https://github.com/matthewp/robot/blob/main/contributing.md
Generate a changeset file to automate the release process. Follow the prompts to describe your changes.
```shell
npm run changeset
```
--------------------------------
### API Call Action
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
An example of an action that triggers an API call to save data. It sends the current context's data to a '/api/save' endpoint using a POST request.
```js
const saveToAPI = action((ctx) => {
fetch('/api/save', {
method: 'POST',
body: JSON.stringify(ctx.data)
});
return ctx;
});
```
--------------------------------
### Basic LitElement with Robot State Machine
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/lit-robot.md
Integrates a state machine into a LitElement for controlling internal state. Requires importing Robot, LitElement, and robot3's createMachine.
```js
import { createMachine, state, transition } from 'robot3';
import { LitElement, html } from 'lit-element';
import { Robot } from 'lit-robot';
const machine = createMachine({
off: state(
transition('toggle', 'on')
),
on: state(
transition('toggle', 'off')
)
});
class App extends Robot(LitElement) {
static machine = machine;
render() {
let { send } = this.service;
let current = this.machine.state;
return html`
State: ${current.name}
`;
}
}
customElements.define('my-app', component(App));
```
--------------------------------
### Define Transitions with Target States
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-transitions.md
Ensure the target state specified in a transition exists within the machine definition. This example shows transitions from 'red' to 'yellow', and 'yellow' to 'green'.
```javascript
const machine = createMachine({
red: state(
transition('next', 'yellow') // 'yellow' must exist
),
yellow: state(
transition('next', 'green')
),
green: state(
transition('next', 'red')
)
});
```
--------------------------------
### Child Svelte Component Accessing Context
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/svelte-robot-factory.md
A child Svelte component can access the Robot service's context to display context-specific data. This example displays the 'foo' property from the context.
```svelte
/// Child.svelte
Context value of foo property: {foo}
```
--------------------------------
### Create a Machine with an Initial State
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/createMachine.md
Creates a toggle machine that can be initialized to either 'active' or 'inactive' state. The initial state is passed as the first argument to createMachine.
```javascript
const toggleMachine = initial => createMachine(initial, {
active: state(
transition('toggle', 'inactive')
),
inactive: state(
transition('toggle', 'active')
)
});
const myMachine = toggleMachine('inactive');
const service = interpret(myMachine, () => {});
console.log(service.machine.current, 'inactive');
```
--------------------------------
### Svelte Component with Robot Service
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/svelte-robot-factory.md
Integrate the Robot service into a Svelte component to access its state, context, and send events. This example shows how to subscribe to the service and dispatch a 'toggle' event.
```svelte
Current state value: {current}
```
--------------------------------
### Enable Features with Guards
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Use guards to conditionally enable features based on context properties like user roles or feature flags. This example shows how to guard a transition to a 'newFeature' state.
```js
const featureEnabled = (ctx) => ctx.features.newUI === true;
const betaUser = (ctx) => ctx.user.betaTester === true;
const machine = createMachine({
home: state(
transition('openNewFeature', 'newFeature',
guard(featureEnabled),
guard(betaUser)
)
),
newFeature: state()
});
```
--------------------------------
### Chaining Multiple Actions in a Transition
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Shows how to define a sequence of actions within a single transition. Actions are executed in the order they are listed, with the output context of one action becoming the input for the next.
```js
const validate = reduce((ctx, ev) => ({
...ctx,
isValid: ev.data.length > 0
}));
const trackSubmit = action((ctx) => {
analytics.track('form_submitted');
return ctx;
});
const clearForm = reduce((ctx) => ({
...ctx,
data: ''
}));
const machine = createMachine({
editing: state(
transition('submit', 'submitted',
validate, // 1. Validate data
trackSubmit, // 2. Track event
clearForm // 3. Clear form
)
),
submitted: state()
});
```
--------------------------------
### Basic Immediate Transition
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/immediate.md
Defines a state that immediately transitions to the 'work' state upon entering.
```javascript
import { createMachine, reduce, state, transition } from 'robot3';
const machine = createMachine({
breakfast: state(
immediate('work')
),
work: state()
});
```
--------------------------------
### Use Guarded Transitions in Machine Definition
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/composition.md
Define a machine using extended reusable transitions that incorporate guards. This example applies a guard to limit the 'first' name input to 10 characters.
```javascript
import { createMachine, guard, state } from 'robot3';
import { formField } from './transitions.js';
const machine = createMachine({
form: state(
formField('first',
guard((ctx) => ctx.first.length <= 10)
),
formField('last')
)
});
```
--------------------------------
### Context Updating Actions: Increment and Set User
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Provides examples of actions that modify the machine's context. `increment` increases a count, and `setUser` updates the user information based on event data.
```js
const increment = action((ctx) => ({ ...ctx,
count: ctx.count + 1
}));
const setUser = action((ctx, event) => ({ ...ctx,
user: event.data
}));
const machine = createMachine({
idle: state(
transition('increment', 'idle', increment),
transition('login', 'authenticated', setUser)
),
authenticated: state()
}, () => ({ count: 0,
user: null
}));
```
--------------------------------
### Chaining Multiple Guards
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Demonstrates how to chain multiple guards for a single transition. All guards must return true for the transition to be allowed.
```javascript
const isValid = (ctx) => ctx.input.length > 0;
const hasPermission = (ctx) => ctx.user.role === 'admin';
const notRateLimited = (ctx) => ctx.requestCount < 10;
const machine = createMachine({
idle: state(
transition('submit', 'processing',
guard(isValid),
guard(hasPermission),
guard(notRateLimited)
)
),
processing: state()
});
```
--------------------------------
### Guard Execution Timing and Side Effects
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Guards execute before actions and reducers, ensuring they see the old context and preventing actions/reducers from running if guards fail. This example logs context values to demonstrate execution order.
```js
const machine = createMachine({
idle: state(
transition('submit', 'processing',
guard((ctx) => {
console.log('Guard checking:', ctx.value); // Sees old value
return ctx.value > 0;
}),
reduce((ctx) => {
console.log('Reducer running:', ctx.value); // Only runs if guard passes
return { ...ctx, value: ctx.value + 1 };
})
)
),
processing: state()
}, () => ({ value: 5 }));
```
--------------------------------
### Run Core Tests from CLI
Source: https://github.com/matthewp/robot/blob/main/contributing.md
Execute all tests for the core package directly from the command line.
```shell
npm test --workspace=packages/core
```
--------------------------------
### LitElement Component with Robot State Machine
Source: https://github.com/matthewp/robot/blob/main/packages/lit-robot/readme.md
Demonstrates how to create a LitElement component that integrates with Robot for state management. Ensure you have the necessary imports for Robot, LitElement, and htm.
```js
import { Robot } from 'lit-robot';
import { LitElement, html } from 'lit-element';
import { html } from 'htm/prect';
class MyApp extends Robot(LitElement) {
static machine = createMachine({
one: state(
transition('next', 'two')
),
two: state()
});
render() {
let { send } = this.service;
let current = this.machine.state;
return html`
`;
}
}
```
--------------------------------
### Implementing Immediate Transitions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-events.md
Use `immediate` transitions to automatically transition to a new state upon entering a specific state, often used with guards for conditional logic.
```javascript
import { createMachine, state, transition, immediate } from 'robot3';
const machine = createMachine({
idle: state(
transition('fetch', 'loading')
),
loading: state(
transition('done', 'validate')
),
validate: state(
// Automatically transitions when entering 'validate'
immediate('loaded', guard(isValid)),
immediate('error', guard(isInvalid))
),
loaded: state(),
error: state()
});
```
--------------------------------
### Initial State
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/createMachine.md
Optionally, you can provide the initial state as the first argument to `createMachine`. If no initial state is provided, the first state listed in the states object will be the initial state.
```APIDOC
## createMachine(initialState, states, context?)
### Description
Defines the initial state of the machine.
### Parameters
#### initialState
- **initialState** (string) - Required - The name of the state to be set as the initial state.
#### states
- **states** (object) - Required - An object where keys are state names and values are state definitions.
### Request Example
```js
const toggleMachine = initial => createMachine(initial, {
active: state(
transition('toggle', 'inactive')
),
inactive: state(
transition('toggle', 'active')
)
});
const myMachine = toggleMachine('inactive');
```
```
--------------------------------
### Pure vs. Impure Guards
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Illustrates the difference between pure guards (recommended) and impure guards. Pure guards do not modify context or external state and return consistent results, making them predictable and testable.
```js
// ✅ Good - pure guard
const isValid = (ctx) => ctx.count > 0;
// ❌ Bad - has side effects
const isValidWithSideEffect = (ctx) => {
console.log('Checking validity'); // Side effect
ctx.count++; // Mutates context
return true;
};
// ❌ Bad - non-deterministic
const isValidRandom = (ctx) => Math.random() > 0.5; // Random result
```
--------------------------------
### Sending Events to Robot State Machine in Haunted Component
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/haunted-robot.md
This example demonstrates how to send events to a Robot state machine from a Haunted component. It uses the `send` function returned by the `useMachine` hook to trigger transitions, such as 'toggle', on button clicks.
```js
const [current, send] = useMachine(machine);
return html`
`;
```
--------------------------------
### Event-Driven Architecture with Multiple Event Sources
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-events.md
Demonstrates how different parts of an application can send events to a state machine, making the system reactive and decoupled. Events can be simple strings or objects with data.
```javascript
// Different parts of your app can send events
button.addEventListener('click', () => {
service.send('userAction');
});
socket.on('message', (data) => {
service.send({ type: 'messageReceived', data });
});
setTimeout(() => {
service.send('timeout');
}, 5000);
// The machine handles all events based on current state
const machine = createMachine({
waiting: state(
transition('userAction', 'processing'),
transition('messageReceived', 'processing'),
transition('timeout', 'expired')
),
processing: state(),
expired: state()
});
```
--------------------------------
### Robot Machine Definition and Service Initialization
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/svelte-robot-factory.md
Define a Robot state machine with states, transitions, and context reduction. Initialize the useMachine service with the defined machine and initial event.
```javascript
/// store
import { createMachine, state, transition, invoke, reduce } from 'robot3';
import { useMachine } from 'svelte-robot-factory';
const context = event => ({
foo: event.foo
});
const event = {
foo: 'initial'
};
const machine = createMachine({
inactive: state(
transition('toggle', 'active',
reduce((ctx, ev)=>({ ...ctx, foo: 'bar'}))
)
),
active: state(
transition('toggle', 'inactive',
reduce((ctx, ev)=>({ ...ctx, foo: 'foo'}))
)
)
}, context);
const service = useMachine(machine, event);
export default service;
```
--------------------------------
### Interpret Robot3 Machines into Services
Source: https://context7.com/matthewp/robot/llms.txt
Create a live service from a machine using `interpret`. The service manages the machine's state, context, and provides a `send` function. It does not mutate the original machine.
```javascript
import { createMachine, state, transition, reduce } from 'robot3';
import { interpret } from 'robot3';
const machine = createMachine({
asleep: state(transition('wake', 'awake')),
awake: state(transition('sleep', 'asleep'))
}, () => ({ wakeCount: 0 }));
const service = interpret(
machine,
(svc) => {
// onChange fires after every transition (even self-transitions)
console.log(`→ ${svc.machine.current}`, svc.context);
},
{ wakeCount: 10 } // initialContext passed to the context function
);
console.log(service.machine.current); // 'asleep'
console.log(service.context.wakeCount); // 10
service.send('wake'); // → awake { wakeCount: 10 }
service.send('sleep'); // → asleep { wakeCount: 10 }
// Send an event object with extra data (available in guards/reducers as `ev`)
service.send({ type: 'wake', source: 'alarm' });
```
--------------------------------
### Compose Machine with Imported Transitions
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/composition.md
Import reusable transition functions from a module to create a more succinct machine definition. This promotes code reuse and cleaner machine structures.
```javascript
import { createMachine, state } from 'robot3';
import { formField } from './transitions.js';
const machine = createMachine({
form: state(
formField('first'),
formField('last')
)
});
```
--------------------------------
### Create a State Machine with robot3
Source: https://context7.com/matthewp/robot/llms.txt
Define an immutable state machine using `createMachine`, `state`, `transition`, and `reduce`. The context function initializes the machine's context.
```javascript
import { createMachine, state, transition, reduce } from 'robot3';
// Context function receives the initialContext passed to interpret()
const context = initialCtx => ({
user: initialCtx?.user ?? null,
count: 0,
});
const machine = createMachine('idle', {
idle: state(
transition('start', 'running')
),
running: state(
transition('increment', 'running',
reduce((ctx) => ({ ...ctx, count: ctx.count + 1 }))
),
transition('stop', 'idle')
)
}, context);
console.log(machine.current); // 'idle'
console.log(machine.state.name); // 'idle'
console.log(machine.state.value.final); // false
```
--------------------------------
### Define Machine Context with Initial Context
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/createMachine.md
Illustrates how to define a context function that uses an initialContext argument. This context is passed to the interpret function.
```javascript
const context = initialContext => ({
foo: initialContext.foo
});
const machine = createMachine({
idle: state()
}, context);
const initialContext = {
foo: 'bar'
};
interpret(machine, service => {
// Do stuff when the service changes.
}, initialContext);
```
--------------------------------
### Basic Preact Component with useMachine Hook
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/preact-robot.md
Demonstrates a simple Preact component that uses the `useMachine` hook to manage a state machine. It displays the current state and a button to send events.
```jsx
import { createMachine, state, transition } from 'robot3';
import { h, render } from 'preact';
import { useMachine } from 'preact-robot';
const machine = createMachine({
off: state(
transition('toggle', 'on')
),
on: state(
transition('toggle', 'off')
)
});
function App() {
const [current, send] = useMachine(machine);
return (
<>
State: {current.name}
>
);
}
render(, document.querySelector('#app'));
```
--------------------------------
### Sending an Event to a State Machine
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-events.md
Demonstrates sending an event to trigger a state transition, including guards and reducers. The `service.send('fetch')` call initiates the event flow.
```javascript
const machine = createMachine({
idle: state(
transition('fetch', 'loading',
guard((ctx) => ctx.hasToken),
reduce((ctx) => ({ ...ctx, loading: true }))
)
),
loading: state()
});
// This triggers the entire flow above
service.send('fetch');
```
--------------------------------
### Astro Project Structure Overview
Source: https://github.com/matthewp/robot/blob/main/docs/README.md
This is a typical file structure for an Astro project. Pages are routed based on their file names in `src/pages/`.
```text
/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
--------------------------------
### Define Machine with Context
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-state.md
When creating a machine, you can provide a factory function as the second argument to define initial context data. This data persists across states.
```javascript
const machine = createMachine({
idle: state(
transition('fetch', 'loading')
),
loading: state(
transition('success', 'loaded')
),
loaded: state()
}, () => ({
// This is context - data that can change
users: [],
errorMessage: null,
retryCount: 0
}));
```
--------------------------------
### Action Pattern: Logging and Analytics
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
An action to log transition events with timestamps and track them using an analytics service. This is useful for monitoring and debugging.
```javascript
const trackTransition = action((ctx, ev) => {
console.log(`[${new Date().toISOString()}] ${ev.type}`);
analytics.track('transition', {
event: ev.type,
state: ctx.currentState
});
return ctx;
});
// Add to every important transition
transition('submit', 'processing', trackTransition)
```
--------------------------------
### Best Practice: Single Responsibility Per Action
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-actions.md
Demonstrates breaking down a complex action into smaller, focused actions, each handling a single concern like logging, persistence, or analytics.
```javascript
// ❌ Bad - doing too much
const megaAction = action((ctx, ev) => {
console.log('Event:', ev);
localStorage.setItem('data', ctx.data);
analytics.track('event');
document.title = ctx.page;
return { ...ctx, processed: true };
});
// ✅ Better - separate concerns
const logEvent = action((ctx, ev) => { /* ... */ });
const persistData = action((ctx) => { /* ... */ });
const trackEvent = action((ctx) => { /* ... */ });
const updateTitle = action((ctx) => { /* ... */ });
const markProcessed = reduce((ctx) => ({ ...ctx, processed: true }));
transition('submit', 'processing',
logEvent,
persistData,
trackEvent,
updateTitle,
markProcessed
)
```
--------------------------------
### Testing Pure Guards
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Demonstrates how to test guards independently of the state machine. Since guards are pure functions, they can be tested with simple assertions using sample context and event objects.
```js
const isEligible = (ctx, ev) => {
return ev.age >= 18 && ctx.country === 'US';
};
// Test without a full machine
console.assert(
isEligible({ country: 'US' }, { age: 21 }) === true
);
console.assert(
isEligible({ country: 'US' }, { age: 16 }) === false
);
console.assert(
isEligible({ country: 'UK' }, { age: 21 }) === false
);
```
--------------------------------
### State Machine With Guards
Source: https://github.com/matthewp/robot/blob/main/docs/src/content/docs/concepts-guards.md
Shows a concise state machine using guards to handle conditional transitions inline. This avoids excessive states.
```javascript
const machine = createMachine({
idle: state(
transition('submit', 'submitting',
guard(isValid),
guard(hasPermission)
)
),
submitting: state()
});
```