parent
b3ad6815ad
commit
2022ebe38c
@ -0,0 +1,58 @@
|
||||
const STATES = Object.freeze({
|
||||
INITIAL: "initial",
|
||||
SEARCH: "search",
|
||||
MANUAL_CONNECT: "manualConnect",
|
||||
READY_TO_ROLL: "ready",
|
||||
ERROR: "error",
|
||||
});
|
||||
|
||||
const EVENTS = Object.freeze({
|
||||
TO_SEARCH: "toSearch",
|
||||
TO_MANUAL_CONNECT: "toManualConnect",
|
||||
TO_READY: "toReady",
|
||||
TO_ERROR: "toError",
|
||||
});
|
||||
|
||||
const transitions = new Map([
|
||||
[[STATES.INITIAL, EVENTS.TO_SEARCH], STATES.SEARCH],
|
||||
[[STATES.INITIAL, EVENTS.TO_ERROR], STATES.ERROR],
|
||||
|
||||
[[STATES.SEARCH, EVENTS.TO_MANUAL_CONNECT], STATES.MANUAL_CONNECT],
|
||||
[[STATES.SEARCH, EVENTS.TO_READY], STATES.READY_TO_ROLL],
|
||||
|
||||
[[STATES.MANUAL_CONNECT, EVENTS.TO_READY], STATES.READY_TO_ROLL],
|
||||
[[STATES.MANUAL_CONNECT, EVENTS.TO_ERROR], STATES.ERROR],
|
||||
]);
|
||||
|
||||
function createFSM(initialState = STATES.INITIAL) {
|
||||
const fsm = new EventTarget();
|
||||
let state = initialState;
|
||||
|
||||
fsm.getState = () => state;
|
||||
|
||||
fsm.dispatch = (eventName) => {
|
||||
const key = JSON.stringify([state, eventName]);
|
||||
const next = [...transitions.entries()].find(
|
||||
([k]) => JSON.stringify(k) === key,
|
||||
)?.[1];
|
||||
|
||||
if (next) {
|
||||
const prev = state;
|
||||
state = next;
|
||||
|
||||
fsm.dispatchEvent(
|
||||
new CustomEvent("statechange", {
|
||||
detail: { prev, next, trigger: eventName },
|
||||
}),
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
console.warn(`No transition from "${state}" on "${eventName}"`);
|
||||
return false;
|
||||
};
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
export { createFSM, STATES, EVENTS };
|
||||
@ -0,0 +1,32 @@
|
||||
import { createFSM, STATES } from "./state.js";
|
||||
|
||||
const fsm = createFSM();
|
||||
const container = document.getElementById("app");
|
||||
|
||||
const pages = {
|
||||
[STATES.INITIAL]: `
|
||||
<h1>INITIAL</h1>
|
||||
`,
|
||||
[STATES.SEARCH]: `
|
||||
<h1>SEARCH</h1>
|
||||
`,
|
||||
[STATES.MANUAL_CONNECT]: `
|
||||
<h1>MANUAL CONNECT</h1>
|
||||
`,
|
||||
[STATES.ERROR]: `
|
||||
<h1>ERROR</h1>
|
||||
`,
|
||||
};
|
||||
|
||||
function render(state) {
|
||||
container.innerHTML = pages[state] ?? "<p>Unknown state</p>";
|
||||
}
|
||||
|
||||
fsm.addEventListener("statechange", (e) => {
|
||||
const { next } = e.detail;
|
||||
render(next);
|
||||
});
|
||||
|
||||
render(fsm.getState());
|
||||
|
||||
export { fsm };
|
||||
Loading…
Reference in new issue