diff options
-rw-r--r-- | src/lustre.ffi.mjs | 6 | ||||
-rw-r--r-- | src/runtime.ffi.mjs | 105 |
2 files changed, 82 insertions, 29 deletions
diff --git a/src/lustre.ffi.mjs b/src/lustre.ffi.mjs index 39ba9ec..38b3a95 100644 --- a/src/lustre.ffi.mjs +++ b/src/lustre.ffi.mjs @@ -10,7 +10,6 @@ import { Ok, Error, isEqual } from "./gleam.mjs"; /// export class App { #root = null; - #el = null; #state = null; #queue = []; #effects = []; @@ -68,8 +67,7 @@ export class App { } destroy() { - this.#root = null; - this.#el.remove(); + this.#root.remove(); this.#state = null; this.#queue = []; this.#effects = []; @@ -83,7 +81,7 @@ export class App { const node = this.#view(this.#state); const vdom = map(node, (msg) => this.dispatch(msg)); - this.#el = morph(this.#root, vdom); + morph(this.#root, vdom); } #tick() { diff --git a/src/runtime.ffi.mjs b/src/runtime.ffi.mjs index 1bdc1f8..1a1af4b 100644 --- a/src/runtime.ffi.mjs +++ b/src/runtime.ffi.mjs @@ -1,23 +1,23 @@ import { element, namespaced, text } from "./lustre/element.mjs"; -import { List } from "./gleam.mjs"; +import { List, Empty } from "./gleam.mjs"; import { Some, None } from "../gleam_stdlib/gleam/option.mjs"; const Element = element("").constructor; const ElementNs = namespaced("", "").constructor; const Text = text("").constructor; -export function morph(prev, curr) { +export function morph(prev, curr, parent) { if (curr instanceof ElementNs) return prev?.nodeType === 1 && prev.nodeName === curr[0].toUpperCase() && prev.namespaceURI === curr[3] - ? morphElement(prev, curr, curr[3]) - : createElement(prev, curr, curr[3]); + ? morphElement(prev, curr, curr[3], parent) + : createElement(prev, curr, curr[3], parent); if (curr instanceof Element) { return prev?.nodeType === 1 && prev.nodeName === curr[0].toUpperCase() - ? morphElement(prev, curr) - : createElement(prev, curr); + ? morphElement(prev, curr, null, parent) + : createElement(prev, curr, null, parent); } if (curr instanceof Text) { @@ -38,7 +38,7 @@ export function morph(prev, curr) { // ELEMENTS -------------------------------------------------------------------- -function createElement(prev, curr, ns) { +function createElement(prev, curr, ns, parent = null) { const el = ns ? document.createElementNS(ns, curr[0]) : document.createElement(curr[0]); @@ -49,17 +49,38 @@ function createElement(prev, curr, ns) { attr = attr.tail; } - let child = curr[2]; - while (child.head) { - el.appendChild(morph(null, child.head)); - child = child.tail; - } + if (customElements.get(curr[0])) { + el._slot = curr[2]; + } else if (curr[0] === "slot") { + let child = new Empty(); + let parentWithSlot = parent; + + while (parentWithSlot) { + if (parentWithSlot._slot) { + child = parentWithSlot._slot; + break; + } else { + parentWithSlot = parentWithSlot.parentNode; + } + } - if (prev) prev.replaceWith(el); + while (child.head) { + el.appendChild(morph(null, child.head, el)); + child = child.tail; + } + } else { + let child = curr[2]; + while (child.head) { + el.appendChild(morph(null, child.head, el)); + child = child.tail; + } + + if (prev) prev.replaceWith(el); + } return el; } -function morphElement(prev, curr, ns) { +function morphElement(prev, curr, ns, parent) { const prevAttrs = prev.attributes; const currAttrs = new Map(); @@ -83,21 +104,55 @@ function morphElement(prev, curr, ns) { morphAttr(prev, name, value); } - let prevChild = prev.firstChild; - let currChild = curr[2]; + if (customElements.get(curr[0])) { + prev._slot = curr[2]; + } else if (curr[0] === "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 (currChild.head) { + morph(prevChild, currChild.head, prev); + currChild = currChild.tail; + } - while (prevChild) { - if (currChild.head) { - morph(prevChild, currChild.head); - currChild = currChild.tail; + prevChild = prevChild.nextSibling; } - prevChild = prevChild.nextSibling; - } + while (currChild.head) { + prev.appendChild(morph(null, currChild.head, prev)); + currChild = currChild.tail; + } + } else { + let prevChild = prev.firstChild; + let currChild = curr[2]; + + while (prevChild) { + if (currChild.head) { + morph(prevChild, currChild.head, prev); + currChild = currChild.tail; + prevChild = prevChild.nextSibling; + } else { + const next = prevChild.nextSibling; + prevChild.remove(); + prevChild = next; + } + } - while (currChild.head) { - prev.appendChild(morph(null, currChild.head)); - currChild = currChild.tail; + while (currChild.head) { + prev.appendChild(morph(null, currChild.head, prev)); + currChild = currChild.tail; + } } return prev; |