aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2024-06-19 08:57:06 +0100
committerHayleigh Thompson <me@hayleigh.dev>2024-06-19 08:57:06 +0100
commit918180e34b4e42acac79abb9e54bb935d8a33c86 (patch)
treebccfdb5dc58d2776b574eece75d20f84aae2d453
parent41b48e53bb100b1496cbdd53c82f6c7f556a81f4 (diff)
downloadlustre-918180e34b4e42acac79abb9e54bb935d8a33c86.tar.gz
lustre-918180e34b4e42acac79abb9e54bb935d8a33c86.zip
:rocket: Build server component runtime.
-rw-r--r--priv/static/lustre-server-component.min.mjs2
-rw-r--r--priv/static/lustre-server-component.mjs60
-rw-r--r--src/lustre/server_component.gleam2
3 files changed, 43 insertions, 21 deletions
diff --git a/priv/static/lustre-server-component.min.mjs b/priv/static/lustre-server-component.min.mjs
index c0d3a1a..1dd84df 100644
--- a/priv/static/lustre-server-component.min.mjs
+++ b/priv/static/lustre-server-component.min.mjs
@@ -1 +1 @@
-function N(t,e,i,r=!1){let s,a=[{prev:t,next:e,parent:t.parentNode}];for(;a.length;){let{prev:n,next:o,parent:l}=a.pop();if(o.subtree!==void 0&&(o=o.subtree()),o.content!==void 0)if(n)if(n.nodeType===Node.TEXT_NODE)n.textContent!==o.content&&(n.textContent=o.content),s??=n;else{let c=document.createTextNode(o.content);l.replaceChild(c,n),s??=c}else{let c=document.createTextNode(o.content);l.appendChild(c),s??=c}else if(o.tag!==void 0){let c=D({prev:n,next:o,dispatch:i,stack:a,isComponent:r});n?n!==c&&l.replaceChild(c,n):l.appendChild(c),s??=c}else o.elements!==void 0?k(o,c=>{a.unshift({prev:n,next:c,parent:l}),n=n?.nextSibling}):o.subtree!==void 0&&a.push({prev:n,next:o,parent:l})}return s}function J(t,e,i){let r=t.parentNode;for(let s of e[0]){let a=s[0].split("-"),n=s[1],o=w(r,a),l;if(o!==null&&o!==r)l=N(o,n,i);else{let c=w(r,a.slice(0,-1)),u=document.createTextNode("");c.appendChild(u),l=N(u,n,i)}a==="0"&&(t=l)}for(let s of e[1]){let a=s[0].split("-");w(r,a).remove()}for(let s of e[2]){let a=s[0].split("-"),n=s[1],o=w(r,a),l=S.get(o);for(let c of n[0]){let u=c[0],m=c[1];if(u.startsWith("data-lustre-on-")){let y=u.slice(15),p=i(M);l.has(y)||el.addEventListener(y,b),l.set(y,p),el.setAttribute(u,m)}else o.setAttribute(u,m),o[u]=m}for(let c of n[1])if(c[0].startsWith("data-lustre-on-")){let u=c[0].slice(15);o.removeEventListener(u,b),l.delete(u)}else o.removeAttribute(c[0])}return t}function D({prev:t,next:e,dispatch:i,stack:r}){let s=e.namespace||"http://www.w3.org/1999/xhtml",a=t&&t.nodeType===Node.ELEMENT_NODE&&t.localName===e.tag&&t.namespaceURI===(e.namespace||"http://www.w3.org/1999/xhtml"),n=a?t:s?document.createElementNS(s,e.tag):document.createElement(e.tag),o;if(S.has(n))o=S.get(n);else{let f=new Map;S.set(n,f),o=f}let l=a?new Set(o.keys()):null,c=a?new Set(Array.from(t.attributes,f=>f.name)):null,u=null,m=null,y=null;for(let f of e.attrs){let d=f[0],h=f[1];if(f.as_property)n[d]!==h&&(n[d]=h),a&&c.delete(d);else if(d.startsWith("on")){let g=d.slice(2),E=i(h);o.has(g)||n.addEventListener(g,b),o.set(g,E),a&&l.delete(g)}else if(d.startsWith("data-lustre-on-")){let g=d.slice(15),E=i(M);o.has(g)||n.addEventListener(g,b),o.set(g,E),n.setAttribute(d,h)}else d==="class"?u=u===null?h:u+" "+h:d==="style"?m=m===null?h:m+h:d==="dangerous-unescaped-html"?y=h:(n.getAttribute(d)!==h&&n.setAttribute(d,h),(d==="value"||d==="selected")&&(n[d]=h),a&&c.delete(d))}if(u!==null&&(n.setAttribute("class",u),a&&c.delete("class")),m!==null&&(n.setAttribute("style",m),a&&c.delete("style")),a){for(let f of c)n.removeAttribute(f);for(let f of l)o.delete(f),n.removeEventListener(f,b)}if(e.key!==void 0&&e.key!=="")n.setAttribute("data-lustre-key",e.key);else if(y!==null)return n.innerHTML=y,n;let p=n.firstChild,x=null,C=null,O=null,A=e.children[Symbol.iterator]().next().value;a&&A!==void 0&&A.key!==void 0&&A.key!==""&&(x=new Set,C=L(t),O=L(e));for(let f of e.children)k(f,d=>{d.key!==void 0&&x!==null?p=W(p,d,n,r,O,C,x):(r.unshift({prev:p,next:d,parent:n}),p=p?.nextSibling)});for(;p;){let f=p.nextSibling;n.removeChild(p),p=f}return n}var S=new WeakMap;function b(t){let e=t.currentTarget;if(!S.has(e)){e.removeEventListener(t.type,b);return}let i=S.get(e);if(!i.has(t.type)){e.removeEventListener(t.type,b);return}i.get(t.type)(t)}function M(t){let e=t.currentTarget,i=e.getAttribute(`data-lustre-on-${t.type}`),r=JSON.parse(e.getAttribute("data-lustre-data")||"{}"),s=JSON.parse(e.getAttribute("data-lustre-include")||"[]");switch(t.type){case"input":case"change":s.push("target.value");break}return{tag:i,data:s.reduce((a,n)=>{let o=n.split(".");for(let l=0,c=a,u=t;l<o.length;l++)l===o.length-1?c[o[l]]=u[o[l]]:(c[o[l]]??={},u=u[o[l]],c=c[o[l]]);return a},{data:r})}}function L(t){let e=new Map;if(t)for(let i of t.children)k(i,r=>{let s=r?.key||r?.getAttribute?.("data-lustre-key");s&&e.set(s,r)});return e}function w(t,e){let i,r,s=t;for(;[i,...r]=e,i!==void 0;)s=s.childNodes.item(i),e=r;return s}function W(t,e,i,r,s,a,n){for(;t&&!s.has(t.getAttribute("data-lustre-key"));){let l=t.nextSibling;i.removeChild(t),t=l}if(a.size===0)return k(e,l=>{r.unshift({prev:t,next:l,parent:i}),t=t?.nextSibling}),t;if(n.has(e.key))return console.warn(`Duplicate key found in Lustre vnode: ${e.key}`),r.unshift({prev:null,next:e,parent:i}),t;n.add(e.key);let o=a.get(e.key);if(!o&&!t)return r.unshift({prev:null,next:e,parent:i}),t;if(!o&&t!==null){let l=document.createTextNode("");return i.insertBefore(l,t),r.unshift({prev:l,next:e,parent:i}),t}return!o||o===t?(r.unshift({prev:t,next:e,parent:i}),t=t?.nextSibling,t):(i.insertBefore(o,t),r.unshift({prev:o,next:e,parent:i}),t)}function k(t,e){if(t.elements!==void 0)for(let i of t.elements)e(i);else e(t)}var T=class extends HTMLElement{static get observedAttributes(){return["route"]}#s=null;#t=null;#e=null;#n=null;constructor(){super(),this.#n=this.attachShadow({mode:"closed"}),this.#s=new MutationObserver(e=>{let i=[];for(let r of e)if(r.type==="attributes"){let{attributeName:s,oldValue:a}=r,n=this.getAttribute(s);if(a!==n)try{i.push([s,JSON.parse(n)])}catch{i.push([s,n])}}i.length&&this.#e?.send(JSON.stringify([5,i]))})}connectedCallback(){this.#t=document.createElement("div"),this.#n.appendChild(this.#t);let e=new CSSStyleSheet;for(let{cssRules:i}of document.styleSheets)for(let r of i)console.log(r),e.insertRule(r.cssText);this.#n.adoptedStyleSheets=[e]}attributeChangedCallback(e,i,r){switch(e){case"route":if(!r)this.#e?.close(),this.#e=null;else if(i!==r){let s=this.getAttribute("id"),a=r+(s?`?id=${s}`:""),n=window.location.protocol==="https:"?"wss":"ws";this.#e?.close(),this.#e=new WebSocket(`${n}://${window.location.host}${a}`),this.#e.addEventListener("message",o=>this.messageReceivedCallback(o))}}}messageReceivedCallback({data:e}){let[i,...r]=JSON.parse(e);switch(i){case 0:return this.diff(r);case 1:return this.emit(r);case 2:return this.init(r)}}init([e,i]){let r=[];for(let s of e)s in this?r.push([s,this[s]]):this.hasAttribute(s)&&r.push([s,this.getAttribute(s)]),Object.defineProperty(this,s,{get(){return this[`_${s}`]??this.getAttribute(s)},set(a){let n=this[s];typeof a=="string"?this.setAttribute(s,a):this[`_${s}`]=a,n!==a&&this.#e?.send(JSON.stringify([5,[[s,a]]]))}});this.#s.observe(this,{attributeFilter:e,attributeOldValue:!0,attributes:!0,characterData:!1,characterDataOldValue:!1,childList:!1,subtree:!1}),this.morph(i),r.length&&this.#e?.send(JSON.stringify([5,r]))}morph(e){this.#t=N(this.#t,e,i=>r=>{let s=i(r);this.#e?.send(JSON.stringify([4,s.tag,s.data]))})}diff([e]){this.#t=J(this.#t,e,i=>r=>{let s=i(r);this.#e?.send(JSON.stringify([4,s.tag,s.data]))})}emit([e,i]){this.dispatchEvent(new CustomEvent(e,{detail:i}))}disconnectedCallback(){this.#e?.close()}get adoptedStyleSheets(){return this.#n.adoptedStyleSheets}set adoptedStyleSheets(e){this.#n.adoptedStyleSheets=e}};window.customElements.define("lustre-server-component",T);export{T as LustreServerComponent};
+function S(e,t,s,r=!1){let i,o=[{prev:e,next:t,parent:e.parentNode}];for(;o.length;){let{prev:n,next:a,parent:l}=o.pop();if(a.subtree!==void 0&&(a=a.subtree()),a.content!==void 0)if(n)if(n.nodeType===Node.TEXT_NODE)n.textContent!==a.content&&(n.textContent=a.content),i??=n;else{let c=document.createTextNode(a.content);l.replaceChild(c,n),i??=c}else{let c=document.createTextNode(a.content);l.appendChild(c),i??=c}else if(a.tag!==void 0){let c=W({prev:n,next:a,dispatch:s,stack:o,isComponent:r});n?n!==c&&l.replaceChild(c,n):l.appendChild(c),i??=c}else a.elements!==void 0?A(a,c=>{o.unshift({prev:n,next:c,parent:l}),n=n?.nextSibling}):a.subtree!==void 0&&o.push({prev:n,next:a,parent:l})}return i}function J(e,t,s,r=0){let i=e.parentNode;for(let o of t[0]){let n=o[0].split("-"),a=o[1],l=k(i,n,r),c;if(l!==null&&l!==i)c=S(l,a,s);else{let u=k(i,n.slice(0,-1),r),f=document.createTextNode("");u.appendChild(f),c=S(f,a,s)}n==="0"&&(e=c)}for(let o of t[1]){let n=o[0].split("-");k(i,n,r).remove()}for(let o of t[2]){let n=o[0].split("-"),a=o[1],l=k(i,n,r),c=N.get(l);for(let u of a[0]){let f=u[0],b=u[1];if(f.startsWith("data-lustre-on-")){let p=f.slice(15),w=s(M);c.has(p)||el.addEventListener(p,y),c.set(p,w),el.setAttribute(f,b)}else l.setAttribute(f,b),l[f]=b}for(let u of a[1])if(u[0].startsWith("data-lustre-on-")){let f=u[0].slice(15);l.removeEventListener(f,y),c.delete(f)}else l.removeAttribute(u[0])}return e}function W({prev:e,next:t,dispatch:s,stack:r}){let i=t.namespace||"http://www.w3.org/1999/xhtml",o=e&&e.nodeType===Node.ELEMENT_NODE&&e.localName===t.tag&&e.namespaceURI===(t.namespace||"http://www.w3.org/1999/xhtml"),n=o?e:i?document.createElementNS(i,t.tag):document.createElement(t.tag),a;if(N.has(n))a=N.get(n);else{let h=new Map;N.set(n,h),a=h}let l=o?new Set(a.keys()):null,c=o?new Set(Array.from(e.attributes,h=>h.name)):null,u=null,f=null,b=null;for(let h of t.attrs){let d=h[0],m=h[1];if(h.as_property)n[d]!==m&&(n[d]=m),o&&c.delete(d);else if(d.startsWith("on")){let g=d.slice(2),E=s(m);a.has(g)||n.addEventListener(g,y),a.set(g,E),o&&l.delete(g)}else if(d.startsWith("data-lustre-on-")){let g=d.slice(15),E=s(M);a.has(g)||n.addEventListener(g,y),a.set(g,E),n.setAttribute(d,m)}else d==="class"?u=u===null?m:u+" "+m:d==="style"?f=f===null?m:f+m:d==="dangerous-unescaped-html"?b=m:(n.getAttribute(d)!==m&&n.setAttribute(d,m),(d==="value"||d==="selected")&&(n[d]=m),o&&c.delete(d))}if(u!==null&&(n.setAttribute("class",u),o&&c.delete("class")),f!==null&&(n.setAttribute("style",f),o&&c.delete("style")),o){for(let h of c)n.removeAttribute(h);for(let h of l)a.delete(h),n.removeEventListener(h,y)}if(t.key!==void 0&&t.key!=="")n.setAttribute("data-lustre-key",t.key);else if(b!==null)return n.innerHTML=b,n;let p=n.firstChild,w=null,C=null,T=null,x=t.children[Symbol.iterator]().next().value;o&&x!==void 0&&x.key!==void 0&&x.key!==""&&(w=new Set,C=L(e),T=L(t));for(let h of t.children)A(h,d=>{d.key!==void 0&&w!==null?p=F(p,d,n,r,T,C,w):(r.unshift({prev:p,next:d,parent:n}),p=p?.nextSibling)});for(;p;){let h=p.nextSibling;n.removeChild(p),p=h}return n}var N=new WeakMap;function y(e){let t=e.currentTarget;if(!N.has(t)){t.removeEventListener(e.type,y);return}let s=N.get(t);if(!s.has(e.type)){t.removeEventListener(e.type,y);return}s.get(e.type)(e)}function M(e){let t=e.currentTarget,s=t.getAttribute(`data-lustre-on-${e.type}`),r=JSON.parse(t.getAttribute("data-lustre-data")||"{}"),i=JSON.parse(t.getAttribute("data-lustre-include")||"[]");switch(e.type){case"input":case"change":i.push("target.value");break}return{tag:s,data:i.reduce((o,n)=>{let a=n.split(".");for(let l=0,c=o,u=e;l<a.length;l++)l===a.length-1?c[a[l]]=u[a[l]]:(c[a[l]]??={},u=u[a[l]],c=c[a[l]]);return o},{data:r})}}function L(e){let t=new Map;if(e)for(let s of e.children)A(s,r=>{let i=r?.key||r?.getAttribute?.("data-lustre-key");i&&t.set(i,r)});return t}function k(e,t,s){let r,i,o=e,n=!0;for(;[r,...i]=t,r!==void 0;)o=o.childNodes.item(n?r+s:r),n=!1,t=i;return o}function F(e,t,s,r,i,o,n){for(;e&&!i.has(e.getAttribute("data-lustre-key"));){let l=e.nextSibling;s.removeChild(e),e=l}if(o.size===0)return A(t,l=>{r.unshift({prev:e,next:l,parent:s}),e=e?.nextSibling}),e;if(n.has(t.key))return console.warn(`Duplicate key found in Lustre vnode: ${t.key}`),r.unshift({prev:null,next:t,parent:s}),e;n.add(t.key);let a=o.get(t.key);if(!a&&!e)return r.unshift({prev:null,next:t,parent:s}),e;if(!a&&e!==null){let l=document.createTextNode("");return s.insertBefore(l,e),r.unshift({prev:l,next:t,parent:s}),e}return!a||a===e?(r.unshift({prev:e,next:t,parent:s}),e=e?.nextSibling,e):(s.insertBefore(a,e),r.unshift({prev:a,next:t,parent:s}),e)}function A(e,t){if(e.elements!==void 0)for(let s of e.elements)t(s);else t(e)}var O=class extends HTMLElement{static get observedAttributes(){return["route"]}#i=null;#e=null;#t=null;#n=null;#s=0;constructor(){super(),this.#n=this.attachShadow({mode:"closed"}),this.#i=new MutationObserver(t=>{let s=[];for(let r of t)if(r.type==="attributes"){let{attributeName:i,oldValue:o}=r,n=this.getAttribute(i);if(o!==n)try{s.push([i,JSON.parse(n)])}catch{s.push([i,n])}}s.length&&this.#t?.send(JSON.stringify([5,s]))})}connectedCallback(){for(let t of document.querySelectorAll("link"))t.rel==="stylesheet"&&(this.#n.appendChild(t.cloneNode(!0)),this.#s++);for(let t of document.querySelectorAll("style"))this.#n.appendChild(t.cloneNode(!0)),this.#s++;this.#e=document.createElement("div"),this.#n.appendChild(this.#e)}attributeChangedCallback(t,s,r){switch(t){case"route":if(!r)this.#t?.close(),this.#t=null;else if(s!==r){let i=this.getAttribute("id"),o=r+(i?`?id=${i}`:""),n=window.location.protocol==="https:"?"wss":"ws";this.#t?.close(),this.#t=new WebSocket(`${n}://${window.location.host}${o}`),this.#t.addEventListener("message",a=>this.messageReceivedCallback(a))}}}messageReceivedCallback({data:t}){let[s,...r]=JSON.parse(t);switch(s){case 0:return this.diff(r);case 1:return this.emit(r);case 2:return this.init(r)}}init([t,s]){let r=[];for(let i of t)i in this?r.push([i,this[i]]):this.hasAttribute(i)&&r.push([i,this.getAttribute(i)]),Object.defineProperty(this,i,{get(){return this[`_${i}`]??this.getAttribute(i)},set(o){let n=this[i];typeof o=="string"?this.setAttribute(i,o):this[`_${i}`]=o,n!==o&&this.#t?.send(JSON.stringify([5,[[i,o]]]))}});this.#i.observe(this,{attributeFilter:t,attributeOldValue:!0,attributes:!0,characterData:!1,characterDataOldValue:!1,childList:!1,subtree:!1}),this.morph(s),r.length&&this.#t?.send(JSON.stringify([5,r]))}morph(t){this.#e=S(this.#e,t,s=>r=>{let i=JSON.parse(this.getAttribute("data-lustre-data")||"{}"),o=s(r);o.data=$(i,o.data),this.#t?.send(JSON.stringify([4,o.tag,o.data]))})}diff([t]){this.#e=J(this.#e,t,s=>r=>{let i=s(r);this.#t?.send(JSON.stringify([4,i.tag,i.data]))},this.#s)}emit([t,s]){this.dispatchEvent(new CustomEvent(t,{detail:s}))}disconnectedCallback(){this.#t?.close()}get adoptedStyleSheets(){return this.#n.adoptedStyleSheets}set adoptedStyleSheets(t){this.#n.adoptedStyleSheets=t}};window.customElements.define("lustre-server-component",O);function $(e,t){for(let s in t)t[s]instanceof Object&&Object.assign(t[s],$(e[s],t[s]));return Object.assign(e||{},t),e}export{O as LustreServerComponent};
diff --git a/priv/static/lustre-server-component.mjs b/priv/static/lustre-server-component.mjs
index 0892fb5..8732f1d 100644
--- a/priv/static/lustre-server-component.mjs
+++ b/priv/static/lustre-server-component.mjs
@@ -52,17 +52,17 @@ function morph(prev, next, dispatch, isComponent = false) {
}
return out;
}
-function patch(root, diff2, dispatch) {
+function patch(root, diff2, dispatch, stylesOffset = 0) {
const rootParent = root.parentNode;
for (const created of diff2[0]) {
const key = created[0].split("-");
const next = created[1];
- const prev = getDeepChild(rootParent, key);
+ const prev = getDeepChild(rootParent, key, stylesOffset);
let result;
if (prev !== null && prev !== rootParent) {
result = morph(prev, next, dispatch);
} 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);
@@ -73,13 +73,13 @@ function patch(root, diff2, dispatch) {
}
for (const removed of diff2[1]) {
const key = removed[0].split("-");
- const deletedNode = getDeepChild(rootParent, key);
+ const deletedNode = getDeepChild(rootParent, key, stylesOffset);
deletedNode.remove();
}
for (const updated of diff2[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]) {
const name = created[0];
@@ -286,12 +286,14 @@ function getKeyedChildren(el2) {
}
return keyedChildren;
}
-function getDeepChild(el2, path) {
+function getDeepChild(el2, path, stylesOffset) {
let n;
let rest;
let child = el2;
+ let isFirstInPath = true;
while ([n, ...rest] = path, n !== void 0) {
- child = child.childNodes.item(n);
+ child = child.childNodes.item(isFirstInPath ? n + stylesOffset : n);
+ isFirstInPath = false;
path = rest;
}
return child;
@@ -354,6 +356,7 @@ var LustreServerComponent = class extends HTMLElement {
#root = null;
#socket = null;
#shadow = null;
+ #stylesOffset = 0;
constructor() {
super();
this.#shadow = this.attachShadow({ mode: "closed" });
@@ -378,16 +381,18 @@ var LustreServerComponent = class extends HTMLElement {
});
}
connectedCallback() {
- this.#root = document.createElement("div");
- this.#shadow.appendChild(this.#root);
- const sheet = new CSSStyleSheet();
- for (const { cssRules } of document.styleSheets) {
- for (const rule of cssRules) {
- console.log(rule);
- sheet.insertRule(rule.cssText);
+ for (const link of document.querySelectorAll("link")) {
+ if (link.rel === "stylesheet") {
+ this.#shadow.appendChild(link.cloneNode(true));
+ this.#stylesOffset++;
}
}
- this.#shadow.adoptedStyleSheets = [sheet];
+ for (const style of document.querySelectorAll("style")) {
+ this.#shadow.appendChild(style.cloneNode(true));
+ this.#stylesOffset++;
+ }
+ this.#root = document.createElement("div");
+ this.#shadow.appendChild(this.#root);
}
attributeChangedCallback(name, prev, next) {
switch (name) {
@@ -465,15 +470,24 @@ var LustreServerComponent = class extends HTMLElement {
}
morph(vdom) {
this.#root = morph(this.#root, vdom, (handler) => (event2) => {
+ const data = JSON.parse(this.getAttribute("data-lustre-data") || "{}");
const msg = handler(event2);
+ msg.data = merge(data, msg.data);
this.#socket?.send(JSON.stringify([event, msg.tag, msg.data]));
});
}
diff([diff2]) {
- this.#root = patch(this.#root, diff2, (handler) => (event2) => {
- const msg = handler(event2);
- this.#socket?.send(JSON.stringify([event, msg.tag, msg.data]));
- });
+ this.#root = patch(
+ this.#root,
+ diff2,
+ (handler) => (event2) => {
+ const msg = handler(event2);
+ this.#socket?.send(
+ JSON.stringify([event, msg.tag, msg.data])
+ );
+ },
+ this.#stylesOffset
+ );
}
emit([event2, data]) {
this.dispatchEvent(new CustomEvent(event2, { detail: data }));
@@ -489,6 +503,14 @@ var LustreServerComponent = class extends HTMLElement {
}
};
window.customElements.define("lustre-server-component", LustreServerComponent);
+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;
+}
export {
LustreServerComponent
};
diff --git a/src/lustre/server_component.gleam b/src/lustre/server_component.gleam
index 93e3e6a..86bd802 100644
--- a/src/lustre/server_component.gleam
+++ b/src/lustre/server_component.gleam
@@ -109,7 +109,7 @@ pub fn script() -> Element(msg) {
element("script", [attribute("type", "module")], [
// <<INJECT RUNTIME>>
element.text(
- "function N(t,e,i,r=!1){let s,a=[{prev:t,next:e,parent:t.parentNode}];for(;a.length;){let{prev:n,next:o,parent:l}=a.pop();if(o.subtree!==void 0&&(o=o.subtree()),o.content!==void 0)if(n)if(n.nodeType===Node.TEXT_NODE)n.textContent!==o.content&&(n.textContent=o.content),s??=n;else{let c=document.createTextNode(o.content);l.replaceChild(c,n),s??=c}else{let c=document.createTextNode(o.content);l.appendChild(c),s??=c}else if(o.tag!==void 0){let c=D({prev:n,next:o,dispatch:i,stack:a,isComponent:r});n?n!==c&&l.replaceChild(c,n):l.appendChild(c),s??=c}else o.elements!==void 0?k(o,c=>{a.unshift({prev:n,next:c,parent:l}),n=n?.nextSibling}):o.subtree!==void 0&&a.push({prev:n,next:o,parent:l})}return s}function J(t,e,i){let r=t.parentNode;for(let s of e[0]){let a=s[0].split(\"-\"),n=s[1],o=w(r,a),l;if(o!==null&&o!==r)l=N(o,n,i);else{let c=w(r,a.slice(0,-1)),u=document.createTextNode(\"\");c.appendChild(u),l=N(u,n,i)}a===\"0\"&&(t=l)}for(let s of e[1]){let a=s[0].split(\"-\");w(r,a).remove()}for(let s of e[2]){let a=s[0].split(\"-\"),n=s[1],o=w(r,a),l=S.get(o);for(let c of n[0]){let u=c[0],m=c[1];if(u.startsWith(\"data-lustre-on-\")){let y=u.slice(15),p=i(M);l.has(y)||el.addEventListener(y,b),l.set(y,p),el.setAttribute(u,m)}else o.setAttribute(u,m),o[u]=m}for(let c of n[1])if(c[0].startsWith(\"data-lustre-on-\")){let u=c[0].slice(15);o.removeEventListener(u,b),l.delete(u)}else o.removeAttribute(c[0])}return t}function D({prev:t,next:e,dispatch:i,stack:r}){let s=e.namespace||\"http://www.w3.org/1999/xhtml\",a=t&&t.nodeType===Node.ELEMENT_NODE&&t.localName===e.tag&&t.namespaceURI===(e.namespace||\"http://www.w3.org/1999/xhtml\"),n=a?t:s?document.createElementNS(s,e.tag):document.createElement(e.tag),o;if(S.has(n))o=S.get(n);else{let f=new Map;S.set(n,f),o=f}let l=a?new Set(o.keys()):null,c=a?new Set(Array.from(t.attributes,f=>f.name)):null,u=null,m=null,y=null;for(let f of e.attrs){let d=f[0],h=f[1];if(f.as_property)n[d]!==h&&(n[d]=h),a&&c.delete(d);else if(d.startsWith(\"on\")){let g=d.slice(2),E=i(h);o.has(g)||n.addEventListener(g,b),o.set(g,E),a&&l.delete(g)}else if(d.startsWith(\"data-lustre-on-\")){let g=d.slice(15),E=i(M);o.has(g)||n.addEventListener(g,b),o.set(g,E),n.setAttribute(d,h)}else d===\"class\"?u=u===null?h:u+\" \"+h:d===\"style\"?m=m===null?h:m+h:d===\"dangerous-unescaped-html\"?y=h:(n.getAttribute(d)!==h&&n.setAttribute(d,h),(d===\"value\"||d===\"selected\")&&(n[d]=h),a&&c.delete(d))}if(u!==null&&(n.setAttribute(\"class\",u),a&&c.delete(\"class\")),m!==null&&(n.setAttribute(\"style\",m),a&&c.delete(\"style\")),a){for(let f of c)n.removeAttribute(f);for(let f of l)o.delete(f),n.removeEventListener(f,b)}if(e.key!==void 0&&e.key!==\"\")n.setAttribute(\"data-lustre-key\",e.key);else if(y!==null)return n.innerHTML=y,n;let p=n.firstChild,x=null,C=null,O=null,A=e.children[Symbol.iterator]().next().value;a&&A!==void 0&&A.key!==void 0&&A.key!==\"\"&&(x=new Set,C=L(t),O=L(e));for(let f of e.children)k(f,d=>{d.key!==void 0&&x!==null?p=W(p,d,n,r,O,C,x):(r.unshift({prev:p,next:d,parent:n}),p=p?.nextSibling)});for(;p;){let f=p.nextSibling;n.removeChild(p),p=f}return n}var S=new WeakMap;function b(t){let e=t.currentTarget;if(!S.has(e)){e.removeEventListener(t.type,b);return}let i=S.get(e);if(!i.has(t.type)){e.removeEventListener(t.type,b);return}i.get(t.type)(t)}function M(t){let e=t.currentTarget,i=e.getAttribute(`data-lustre-on-${t.type}`),r=JSON.parse(e.getAttribute(\"data-lustre-data\")||\"{}\"),s=JSON.parse(e.getAttribute(\"data-lustre-include\")||\"[]\");switch(t.type){case\"input\":case\"change\":s.push(\"target.value\");break}return{tag:i,data:s.reduce((a,n)=>{let o=n.split(\".\");for(let l=0,c=a,u=t;l<o.length;l++)l===o.length-1?c[o[l]]=u[o[l]]:(c[o[l]]??={},u=u[o[l]],c=c[o[l]]);return a},{data:r})}}function L(t){let e=new Map;if(t)for(let i of t.children)k(i,r=>{let s=r?.key||r?.getAttribute?.(\"data-lustre-key\");s&&e.set(s,r)});return e}function w(t,e){let i,r,s=t;for(;[i,...r]=e,i!==void 0;)s=s.childNodes.item(i),e=r;return s}function W(t,e,i,r,s,a,n){for(;t&&!s.has(t.getAttribute(\"data-lustre-key\"));){let l=t.nextSibling;i.removeChild(t),t=l}if(a.size===0)return k(e,l=>{r.unshift({prev:t,next:l,parent:i}),t=t?.nextSibling}),t;if(n.has(e.key))return console.warn(`Duplicate key found in Lustre vnode: ${e.key}`),r.unshift({prev:null,next:e,parent:i}),t;n.add(e.key);let o=a.get(e.key);if(!o&&!t)return r.unshift({prev:null,next:e,parent:i}),t;if(!o&&t!==null){let l=document.createTextNode(\"\");return i.insertBefore(l,t),r.unshift({prev:l,next:e,parent:i}),t}return!o||o===t?(r.unshift({prev:t,next:e,parent:i}),t=t?.nextSibling,t):(i.insertBefore(o,t),r.unshift({prev:o,next:e,parent:i}),t)}function k(t,e){if(t.elements!==void 0)for(let i of t.elements)e(i);else e(t)}var T=class extends HTMLElement{static get observedAttributes(){return[\"route\"]}#s=null;#t=null;#e=null;#n=null;constructor(){super(),this.#n=this.attachShadow({mode:\"closed\"}),this.#s=new MutationObserver(e=>{let i=[];for(let r of e)if(r.type===\"attributes\"){let{attributeName:s,oldValue:a}=r,n=this.getAttribute(s);if(a!==n)try{i.push([s,JSON.parse(n)])}catch{i.push([s,n])}}i.length&&this.#e?.send(JSON.stringify([5,i]))})}connectedCallback(){this.#t=document.createElement(\"div\"),this.#n.appendChild(this.#t);let e=new CSSStyleSheet;for(let{cssRules:i}of document.styleSheets)for(let r of i)console.log(r),e.insertRule(r.cssText);this.#n.adoptedStyleSheets=[e]}attributeChangedCallback(e,i,r){switch(e){case\"route\":if(!r)this.#e?.close(),this.#e=null;else if(i!==r){let s=this.getAttribute(\"id\"),a=r+(s?`?id=${s}`:\"\"),n=window.location.protocol===\"https:\"?\"wss\":\"ws\";this.#e?.close(),this.#e=new WebSocket(`${n}://${window.location.host}${a}`),this.#e.addEventListener(\"message\",o=>this.messageReceivedCallback(o))}}}messageReceivedCallback({data:e}){let[i,...r]=JSON.parse(e);switch(i){case 0:return this.diff(r);case 1:return this.emit(r);case 2:return this.init(r)}}init([e,i]){let r=[];for(let s of e)s in this?r.push([s,this[s]]):this.hasAttribute(s)&&r.push([s,this.getAttribute(s)]),Object.defineProperty(this,s,{get(){return this[`_${s}`]??this.getAttribute(s)},set(a){let n=this[s];typeof a==\"string\"?this.setAttribute(s,a):this[`_${s}`]=a,n!==a&&this.#e?.send(JSON.stringify([5,[[s,a]]]))}});this.#s.observe(this,{attributeFilter:e,attributeOldValue:!0,attributes:!0,characterData:!1,characterDataOldValue:!1,childList:!1,subtree:!1}),this.morph(i),r.length&&this.#e?.send(JSON.stringify([5,r]))}morph(e){this.#t=N(this.#t,e,i=>r=>{let s=i(r);this.#e?.send(JSON.stringify([4,s.tag,s.data]))})}diff([e]){this.#t=J(this.#t,e,i=>r=>{let s=i(r);this.#e?.send(JSON.stringify([4,s.tag,s.data]))})}emit([e,i]){this.dispatchEvent(new CustomEvent(e,{detail:i}))}disconnectedCallback(){this.#e?.close()}get adoptedStyleSheets(){return this.#n.adoptedStyleSheets}set adoptedStyleSheets(e){this.#n.adoptedStyleSheets=e}};window.customElements.define(\"lustre-server-component\",T);export{T as LustreServerComponent};",
+ "function S(e,t,s,r=!1){let i,o=[{prev:e,next:t,parent:e.parentNode}];for(;o.length;){let{prev:n,next:a,parent:l}=o.pop();if(a.subtree!==void 0&&(a=a.subtree()),a.content!==void 0)if(n)if(n.nodeType===Node.TEXT_NODE)n.textContent!==a.content&&(n.textContent=a.content),i??=n;else{let c=document.createTextNode(a.content);l.replaceChild(c,n),i??=c}else{let c=document.createTextNode(a.content);l.appendChild(c),i??=c}else if(a.tag!==void 0){let c=W({prev:n,next:a,dispatch:s,stack:o,isComponent:r});n?n!==c&&l.replaceChild(c,n):l.appendChild(c),i??=c}else a.elements!==void 0?A(a,c=>{o.unshift({prev:n,next:c,parent:l}),n=n?.nextSibling}):a.subtree!==void 0&&o.push({prev:n,next:a,parent:l})}return i}function J(e,t,s,r=0){let i=e.parentNode;for(let o of t[0]){let n=o[0].split(\"-\"),a=o[1],l=k(i,n,r),c;if(l!==null&&l!==i)c=S(l,a,s);else{let u=k(i,n.slice(0,-1),r),f=document.createTextNode(\"\");u.appendChild(f),c=S(f,a,s)}n===\"0\"&&(e=c)}for(let o of t[1]){let n=o[0].split(\"-\");k(i,n,r).remove()}for(let o of t[2]){let n=o[0].split(\"-\"),a=o[1],l=k(i,n,r),c=N.get(l);for(let u of a[0]){let f=u[0],b=u[1];if(f.startsWith(\"data-lustre-on-\")){let p=f.slice(15),w=s(M);c.has(p)||el.addEventListener(p,y),c.set(p,w),el.setAttribute(f,b)}else l.setAttribute(f,b),l[f]=b}for(let u of a[1])if(u[0].startsWith(\"data-lustre-on-\")){let f=u[0].slice(15);l.removeEventListener(f,y),c.delete(f)}else l.removeAttribute(u[0])}return e}function W({prev:e,next:t,dispatch:s,stack:r}){let i=t.namespace||\"http://www.w3.org/1999/xhtml\",o=e&&e.nodeType===Node.ELEMENT_NODE&&e.localName===t.tag&&e.namespaceURI===(t.namespace||\"http://www.w3.org/1999/xhtml\"),n=o?e:i?document.createElementNS(i,t.tag):document.createElement(t.tag),a;if(N.has(n))a=N.get(n);else{let h=new Map;N.set(n,h),a=h}let l=o?new Set(a.keys()):null,c=o?new Set(Array.from(e.attributes,h=>h.name)):null,u=null,f=null,b=null;for(let h of t.attrs){let d=h[0],m=h[1];if(h.as_property)n[d]!==m&&(n[d]=m),o&&c.delete(d);else if(d.startsWith(\"on\")){let g=d.slice(2),E=s(m);a.has(g)||n.addEventListener(g,y),a.set(g,E),o&&l.delete(g)}else if(d.startsWith(\"data-lustre-on-\")){let g=d.slice(15),E=s(M);a.has(g)||n.addEventListener(g,y),a.set(g,E),n.setAttribute(d,m)}else d===\"class\"?u=u===null?m:u+\" \"+m:d===\"style\"?f=f===null?m:f+m:d===\"dangerous-unescaped-html\"?b=m:(n.getAttribute(d)!==m&&n.setAttribute(d,m),(d===\"value\"||d===\"selected\")&&(n[d]=m),o&&c.delete(d))}if(u!==null&&(n.setAttribute(\"class\",u),o&&c.delete(\"class\")),f!==null&&(n.setAttribute(\"style\",f),o&&c.delete(\"style\")),o){for(let h of c)n.removeAttribute(h);for(let h of l)a.delete(h),n.removeEventListener(h,y)}if(t.key!==void 0&&t.key!==\"\")n.setAttribute(\"data-lustre-key\",t.key);else if(b!==null)return n.innerHTML=b,n;let p=n.firstChild,w=null,C=null,T=null,x=t.children[Symbol.iterator]().next().value;o&&x!==void 0&&x.key!==void 0&&x.key!==\"\"&&(w=new Set,C=L(e),T=L(t));for(let h of t.children)A(h,d=>{d.key!==void 0&&w!==null?p=F(p,d,n,r,T,C,w):(r.unshift({prev:p,next:d,parent:n}),p=p?.nextSibling)});for(;p;){let h=p.nextSibling;n.removeChild(p),p=h}return n}var N=new WeakMap;function y(e){let t=e.currentTarget;if(!N.has(t)){t.removeEventListener(e.type,y);return}let s=N.get(t);if(!s.has(e.type)){t.removeEventListener(e.type,y);return}s.get(e.type)(e)}function M(e){let t=e.currentTarget,s=t.getAttribute(`data-lustre-on-${e.type}`),r=JSON.parse(t.getAttribute(\"data-lustre-data\")||\"{}\"),i=JSON.parse(t.getAttribute(\"data-lustre-include\")||\"[]\");switch(e.type){case\"input\":case\"change\":i.push(\"target.value\");break}return{tag:s,data:i.reduce((o,n)=>{let a=n.split(\".\");for(let l=0,c=o,u=e;l<a.length;l++)l===a.length-1?c[a[l]]=u[a[l]]:(c[a[l]]??={},u=u[a[l]],c=c[a[l]]);return o},{data:r})}}function L(e){let t=new Map;if(e)for(let s of e.children)A(s,r=>{let i=r?.key||r?.getAttribute?.(\"data-lustre-key\");i&&t.set(i,r)});return t}function k(e,t,s){let r,i,o=e,n=!0;for(;[r,...i]=t,r!==void 0;)o=o.childNodes.item(n?r+s:r),n=!1,t=i;return o}function F(e,t,s,r,i,o,n){for(;e&&!i.has(e.getAttribute(\"data-lustre-key\"));){let l=e.nextSibling;s.removeChild(e),e=l}if(o.size===0)return A(t,l=>{r.unshift({prev:e,next:l,parent:s}),e=e?.nextSibling}),e;if(n.has(t.key))return console.warn(`Duplicate key found in Lustre vnode: ${t.key}`),r.unshift({prev:null,next:t,parent:s}),e;n.add(t.key);let a=o.get(t.key);if(!a&&!e)return r.unshift({prev:null,next:t,parent:s}),e;if(!a&&e!==null){let l=document.createTextNode(\"\");return s.insertBefore(l,e),r.unshift({prev:l,next:t,parent:s}),e}return!a||a===e?(r.unshift({prev:e,next:t,parent:s}),e=e?.nextSibling,e):(s.insertBefore(a,e),r.unshift({prev:a,next:t,parent:s}),e)}function A(e,t){if(e.elements!==void 0)for(let s of e.elements)t(s);else t(e)}var O=class extends HTMLElement{static get observedAttributes(){return[\"route\"]}#i=null;#e=null;#t=null;#n=null;#s=0;constructor(){super(),this.#n=this.attachShadow({mode:\"closed\"}),this.#i=new MutationObserver(t=>{let s=[];for(let r of t)if(r.type===\"attributes\"){let{attributeName:i,oldValue:o}=r,n=this.getAttribute(i);if(o!==n)try{s.push([i,JSON.parse(n)])}catch{s.push([i,n])}}s.length&&this.#t?.send(JSON.stringify([5,s]))})}connectedCallback(){for(let t of document.querySelectorAll(\"link\"))t.rel===\"stylesheet\"&&(this.#n.appendChild(t.cloneNode(!0)),this.#s++);for(let t of document.querySelectorAll(\"style\"))this.#n.appendChild(t.cloneNode(!0)),this.#s++;this.#e=document.createElement(\"div\"),this.#n.appendChild(this.#e)}attributeChangedCallback(t,s,r){switch(t){case\"route\":if(!r)this.#t?.close(),this.#t=null;else if(s!==r){let i=this.getAttribute(\"id\"),o=r+(i?`?id=${i}`:\"\"),n=window.location.protocol===\"https:\"?\"wss\":\"ws\";this.#t?.close(),this.#t=new WebSocket(`${n}://${window.location.host}${o}`),this.#t.addEventListener(\"message\",a=>this.messageReceivedCallback(a))}}}messageReceivedCallback({data:t}){let[s,...r]=JSON.parse(t);switch(s){case 0:return this.diff(r);case 1:return this.emit(r);case 2:return this.init(r)}}init([t,s]){let r=[];for(let i of t)i in this?r.push([i,this[i]]):this.hasAttribute(i)&&r.push([i,this.getAttribute(i)]),Object.defineProperty(this,i,{get(){return this[`_${i}`]??this.getAttribute(i)},set(o){let n=this[i];typeof o==\"string\"?this.setAttribute(i,o):this[`_${i}`]=o,n!==o&&this.#t?.send(JSON.stringify([5,[[i,o]]]))}});this.#i.observe(this,{attributeFilter:t,attributeOldValue:!0,attributes:!0,characterData:!1,characterDataOldValue:!1,childList:!1,subtree:!1}),this.morph(s),r.length&&this.#t?.send(JSON.stringify([5,r]))}morph(t){this.#e=S(this.#e,t,s=>r=>{let i=JSON.parse(this.getAttribute(\"data-lustre-data\")||\"{}\"),o=s(r);o.data=$(i,o.data),this.#t?.send(JSON.stringify([4,o.tag,o.data]))})}diff([t]){this.#e=J(this.#e,t,s=>r=>{let i=s(r);this.#t?.send(JSON.stringify([4,i.tag,i.data]))},this.#s)}emit([t,s]){this.dispatchEvent(new CustomEvent(t,{detail:s}))}disconnectedCallback(){this.#t?.close()}get adoptedStyleSheets(){return this.#n.adoptedStyleSheets}set adoptedStyleSheets(t){this.#n.adoptedStyleSheets=t}};window.customElements.define(\"lustre-server-component\",O);function $(e,t){for(let s in t)t[s]instanceof Object&&Object.assign(t[s],$(e[s],t[s]));return Object.assign(e||{},t),e}export{O as LustreServerComponent};",
),
])
}