@jbpark/use-hooks 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ A collection of reusable React 19 hooks for common UI and interaction patterns.
11
11
 
12
12
  ## Features
13
13
 
14
- - 📦 **10 Production-Ready Hooks** - Utilities for scrolling, viewport, storage, and more
14
+ - 📦 **11 Production-Ready Hooks** - Utilities for scrolling, viewport, storage, and more
15
15
  - 🎯 **Full TypeScript Support** - Complete type definitions for better development experience
16
16
  - ⚡ **Tree-Shakeable** - Import only what you need
17
17
  - 🔒 **SSR-Safe** - Built-in protection for window/document globals
@@ -74,6 +74,7 @@ function MyComponent() {
74
74
  | `useImage` | Preload images and expose loading/error states |
75
75
  | `useRecursiveTimeout` | Recursively schedule async/sync callbacks |
76
76
  | `useViewport` | visualViewport support with in-app mode option and debounce |
77
+ | `useDebounce` | Delay function execution to prevent excessive updates (autoInvoke support) |
77
78
 
78
79
  ## Development
79
80
 
@@ -100,6 +101,7 @@ pnpm exec prettier --write .
100
101
  src/
101
102
  ├── hooks/ # Individual hook implementations
102
103
  │ ├── useBodyScrollLock/
104
+ │ ├── useDebounce/
103
105
  │ ├── useElementPosition/
104
106
  │ ├── useElementScroll/
105
107
  │ ├── useImage/
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react"),E=(e,{delay:o=100,autoInvoke:d=!0},t=[])=>{const s=n.useRef(null),c=n.useRef(e),i=n.useRef(t),l=n.useRef(void 0);n.useEffect(()=>{c.current=e}),n.useEffect(()=>{i.current=t});const r=n.useRef(null);return r.current||(r.current=((...u)=>{s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{c.current(...u)},o)})),n.useEffect(()=>{const u=l.current===void 0||l.current.length!==t.length||l.current.some((a,w)=>a!==t[w]);u&&s.current&&clearTimeout(s.current),d&&u&&(l.current===void 0?c.current():r.current&&r.current()),l.current=t}),n.useEffect(()=>()=>{s.current&&clearTimeout(s.current)},[]),r.current},S=(e=!0)=>{n.useEffect(()=>{if(!e)return;const o=window.scrollY,d=/iPad|iPhone|iPod/.test(navigator.userAgent),t={documentElement:{overflow:document.documentElement.style.overflow,height:document.documentElement.style.height,position:document.documentElement.style.position,width:document.documentElement.style.width},body:{overflow:document.body.style.overflow,height:document.body.style.height,position:document.body.style.position,top:document.body.style.top,left:document.body.style.left,right:document.body.style.right,width:document.body.style.width,webkitOverflowScrolling:document.body.style.getPropertyValue("-webkit-overflow-scrolling")}};if(document.documentElement.style.overflow="hidden",document.documentElement.style.height="100%",document.documentElement.style.position="fixed",document.documentElement.style.width="100%",document.body.style.overflow="hidden",document.body.style.height="100%",document.body.style.position="fixed",document.body.style.top=`-${o}px`,document.body.style.left="0",document.body.style.right="0",document.body.style.width="100%",d){document.body.style.setProperty("-webkit-overflow-scrolling","touch");const s=r=>{(r.target===document.body||r.target===document.documentElement||r.target===window)&&(r.preventDefault(),r.stopPropagation(),r.stopImmediatePropagation())},c=()=>{window.scrollTo(0,0),document.body.scrollTop=0,document.documentElement.scrollTop=0},i=["scroll","touchmove","touchstart","touchend"];i.forEach(r=>{window.addEventListener(r,s,{passive:!1,capture:!0}),document.addEventListener(r,s,{passive:!1,capture:!0}),document.body.addEventListener(r,s,{passive:!1,capture:!0})});const l=setInterval(c,16);return()=>{clearInterval(l),i.forEach(r=>{window.removeEventListener(r,s,{capture:!0}),document.removeEventListener(r,s,{capture:!0}),document.body.removeEventListener(r,s,{capture:!0})}),document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,t.body.webkitOverflowScrolling?document.body.style.setProperty("-webkit-overflow-scrolling",t.body.webkitOverflowScrolling):document.body.style.removeProperty("-webkit-overflow-scrolling"),window.scrollTo(0,o)}}return()=>{document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,window.scrollTo(0,o)}},[e])},L=e=>{const[o,d]=n.useState(null);return n.useEffect(()=>{const t=i=>typeof i=="string"?document.querySelector(i):i.current,s=()=>{const i=t(e);d(i?i.getBoundingClientRect():null)},c=()=>{requestAnimationFrame(s)};return s(),window.addEventListener("scroll",c,{passive:!0}),window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("scroll",c),window.removeEventListener("resize",c)}},[e]),o},T=()=>{const[e,o]=n.useState(null),[d,t]=n.useState({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!1,scrollableHeight:0,clientHeight:0,scrollHeight:0}),s=n.useCallback(c=>{o(c)},[]);return n.useEffect(()=>{if(!e)return;const c=()=>{const{scrollTop:r,scrollHeight:u,clientHeight:a}=e,w=u-a;if(w<=0){t({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!0,scrollableHeight:0,clientHeight:a,scrollHeight:u});return}const m=Math.min(100,Math.max(0,r/w*100));t({scrollY:r,scrollPercentage:m,isAtTop:r<=0,isAtBottom:r>=w-1,scrollableHeight:w,clientHeight:a,scrollHeight:u})};c();const i=()=>{c()};e.addEventListener("scroll",i,{passive:!0});const l=new ResizeObserver(()=>{c()});return l.observe(e),()=>{e.removeEventListener("scroll",i),l.unobserve(e)}},[e]),{...d,element:e,setRef:s}},f={sm:640,md:768,lg:1024,xl:1280,"2xl":1536},x=e=>{let o="xs";return e>=f["2xl"]?o="2xl":e>=f.xl?o="xl":e>=f.lg?o="lg":e>=f.md?o="md":e>=f.sm?o="sm":o="xs",{current:o,xs:e<f.sm,sm:e>=f.sm&&e<f.md,md:e>=f.md&&e<f.lg,lg:e>=f.lg&&e<f.xl,xl:e>=f.xl&&e<f["2xl"],"2xl":e>=f["2xl"]}},R=e=>{const{delay:o=100,container:d}=e||{},[t,s]=n.useState({width:0,height:0}),[c,i]=n.useState({current:"xs",xs:!0,sm:!1,md:!1,lg:!1,xl:!1,"2xl":!1}),[l,r]=n.useState({width:0,height:0}),u=n.useRef(null),a=n.useRef(null);return E(()=>{r(t)},{delay:o},[t]),n.useEffect(()=>{const w=()=>{const h=d??u.current??document.body;if(!h)return;const{offsetWidth:y,offsetHeight:v}=h;s(p=>p.width!==y||p.height!==v?{width:y,height:v}:p),i(p=>{const b=x(y);return p.current!==b.current?b:p})},m=()=>{const h=d??u.current??document.body;h&&(w(),a.current&&a.current.disconnect(),a.current=new ResizeObserver(()=>{requestAnimationFrame(()=>{w()})}),a.current.observe(h))},g=()=>{a.current&&(a.current.disconnect(),a.current=null)};return m(),()=>{g()}},[d]),{size:l,breakpoint:c,ref:u}},V=(e,o={})=>{const{retryCount:d=0,retryDelay:t=1e3}=o,[s,c]=n.useState(!0),[i,l]=n.useState(null),[r,u]=n.useState(!1),[a,w]=n.useState(0),m=n.useCallback(()=>{if(!e){c(!1),u(!1);return}c(!0),l(null);const h=new Image;h.src=e,h.onload=()=>{c(!1),u(!0),l(null),w(0)},h.onerror=y=>{c(!1),u(!1),l(y),a<d&&setTimeout(()=>{w(v=>v+1)},t)}},[e,a,d,t]);n.useEffect(()=>{m()},[m]);const g=n.useCallback(()=>{w(0),m()},[m]);return{loading:s,error:i,loaded:r,retry:g}},z=(e,o)=>{const d=n.useRef(o),[t,s]=n.useState(()=>{if(typeof window>"u")return o;try{const i=window.localStorage.getItem(e);return i?JSON.parse(i):o}catch{return o}});n.useEffect(()=>{if(!(typeof window>"u"))try{const i=window.localStorage.getItem(e);i?s(JSON.parse(i)):window.localStorage.setItem(e,JSON.stringify(d.current))}catch(i){console.error(`Error reading localStorage key "${e}":`,i)}},[e]);const c=n.useCallback(i=>{try{s(l=>{const r=i instanceof Function?i(l):i;return localStorage.setItem(e,JSON.stringify(r)),r})}catch(l){console.error(`Error setting localStorage key "${e}":`,l)}},[e]);return[t,c]},P=(e,o)=>{const d=n.useRef(e);n.useEffect(()=>{d.current=e},[e]),n.useEffect(()=>{let t;function s(){const c=d.current();c instanceof Promise?c.then(()=>{o&&(t=setTimeout(s,o))}):o&&(t=setTimeout(s,o))}if(o)return t=setTimeout(s,o),()=>t&&clearTimeout(t)},[o])},H=e=>{const o=n.useRef([]),d=n.useCallback(s=>{if(o.current[s]&&(o.current[s].scrollIntoView({behavior:"smooth",block:"start",inline:"start",...e}),e?.offset)){const c=o.current[s].getBoundingClientRect().top+window.scrollY-e.offset;window.scrollTo({top:c,behavior:e.behavior||"smooth"})}},[e]),t=n.useCallback((s,c)=>{o.current[c]=s},[]);return{elementRefs:o,setElementRef:t,scrollToElement:d}},I=()=>{const[e,o]=n.useState({x:0,y:0,percent:{x:0,y:0}});return n.useEffect(()=>{const d=()=>{const i=window.scrollX||0,l=window.scrollY||0,r=/iPad|iPhone|iPod/.test(navigator.userAgent),u=window.visualViewport,a=r&&u?u.width:window.innerWidth,w=r&&u?u.height:window.innerHeight,m=Math.max(0,document.documentElement.scrollWidth-a),g=Math.max(0,document.documentElement.scrollHeight-w),h=m===0?0:Math.min(100,i/m*100),y=g===0?0:Math.min(100,l/g*100);o({x:i,y:l,percent:{x:Math.floor(Math.max(0,h)),y:Math.floor(Math.max(0,y))}})};d();const t=()=>{d()},s=()=>{setTimeout(d,100)},c=()=>{setTimeout(d,50)};return window.addEventListener("scroll",t,{passive:!0}),window.addEventListener("resize",s),window.addEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.addEventListener("resize",c),()=>{window.removeEventListener("scroll",t),window.removeEventListener("resize",s),window.removeEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.removeEventListener("resize",c)}},[]),e},k=(e={})=>{const{isInApp:o=!1,debounce:d=100}=e,[t,s]=n.useState({width:0,height:0,offsetLeft:0,offsetTop:0,pageLeft:0,pageTop:0,scale:1}),c=n.useCallback(()=>{const l=window.innerHeight,r=window.visualViewport?.height||l,u=document.documentElement.clientHeight,a=document.body.clientHeight;return window.visualViewport&&Math.abs(r-l)>100?r:Math.max(l,u,a)},[]),i=n.useCallback(()=>{if(window.visualViewport&&!o)return window.visualViewport;const l=window.visualViewport?.width||window.innerWidth,r=o?c():window.visualViewport?.height||window.innerHeight;return{width:l,height:r,offsetLeft:window.visualViewport?.offsetLeft||0,offsetTop:window.visualViewport?.offsetTop||0,pageLeft:window.scrollX??window.pageXOffset??0,pageTop:window.scrollY??window.pageYOffset??0,scale:window.visualViewport?.scale||1}},[o,c]);return n.useEffect(()=>{let l;const r=()=>{clearTimeout(l),l=setTimeout(()=>{s(i())},d)},u=()=>s(i());u();const a=["resize","orientationchange"];o&&a.push("focus","blur","touchstart","touchend"),a.forEach(m=>{m==="resize"||m==="orientationchange"?window.addEventListener(m,r):window.addEventListener(m,u,{passive:!0})}),window.visualViewport&&(window.visualViewport.addEventListener("resize",u),window.visualViewport.addEventListener("scroll",u));let w;if(o){let m=i().height;w=setInterval(()=>{const g=i().height;Math.abs(g-m)>50&&(m=g,u())},500)}return()=>{clearTimeout(l),w&&clearInterval(w),a.forEach(m=>{window.removeEventListener(m,m==="resize"||m==="orientationchange"?r:u)}),window.visualViewport&&(window.visualViewport.removeEventListener("resize",u),window.visualViewport.removeEventListener("scroll",u))}},[i,o,d]),t};exports.useBodyScrollLock=S;exports.useDebounce=E;exports.useElementPosition=L;exports.useElementScroll=T;exports.useImage=V;exports.useLocalStorage=z;exports.useRecursiveTimeout=P;exports.useResponsiveSize=R;exports.useScrollToElements=H;exports.useViewport=k;exports.useWindowScroll=I;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react"),L=(e,{delay:o=100,autoInvoke:d=!0},t=[])=>{const s=n.useRef(null),c=n.useRef(e),i=n.useRef(t),l=n.useRef(void 0);n.useEffect(()=>{c.current=e}),n.useEffect(()=>{i.current=t});const r=n.useRef(null);return r.current||(r.current=((...u)=>{s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{c.current(...u)},o)})),n.useEffect(()=>{const u=l.current===void 0||l.current.length!==t.length||l.current.some((w,a)=>w!==t[a]);u&&s.current&&clearTimeout(s.current),d&&u&&(l.current===void 0?c.current():r.current&&r.current()),l.current=t}),n.useEffect(()=>()=>{s.current&&clearTimeout(s.current)},[]),r.current},T=(e=!0)=>{n.useEffect(()=>{if(!e)return;const o=window.scrollY,d=/iPad|iPhone|iPod/.test(navigator.userAgent),t={documentElement:{overflow:document.documentElement.style.overflow,height:document.documentElement.style.height,position:document.documentElement.style.position,width:document.documentElement.style.width},body:{overflow:document.body.style.overflow,height:document.body.style.height,position:document.body.style.position,top:document.body.style.top,left:document.body.style.left,right:document.body.style.right,width:document.body.style.width,webkitOverflowScrolling:document.body.style.getPropertyValue("-webkit-overflow-scrolling")}};if(document.documentElement.style.overflow="hidden",document.documentElement.style.height="100%",document.documentElement.style.position="fixed",document.documentElement.style.width="100%",document.body.style.overflow="hidden",document.body.style.height="100%",document.body.style.position="fixed",document.body.style.top=`-${o}px`,document.body.style.left="0",document.body.style.right="0",document.body.style.width="100%",d){document.body.style.setProperty("-webkit-overflow-scrolling","touch");const s=r=>{(r.target===document.body||r.target===document.documentElement||r.target===window)&&(r.preventDefault(),r.stopPropagation(),r.stopImmediatePropagation())},c=()=>{window.scrollTo(0,0),document.body.scrollTop=0,document.documentElement.scrollTop=0},i=["scroll","touchmove","touchstart","touchend"];i.forEach(r=>{window.addEventListener(r,s,{passive:!1,capture:!0}),document.addEventListener(r,s,{passive:!1,capture:!0}),document.body.addEventListener(r,s,{passive:!1,capture:!0})});const l=setInterval(c,16);return()=>{clearInterval(l),i.forEach(r=>{window.removeEventListener(r,s,{capture:!0}),document.removeEventListener(r,s,{capture:!0}),document.body.removeEventListener(r,s,{capture:!0})}),document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,t.body.webkitOverflowScrolling?document.body.style.setProperty("-webkit-overflow-scrolling",t.body.webkitOverflowScrolling):document.body.style.removeProperty("-webkit-overflow-scrolling"),window.scrollTo(0,o)}}return()=>{document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,window.scrollTo(0,o)}},[e])},x=e=>{const[o,d]=n.useState(null);return n.useEffect(()=>{const t=i=>typeof i=="string"?document.querySelector(i):i.current,s=()=>{const i=t(e);d(i?i.getBoundingClientRect():null)},c=()=>{requestAnimationFrame(s)};return s(),window.addEventListener("scroll",c,{passive:!0}),window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("scroll",c),window.removeEventListener("resize",c)}},[e]),o},R=()=>{const[e,o]=n.useState(null),[d,t]=n.useState({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!1,scrollableHeight:0,clientHeight:0,scrollHeight:0}),s=n.useCallback(c=>{o(c)},[]);return n.useEffect(()=>{if(!e)return;const c=()=>{const{scrollTop:r,scrollHeight:u,clientHeight:w}=e,a=u-w;if(a<=0){t({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!0,scrollableHeight:0,clientHeight:w,scrollHeight:u});return}const m=Math.min(100,Math.max(0,r/a*100));t({scrollY:r,scrollPercentage:m,isAtTop:r<=0,isAtBottom:r>=a-1,scrollableHeight:a,clientHeight:w,scrollHeight:u})};c();const i=()=>{c()};e.addEventListener("scroll",i,{passive:!0});const l=new ResizeObserver(()=>{c()});return l.observe(e),()=>{e.removeEventListener("scroll",i),l.unobserve(e)}},[e]),{...d,element:e,setRef:s}},f={sm:640,md:768,lg:1024,xl:1280,"2xl":1536},V=e=>{let o="xs";return e>=f["2xl"]?o="2xl":e>=f.xl?o="xl":e>=f.lg?o="lg":e>=f.md?o="md":e>=f.sm?o="sm":o="xs",{current:o,xs:e<f.sm,sm:e>=f.sm&&e<f.md,md:e>=f.md&&e<f.lg,lg:e>=f.lg&&e<f.xl,xl:e>=f.xl&&e<f["2xl"],"2xl":e>=f["2xl"]}},z=e=>{const{delay:o=100,container:d}=e||{},[t,s]=n.useState({width:0,height:0}),[c,i]=n.useState({current:"xs",xs:!0,sm:!1,md:!1,lg:!1,xl:!1,"2xl":!1}),[l,r]=n.useState({width:0,height:0}),[u,w]=n.useState(null),a=n.useRef(null),m=n.useCallback(h=>{w(h)},[]);return L(()=>{r(t)},{delay:o},[t]),n.useEffect(()=>{const h=()=>{const y=d??u??document.body;if(!y)return;const{offsetWidth:b,offsetHeight:E}=y;s(p=>p.width!==b||p.height!==E?{width:b,height:E}:p),i(p=>{const S=V(b);return p.current!==S.current?S:p})},g=()=>{const y=d??u??document.body;y&&(h(),a.current&&a.current.disconnect(),a.current=new ResizeObserver(()=>{requestAnimationFrame(()=>{h()})}),a.current.observe(y))},v=()=>{a.current&&(a.current.disconnect(),a.current=null)};return g(),()=>{v()}},[d,u]),{size:l,breakpoint:c,ref:m}},P=(e,o={})=>{const{retryCount:d=0,retryDelay:t=1e3}=o,[s,c]=n.useState(!0),[i,l]=n.useState(null),[r,u]=n.useState(!1),[w,a]=n.useState(0),m=n.useCallback(()=>{if(!e){c(!1),u(!1);return}c(!0),l(null);const g=new Image;g.src=e,g.onload=()=>{c(!1),u(!0),l(null),a(0)},g.onerror=v=>{c(!1),u(!1),l(v),w<d&&setTimeout(()=>{a(y=>y+1)},t)}},[e,w,d,t]);n.useEffect(()=>{m()},[m]);const h=n.useCallback(()=>{a(0),m()},[m]);return{loading:s,error:i,loaded:r,retry:h}},H=(e,o)=>{const d=n.useRef(o),[t,s]=n.useState(()=>{if(typeof window>"u")return o;try{const i=window.localStorage.getItem(e);return i?JSON.parse(i):o}catch{return o}});n.useEffect(()=>{if(!(typeof window>"u"))try{const i=window.localStorage.getItem(e);i?s(JSON.parse(i)):window.localStorage.setItem(e,JSON.stringify(d.current))}catch(i){console.error(`Error reading localStorage key "${e}":`,i)}},[e]);const c=n.useCallback(i=>{try{s(l=>{const r=i instanceof Function?i(l):i;return localStorage.setItem(e,JSON.stringify(r)),r})}catch(l){console.error(`Error setting localStorage key "${e}":`,l)}},[e]);return[t,c]},I=(e,o)=>{const d=n.useRef(e);n.useEffect(()=>{d.current=e},[e]),n.useEffect(()=>{let t;function s(){const c=d.current();c instanceof Promise?c.then(()=>{o&&(t=setTimeout(s,o))}):o&&(t=setTimeout(s,o))}if(o)return t=setTimeout(s,o),()=>t&&clearTimeout(t)},[o])},k=e=>{const o=n.useRef([]),d=n.useCallback(s=>{if(o.current[s]&&(o.current[s].scrollIntoView({behavior:"smooth",block:"start",inline:"start",...e}),e?.offset)){const c=o.current[s].getBoundingClientRect().top+window.scrollY-e.offset;window.scrollTo({top:c,behavior:e.behavior||"smooth"})}},[e]),t=n.useCallback((s,c)=>{o.current[c]=s},[]);return{elementRefs:o,setElementRef:t,scrollToElement:d}},C=()=>{const[e,o]=n.useState({x:0,y:0,percent:{x:0,y:0}});return n.useEffect(()=>{const d=()=>{const i=window.scrollX||0,l=window.scrollY||0,r=/iPad|iPhone|iPod/.test(navigator.userAgent),u=window.visualViewport,w=r&&u?u.width:window.innerWidth,a=r&&u?u.height:window.innerHeight,m=Math.max(0,document.documentElement.scrollWidth-w),h=Math.max(0,document.documentElement.scrollHeight-a),g=m===0?0:Math.min(100,i/m*100),v=h===0?0:Math.min(100,l/h*100);o({x:i,y:l,percent:{x:Math.floor(Math.max(0,g)),y:Math.floor(Math.max(0,v))}})};d();const t=()=>{d()},s=()=>{setTimeout(d,100)},c=()=>{setTimeout(d,50)};return window.addEventListener("scroll",t,{passive:!0}),window.addEventListener("resize",s),window.addEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.addEventListener("resize",c),()=>{window.removeEventListener("scroll",t),window.removeEventListener("resize",s),window.removeEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.removeEventListener("resize",c)}},[]),e},O=(e={})=>{const{isInApp:o=!1,debounce:d=100}=e,[t,s]=n.useState({width:0,height:0,offsetLeft:0,offsetTop:0,pageLeft:0,pageTop:0,scale:1}),c=n.useCallback(()=>{const l=window.innerHeight,r=window.visualViewport?.height||l,u=document.documentElement.clientHeight,w=document.body.clientHeight;return window.visualViewport&&Math.abs(r-l)>100?r:Math.max(l,u,w)},[]),i=n.useCallback(()=>{if(window.visualViewport&&!o)return window.visualViewport;const l=window.visualViewport?.width||window.innerWidth,r=o?c():window.visualViewport?.height||window.innerHeight;return{width:l,height:r,offsetLeft:window.visualViewport?.offsetLeft||0,offsetTop:window.visualViewport?.offsetTop||0,pageLeft:window.scrollX??window.pageXOffset??0,pageTop:window.scrollY??window.pageYOffset??0,scale:window.visualViewport?.scale||1}},[o,c]);return n.useEffect(()=>{let l;const r=()=>{clearTimeout(l),l=setTimeout(()=>{s(i())},d)},u=()=>s(i());u();const w=["resize","orientationchange"];o&&w.push("focus","blur","touchstart","touchend"),w.forEach(m=>{m==="resize"||m==="orientationchange"?window.addEventListener(m,r):window.addEventListener(m,u,{passive:!0})}),window.visualViewport&&(window.visualViewport.addEventListener("resize",u),window.visualViewport.addEventListener("scroll",u));let a;if(o){let m=i().height;a=setInterval(()=>{const h=i().height;Math.abs(h-m)>50&&(m=h,u())},500)}return()=>{clearTimeout(l),a&&clearInterval(a),w.forEach(m=>{window.removeEventListener(m,m==="resize"||m==="orientationchange"?r:u)}),window.visualViewport&&(window.visualViewport.removeEventListener("resize",u),window.visualViewport.removeEventListener("scroll",u))}},[i,o,d]),t};exports.useBodyScrollLock=T;exports.useDebounce=L;exports.useElementPosition=x;exports.useElementScroll=R;exports.useImage=P;exports.useLocalStorage=H;exports.useRecursiveTimeout=I;exports.useResponsiveSize=z;exports.useScrollToElements=k;exports.useViewport=O;exports.useWindowScroll=C;
package/dist/index.d.ts CHANGED
@@ -73,7 +73,7 @@ export declare const useResponsiveSize: <T extends HTMLElement>(options?: Option
73
73
  height: number;
74
74
  };
