UNPKG

@mr_hugo/boredom

Version:

Another boring JavaScript framework.

4 lines (2 loc) 8.63 kB
var M=async t=>{let e=new Map;for(let n=0;n<t.length;++n){let r=A(`script[src*="${t[n]}"]`)?.getAttribute("src"),i=null;if(r)try{let o=await import(r);for(let s of Object.keys(o)){i=o[s];break}e.set(t[n],i)}catch(o){console.error(`Unable to import "${r}"`,o)}}return e},k=()=>Array.from(D("template[data-component]")).filter(t=>t instanceof HTMLElement).map(t=>{let e={name:"",attributes:[]};for(let n in t.dataset)n==="component"?e.name=t.dataset[n]??"":e.attributes.push([F(n),t.dataset[n]??""]);if(e.name==="")throw new Error(`A <template> was found with an invalid data-component: "${t.dataset.component}"`);return e}).map(({name:t,attributes:e})=>(Q(t,{attributes:e}),t)),w=(t,e)=>{let n=f(t);if(!O(n)){let r=`The tag name "${t}" is not a BoreDOM component. "createComponent" only accepts tag-names with matching <template> tags that have a data-component attribute in them.`;throw console.error(r),new Error(r)}return e&&(n.renderCallback=e),n},y=t=>{let e=A(t);if(!(e===null||!O(e)))return e},A=t=>document.querySelector(t),D=t=>document.querySelectorAll(t),f=(t,e)=>{let n=document.createElement(t);return e&&Array.isArray(e)&&e.length>0&&e.map(r=>n.appendChild(r)),n};var I=(t,e)=>{document.readyState==="loading"?addEventListener("DOMContentLoaded",()=>dispatchEvent(new CustomEvent(t,{detail:e}))):dispatchEvent(new CustomEvent(t,{detail:e}))};var H=t=>typeof t=="object",v=t=>typeof t=="function",O=t=>H(t)&&"isBored"in t&&!!t.isBored;var F=t=>{if(t===""||!t.split("").some(n=>n!==n.toLowerCase()))return t;let e="";for(let n=0;n<t.length;n++){let r=t[n];r===r.toUpperCase()&&n!==0&&(e+="-"),e+=r.toLowerCase()}return e};var C=t=>t.startsWith("on"),z=t=>t.startsWith("queriedOn"),S=t=>C(t)?t.slice(2).toLowerCase():t.slice(9).toLowerCase(),E=class extends HTMLElement{},Q=(t,e={})=>{customElements.get(t)||customElements.define(t,class extends E{static get observedAttributes(){return typeof e.attributeChangedCallback=="object"?Object.keys(e.attributeChangedCallback):[]}constructor(){super()}isBored=!0;traverse(n,{traverseShadowRoot:r,query:i}={}){Array.from(r?this.shadowRoot?.querySelectorAll(i??"*")??[]:[]).concat(Array.from(this.querySelectorAll(i??"*"))).filter(o=>o instanceof HTMLElement).forEach(n)}#t(n){return n.split("'").filter(r=>r.length>2&&!(r.includes("(")||r.includes(",")||r.includes(")")))}#e(){let n;this.traverse(r=>{if(r instanceof HTMLElement){customElements.get(r.tagName.toLowerCase())&&(n=r);for(let o=0;o<r.attributes.length;o++){let s=r.attributes[o];if(C(s.name)){let a=this.#t(s.value);a.length>0&&a.forEach(c=>{r.addEventListener(S(s.name),l=>I(c,{event:l,dispatcher:r,component:this,index:this.parentElement?Array.from(this.parentElement.children).indexOf(this):-1}))}),r.setAttribute(`data-${s.name}-dispatches`,a.join()),r.removeAttribute(s.name)}}}},{traverseShadowRoot:!0})}isInitialized=!1;#n(){let n=A(`[data-component="${t}"]`)??f("template"),r=n.getAttribute("shadowrootmode");if(e.style||e.shadow||r){let o=e.shadowrootmode??r??"open",s=this.attachShadow({mode:o});if(e.style){let a=f("style");a.textContent=e.style,s.appendChild(a)}if(e.shadow){let a=f("template");a.innerHTML=e.shadow,s.appendChild(a.content.cloneNode(!0))}else r&&s.appendChild(n.content.cloneNode(!0))}n&&!r&&this.appendChild(n.content.cloneNode(!0)),e.onSlotChange&&this.traverse(o=>{o instanceof HTMLSlotElement&&o.addEventListener("slotchange",s=>e.onSlotChange?.(s))},{traverseShadowRoot:!0}),v(e.onClick)&&this.addEventListener("click",e.onClick);for(let[o,s]of Object.entries(e))if(C(o)){if(!v(s))continue;this.addEventListener(S(o),s)}else if(z(o)){let a=s;if(!H(a))continue;let c=S(o);for(let[l,d]of Object.entries(a))this.traverse(u=>{u.addEventListener(c,d)},{traverseShadowRoot:!0,query:l})}e.attributes&&Array.isArray(e.attributes)&&e.attributes.map(([o,s])=>this.setAttribute(o,s)),this.#e(),this.isInitialized=!0}renderCallback=n=>{};connectedCallback(){this.isInitialized||this.#n(),this.renderCallback(this),e.connectedCallback?.(this)}slots=b(this);updateSlot(n,r,i){document.createElement(i).setAttribute("slot",n)}disconnectedCallback(){console.log("disconnected "+this.tagName),e.disconnectedCallback?.(this)}adoptedCallback(){console.log("adopted "+this.tagName),e.adoptedCallback?.(this)}attributeChangedCallback(n,r,i){e.attributeChangedCallback&&e.attributeChangedCallback[n]({element:this,name:n,oldValue:r,newValue:i})}})};function j(t,e){let n=e;return e===null||t.forEach(r=>{n=n[r]}),n}function R(t,e=[]){let n=[{path:[],obj:t}],r=[];for(;n.length>0;){let{path:i,obj:o}=n.pop();for(let s in o){if(e.includes(s))continue;let a=o[s],c=i.concat(s);typeof a=="object"&&a!==null&&n.push({path:c,obj:a}),r.push({path:c,value:a})}}return r}function x(t){if(t==null||typeof t!="object")return!1;let e=Object.getPrototypeOf(t);return e==null?!0:e===Object.prototype}function $(t,e,n){return(r,i)=>{addEventListener(r,o=>{let s=o?.detail?.event.currentTarget,a;for(;s;){if(s===t){i({state:e,e:o.detail,detail:n});return}s instanceof HTMLElement?s=s.parentElement:s=void 0}})}}function W(t){return new Proxy({},{get(e,n,r){let i=new Error(`Ref "${String(n)}" not found in <${t.tagName}>`);if(typeof n=="string"){let o=t.querySelectorAll(`[data-ref="${n}"]`);if(!o)throw i;let s=Array.from(o).filter(a=>a instanceof HTMLElement);if(s.length===0)throw i;return s.length===1?s[0]:s}}})}function b(t){return new Proxy({},{get(e,n,r){let i=new Error(`Slot "${String(n)}" not found in <${t.tagName}>`);if(typeof n=="string"){let o=t.querySelectorAll(`slot[name="${n}"]`);if(!o)throw i;let s=Array.from(o).filter(a=>a instanceof HTMLSlotElement);if(s.length===0)throw i;return s.length===1?s[0]:s}},set(e,n,r){if(typeof n!="string")return!1;let i=r;if(r instanceof HTMLElement)r.setAttribute("data-slot",n);else if(typeof r=="string")i=f("span"),i.setAttribute("data-slot",n),i.innerText=r;else throw new Error(`Invalid value for slot ${n} in <${t.tagName}>`);let o=Array.from(t.querySelectorAll(`[data-slot="${n}"]`));return o.length>0?o.forEach(s=>s.parentElement?.replaceChild(i,s)):Array.from(t.querySelectorAll(`slot[name="${n}"]`)).forEach(a=>a.parentElement?.replaceChild(i,a)),!0}})}function L(t,e,n){let r=n||{targets:new WeakMap,path:[]};if(t!==void 0)return new Proxy(t,{set(i,o,s){return typeof o=="string"&&console.error(`State is read-only for web components. Unable to set '${o}'.`),!1},get(i,o,s){let a=Reflect.get(i,o,s),c=o==="__proto__";if(typeof o=="string"&&!c&&(r.targets.has(i)||(r.targets.set(i,r.path.join(".")),r.path.push(o))),c||Array.isArray(a)||x(a))return L(a,e,r);let l=r.targets.get(i)??"";return typeof l=="string"&&typeof o=="string"&&(Array.isArray(i)||(l+=l!==""?`.${o}`:o),e.indexOf(l)===-1&&e.push(l)),r.path.length=0,r.path.push(l),a}})}function U(t){return()=>{let e=t.internal.updates;for(let n=0;n<e.path.length;n++){let r=e.path[n],i=e.subscribers.get(r.slice(r.indexOf(".")+1))??[];for(let o=0;o<i.length;o++)i[o](t.app)}e.path=[],e.value=[],e.raf=void 0}}function B(t){let e=t.internal,n=t;if(n===void 0)return t;let r=new WeakSet;return R(t,["internal"]).forEach(({path:i,value:o})=>{if(Array.isArray(o)||x(o)&&!r.has(o)){let a=i.join("."),c=j(i.slice(0,-1),n);if(c===o)return;c[i.at(-1)]=new Proxy(o,{set(d,u,p){return!(d[u]!==p)||(Reflect.set(d,u,p),typeof u!="string")||(Array.isArray(o)?e.updates.path.push(`${a}`):e.updates.path.push(`${a}.${u}`),e.updates.value.push(d),e.updates.raf||(e.updates.raf=requestAnimationFrame(U(t)))),!0}}),r.add(o)}}),t}function N(t){let e=t.internal.customTags.filter(r=>y(r)!==void 0),n=t.internal.components;for(let[r,i]of n.entries()){if(i===null||!e.includes(r))continue;let o=y(r);if(!o){console.log(`<${r}> is not yet in the DOM. The associated JS script will be called when the component is connected.`);return}i(t,{index:0,name:r,data:void 0})(o)}}function q(t,e,n){let r=e.internal.components.get(t);if(r){let i={...n,tagName:t};return w(t,r(e,i))}return w(t)}async function lt(t,e){let n=k(),r=await M(n);if(e)for(let s of Object.keys(e))r.set(s,e[s]);let o=B({app:t,internal:{customTags:n,components:r,updates:{path:[],value:[],raf:void 0,subscribers:new Map}}});if(N(o),!o.app)throw new Error("Unable to proxify state object.");return o.app}function dt(t){let e=null,n;return(r,i)=>o=>{let{internal:s,app:a}=r,c=[],l=L(a,c),d=W(o),u=b(o),p=$(o,a,i);if(e!==o){let T=async()=>{let h=s.updates.subscribers;for(let g of c){let m=h.get(g);m?m.includes(n)||m.push(n):h.set(g,[n])}},P=t({detail:i,state:l,refs:d,on:p,self:o});n=h=>{P({state:h,refs:d,slots:u,self:o,detail:i,makeComponent:(g,m)=>q(g,r,m?.detail)}),T()}}n(l),e=o}}export{lt as inflictBoreDOM,y as queryComponent,dt as webComponent};