UNPKG

b0nes

Version:

Zero-dependency component library and SSR/SSG framework

90 lines (76 loc) 2.58 kB
import { createFSM } from '/client/fsm.js'; import { createStore } from '/client/store.js'; export const client = (root) => { // Create a store, add state and actions... usually what // redux does window.store = createStore({ state: { step: 'step1', name: '', email: '', age: '' }, actions: { update: (state, payload) => ({ ...state, ...payload }), setStep: (state, step) => ({ ...state, step }) } }); // Create your tiny finite state machine, initial state, states, ... const fsm = createFSM({ initial: 'step1', states: { step1: { on: { NEXT: 'step2', }}, step2: { on: { NEXT: 'step3', BACK: 'step1' }}, step3: { on: { SUBMIT: 'success', BACK: 'step2' }}, success: {} } }); // This connects the store to the FSM together fsm.subscribe((transition) => { window.store.dispatch('setStep', transition.to); }); const progress = root.querySelector('progress'); const status = root.querySelector('[data-status]'); // The rendering what needs to happen to make it work? // some logic to remove hidden attribute or to surface things like results const render = () => { const s = window.store.getState(); progress.value = { step1:1, step2:2, step3:3, success:3 }[s.step]; status.textContent = s.step; // Show/hide steps root.querySelectorAll('[data-step]').forEach(el => { el.hidden = el.dataset.step !== s.step; }); // Success: fill data if (s.step === 'success') { root.querySelectorAll('[data-field]').forEach(el => { el.textContent = s[el.dataset.field] || '—'; }); } }; // Sync inputs → store (two-way binding) root.addEventListener('input', e => { if (e.target.name) { window.store.dispatch('update', { [e.target.name]: e.target.value }); } }); //cleanup const resetForm = () => { fsm.reset(); window.store.reset(); console.log(store.getState()) // Clear DOM inputs (because value property doesn't auto-update from store on reset) root.querySelectorAll('input').forEach(input => { input.value = ''; }); } // Buttons → FSM events root.addEventListener('click', e => { console.log('clicked',e) if (!e.target.matches('button[data-action]')) return; const a = e.target.dataset.action; if (a === 'next') fsm.send('NEXT'); if (a === 'back') fsm.send('BACK'); if (a === 'submit') fsm.send('SUBMIT'); if (a === 'reset') { resetForm() } }); render(); window.store.subscribe(render); };