75
75
  breakpoint: BreakpointInfo;
76
- ref: RefObject<T | null>;
76
+ ref: (node: T | null) => void;
77
77
  };
78
78
 
79
79
  export declare const useScrollToElements: (options?: Options_4) => {
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
1
- import { useRef as y, useEffect as f, useState as h, useCallback as v } from "react";
2
- const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
3
- const n = y(null), i = y(e), s = y(t), c = y(void 0);
1
+ import { useRef as y, useEffect as f, useState as h, useCallback as p } from "react";
2
+ const V = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
3
+ const n = y(null), i = y(e), s = y(t), l = y(void 0);
4
4
  f(() => {
5
5
  i.current = e;
6
6
  }), f(() => {
7
7
  s.current = t;
8
8
  });
9
9
  const r = y(null);
10
- return r.current || (r.current = ((...l) => {
10
+ return r.current || (r.current = ((...c) => {
11
11
  n.current && clearTimeout(n.current), n.current = setTimeout(() => {
12
- i.current(...l);
12
+ i.current(...c);
13
13
  }, o);
14
14
  })), f(() => {
15
- const l = c.current === void 0 || c.current.length !== t.length || c.current.some((u, a) => u !== t[a]);
16
- l && n.current && clearTimeout(n.current), d && l && (c.current === void 0 ? i.current() : r.current && r.current()), c.current = t;
15
+ const c = l.current === void 0 || l.current.length !== t.length || l.current.some((a, u) => a !== t[u]);
16
+ c && n.current && clearTimeout(n.current), d && c && (l.current === void 0 ? i.current() : r.current && r.current()), l.current = t;
17
17
  }), f(() => () => {
18
18
  n.current && clearTimeout(n.current);
19
19
  }, []), r.current;
20
- }, z = (e = !0) => {
20
+ }, I = (e = !0) => {
21
21
  f(() => {
22
22
  if (!e)
23
23
  return;
@@ -60,9 +60,9 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
60
60
  capture: !0
61
61
  });
62
62
  });
63
- const c = setInterval(i, 16);
63
+ const l = setInterval(i, 16);
64
64
  return () => {
65
- clearInterval(c), s.forEach((r) => {
65
+ clearInterval(l), s.forEach((r) => {
66
66
  window.removeEventListener(r, n, { capture: !0 }), document.removeEventListener(r, n, { capture: !0 }), document.body.removeEventListener(r, n, {
67
67
  capture: !0
68
68
  });
@@ -76,7 +76,7 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
76
76
  document.documentElement.style.overflow = t.documentElement.overflow, document.documentElement.style.height = t.documentElement.height, document.documentElement.style.position = t.documentElement.position, document.documentElement.style.width = t.documentElement.width, document.body.style.overflow = t.body.overflow, document.body.style.height = t.body.height, document.body.style.position = t.body.position, document.body.style.top = t.body.top, document.body.style.left = t.body.left, document.body.style.right = t.body.right, document.body.style.width = t.body.width, window.scrollTo(0, o);
77
77
  };
78
78
  }, [e]);
79
- }, H = (e) => {
79
+ }, P = (e) => {
80
80
  const [o, d] = h(null);
81
81
  return f(() => {
82
82
  const t = (s) => typeof s == "string" ? document.querySelector(s) : s.current, n = () => {
@@ -89,7 +89,7 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
89
89
  window.removeEventListener("scroll", i), window.removeEventListener("resize", i);
90
90
  };
91
91
  }, [e]), o;
92
- }, I = () => {
92
+ }, R = () => {
93
93
  const [e, o] = h(null), [d, t] = h({
94
94
  scrollY: 0,
95
95
  scrollPercentage: 0,
@@ -98,38 +98,38 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
98
98
  scrollableHeight: 0,
99
99
  clientHeight: 0,
100
100
  scrollHeight: 0
101
- }), n = v((i) => {
101
+ }), n = p((i) => {
102
102
  o(i);
103
103
  }, []);
104
104
  return f(() => {
105
105
  if (!e)
106
106
  return;
107
107
  const i = () => {
108
- const { scrollTop: r, scrollHeight: l, clientHeight: u } = e, a = l - u;
109
- if (a <= 0) {
108
+ const { scrollTop: r, scrollHeight: c, clientHeight: a } = e, u = c - a;
109
+ if (u <= 0) {
110
110
  t({
111
111
  scrollY: 0,
112
112
  scrollPercentage: 0,
113
113
  isAtTop: !0,
114
114
  isAtBottom: !0,
115
115
  scrollableHeight: 0,
116
- clientHeight: u,
117
- scrollHeight: l
116
+ clientHeight: a,
117
+ scrollHeight: c
118
118
  });
119
119
  return;
120
120
  }
121
121
  const m = Math.min(
122
122
  100,
123
- Math.max(0, r / a * 100)
123
+ Math.max(0, r / u * 100)
124
124
  );
125
125
  t({
126
126
  scrollY: r,
127
127
  scrollPercentage: m,
128
128
  isAtTop: r <= 0,
129
- isAtBottom: r >= a - 1,
130
- scrollableHeight: a,
131
- clientHeight: u,
132
- scrollHeight: l
129
+ isAtBottom: r >= u - 1,
130
+ scrollableHeight: u,
131
+ clientHeight: a,
132
+ scrollHeight: c
133
133
  });
134
134
  };
135
135
  i();
@@ -137,11 +137,11 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
137
137
  i();
138
138
  };
139
139
  e.addEventListener("scroll", s, { passive: !0 });
140
- const c = new ResizeObserver(() => {
140
+ const l = new ResizeObserver(() => {
141
141
  i();
142
142
  });
143
- return c.observe(e), () => {
144
- e.removeEventListener("scroll", s), c.unobserve(e);
143
+ return l.observe(e), () => {
144
+ e.removeEventListener("scroll", s), l.unobserve(e);
145
145
  };
146
146
  }, [e]), { ...d, element: e, setRef: n };
147
147
  }, w = {
@@ -156,7 +156,7 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
156
156
  // >= 1280px
157
157
  "2xl": 1536
158
158
  // >= 1536px
159
- }, T = (e) => {
159
+ }, z = (e) => {
160
160
  let o = "xs";
161
161
  return e >= w["2xl"] ? o = "2xl" : e >= w.xl ? o = "xl" : e >= w.lg ? o = "lg" : e >= w.md ? o = "md" : e >= w.sm ? o = "sm" : o = "xs", {
162
162
  current: o,
@@ -167,7 +167,7 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
167
167
  xl: e >= w.xl && e < w["2xl"],
168
168
  "2xl": e >= w["2xl"]
169
169
  };
170
- }, P = (e) => {
170
+ }, A = (e) => {
171
171
  const { delay: o = 100, container: d } = e || {}, [t, n] = h({ width: 0, height: 0 }), [i, s] = h({
172
172
  current: "xs",
173
173
  xs: !0,
@@ -176,70 +176,72 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
176
176
  lg: !1,
177
177
  xl: !1,
178
178
  "2xl": !1
179
- }), [c, r] = h({ width: 0, height: 0 }), l = y(null), u = y(null);
180
- return x(
179
+ }), [l, r] = h({ width: 0, height: 0 }), [c, a] = h(null), u = y(null), m = p((g) => {
180
+ a(g);
181
+ }, []);
182
+ return V(
181
183
  () => {
182
184
  r(t);
183
185
  },
184
186
  { delay: o },
185
187
  [t]
186
188
  ), f(() => {
187
- const a = () => {
188
- const g = d ?? l.current ?? document.body;
189
- if (!g)
189
+ const g = () => {
190
+ const b = d ?? c ?? document.body;
191
+ if (!b)
190
192
  return;
191
- const { offsetWidth: b, offsetHeight: S } = g;
192
- n((E) => E.width !== b || E.height !== S ? { width: b, height: S } : E), s((E) => {
193
- const L = T(b);
194
- return E.current !== L.current ? L : E;
193
+ const { offsetWidth: L, offsetHeight: x } = b;
194
+ n((E) => E.width !== L || E.height !== x ? { width: L, height: x } : E), s((E) => {
195
+ const T = z(L);
196
+ return E.current !== T.current ? T : E;
195
197
  });
196
- }, m = () => {
197
- const g = d ?? l.current ?? document.body;
198
- g && (a(), u.current && u.current.disconnect(), u.current = new ResizeObserver(() => {
198
+ }, v = () => {
199
+ const b = d ?? c ?? document.body;
200
+ b && (g(), u.current && u.current.disconnect(), u.current = new ResizeObserver(() => {
199
201
  requestAnimationFrame(() => {
200
- a();
202
+ g();
201
203
  });
202
- }), u.current.observe(g));
203
- }, p = () => {
204
+ }), u.current.observe(b));
205
+ }, S = () => {
204
206
  u.current && (u.current.disconnect(), u.current = null);
205
207
  };
206
- return m(), () => {
207
- p();
208
+ return v(), () => {
209
+ S();
208
210
  };
209
- }, [d]), {
210
- size: c,
211
+ }, [d, c]), {
212
+ size: l,
211
213
  breakpoint: i,
212
- ref: l
214
+ ref: m
213
215
  };
214
- }, R = (e, o = {}) => {
215
- const { retryCount: d = 0, retryDelay: t = 1e3 } = o, [n, i] = h(!0), [s, c] = h(null), [r, l] = h(!1), [u, a] = h(0), m = v(() => {
216
+ }, O = (e, o = {}) => {
217
+ const { retryCount: d = 0, retryDelay: t = 1e3 } = o, [n, i] = h(!0), [s, l] = h(null), [r, c] = h(!1), [a, u] = h(0), m = p(() => {
216
218
  if (!e) {
217
- i(!1), l(!1);
219
+ i(!1), c(!1);
218
220
  return;
219
221
  }
220
- i(!0), c(null);
221
- const g = new Image();
222
- g.src = e, g.onload = () => {
223
- i(!1), l(!0), c(null), a(0);
224
- }, g.onerror = (b) => {
225
- i(!1), l(!1), c(b), u < d && setTimeout(() => {
226
- a((S) => S + 1);
222
+ i(!0), l(null);
223
+ const v = new Image();
224
+ v.src = e, v.onload = () => {
225
+ i(!1), c(!0), l(null), u(0);
226
+ }, v.onerror = (S) => {
227
+ i(!1), c(!1), l(S), a < d && setTimeout(() => {
228
+ u((b) => b + 1);
227
229
  }, t);
228
230
  };
229
- }, [e, u, d, t]);
231
+ }, [e, a, d, t]);
230
232
  f(() => {
231
233
  m();
232
234
  }, [m]);
233
- const p = v(() => {
234
- a(0), m();
235
+ const g = p(() => {
236
+ u(0), m();
235
237
  }, [m]);
236
238
  return {
237
239
  loading: n,
238
240
  error: s,
239
241
  loaded: r,
240
- retry: p
242
+ retry: g
241
243
  };
242
- }, A = (e, o) => {
244
+ }, M = (e, o) => {
243
245
  const d = y(o), [t, n] = h(() => {
244
246
  if (typeof window > "u")
245
247
  return o;
@@ -259,21 +261,21 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
259
261
  console.error(`Error reading localStorage key "${e}":`, s);
260
262
  }
261
263
  }, [e]);
262
- const i = v(
264
+ const i = p(
263
265
  (s) => {
264
266
  try {
265
- n((c) => {
266
- const r = s instanceof Function ? s(c) : s;
267
+ n((l) => {
268
+ const r = s instanceof Function ? s(l) : s;
267
269
  return localStorage.setItem(e, JSON.stringify(r)), r;
268
270
  });
269
- } catch (c) {
270
- console.error(`Error setting localStorage key "${e}":`, c);
271
+ } catch (l) {
272
+ console.error(`Error setting localStorage key "${e}":`, l);
271
273
  }
272
274
  },
273
275
  [e]
274
276
  );
275
277
  return [t, i];
276
- }, O = (e, o) => {
278
+ }, Y = (e, o) => {
277
279
  const d = y(e);
278
280
  f(() => {
279
281
  d.current = e;
@@ -288,8 +290,8 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
288
290
  if (o)
289
291
  return t = setTimeout(n, o), () => t && clearTimeout(t);
290
292
  }, [o]);
291
- }, M = (e) => {
292
- const o = y([]), d = v(
293
+ }, C = (e) => {
294
+ const o = y([]), d = p(
293
295
  (n) => {
294
296
  if (o.current[n] && (o.current[n].scrollIntoView({
295
297
  behavior: "smooth",
@@ -305,11 +307,11 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
305
307
  }
306
308
  },
307
309
  [e]
308
- ), t = v((n, i) => {
310
+ ), t = p((n, i) => {
309
311
  o.current[i] = n;
310
312
  }, []);
311
313
  return { elementRefs: o, setElementRef: t, scrollToElement: d };
312
- }, Y = () => {
314
+ }, k = () => {
313
315
  const [e, o] = h({
314
316
  x: 0,
315
317
  y: 0,
@@ -320,19 +322,19 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
320
322
  });
321
323
  return f(() => {
322
324
  const d = () => {
323
- const s = window.scrollX || 0, c = window.scrollY || 0, r = /iPad|iPhone|iPod/.test(navigator.userAgent), l = window.visualViewport, u = r && l ? l.width : window.innerWidth, a = r && l ? l.height : window.innerHeight, m = Math.max(
325
+ const s = window.scrollX || 0, l = window.scrollY || 0, r = /iPad|iPhone|iPod/.test(navigator.userAgent), c = window.visualViewport, a = r && c ? c.width : window.innerWidth, u = r && c ? c.height : window.innerHeight, m = Math.max(
324
326
  0,
325
- document.documentElement.scrollWidth - u
326
- ), p = Math.max(
327
+ document.documentElement.scrollWidth - a
328
+ ), g = Math.max(
327
329
  0,
328
- document.documentElement.scrollHeight - a
329
- ), g = m === 0 ? 0 : Math.min(100, s / m * 100), b = p === 0 ? 0 : Math.min(100, c / p * 100);
330
+ document.documentElement.scrollHeight - u
331
+ ), v = m === 0 ? 0 : Math.min(100, s / m * 100), S = g === 0 ? 0 : Math.min(100, l / g * 100);
330
332
  o({
331
333
  x: s,
332
- y: c,
334
+ y: l,
333
335
  percent: {
334
- x: Math.floor(Math.max(0, g)),
335
- y: Math.floor(Math.max(0, b))
336
+ x: Math.floor(Math.max(0, v)),
337
+ y: Math.floor(Math.max(0, S))
336
338
  }
337
339
  });
338
340
  };
@@ -351,7 +353,7 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
351
353
  );
352
354
  };
353
355
  }, []), e;
354
- }, C = (e = {}) => {
356
+ }, B = (e = {}) => {
355
357
  const { isInApp: o = !1, debounce: d = 100 } = e, [t, n] = h({
356
358
  width: 0,
357
359
  height: 0,
@@ -360,15 +362,15 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
360
362
  pageLeft: 0,
361
363
  pageTop: 0,
362
364
  scale: 1
363
- }), i = v(() => {
364
- const c = window.innerHeight, r = window.visualViewport?.height || c, l = document.documentElement.clientHeight, u = document.body.clientHeight;
365
- return window.visualViewport && Math.abs(r - c) > 100 ? r : Math.max(c, l, u);
366
- }, []), s = v(() => {
365
+ }), i = p(() => {
366
+ const l = window.innerHeight, r = window.visualViewport?.height || l, c = document.documentElement.clientHeight, a = document.body.clientHeight;
367
+ return window.visualViewport && Math.abs(r - l) > 100 ? r : Math.max(l, c, a);
368
+ }, []), s = p(() => {
367
369
  if (window.visualViewport && !o)
368
370
  return window.visualViewport;
369
- const c = window.visualViewport?.width || window.innerWidth, r = o ? i() : window.visualViewport?.height || window.innerHeight;
371
+ const l = window.visualViewport?.width || window.innerWidth, r = o ? i() : window.visualViewport?.height || window.innerHeight;
370
372
  return {
371
- width: c,
373
+ width: l,
372
374
  height: r,
373
375
  offsetLeft: window.visualViewport?.offsetLeft || 0,
374
376
  offsetTop: window.visualViewport?.offsetTop || 0,
@@ -378,45 +380,45 @@ const x = (e, { delay: o = 100, autoInvoke: d = !0 }, t = []) => {
378
380
  };
379
381
  }, [o, i]);
380
382
  return f(() => {
381
- let c;
383
+ let l;
382
384
  const r = () => {
383
- clearTimeout(c), c = setTimeout(() => {
385
+ clearTimeout(l), l = setTimeout(() => {
384
386
  n(s());
385
387
  }, d);
386
- }, l = () => n(s());
387
- l();
388
- const u = ["resize", "orientationchange"];
389
- o && u.push("focus", "blur", "touchstart", "touchend"), u.forEach((m) => {
390
- m === "resize" || m === "orientationchange" ? window.addEventListener(m, r) : window.addEventListener(m, l, { passive: !0 });
391
- }), window.visualViewport && (window.visualViewport.addEventListener("resize", l), window.visualViewport.addEventListener("scroll", l));
392
- let a;
388
+ }, c = () => n(s());
389
+ c();
390
+ const a = ["resize", "orientationchange"];
391
+ o && a.push("focus", "blur", "touchstart", "touchend"), a.forEach((m) => {
392
+ m === "resize" || m === "orientationchange" ? window.addEventListener(m, r) : window.addEventListener(m, c, { passive: !0 });
393
+ }), window.visualViewport && (window.visualViewport.addEventListener("resize", c), window.visualViewport.addEventListener("scroll", c));
394
+ let u;
393
395
  if (o) {
394
396
  let m = s().height;
395
- a = setInterval(() => {
396
- const p = s().height;
397
- Math.abs(p - m) > 50 && (m = p, l());
397
+ u = setInterval(() => {
398
+ const g = s().height;
399
+ Math.abs(g - m) > 50 && (m = g, c());
398
400
  }, 500);
399
401
  }
400
402
  return () => {
401
- clearTimeout(c), a && clearInterval(a), u.forEach((m) => {
403
+ clearTimeout(l), u && clearInterval(u), a.forEach((m) => {
402
404
  window.removeEventListener(
403
405
  m,
404
- m === "resize" || m === "orientationchange" ? r : l
406
+ m === "resize" || m === "orientationchange" ? r : c
405
407
  );
406
- }), window.visualViewport && (window.visualViewport.removeEventListener("resize", l), window.visualViewport.removeEventListener("scroll", l));
408
+ }), window.visualViewport && (window.visualViewport.removeEventListener("resize", c), window.visualViewport.removeEventListener("scroll", c));
407
409
  };
408
410
  }, [s, o, d]), t;
409
411
  };
410
412
  export {
411
- z as useBodyScrollLock,
412
- x as useDebounce,
413
- H as useElementPosition,
414
- I as useElementScroll,
415
- R as useImage,
416
- A as useLocalStorage,
417
- O as useRecursiveTimeout,
418
- P as useResponsiveSize,
419
- M as useScrollToElements,
420
- C as useViewport,
421
- Y as useWindowScroll
413
+ I as useBodyScrollLock,
414
+ V as useDebounce,
415
+ P as useElementPosition,
416
+ R as useElementScroll,
417
+ O as useImage,
418
+ M as useLocalStorage,
419
+ Y as useRecursiveTimeout,
420
+ A as useResponsiveSize,
421
+ C as useScrollToElements,
422
+ B as useViewport,
423
+ k as useWindowScroll
422
424
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbpark/use-hooks",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "A collection of reusable React 19 hooks for common UI and interaction patterns",
5
5
  "keywords": [
6
6
  "react",