Created
January 31, 2024 21:28
-
-
Save maxsei/9107cdeab4ac90b4d7474ea6068004c7 to your computer and use it in GitHub Desktop.
super small hiccup-like javascript framework powerd by "signals" 1116 bytes 521 bytes gzipped
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // START FRAMEWORK | |
| class Signal { | |
| state; | |
| subs; | |
| constructor(state) { | |
| this.state = state; | |
| this.subs = []; | |
| } | |
| subscribe(sub) { | |
| this.subs.push(sub); | |
| } | |
| next(curr) { | |
| this.subs.map((sub) => sub(this.state, curr)); | |
| this.state = curr; | |
| } | |
| deref() { | |
| return this.state; | |
| } | |
| } | |
| const signal = (x) => new Signal(x); | |
| const hic = (tree) => { | |
| if (tree instanceof Signal) { | |
| let el = hic(tree.deref()); | |
| tree.subscribe((prev, curr) => { | |
| if (prev === curr) { | |
| return; | |
| } | |
| const newEl = hic(curr); | |
| el.replaceWith(newEl); | |
| el = newEl; | |
| }); | |
| return el; | |
| } | |
| if (typeof tree === "string" || typeof tree === "number") { | |
| return document.createTextNode(tree); | |
| } | |
| if (!Array.isArray(tree)) { | |
| // console.error(tree) | |
| throw new Error("cannot parse tree"); | |
| } | |
| let [tag, attrs, ...children] = tree; | |
| // NB: renaming class is as a convenience. | |
| if (attrs.class) { | |
| attrs.className = attrs.class; | |
| delete attrs.class; | |
| } | |
| const el = Object.assign(document.createElement(tag), attrs); | |
| el.append(...children.filter(Boolean).map(hic)); | |
| return el; | |
| }; | |
| // END FRAMEWORK | |
| // START USAGE | |
| const app = document.querySelector("#app"); | |
| const counter = signal(0); | |
| const el = hic([ | |
| "div", | |
| { id: "root" }, | |
| "Hello, ", | |
| "World", | |
| null, | |
| ["div", { class: "red" }, "With a nested elements..."], | |
| [ | |
| "div", | |
| {}, | |
| ["button", { onclick: () => counter.next(counter.deref() - 1) }, "-"], | |
| ["button", { onclick: () => counter.next(counter.deref() + 1) }, "+"], | |
| ], | |
| ["div", {}, "count: ", counter], | |
| ]); | |
| app.appendChild(el); | |
| // END USAGE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment