Skip to content

Instantly share code, notes, and snippets.

@maxsei
Created January 31, 2024 21:28
Show Gist options
  • Select an option

  • Save maxsei/9107cdeab4ac90b4d7474ea6068004c7 to your computer and use it in GitHub Desktop.

Select an option

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
// 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