aboutsummaryrefslogtreecommitdiff
path: root/priv/lustre-server-component.mjs
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2024-02-15 17:01:19 +0000
committerHayleigh Thompson <me@hayleigh.dev>2024-02-15 17:01:19 +0000
commit48394b9a69fcbe7864f235f0803fb99305905487 (patch)
treec3324ff171c34c2dc0f7546ff8739e09c995e725 /priv/lustre-server-component.mjs
parente486614c0aafbed8da06b22fa20c32812d01ed52 (diff)
downloadlustre-48394b9a69fcbe7864f235f0803fb99305905487.tar.gz
lustre-48394b9a69fcbe7864f235f0803fb99305905487.zip
:wrench: Build the server component runtime.
Diffstat (limited to 'priv/lustre-server-component.mjs')
-rw-r--r--priv/lustre-server-component.mjs558
1 files changed, 0 insertions, 558 deletions
diff --git a/priv/lustre-server-component.mjs b/priv/lustre-server-component.mjs
deleted file mode 100644
index 8230074..0000000
--- a/priv/lustre-server-component.mjs
+++ /dev/null
@@ -1,558 +0,0 @@
-// build/dev/javascript/lustre/lustre/internals/constants.mjs
-var diff = 0;
-var emit = 1;
-var init = 2;
-var event = 4;
-var attrs = 5;
-
-// build/dev/javascript/prelude.mjs
-var CustomType = class {
- withFields(fields) {
- let properties = Object.keys(this).map(
- (label) => label in fields ? fields[label] : this[label]
- );
- return new this.constructor(...properties);
- }
-};
-var List = class {
- static fromArray(array, tail) {
- let t = tail || new Empty();
- return array.reduceRight((xs, x) => new NonEmpty(x, xs), t);
- }
- [Symbol.iterator]() {
- return new ListIterator(this);
- }
- toArray() {
- return [...this];
- }
- atLeastLength(desired) {
- for (let _ of this) {
- if (desired <= 0)
- return true;
- desired--;
- }
- return desired <= 0;
- }
- hasLength(desired) {
- for (let _ of this) {
- if (desired <= 0)
- return false;
- desired--;
- }
- return desired === 0;
- }
- countLength() {
- let length2 = 0;
- for (let _ of this)
- length2++;
- return length2;
- }
-};
-var ListIterator = class {
- #current;
- constructor(current) {
- this.#current = current;
- }
- next() {
- if (this.#current instanceof Empty) {
- return { done: true };
- } else {
- let { head, tail } = this.#current;
- this.#current = tail;
- return { value: head, done: false };
- }
- }
-};
-var Empty = class extends List {
-};
-var NonEmpty = class extends List {
- constructor(head, tail) {
- super();
- this.head = head;
- this.tail = tail;
- }
-};
-var Result = class _Result extends CustomType {
- static isResult(data) {
- return data instanceof _Result;
- }
-};
-var Ok = class extends Result {
- constructor(value) {
- super();
- this[0] = value;
- }
- isOk() {
- return true;
- }
-};
-var Error = class extends Result {
- constructor(detail) {
- super();
- this[0] = detail;
- }
- isOk() {
- return false;
- }
-};
-function makeError(variant, module, line, fn, message, extra) {
- let error = new globalThis.Error(message);
- error.gleam_error = variant;
- error.module = module;
- error.line = line;
- error.fn = fn;
- for (let k in extra)
- error[k] = extra[k];
- return error;
-}
-
-// build/dev/javascript/gleam_stdlib/dict.mjs
-var tempDataView = new DataView(new ArrayBuffer(8));
-var SHIFT = 5;
-var BUCKET_SIZE = Math.pow(2, SHIFT);
-var MASK = BUCKET_SIZE - 1;
-var MAX_INDEX_NODE = BUCKET_SIZE / 2;
-var MIN_ARRAY_NODE = BUCKET_SIZE / 4;
-
-// build/dev/javascript/gleam_stdlib/gleam/result.mjs
-function map2(result, fun) {
- if (result.isOk()) {
- let x = result[0];
- return new Ok(fun(x));
- } else if (!result.isOk()) {
- let e = result[0];
- return new Error(e);
- } else {
- throw makeError(
- "case_no_match",
- "gleam/result",
- 67,
- "map",
- "No case clause matched",
- { values: [result] }
- );
- }
-}
-
-// build/dev/javascript/lustre/vdom.ffi.mjs
-function morph(prev, curr, dispatch, parent) {
- if (curr?.tag && prev?.nodeType === 1) {
- const nodeName = curr.tag.toUpperCase();
- const ns = curr.namespace || "http://www.w3.org/1999/xhtml";
- if (prev.nodeName === nodeName && prev.namespaceURI == ns) {
- return morphElement(prev, curr, dispatch, parent);
- } else {
- return createElement(prev, curr, dispatch, parent);
- }
- }
- if (curr?.tag) {
- return createElement(prev, curr, dispatch, parent);
- }
- if (typeof curr?.content === "string") {
- return prev?.nodeType === 3 ? morphText(prev, curr) : createText(prev, curr);
- }
- return document.createComment(
- [
- "[internal lustre error] I couldn't work out how to render this element. This",
- "function should only be called internally by lustre's runtime: if you think",
- "this is an error, please open an issue at",
- "https://github.com/hayleigh-dot-dev/gleam-lustre/issues/new"
- ].join(" ")
- );
-}
-function patch(root, diff2, dispatch) {
- for (const created of diff2[0]) {
- const key = created[0];
- if (key === "0") {
- morph(root, created[1], dispatch, root.parentNode);
- } else {
- const segments = Array.from(key);
- const parentKey = segments.slice(0, -1).join("");
- const indexKey = segments.slice(-1)[0];
- const prev = root.querySelector(`[data-lustre-key="${key}"]`) ?? root.querySelector(`[data-lustre-key="${parentKey}"]`).childNodes[indexKey];
- morph(prev, created[1], dispatch, prev.parentNode);
- }
- }
- for (const removed of diff2[1]) {
- const key = removed[0];
- const segments = Array.from(key);
- const parentKey = segments.slice(0, -1).join("");
- const indexKey = segments.slice(-1)[0];
- const prev = root.querySelector(`[data-lustre-key="${key}"]`) ?? root.querySelector(`[data-lustre-key="${parentKey}"]`).childNodes[indexKey];
- prev.remove();
- }
- for (const updated of diff2[2]) {
- const key = updated[0];
- const prev = key === "0" ? root : root.querySelector(`[data-lustre-key="${key}"]`);
- prev.$lustre ??= { __registered_events: /* @__PURE__ */ new Set() };
- for (const created of updated[0]) {
- morphAttr(prev, created.name, created.value, dispatch);
- }
- for (const removed of updated[1]) {
- if (prev.$lustre.__registered_events.has(removed)) {
- const event2 = removed.slice(2).toLowerCase();
- prev.removeEventListener(event2, prev.$lustre[`${removed}Handler`]);
- prev.$lustre.__registered_events.delete(removed);
- delete prev.$lustre[removed];
- delete prev.$lustre[`${removed}Handler`];
- } else {
- prev.removeAttribute(removed);
- }
- }
- }
- return root;
-}
-function createElement(prev, curr, dispatch, parent = null) {
- const el = curr.namespace ? document.createElementNS(curr.namespace, curr.tag) : document.createElement(curr.tag);
- el.$lustre = {
- __registered_events: /* @__PURE__ */ new Set()
- };
- let dangerousUnescapedHtml = "";
- for (const attr of curr.attrs) {
- if (attr[0] === "class") {
- morphAttr(el, attr[0], `${el.className} ${attr[1]}`);
- } else if (attr[0] === "style") {
- morphAttr(el, attr[0], `${el.style.cssText} ${attr[1]}`);
- } else if (attr[0] === "dangerous-unescaped-html") {
- dangerousUnescapedHtml += attr[1];
- } else if (attr[0] !== "") {
- morphAttr(el, attr[0], attr[1], dispatch);
- }
- }
- if (customElements.get(curr.tag)) {
- el._slot = curr.children;
- } else if (curr.tag === "slot") {
- let children = new Empty();
- let parentWithSlot = parent;
- while (parentWithSlot) {
- if (parentWithSlot._slot) {
- children = parentWithSlot._slot;
- break;
- } else {
- parentWithSlot = parentWithSlot.parentNode;
- }
- }
- for (const child of children) {
- el.appendChild(morph(null, child, dispatch, el));
- }
- } else if (dangerousUnescapedHtml) {
- el.innerHTML = dangerousUnescapedHtml;
- } else {
- for (const child of curr.children) {
- el.appendChild(morph(null, child, dispatch, el));
- }
- }
- if (prev)
- prev.replaceWith(el);
- return el;
-}
-function morphElement(prev, curr, dispatch, parent) {
- const prevAttrs = prev.attributes;
- const currAttrs = /* @__PURE__ */ new Map();
- prev.$lustre ??= { __registered_events: /* @__PURE__ */ new Set() };
- for (const currAttr of curr.attrs) {
- if (currAttr[0] === "class" && currAttrs.has("class")) {
- currAttrs.set(currAttr[0], `${currAttrs.get("class")} ${currAttr[1]}`);
- } else if (currAttr[0] === "style" && currAttrs.has("style")) {
- currAttrs.set(currAttr[0], `${currAttrs.get("style")} ${currAttr[1]}`);
- } else if (currAttr[0] === "dangerous-unescaped-html" && currAttrs.has("dangerous-unescaped-html")) {
- currAttrs.set(
- currAttr[0],
- `${currAttrs.get("dangerous-unescaped-html")} ${currAttr[1]}`
- );
- } else if (currAttr[0] !== "") {
- currAttrs.set(currAttr[0], currAttr[1]);
- }
- }
- for (const { name, value: prevValue } of prevAttrs) {
- if (!currAttrs.has(name)) {
- prev.removeAttribute(name);
- } else {
- const value = currAttrs.get(name);
- if (value !== prevValue) {
- morphAttr(prev, name, value, dispatch);
- currAttrs.delete(name);
- }
- }
- }
- for (const name of prev.$lustre.__registered_events) {
- if (!currAttrs.has(name)) {
- const event2 = name.slice(2).toLowerCase();
- prev.removeEventListener(event2, prev.$lustre[`${name}Handler`]);
- prev.$lustre.__registered_events.delete(name);
- delete prev.$lustre[name];
- delete prev.$lustre[`${name}Handler`];
- }
- }
- for (const [name, value] of currAttrs) {
- morphAttr(prev, name, value, dispatch);
- }
- if (customElements.get(curr.tag)) {
- prev._slot = curr.children;
- } else if (curr.tag === "slot") {
- let prevChild = prev.firstChild;
- let currChild = new Empty();
- let parentWithSlot = parent;
- while (parentWithSlot) {
- if (parentWithSlot._slot) {
- currChild = parentWithSlot._slot;
- break;
- } else {
- parentWithSlot = parentWithSlot.parentNode;
- }
- }
- while (prevChild) {
- if (Array.isArray(currChild) && currChild.length) {
- morph(prevChild, currChild.shift(), dispatch, prev);
- } else if (currChild.head) {
- morph(prevChild, currChild.head, dispatch, prev);
- currChild = currChild.tail;
- }
- prevChild = prevChild.nextSibling;
- }
- for (const child of currChild) {
- prev.appendChild(morph(null, child, dispatch, prev));
- }
- } else if (currAttrs.has("dangerous-unescaped-html")) {
- prev.innerHTML = currAttrs.get("dangerous-unescaped-html");
- } else {
- let prevChild = prev.firstChild;
- let currChild = curr.children;
- while (prevChild) {
- if (Array.isArray(currChild) && currChild.length) {
- const next = prevChild.nextSibling;
- morph(prevChild, currChild.shift(), dispatch, prev);
- prevChild = next;
- } else if (currChild.head) {
- const next = prevChild.nextSibling;
- morph(prevChild, currChild.head, dispatch, prev);
- currChild = currChild.tail;
- prevChild = next;
- } else {
- const next = prevChild.nextSibling;
- prevChild.remove();
- prevChild = next;
- }
- }
- for (const child of currChild) {
- prev.appendChild(morph(null, child, dispatch, prev));
- }
- }
- return prev;
-}
-function morphAttr(el, name, value, dispatch) {
- switch (typeof value) {
- case (name.startsWith("data-lustre-on-") && "string"): {
- if (!value) {
- el.removeAttribute(name);
- el.removeEventListener(event2, el.$lustre[`${name}Handler`]);
- break;
- }
- if (el.hasAttribute(name))
- break;
- const event2 = name.slice(15).toLowerCase();
- const handler = (e) => dispatch(serverEventHandler(e));
- if (el.$lustre[`${name}Handler`]) {
- el.removeEventListener(event2, el.$lustre[`${name}Handler`]);
- }
- el.addEventListener(event2, handler);
- el.$lustre[name] = value;
- el.$lustre[`${name}Handler`] = handler;
- el.$lustre.__registered_events.add(name);
- el.setAttribute(name, value);
- break;
- }
- case "string":
- if (el.getAttribute(name) !== value)
- el.setAttribute(name, value);
- if (value === "")
- el.removeAttribute(name);
- if (name === "value" && el.value !== value)
- el.value = value;
- break;
- case (name.startsWith("on") && "function"): {
- if (el.$lustre[name] === value)
- break;
- const event2 = name.slice(2).toLowerCase();
- const handler = (e) => map2(value(e), dispatch);
- if (el.$lustre[`${name}Handler`]) {
- el.removeEventListener(event2, el.$lustre[`${name}Handler`]);
- }
- el.addEventListener(event2, handler);
- el.$lustre[name] = value;
- el.$lustre[`${name}Handler`] = handler;
- el.$lustre.__registered_events.add(name);
- break;
- }
- default:
- el[name] = value;
- }
-}
-function createText(prev, curr) {
- const el = document.createTextNode(curr.content);
- if (prev)
- prev.replaceWith(el);
- return el;
-}
-function morphText(prev, curr) {
- const prevValue = prev.nodeValue;
- const currValue = curr.content;
- if (!currValue) {
- prev?.remove();
- return null;
- }
- if (prevValue !== currValue)
- prev.nodeValue = currValue;
- return prev;
-}
-function serverEventHandler(event2) {
- const el = event2.target;
- const tag = el.getAttribute(`data-lustre-on-${event2.type}`);
- const data = JSON.parse(el.getAttribute("data-lustre-data") || "{}");
- const include = JSON.parse(el.getAttribute("data-lustre-include") || "[]");
- switch (event2.type) {
- case "input":
- case "change":
- include.push("target.value");
- break;
- }
- return {
- tag,
- data: include.reduce((data2, property) => {
- const path = property.split(".");
- for (let i = 0, o = data2, e = event2; i < path.length; i++) {
- if (i === path.length - 1) {
- o[path[i]] = e[path[i]];
- } else {
- o[path[i]] ??= {};
- e = e[path[i]];
- o = o[path[i]];
- }
- }
- return data2;
- }, data)
- };
-}
-
-// src/server-component.mjs
-var LustreServerComponent = class extends HTMLElement {
- static get observedAttributes() {
- return ["route"];
- }
- #observer = null;
- #root = null;
- #socket = null;
- constructor() {
- super();
- this.#observer = new MutationObserver((mutations) => {
- const changed = [];
- for (const mutation of mutations) {
- if (mutation.type === "attributes") {
- const { attributeName: name, oldValue: prev } = mutation;
- const next = this.getAttribute(name);
- if (prev !== next) {
- try {
- changed.push([name, JSON.parse(next)]);
- } catch {
- changed.push([name, next]);
- }
- }
- }
- }
- if (changed.length) {
- this.#socket?.send(JSON.stringify([attrs, changed]));
- }
- });
- }
- connectedCallback() {
- this.#root = document.createElement("div");
- this.appendChild(this.#root);
- }
- attributeChangedCallback(name, prev, next) {
- switch (name) {
- case "route": {
- if (!next) {
- this.#socket?.close();
- this.#socket = null;
- } else if (prev !== next) {
- const id = this.getAttribute("id");
- const route = next + (id ? `?id=${id}` : "");
- this.#socket?.close();
- this.#socket = new WebSocket(`ws://${window.location.host}${route}`);
- this.#socket.addEventListener("message", ({ data }) => {
- const [kind, ...payload] = JSON.parse(data);
- switch (kind) {
- case diff:
- return this.diff(payload);
- case emit:
- return this.emit(payload);
- case init:
- return this.init(payload);
- }
- });
- }
- }
- }
- }
- init([attrs2, vdom]) {
- const initial = [];
- for (const attr of attrs2) {
- if (attr in this) {
- initial.push([attr, this[attr]]);
- } else if (this.hasAttribute(attr)) {
- initial.push([attr, this.getAttribute(attr)]);
- }
- Object.defineProperty(this, attr, {
- get() {
- return this[`_${attr}`] ?? this.getAttribute(attr);
- },
- set(value) {
- const prev = this[attr];
- if (typeof value === "string") {
- this.setAttribute(attr, value);
- } else {
- this[`_${attr}`] = value;
- }
- if (prev !== value) {
- this.#socket?.send(
- JSON.stringify([attrs, [[attr, value]]])
- );
- }
- }
- });
- }
- this.#observer.observe(this, {
- attributeFilter: attrs2,
- attributeOldValue: true,
- attributes: true,
- characterData: false,
- characterDataOldValue: false,
- childList: false,
- subtree: false
- });
- this.morph(vdom);
- if (initial.length) {
- this.#socket?.send(JSON.stringify([attrs, initial]));
- }
- }
- morph(vdom) {
- this.#root = morph(this.#root, vdom, (msg) => {
- this.#socket?.send(JSON.stringify([event, msg.tag, msg.data]));
- });
- }
- diff([diff2]) {
- this.#root = patch(this.#root, diff2, (msg) => {
- this.#socket?.send(JSON.stringify([event, msg.tag, msg.data]));
- });
- }
- emit([event2, data]) {
- this.dispatchEvent(new CustomEvent(event2, { detail: data }));
- }
- disconnectedCallback() {
- this.#socket?.close();
- }
-};
-window.customElements.define("lustre-server-component", LustreServerComponent);
-export {
- LustreServerComponent
-};