@pivanov/utils
Version:
A collection of personal utilities to live a happier life
8 lines (7 loc) • 12.4 kB
JavaScript
/*!
* @pivanov/utils v0.0.2
* (c) 2024-present Pavel Ivanov
* Released under the MIT License.
* https://github.com/pivanov/utils
*/
;var e=require("react"),t=require("react/jsx-runtime"),r=require("react-dom/client");const n=e=>{if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t},o=(e,...t)=>{if(!t.length)return e;const r=t.shift();if(void 0===r)return e;if(n(e)&&n(r))for(const t of Object.keys(r)){const s=r[t];if(n(s)){e[t]||Object.assign(e,{[t]:{}});const r=e[t];n(r)&&o(r,s)}else Object.assign(e,{[t]:s})}return o(e,...t)},s=(e,t)=>"bigint"==typeof t?t.toString():t,i=e=>`${((e,t="🚀")=>{let r=0;const n=e+t;for(let e=0;e<n.length;e++)r=(r<<5)-r+n.charCodeAt(e),r|=0;return(r>>>0).toString(16)})(e)}::${e}`,a=(e,t)=>{if(!e)return;const r=i(e);window.dispatchEvent(new CustomEvent(r,{detail:t,bubbles:!0,cancelable:!1}))},c=(e,t)=>{if(!e||"function"!=typeof t)return()=>{};const r=(e=>t=>{if(t instanceof CustomEvent)try{e(t.detail)}catch(e){console.error("Event listener error:",e)}})(t),n=i(e);return window.addEventListener(n,r),()=>window.removeEventListener(n,r)},l=(e,n,o={},s)=>{const i=class extends HTMLElement{constructor(){super();let e=Array.from(document.styleSheets).find((e=>e instanceof CSSStyleSheet&&!e.disabled));if(!e){const t=document.createElement("style");document.head.appendChild(t),e=t.sheet}Array.from(e.cssRules).find((e=>e.selectorText===`${this.tagName.toLowerCase()}`))||e.insertRule(`${this.tagName.toLowerCase()} { display: inline-flex; }`,e.cssRules.length);const t=o.shadow||(s?.length?"open":"closed");if(!o.shadow&&s?.length&&console.info("@@@ Styles are provided but shadowDOM is not enabled"),this.container=t?this.attachShadow({mode:t}):this,s&&t){const e=document.createElement("style");e.textContent=s.join("\n"),this.container.appendChild(e)}}connectedCallback(){this.root||(this.root=r.createRoot(this.container),this.subscribeToEvents())}disconnectedCallback(){this.root&&this.root.unmount()}subscribeToEvents(){c("@@-widget-create",(e=>{const{widgetProps:t,cacheKey:r}=e;this.cacheKey||r!==`${this.tagName.toLowerCase().replace("widget-","")}-${this.uuid}`||(this.cacheKey=r,this.mountComponent(t))})),c("@@-widget-update",(e=>{const{widgetProps:t,cacheKey:r}=e;this.cacheKey===r&&r===`${this.tagName.toLowerCase().replace("widget-","")}-${this.uuid}`&&a("@@-widget-update-props",{widgetProps:t,uuid:this.uuid})}))}mountComponent(e){this.root&&e&&this.root.render(t.jsx(n,{...e,container:this.container,root:this}))}};return customElements.get(e)||customElements.define(e,i),i},f=e.memo((r=>{const{name:n,uuid:o}=r,s=e.useRef(),i=`widget-${n}`;return e.useEffect((()=>{s.current&&(s.current.uuid=o)}),[o]),"string"==typeof o&&o.length?t.jsx(i,{ref:s}):null}),(()=>!0)),u=r=>{const{name:n,uuid:o,widgetProps:s}=r,i=e.useRef(!1),l=o?.trim()||crypto.randomUUID().replace(/-/g,"").slice(0,6),u=n.trim().toLowerCase(),p=`${u}-${l}`,d=!!u.length&&!!l.length;return e.useEffect((()=>{d&&i.current&&a("@@-widget-update",{widgetName:u,widgetProps:s,cacheKey:p})}),[s,l,u,d,p]),c("@@-widgets-loaded",(()=>{i.current=!0,a("@@-widget-create",{widgetName:u,widgetProps:s,cacheKey:p})})),d?t.jsx(f,{name:u,uuid:l}):(console.warn("Invalid widget!",u),null)},p=t=>{const{root:r,container:n,svgSpritePath:o,children:s}=t,[i,a]=e.useState(!1),[l,f]=e.useState();return e.useEffect((()=>{o?(async e=>{try{const t=await fetch(`${e}`);if(!t.ok)throw new Error(`Failed to fetch SVG: ${t.statusText}`);const r=await t.text(),n=(new DOMParser).parseFromString(r,"image/svg+xml");if(n.querySelector("parsererror"))throw new Error("SVG parsing failed");const o=n.documentElement;return o.setAttribute("xmlns","http://www.w3.org/2000/svg"),o.removeAttribute("id"),o}catch(e){return console.error("Error generating SVG sprite:",e),null}})(o).then((async e=>{n&&e&&n.appendChild(e),a(!0)})):a(!0)}),[]),c("@@-widget-update-props",(e=>{const{widgetProps:t,uuid:n}=e;r.uuid===n&&f(t)})),i?e.cloneElement(s,{...l,key:performance.now()}):null},d=(e,t)=>{if(null===e||"object"!=typeof e)return e;const r=t.get(e);if(r)return r;if(Array.isArray(e)){const r=e.length;if(r<32){const n=new Array(r);t.set(e,n);for(let o=0;o<r;o++)o in e&&(n[o]=d(e[o],t));return n}const n=new Array(r);if(t.set(e,n),Object.keys(e).length===r){let o=0;const s=r-r%8;for(;o<s;)n[o]=d(e[o],t),n[o+1]=d(e[o+1],t),n[o+2]=d(e[o+2],t),n[o+3]=d(e[o+3],t),n[o+4]=d(e[o+4],t),n[o+5]=d(e[o+5],t),n[o+6]=d(e[o+6],t),n[o+7]=d(e[o+7],t),o+=8;for(;o<r;)n[o]=d(e[o],t),o++}else for(let o=0;o<r;o++)o in e&&(n[o]=d(e[o],t));return n}if(e instanceof Date||e instanceof RegExp){return new(0,e.constructor)(e)}if("undefined"!=typeof Buffer)try{if(Buffer.isBuffer(e))return Buffer.from(e)}catch(e){if(e instanceof Error)throw e}if(ArrayBuffer.isView(e)){const t=e.constructor;if("buffer"in e){const r=e;return new t(r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength))}return new t(new ArrayBuffer(e.byteLength))}if(e instanceof ArrayBuffer)return e.slice(0);if(e&&"object"==typeof e&&"buffer"in e&&"byteLength"in e){const t=e;if("undefined"==typeof Buffer){const e=new Uint8Array(t.buffer,t.byteOffset||0,t.byteLength),r=new Uint8Array(e.length);return r.set(e),r}return{buffer:t.buffer instanceof ArrayBuffer?t.buffer.slice(0):new ArrayBuffer(t.byteLength),byteLength:t.byteLength,byteOffset:t.byteOffset||0,length:t.length||t.byteLength,BYTES_PER_ELEMENT:t.BYTES_PER_ELEMENT||1}}if(e instanceof Set){const r=new Set;t.set(e,r);const n=Array.from(e),o=n.length;for(let e=0;e<o;e++)r.add(d(n[e],t));return r}if(e instanceof Map){const r=new Map;t.set(e,r);const n=Array.from(e),o=n.length;for(let e=0;e<o;e++){const[o,s]=n[e];r.set(o,d(s,t))}return r}if(Object.getPrototypeOf(e)===Object.prototype){const r={};t.set(e,r);const n=Object.getOwnPropertySymbols(e),o=n.length;if(o>0)for(let t=0;t<o;t++){const o=n[t],s=Object.getOwnPropertyDescriptor(e,o);s?.enumerable&&Object.defineProperty(r,o,s)}const s=Object.getOwnPropertyDescriptors(e),i=Object.keys(e),a=i.length;let c=!1;for(let e=0;e<a;e++){const t=s[i[e]];if(t.get||t.set){c=!0;break}}if(c)for(let e=0;e<a;e++){const n=i[e],o=s[n];if(o.enumerable)if(o.get||o.set)Object.defineProperty(r,n,o);else{const e=d(o.value,t);Object.defineProperty(r,n,{...o,value:e})}}else{let n=0;const o=a-a%8;for(;n<o;){const o=i[n],s=i[n+1],a=i[n+2],c=i[n+3],l=i[n+4],f=i[n+5],u=i[n+6],p=i[n+7],g=e;r[o]=d(g[o],t),r[s]=d(g[s],t),r[a]=d(g[a],t),r[c]=d(g[c],t),r[l]=d(g[l],t),r[f]=d(g[f],t),r[u]=d(g[u],t),r[p]=d(g[p],t),n+=8}for(;n<a;){const o=i[n++];r[o]=d(e[o],t)}}return r}const n=Object.getPrototypeOf(e),o=Object.create(n);t.set(e,o);const s=Object.getOwnPropertyDescriptors(e),i=Object.keys(s),a=i.length;for(let e=0;e<a;e++){const r=i[e],n=s[r];if(n.enumerable)if(n.get||n.set)Object.defineProperty(o,r,n);else{const e=d(n.value,t);Object.defineProperty(o,r,{...n,value:e})}}const c=Object.getOwnPropertySymbols(e),l=c.length;for(let t=0;t<l;t++){const r=c[t],n=Object.getOwnPropertyDescriptor(e,r);n?.enumerable&&Object.defineProperty(o,r,n)}return o},g=(e,t)=>{if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!g(e[r],t[r]))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(const r of e)if(!t.has(r))return!1;return!0}if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(const[r,n]of e)if(!t.has(r)||!g(n,t.get(r)))return!1;return!0}if(null!==e&&"object"==typeof e&&!Array.isArray(e)&&null!==t&&"object"==typeof t&&!Array.isArray(t)){const r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(const n of r)if(!g(e[n],t[n]))return!1;return!0}return e===t};exports.WidgetComponent=u,exports.busDispatch=a,exports.busSubscribe=c,exports.calculateRenderedTextWidth=(e,t,r=!1,n='Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"')=>{const o=r?e.toUpperCase():e,s=document.createElement("canvas").getContext("2d");return s.font=`${t}px ${n}`,s.measureText(o).width},exports.camelCase=e=>e.trim().toLowerCase().replace(/^[-_\s]+/,"").replace(/[-_\s]+(.)?/g,((e,t)=>t?t.toUpperCase():"")),exports.capitalize=e=>e.charAt(0).toUpperCase()+e.slice(1),exports.capitalizeFirstLetter=e=>e.charAt(0).toUpperCase()+e.slice(1),exports.checkVisibility=e=>{const t=e.getBoundingClientRect(),r=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(t.bottom<0||t.top-r>=0)},exports.deepClone=e=>d(e,new WeakMap),exports.deepMerge=o,exports.importWidgets=async e=>{const t=e.filter((e=>e?.length&&!document.querySelector(`script[src="${e}"]`)));(await Promise.allSettled(t.map((e=>(async e=>new Promise(((t,r)=>{const n=document.createElement("script");n.onload=()=>{t(!0)},n.onerror=()=>{const t=new Error(`Failed to load script: ${e}`);r(t)},n.type="module",n.src=e,document.head.appendChild(n)})))(e))))).forEach(((e,r)=>{"rejected"===e.status&&console.error(`Failed to load widget script ${t[r]}:`,e.reason)})),a("@@-widgets-loaded",!0)},exports.isBoolean=e=>"boolean"==typeof e,exports.isBrowser=()=>"undefined"!=typeof window,exports.isEqual=g,exports.isFunction=e=>"function"==typeof e,exports.isNull=e=>null===e,exports.isNumber=e=>"number"==typeof e,exports.isObject=n,exports.isString=e=>"string"==typeof e,exports.isUndefined=e=>void 0===e,exports.kebabCase=e=>null==e?e:e.normalize("NFKD").replace(/\p{Diacritic}/gu,"").replace(/[^\w\s-]/g," ").replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z])([A-Z][a-z])/g,"$1-$2").replace(/[-_\s]+/g,"-").toLowerCase().replace(/^-+|-+$/g,"").trim(),exports.merge=(e,...t)=>Object.assign(e,...t),exports.omit=(e,t)=>t.reduce(((e,t)=>(delete e[t],e)),{...e}),exports.pascalCase=e=>e.split(/(?=[0-9])|(?<=[0-9])|[^a-zA-Z0-9]+/g).filter(Boolean).map((e=>e.toLowerCase())).map((e=>`${e.charAt(0).toUpperCase()}${e.slice(1)}`)).join(""),exports.pick=(e,t)=>{const r={};for(const n of t)n in e&&(r[n]=e[n]);return r},exports.r2wc=l,exports.registerWidget=e=>{const{name:r,styles:n,component:o,svgSpritePath:s}=e;return l(`widget-${r}`,(e=>{const{root:n,container:i,...a}=e;return t.jsx(p,{container:i,root:n,svgSpritePath:s,children:t.jsx(o,{...a,name:r})})}),{shadow:"open"},n)},exports.renderWidget=e=>{const{name:n,uuid:o,mountTo:s,widgetProps:i}=e,a=o?.trim()||crypto.randomUUID().replace(/-/g,"").slice(0,6),c=n.trim().toLowerCase();!!c.length&&!!a.length&&s&&s instanceof HTMLElement&&r.createRoot(s).render(t.jsx(u,{name:c,uuid:a,widgetProps:i}))},exports.setStyleProperties=(e,t)=>{if(e)for(const[r,n]of Object.entries(t))e.style.setProperty(r,n)},exports.sleep=e=>new Promise((t=>{setTimeout(t,e)})),exports.slugify=e=>e.normalize("NFKD").toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[-\s_]+/g,"-").replace(/^-+|-+$/g,""),exports.storageCalculateSize=async(e,t)=>{const r=await caches.open(e);if(t){const e=await r.match(t);if(e){const t=e.clone();return(await t.arrayBuffer()).byteLength}return 0}const n=await r.keys();let o=0;for(const e of n){const t=await r.match(e);if(t){const e=t.clone();o+=(await e.arrayBuffer()).byteLength}}return o},exports.storageClear=async e=>{const t=await caches.open(e),r=await t.keys();for(const e of r)await t.delete(e)},exports.storageClearByPrefixOrSuffix=async(e,t,r=!0)=>{const n=await caches.open(e),o=await n.keys();for(const e of o){const o=e.url.split("/"),s=o[o.length-1]||"";(r&&s.startsWith(t)||!r&&s.endsWith(t))&&await n.delete(e)}},exports.storageExists=async(e,t)=>{const r=await caches.open(e);return void 0!==await r.match(t)},exports.storageGetAllKeys=async e=>{const t=await caches.open(e);return(await t.keys()).map((e=>{const t=e.url.split("/");return t[t.length-1]||""}))},exports.storageGetItem=async(e,t)=>{const r=await caches.open(e),n=await r.match(t);if(!n)return null;const o=await n.text();return JSON.parse(o)},exports.storageRemoveItem=async(e,t)=>{const r=await caches.open(e);return await r.delete(t)},exports.storageSetItem=async(e,t,r)=>{const n=await caches.open(e),o=JSON.stringify(r,s),i=new Response(o,{headers:{"Content-Type":"application/json"}});await n.put(t,i)},exports.stringifyBigIntValues=s,exports.uncapitalize=e=>e.charAt(0).toLowerCase()+e.slice(1),exports.useEventBus=(t,r,n=[])=>{e.useEffect((()=>{if(t&&"function"==typeof r)return c(t,r)}),[t,r,...n])};