From b2ccfe5f659b6163b037efc07f794707f7342831 Mon Sep 17 00:00:00 2001 From: Delaney Date: Thu, 28 Nov 2024 15:08:17 -0800 Subject: [PATCH 01/14] Fix newline in SDK protocol for paths. (#281) * Fix newline in SDK protocol for paths. Fixes #272 * Update PHP SDK * Fix newline in SDK protocol for paths in Go SDK #272 * Tweak wording --------- Co-authored-by: Ben Croker --- bundles/datastar.js | 3 ++- bundles/datastar.js.map | 6 +++--- code/dotnet/sdk/src/Consts.fs | 4 ++-- code/go/sdk/consts.go | 4 ++-- code/go/sdk/signals.go | 8 ++++++-- code/php/sdk/src/Consts.php | 4 ++-- code/php/sdk/src/events/EventTrait.php | 4 ++-- code/php/sdk/src/events/RemoveSignals.php | 10 +++++++--- code/php/sdk/tests/Unit/RemoveSignalsTest.php | 4 +++- .../official/watchers/backend/sseRemoveSignals.ts | 6 ++---- design/SDK.md | 13 +++++++------ 11 files changed, 38 insertions(+), 28 deletions(-) diff --git a/bundles/datastar.js b/bundles/datastar.js index 2982cbdca..43f895234 100644 --- a/bundles/datastar.js +++ b/bundles/datastar.js @@ -11,5 +11,6 @@ ${g}`);console.error(_);debugger}}let b=r.onLoad(E);b&&(this.removals.has(i)||th `+l:l;break;case"event":r.event=l;break;case"id":t(r.id=l);break;case"retry":let c=parseInt(l,10);isNaN(c)||e(r.retry=c);break}}}}function Nn(t,e){let n=new Uint8Array(t.length+e.length);return n.set(t),n.set(e,t.length),n}function pt(){return{data:"",event:"",id:"",retry:void 0}}var St="text/event-stream",On=1e3,ht="last-event-id";function Oe(t,{signal:e,headers:n,onopen:r,onmessage:o,onclose:i,onerror:s,openWhenHidden:a,fetch:u,retryScaler:m=2,retryMaxWaitMs:l=3e4,retryMaxCount:c=10,...f}){return new Promise((S,A)=>{let v=0,E={...n};E.accept||(E.accept=St);let b;function d(){b.abort(),document.hidden||N()}a||document.addEventListener("visibilitychange",d);let p=On,g=0;function T(){document.removeEventListener("visibilitychange",d),window.clearTimeout(g),b.abort()}e?.addEventListener("abort",()=>{T(),S()});let _=u??window.fetch,D=r??function(){};async function N(){b=new AbortController;try{let L=await _(t,{...f,headers:E,signal:b.signal});await D(L),await mt(L.body,dt(gt(P=>{P?E[ht]=P:delete E[ht]},P=>{p=P},o))),i?.(),T(),S()}catch(L){if(!b.signal.aborted)try{let P=s?.(L)??p;window.clearTimeout(g),g=window.setTimeout(N,P),p*=m,p=Math.min(p,l),v++,v>=c?(T(),A(Qe)):console.error(`Datastar failed to reach ${f.method}:${t.toString()} retry in ${P}ms`)}catch(P){T(),A(P)}}}N()})}var J=`${R}-sse`,ke=`${R}-settling`,W=`${R}-swapping`,he="started",Se="finished";function k(t,e){document.addEventListener(J,n=>{if(n.detail.type!=t)return;let{argsRaw:r}=n.detail;e(r)})}var Et=t=>`${t}`.includes("text/event-stream");function Ie(t,e){document.dispatchEvent(new CustomEvent(J,{detail:{type:t,argsRaw:e}}))}function I(t){return async(e,n,r)=>{if(!n?.length)throw h;let o=r?.onlyRemoteSignals??!0,i=Object.assign({"Content-Type":"application/json",[Ye]:!0},r?.headers),s=e.store().value,a=Object.assign({},s);o&&(a=V(a));let u=JSON.stringify(a),{el:{id:m}}=e;Ie(he,{elID:m});let l=new URL(n,window.location.origin);t=t.toUpperCase();let c={method:t,headers:i,onmessage:f=>{if(!f.event.startsWith(R))return;let S=f.event,A={},v=f.data.split(` `);for(let b of v){let d=b.indexOf(" "),p=b.slice(0,d),g=A[p];g||(g=[],A[p]=g);let T=b.slice(d+1).trim();g.push(T)}let E={};for(let[b,d]of Object.entries(A))E[b]=d.join(` `);Ie(S,E)},onerror:f=>{if(Et(f))throw f;f&&console.error(f.message)},onclose:()=>{Ie(Se,{elID:m})}};if(t==="GET"){let f=new URLSearchParams(l.search);f.append(R,u),l.search=f.toString()}else c.body=u;try{let f=l.toString();await Oe(f,c)}catch(f){if(!Et(f))throw f}}}var bt={pluginType:"action",name:"delete",method:I("delete")};var yt={pluginType:"action",name:"get",method:I("get")};var vt={pluginType:"action",name:"patch",method:I("patch")};var Tt={pluginType:"action",name:"post",method:I("post")};var At={pluginType:"action",name:"put",method:I("put")};var _t={pluginType:"action",name:"clipboard",method:(t,e)=>{if(!navigator.clipboard)throw C;navigator.clipboard.writeText(e)}};var wt={pluginType:"action",name:"setAll",method:(t,e,n)=>{let r=new RegExp(e);t.walkSignals((o,i)=>r.test(o)&&(i.value=n))}};var Rt={pluginType:"action",name:"toggleAll",method:(t,e)=>{let n=new RegExp(e);t.walkSignals((r,o)=>n.test(r)&&(o.value=!o.value))}};var xt={pluginType:"action",name:"clampFit",method:(t,e,n,r,o,i)=>Math.max(o,Math.min(i,(e-n)/(r-n)*(i-o)+o))};var Pt={pluginType:"action",name:"clampFitInt",method:(t,e,n,r,o,i)=>Math.round(Math.max(o,Math.min(i,(e-n)/(r-n)*(i-o)+o)))};var Dt={pluginType:"action",name:"fit",method:(t,e,n,r,o,i)=>(e-n)/(r-n)*(i-o)+o};var Lt={pluginType:"action",name:"fitInt",method:(t,e,n,r,o,i)=>Math.round((e-n)/(r-n)*(i-o)+o)};var kn=`${R}-indicator`,_o=`${kn}-loading`,Mt={pluginType:"attribute",name:"indicator",mustHaveEmptyKey:!0,onLoad:t=>{let{expression:e,upsertSignal:n,el:r}=t,i=n(e,!1),s=a=>{let{type:u,argsRaw:{elID:m}}=a.detail;if(m===r.id)switch(u){case he:i.value=!0;break;case Se:i.value=!1;break}};return document.addEventListener(J,s),()=>{document.removeEventListener(J,s)}}};var Ee=t=>t.replace(/[A-Z]+(?![a-z])|[A-Z]/g,(e,n)=>(n?"-":"")+e.toLowerCase()),F=t=>t.trim()==="true";var Nt={pluginType:"attribute",name:"bind",mustNotEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:t=>t.reactivity.effect(async()=>{let e=Ee(t.key),n=t.expressionFn(t),r;typeof n=="string"?r=n:r=JSON.stringify(n),!r||r==="false"||r==="null"||r==="undefined"?t.el.removeAttribute(e):t.el.setAttribute(e,r)})};var Ot={pluginType:"attribute",name:"class",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:t=>t.reactivity.effect(()=>{let e=t.expressionFn(t);for(let[n,r]of Object.entries(e)){let o=n.split(" ");r?t.el.classList.add(...o):t.el.classList.remove(...o)}})};var In=/^data:(?[^;]+);base64,(?.*)$/,be=["change","input","keydown"],kt={pluginType:"attribute",name:"model",mustHaveEmptyKey:!0,onLoad:t=>{let{el:e,expression:n,upsertSignal:r}=t,o=n;if(typeof o!="string")throw h;let i=e.tagName.toLowerCase(),s="",a=i.includes("input"),u=e.getAttribute("type"),m=i.includes("checkbox")||a&&u==="checkbox";m&&(s=!1);let l=i.includes("select"),c=i.includes("radio")||a&&u==="radio",f=a&&u==="file";c&&(e.getAttribute("name")?.length||e.setAttribute("name",o));let S=r(o,s),A=()=>{let p="value"in e,g=S.value,T=`${g}`;if(m||c){let _=e;m?_.checked=g:c&&(_.checked=T===_.value)}else if(!f)if(l){let _=e;_.multiple?Array.from(_.options).forEach(D=>{D?.disabled||(D.selected=g.includes(D.value))}):_.value=T}else p?e.value=T:e.setAttribute("value",T)},v=t.reactivity.effect(A),E=async()=>{if(f){let T=[...e?.files||[]],_=[],D=[],N=[];await Promise.all(T.map(je=>new Promise(An=>{let Y=new FileReader;Y.onload=()=>{if(typeof Y.result!="string")throw h;let Re=Y.result.match(In);if(!Re?.groups)throw h;_.push(Re.groups.contents),D.push(Re.groups.mime),N.push(je.name)},Y.onloadend=()=>An(void 0),Y.readAsDataURL(je)}))),S.value=_;let L=t.store(),P=`${o}Mimes`,We=`${o}Names`;P in L&&(L[`${P}`].value=D),We in L&&(L[`${We}`].value=N);return}let p=S.value,g=e||e;if(typeof p=="number")S.value=Number(g.value||g.getAttribute("value"));else if(typeof p=="string")S.value=g.value||g.getAttribute("value")||"";else if(typeof p=="boolean")m?S.value=g.checked||g.getAttribute("checked")==="true":S.value=!!(g.value||g.getAttribute("value"));else if(!(typeof p>"u"))if(typeof p=="bigint")S.value=BigInt(g.value||g.getAttribute("value")||"0");else if(Array.isArray(p)){if(l){let D=[...e.selectedOptions].map(N=>N.value);S.value=D}else S.value=JSON.parse(g.value).split(",");console.log(g.value)}else throw le},b=e.tagName.split("-");if(b.length>1){let p=b[0].toLowerCase();be.forEach(g=>{be.push(`${p}-${g}`)})}return be.forEach(p=>e.addEventListener(p,E)),()=>{v(),be.forEach(p=>e.removeEventListener(p,E))}}};function Ce(t){if(!t||t?.length===0)return 0;for(let e of t){if(e.endsWith("ms"))return Number(e.replace("ms",""));if(e.endsWith("s"))return Number(e.replace("s",""))*1e3;try{return parseFloat(e)}catch{}}return 0}function re(t,e,n=!1){return t?t.includes(e)||n:!1}function It(t,e,n=!1,r=!0){let o=-1,i=()=>o&&clearTimeout(o);return function(...a){i(),n&&!o&&t(...a),o=setTimeout(()=>{r&&t(...a),i()},e)}}function Ct(t,e,n=!0,r=!1){let o=!1;return function(...s){o||(n&&t(...s),o=!0,setTimeout(()=>{o=!1,r&&t(...s)},e))}}var Cn=new Set(["window","once","passive","capture","debounce","throttle","remote","outside"]),Ft="",Ht={pluginType:"attribute",name:"on",mustNotEmptyKey:!0,mustNotEmptyExpression:!0,argumentNames:["evt"],onLoad:t=>{let{el:e,key:n,expressionFn:r}=t,o=t.el;t.modifiers.get("window")&&(o=window);let i=c=>{r(t,c)},s=t.modifiers.get("debounce");if(s){let c=Ce(s),f=re(s,"leading",!1),S=re(s,"noTrail",!0);i=It(i,c,f,S)}let a=t.modifiers.get("throttle");if(a){let c=Ce(a),f=re(a,"noLead",!0),S=re(a,"noTrail",!1);i=Ct(i,c,f,S)}let u={capture:!0,passive:!1,once:!1};t.modifiers.has("capture")||(u.capture=!1),t.modifiers.has("passive")&&(u.passive=!0),t.modifiers.has("once")&&(u.once=!0),[...t.modifiers.keys()].filter(c=>!Cn.has(c)).forEach(c=>{let f=t.modifiers.get(c)||[],S=i;i=()=>{let v=event,E=v[c],b;if(typeof E=="function")b=E(...f);else if(typeof E=="boolean")b=E;else if(typeof E=="string"){let d=E.toLowerCase().trim(),p=f.join("").toLowerCase().trim();b=d===p}else throw h;b&&S(v)}});let l=Ee(n).toLowerCase();switch(l){case"load":return i(),delete t.el.dataset.onLoad,()=>{};case"raf":let c,f=()=>{i(),c=requestAnimationFrame(f)};return c=requestAnimationFrame(f),()=>{c&&cancelAnimationFrame(c)};case"store-change":return t.reactivity.effect(()=>{let v=t.store().value;t.modifiers.has("remote")&&(v=V(v));let E=JSON.stringify(v);Ft!==E&&(Ft=E,i())});default:if(t.modifiers.has("outside")){o=document;let A=i,v=!1;i=b=>{let d=b?.target;if(!d)return;let p=e.id===d.id;p&&v&&(v=!1),!p&&!v&&(A(b),v=!0)}}return o.addEventListener(l,i,u),()=>{o.removeEventListener(l,i)}}}};var Vt={pluginType:"attribute",name:"ref",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,bypassExpressionFunctionCreation:()=>!0,onLoad:t=>{let e=t.expression;return t.upsertSignal(e,t.el),()=>{t.removeSignals(e)}}};var $t={pluginType:"attribute",name:"text",mustHaveEmptyKey:!0,onLoad:t=>{let{el:e,expressionFn:n}=t;if(!(e instanceof HTMLElement))throw h;return t.reactivity.effect(()=>{let r=n(t);e.textContent=`${r}`})}};var Ut={pluginType:"attribute",name:"persist",allowedModifiers:new Set(["local","session","remote"]),onLoad:t=>{let e=t.key||R,n=t.expression,r=new Set;if(n.trim()!==""){let l=t.expressionFn(t).split(" ");for(let c of l)r.add(c)}let o="",i=t.modifiers.has("session")?"session":"local",s=t.modifiers.has("remote"),a=m=>{let l=t.store();if(s&&(l=V(l)),r.size>0){let f={};for(let S of r){let A=S.split("."),v=f,E=l;for(let d=0;d{window.removeEventListener(xe,a)}}};var Wt={pluginType:"attribute",name:"replaceUrl",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:t=>t.reactivity.effect(()=>{let e=t.expressionFn(t),n=window.location.href,r=new URL(e,n).toString();window.history.replaceState({},"",r)})};var jt="once",Bt="half",Gt="full",Kt={pluginType:"attribute",name:"intersects",allowedModifiers:new Set([jt,Bt,Gt]),mustHaveEmptyKey:!0,onLoad:t=>{let{modifiers:e}=t,n={threshold:0};e.has(Gt)?n.threshold=1:e.has(Bt)&&(n.threshold=.5);let r=new IntersectionObserver(o=>{o.forEach(i=>{i.isIntersecting&&(t.expressionFn(t),e.has(jt)&&(r.disconnect(),delete t.el.dataset[t.rawKey]))})},n);return r.observe(t.el),()=>r.disconnect()}};var ye="smooth",Fe="instant",He="auto",qt="hstart",Jt="hcenter",zt="hend",Yt="hnearest",Zt="vstart",Xt="vcenter",Qt="vend",en="vnearest",Fn="focus",ve="center",tn="start",nn="end",rn="nearest",on={pluginType:"attribute",name:"scrollIntoView",mustHaveEmptyKey:!0,mustHaveEmptyExpression:!0,allowedModifiers:new Set([ye,Fe,He,qt,Jt,zt,Yt,Zt,Xt,Qt,en,Fn]),onLoad:({el:t,modifiers:e,rawKey:n})=>{t.tabIndex||t.setAttribute("tabindex","0");let r={behavior:ye,block:ve,inline:ve};return e.has(ye)&&(r.behavior=ye),e.has(Fe)&&(r.behavior=Fe),e.has(He)&&(r.behavior=He),e.has(qt)&&(r.inline=tn),e.has(Jt)&&(r.inline=ve),e.has(zt)&&(r.inline=nn),e.has(Yt)&&(r.inline=rn),e.has(Zt)&&(r.block=tn),e.has(Xt)&&(r.block=ve),e.has(Qt)&&(r.block=nn),e.has(en)&&(r.block=rn),tt(t,r,e.has("focus")),delete t.dataset[n],()=>{}}};var sn={pluginType:"attribute",name:"show",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:t=>t.reactivity.effect(async()=>{t.expressionFn(t)?t.el.style.display==="none"&&t.el.style.removeProperty("display"):t.el.style.setProperty("display","none")})};var oe=document,z=!!oe.startViewTransition;var Ve="view-transition",an={pluginType:"attribute",name:Ve,onGlobalInit(){let t=!1;if(document.head.childNodes.forEach(e=>{e instanceof HTMLMetaElement&&e.name===Ve&&(t=!0)}),!t){let e=document.createElement("meta");e.name=Ve,e.content="same-origin",document.head.appendChild(e)}},onLoad:t=>{if(!z){console.error("Browser does not support view transitions");return}return t.reactivity.effect(()=>{let{el:e,expressionFn:n}=t,r=n(t);if(!r)return;let o=e.style;o.viewTransitionName=r})}};var ln={pluginType:"watcher",name:x.ExecuteScript,onGlobalInit:async()=>{k(x.ExecuteScript,({autoRemove:t=`${!0}`,attributes:e=Ze,script:n})=>{let r=F(t);if(!n?.length)throw h;let o=document.createElement("script");e.split(` -`).forEach(i=>{let s=i.indexOf(" "),a=s?i.slice(0,s):i,u=s?i.slice(s):"";o.setAttribute(a.trim(),u.trim())}),o.text=n,document.head.appendChild(o),r&&o.remove()})}};var Ae=new WeakSet;function pn(t,e,n={}){t instanceof Document&&(t=t.documentElement);let r;typeof e=="string"?r=jn(e):r=e;let o=Bn(r),i=$n(t,o,n);return mn(t,o,i)}function mn(t,e,n){if(n.head.block){let r=t.querySelector("head"),o=e.querySelector("head");if(r&&o){let i=gn(o,r,n);Promise.all(i).then(()=>{mn(t,e,Object.assign(n,{head:{block:!1,ignore:!0}}))});return}}if(n.morphStyle==="innerHTML")return dn(e,t,n),t.children;if(n.morphStyle==="outerHTML"||n.morphStyle==null){let r=Kn(e,t,n);if(!r)throw $;let o=r?.previousSibling,i=r?.nextSibling,s=_e(t,r,n);return r?Gn(o,s,i):[]}else throw h}function _e(t,e,n){if(!(n.ignoreActive&&t===document.activeElement))if(e==null){if(n.callbacks.beforeNodeRemoved(t)===!1)return;t.remove(),n.callbacks.afterNodeRemoved(t);return}else{if(we(t,e))return n.callbacks.beforeNodeMorphed(t,e)===!1?void 0:(t instanceof HTMLHeadElement&&n.head.ignore||(e instanceof HTMLHeadElement&&t instanceof HTMLHeadElement&&n.head.style!==M.Morph?gn(e,t,n):(Vn(e,t),dn(e,t,n))),n.callbacks.afterNodeMorphed(t,e),t);if(n.callbacks.beforeNodeRemoved(t)===!1||n.callbacks.beforeNodeAdded(e)===!1)return;if(!t.parentElement)throw h;return t.parentElement.replaceChild(e,t),n.callbacks.afterNodeAdded(e),n.callbacks.afterNodeRemoved(t),e}}function dn(t,e,n){let r=t.firstChild,o=e.firstChild,i;for(;r;){if(i=r,r=i.nextSibling,o==null){if(n.callbacks.beforeNodeAdded(i)===!1)return;e.appendChild(i),n.callbacks.afterNodeAdded(i),j(n,i);continue}if(hn(i,o,n)){_e(o,i,n),o=o.nextSibling,j(n,i);continue}let s=Un(t,e,i,o,n);if(s){o=un(o,s,n),_e(s,i,n),j(n,i);continue}let a=Wn(t,i,o,n);if(a){o=un(o,a,n),_e(a,i,n),j(n,i);continue}if(n.callbacks.beforeNodeAdded(i)===!1)return;e.insertBefore(i,o),n.callbacks.afterNodeAdded(i),j(n,i)}for(;o!==null;){let s=o;o=o.nextSibling,Sn(s,n)}}function Vn(t,e){let n=t.nodeType;if(n===1){for(let r of t.attributes)e.getAttribute(r.name)!==r.value&&e.setAttribute(r.name,r.value);for(let r of e.attributes)t.hasAttribute(r.name)||e.removeAttribute(r.name)}if((n===Node.COMMENT_NODE||n===Node.TEXT_NODE)&&e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue),t instanceof HTMLInputElement&&e instanceof HTMLInputElement&&t.type!=="file")e.value=t.value||"",Te(t,e,"value"),Te(t,e,"checked"),Te(t,e,"disabled");else if(t instanceof HTMLOptionElement)Te(t,e,"selected");else if(t instanceof HTMLTextAreaElement&&e instanceof HTMLTextAreaElement){let r=t.value,o=e.value;r!==o&&(e.value=r),e.firstChild&&e.firstChild.nodeValue!==r&&(e.firstChild.nodeValue=r)}}function Te(t,e,n){let r=t.getAttribute(n),o=e.getAttribute(n);r!==o&&(r?e.setAttribute(n,r):e.removeAttribute(n))}function gn(t,e,n){let r=[],o=[],i=[],s=[],a=n.head.style,u=new Map;for(let l of t.children)u.set(l.outerHTML,l);for(let l of e.children){let c=u.has(l.outerHTML),f=n.head.shouldReAppend(l),S=n.head.shouldPreserve(l);c||S?f?o.push(l):(u.delete(l.outerHTML),i.push(l)):a===M.Append?f&&(o.push(l),s.push(l)):n.head.shouldRemove(l)!==!1&&o.push(l)}s.push(...u.values());let m=[];for(let l of s){let c=document.createRange().createContextualFragment(l.outerHTML).firstChild;if(!c)throw h;if(n.callbacks.beforeNodeAdded(c)){if(c.hasAttribute("href")||c.hasAttribute("src")){let f,S=new Promise(A=>{f=A});c.addEventListener("load",function(){f(void 0)}),m.push(S)}e.appendChild(c),n.callbacks.afterNodeAdded(c),r.push(c)}}for(let l of o)n.callbacks.beforeNodeRemoved(l)!==!1&&(e.removeChild(l),n.callbacks.afterNodeRemoved(l));return n.head.afterHeadMorphed(e,{added:r,kept:i,removed:o}),m}function H(){}function $n(t,e,n){return{target:t,newContent:e,config:n,morphStyle:n.morphStyle,ignoreActive:n.ignoreActive,idMap:Yn(t,e),deadIds:new Set,callbacks:Object.assign({beforeNodeAdded:H,afterNodeAdded:H,beforeNodeMorphed:H,afterNodeMorphed:H,beforeNodeRemoved:H,afterNodeRemoved:H},n.callbacks),head:Object.assign({style:"merge",shouldPreserve:r=>r.getAttribute("im-preserve")==="true",shouldReAppend:r=>r.getAttribute("im-re-append")==="true",shouldRemove:H,afterHeadMorphed:H},n.head)}}function hn(t,e,n){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===e.tagName?t?.id?.length&&t.id===e.id?!0:ie(n,t,e)>0:!1}function we(t,e){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===e.tagName}function un(t,e,n){for(;t!==e;){let r=t;if(t=t?.nextSibling,!r)throw h;Sn(r,n)}return j(n,e),e.nextSibling}function Un(t,e,n,r,o){let i=ie(o,n,e),s=null;if(i>0){s=r;let a=0;for(;s!=null;){if(hn(n,s,o))return s;if(a+=ie(o,s,t),a>i)return null;s=s.nextSibling}}return s}function Wn(t,e,n,r){let o=n,i=e.nextSibling,s=0;for(;o&&i;){if(ie(r,o,t)>0)return null;if(we(e,o))return o;if(we(i,o)&&(s++,i=i.nextSibling,s>=2))return null;o=o.nextSibling}return o}var cn=new DOMParser;function jn(t){let e=t.replace(/]*>|>)([\s\S]*?)<\/svg>/gim,"");if(e.match(/<\/html>/)||e.match(/<\/head>/)||e.match(/<\/body>/)){let n=cn.parseFromString(t,"text/html");if(e.match(/<\/html>/))return Ae.add(n),n;{let r=n.firstChild;return r?(Ae.add(r),r):null}}else{let r=cn.parseFromString(``,"text/html").body.querySelector("template")?.content;if(!r)throw $;return Ae.add(r),r}}function Bn(t){if(t==null)return document.createElement("div");if(Ae.has(t))return t;if(t instanceof Node){let e=document.createElement("div");return e.append(t),e}else{let e=document.createElement("div");for(let n of[...t])e.append(n);return e}}function Gn(t,e,n){let r=[],o=[];for(;t;)r.push(t),t=t.previousSibling;for(;r.length>0;){let i=r.pop();o.push(i),e?.parentElement?.insertBefore(i,e)}for(o.push(e);n;)r.push(n),o.push(n),n=n.nextSibling;for(;r.length;)e?.parentElement?.insertBefore(r.pop(),e.nextSibling);return o}function Kn(t,e,n){let r=t.firstChild,o=r,i=0;for(;r;){let s=qn(r,e,n);s>i&&(o=r,i=s),r=r.nextSibling}return o}function qn(t,e,n){return we(t,e)?.5+ie(n,t,e):0}function Sn(t,e){j(e,t),e.callbacks.beforeNodeRemoved(t)!==!1&&(t.remove(),e.callbacks.afterNodeRemoved(t))}function Jn(t,e){return!t.deadIds.has(e)}function zn(t,e,n){return t.idMap.get(n)?.has(e)||!1}function j(t,e){let n=t.idMap.get(e);if(n)for(let r of n)t.deadIds.add(r)}function ie(t,e,n){let r=t.idMap.get(e);if(!r)return 0;let o=0;for(let i of r)Jn(t,i)&&zn(t,i,n)&&++o;return o}function fn(t,e){let n=t.parentElement,r=t.querySelectorAll("[id]");for(let o of r){let i=o;for(;i!==n&&i;){let s=e.get(i);s==null&&(s=new Set,e.set(i,s)),s.add(o.id),i=i.parentElement}}}function Yn(t,e){let n=new Map;return fn(t,n),fn(e,n),n}var bn={pluginType:"watcher",name:x.MergeFragments,onGlobalInit:async t=>{let e=document.createElement("template");k(x.MergeFragments,({fragments:n="
",selector:r="",mergeMode:o=Xe,settleDuration:i=`${300}`,useViewTransition:s=`${!1}`})=>{let a=parseInt(i),u=F(s);e.innerHTML=n.trim(),[...e.content.children].forEach(l=>{if(!(l instanceof Element))throw h;let c=r||`#${l.getAttribute("id")}`,S=[...document.querySelectorAll(c)||[]];if(!S.length)throw h;z&&u?oe.startViewTransition(()=>En(t,o,a,l,S)):En(t,o,a,l,S)})})}};function En(t,e,n,r,o){for(let i of o){i.classList.add(W);let s=i.outerHTML,a=i;switch(e){case M.Morph:let m=pn(a,r,{callbacks:{beforeNodeRemoved:(l,c)=>(t.cleanup(l),!0)}});if(!m?.length)throw h;a=m[0];break;case M.Inner:a.innerHTML=r.innerHTML;break;case M.Outer:a.replaceWith(r);break;case M.Prepend:a.prepend(r);break;case M.Append:a.append(r);break;case M.Before:a.before(r);break;case M.After:a.after(r);break;case M.UpsertAttributes:r.getAttributeNames().forEach(l=>{let c=r.getAttribute(l);a.setAttribute(l,c)});break;default:throw h}t.cleanup(a),a.classList.add(W),t.applyPlugins(document.body),setTimeout(()=>{i.classList.remove(W),a.classList.remove(W)},n);let u=a.outerHTML;s!==u&&(a.classList.add(ke),setTimeout(()=>{a.classList.remove(ke)},n))}}var yn={pluginType:"watcher",name:x.MergeSignals,onGlobalInit:async t=>{k(x.MergeSignals,({signals:e="{}",onlyIfMissing:n=`${!1}`})=>{let r=F(n),o=` return Object.assign({...ctx.store()}, ${e})`;try{let s=new Function("ctx",o)(t),a=se(t.store(),s,r);t.mergeSignals(a),t.applyPlugins(document.body)}catch(i){console.log(o),console.error(i);debugger}})}};var vn={pluginType:"watcher",name:x.RemoveFragments,onGlobalInit:async()=>{k(x.RemoveFragments,({selector:t,settleDuration:e=`${300}`,useViewTransition:n=`${!1}`})=>{if(!t.length)throw h;let r=parseInt(e),o=F(n),i=document.querySelectorAll(t),s=()=>{for(let a of i)a.classList.add(W);setTimeout(()=>{for(let a of i)a.remove()},r)};z&&o?oe.startViewTransition(()=>s()):s()})}};var Tn={pluginType:"watcher",name:x.RemoveSignals,onGlobalInit:async t=>{k(x.RemoveSignals,({paths:e=""})=>{if(e=e.replaceAll(/\s+/g," "),!e?.length)throw h;let n=e.split(" ");t.removeSignals(...n)})}};ft.load(kt,Vt,Mt,Nt,Wt,Ot,Ht,$t,Ut,Kt,on,sn,an,bt,yt,vt,Tt,At,_t,wt,Rt,xt,Pt,Dt,Lt,bn,yn,vn,Tn,ln);})(); +`).forEach(i=>{let s=i.indexOf(" "),a=s?i.slice(0,s):i,u=s?i.slice(s):"";o.setAttribute(a.trim(),u.trim())}),o.text=n,document.head.appendChild(o),r&&o.remove()})}};var Ae=new WeakSet;function pn(t,e,n={}){t instanceof Document&&(t=t.documentElement);let r;typeof e=="string"?r=jn(e):r=e;let o=Bn(r),i=$n(t,o,n);return mn(t,o,i)}function mn(t,e,n){if(n.head.block){let r=t.querySelector("head"),o=e.querySelector("head");if(r&&o){let i=gn(o,r,n);Promise.all(i).then(()=>{mn(t,e,Object.assign(n,{head:{block:!1,ignore:!0}}))});return}}if(n.morphStyle==="innerHTML")return dn(e,t,n),t.children;if(n.morphStyle==="outerHTML"||n.morphStyle==null){let r=Kn(e,t,n);if(!r)throw $;let o=r?.previousSibling,i=r?.nextSibling,s=_e(t,r,n);return r?Gn(o,s,i):[]}else throw h}function _e(t,e,n){if(!(n.ignoreActive&&t===document.activeElement))if(e==null){if(n.callbacks.beforeNodeRemoved(t)===!1)return;t.remove(),n.callbacks.afterNodeRemoved(t);return}else{if(we(t,e))return n.callbacks.beforeNodeMorphed(t,e)===!1?void 0:(t instanceof HTMLHeadElement&&n.head.ignore||(e instanceof HTMLHeadElement&&t instanceof HTMLHeadElement&&n.head.style!==M.Morph?gn(e,t,n):(Vn(e,t),dn(e,t,n))),n.callbacks.afterNodeMorphed(t,e),t);if(n.callbacks.beforeNodeRemoved(t)===!1||n.callbacks.beforeNodeAdded(e)===!1)return;if(!t.parentElement)throw h;return t.parentElement.replaceChild(e,t),n.callbacks.afterNodeAdded(e),n.callbacks.afterNodeRemoved(t),e}}function dn(t,e,n){let r=t.firstChild,o=e.firstChild,i;for(;r;){if(i=r,r=i.nextSibling,o==null){if(n.callbacks.beforeNodeAdded(i)===!1)return;e.appendChild(i),n.callbacks.afterNodeAdded(i),j(n,i);continue}if(hn(i,o,n)){_e(o,i,n),o=o.nextSibling,j(n,i);continue}let s=Un(t,e,i,o,n);if(s){o=un(o,s,n),_e(s,i,n),j(n,i);continue}let a=Wn(t,i,o,n);if(a){o=un(o,a,n),_e(a,i,n),j(n,i);continue}if(n.callbacks.beforeNodeAdded(i)===!1)return;e.insertBefore(i,o),n.callbacks.afterNodeAdded(i),j(n,i)}for(;o!==null;){let s=o;o=o.nextSibling,Sn(s,n)}}function Vn(t,e){let n=t.nodeType;if(n===1){for(let r of t.attributes)e.getAttribute(r.name)!==r.value&&e.setAttribute(r.name,r.value);for(let r of e.attributes)t.hasAttribute(r.name)||e.removeAttribute(r.name)}if((n===Node.COMMENT_NODE||n===Node.TEXT_NODE)&&e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue),t instanceof HTMLInputElement&&e instanceof HTMLInputElement&&t.type!=="file")e.value=t.value||"",Te(t,e,"value"),Te(t,e,"checked"),Te(t,e,"disabled");else if(t instanceof HTMLOptionElement)Te(t,e,"selected");else if(t instanceof HTMLTextAreaElement&&e instanceof HTMLTextAreaElement){let r=t.value,o=e.value;r!==o&&(e.value=r),e.firstChild&&e.firstChild.nodeValue!==r&&(e.firstChild.nodeValue=r)}}function Te(t,e,n){let r=t.getAttribute(n),o=e.getAttribute(n);r!==o&&(r?e.setAttribute(n,r):e.removeAttribute(n))}function gn(t,e,n){let r=[],o=[],i=[],s=[],a=n.head.style,u=new Map;for(let l of t.children)u.set(l.outerHTML,l);for(let l of e.children){let c=u.has(l.outerHTML),f=n.head.shouldReAppend(l),S=n.head.shouldPreserve(l);c||S?f?o.push(l):(u.delete(l.outerHTML),i.push(l)):a===M.Append?f&&(o.push(l),s.push(l)):n.head.shouldRemove(l)!==!1&&o.push(l)}s.push(...u.values());let m=[];for(let l of s){let c=document.createRange().createContextualFragment(l.outerHTML).firstChild;if(!c)throw h;if(n.callbacks.beforeNodeAdded(c)){if(c.hasAttribute("href")||c.hasAttribute("src")){let f,S=new Promise(A=>{f=A});c.addEventListener("load",function(){f(void 0)}),m.push(S)}e.appendChild(c),n.callbacks.afterNodeAdded(c),r.push(c)}}for(let l of o)n.callbacks.beforeNodeRemoved(l)!==!1&&(e.removeChild(l),n.callbacks.afterNodeRemoved(l));return n.head.afterHeadMorphed(e,{added:r,kept:i,removed:o}),m}function H(){}function $n(t,e,n){return{target:t,newContent:e,config:n,morphStyle:n.morphStyle,ignoreActive:n.ignoreActive,idMap:Yn(t,e),deadIds:new Set,callbacks:Object.assign({beforeNodeAdded:H,afterNodeAdded:H,beforeNodeMorphed:H,afterNodeMorphed:H,beforeNodeRemoved:H,afterNodeRemoved:H},n.callbacks),head:Object.assign({style:"merge",shouldPreserve:r=>r.getAttribute("im-preserve")==="true",shouldReAppend:r=>r.getAttribute("im-re-append")==="true",shouldRemove:H,afterHeadMorphed:H},n.head)}}function hn(t,e,n){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===e.tagName?t?.id?.length&&t.id===e.id?!0:ie(n,t,e)>0:!1}function we(t,e){return!t||!e?!1:t.nodeType===e.nodeType&&t.tagName===e.tagName}function un(t,e,n){for(;t!==e;){let r=t;if(t=t?.nextSibling,!r)throw h;Sn(r,n)}return j(n,e),e.nextSibling}function Un(t,e,n,r,o){let i=ie(o,n,e),s=null;if(i>0){s=r;let a=0;for(;s!=null;){if(hn(n,s,o))return s;if(a+=ie(o,s,t),a>i)return null;s=s.nextSibling}}return s}function Wn(t,e,n,r){let o=n,i=e.nextSibling,s=0;for(;o&&i;){if(ie(r,o,t)>0)return null;if(we(e,o))return o;if(we(i,o)&&(s++,i=i.nextSibling,s>=2))return null;o=o.nextSibling}return o}var cn=new DOMParser;function jn(t){let e=t.replace(/]*>|>)([\s\S]*?)<\/svg>/gim,"");if(e.match(/<\/html>/)||e.match(/<\/head>/)||e.match(/<\/body>/)){let n=cn.parseFromString(t,"text/html");if(e.match(/<\/html>/))return Ae.add(n),n;{let r=n.firstChild;return r?(Ae.add(r),r):null}}else{let r=cn.parseFromString(``,"text/html").body.querySelector("template")?.content;if(!r)throw $;return Ae.add(r),r}}function Bn(t){if(t==null)return document.createElement("div");if(Ae.has(t))return t;if(t instanceof Node){let e=document.createElement("div");return e.append(t),e}else{let e=document.createElement("div");for(let n of[...t])e.append(n);return e}}function Gn(t,e,n){let r=[],o=[];for(;t;)r.push(t),t=t.previousSibling;for(;r.length>0;){let i=r.pop();o.push(i),e?.parentElement?.insertBefore(i,e)}for(o.push(e);n;)r.push(n),o.push(n),n=n.nextSibling;for(;r.length;)e?.parentElement?.insertBefore(r.pop(),e.nextSibling);return o}function Kn(t,e,n){let r=t.firstChild,o=r,i=0;for(;r;){let s=qn(r,e,n);s>i&&(o=r,i=s),r=r.nextSibling}return o}function qn(t,e,n){return we(t,e)?.5+ie(n,t,e):0}function Sn(t,e){j(e,t),e.callbacks.beforeNodeRemoved(t)!==!1&&(t.remove(),e.callbacks.afterNodeRemoved(t))}function Jn(t,e){return!t.deadIds.has(e)}function zn(t,e,n){return t.idMap.get(n)?.has(e)||!1}function j(t,e){let n=t.idMap.get(e);if(n)for(let r of n)t.deadIds.add(r)}function ie(t,e,n){let r=t.idMap.get(e);if(!r)return 0;let o=0;for(let i of r)Jn(t,i)&&zn(t,i,n)&&++o;return o}function fn(t,e){let n=t.parentElement,r=t.querySelectorAll("[id]");for(let o of r){let i=o;for(;i!==n&&i;){let s=e.get(i);s==null&&(s=new Set,e.set(i,s)),s.add(o.id),i=i.parentElement}}}function Yn(t,e){let n=new Map;return fn(t,n),fn(e,n),n}var bn={pluginType:"watcher",name:x.MergeFragments,onGlobalInit:async t=>{let e=document.createElement("template");k(x.MergeFragments,({fragments:n="
",selector:r="",mergeMode:o=Xe,settleDuration:i=`${300}`,useViewTransition:s=`${!1}`})=>{let a=parseInt(i),u=F(s);e.innerHTML=n.trim(),[...e.content.children].forEach(l=>{if(!(l instanceof Element))throw h;let c=r||`#${l.getAttribute("id")}`,S=[...document.querySelectorAll(c)||[]];if(!S.length)throw h;z&&u?oe.startViewTransition(()=>En(t,o,a,l,S)):En(t,o,a,l,S)})})}};function En(t,e,n,r,o){for(let i of o){i.classList.add(W);let s=i.outerHTML,a=i;switch(e){case M.Morph:let m=pn(a,r,{callbacks:{beforeNodeRemoved:(l,c)=>(t.cleanup(l),!0)}});if(!m?.length)throw h;a=m[0];break;case M.Inner:a.innerHTML=r.innerHTML;break;case M.Outer:a.replaceWith(r);break;case M.Prepend:a.prepend(r);break;case M.Append:a.append(r);break;case M.Before:a.before(r);break;case M.After:a.after(r);break;case M.UpsertAttributes:r.getAttributeNames().forEach(l=>{let c=r.getAttribute(l);a.setAttribute(l,c)});break;default:throw h}t.cleanup(a),a.classList.add(W),t.applyPlugins(document.body),setTimeout(()=>{i.classList.remove(W),a.classList.remove(W)},n);let u=a.outerHTML;s!==u&&(a.classList.add(ke),setTimeout(()=>{a.classList.remove(ke)},n))}}var yn={pluginType:"watcher",name:x.MergeSignals,onGlobalInit:async t=>{k(x.MergeSignals,({signals:e="{}",onlyIfMissing:n=`${!1}`})=>{let r=F(n),o=` return Object.assign({...ctx.store()}, ${e})`;try{let s=new Function("ctx",o)(t),a=se(t.store(),s,r);t.mergeSignals(a),t.applyPlugins(document.body)}catch(i){console.log(o),console.error(i);debugger}})}};var vn={pluginType:"watcher",name:x.RemoveFragments,onGlobalInit:async()=>{k(x.RemoveFragments,({selector:t,settleDuration:e=`${300}`,useViewTransition:n=`${!1}`})=>{if(!t.length)throw h;let r=parseInt(e),o=F(n),i=document.querySelectorAll(t),s=()=>{for(let a of i)a.classList.add(W);setTimeout(()=>{for(let a of i)a.remove()},r)};z&&o?oe.startViewTransition(()=>s()):s()})}};var Tn={pluginType:"watcher",name:x.RemoveSignals,onGlobalInit:async t=>{k(x.RemoveSignals,({paths:e=""})=>{let n=e.split(` +`).map(r=>r.trim());if(!n?.length)throw h;t.removeSignals(...n)})}};ft.load(kt,Vt,Mt,Nt,Wt,Ot,Ht,$t,Ut,Kt,on,sn,an,bt,yt,vt,Tt,At,_t,wt,Rt,xt,Pt,Dt,Lt,bn,yn,vn,Tn,ln);})(); //# sourceMappingURL=datastar.js.map diff --git a/bundles/datastar.js.map b/bundles/datastar.js.map index 74dc4ca94..714a00a2f 100644 --- a/bundles/datastar.js.map +++ b/bundles/datastar.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../code/ts/library/src/plugins/official/attributes/core/star.ts", "../code/ts/library/src/plugins/official/attributes/core/computed.ts", "../code/ts/library/src/utils/signals.ts", "../code/ts/library/src/plugins/official/attributes/core/store.ts", "../code/ts/library/src/utils/regex.ts", "../code/ts/library/src/plugins/official/preprocessors/core/actions.ts", "../code/ts/library/src/plugins/official/preprocessors/core/signals.ts", "../code/ts/library/src/engine/consts.ts", "../code/ts/library/src/engine/errors.ts", "../code/ts/library/src/utils/dom.ts", "../code/ts/library/src/vendored/preact-core.ts", "../code/ts/library/src/vendored/deepsignal.ts", "../code/ts/library/src/vendored/ts-merge-patch.ts", "../code/ts/library/src/engine/version.ts", "../code/ts/library/src/engine/engine.ts", "../code/ts/library/src/engine/index.ts", "../code/ts/library/src/vendored/fetch-event-source/parse.ts", "../code/ts/library/src/vendored/fetch-event-source/fetch.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseShared.ts", "../code/ts/library/src/plugins/official/actions/backend/sseShared.ts", "../code/ts/library/src/plugins/official/actions/backend/sseDelete.ts", "../code/ts/library/src/plugins/official/actions/backend/sseGet.ts", "../code/ts/library/src/plugins/official/actions/backend/ssePatch.ts", "../code/ts/library/src/plugins/official/actions/backend/ssePost.ts", "../code/ts/library/src/plugins/official/actions/backend/ssePut.ts", "../code/ts/library/src/plugins/official/actions/dom/clipboard.ts", "../code/ts/library/src/plugins/official/actions/logic/setAll.ts", "../code/ts/library/src/plugins/official/actions/logic/toggleAll.ts", "../code/ts/library/src/plugins/official/actions/math/clampFit.ts", "../code/ts/library/src/plugins/official/actions/math/clampFitInt.ts", "../code/ts/library/src/plugins/official/actions/math/fit.ts", "../code/ts/library/src/plugins/official/actions/math/fitInt.ts", "../code/ts/library/src/plugins/official/attributes/backend/indicator.ts", "../code/ts/library/src/utils/text.ts", "../code/ts/library/src/plugins/official/attributes/dom/bind.ts", "../code/ts/library/src/plugins/official/attributes/dom/class.ts", "../code/ts/library/src/plugins/official/attributes/dom/model.ts", "../code/ts/library/src/utils/arguments.ts", "../code/ts/library/src/utils/timing.ts", "../code/ts/library/src/plugins/official/attributes/dom/on.ts", "../code/ts/library/src/plugins/official/attributes/dom/ref.ts", "../code/ts/library/src/plugins/official/attributes/dom/text.ts", "../code/ts/library/src/plugins/official/attributes/storage/persist.ts", "../code/ts/library/src/plugins/official/attributes/url/replaceUrl.ts", "../code/ts/library/src/plugins/official/attributes/visibility/intersects.ts", "../code/ts/library/src/plugins/official/attributes/visibility/scrollIntoView.ts", "../code/ts/library/src/plugins/official/attributes/visibility/show.ts", "../code/ts/library/src/utils/view-transitions.ts", "../code/ts/library/src/plugins/official/attributes/visibility/viewTransition.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseExecuteScript.ts", "../code/ts/library/src/vendored/idiomorph.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseMergeFragment.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseMergeSignals.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseRemoveFragments.ts", "../code/ts/library/src/plugins/official/watchers/backend/sseRemoveSignals.ts", "../code/ts/library/src/bundles/datastar.ts"], - "sourcesContent": ["// Authors: Delaney Gillilan\n// Icon: material-symbols:rocket\n// Slug: Star\n// Description: Sage advice for the weary traveler\n\nimport { AttributePlugin } from \"../../../../engine\";\n\nexport const Star: AttributePlugin = {\n pluginType: \"attribute\",\n name: \"star\",\n onLoad: () => {\n alert(\"YOU ARE PROBABLY OVERCOMPLICATING IT\");\n },\n};\n", "// Authors: Delaney Gillilan\n// Icon: fluent:draw-text-24-filled\n// Slug: Create a computed signal\n// Description: This attribute creates a computed signal that updates when its dependencies change.\n\nimport { AttributePlugin } from \"../../../../engine\";\n\nexport const Computed: AttributePlugin = {\n pluginType: \"attribute\",\n name: \"computed\",\n mustNotEmptyKey: true,\n onLoad: (ctx) => {\n const store = ctx.store();\n store[ctx.key] = ctx.reactivity.computed(() => {\n return ctx.expressionFn(ctx);\n });\n\n return () => {\n const store = ctx.store();\n delete store[ctx.key];\n };\n },\n};\n", "export function remoteSignals(obj: Object): Object {\n const res: Record = {};\n\n for (const [k, v] of Object.entries(obj)) {\n if (k.startsWith(\"_\")) {\n continue;\n } else if (typeof v === \"object\" && !Array.isArray(v)) {\n res[k] = remoteSignals(v); // recurse\n } else {\n res[k] = v;\n }\n }\n\n return res;\n}\n\nexport function storeFromPossibleContents(\n currentStore: any,\n contents: any,\n hasIfMissing: boolean,\n) {\n const actual: any = {};\n\n if (!hasIfMissing) {\n Object.assign(actual, contents);\n } else {\n for (const key in contents) {\n const currentValue = currentStore[key]?.value;\n if (currentValue === undefined || currentValue === null) {\n actual[key] = contents[key];\n }\n }\n }\n\n return actual;\n}\n", "// Authors: Delaney Gillilan\n// Icon: material-symbols:home-storage\n// Slug: Store signals into a singleton per page\n// Description: This action stores signals into a singleton per page. This is useful for storing signals that are used across multiple components.\n\nimport {\n AttributeContext,\n AttributePlugin,\n RegexpGroups,\n} from \"../../../../engine\";\nimport { storeFromPossibleContents } from \"../../../../utils/signals\";\n\n// Setup the global store\nexport const Store: AttributePlugin = {\n pluginType: \"attribute\",\n name: \"store\",\n removeNewLines: true,\n preprocessors: {\n pre: [\n {\n pluginType: \"preprocessor\",\n name: \"store\",\n regexp: /(?.+)/g,\n replacer: (groups: RegexpGroups) => {\n const { whole } = groups;\n return `Object.assign({...ctx.store()}, ${whole})`;\n },\n },\n ],\n },\n allowedModifiers: new Set([\"ifmissing\"]),\n onLoad: (ctx: AttributeContext) => {\n const possibleMergeSignals = ctx.expressionFn(ctx);\n const actualMergeSignals = storeFromPossibleContents(\n ctx.store(),\n possibleMergeSignals,\n ctx.modifiers.has(\"ifmissing\"),\n );\n ctx.mergeSignals(actualMergeSignals);\n\n delete ctx.el.dataset[ctx.rawKey];\n },\n};\n", "export const validJSIdentifier = `[a-zA-Z_$]+`;\nexport const validNestedJSIdentifier = validJSIdentifier + `[0-9a-zA-Z_$.]*`;\n\nexport function wholePrefixSuffix(\n rune: string,\n prefix: string,\n suffix: string,\n nestable = true,\n) {\n const identifier = nestable ? validNestedJSIdentifier : validJSIdentifier;\n return new RegExp(\n `(?${rune}(?<${prefix}>${identifier})${suffix})`,\n `g`,\n );\n}\n", "import { PreprocessorPlugin, RegexpGroups } from \"../../../../engine\";\nimport { wholePrefixSuffix } from \"../../../../utils/regex\";\n\n// Replacing $action(args) with ctx.actions.action(ctx, args)\nexport const ActionsProcessor: PreprocessorPlugin = {\n name: \"action\",\n pluginType: \"preprocessor\",\n regexp: wholePrefixSuffix(\n \"\\\\$\",\n \"action\",\n \"(?\\\\((?.*)\\\\))\",\n false,\n ),\n replacer: ({ action, args }: RegexpGroups) => {\n const withCtx = [`ctx`];\n if (args) {\n withCtx.push(...args.split(\",\").map((x) => x.trim()));\n }\n const argsJoined = withCtx.join(\",\");\n return `ctx.actions.${action}.method(${argsJoined})`;\n },\n};\n", "import { PreprocessorPlugin, RegexpGroups } from \"../../../../engine\";\nimport { wholePrefixSuffix } from \"../../../../utils/regex\";\n\n// Replacing $signal with ctx.store.signal.value`\nexport const SignalsProcessor: PreprocessorPlugin = {\n name: \"signal\",\n pluginType: \"preprocessor\",\n regexp: wholePrefixSuffix(\"\\\\$\", \"signal\", \"(?\\\\([^\\\\)]*\\\\))?\"),\n replacer: (groups: RegexpGroups) => {\n const { signal, method } = groups;\n const prefix = `ctx.store()`;\n if (!method?.length) {\n return `${prefix}.${signal}.value`;\n }\n const parts = signal.split(\".\");\n const methodName = parts.pop();\n const nestedSignal = parts.join(\".\");\n return `${prefix}.${nestedSignal}.value.${methodName}${method}`;\n },\n};\n", "// This is auto-generated by Datastar. DO NOT EDIT.\n\nexport const DATASTAR = \"datastar\";\nexport const DATASTAR_EVENT = \"datastar-event\";\nexport const DATASTAR_REQUEST = \"Datastar-Request\";\nexport const VERSION = \"0.20.1\";\n\n// #region Defaults\n\n// #region Default durations\n\n// The default duration for settling during merges. Allows for CSS transitions to complete.\nexport const DefaultSettleDurationMs = 300;\n// The default duration for retrying SSE on connection reset. This is part of the underlying retry mechanism of SSE.\nexport const DefaultSseRetryDurationMs = 1000;\n\n// #endregion\n\n\n// #region Default strings\n\n// The default attributes for ` }} - @Page() { + @Page( + "A real-time hypermedia framework", + "Datastar helps you build real-time web applications with the simplicity of server-side rendering and the power of a full-stack SPA framework.", + ) {
@@ -150,7 +153,7 @@ templ TodosMVCView(mvc *TodoMVC) {

This mini application is driven by a diff --git a/code/go/site/routes_memes.templ b/code/go/site/routes_memes.templ index d5b1f292f..9b6db4969 100644 --- a/code/go/site/routes_memes.templ +++ b/code/go/site/routes_memes.templ @@ -3,7 +3,7 @@ package site import "net/http" templ PageMemes(r *http.Request, memes ...string) { - @Page() { + @Page("Hot fresh memes", "The most wasted of all days is one without laughter.") { @header(r)

Memes
diff --git a/code/go/site/routes_reference.go b/code/go/site/routes_reference.go index 126375df5..d270dc454 100644 --- a/code/go/site/routes_reference.go +++ b/code/go/site/routes_reference.go @@ -11,7 +11,7 @@ import ( ) func setupReferenceRoutes(ctx context.Context, router chi.Router) error { - mdElementRenderers, _, err := markdownRenders(ctx, "reference") + mdDataset, err := markdownRenders(ctx, "reference") if err != nil { return err } @@ -62,7 +62,7 @@ func setupReferenceRoutes(ctx context.Context, router chi.Router) error { essaysRouter.Get("/{name}", func(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "name") - contents, ok := mdElementRenderers[name] + mdData, ok := mdDataset[name] if !ok { http.Error(w, "not found", http.StatusNotFound) return @@ -78,7 +78,7 @@ func setupReferenceRoutes(ctx context.Context, router chi.Router) error { } } - SidebarPage(r, sidebarGroups, currentLink, contents).Render(r.Context(), w) + SidebarPage(r, sidebarGroups, currentLink, mdData.Title, mdData.Description, mdData.Contents).Render(r.Context(), w) }) }) diff --git a/code/go/site/shared.templ b/code/go/site/shared.templ index 3abca9a2f..92ca0a824 100644 --- a/code/go/site/shared.templ +++ b/code/go/site/shared.templ @@ -8,32 +8,33 @@ import ( "strings" ) -templ Page() { +templ Page(title, description string) { - Datastar – A real-time hypermedia framework + { title } + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + `, highlightCSSBuffer.String())) @@ -124,7 +132,7 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere mdDir := "static/md/" + staticMdPath docs, err := staticFS.ReadDir(mdDir) if err != nil { - return nil, nil, fmt.Errorf("error reading docs dir: %w", err) + return nil, fmt.Errorf("error reading docs dir: %w", err) } // regExpImg := regexp.MustCompile(`(?P!\[[^\]]+]\((?P[^)]+)\))`) @@ -133,14 +141,16 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere codeSnippets := regexp.MustCompile(`!!!CODE_SNIPPET:(?[^!]*)!!!`) // Icon or mascot from https://icones.js.org/collection/vscode-icons - mdElementRenderers = map[string]string{} - mdAnchors = map[string][]string{} + res := MarkdownDataset{} + + titleTrimmer := regexp.MustCompile(`^#+\s*`) + for _, de := range docs { fullPath := mdDir + "/" + de.Name() b, err := staticFS.ReadFile(fullPath) if err != nil { - return nil, nil, fmt.Errorf("error reading doc %s: %w", de.Name(), err) + return nil, fmt.Errorf("error reading doc %s: %w", de.Name(), err) } // Package version @@ -155,10 +165,10 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere baseDir := filepath.Dir(fullWithTestExtension) fileEntries, err := staticFS.ReadDir(baseDir) if err != nil { - return nil, nil, fmt.Errorf("error reading code snippet dir %s: %w", baseDir, err) + return nil, fmt.Errorf("error reading code snippet dir %s: %w", baseDir, err) } if len(fileEntries) == 0 { - return nil, nil, fmt.Errorf("no files found in code snippet dir %s", baseDir) + return nil, fmt.Errorf("no files found in code snippet dir %s", baseDir) } snippetBlock := CodeSnippetBlock{ @@ -178,7 +188,7 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere codeSnippetRaw, err := staticFS.ReadFile(fileFullPath) if err != nil { - return nil, nil, fmt.Errorf("error reading code snippet %s: %w", fileFullPath, err) + return nil, fmt.Errorf("error reading code snippet %s: %w", fileFullPath, err) } codeSnippet := string(codeSnippetRaw) @@ -186,7 +196,7 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere defer bytebufferpool.Put(buf) if err := htmlHighlight(buf, codeSnippet, ext, ""); err != nil { - return nil, nil, fmt.Errorf("error highlighting code snippet %s: %w", fileFullPath, err) + return nil, fmt.Errorf("error highlighting code snippet %s: %w", fileFullPath, err) } icon := "" @@ -220,11 +230,16 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere b = bytes.ReplaceAll(b, fullMatch, buf.Bytes()) } + title := "" + // Get all anchors anchors := []string{} lines := strings.Split(string(b), "\n") for _, line := range lines { if strings.HasPrefix(line, "#") { + if title == "" { + title = titleTrimmer.ReplaceAllString(line, "") + } parts := strings.Split(line, " ") anchor := strings.Join(parts[1:], " ") anchors = append(anchors, anchor) @@ -236,11 +251,16 @@ func markdownRenders(ctx context.Context, staticMdPath string) (mdElementRendere renderedHTML := string(markdown.Render(doc, mdRenderer())) name := de.Name()[0 : len(de.Name())-3] - mdElementRenderers[name] = renderedHTML - mdAnchors[name] = anchors + + res[name] = &MarkdownData{ + Anchors: anchors, + Title: title, + Description: "", + Contents: renderedHTML, + } } - return mdElementRenderers, mdAnchors, nil + return res, nil } func KVPairsAttrs(kvPairs ...string) templ.Attributes { diff --git a/code/go/site/smoketests/dialogs_browser_test.go b/code/go/site/smoketests/dialogs_browser_test.go index 2339874aa..9fa149457 100644 --- a/code/go/site/smoketests/dialogs_browser_test.go +++ b/code/go/site/smoketests/dialogs_browser_test.go @@ -2,7 +2,6 @@ package smoketests import ( "testing" - "time" "github.com/stretchr/testify/assert" ) @@ -20,13 +19,12 @@ func TestExampleDialogsBrowser(t *testing.T) { wait, handle := page.MustHandleDialog() go btn.MustClick() - // This is a workaround for the dialog not being available after wiat - time.Sleep(1 * time.Second) - wait() + page.MustWaitIdle() handle(true, "test") handle(true, "") + page.MustWaitIdle() confirmation := page.MustElement("#confirmation") confirmationText := confirmation.MustText() diff --git a/code/go/site/smoketests/lazy_tabs_test.go b/code/go/site/smoketests/lazy_tabs_test.go index 368572235..39cea2f97 100644 --- a/code/go/site/smoketests/lazy_tabs_test.go +++ b/code/go/site/smoketests/lazy_tabs_test.go @@ -7,6 +7,7 @@ import ( ) func TestExampleLazyTabs(t *testing.T) { + g := setup(t) page := g.page("examples/lazy_tabs") diff --git a/code/go/site/smoketests/setup_test.go b/code/go/site/smoketests/setup_test.go index 843106140..aa70e1c83 100644 --- a/code/go/site/smoketests/setup_test.go +++ b/code/go/site/smoketests/setup_test.go @@ -41,11 +41,11 @@ func TestMain(m *testing.M) { } var setup = func() func(t *testing.T) G { + browser := rod.New().MustConnect() return func(t *testing.T) G { - t.Parallel() // run each test concurrently - + // t.Parallel() // run each test concurrently return G{got.New(t), browser} } }() diff --git a/code/go/site/smoketests/sortable_test.go b/code/go/site/smoketests/sortable_test.go index 72a619dc6..691a12b7f 100644 --- a/code/go/site/smoketests/sortable_test.go +++ b/code/go/site/smoketests/sortable_test.go @@ -25,7 +25,7 @@ func TestExampleSortable(t *testing.T) { page.Mouse.MoveLinear(proto.NewPoint(760.5, 735.0), 1) page.Mouse.MustUp("left") - page.MustWaitStable() + page.MustWaitIdle() result := page.MustElement("#sortContainer").MustHTML() diff --git a/code/go/site/static/md/examples/animations.md b/code/go/site/static/md/examples/animations.md index a3752b1bd..1b479719d 100644 --- a/code/go/site/static/md/examples/animations.md +++ b/code/go/site/static/md/examples/animations.md @@ -67,13 +67,14 @@ Building on the last example, we can fade in the new content the same way, start One of the nice features for reactivity is to show a spinner when a request is in flight. On any element that is using backend actions you can add a `data-indicator` attribute to show a spinner when the request is in flight. This can be done like so: ```html +
Spinner
``` -This will show the element with the id `request_in_flight_indicator` when the request is in flight and hide it when the request is complete. +This will show the spinner element when the request is in flight and hide it when the request is complete. diff --git a/code/go/site/static/md/examples/bad_apple.md b/code/go/site/static/md/examples/bad_apple.md index ff9c47f57..53b8f21e9 100644 --- a/code/go/site/static/md/examples/bad_apple.md +++ b/code/go/site/static/md/examples/bad_apple.md @@ -5,7 +5,7 @@
@@ -38,7 +38,7 @@ We take the [already converted](https://github.com/trung-kieen/bad-apple-ascii) ```html
diff --git a/code/go/site/static/md/examples/classes.md b/code/go/site/static/md/examples/classes.md index c0d61ef47..4aaa33c37 100644 --- a/code/go/site/static/md/examples/classes.md +++ b/code/go/site/static/md/examples/classes.md @@ -3,7 +3,7 @@ ## Demo
@@ -17,7 +17,7 @@ ```html
diff --git a/code/go/site/static/md/examples/click_to_edit.md b/code/go/site/static/md/examples/click_to_edit.md index bc3ef566c..a46e7075a 100644 --- a/code/go/site/static/md/examples/click_to_edit.md +++ b/code/go/site/static/md/examples/click_to_edit.md @@ -38,7 +38,7 @@ This returns a form that can be used to edit the contact
+
Event count: EventCount
Last Event Details: EventTime
@@ -22,7 +22,7 @@ ## Explanation ```html -
+
Event count: EventCount
diff --git a/code/go/site/static/md/examples/debounce_and_throttle.md b/code/go/site/static/md/examples/debounce_and_throttle.md index 82fc6d110..1f4f2c83e 100644 --- a/code/go/site/static/md/examples/debounce_and_throttle.md +++ b/code/go/site/static/md/examples/debounce_and_throttle.md @@ -4,13 +4,13 @@ Debouncing and throttling are two techniques to limit the number of times a func ## Throttling -
+
Text
```html
@@ -21,12 +21,12 @@ In the example above, the `data-on-raf.throttle_500ms` directive ensures that th ### Debouncing - ```html diff --git a/code/go/site/static/md/examples/file_upload.md b/code/go/site/static/md/examples/file_upload.md index 179e5c963..70600fb19 100644 --- a/code/go/site/static/md/examples/file_upload.md +++ b/code/go/site/static/md/examples/file_upload.md @@ -18,7 +18,7 @@ In this example we show how to create a file upload form that will be submitted