aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2024-06-19 08:56:54 +0100
committerHayleigh Thompson <me@hayleigh.dev>2024-06-19 08:56:54 +0100
commit41b48e53bb100b1496cbdd53c82f6c7f556a81f4 (patch)
treeba35b23e9634e544d323c1ca1ec280a712c11973
parenta924297b13039e752c6bbd12d9a8ee429a2d4e63 (diff)
downloadlustre-41b48e53bb100b1496cbdd53c82f6c7f556a81f4.tar.gz
lustre-41b48e53bb100b1496cbdd53c82f6c7f556a81f4.zip
:recycle: Adopt component styles by copying page <link> and <style> tags.
-rw-r--r--src/server-component.mjs34
-rw-r--r--src/vdom.ffi.mjs16
2 files changed, 39 insertions, 11 deletions
diff --git a/src/server-component.mjs b/src/server-component.mjs
index d4cb4a9..855ff9d 100644
--- a/src/server-component.mjs
+++ b/src/server-component.mjs
@@ -19,6 +19,7 @@ export class LustreServerComponent extends HTMLElement {
#root = null;
#socket = null;
#shadow = null;
+ #stylesOffset = 0;
constructor() {
super();
@@ -52,11 +53,13 @@ export class LustreServerComponent extends HTMLElement {
for (const link of document.querySelectorAll("link")) {
if (link.rel === "stylesheet") {
this.#shadow.appendChild(link.cloneNode(true));
+ this.#stylesOffset++;
}
}
for (const style of document.querySelectorAll("style")) {
this.#shadow.appendChild(style.cloneNode(true));
+ this.#stylesOffset++;
}
this.#root = document.createElement("div");
@@ -152,16 +155,27 @@ export class LustreServerComponent extends HTMLElement {
morph(vdom) {
this.#root = morph(this.#root, vdom, (handler) => (event) => {
+ const data = JSON.parse(this.getAttribute("data-lustre-data") || "{}");
const msg = handler(event);
+
+ msg.data = merge(data, msg.data);
+
this.#socket?.send(JSON.stringify([Constants.event, msg.tag, msg.data]));
});
}
diff([diff]) {
- this.#root = patch(this.#root, diff, (handler) => (event) => {
- const msg = handler(event);
- this.#socket?.send(JSON.stringify([Constants.event, msg.tag, msg.data]));
- });
+ this.#root = patch(
+ this.#root,
+ diff,
+ (handler) => (event) => {
+ const msg = handler(event);
+ this.#socket?.send(
+ JSON.stringify([Constants.event, msg.tag, msg.data]),
+ );
+ },
+ this.#stylesOffset,
+ );
}
emit([event, data]) {
@@ -182,3 +196,15 @@ export class LustreServerComponent extends HTMLElement {
}
window.customElements.define("lustre-server-component", LustreServerComponent);
+
+// UTILS -----------------------------------------------------------------------
+
+function merge(target, source) {
+ for (const key in source) {
+ if (source[key] instanceof Object)
+ Object.assign(source[key], merge(target[key], source[key]));
+ }
+
+ Object.assign(target || {}, source);
+ return target;
+}
diff --git a/src/vdom.ffi.mjs b/src/vdom.ffi.mjs
index c3d12e2..0c645c1 100644
--- a/src/vdom.ffi.mjs
+++ b/src/vdom.ffi.mjs
@@ -84,7 +84,7 @@ export function morph(prev, next, dispatch, isComponent = false) {
return out;
}
-export function patch(root, diff, dispatch) {
+export function patch(root, diff, dispatch, stylesOffset = 0) {
const rootParent = root.parentNode;
// A diff is a tuple of three arrays: created, removed, updated. Each of these
@@ -101,7 +101,7 @@ export function patch(root, diff, dispatch) {
for (const created of diff[0]) {
const key = created[0].split("-");
const next = created[1];
- const prev = getDeepChild(rootParent, key);
+ const prev = getDeepChild(rootParent, key, stylesOffset);
let result;
@@ -113,7 +113,7 @@ export function patch(root, diff, dispatch) {
// tree. This can happen because we might get a patch that tells us some node
// was created at a path that doesn't exist yet.
else {
- const parent = getDeepChild(rootParent, key.slice(0, -1));
+ const parent = getDeepChild(rootParent, key.slice(0, -1), stylesOffset);
const temp = document.createTextNode("");
parent.appendChild(temp);
result = morph(temp, next, dispatch);
@@ -130,7 +130,7 @@ export function patch(root, diff, dispatch) {
// the removed element.
for (const removed of diff[1]) {
const key = removed[0].split("-");
- const deletedNode = getDeepChild(rootParent, key);
+ const deletedNode = getDeepChild(rootParent, key, stylesOffset);
deletedNode.remove();
}
@@ -139,7 +139,7 @@ export function patch(root, diff, dispatch) {
for (const updated of diff[2]) {
const key = updated[0].split("-");
const patches = updated[1];
- const prev = getDeepChild(rootParent, key);
+ const prev = getDeepChild(rootParent, key, stylesOffset);
const handlersForEl = registeredHandlers.get(prev);
for (const created of patches[0]) {
@@ -455,13 +455,15 @@ function getKeyedChildren(el) {
return keyedChildren;
}
-function getDeepChild(el, path) {
+function getDeepChild(el, path, stylesOffset) {
let n;
let rest;
let child = el;
+ let isFirstInPath = true;
while ((([n, ...rest] = path), n !== undefined)) {
- child = child.childNodes.item(n);
+ child = child.childNodes.item(isFirstInPath ? n + stylesOffset : n);
+ isFirstInPath = false;
path = rest;
}