diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2023-09-09 18:43:18 +0100 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2023-09-09 18:43:18 +0100 |
commit | 36b4cbf432bdccbc0d3c16692d913e4d1e263dfa (patch) | |
tree | 8a81901edbd1d413832cfc4699490a8ff7518584 /lib/src/runtime.ffi.mjs | |
parent | 6d295d0bcf23bb4410d6d93435ce53f9670a1d1c (diff) | |
download | lustre-36b4cbf432bdccbc0d3c16692d913e4d1e263dfa.tar.gz lustre-36b4cbf432bdccbc0d3c16692d913e4d1e263dfa.zip |
:zap: Improve render performance.
Diffstat (limited to 'lib/src/runtime.ffi.mjs')
-rw-r--r-- | lib/src/runtime.ffi.mjs | 88 |
1 files changed, 39 insertions, 49 deletions
diff --git a/lib/src/runtime.ffi.mjs b/lib/src/runtime.ffi.mjs index 59c5883..8986d7f 100644 --- a/lib/src/runtime.ffi.mjs +++ b/lib/src/runtime.ffi.mjs @@ -1,21 +1,22 @@ -import { List, Empty } from "./gleam.mjs"; -import { Some, None } from "../gleam_stdlib/gleam/option.mjs"; +import { Empty } from "./gleam.mjs"; +import { map as result_map } from "../gleam_stdlib/gleam/result.mjs"; -export function morph(prev, curr, parent) { - if (curr[3]) +export function morph(prev, curr, dispatch, parent) { + if (curr[3]) { return prev?.nodeType === 1 && prev.nodeName === curr[0].toUpperCase() && prev.namespaceURI === curr[3] - ? morphElement(prev, curr, curr[3], parent) - : createElement(prev, curr, curr[3], parent); + ? morphElement(prev, curr, curr[3], dispatch, parent) + : createElement(prev, curr, curr[3], dispatch, parent); + } if (curr[2]) { return prev?.nodeType === 1 && prev.nodeName === curr[0].toUpperCase() - ? morphElement(prev, curr, null, parent) - : createElement(prev, curr, null, parent); + ? morphElement(prev, curr, null, dispatch, parent) + : createElement(prev, curr, null, dispatch, parent); } - if (curr[0]) { + if (curr[0] && typeof curr[0] === "string") { return prev?.nodeType === 3 ? morphText(prev, curr) : createText(prev, curr); @@ -33,11 +34,13 @@ export function morph(prev, curr, parent) { // ELEMENTS -------------------------------------------------------------------- -function createElement(prev, curr, ns, parent = null) { +function createElement(prev, curr, ns, dispatch, parent = null) { const el = ns ? document.createElementNS(ns, curr[0]) : document.createElement(curr[0]); + el.$lustre = {}; + let attr = curr[1]; while (attr.head) { morphAttr( @@ -45,7 +48,8 @@ function createElement(prev, curr, ns, parent = null) { attr.head[0], attr.head[0] === "class" && el.className ? `${el.className} ${attr.head[1]}` - : attr.head[1] + : attr.head[1], + dispatch ); attr = attr.tail; @@ -67,13 +71,13 @@ function createElement(prev, curr, ns, parent = null) { } while (child.head) { - el.appendChild(morph(null, child.head, el)); + el.appendChild(morph(null, child.head, dispatch, el)); child = child.tail; } } else { let child = curr[2]; while (child.head) { - el.appendChild(morph(null, child.head, el)); + el.appendChild(morph(null, child.head, dispatch, el)); child = child.tail; } @@ -83,7 +87,7 @@ function createElement(prev, curr, ns, parent = null) { return el; } -function morphElement(prev, curr, ns, parent) { +function morphElement(prev, curr, ns, dispatch, parent) { const prevAttrs = prev.attributes; const currAttrs = new Map(); @@ -106,14 +110,14 @@ function morphElement(prev, curr, ns, parent) { const value = currAttrs.get(name); if (value !== prevValue) { - morphAttr(prev, name, value); + morphAttr(prev, name, value, dispatch); currAttrs.delete(name); } } } for (const [name, value] of currAttrs) { - morphAttr(prev, name, value); + morphAttr(prev, name, value, dispatch); } if (customElements.get(curr[0])) { @@ -134,7 +138,7 @@ function morphElement(prev, curr, ns, parent) { while (prevChild) { if (currChild.head) { - morph(prevChild, currChild.head, prev); + morph(prevChild, currChild.head, dispatch, prev); currChild = currChild.tail; } @@ -142,7 +146,7 @@ function morphElement(prev, curr, ns, parent) { } while (currChild.head) { - prev.appendChild(morph(null, currChild.head, prev)); + prev.appendChild(morph(null, currChild.head, dispatch, prev)); currChild = currChild.tail; } } else { @@ -152,7 +156,7 @@ function morphElement(prev, curr, ns, parent) { while (prevChild) { if (currChild.head) { const next = prevChild.nextSibling; - morph(prevChild, currChild.head, prev); + morph(prevChild, currChild.head, dispatch, prev); currChild = currChild.tail; prevChild = next; } else { @@ -163,7 +167,7 @@ function morphElement(prev, curr, ns, parent) { } while (currChild.head) { - prev.appendChild(morph(null, currChild.head, prev)); + prev.appendChild(morph(null, currChild.head, dispatch, prev)); currChild = currChild.tail; } } @@ -173,51 +177,37 @@ function morphElement(prev, curr, ns, parent) { // ATTRIBUTES ------------------------------------------------------------------ -function morphAttr(el, name, value) { +function morphAttr(el, name, value, dispatch) { switch (typeof value) { case "string": if (el.getAttribute(name) !== value) el.setAttribute(name, value); break; - // Boolean attributes work a bit differently in HTML. Their presence always - // implies true: to set an attribute to false you need to remove it entirely. - case "boolean": - value ? el.setAttribute(name, name) : el.removeAttribute(name); - break; - // Event listeners need to be handled slightly differently because we need // to be able to support custom events. We case name.startsWith("on") && "function": { + if (el.$lustre[name] === value) break; + const event = name.slice(2).toLowerCase(); + const handler = (e) => result_map(value(e), dispatch); - if (el[`_${name}`] === value) break; + console.log(el.dataset); - el.removeEventListener(event, el[`_${name}`]); - el.addEventListener(event, value); - el[`_${name}`] = value; - break; - } + if (el.$lustre[`${name}Handler`]) { + el.removeEventListener(event, el.$lustre[`${name}Handler`]); + } - default: { - el[name] = toJsValue(value); - } - } -} + el.addEventListener(event, handler); -function toJsValue(value) { - if (value instanceof List) { - return value.toArray().map(toJsValue); - } + el.$lustre[name] = value; + el.$lustre[`${name}Handler`] = handler; - if (value instanceof Some) { - return toJsValue(value[0]); - } + break; + } - if (value instanceof None) { - return null; + default: + el[name] = value; } - - return value; } // TEXT ------------------------------------------------------------------------ |