@efflore/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
2 lines (1 loc) • 4.47 kB
JavaScript
const t=t=>e=>typeof e===t,e=t("string"),s=t("object"),r=t("function"),n=t=>null==t,a=t=>null!=t,o=t=>t.nodeType!==Node.COMMENT_NODE,c=t=>n(t)?[]:[t],i="warn",l="error",u=(t,e,s="debug")=>([l,i].includes(s)&&console[s](e,t),t);let h;const{enqueue:g,cleanup:d}=(()=>{const t=new Map,e=new Map;let s;const r=(t,e)=>{try{t()}catch(t){u(t,e,l)}},n=()=>{s=null,t.forEach(((t,e)=>t.forEach(((t,s)=>r(t(e),`Effect ${s} on ${e?.localName||"unknown"} failed`))))),t.clear(),e.forEach((t=>r(t,"Cleanup failed"))),e.clear()},a=t=>(e,r)=>{const a=!t.has(e);t.set(e,r),a&&(s&&cancelAnimationFrame(s),s=requestAnimationFrame(n))};return queueMicrotask(n),{enqueue:(e,s,r)=>{return a((n=e,t.has(n)||t.set(n,new Map),t.get(n)))(s,r);var n},cleanup:a(e)}})(),p=t=>{h&&t.add(h)},b=t=>t.forEach((t=>t())),f=(t,e)=>{const s=h;h=e;try{t()}catch(t){u(t,"Error during reactive computation",l)}finally{h=s}},m=t=>(t=>a(t)&&(s(t)||r(t)))(t)&&r(t["set"]),y=t=>{const e=new Set,s=()=>(p(e),t);return s.set=s=>{const n=t;t=r(s)&&s.length?s(t):s,Object.is(t,n)||b(e)},s},E=(t,e=!1)=>{const s=new Set;let r,a=!0;const o=()=>{a=!0,e&&b(s)};return()=>(p(s),e&&!a||f((()=>{r=t(),a=n(r)}),o),r)},v=t=>{const e=()=>f((()=>{const e=t(g);r(e)&&d(t,e)}),e);e()},w=(t,e,s,n=void 0)=>{const a=t.constructor.attributeMap[e];return r(a)?a(c(s),t,n)[0]:s},x="context-request";class C extends Event{context;callback;subscribe;constructor(t,e,s=!1){super(x,{bubbles:!0,composed:!0}),this.context=t,this.callback=e,this.subscribe=s}}const N=t=>async e=>{await e.host.constructor.registry.whenDefined(e.target.localName);for(const[s,n]of Object.entries(t))e.target.set(s,m(n)?n:r(n)?y(n):e.host.signal(n));return e},A=(t,e)=>s=>(s.target.addEventListener(t,e),s),M=(t,e)=>s=>(s.target.removeEventListener(t,e),s),S=(t,e=t)=>s=>(v((()=>{s.target.dispatchEvent(new CustomEvent(t,{detail:s.host.get(e),bubbles:!0}))})),s),k=t=>[a(t[0])],q=t=>t.map((t=>parseInt(t,10))).filter(Number.isFinite),O=t=>t.map(parseFloat).filter(Number.isFinite),$=t=>t,F=t=>{let e=[];try{e=t.map((t=>JSON.parse(t)))}catch(t){u(t,"Failed to parse JSON",l)}return e},L=(t,s,a,o,c,i)=>{const l=o();return r(s)||t.host.set(s,e(s)&&e(l)?w(t.host,s,l):l,!1),v((e=>{const u=o(),h=r(s)?s(u):t.host.get(s);Object.is(h,u)||e(t.target,a,i&&(t=>null===t)(h)?i:n(h)?c(l):c(h))})),t},T=t=>e=>L(e,t,"t",(()=>e.target.textContent||""),(t=>e=>()=>{Array.from(e.childNodes).filter(o).forEach((t=>t.remove())),e.append(document.createTextNode(t))})),j=(t,e=t)=>s=>L(s,e,`p-${String(t)}`,(()=>s.target[t]),(e=>s=>()=>s[t]=e)),P=(t,e=t)=>s=>L(s,e,`a-${t}`,(()=>s.target.getAttribute(t)),(e=>s=>()=>s.setAttribute(t,e)),(e=>()=>e.removeAttribute(t))),D=(t,e=t)=>s=>L(s,e,`a-${t}`,(()=>s.target.hasAttribute(t)),(e=>s=>()=>s.toggleAttribute(t,e))),J=(t,e=t)=>s=>L(s,e,`c-${t}`,(()=>s.target.classList.contains(t)),(e=>s=>()=>s.classList.toggle(t,e))),H=(t,e=t)=>s=>L(s,e,`s-${t}`,(()=>s.target.style.getPropertyValue(t)),(e=>s=>()=>s.style.setProperty(t,e)),(e=>()=>e.style.removeProperty(t)));class I extends HTMLElement{static registry=customElements;static attributeMap={};static consumedContexts;static providedContexts;static define(t){try{this.registry.get(t)||this.registry.define(t,this)}catch(e){u(t,e.message,l)}}#t=new Map;self=[{host:this,target:this}];root=this.shadowRoot||this;attributeChangedCallback(t,e,s){s!==e&&this.set(t,w(this,t,s,e))}connectedCallback(){(t=>{const e=t.constructor,s=e.consumedContexts||[];for(const e of s)t.set(String(e),void 0,!1);setTimeout((()=>{for(const e of s)t.dispatchEvent(new C(e,(s=>t.set(String(e),s))))}));const n=e.providedContexts||[];n.length&&t.addEventListener(x,(e=>{const{context:s,callback:a}=e;n.includes(s)&&r(a)&&(e.stopPropagation(),a(t.signal(String(s))))}))})(this)}disconnectedCallback(){}has(t){return this.#t.has(t)}get(t){const e=t=>r(t)?e(t()):t;return e(this.#t.get(t))}set(t,e,s=!0){if(this.#t.has(t)){if(s){const s=this.#t.get(t);m(s)&&s.set(e)}}else this.#t.set(t,m(e)?e:y(e))}delete(t){return this.#t.delete(t)}signal(t){return this.#t.get(t)}first(t){return c(this.root.querySelector(t)).map((t=>({host:this,target:t})))}all(t){return Array.from(this.root.querySelectorAll(t)).map((t=>({host:this,target:t})))}}export{I as UIElement,k as asBoolean,q as asInteger,F as asJSON,O as asNumber,$ as asString,E as derive,v as effect,S as emit,u as log,c as maybe,M as off,A as on,N as pass,P as setAttribute,j as setProperty,H as setStyle,T as setText,D as toggleAttribute,J as toggleClass};