preact-missing-hooks
Version:
A lightweight, extendable collection of missing React-like hooks for Preact — plus fresh, powerful new ones designed specifically for modern Preact apps.
3 lines (2 loc) • 15 kB
JavaScript
import{useState as e,useCallback as r,useEffect as n,useMemo as t,useRef as o}from"preact/hooks";import{isValidElement as s,cloneElement as i}from"preact";function c(){const[n,t]=e(!1);return[r(e=>{t(!0),Promise.resolve().then(()=>{e(),t(!1)})},[]),n]}function u(e,r,t){n(()=>{const n=e.current;if(!n)return;const o=new MutationObserver(r);return o.observe(n,t),()=>o.disconnect()},[e,r,t])}const a=new Map;function l(){return{emit:r((e,...r)=>{const n=a.get(e);n&&n.forEach(e=>e(...r))},[]),on:r((e,r)=>{let n=a.get(e);return n||(n=new Set,a.set(e,n)),n.add(r),()=>{n.delete(r),0===n.size&&a.delete(e)}},[])}}function d(){return d=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var n=arguments[r];for(var t in n)({}).hasOwnProperty.call(n,t)&&(e[t]=n[t])}return e},d.apply(null,arguments)}function f(e,r,n="preserve"){return t(()=>{if(!e)return e;const t=e=>{if(!s(e))return e;const t=e.props||{};let o;o="override"===n?d({},t,r):d({},r,t);const c=null==t?void 0:t.style,u=null==r?void 0:r.style;return c&&u&&"object"==typeof c&&"object"==typeof u&&(o.style="override"===n?d({},c,u):d({},u,c)),i(e,o)};return Array.isArray(e)?e.map(t):t(e)},[e,r,n])}function p(){const[r,t]=e(()=>{if("undefined"==typeof window)return"no-preference";const e=window.matchMedia("(prefers-color-scheme: dark)"),r=window.matchMedia("(prefers-color-scheme: light)");return e.matches?"dark":r.matches?"light":"no-preference"});return n(()=>{if("undefined"==typeof window)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=e=>{t(e.matches?"dark":"light")},n=()=>{const e=window.matchMedia("(prefers-color-scheme: dark)"),r=window.matchMedia("(prefers-color-scheme: light)");t(e.matches?"dark":r.matches?"light":"no-preference")};e.addEventListener("change",r);const o=window.matchMedia("(prefers-color-scheme: light)");return o.addEventListener("change",n),()=>{e.removeEventListener("change",r),o.removeEventListener("change",n)}},[]),r}function v(){if("undefined"==typeof navigator)return{online:!0};const e={online:navigator.onLine},r=navigator.connection;return r&&(void 0!==r.effectiveType&&(e.effectiveType=r.effectiveType),void 0!==r.downlink&&(e.downlink=r.downlink),void 0!==r.rtt&&(e.rtt=r.rtt),void 0!==r.saveData&&(e.saveData=r.saveData),void 0!==r.type&&(e.connectionType=r.type)),e}function m(){const[r,t]=e(v);return n(()=>{if("undefined"==typeof window)return;const e=()=>t(v());window.addEventListener("online",e),window.addEventListener("offline",e);const r=navigator.connection;return null!=r&&r.addEventListener&&r.addEventListener("change",e),()=>{window.removeEventListener("online",e),window.removeEventListener("offline",e),null!=r&&r.removeEventListener&&r.removeEventListener("change",e)}},[]),r}function h(n={}){const{resetDelay:t=2e3}=n,[o,s]=e(!1),[i,c]=e(null),u=r(()=>{s(!1),c(null)},[]);return{copy:r(async e=>{if(c(null),"undefined"==typeof navigator||!navigator.clipboard){const e=new Error("Clipboard API is not available");return c(e),!1}try{return await navigator.clipboard.writeText(e),s(!0),t>0&&setTimeout(()=>s(!1),t),!0}catch(e){const r=e instanceof Error?e:new Error(String(e));return c(r),!1}},[t]),paste:r(async()=>{if(c(null),"undefined"==typeof navigator||!navigator.clipboard){const e=new Error("Clipboard API is not available");return c(e),""}try{return await navigator.clipboard.readText()}catch(e){const r=e instanceof Error?e:new Error(String(e));return c(r),""}},[]),copied:o,error:i,reset:u}}function w(e,r){const{onRageClick:t,threshold:s=5,timeWindow:i=1e3,distanceThreshold:c=30}=r,u=o(t);u.current=t;const a=o([]);n(()=>{const r=e.current;if(!r)return;const n=e=>{const r=Date.now(),n={time:r,x:e.clientX,y:e.clientY},t=r-i,o=a.current.filter(e=>e.time>=t);if(o.push(n),Infinity!==c){const r=o.filter(e=>{return r=e,t=n,Math.hypot(t.x-r.x,t.y-r.y)<=c;var r,t});if(r.length>=s)return u.current({count:r.length,event:e}),void(a.current=[])}else if(o.length>=s)return u.current({count:o.length,event:e}),void(a.current=[]);a.current=o};return r.addEventListener("click",n),()=>r.removeEventListener("click",n)},[e,s,i,c])}function y(t,s){const{mode:i,concurrency:c=4}=s,u="sequential"===i?1:Math.max(1,c),[a,l]=e(!1),[d,f]=e(void 0),[p,v]=e(void 0),[m,h]=e(0),w=o([]),y=o(0),g=o(0),b=o(!1),E=o(t);E.current=t;const k=r(()=>{h(w.current.length+g.current)},[]),x=r(()=>{if(b.current)return;if(g.current>=u)return;if(0===w.current.length)return 0===g.current&&l(!1),void k();w.current.sort((e,r)=>e.priority!==r.priority?e.priority-r.priority:e.sequence-r.sequence);const e=w.current.shift();g.current+=1,l(!0),k(),(0,E.current)(e.data).then(r=>{f(r),v(void 0),e.resolve(r)}).catch(r=>{v(r),e.reject(r)}).finally(()=>{g.current-=1,k(),x()}),w.current.length>0&&g.current<u&&x()},[u,k]),M=r((e,r)=>{var n;if(b.current)return Promise.reject(new Error("Worker is terminated"));const t=null!=(n=null==r?void 0:r.priority)?n:1,o=++y.current,s=new Promise((r,n)=>{w.current.push({data:e,priority:t,sequence:o,resolve:r,reject:n})});return k(),l(!0),queueMicrotask(x),s},[x,k]),S=r(()=>{const e=w.current;w.current=[],e.forEach(e=>e.reject(new Error("Task cleared from queue"))),k(),0===g.current&&l(!1)},[k]),P=r(()=>{b.current=!0,S()},[S]);return n(()=>()=>{b.current=!0},[]),{run:M,loading:a,result:d,error:p,queueSize:m,clearQueue:S,terminate:P}}const g=new Map;function b(e){return new Promise((r,n)=>{e.onsuccess=()=>r(e.result),e.onerror=()=>{var r;return n(null!=(r=e.error)?r:new DOMException("Unknown IndexedDB error"))}})}function E(e,r){return r?e.then(e=>(null==r.onSuccess||r.onSuccess(e),e)).catch(e=>{throw null==r.onError||r.onError(e),e}):e}function k(r){const[t,s]=e(null),[i,c]=e(null),[u,a]=e(!1),l=o(r);return l.current=r,n(()=>{let e=!1;c(null),a(!1),s(null);const{name:r,version:n,tables:t}=l.current;return function(e){const r=`${e.name}_v${e.version}`;let n=g.get(r);return n||(n=function(e){return new Promise((r,n)=>{const t=indexedDB.open(e.name,e.version);t.onerror=()=>{var e;return n(null!=(e=t.error)?e:new DOMException("Failed to open database"))},t.onsuccess=()=>r(t.result),t.onupgradeneeded=r=>{const n=r.target.result,t=e.tables;for(const e of Object.keys(t)){const r=t[e];if(!n.objectStoreNames.contains(e)){var o;const t=n.createObjectStore(e,{keyPath:r.keyPath,autoIncrement:null!=(o=r.autoIncrement)&&o});if(r.indexes)for(const e of r.indexes)t.createIndex(e,e,{unique:!1})}}}})}(e),g.set(r,n),n)}({name:r,version:n,tables:t}).then(r=>{if(e)return void r.close();const n=function(e){return{get db(){return e},hasTable:r=>e.objectStoreNames.contains(r),table:r=>function(e,r){return function(e,r){function n(n){return e.transaction([r],n).objectStore(r)}return{insert:(e,r)=>E(b(n("readwrite").add(e)),r),update(e,r,t){const o=n("readwrite");return E(b(o.get(e)).then(e=>{if(void 0===e)throw new DOMException("Key not found","NotFoundError");const n=d({},e,r);return b(o.put(n))}).then(()=>{}),t)},delete:(e,r)=>E(b(n("readwrite").delete(e)).then(()=>{}),r),exists:e=>b(n("readonly").getKey(e)).then(e=>void 0!==e),query(e,r){const t=n("readonly").openCursor(),o=[];return E(new Promise((r,n)=>{t.onsuccess=()=>{const n=t.result;n?(e(n.value)&&o.push(n.value),n.continue()):r(o)},t.onerror=()=>{var e;return n(null!=(e=t.error)?e:new DOMException("Unknown error"))}}),r)},upsert:(e,r)=>E(b(n("readwrite").put(e)),r),bulkInsert(e,r){const t=n("readwrite"),o=[];if(0===e.length)return E(Promise.resolve(o),r);let s=0;return E(new Promise((r,n)=>{e.forEach((i,c)=>{const u=t.add(i);u.onsuccess=()=>{o[c]=u.result,s++,s===e.length&&r(o)},u.onerror=()=>{var e;return n(null!=(e=u.error)?e:new DOMException("Unknown error"))}})}),r)},clear:e=>E(b(n("readwrite").clear()).then(()=>{}),e),count:e=>E(b(n("readonly").count()),null!=e?e:{})}}(e,r)}(e,r),transaction(r,n,t,o){const s=e.transaction(r,n),i={table:e=>function(e,r){return function(e,r){function n(){return e.objectStore(r)}return{insert:(e,r)=>E(b(n().add(e)),r),update(e,r,t){const o=n();return E(b(o.get(e)).then(e=>{if(void 0===e)throw new DOMException("Key not found","NotFoundError");const n=d({},e,r);return b(o.put(n))}).then(()=>{}),t)},delete:(e,r)=>E(b(n().delete(e)).then(()=>{}),r),exists:e=>b(n().getKey(e)).then(e=>void 0!==e),query(e,r){const t=n().openCursor(),o=[];return E(new Promise((r,n)=>{t.onsuccess=()=>{const n=t.result;n?(e(n.value)&&o.push(n.value),n.continue()):r(o)},t.onerror=()=>{var e;return n(null!=(e=t.error)?e:new DOMException("Unknown error"))}}),r)},upsert:(e,r)=>E(b(n().put(e)),r),bulkInsert(e,r){const t=n(),o=[];if(0===e.length)return E(Promise.resolve(o),r);let s=0;return E(new Promise((r,n)=>{e.forEach((i,c)=>{const u=t.add(i);u.onsuccess=()=>{o[c]=u.result,s++,s===e.length&&r(o)},u.onerror=()=>{var e;return n(null!=(e=u.error)?e:new DOMException("Unknown error"))}})}),r)},clear:e=>E(b(n().clear()).then(()=>{}),e),count:e=>E(b(n().count()),null!=e?e:{})}}(e,r)}(s,e)},c=new Promise((e,r)=>{s.oncomplete=()=>e(),s.onerror=()=>{var e;return r(null!=(e=s.error)?e:new DOMException("Transaction failed"))}}),u=t(i);return function(e,r){return r?e.then(()=>null==r.onSuccess?void 0:r.onSuccess()).catch(e=>{throw null==r.onError||r.onError(e),e}):e}(Promise.resolve(u).then(()=>c),o)}}}(r);s(n),a(!0)}).catch(r=>{e||c(r)}),()=>{e=!0}},[r.name,r.version]),{db:t,isReady:u,error:i}}const x=/\b(?:25[0-5]|2[0-4]\d|1?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|1?\d{1,2})){3}\b/g,M=["stun:stun.l.google.com:19302"],S=3e3;function P(r={}){const{stunServers:t=M,timeout:s=S,onDetect:i}=r,[c,u]=e([]),[a,l]=e(!0),[d,f]=e(null),p=o(null),v=o(null),m=o(new Set),h=o(i);return h.current=i,n(()=>{if("undefined"==typeof window)return l(!1),void f("WebRTC IP detection is not available during SSR");if("undefined"==typeof RTCPeerConnection)return l(!1),void f("RTCPeerConnection is not available");const e=new Set;m.current=e;const r=()=>{v.current&&(clearTimeout(v.current),v.current=null),p.current&&(p.current.close(),p.current=null),l(!1)},n=r=>{e.has(r)||(e.add(r),u(e=>[...e,r]),null==h.current||h.current(r))};try{const e=new RTCPeerConnection({iceServers:[{urls:t}]});p.current=e,e.onicecandidate=e=>{const r=e.candidate;r&&r.candidate&&function(e){const r=e.match(x);return r?[...r]:[]}(r.candidate).forEach(n)},e.createDataChannel(""),e.createOffer().then(r=>e.setLocalDescription(r)).catch(e=>{f(e instanceof Error?e.message:"Failed to create offer"),r()}),v.current=setTimeout(()=>r(),s)}catch(e){f(e instanceof Error?e.message:"WebRTC setup failed"),r()}return()=>{r()}},[t.join(","),s]),{ips:c,loading:a,error:d}}function D(t){const{wasmUrl:s,exportName:i="compute",workerUrl:c,importObject:u}=t,[a,l]=e(void 0),[d,f]=e(!0),[p,v]=e(null),[m,h]=e(!1),w=o(null),y=o(null),g=o(null);return n(()=>{if("undefined"==typeof window)return v("useWasmCompute is not available during SSR"),void f(!1);if("undefined"==typeof Worker)return v("Worker is not supported in this environment"),void f(!1);if("undefined"==typeof WebAssembly||"function"!=typeof WebAssembly.instantiate)return v("WebAssembly is not supported in this environment"),void f(!1);v(null),h(!1);const e=function(e){if(e)return new Worker(e);const r=new Blob(["\nself.onmessage = async (e) => {\n const d = e.data;\n if (d.type === 'init') {\n try {\n const res = await fetch(d.wasmUrl);\n const buf = await res.arrayBuffer();\n const mod = await WebAssembly.instantiate(buf, d.importObject || {});\n self.wasmInstance = mod.instance;\n self.exportName = d.exportName || 'compute';\n self.postMessage({ type: 'ready' });\n } catch (err) {\n self.postMessage({ type: 'error', error: (err && err.message) || String(err) });\n }\n return;\n }\n if (d.type === 'compute') {\n try {\n const fn = self.wasmInstance.exports[self.exportName];\n if (typeof fn !== 'function') {\n self.postMessage({ type: 'error', error: 'Export \"' + self.exportName + '\" is not a function' });\n return;\n }\n const result = fn(d.input);\n self.postMessage({ type: 'result', result: result });\n } catch (err) {\n self.postMessage({ type: 'error', error: (err && err.message) || String(err) });\n }\n }\n};\n"],{type:"application/javascript"}),n=URL.createObjectURL(r),t=new Worker(n);return URL.revokeObjectURL(n),t}(c);w.current=e;const r=e=>{var r;const{type:n,result:t,error:o}=null!=(r=e.data)?r:{};return"ready"===n?(h(!0),void f(!1)):"error"===n?(v(null!=o?o:"Unknown error"),f(!1),void(g.current&&(g.current(new Error(o)),y.current=null,g.current=null))):void("result"===n&&(l(t),f(!1),y.current&&(y.current(t),y.current=null,g.current=null)))};return e.addEventListener("message",r),e.postMessage({type:"init",wasmUrl:s,exportName:i,importObject:null!=u?u:{}}),()=>{e.removeEventListener("message",r),e.terminate(),w.current=null,g.current&&(g.current(new Error("Worker terminated")),y.current=null,g.current=null)}},[s,i,c,u]),{compute:r(e=>new Promise((r,n)=>{w.current&&m?p?n(new Error(p)):(y.current=r,g.current=n,f(!0),w.current.postMessage({type:"compute",input:e})):n(new Error("WASM not ready"))}),[m,p]),result:a,loading:d,error:p,ready:m}}function L(r,s={}){const{maxHistory:i=100,throughputWindowMs:c=1e3}=s,[u,a]=e([]),[l,d]=e(0),[f,p]=e(0),[v,m]=e([]),[h,w]=e(0),y=o([]),g=o(0),b=o(0);n(()=>{if(!r)return;const e=e=>{const r=function(e){if(null==e||"object"!=typeof e)return null;const r=e.type;return"task_start"!==r&&"task_end"!==r&&"task_fail"!==r&&"queue_size"!==r?null:{type:r,taskId:"string"==typeof e.taskId?e.taskId:void 0,duration:"number"==typeof e.duration?e.duration:void 0,error:"string"==typeof e.error?e.error:void 0,size:"number"==typeof e.size?e.size:void 0,timestamp:Date.now()}}(e.data);if(r)if(m(e=>[...e,r].slice(-i)),"task_start"===r.type&&r.taskId)a(e=>e.includes(r.taskId)?e:[...e,r.taskId]);else if("task_end"===r.type){r.taskId&&a(e=>e.filter(e=>e!==r.taskId)),d(e=>e+1);const e=Date.now()-c;y.current=[...y.current.filter(r=>r>=e),r.timestamp],"number"==typeof r.duration&&(g.current+=r.duration,b.current+=1)}else"task_fail"===r.type?(r.taskId&&a(e=>e.filter(e=>e!==r.taskId)),p(e=>e+1)):"queue_size"===r.type&&"number"==typeof r.size&&w(r.size)};return r.addEventListener("message",e),()=>r.removeEventListener("message",e)},[r,i]);const E=t(()=>{const e=b.current;return e>0?g.current/e:0},[v]),k=t(()=>{const e=Date.now()-c;return y.current.filter(r=>r>=e).length/(c/1e3)},[v,c]),x=t(()=>({runningTasks:u,completedCount:l,failedCount:f,averageDurationMs:E,throughputPerSecond:k,currentQueueSize:h,totalProcessed:l+f,recentEventCount:v.length}),[u,l,f,E,k,h,v.length]);return{runningTasks:u,completedCount:l,failedCount:f,eventHistory:v,averageDurationMs:E,throughputPerSecond:k,currentQueueSize:h,progress:x}}export{h as useClipboard,l as useEventBus,k as useIndexedDB,u as useMutationObserver,m as useNetworkState,p as usePreferredTheme,w as useRageClick,y as useThreadedWorker,c as useTransition,D as useWasmCompute,P as useWebRTCIP,L as useWorkerNotifications,f as useWrappedChildren};
//# sourceMappingURL=entry.modern.mjs.map