Checkbox

Parent State

We'll start by creating a compound state.

import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { // child states will go here }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }

This defines the root state for our program. We will later interact with the state machine by calling methods on the checkboxState object.

Child states

Let's add the child checked and unchecked p states to our state machine.

import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic(), checked: atomic(), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }

Because the unchecked state is listed first among the child states, it is the initial state that the state machine will transition to when we initialise it.

State transitions

We have added the necessary checkbox states above, but how do we switch between them? We'll add event handlers that transition from one state to the other.

import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }
import { atomic, compound } from 'hine'; const checkboxState = compound({ name: 'checkbox', children: { unchecked: atomic({ on: { toggle: { goto: 'checked' }, }, }), checked: atomic({ on: { toggle: { goto: 'unchecked' }, }, }), }, }); console.log({ checkboxState }); // { checkboxState: CompoundState{} }

Responding to changes

We can now run our checkbox state machine! We will add a myFunction() always listener. The function will be called with an event object every time event is dispatched to our machine.

import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });
import { compound } from 'hine'; const checkboxState = compound({ always: 'myFunction', }); checkboxState.resolve({ actions: { myFunction(event) { console.log(checkboxState === event.target); // true }, }, });

Dispatching events

Now that we have a checkbox machine we can run it! We will call the .matches() method to confirm the current state and .dispatch() to change the current state.

import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true
import { compound } from 'hine'; const checkboxState = compound({ on: { toggle: [ /* ...omitted for brevity */ ], }, children: { /* ...omitted for brevity */ }, }); checkboxState.resolve(); console.log(checkboxState.matches('checkbox.unchecked')); // true checkboxState.dispatch('toggle'); console.log(checkboxState.matches('checkbox.checked')); // true

There you have it! That's most of what you need to create a simple state machine. By subscribing to the machine you can use it to emit side effects like manipulating a checkbox on a web page or logging a state change to analytics.

As an added challenge, try implementing a counter with an active and inactive state similar to the checked and unchecked states. It should only be possible to increment the counter in the active state.