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