UNPKG

@aegisjsproject/state

Version:
3 lines (2 loc) 9.63 kB
const e=new Map,t=new BroadcastChannel("aegis:state_sync"),n=crypto.randomUUID(),a=Symbol("proxy"),r=Symbol("aegis:state:update");let s=!0;const o=new EventTarget,i="aegisStateKey",c="aegisStateAttr",l="aegisStateStyle",f="aegisStateProperty",u="data-aegis-state-key",d="data-aegis-state-attr",m="data-aegis-state-property",y="data-aegis-state-style",g="change",p="beforechange",h=(e,t=null)=>history.state?.[e]??t;function b(e,t=document.documentElement){const n=t.querySelectorAll(e);return t.matches instanceof Function&&t.matches(e)?[t,...n]:Array.from(n)}async function E({state:e=history.state??{}}={}){const t=this.dataset.aegisStateKey,n=e?.[t];if(await(scheduler?.yield()),"string"==typeof this.dataset[c]){const e=this.dataset[c],t=this.getAttribute(e);"string"==typeof t&&t.startsWith("blob:")&&URL.revokeObjectURL(t),"boolean"==typeof n?this.toggleAttribute(e,n):null==n?this.removeAttribute(e):n instanceof Blob?this.setAttribute(e,URL.createObjectURL(n)):this.setAttribute(e,n)}else"string"==typeof this.dataset[f]&&"innerHTML"!==this.dataset[f]?this[this.dataset[f]]=n:"string"==typeof this.dataset[l]?null==n||!1===n?this.style.removeProperty(this.dataset[l]):this.style.setProperty(this.dataset[l],n):this instanceof HTMLInputElement||this instanceof HTMLSelectElement||this instanceof HTMLTextAreaElement?this.value=n:this.textContent=n}const v=new MutationObserver((e=>{e.forEach((e=>{switch(e.type){case"childList":e.addedNodes.forEach((e=>{e.nodeType===Node.ELEMENT_NODE&&b(`[${u}]`,e.target).forEach((e=>{e[r]=E.bind(e),L(e[r],e.dataset[i])}))})),e.removedNodes.forEach((e=>{e.nodeType===Node.ELEMENT_NODE&&b(`[${u}]`,e.target).forEach((e=>{P(e[r]),delete e[r]}))}));break;case"attributes":"string"==typeof e.oldValue?(P(e.target[r]),delete e.target[r]):"string"==typeof e.target.dataset[i]&&(e.target[r]=E.bind(e.target),L(e.target[r],e.target.dataset[i]))}}))}));function S(e,t,a={}){return{sender:n,type:e,state:M(),msgId:crypto.randomUUID(),recipient:t,location:location.href,timestamp:Date.now(),...a}}function w(e=M(),t=location.href){const n=T(e);return 0!==n.length&&(history.replaceState(e,"",t),O(n),!0)}function A(){s&&(t.close(),s=!1)}function T(e,t=M()){if(t!==e){const n=Object.keys(t),a=Object.keys(e),r=a.filter((e=>!n.includes(e))),s=n.filter((e=>!a.includes(e))),o=n.filter((n=>n in e&&n in t&&e[n]!==t[n]));return Object.freeze([...r,...o,...s])}return[]}async function O(t){if(Array.isArray(t)&&0!==t.length){const n=M(),a=Object.fromEntries(t.map((e=>[e,n[e]])));await Promise.allSettled(Array.from(e.entries(),(([e,n])=>{(0===n.length||n.some((e=>t.includes(e))))&&e({diff:t,state:a})})))}}function L(t,...n){return t instanceof Function&&!e.has(t)&&(e.set(t,n),!0)}function k(e,t=null){return new Proxy({toString:()=>h(e,t)?.toString()??"",valueOf(){const n=h(e,t);return n?.valueOf instanceof Function?n.valueOf():n},toJSON:()=>h(e,t),[Symbol.toPrimitive](n){const a=h(e,t);return typeof a===n||"default"===n&&"object"!=typeof a?a:a?.[Symbol.toPrimitive]instanceof Function?a?.[Symbol.toPrimitive]instanceof Function?a[Symbol.toPrimitive](n):a:"number"!==n&&a?.toString instanceof Function?a.toString():"number"===n?parseFloat(a):a},[a]:!0,[Symbol.toStringTag]:"StateValue",[Symbol.iterator]:()=>h(e,t)?.[Symbol.iterator]()},{defineProperty(n,a,r){const s=h(e,t);return!!Reflect.defineProperty(s,a,r)&&(x(e,s),s)},deleteProperty:(n,a)=>Reflect.deleteProperty(h(e,t),a),get(n,a){const r=h(e,t);if(a in n)return n[a];if("object"==typeof r){const e=Reflect.get(r,a,r);return e instanceof Function?e.bind(r):e}return r[a]},getOwnPropertyDescriptor:(n,a)=>Reflect.getOwnPropertyDescriptor(h(e,t),a),getPrototypeOf(){const n=h(e,t);return"object"==typeof n?Reflect.getPrototypeOf(n):Object.getPrototypeOf(n)},has:(n,a)=>Reflect.has(h(e,t),a),isExtensible:()=>Reflect.isExtensible(h(e,t)),ownKeys:()=>Reflect.ownKeys(h(e,t)),preventExtensions:()=>Reflect.preventExtensions(h(e,t)),set(n,a,r){const s=h(e,t);return!!Reflect.set(s,a,r,s)&&(x(e,s),!0)}})}const P=t=>e.delete(t),M=()=>Object.freeze(null===history.state?{}:structuredClone(history.state)),R=e=>e in M();function x(e,t){const n=M();if("string"!=typeof e||0===e.length)throw new TypeError("Invalid key.");if("function"==typeof t)N(e,t);else if(n[e]!==t){const r={key:e,oldValue:n[e],newValue:t},s=new CustomEvent(p,{cancelable:!0,detail:r});o.dispatchEvent(s),s.defaultPrevented||(U({...M(),[e]:t?.[a]?t.valueOf():t},location.href),o.dispatchEvent(new CustomEvent(g,{detail:r})))}}const N=async(e,t)=>await Promise.try((()=>t(h(e),e))).then((t=>(x(e,t),t)));function j(e,t=null){return[k(e,t),t=>x(e,t)]}function F(e){const t={...M()};delete t[e],U(t,location.href)}const H=(e="aegis:state")=>localStorage.setItem(e,JSON.stringify(M())),I=(e="aegis:state")=>w(JSON.parse(localStorage.getItem(e)),location.href),D=()=>U({},location.href);function U(e=M(),n=location.href){w(e,n)&&s&&t.postMessage(S("update"))}function C({signal:e}={}){t.addEventListener("message",(e=>{if(e.isTrusted&&"string"==typeof e.data.msgId&&"string"==typeof e.data.sender&&e.data.sender!==n&&"object"==typeof e.data.state&&("string"!=typeof e.data.recipient||e.data.recipient===n)){const n=M();if(0!==T(e.data.state,n).length)switch(e.data.type){case"update":w({...n,...e.data.state},location.href);break;case"sync":s&&t.postMessage(S("update",e.data.sender));break;case"clear":w({},location.href);break;default:reportError(new Error(`Unhandled broadcast channel message type: ${e.data.type}`))}}}),{signal:e}),t.postMessage(S("sync")),e instanceof AbortSignal&&e.aborted?A():e instanceof AbortSignal&&e.addEventListener("abort",A,{once:!0})}function q(e=document.documentElement,{signal:t,base:n=document.documentElement}={}){if(t instanceof AbortSignal&&t.aborted)throw t.reason;if("string"==typeof e)q(n.querySelector(e),{signal:t});else{if(!(e instanceof Element||e instanceof ShadowRoot))throw new TypeError("Target must be an element, selector, or shadow root.");v.observe(e,{childList:!0,subtree:!0,attributeFilter:[u],attributeOldValue:!0}),b(`[${u}]`,e).forEach((e=>{e[r]=E.bind(e),L(e[r],e.dataset[i]),e[r]({state:history.state})})),t instanceof AbortSignal&&t.addEventListener("abort",(()=>v.disconnect()),{once:!0})}}function $(e,t,{attr:n,style:a,base:r=document.body}={}){if("string"==typeof e)$(r.querySelector(e),t,{attr:n,style:a});else{if(!(e instanceof Element))throw new TypeError("Target must be an element or selector.");e instanceof HTMLElement?(e.dataset[i]=t,"string"==typeof n?e.dataset[c]=n:"string"==typeof a&&(e.dataset[l]=a),requestAnimationFrame((()=>E.call(e,{state:history.state??{}})))):e instanceof Element&&(e.setAttribute(u,t),"string"==typeof n?e.setAttribute(d,n):"string"==typeof a&&e.setAttribute(y,a),requestAnimationFrame((()=>E.call(e,{state:history.state??{}}))))}}function V(e,t,n,{base:a=document.documentElement,signal:r}={}){if(r instanceof AbortSignal&&r.aborted)throw r.reason;if("string"==typeof e)return V(a.querySelector(e),t,n,{});if(e instanceof Element){if("string"!=typeof t||0===t.length)throw new TypeError("State key must be a non-empty string.");if(n instanceof Function){const a=function({state:e={}}={}){return n.call(this,e[t],this)}.bind(e);return L(a,t),r instanceof AbortSignal&&r.addEventListener("abort",(()=>P(a)),{once:!0}),a}throw new TypeError("Callback must be a function.")}throw new TypeError("Target must be an element or selector.")}function K({target:e,currentTarget:t,type:n}){if(!(e instanceof HTMLElement))throw new TypeError(`Event ${n} target must be an HTMLElement.`);if(e.isContentEditable&&"string"==typeof e.dataset.name&&0!==e.dataset.name.length)x(e.dataset.name,e.textContent);else if("string"!=typeof e.name||0===e.name.length)e.isSameNode(t)&&e.removeEventListener(n,K);else if(e instanceof HTMLSelectElement)x(e.name,e.multiple?Array.from(e.selectedOptions,(e=>e.value)):e.value);else if(e instanceof HTMLInputElement)switch(e.type){case"checkbox":{const t=Array.from(e.form?.elements??[e]).filter((t=>t.name===e.name&&"checkbox"===t.type));1===t.length?x(e.name,"on"===e.value?e.checked:e.value):x(e.name,Array.from(t).filter((e=>e.checked)).map((e=>e.value)))}break;case"radio":x(e.name,Array.from(e.form?.elements??[e]).filter((t=>t.name===e.name&&t.checked)).find((e=>e.value))?.value);break;case"number":case"range":x(e.name,e.valueAsNumber);break;case"date":x(e.name,e.valueAsDate?.toISOString()?.split("T")?.at(0));break;case"file":x(e.name,e.multiple?Array.from(e.files):e.files.item(0));break;case"datetime-local":x(e.name,e.valueAsDate);break;default:x(e.name,e.value)}else if(e instanceof HTMLTextAreaElement)x(e.name,e.value);else{if(!e.constructor.formAssociated)throw new TypeError(`Event ${n} target is not a valid form element.`);x(e.name,e.value)}}function J(e,{signal:t,once:n=!1,passive:a=!1}={}){o.addEventListener(g,e,{signal:t,once:n,passive:a})}function _(e,{signal:t,once:n=!1,passive:a=!1}={}){o.addEventListener(p,e,{signal:t,once:n,passive:a})}export{o as EVENT_TARGET,p as beforeChangeEvent,$ as bindState,g as changeEvent,K as changeHandler,D as clearState,A as closeChannel,V as createStateHandler,F as deleteState,T as diffState,k as getState,M as getStateObj,R as hasState,j as manageState,O as notifyStateChange,q as observeDOMState,L as observeStateChanges,_ as onBeforeStateChange,J as onStateChange,U as replaceState,I as restoreState,H as saveState,x as setState,c as stateAttr,d as stateAttrAttribute,i as stateKey,u as stateKeyAttribute,f as stateProperty,m as statePropertyAttr,l as stateStyle,y as stateStyleAttribute,P as unobserveStateChanges,N as updateState,C as watchState}; //# sourceMappingURL=state.mjs.map