@jbpark/use-hooks 2.2.0 → 2.3.0

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.
Files changed (63) hide show
  1. package/README.ko.md +23 -29
  2. package/README.md +23 -29
  3. package/dist/hooks/index.d.mts +14 -13
  4. package/dist/hooks/index.mjs +14 -13
  5. package/dist/hooks/{useBodyScrollLock/index.d.mts → use-body-scroll-lock.d.mts} +2 -2
  6. package/dist/hooks/{useBodyScrollLock/index.mjs → use-body-scroll-lock.mjs} +46 -37
  7. package/dist/hooks/use-body-scroll-lock.mjs.map +1 -0
  8. package/dist/hooks/use-click-outside.d.mts +7 -0
  9. package/dist/hooks/use-click-outside.mjs +29 -0
  10. package/dist/hooks/use-click-outside.mjs.map +1 -0
  11. package/dist/hooks/{useDebounce/index.d.mts → use-debounce.d.mts} +2 -2
  12. package/dist/hooks/{useDebounce/index.mjs → use-debounce.mjs} +2 -6
  13. package/dist/hooks/use-debounce.mjs.map +1 -0
  14. package/dist/hooks/{useElementPosition/index.d.mts → use-element-position.d.mts} +2 -2
  15. package/dist/hooks/{useElementPosition/index.mjs → use-element-position.mjs} +2 -2
  16. package/dist/hooks/use-element-position.mjs.map +1 -0
  17. package/dist/hooks/{useElementScroll/index.d.mts → use-element-scroll.d.mts} +2 -2
  18. package/dist/hooks/{useElementScroll/index.mjs → use-element-scroll.mjs} +2 -2
  19. package/dist/hooks/use-element-scroll.mjs.map +1 -0
  20. package/dist/hooks/{useImage/index.d.mts → use-image.d.mts} +2 -2
  21. package/dist/hooks/{useImage/index.mjs → use-image.mjs} +20 -12
  22. package/dist/hooks/use-image.mjs.map +1 -0
  23. package/dist/hooks/{useLocalStorage/index.d.mts → use-local-storage.d.mts} +2 -2
  24. package/dist/hooks/{useLocalStorage/index.mjs → use-local-storage.mjs} +20 -4
  25. package/dist/hooks/use-local-storage.mjs.map +1 -0
  26. package/dist/hooks/{useRecursiveTimeout/index.d.mts → use-recursive-timeout.d.mts} +2 -2
  27. package/dist/hooks/{useRecursiveTimeout/index.mjs → use-recursive-timeout.mjs} +5 -3
  28. package/dist/hooks/use-recursive-timeout.mjs.map +1 -0
  29. package/dist/hooks/{useResponsiveSize/index.d.mts → use-responsive-size.d.mts} +2 -2
  30. package/dist/hooks/{useResponsiveSize/index.mjs → use-responsive-size.mjs} +3 -3
  31. package/dist/hooks/use-responsive-size.mjs.map +1 -0
  32. package/dist/hooks/{useScrollToElements/index.d.mts → use-scroll-to-elements.d.mts} +4 -4
  33. package/dist/hooks/use-scroll-to-elements.mjs +34 -0
  34. package/dist/hooks/use-scroll-to-elements.mjs.map +1 -0
  35. package/dist/hooks/{useThrottle/index.d.mts → use-throttle.d.mts} +2 -2
  36. package/dist/hooks/{useThrottle/index.mjs → use-throttle.mjs} +2 -2
  37. package/dist/hooks/use-throttle.mjs.map +1 -0
  38. package/dist/hooks/{useTimeline/index.d.mts → use-timeline.d.mts} +2 -2
  39. package/dist/hooks/{useTimeline/index.mjs → use-timeline.mjs} +4 -3
  40. package/dist/hooks/use-timeline.mjs.map +1 -0
  41. package/dist/hooks/{useViewport/index.d.mts → use-viewport.d.mts} +2 -2
  42. package/dist/hooks/{useViewport/index.mjs → use-viewport.mjs} +2 -2
  43. package/dist/hooks/use-viewport.mjs.map +1 -0
  44. package/dist/hooks/{useWindowScroll/index.d.mts → use-window-scroll.d.mts} +2 -2
  45. package/dist/hooks/{useWindowScroll/index.mjs → use-window-scroll.mjs} +2 -2
  46. package/dist/hooks/use-window-scroll.mjs.map +1 -0
  47. package/dist/index.d.mts +15 -14
  48. package/dist/index.mjs +15 -14
  49. package/package.json +16 -10
  50. package/dist/hooks/useBodyScrollLock/index.mjs.map +0 -1
  51. package/dist/hooks/useDebounce/index.mjs.map +0 -1
  52. package/dist/hooks/useElementPosition/index.mjs.map +0 -1
  53. package/dist/hooks/useElementScroll/index.mjs.map +0 -1
  54. package/dist/hooks/useImage/index.mjs.map +0 -1
  55. package/dist/hooks/useLocalStorage/index.mjs.map +0 -1
  56. package/dist/hooks/useRecursiveTimeout/index.mjs.map +0 -1
  57. package/dist/hooks/useResponsiveSize/index.mjs.map +0 -1
  58. package/dist/hooks/useScrollToElements/index.mjs +0 -34
  59. package/dist/hooks/useScrollToElements/index.mjs.map +0 -1
  60. package/dist/hooks/useThrottle/index.mjs.map +0 -1
  61. package/dist/hooks/useTimeline/index.mjs.map +0 -1
  62. package/dist/hooks/useViewport/index.mjs.map +0 -1
  63. package/dist/hooks/useWindowScroll/index.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-image.mjs","names":[],"sources":["../../src/hooks/use-image.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ninterface Options {\n retryCount?: number;\n retryDelay?: number;\n}\n\nconst useImage = (src: string, options: Options = {}) => {\n const { retryCount = 0, retryDelay = 1000 } = options;\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | Event | null>(null);\n const [loaded, setLoaded] = useState(false);\n const [attemptCount, setAttemptCount] = useState(0);\n const [reloadToken, setReloadToken] = useState(0);\n\n useEffect(() => {\n if (!src) {\n setLoading(false);\n setLoaded(false);\n return;\n }\n\n let cancelled = false;\n let retryTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n setLoading(true);\n setError(null);\n\n const img = new Image();\n img.src = src;\n\n img.onload = () => {\n if (cancelled) {\n return;\n }\n setLoading(false);\n setLoaded(true);\n setError(null);\n };\n\n img.onerror = err => {\n if (cancelled) {\n return;\n }\n setLoading(false);\n setLoaded(false);\n setError(err);\n\n if (attemptCount < retryCount) {\n retryTimeoutId = setTimeout(() => {\n if (!cancelled) {\n setAttemptCount(prev => prev + 1);\n }\n }, retryDelay);\n }\n };\n\n return () => {\n cancelled = true;\n img.onload = null;\n img.onerror = null;\n if (retryTimeoutId) {\n clearTimeout(retryTimeoutId);\n }\n };\n }, [src, attemptCount, retryCount, retryDelay, reloadToken]);\n\n const retry = useCallback(() => {\n setAttemptCount(0);\n setReloadToken(token => token + 1);\n }, []);\n\n return {\n loading,\n error,\n loaded,\n retry,\n };\n};\n\nexport default useImage;\n"],"mappings":";;;AAOA,MAAM,YAAY,KAAa,UAAmB,EAAE,KAAK;CACvD,MAAM,EAAE,aAAa,GAAG,aAAa,QAAS;CAE9C,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAgC,KAAK;CAC/D,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CACnD,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;AAEjD,iBAAgB;AACd,MAAI,CAAC,KAAK;AACR,cAAW,MAAM;AACjB,aAAU,MAAM;AAChB;;EAGF,IAAI,YAAY;EAChB,IAAI;AAEJ,aAAW,KAAK;AAChB,WAAS,KAAK;EAEd,MAAM,MAAM,IAAI,OAAO;AACvB,MAAI,MAAM;AAEV,MAAI,eAAe;AACjB,OAAI,UACF;AAEF,cAAW,MAAM;AACjB,aAAU,KAAK;AACf,YAAS,KAAK;;AAGhB,MAAI,WAAU,QAAO;AACnB,OAAI,UACF;AAEF,cAAW,MAAM;AACjB,aAAU,MAAM;AAChB,YAAS,IAAI;AAEb,OAAI,eAAe,WACjB,kBAAiB,iBAAiB;AAChC,QAAI,CAAC,UACH,kBAAgB,SAAQ,OAAO,EAAE;MAElC,WAAW;;AAIlB,eAAa;AACX,eAAY;AACZ,OAAI,SAAS;AACb,OAAI,UAAU;AACd,OAAI,eACF,cAAa,eAAe;;IAG/B;EAAC;EAAK;EAAc;EAAY;EAAY;EAAY,CAAC;AAO5D,QAAO;EACL;EACA;EACA;EACA,OATY,kBAAkB;AAC9B,mBAAgB,EAAE;AAClB,mBAAe,UAAS,QAAQ,EAAE;KACjC,EAAE,CAAC;EAOL"}
@@ -1,5 +1,5 @@
1
- //#region src/hooks/useLocalStorage/index.d.ts
1
+ //#region src/hooks/use-local-storage.d.ts
2
2
  declare const useLocalStorage: <T>(key: string, initialValue: T) => readonly [T, (value: T | ((val: T) => T)) => void];
3
3
  //#endregion
4
4
  export { useLocalStorage };
5
- //# sourceMappingURL=index.d.mts.map
5
+ //# sourceMappingURL=use-local-storage.d.mts.map
@@ -1,8 +1,11 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
2
 
3
- //#region src/hooks/useLocalStorage/index.ts
3
+ //#region src/hooks/use-local-storage.ts
4
4
  const useLocalStorage = (key, initialValue) => {
5
- const initialRef = useRef(initialValue);
5
+ const initialValueRef = useRef(initialValue);
6
+ useEffect(() => {
7
+ initialValueRef.current = initialValue;
8
+ });
6
9
  const [storedValue, setStoredValue] = useState(() => {
7
10
  if (typeof window === "undefined") return initialValue;
8
11
  try {
@@ -17,11 +20,24 @@ const useLocalStorage = (key, initialValue) => {
17
20
  try {
18
21
  const item = window.localStorage.getItem(key);
19
22
  if (item) setStoredValue(JSON.parse(item));
20
- else window.localStorage.setItem(key, JSON.stringify(initialRef.current));
23
+ else window.localStorage.setItem(key, JSON.stringify(initialValueRef.current));
21
24
  } catch (e) {
22
25
  console.error(`Error reading localStorage key "${key}":`, e);
23
26
  }
24
27
  }, [key]);
28
+ useEffect(() => {
29
+ if (typeof window === "undefined") return;
30
+ const onStorage = (event) => {
31
+ if (event.key !== key) return;
32
+ try {
33
+ setStoredValue(event.newValue ? JSON.parse(event.newValue) : initialValueRef.current);
34
+ } catch (e) {
35
+ console.error(`Error parsing localStorage key "${key}" from storage event:`, e);
36
+ }
37
+ };
38
+ window.addEventListener("storage", onStorage);
39
+ return () => window.removeEventListener("storage", onStorage);
40
+ }, [key]);
25
41
  return [storedValue, useCallback((value) => {
26
42
  try {
27
43
  setStoredValue((prev) => {
@@ -37,4 +53,4 @@ const useLocalStorage = (key, initialValue) => {
37
53
 
38
54
  //#endregion
39
55
  export { useLocalStorage as default };
40
- //# sourceMappingURL=index.mjs.map
56
+ //# sourceMappingURL=use-local-storage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-local-storage.mjs","names":[],"sources":["../../src/hooks/use-local-storage.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst useLocalStorage = <T>(key: string, initialValue: T) => {\n const initialValueRef = useRef(initialValue);\n\n useEffect(() => {\n initialValueRef.current = initialValue;\n });\n\n const [storedValue, setStoredValue] = useState<T>(() => {\n if (typeof window === 'undefined') {\n return initialValue;\n }\n try {\n const item = window.localStorage.getItem(key);\n return item ? (JSON.parse(item) as T) : initialValue;\n } catch {\n return initialValue;\n }\n });\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n try {\n const item = window.localStorage.getItem(key);\n if (item) {\n setStoredValue(JSON.parse(item) as T);\n } else {\n window.localStorage.setItem(\n key,\n JSON.stringify(initialValueRef.current),\n );\n }\n } catch (e) {\n console.error(`Error reading localStorage key \"${key}\":`, e);\n }\n }, [key]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const onStorage = (event: StorageEvent) => {\n if (event.key !== key) {\n return;\n }\n\n try {\n setStoredValue(\n event.newValue\n ? (JSON.parse(event.newValue) as T)\n : initialValueRef.current,\n );\n } catch (e) {\n console.error(\n `Error parsing localStorage key \"${key}\" from storage event:`,\n e,\n );\n }\n };\n\n window.addEventListener('storage', onStorage);\n return () => window.removeEventListener('storage', onStorage);\n }, [key]);\n\n const setValue = useCallback(\n (value: T | ((val: T) => T)) => {\n try {\n setStoredValue(prev => {\n const valueToStore = value instanceof Function ? value(prev) : value;\n localStorage.setItem(key, JSON.stringify(valueToStore));\n return valueToStore;\n });\n } catch (e) {\n console.error(`Error setting localStorage key \"${key}\":`, e);\n }\n },\n [key],\n );\n\n return [storedValue, setValue] as const;\n};\n\nexport default useLocalStorage;\n"],"mappings":";;;AAEA,MAAM,mBAAsB,KAAa,iBAAoB;CAC3D,MAAM,kBAAkB,OAAO,aAAa;AAE5C,iBAAgB;AACd,kBAAgB,UAAU;GAC1B;CAEF,MAAM,CAAC,aAAa,kBAAkB,eAAkB;AACtD,MAAI,OAAO,WAAW,YACpB,QAAO;AAET,MAAI;GACF,MAAM,OAAO,OAAO,aAAa,QAAQ,IAAI;AAC7C,UAAO,OAAQ,KAAK,MAAM,KAAK,GAAS;UAClC;AACN,UAAO;;GAET;AAEF,iBAAgB;AACd,MAAI,OAAO,WAAW,YACpB;AAGF,MAAI;GACF,MAAM,OAAO,OAAO,aAAa,QAAQ,IAAI;AAC7C,OAAI,KACF,gBAAe,KAAK,MAAM,KAAK,CAAM;OAErC,QAAO,aAAa,QAClB,KACA,KAAK,UAAU,gBAAgB,QAAQ,CACxC;WAEI,GAAG;AACV,WAAQ,MAAM,mCAAmC,IAAI,KAAK,EAAE;;IAE7D,CAAC,IAAI,CAAC;AAET,iBAAgB;AACd,MAAI,OAAO,WAAW,YACpB;EAGF,MAAM,aAAa,UAAwB;AACzC,OAAI,MAAM,QAAQ,IAChB;AAGF,OAAI;AACF,mBACE,MAAM,WACD,KAAK,MAAM,MAAM,SAAS,GAC3B,gBAAgB,QACrB;YACM,GAAG;AACV,YAAQ,MACN,mCAAmC,IAAI,wBACvC,EACD;;;AAIL,SAAO,iBAAiB,WAAW,UAAU;AAC7C,eAAa,OAAO,oBAAoB,WAAW,UAAU;IAC5D,CAAC,IAAI,CAAC;AAiBT,QAAO,CAAC,aAfS,aACd,UAA+B;AAC9B,MAAI;AACF,mBAAe,SAAQ;IACrB,MAAM,eAAe,iBAAiB,WAAW,MAAM,KAAK,GAAG;AAC/D,iBAAa,QAAQ,KAAK,KAAK,UAAU,aAAa,CAAC;AACvD,WAAO;KACP;WACK,GAAG;AACV,WAAQ,MAAM,mCAAmC,IAAI,KAAK,EAAE;;IAGhE,CAAC,IAAI,CACN,CAE6B"}
@@ -1,5 +1,5 @@
1
- //#region src/hooks/useRecursiveTimeout/index.d.ts
1
+ //#region src/hooks/use-recursive-timeout.d.ts
2
2
  declare const useRecursiveTimeout: <T>(callback: () => Promise<T> | (() => void), delay: number | null) => void;
3
3
  //#endregion
4
4
  export { useRecursiveTimeout };
5
- //# sourceMappingURL=index.d.mts.map
5
+ //# sourceMappingURL=use-recursive-timeout.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useRef } from "react";
2
2
 
3
- //#region src/hooks/useRecursiveTimeout/index.ts
3
+ //#region src/hooks/use-recursive-timeout.ts
4
4
  const useRecursiveTimeout = (callback, delay) => {
5
5
  const savedCallback = useRef(callback);
6
6
  useEffect(() => {
@@ -17,11 +17,13 @@ const useRecursiveTimeout = (callback, delay) => {
17
17
  }
18
18
  if (delay) {
19
19
  id = setTimeout(tick, delay);
20
- return () => id && clearTimeout(id);
20
+ return () => {
21
+ clearTimeout(id);
22
+ };
21
23
  }
22
24
  }, [delay]);
23
25
  };
24
26
 
25
27
  //#endregion
26
28
  export { useRecursiveTimeout as default };
27
- //# sourceMappingURL=index.mjs.map
29
+ //# sourceMappingURL=use-recursive-timeout.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-recursive-timeout.mjs","names":[],"sources":["../../src/hooks/use-recursive-timeout.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nconst useRecursiveTimeout = <T>(\n callback: () => Promise<T> | (() => void),\n delay: number | null,\n) => {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n let id: ReturnType<typeof setTimeout>;\n\n function tick() {\n const ret = savedCallback.current();\n\n if (ret instanceof Promise) {\n ret.then(() => {\n if (delay) {\n id = setTimeout(tick, delay);\n }\n });\n } else {\n if (delay) {\n id = setTimeout(tick, delay);\n }\n }\n }\n\n if (delay) {\n id = setTimeout(tick, delay);\n return () => {\n clearTimeout(id);\n };\n }\n }, [delay]);\n};\n\nexport default useRecursiveTimeout;\n"],"mappings":";;;AAEA,MAAM,uBACJ,UACA,UACG;CACH,MAAM,gBAAgB,OAAO,SAAS;AAEtC,iBAAgB;AACd,gBAAc,UAAU;IACvB,CAAC,SAAS,CAAC;AAEd,iBAAgB;EACd,IAAI;EAEJ,SAAS,OAAO;GACd,MAAM,MAAM,cAAc,SAAS;AAEnC,OAAI,eAAe,QACjB,KAAI,WAAW;AACb,QAAI,MACF,MAAK,WAAW,MAAM,MAAM;KAE9B;YAEE,MACF,MAAK,WAAW,MAAM,MAAM;;AAKlC,MAAI,OAAO;AACT,QAAK,WAAW,MAAM,MAAM;AAC5B,gBAAa;AACX,iBAAa,GAAG;;;IAGnB,CAAC,MAAM,CAAC"}
@@ -1,4 +1,4 @@
1
- //#region src/hooks/useResponsiveSize/index.d.ts
1
+ //#region src/hooks/use-responsive-size.d.ts
2
2
  type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
3
3
  interface BreakpointInfo {
4
4
  current: Breakpoint;
@@ -23,4 +23,4 @@ declare const useResponsiveSize: <T extends HTMLElement>(options?: Options) => {
23
23
  };
24
24
  //#endregion
25
25
  export { useResponsiveSize };
26
- //# sourceMappingURL=index.d.mts.map
26
+ //# sourceMappingURL=use-responsive-size.d.mts.map
@@ -1,7 +1,7 @@
1
- import useDebounce from "../useDebounce/index.mjs";
1
+ import useDebounce from "./use-debounce.mjs";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
 
4
- //#region src/hooks/useResponsiveSize/index.ts
4
+ //#region src/hooks/use-responsive-size.ts
5
5
  const BREAKPOINTS = {
6
6
  xs: 0,
7
7
  sm: 640,
@@ -105,4 +105,4 @@ const useResponsiveSize = (options) => {
105
105
 
106
106
  //#endregion
107
107
  export { useResponsiveSize as default };
108
- //# sourceMappingURL=index.mjs.map
108
+ //# sourceMappingURL=use-responsive-size.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-responsive-size.mjs","names":[],"sources":["../../src/hooks/use-responsive-size.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport useDebounce from './use-debounce';\n\ntype Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\ninterface BreakpointInfo {\n current: Breakpoint;\n xs: boolean;\n sm: boolean;\n md: boolean;\n lg: boolean;\n xl: boolean;\n '2xl': boolean;\n}\n\ninterface Options {\n delay?: number;\n container?: HTMLElement | null;\n}\n\nconst BREAKPOINTS = {\n xs: 0, // < 640px\n sm: 640, // >= 640px\n md: 768, // >= 768px\n lg: 1024, // >= 1024px\n xl: 1280, // >= 1280px\n '2xl': 1536, // >= 1536px\n} as const;\n\nconst getBreakpointInfo = (width: number): BreakpointInfo => {\n let current: Breakpoint = 'xs';\n\n if (width >= BREAKPOINTS['2xl']) {\n current = '2xl';\n } else if (width >= BREAKPOINTS.xl) {\n current = 'xl';\n } else if (width >= BREAKPOINTS.lg) {\n current = 'lg';\n } else if (width >= BREAKPOINTS.md) {\n current = 'md';\n } else if (width >= BREAKPOINTS.sm) {\n current = 'sm';\n } else {\n current = 'xs';\n }\n\n return {\n current,\n xs: width < BREAKPOINTS.sm,\n sm: width >= BREAKPOINTS.sm && width < BREAKPOINTS.md,\n md: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,\n lg: width >= BREAKPOINTS.lg && width < BREAKPOINTS.xl,\n xl: width >= BREAKPOINTS.xl && width < BREAKPOINTS['2xl'],\n '2xl': width >= BREAKPOINTS['2xl'],\n };\n};\n\nconst useResponsiveSize = <T extends HTMLElement>(options?: Options) => {\n const { delay = 100, container } = options || {};\n const [size, setSize] = useState({ width: 0, height: 0 });\n const [breakpoint, setBreakpoint] = useState<BreakpointInfo>({\n current: 'xs',\n xs: true,\n sm: false,\n md: false,\n lg: false,\n xl: false,\n '2xl': false,\n });\n\n const [debouncedSize, setDebouncedSize] = useState({ width: 0, height: 0 });\n\n const [element, setElement] = useState<T | null>(null);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n const ref = useCallback((node: T | null) => {\n setElement(node);\n }, []);\n\n useDebounce(\n () => {\n setDebouncedSize(size);\n },\n { delay },\n [size],\n );\n\n useEffect(() => {\n const updateSize = () => {\n const target = container ?? element ?? document.body;\n\n if (!target) {\n return;\n }\n\n const { offsetWidth, offsetHeight } = target;\n\n setSize(prev => {\n if (prev.width !== offsetWidth || prev.height !== offsetHeight) {\n return { width: offsetWidth, height: offsetHeight };\n }\n return prev;\n });\n\n setBreakpoint(prev => {\n const next = getBreakpointInfo(offsetWidth);\n if (prev.current !== next.current) {\n return next;\n }\n return prev;\n });\n };\n\n const connect = () => {\n const target = container ?? element ?? document.body;\n\n if (!target) {\n return;\n }\n\n updateSize();\n\n if (observerRef.current) {\n observerRef.current.disconnect();\n }\n\n observerRef.current = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n updateSize();\n });\n });\n\n observerRef.current.observe(target);\n };\n\n const disconnect = () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n\n connect();\n\n return () => {\n disconnect();\n };\n }, [container, element]);\n\n return {\n size: debouncedSize,\n breakpoint,\n ref,\n };\n};\n\nexport default useResponsiveSize;\n"],"mappings":";;;;AAqBA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACR;AAED,MAAM,qBAAqB,UAAkC;CAC3D,IAAI,UAAsB;AAE1B,KAAI,SAAS,YAAY,OACvB,WAAU;UACD,SAAS,YAAY,GAC9B,WAAU;UACD,SAAS,YAAY,GAC9B,WAAU;UACD,SAAS,YAAY,GAC9B,WAAU;UACD,SAAS,YAAY,GAC9B,WAAU;KAEV,WAAU;AAGZ,QAAO;EACL;EACA,IAAI,QAAQ,YAAY;EACxB,IAAI,SAAS,YAAY,MAAM,QAAQ,YAAY;EACnD,IAAI,SAAS,YAAY,MAAM,QAAQ,YAAY;EACnD,IAAI,SAAS,YAAY,MAAM,QAAQ,YAAY;EACnD,IAAI,SAAS,YAAY,MAAM,QAAQ,YAAY;EACnD,OAAO,SAAS,YAAY;EAC7B;;AAGH,MAAM,qBAA4C,YAAsB;CACtE,MAAM,EAAE,QAAQ,KAAK,cAAc,WAAW,EAAE;CAChD,MAAM,CAAC,MAAM,WAAW,SAAS;EAAE,OAAO;EAAG,QAAQ;EAAG,CAAC;CACzD,MAAM,CAAC,YAAY,iBAAiB,SAAyB;EAC3D,SAAS;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;EACR,CAAC;CAEF,MAAM,CAAC,eAAe,oBAAoB,SAAS;EAAE,OAAO;EAAG,QAAQ;EAAG,CAAC;CAE3E,MAAM,CAAC,SAAS,cAAc,SAAmB,KAAK;CACtD,MAAM,cAAc,OAA8B,KAAK;CAEvD,MAAM,MAAM,aAAa,SAAmB;AAC1C,aAAW,KAAK;IACf,EAAE,CAAC;AAEN,mBACQ;AACJ,mBAAiB,KAAK;IAExB,EAAE,OAAO,EACT,CAAC,KAAK,CACP;AAED,iBAAgB;EACd,MAAM,mBAAmB;GACvB,MAAM,SAAS,aAAa,WAAW,SAAS;AAEhD,OAAI,CAAC,OACH;GAGF,MAAM,EAAE,aAAa,iBAAiB;AAEtC,YAAQ,SAAQ;AACd,QAAI,KAAK,UAAU,eAAe,KAAK,WAAW,aAChD,QAAO;KAAE,OAAO;KAAa,QAAQ;KAAc;AAErD,WAAO;KACP;AAEF,kBAAc,SAAQ;IACpB,MAAM,OAAO,kBAAkB,YAAY;AAC3C,QAAI,KAAK,YAAY,KAAK,QACxB,QAAO;AAET,WAAO;KACP;;EAGJ,MAAM,gBAAgB;GACpB,MAAM,SAAS,aAAa,WAAW,SAAS;AAEhD,OAAI,CAAC,OACH;AAGF,eAAY;AAEZ,OAAI,YAAY,QACd,aAAY,QAAQ,YAAY;AAGlC,eAAY,UAAU,IAAI,qBAAqB;AAC7C,gCAA4B;AAC1B,iBAAY;MACZ;KACF;AAEF,eAAY,QAAQ,QAAQ,OAAO;;EAGrC,MAAM,mBAAmB;AACvB,OAAI,YAAY,SAAS;AACvB,gBAAY,QAAQ,YAAY;AAChC,gBAAY,UAAU;;;AAI1B,WAAS;AAET,eAAa;AACX,eAAY;;IAEb,CAAC,WAAW,QAAQ,CAAC;AAExB,QAAO;EACL,MAAM;EACN;EACA;EACD"}
@@ -1,14 +1,14 @@
1
1
  import * as react from "react";
2
2
 
3
- //#region src/hooks/useScrollToElements/index.d.ts
3
+ //#region src/hooks/use-scroll-to-elements.d.ts
4
4
  interface Options extends ScrollIntoViewOptions {
5
5
  offset?: number;
6
6
  }
7
7
  declare const useScrollToElements: (options?: Options) => {
8
- elementRefs: react.RefObject<HTMLElement[]>;
9
- setElementRef: (element: HTMLElement, index: number) => void;
8
+ elementRefs: react.RefObject<(HTMLElement | null)[]>;
9
+ setElementRef: (element: HTMLElement | null, index: number) => void;
10
10
  scrollToElement: (index: number) => void;
11
11
  };
12
12
  //#endregion
13
13
  export { useScrollToElements };
14
- //# sourceMappingURL=index.d.mts.map
14
+ //# sourceMappingURL=use-scroll-to-elements.d.mts.map
@@ -0,0 +1,34 @@
1
+ import { useCallback, useRef } from "react";
2
+
3
+ //#region src/hooks/use-scroll-to-elements.ts
4
+ const useScrollToElements = (options) => {
5
+ const elementRefs = useRef([]);
6
+ const scrollToElement = useCallback((index) => {
7
+ const element = elementRefs.current[index];
8
+ if (!element) return;
9
+ element.scrollIntoView({
10
+ behavior: "smooth",
11
+ block: "start",
12
+ inline: "start",
13
+ ...options
14
+ });
15
+ if (options?.offset) {
16
+ const top = element.getBoundingClientRect().top + window.scrollY - options.offset;
17
+ window.scrollTo({
18
+ top,
19
+ behavior: options.behavior || "smooth"
20
+ });
21
+ }
22
+ }, [options]);
23
+ return {
24
+ elementRefs,
25
+ setElementRef: useCallback((element, index) => {
26
+ elementRefs.current[index] = element;
27
+ }, []),
28
+ scrollToElement
29
+ };
30
+ };
31
+
32
+ //#endregion
33
+ export { useScrollToElements as default };
34
+ //# sourceMappingURL=use-scroll-to-elements.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-scroll-to-elements.mjs","names":[],"sources":["../../src/hooks/use-scroll-to-elements.ts"],"sourcesContent":["import { useCallback, useRef } from 'react';\n\ninterface Options extends ScrollIntoViewOptions {\n offset?: number;\n}\nconst useScrollToElements = (options?: Options) => {\n const elementRefs = useRef<(HTMLElement | null)[]>([]);\n\n const scrollToElement = useCallback(\n (index: number) => {\n const element = elementRefs.current[index];\n\n if (!element) {\n return;\n }\n\n element.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n inline: 'start',\n ...options,\n });\n\n if (options?.offset) {\n const top =\n element.getBoundingClientRect().top + window.scrollY - options.offset;\n\n window.scrollTo({\n top,\n behavior: options.behavior || 'smooth',\n });\n }\n },\n [options],\n );\n\n const setElementRef = useCallback(\n (element: HTMLElement | null, index: number) => {\n elementRefs.current[index] = element;\n },\n [],\n );\n\n return { elementRefs, setElementRef, scrollToElement };\n};\n\nexport default useScrollToElements;\n"],"mappings":";;;AAKA,MAAM,uBAAuB,YAAsB;CACjD,MAAM,cAAc,OAA+B,EAAE,CAAC;CAEtD,MAAM,kBAAkB,aACrB,UAAkB;EACjB,MAAM,UAAU,YAAY,QAAQ;AAEpC,MAAI,CAAC,QACH;AAGF,UAAQ,eAAe;GACrB,UAAU;GACV,OAAO;GACP,QAAQ;GACR,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS,QAAQ;GACnB,MAAM,MACJ,QAAQ,uBAAuB,CAAC,MAAM,OAAO,UAAU,QAAQ;AAEjE,UAAO,SAAS;IACd;IACA,UAAU,QAAQ,YAAY;IAC/B,CAAC;;IAGN,CAAC,QAAQ,CACV;AASD,QAAO;EAAE;EAAa,eAPA,aACnB,SAA6B,UAAkB;AAC9C,eAAY,QAAQ,SAAS;KAE/B,EAAE,CACH;EAEoC;EAAiB"}
@@ -1,5 +1,5 @@
1
- //#region src/hooks/useThrottle/index.d.ts
1
+ //#region src/hooks/use-throttle.d.ts
2
2
  declare const useThrottle: <T>(value: T, delay?: number) => T;
3
3
  //#endregion
4
4
  export { useThrottle };
5
- //# sourceMappingURL=index.d.mts.map
5
+ //# sourceMappingURL=use-throttle.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useRef, useState } from "react";
2
2
 
3
- //#region src/hooks/useThrottle/index.ts
3
+ //#region src/hooks/use-throttle.ts
4
4
  const useThrottle = (value, delay = 100) => {
5
5
  const [throttledValue, setThrottledValue] = useState(value);
6
6
  const lastExecutedRef = useRef(0);
@@ -39,4 +39,4 @@ const useThrottle = (value, delay = 100) => {
39
39
 
40
40
  //#endregion
41
41
  export { useThrottle as default };
42
- //# sourceMappingURL=index.mjs.map
42
+ //# sourceMappingURL=use-throttle.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-throttle.mjs","names":[],"sources":["../../src/hooks/use-throttle.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\nconst useThrottle = <T>(value: T, delay = 100): T => {\n const [throttledValue, setThrottledValue] = useState(value);\n const lastExecutedRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestValueRef = useRef(value);\n\n useEffect(() => {\n latestValueRef.current = value;\n }, [value]);\n\n useEffect(() => {\n const now = Date.now();\n const elapsed = now - lastExecutedRef.current;\n\n if (elapsed >= delay) {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n\n lastExecutedRef.current = now;\n setThrottledValue(latestValueRef.current);\n return;\n }\n\n const remaining = delay - elapsed;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n lastExecutedRef.current = Date.now();\n setThrottledValue(latestValueRef.current);\n }, remaining);\n\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n };\n }, [value, delay]);\n\n return throttledValue;\n};\n\nexport default useThrottle;\n"],"mappings":";;;AAEA,MAAM,eAAkB,OAAU,QAAQ,QAAW;CACnD,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,MAAM;CAC3D,MAAM,kBAAkB,OAAO,EAAE;CACjC,MAAM,aAAa,OAA6C,KAAK;CACrE,MAAM,iBAAiB,OAAO,MAAM;AAEpC,iBAAgB;AACd,iBAAe,UAAU;IACxB,CAAC,MAAM,CAAC;AAEX,iBAAgB;EACd,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,UAAU,MAAM,gBAAgB;AAEtC,MAAI,WAAW,OAAO;AACpB,OAAI,WAAW,SAAS;AACtB,iBAAa,WAAW,QAAQ;AAChC,eAAW,UAAU;;AAGvB,mBAAgB,UAAU;AAC1B,qBAAkB,eAAe,QAAQ;AACzC;;EAGF,MAAM,YAAY,QAAQ;AAE1B,MAAI,WAAW,QACb,cAAa,WAAW,QAAQ;AAGlC,aAAW,UAAU,iBAAiB;AACpC,mBAAgB,UAAU,KAAK,KAAK;AACpC,qBAAkB,eAAe,QAAQ;KACxC,UAAU;AAEb,eAAa;AACX,OAAI,WAAW,SAAS;AACtB,iBAAa,WAAW,QAAQ;AAChC,eAAW,UAAU;;;IAGxB,CAAC,OAAO,MAAM,CAAC;AAElB,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import * as react from "react";
2
2
 
3
- //#region src/hooks/useTimeline/index.d.ts
3
+ //#region src/hooks/use-timeline.d.ts
4
4
  interface TimelineStep {
5
5
  scale?: number;
6
6
  rotate?: {
@@ -47,4 +47,4 @@ declare const useTimeline: ({
47
47
  };
48
48
  //#endregion
49
49
  export { useTimeline };
50
- //# sourceMappingURL=index.d.mts.map
50
+ //# sourceMappingURL=use-timeline.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
2
 
3
- //#region src/hooks/useTimeline/index.ts
3
+ //#region src/hooks/use-timeline.ts
4
4
  const registeredProperties = /* @__PURE__ */ new Set();
5
5
  const registerCSSProperty = (name, syntax = "<length>", initialValue = "0px") => {
6
6
  if (registeredProperties.has(name) || typeof CSS === "undefined" || !CSS.registerProperty) return;
@@ -136,13 +136,14 @@ const useTimeline = ({ steps = [], loading, immediate, loop }) => {
136
136
  if (immediate || slotIndex < 0 || !ref.current) return;
137
137
  const container = ref.current;
138
138
  const timers = [];
139
- requestAnimationFrame(() => {
139
+ const rafId = requestAnimationFrame(() => {
140
140
  timeline[slotIndex]?.forEach((step) => {
141
141
  const stepTimers = applyStep(container, step);
142
142
  if (stepTimers) timers.push(...stepTimers);
143
143
  });
144
144
  });
145
145
  return () => {
146
+ cancelAnimationFrame(rafId);
146
147
  timers.forEach(clearTimeout);
147
148
  };
148
149
  }, [
@@ -172,4 +173,4 @@ const useTimeline = ({ steps = [], loading, immediate, loop }) => {
172
173
 
173
174
  //#endregion
174
175
  export { useTimeline as default };
175
- //# sourceMappingURL=index.mjs.map
176
+ //# sourceMappingURL=use-timeline.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-timeline.mjs","names":[],"sources":["../../src/hooks/use-timeline.ts"],"sourcesContent":["import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\n\nconst registeredProperties = new Set<string>();\n\nconst registerCSSProperty = (\n name: string,\n syntax = '<length>',\n initialValue = '0px',\n) => {\n if (\n registeredProperties.has(name) ||\n typeof CSS === 'undefined' ||\n !CSS.registerProperty\n ) {\n return;\n }\n\n try {\n CSS.registerProperty({\n name,\n syntax,\n inherits: false,\n initialValue,\n });\n registeredProperties.add(name);\n } catch {\n // 이미 등록된 경우 무시\n }\n};\n\nexport interface TimelineStep {\n scale?: number;\n rotate?: { x?: number; y?: number; z?: number };\n position?: { x?: number; y?: number };\n top?: number;\n left?: number;\n width?: number;\n height?: number;\n zIndex?: number;\n filter?: string;\n backgroundColor?: string;\n opacity?: number;\n selector: string;\n transition: Transition;\n}\n\ninterface Transition {\n duration: number;\n ease?: string;\n delay?: number;\n easeX?: string;\n easeY?: string;\n}\n\ninterface Options {\n steps?: TimelineStep[];\n loading?: boolean;\n immediate?: boolean;\n loop?: boolean;\n}\n\nconst buildTimeline = (steps: TimelineStep[]): TimelineStep[][] => {\n const groups: TimelineStep[][] = [];\n\n for (const step of steps) {\n if (step.transition.delay === 0 && groups.length > 0) {\n groups[groups.length - 1]?.push(step);\n } else {\n groups.push([step]);\n }\n }\n\n return groups;\n};\n\nconst buildTransform = (step: TimelineStep) => {\n const parts: string[] = [];\n\n if (step.position?.x != null || step.position?.y != null) {\n parts.push(\n `translate(${step.position.x ?? 0}px, ${step.position.y ?? 0}px)`,\n );\n }\n\n if (step.scale != null) {\n parts.push(`scale(${step.scale})`);\n }\n\n if (step.rotate?.x != null) {\n parts.push(`rotateX(${step.rotate.x}deg)`);\n }\n\n if (step.rotate?.y != null) {\n parts.push(`rotateY(${step.rotate.y}deg)`);\n }\n\n if (step.rotate?.z != null) {\n parts.push(`rotateZ(${step.rotate.z}deg)`);\n }\n\n return parts.join(' ') || undefined;\n};\n\nconst applyStep = (\n container: HTMLElement,\n step: TimelineStep,\n skipTransition?: boolean,\n) => {\n const elements = container.matches(step.selector)\n ? [container]\n : Array.from(container.querySelectorAll<HTMLElement>(step.selector));\n\n if (!elements.length) {\n return;\n }\n\n const dur = `${step.transition.duration}ms`;\n const eas = step.transition.ease ?? 'ease-out';\n const easX = step.transition.easeX;\n const easY = step.transition.easeY;\n const hasCurve = !!(easX || easY);\n const timers: ReturnType<typeof setTimeout>[] = [];\n\n elements.forEach(el => {\n if (skipTransition) {\n el.style.transition = 'none';\n } else if (hasCurve) {\n const xEase = easX ?? eas;\n const yEase = easY ?? eas;\n el.style.transition = [\n `--tx ${dur} ${xEase}`,\n `--ty ${dur} ${yEase}`,\n `--s ${dur} ${eas}`,\n `rotate ${dur} ${eas}`,\n `width ${dur} ${eas}`,\n `height ${dur} ${eas}`,\n `filter ${dur} ${eas}`,\n `opacity ${dur} ${eas}`,\n ].join(', ');\n } else {\n el.style.transition = `all ${dur} ${eas}`;\n }\n\n if (step.backgroundColor) {\n el.style.backgroundColor = step.backgroundColor;\n }\n\n if (step.opacity !== undefined) {\n el.style.opacity = String(step.opacity);\n }\n\n if (step.top !== undefined) {\n el.style.top = `${step.top}px`;\n }\n\n if (step.left !== undefined) {\n el.style.left = `${step.left}px`;\n }\n\n if (step.width !== undefined) {\n el.style.width = `${step.width}px`;\n }\n\n if (step.height !== undefined) {\n el.style.height = `${step.height}px`;\n }\n\n if (step.zIndex !== undefined) {\n if (skipTransition) {\n el.style.zIndex = String(step.zIndex);\n } else {\n const timerId = setTimeout(() => {\n el.style.zIndex = String(step.zIndex);\n }, step.transition.duration / 2);\n timers.push(timerId);\n }\n }\n\n if (step.filter !== undefined) {\n el.style.filter = step.filter;\n }\n\n if (step.rotate?.z !== undefined) {\n el.style.rotate = `${step.rotate.z}deg`;\n }\n\n if (hasCurve) {\n if (step.position?.x != null || step.position?.y != null) {\n el.style.setProperty('--tx', `${step.position.x ?? 0}px`);\n el.style.setProperty('--ty', `${step.position.y ?? 0}px`);\n }\n if (step.scale != null) {\n el.style.setProperty('--s', String(step.scale));\n }\n el.style.transform = `translate(var(--tx), var(--ty)) scale(var(--s, 1))`;\n } else {\n const transform = buildTransform(step);\n\n if (transform) {\n el.style.transform = transform;\n }\n }\n });\n\n return timers;\n};\n\nconst useTimeline = ({ steps = [], loading, immediate, loop }: Options) => {\n const [slotIndex, setSlotIndex] = useState(-1);\n const [completed, setCompleted] = useState(() => !!immediate);\n\n const ref = useRef<HTMLDivElement>(null);\n const timeline = useMemo(() => buildTimeline(steps), [steps]);\n const hasCurveSteps = useMemo(\n () => steps.some(s => s.transition.easeX || s.transition.easeY),\n [steps],\n );\n\n useLayoutEffect(() => {\n if (hasCurveSteps) {\n registerCSSProperty('--tx');\n registerCSSProperty('--ty');\n registerCSSProperty('--s', '<number>', '1');\n }\n }, [hasCurveSteps]);\n\n useLayoutEffect(() => {\n if (!immediate || !ref.current || !steps.length) {\n return;\n }\n\n const container = ref.current;\n steps.forEach(step => applyStep(container, step, true));\n }, [immediate, steps]);\n\n useEffect(() => {\n if (immediate || loading || !timeline.length) {\n return;\n }\n\n const firstDelay = timeline[0]?.[0]?.transition.delay ?? 0;\n const timerId = window.setTimeout(() => {\n requestAnimationFrame(() => setSlotIndex(0));\n }, firstDelay);\n\n return () => clearTimeout(timerId);\n }, [loading, timeline, immediate]);\n\n useEffect(() => {\n if (immediate || loading || slotIndex < 0) {\n return;\n }\n\n const isLast = slotIndex >= timeline.length - 1;\n\n if (isLast && !loop) {\n return;\n }\n\n const currentSlot = timeline[slotIndex];\n const maxDuration = Math.max(\n ...(currentSlot?.map(s => s.transition.duration) ?? [0]),\n );\n\n const nextIndex = isLast ? 0 : slotIndex + 1;\n const nextDelay = timeline[nextIndex]?.[0]?.transition.delay ?? 0;\n\n const timerId = window.setTimeout(() => {\n setSlotIndex(nextIndex);\n }, maxDuration + nextDelay);\n\n return () => clearTimeout(timerId);\n }, [loading, slotIndex, timeline, immediate, loop]);\n\n useEffect(() => {\n if (immediate || slotIndex < 0 || !ref.current) {\n return;\n }\n\n const container = ref.current;\n const timers: ReturnType<typeof setTimeout>[] = [];\n\n const rafId = requestAnimationFrame(() => {\n timeline[slotIndex]?.forEach(step => {\n const stepTimers = applyStep(container, step);\n\n if (stepTimers) {\n timers.push(...stepTimers);\n }\n });\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n timers.forEach(clearTimeout);\n };\n }, [immediate, slotIndex, timeline]);\n\n useEffect(() => {\n if (\n immediate ||\n loop ||\n slotIndex < 0 ||\n slotIndex < timeline.length - 1 ||\n !timeline.length\n ) {\n return;\n }\n\n const lastSlot = timeline[slotIndex];\n const maxDuration = Math.max(\n ...(lastSlot?.map(s => s.transition.duration) ?? [0]),\n );\n\n const timerId = window.setTimeout(() => {\n setCompleted(true);\n }, maxDuration);\n\n return () => clearTimeout(timerId);\n }, [slotIndex, timeline, immediate, loop]);\n\n return { ref, completed };\n};\n\nexport default useTimeline;\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region src/hooks/useViewport/index.d.ts
1
+ //#region src/hooks/use-viewport.d.ts
2
2
  type ViewportInfo = VisualViewport | {
3
3
  width: number;
4
4
  height: number;
@@ -15,4 +15,4 @@ interface Options {
15
15
  declare const useViewport: (options?: Options) => ViewportInfo;
16
16
  //#endregion
17
17
  export { useViewport };
18
- //# sourceMappingURL=index.d.mts.map
18
+ //# sourceMappingURL=use-viewport.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useEffect, useState } from "react";
2
2
 
3
- //#region src/hooks/useViewport/index.ts
3
+ //#region src/hooks/use-viewport.ts
4
4
  const useViewport = (options = {}) => {
5
5
  const { isInApp = false, debounce = 100 } = options;
6
6
  const [viewport, setViewport] = useState({
@@ -84,4 +84,4 @@ const useViewport = (options = {}) => {
84
84
 
85
85
  //#endregion
86
86
  export { useViewport as default };
87
- //# sourceMappingURL=index.mjs.map
87
+ //# sourceMappingURL=use-viewport.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-viewport.mjs","names":[],"sources":["../../src/hooks/use-viewport.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ntype ViewportInfo =\n | VisualViewport\n | {\n width: number;\n height: number;\n offsetLeft: number;\n offsetTop: number;\n pageLeft: number;\n pageTop: number;\n scale: number;\n };\n\ninterface Options {\n isInApp?: boolean;\n debounce?: number;\n}\n\nconst useViewport = (options: Options = {}) => {\n const { isInApp = false, debounce = 100 } = options;\n\n const [viewport, setViewport] = useState<ViewportInfo>({\n width: 0,\n height: 0,\n offsetLeft: 0,\n offsetTop: 0,\n pageLeft: 0,\n pageTop: 0,\n scale: 1,\n });\n\n const getAppViewHeight = useCallback(() => {\n const windowHeight = window.innerHeight;\n const visualHeight = window.visualViewport?.height || windowHeight;\n const documentHeight = document.documentElement.clientHeight;\n const bodyHeight = document.body.clientHeight;\n\n if (window.visualViewport && Math.abs(visualHeight - windowHeight) > 100) {\n return visualHeight;\n }\n\n return Math.max(windowHeight, documentHeight, bodyHeight);\n }, []);\n\n const readViewport = useCallback((): ViewportInfo => {\n if (window.visualViewport && !isInApp) {\n return window.visualViewport;\n }\n\n const width = window.visualViewport?.width || window.innerWidth;\n const height = isInApp\n ? getAppViewHeight()\n : window.visualViewport?.height || window.innerHeight;\n\n return {\n width,\n height,\n offsetLeft: window.visualViewport?.offsetLeft || 0,\n offsetTop: window.visualViewport?.offsetTop || 0,\n pageLeft: window.scrollX ?? window.pageXOffset ?? 0,\n pageTop: window.scrollY ?? window.pageYOffset ?? 0,\n scale: window.visualViewport?.scale || 1,\n };\n }, [isInApp, getAppViewHeight]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const debouncedUpdate = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n setViewport(readViewport());\n }, debounce);\n };\n\n const immediateUpdate = () => setViewport(readViewport());\n\n immediateUpdate();\n\n const events = ['resize', 'orientationchange'];\n\n if (isInApp) {\n events.push('focus', 'blur', 'touchstart', 'touchend');\n }\n\n events.forEach(event => {\n if (event === 'resize' || event === 'orientationchange') {\n window.addEventListener(event, debouncedUpdate);\n } else {\n window.addEventListener(event, immediateUpdate, { passive: true });\n }\n });\n\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', immediateUpdate);\n window.visualViewport.addEventListener('scroll', immediateUpdate);\n }\n\n let intervalId: ReturnType<typeof setInterval>;\n if (isInApp) {\n let lastHeight = readViewport().height;\n intervalId = setInterval(() => {\n const currentHeight = readViewport().height;\n if (Math.abs(currentHeight - lastHeight) > 50) {\n lastHeight = currentHeight;\n immediateUpdate();\n }\n }, 500);\n }\n\n return () => {\n clearTimeout(timeoutId);\n if (intervalId) clearInterval(intervalId);\n\n events.forEach(event => {\n window.removeEventListener(\n event,\n event === 'resize' || event === 'orientationchange'\n ? debouncedUpdate\n : immediateUpdate,\n );\n });\n\n if (window.visualViewport) {\n window.visualViewport.removeEventListener('resize', immediateUpdate);\n window.visualViewport.removeEventListener('scroll', immediateUpdate);\n }\n };\n }, [readViewport, isInApp, debounce]);\n\n return viewport;\n};\n\nexport default useViewport;\n"],"mappings":";;;AAmBA,MAAM,eAAe,UAAmB,EAAE,KAAK;CAC7C,MAAM,EAAE,UAAU,OAAO,WAAW,QAAQ;CAE5C,MAAM,CAAC,UAAU,eAAe,SAAuB;EACrD,OAAO;EACP,QAAQ;EACR,YAAY;EACZ,WAAW;EACX,UAAU;EACV,SAAS;EACT,OAAO;EACR,CAAC;CAEF,MAAM,mBAAmB,kBAAkB;EACzC,MAAM,eAAe,OAAO;EAC5B,MAAM,eAAe,OAAO,gBAAgB,UAAU;EACtD,MAAM,iBAAiB,SAAS,gBAAgB;EAChD,MAAM,aAAa,SAAS,KAAK;AAEjC,MAAI,OAAO,kBAAkB,KAAK,IAAI,eAAe,aAAa,GAAG,IACnE,QAAO;AAGT,SAAO,KAAK,IAAI,cAAc,gBAAgB,WAAW;IACxD,EAAE,CAAC;CAEN,MAAM,eAAe,kBAAgC;AACnD,MAAI,OAAO,kBAAkB,CAAC,QAC5B,QAAO,OAAO;AAQhB,SAAO;GACL,OANY,OAAO,gBAAgB,SAAS,OAAO;GAOnD,QANa,UACX,kBAAkB,GAClB,OAAO,gBAAgB,UAAU,OAAO;GAK1C,YAAY,OAAO,gBAAgB,cAAc;GACjD,WAAW,OAAO,gBAAgB,aAAa;GAC/C,UAAU,OAAO,WAAW,OAAO,eAAe;GAClD,SAAS,OAAO,WAAW,OAAO,eAAe;GACjD,OAAO,OAAO,gBAAgB,SAAS;GACxC;IACA,CAAC,SAAS,iBAAiB,CAAC;AAE/B,iBAAgB;EACd,IAAI;EAEJ,MAAM,wBAAwB;AAC5B,gBAAa,UAAU;AACvB,eAAY,iBAAiB;AAC3B,gBAAY,cAAc,CAAC;MAC1B,SAAS;;EAGd,MAAM,wBAAwB,YAAY,cAAc,CAAC;AAEzD,mBAAiB;EAEjB,MAAM,SAAS,CAAC,UAAU,oBAAoB;AAE9C,MAAI,QACF,QAAO,KAAK,SAAS,QAAQ,cAAc,WAAW;AAGxD,SAAO,SAAQ,UAAS;AACtB,OAAI,UAAU,YAAY,UAAU,oBAClC,QAAO,iBAAiB,OAAO,gBAAgB;OAE/C,QAAO,iBAAiB,OAAO,iBAAiB,EAAE,SAAS,MAAM,CAAC;IAEpE;AAEF,MAAI,OAAO,gBAAgB;AACzB,UAAO,eAAe,iBAAiB,UAAU,gBAAgB;AACjE,UAAO,eAAe,iBAAiB,UAAU,gBAAgB;;EAGnE,IAAI;AACJ,MAAI,SAAS;GACX,IAAI,aAAa,cAAc,CAAC;AAChC,gBAAa,kBAAkB;IAC7B,MAAM,gBAAgB,cAAc,CAAC;AACrC,QAAI,KAAK,IAAI,gBAAgB,WAAW,GAAG,IAAI;AAC7C,kBAAa;AACb,sBAAiB;;MAElB,IAAI;;AAGT,eAAa;AACX,gBAAa,UAAU;AACvB,OAAI,WAAY,eAAc,WAAW;AAEzC,UAAO,SAAQ,UAAS;AACtB,WAAO,oBACL,OACA,UAAU,YAAY,UAAU,sBAC5B,kBACA,gBACL;KACD;AAEF,OAAI,OAAO,gBAAgB;AACzB,WAAO,eAAe,oBAAoB,UAAU,gBAAgB;AACpE,WAAO,eAAe,oBAAoB,UAAU,gBAAgB;;;IAGvE;EAAC;EAAc;EAAS;EAAS,CAAC;AAErC,QAAO"}
@@ -1,4 +1,4 @@
1
- //#region src/hooks/useWindowScroll/index.d.ts
1
+ //#region src/hooks/use-window-scroll.d.ts
2
2
  declare const useWindowScroll: () => {
3
3
  x: number;
4
4
  y: number;
@@ -9,4 +9,4 @@ declare const useWindowScroll: () => {
9
9
  };
10
10
  //#endregion
11
11
  export { useWindowScroll };
12
- //# sourceMappingURL=index.d.mts.map
12
+ //# sourceMappingURL=use-window-scroll.d.mts.map
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useState } from "react";
2
2
 
3
- //#region src/hooks/useWindowScroll/index.ts
3
+ //#region src/hooks/use-window-scroll.ts
4
4
  const useWindowScroll = () => {
5
5
  const [state, setState] = useState({
6
6
  x: 0,
@@ -57,4 +57,4 @@ const useWindowScroll = () => {
57
57
 
58
58
  //#endregion
59
59
  export { useWindowScroll as default };
60
- //# sourceMappingURL=index.mjs.map
60
+ //# sourceMappingURL=use-window-scroll.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-window-scroll.mjs","names":[],"sources":["../../src/hooks/use-window-scroll.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nconst useWindowScroll = () => {\n const [state, setState] = useState({\n x: 0,\n y: 0,\n percent: {\n x: 0,\n y: 0,\n },\n });\n\n useEffect(() => {\n const calculate = () => {\n const x = window.scrollX || 0;\n const y = window.scrollY || 0;\n\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);\n const visualViewport = window.visualViewport;\n\n const viewportWidth =\n isIOS && visualViewport ? visualViewport.width : window.innerWidth;\n\n const viewportHeight =\n isIOS && visualViewport ? visualViewport.height : window.innerHeight;\n\n const maxScrollX = Math.max(\n 0,\n document.documentElement.scrollWidth - viewportWidth,\n );\n const maxScrollY = Math.max(\n 0,\n document.documentElement.scrollHeight - viewportHeight,\n );\n\n const percentX =\n maxScrollX === 0 ? 0 : Math.min(100, (x / maxScrollX) * 100);\n const percentY =\n maxScrollY === 0 ? 0 : Math.min(100, (y / maxScrollY) * 100);\n\n setState({\n x,\n y,\n percent: {\n x: Math.floor(Math.max(0, percentX)),\n y: Math.floor(Math.max(0, percentY)),\n },\n });\n };\n\n calculate();\n\n const onScroll = () => {\n calculate();\n };\n\n const onResize = () => {\n setTimeout(calculate, 100);\n };\n\n const onVisualViewportChange = () => {\n setTimeout(calculate, 50);\n };\n\n window.addEventListener('scroll', onScroll, { passive: true });\n window.addEventListener('resize', onResize);\n window.addEventListener('orientationchange', onResize);\n\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', onVisualViewportChange);\n }\n\n return () => {\n window.removeEventListener('scroll', onScroll);\n window.removeEventListener('resize', onResize);\n window.removeEventListener('orientationchange', onResize);\n\n if (window.visualViewport) {\n window.visualViewport.removeEventListener(\n 'resize',\n onVisualViewportChange,\n );\n }\n };\n }, []);\n\n return state;\n};\n\nexport default useWindowScroll;\n"],"mappings":";;;AAEA,MAAM,wBAAwB;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAS;EACjC,GAAG;EACH,GAAG;EACH,SAAS;GACP,GAAG;GACH,GAAG;GACJ;EACF,CAAC;AAEF,iBAAgB;EACd,MAAM,kBAAkB;GACtB,MAAM,IAAI,OAAO,WAAW;GAC5B,MAAM,IAAI,OAAO,WAAW;GAE5B,MAAM,QAAQ,mBAAmB,KAAK,UAAU,UAAU;GAC1D,MAAM,iBAAiB,OAAO;GAE9B,MAAM,gBACJ,SAAS,iBAAiB,eAAe,QAAQ,OAAO;GAE1D,MAAM,iBACJ,SAAS,iBAAiB,eAAe,SAAS,OAAO;GAE3D,MAAM,aAAa,KAAK,IACtB,GACA,SAAS,gBAAgB,cAAc,cACxC;GACD,MAAM,aAAa,KAAK,IACtB,GACA,SAAS,gBAAgB,eAAe,eACzC;GAED,MAAM,WACJ,eAAe,IAAI,IAAI,KAAK,IAAI,KAAM,IAAI,aAAc,IAAI;GAC9D,MAAM,WACJ,eAAe,IAAI,IAAI,KAAK,IAAI,KAAM,IAAI,aAAc,IAAI;AAE9D,YAAS;IACP;IACA;IACA,SAAS;KACP,GAAG,KAAK,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;KACpC,GAAG,KAAK,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;KACrC;IACF,CAAC;;AAGJ,aAAW;EAEX,MAAM,iBAAiB;AACrB,cAAW;;EAGb,MAAM,iBAAiB;AACrB,cAAW,WAAW,IAAI;;EAG5B,MAAM,+BAA+B;AACnC,cAAW,WAAW,GAAG;;AAG3B,SAAO,iBAAiB,UAAU,UAAU,EAAE,SAAS,MAAM,CAAC;AAC9D,SAAO,iBAAiB,UAAU,SAAS;AAC3C,SAAO,iBAAiB,qBAAqB,SAAS;AAEtD,MAAI,OAAO,eACT,QAAO,eAAe,iBAAiB,UAAU,uBAAuB;AAG1E,eAAa;AACX,UAAO,oBAAoB,UAAU,SAAS;AAC9C,UAAO,oBAAoB,UAAU,SAAS;AAC9C,UAAO,oBAAoB,qBAAqB,SAAS;AAEzD,OAAI,OAAO,eACT,QAAO,eAAe,oBACpB,UACA,uBACD;;IAGJ,EAAE,CAAC;AAEN,QAAO"}
package/dist/index.d.mts CHANGED
@@ -1,15 +1,16 @@
1
- import { useDebounce } from "./hooks/useDebounce/index.mjs";
2
- import { useBodyScrollLock } from "./hooks/useBodyScrollLock/index.mjs";
3
- import { useElementPosition } from "./hooks/useElementPosition/index.mjs";
4
- import { useElementScroll } from "./hooks/useElementScroll/index.mjs";
5
- import { useResponsiveSize } from "./hooks/useResponsiveSize/index.mjs";
6
- import { useImage } from "./hooks/useImage/index.mjs";
7
- import { useLocalStorage } from "./hooks/useLocalStorage/index.mjs";
8
- import { useRecursiveTimeout } from "./hooks/useRecursiveTimeout/index.mjs";
9
- import { useScrollToElements } from "./hooks/useScrollToElements/index.mjs";
10
- import { useThrottle } from "./hooks/useThrottle/index.mjs";
11
- import { useTimeline } from "./hooks/useTimeline/index.mjs";
12
- import { useWindowScroll } from "./hooks/useWindowScroll/index.mjs";
13
- import { useViewport } from "./hooks/useViewport/index.mjs";
1
+ import { useDebounce } from "./hooks/use-debounce.mjs";
2
+ import { useBodyScrollLock } from "./hooks/use-body-scroll-lock.mjs";
3
+ import { useClickOutside } from "./hooks/use-click-outside.mjs";
4
+ import { useElementPosition } from "./hooks/use-element-position.mjs";
5
+ import { useElementScroll } from "./hooks/use-element-scroll.mjs";
6
+ import { useResponsiveSize } from "./hooks/use-responsive-size.mjs";
7
+ import { useImage } from "./hooks/use-image.mjs";
8
+ import { useLocalStorage } from "./hooks/use-local-storage.mjs";
9
+ import { useRecursiveTimeout } from "./hooks/use-recursive-timeout.mjs";
10
+ import { useScrollToElements } from "./hooks/use-scroll-to-elements.mjs";
11
+ import { useThrottle } from "./hooks/use-throttle.mjs";
12
+ import { useTimeline } from "./hooks/use-timeline.mjs";
13
+ import { useWindowScroll } from "./hooks/use-window-scroll.mjs";
14
+ import { useViewport } from "./hooks/use-viewport.mjs";
14
15
  import "./hooks/index.mjs";
15
- export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
16
+ export { useBodyScrollLock, useClickOutside, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
package/dist/index.mjs CHANGED
@@ -1,16 +1,17 @@
1
- import useDebounce from "./hooks/useDebounce/index.mjs";
2
- import useBodyScrollLock from "./hooks/useBodyScrollLock/index.mjs";
3
- import useElementPosition from "./hooks/useElementPosition/index.mjs";
4
- import useElementScroll from "./hooks/useElementScroll/index.mjs";
5
- import useResponsiveSize from "./hooks/useResponsiveSize/index.mjs";
6
- import useImage from "./hooks/useImage/index.mjs";
7
- import useLocalStorage from "./hooks/useLocalStorage/index.mjs";
8
- import useRecursiveTimeout from "./hooks/useRecursiveTimeout/index.mjs";
9
- import useScrollToElements from "./hooks/useScrollToElements/index.mjs";
10
- import useThrottle from "./hooks/useThrottle/index.mjs";
11
- import useTimeline from "./hooks/useTimeline/index.mjs";
12
- import useWindowScroll from "./hooks/useWindowScroll/index.mjs";
13
- import useViewport from "./hooks/useViewport/index.mjs";
1
+ import useDebounce from "./hooks/use-debounce.mjs";
2
+ import useBodyScrollLock from "./hooks/use-body-scroll-lock.mjs";
3
+ import useClickOutside from "./hooks/use-click-outside.mjs";
4
+ import useElementPosition from "./hooks/use-element-position.mjs";
5
+ import useElementScroll from "./hooks/use-element-scroll.mjs";
6
+ import useResponsiveSize from "./hooks/use-responsive-size.mjs";
7
+ import useImage from "./hooks/use-image.mjs";
8
+ import useLocalStorage from "./hooks/use-local-storage.mjs";
9
+ import useRecursiveTimeout from "./hooks/use-recursive-timeout.mjs";
10
+ import useScrollToElements from "./hooks/use-scroll-to-elements.mjs";
11
+ import useThrottle from "./hooks/use-throttle.mjs";
12
+ import useTimeline from "./hooks/use-timeline.mjs";
13
+ import useWindowScroll from "./hooks/use-window-scroll.mjs";
14
+ import useViewport from "./hooks/use-viewport.mjs";
14
15
  import "./hooks/index.mjs";
15
16
 
16
- export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
17
+ export { useBodyScrollLock, useClickOutside, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbpark/use-hooks",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "A collection of reusable React 19 hooks for common UI and interaction patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -21,6 +21,10 @@
21
21
  "url": "https://github.com/pjb0811/use-hooks/issues"
22
22
  },
23
23
  "private": false,
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "packageManager": "pnpm@10.28.0",
24
28
  "type": "module",
25
29
  "main": "./dist/index.mjs",
26
30
  "types": "./dist/index.d.mts",
@@ -34,13 +38,21 @@
34
38
  "files": [
35
39
  "dist"
36
40
  ],
41
+ "scripts": {
42
+ "dev": "vite",
43
+ "build": "tsc -b && tsdown",
44
+ "lint": "eslint .",
45
+ "preview": "vite preview",
46
+ "prepublishOnly": "pnpm build",
47
+ "prepare": "husky"
48
+ },
37
49
  "peerDependencies": {
38
50
  "react": "^19.1.1",
39
51
  "react-dom": "^19.1.1"
40
52
  },
41
53
  "devDependencies": {
42
- "@changesets/cli": "^2.29.8",
43
54
  "@eslint/js": "^9.33.0",
55
+ "@jbpark/ui-kit": "^2.7.0",
44
56
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
45
57
  "@types/node": "^24.5.2",
46
58
  "@types/react": "^19.1.10",
@@ -58,6 +70,7 @@
58
70
  "prettier-plugin-tailwindcss": "^0.6.14",
59
71
  "react": "^19.1.1",
60
72
  "react-dom": "^19.1.1",
73
+ "react-router-dom": "^7.18.1",
61
74
  "tsdown": "^0.20.3",
62
75
  "typescript": "~5.8.3",
63
76
  "typescript-eslint": "^8.39.1",
@@ -70,12 +83,5 @@
70
83
  "bash -c 'pnpm lint'",
71
84
  "bash -c 'tsc -b'"
72
85
  ]
73
- },
74
- "scripts": {
75
- "dev": "vite",
76
- "build": "tsc -b && tsdown",
77
- "lint": "eslint .",
78
- "preview": "vite preview",
79
- "changeset": "changeset"
80
86
  }
81
- }
87
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useBodyScrollLock/index.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nconst useBodyScrollLock = (enabled: boolean = true) => {\n useEffect(() => {\n if (!enabled) {\n return;\n }\n const scrollY = window.scrollY;\n\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);\n\n const originalStyles = {\n documentElement: {\n overflow: document.documentElement.style.overflow,\n height: document.documentElement.style.height,\n position: document.documentElement.style.position,\n width: document.documentElement.style.width,\n },\n body: {\n overflow: document.body.style.overflow,\n height: document.body.style.height,\n position: document.body.style.position,\n top: document.body.style.top,\n left: document.body.style.left,\n right: document.body.style.right,\n width: document.body.style.width,\n webkitOverflowScrolling: document.body.style.getPropertyValue(\n '-webkit-overflow-scrolling',\n ),\n },\n };\n\n document.documentElement.style.overflow = 'hidden';\n document.documentElement.style.height = '100%';\n document.documentElement.style.position = 'fixed';\n document.documentElement.style.width = '100%';\n\n document.body.style.overflow = 'hidden';\n document.body.style.height = '100%';\n document.body.style.position = 'fixed';\n document.body.style.top = `-${scrollY}px`;\n document.body.style.left = '0';\n document.body.style.right = '0';\n document.body.style.width = '100%';\n\n if (isIOS) {\n document.body.style.setProperty('-webkit-overflow-scrolling', 'touch');\n\n const preventAll = (e: Event) => {\n if (\n e.target === document.body ||\n e.target === document.documentElement ||\n e.target === window\n ) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n }\n };\n\n const preventScroll = () => {\n window.scrollTo(0, 0);\n document.body.scrollTop = 0;\n document.documentElement.scrollTop = 0;\n };\n\n const events = ['scroll', 'touchmove', 'touchstart', 'touchend'];\n events.forEach(event => {\n window.addEventListener(event, preventAll, {\n passive: false,\n capture: true,\n });\n document.addEventListener(event, preventAll, {\n passive: false,\n capture: true,\n });\n document.body.addEventListener(event, preventAll, {\n passive: false,\n capture: true,\n });\n });\n\n const scrollInterval = setInterval(preventScroll, 16);\n\n return () => {\n clearInterval(scrollInterval);\n events.forEach(event => {\n window.removeEventListener(event, preventAll, { capture: true });\n document.removeEventListener(event, preventAll, { capture: true });\n document.body.removeEventListener(event, preventAll, {\n capture: true,\n });\n });\n\n document.documentElement.style.overflow =\n originalStyles.documentElement.overflow;\n document.documentElement.style.height =\n originalStyles.documentElement.height;\n document.documentElement.style.position =\n originalStyles.documentElement.position;\n document.documentElement.style.width =\n originalStyles.documentElement.width;\n\n document.body.style.overflow = originalStyles.body.overflow;\n document.body.style.height = originalStyles.body.height;\n document.body.style.position = originalStyles.body.position;\n document.body.style.top = originalStyles.body.top;\n document.body.style.left = originalStyles.body.left;\n document.body.style.right = originalStyles.body.right;\n document.body.style.width = originalStyles.body.width;\n\n if (originalStyles.body.webkitOverflowScrolling) {\n document.body.style.setProperty(\n '-webkit-overflow-scrolling',\n originalStyles.body.webkitOverflowScrolling,\n );\n } else {\n document.body.style.removeProperty('-webkit-overflow-scrolling');\n }\n\n window.scrollTo(0, scrollY);\n };\n }\n\n return () => {\n document.documentElement.style.overflow =\n originalStyles.documentElement.overflow;\n document.documentElement.style.height =\n originalStyles.documentElement.height;\n document.documentElement.style.position =\n originalStyles.documentElement.position;\n document.documentElement.style.width =\n originalStyles.documentElement.width;\n\n document.body.style.overflow = originalStyles.body.overflow;\n document.body.style.height = originalStyles.body.height;\n document.body.style.position = originalStyles.body.position;\n document.body.style.top = originalStyles.body.top;\n document.body.style.left = originalStyles.body.left;\n document.body.style.right = originalStyles.body.right;\n document.body.style.width = originalStyles.body.width;\n\n window.scrollTo(0, scrollY);\n };\n }, [enabled]);\n};\n\nexport default useBodyScrollLock;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useDebounce/index.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\ninterface Options {\n delay?: number;\n autoInvoke?: boolean;\n}\n\nconst useDebounce = <T extends (...args: unknown[]) => unknown>(\n callback: T,\n { delay = 100, autoInvoke = true }: Options,\n deps: React.DependencyList = [],\n): T => {\n const timeoutRef = useRef<NodeJS.Timeout | null>(null);\n const callbackRef = useRef(callback);\n const depsRef = useRef(deps);\n const prevDeps = useRef<React.DependencyList | undefined>(undefined);\n\n useEffect(() => {\n callbackRef.current = callback;\n });\n\n useEffect(() => {\n depsRef.current = deps;\n });\n\n const stableDebouncedCallback = useRef<T | null>(null);\n\n if (!stableDebouncedCallback.current) {\n stableDebouncedCallback.current = ((...args: Parameters<T>) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n callbackRef.current(...args);\n }, delay);\n }) as T;\n }\n\n useEffect(() => {\n const depsChanged =\n prevDeps.current === undefined ||\n prevDeps.current.length !== deps.length ||\n prevDeps.current.some((dep, i) => dep !== deps[i]);\n\n if (depsChanged && timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n if (autoInvoke && depsChanged) {\n const isFirstRender = prevDeps.current === undefined;\n if (isFirstRender) {\n callbackRef.current();\n } else if (stableDebouncedCallback.current) {\n stableDebouncedCallback.current();\n }\n }\n\n prevDeps.current = deps;\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n return stableDebouncedCallback.current;\n};\n\nexport default useDebounce;\n"],"mappings":";;;AAOA,MAAM,eACJ,UACA,EAAE,QAAQ,KAAK,aAAa,QAC5B,OAA6B,EAAE,KACzB;CACN,MAAM,aAAa,OAA8B,KAAK;CACtD,MAAM,cAAc,OAAO,SAAS;CACpC,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,WAAW,OAAyC,OAAU;AAEpE,iBAAgB;AACd,cAAY,UAAU;GACtB;AAEF,iBAAgB;AACd,UAAQ,UAAU;GAClB;CAEF,MAAM,0BAA0B,OAAiB,KAAK;AAEtD,KAAI,CAAC,wBAAwB,QAC3B,yBAAwB,YAAY,GAAG,SAAwB;AAC7D,MAAI,WAAW,QACb,cAAa,WAAW,QAAQ;AAGlC,aAAW,UAAU,iBAAiB;AACpC,eAAY,QAAQ,GAAG,KAAK;KAC3B,MAAM;;AAIb,iBAAgB;EACd,MAAM,cACJ,SAAS,YAAY,UACrB,SAAS,QAAQ,WAAW,KAAK,UACjC,SAAS,QAAQ,MAAM,KAAK,MAAM,QAAQ,KAAK,GAAG;AAEpD,MAAI,eAAe,WAAW,QAC5B,cAAa,WAAW,QAAQ;AAGlC,MAAI,cAAc,aAEhB;OADsB,SAAS,YAAY,OAEzC,aAAY,SAAS;YACZ,wBAAwB,QACjC,yBAAwB,SAAS;;AAIrC,WAAS,UAAU;GACnB;AAEF,iBAAgB;AACd,eAAa;AACX,OAAI,WAAW,QACb,cAAa,WAAW,QAAQ;;IAGnC,EAAE,CAAC;AAEN,QAAO,wBAAwB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useElementPosition/index.ts"],"sourcesContent":["import { type RefObject, useEffect, useState } from 'react';\n\ntype ElementReference<T> = string | RefObject<T>;\n\nconst useElementPosition = <T>(elementRef: ElementReference<T>) => {\n const [rect, setRect] = useState<DOMRect | null>(null);\n\n useEffect(() => {\n const getElement = (ref: ElementReference<T>): T | null => {\n if (typeof ref === 'string') {\n return document.querySelector(ref) as T;\n }\n return ref.current;\n };\n\n const updateRect = () => {\n const element = getElement(elementRef) as HTMLElement | null;\n if (element) {\n setRect(element.getBoundingClientRect());\n } else {\n setRect(null);\n }\n };\n\n const onUpdate = () => {\n requestAnimationFrame(updateRect);\n };\n\n updateRect();\n\n window.addEventListener('scroll', onUpdate, { passive: true });\n window.addEventListener('resize', onUpdate, { passive: true });\n\n return () => {\n window.removeEventListener('scroll', onUpdate);\n window.removeEventListener('resize', onUpdate);\n };\n }, [elementRef]);\n\n return rect;\n};\n\nexport default useElementPosition;\n"],"mappings":";;;AAIA,MAAM,sBAAyB,eAAoC;CACjE,MAAM,CAAC,MAAM,WAAW,SAAyB,KAAK;AAEtD,iBAAgB;EACd,MAAM,cAAc,QAAuC;AACzD,OAAI,OAAO,QAAQ,SACjB,QAAO,SAAS,cAAc,IAAI;AAEpC,UAAO,IAAI;;EAGb,MAAM,mBAAmB;GACvB,MAAM,UAAU,WAAW,WAAW;AACtC,OAAI,QACF,SAAQ,QAAQ,uBAAuB,CAAC;OAExC,SAAQ,KAAK;;EAIjB,MAAM,iBAAiB;AACrB,yBAAsB,WAAW;;AAGnC,cAAY;AAEZ,SAAO,iBAAiB,UAAU,UAAU,EAAE,SAAS,MAAM,CAAC;AAC9D,SAAO,iBAAiB,UAAU,UAAU,EAAE,SAAS,MAAM,CAAC;AAE9D,eAAa;AACX,UAAO,oBAAoB,UAAU,SAAS;AAC9C,UAAO,oBAAoB,UAAU,SAAS;;IAE/C,CAAC,WAAW,CAAC;AAEhB,QAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useElementScroll/index.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ninterface ScrollPosition {\n scrollY: number;\n scrollPercentage: number;\n isAtTop: boolean;\n isAtBottom: boolean;\n scrollableHeight: number;\n clientHeight: number;\n scrollHeight: number;\n}\n\nconst useElementScroll = () => {\n const [element, setElement] = useState<HTMLElement | null>(null);\n const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({\n scrollY: 0,\n scrollPercentage: 0,\n isAtTop: true,\n isAtBottom: false,\n scrollableHeight: 0,\n clientHeight: 0,\n scrollHeight: 0,\n });\n\n const setRef = useCallback((el: HTMLElement | null) => {\n setElement(el);\n }, []);\n\n useEffect(() => {\n if (!element) {\n return;\n }\n\n const updateScrollPosition = () => {\n const { scrollTop, scrollHeight, clientHeight } = element;\n const scrollableHeight = scrollHeight - clientHeight;\n\n if (scrollableHeight <= 0) {\n setScrollPosition({\n scrollY: 0,\n scrollPercentage: 0,\n isAtTop: true,\n isAtBottom: true,\n scrollableHeight: 0,\n clientHeight,\n scrollHeight,\n });\n return;\n }\n\n const percentage = Math.min(\n 100,\n Math.max(0, (scrollTop / scrollableHeight) * 100),\n );\n\n setScrollPosition({\n scrollY: scrollTop,\n scrollPercentage: percentage,\n isAtTop: scrollTop <= 0,\n isAtBottom: scrollTop >= scrollableHeight - 1,\n scrollableHeight,\n clientHeight,\n scrollHeight,\n });\n };\n\n updateScrollPosition();\n\n const onScroll = () => {\n updateScrollPosition();\n };\n\n element.addEventListener('scroll', onScroll, { passive: true });\n\n const resizeObserver = new ResizeObserver(() => {\n updateScrollPosition();\n });\n\n resizeObserver.observe(element);\n\n return () => {\n element.removeEventListener('scroll', onScroll);\n resizeObserver.unobserve(element);\n };\n }, [element]);\n\n return { ...scrollPosition, element, setRef };\n};\n\nexport default useElementScroll;\n"],"mappings":";;;AAYA,MAAM,yBAAyB;CAC7B,MAAM,CAAC,SAAS,cAAc,SAA6B,KAAK;CAChE,MAAM,CAAC,gBAAgB,qBAAqB,SAAyB;EACnE,SAAS;EACT,kBAAkB;EAClB,SAAS;EACT,YAAY;EACZ,kBAAkB;EAClB,cAAc;EACd,cAAc;EACf,CAAC;CAEF,MAAM,SAAS,aAAa,OAA2B;AACrD,aAAW,GAAG;IACb,EAAE,CAAC;AAEN,iBAAgB;AACd,MAAI,CAAC,QACH;EAGF,MAAM,6BAA6B;GACjC,MAAM,EAAE,WAAW,cAAc,iBAAiB;GAClD,MAAM,mBAAmB,eAAe;AAExC,OAAI,oBAAoB,GAAG;AACzB,sBAAkB;KAChB,SAAS;KACT,kBAAkB;KAClB,SAAS;KACT,YAAY;KACZ,kBAAkB;KAClB;KACA;KACD,CAAC;AACF;;AAQF,qBAAkB;IAChB,SAAS;IACT,kBAPiB,KAAK,IACtB,KACA,KAAK,IAAI,GAAI,YAAY,mBAAoB,IAAI,CAClD;IAKC,SAAS,aAAa;IACtB,YAAY,aAAa,mBAAmB;IAC5C;IACA;IACA;IACD,CAAC;;AAGJ,wBAAsB;EAEtB,MAAM,iBAAiB;AACrB,yBAAsB;;AAGxB,UAAQ,iBAAiB,UAAU,UAAU,EAAE,SAAS,MAAM,CAAC;EAE/D,MAAM,iBAAiB,IAAI,qBAAqB;AAC9C,yBAAsB;IACtB;AAEF,iBAAe,QAAQ,QAAQ;AAE/B,eAAa;AACX,WAAQ,oBAAoB,UAAU,SAAS;AAC/C,kBAAe,UAAU,QAAQ;;IAElC,CAAC,QAAQ,CAAC;AAEb,QAAO;EAAE,GAAG;EAAgB;EAAS;EAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useImage/index.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ninterface Options {\n retryCount?: number;\n retryDelay?: number;\n}\n\nconst useImage = (src: string, options: Options = {}) => {\n const { retryCount = 0, retryDelay = 1000 } = options;\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | Event | null>(null);\n const [loaded, setLoaded] = useState(false);\n const [attemptCount, setAttemptCount] = useState(0);\n\n const loadImage = useCallback(() => {\n if (!src) {\n setLoading(false);\n setLoaded(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n const img = new Image();\n img.src = src;\n\n img.onload = () => {\n setLoading(false);\n setLoaded(true);\n setError(null);\n setAttemptCount(0);\n };\n\n img.onerror = err => {\n setLoading(false);\n setLoaded(false);\n setError(err);\n\n if (attemptCount < retryCount) {\n setTimeout(() => {\n setAttemptCount(prev => prev + 1);\n }, retryDelay);\n }\n };\n }, [src, attemptCount, retryCount, retryDelay]);\n\n useEffect(() => {\n loadImage();\n }, [loadImage]);\n\n const retry = useCallback(() => {\n setAttemptCount(0);\n loadImage();\n }, [loadImage]);\n\n return {\n loading,\n error,\n loaded,\n retry,\n };\n};\n\nexport default useImage;\n"],"mappings":";;;AAOA,MAAM,YAAY,KAAa,UAAmB,EAAE,KAAK;CACvD,MAAM,EAAE,aAAa,GAAG,aAAa,QAAS;CAE9C,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,OAAO,YAAY,SAAgC,KAAK;CAC/D,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CAEnD,MAAM,YAAY,kBAAkB;AAClC,MAAI,CAAC,KAAK;AACR,cAAW,MAAM;AACjB,aAAU,MAAM;AAChB;;AAGF,aAAW,KAAK;AAChB,WAAS,KAAK;EAEd,MAAM,MAAM,IAAI,OAAO;AACvB,MAAI,MAAM;AAEV,MAAI,eAAe;AACjB,cAAW,MAAM;AACjB,aAAU,KAAK;AACf,YAAS,KAAK;AACd,mBAAgB,EAAE;;AAGpB,MAAI,WAAU,QAAO;AACnB,cAAW,MAAM;AACjB,aAAU,MAAM;AAChB,YAAS,IAAI;AAEb,OAAI,eAAe,WACjB,kBAAiB;AACf,qBAAgB,SAAQ,OAAO,EAAE;MAChC,WAAW;;IAGjB;EAAC;EAAK;EAAc;EAAY;EAAW,CAAC;AAE/C,iBAAgB;AACd,aAAW;IACV,CAAC,UAAU,CAAC;AAOf,QAAO;EACL;EACA;EACA;EACA,OATY,kBAAkB;AAC9B,mBAAgB,EAAE;AAClB,cAAW;KACV,CAAC,UAAU,CAAC;EAOd"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useLocalStorage/index.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst useLocalStorage = <T>(key: string, initialValue: T) => {\n const initialRef = useRef(initialValue);\n const [storedValue, setStoredValue] = useState<T>(() => {\n if (typeof window === 'undefined') {\n return initialValue;\n }\n try {\n const item = window.localStorage.getItem(key);\n return item ? (JSON.parse(item) as T) : initialValue;\n } catch {\n return initialValue;\n }\n });\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n try {\n const item = window.localStorage.getItem(key);\n if (item) {\n setStoredValue(JSON.parse(item) as T);\n } else {\n window.localStorage.setItem(key, JSON.stringify(initialRef.current));\n }\n } catch (e) {\n console.error(`Error reading localStorage key \"${key}\":`, e);\n }\n }, [key]);\n\n const setValue = useCallback(\n (value: T | ((val: T) => T)) => {\n try {\n setStoredValue(prev => {\n const valueToStore = value instanceof Function ? value(prev) : value;\n localStorage.setItem(key, JSON.stringify(valueToStore));\n return valueToStore;\n });\n } catch (e) {\n console.error(`Error setting localStorage key \"${key}\":`, e);\n }\n },\n [key],\n );\n\n return [storedValue, setValue] as const;\n};\n\nexport default useLocalStorage;\n"],"mappings":";;;AAEA,MAAM,mBAAsB,KAAa,iBAAoB;CAC3D,MAAM,aAAa,OAAO,aAAa;CACvC,MAAM,CAAC,aAAa,kBAAkB,eAAkB;AACtD,MAAI,OAAO,WAAW,YACpB,QAAO;AAET,MAAI;GACF,MAAM,OAAO,OAAO,aAAa,QAAQ,IAAI;AAC7C,UAAO,OAAQ,KAAK,MAAM,KAAK,GAAS;UAClC;AACN,UAAO;;GAET;AAEF,iBAAgB;AACd,MAAI,OAAO,WAAW,YACpB;AAGF,MAAI;GACF,MAAM,OAAO,OAAO,aAAa,QAAQ,IAAI;AAC7C,OAAI,KACF,gBAAe,KAAK,MAAM,KAAK,CAAM;OAErC,QAAO,aAAa,QAAQ,KAAK,KAAK,UAAU,WAAW,QAAQ,CAAC;WAE/D,GAAG;AACV,WAAQ,MAAM,mCAAmC,IAAI,KAAK,EAAE;;IAE7D,CAAC,IAAI,CAAC;AAiBT,QAAO,CAAC,aAfS,aACd,UAA+B;AAC9B,MAAI;AACF,mBAAe,SAAQ;IACrB,MAAM,eAAe,iBAAiB,WAAW,MAAM,KAAK,GAAG;AAC/D,iBAAa,QAAQ,KAAK,KAAK,UAAU,aAAa,CAAC;AACvD,WAAO;KACP;WACK,GAAG;AACV,WAAQ,MAAM,mCAAmC,IAAI,KAAK,EAAE;;IAGhE,CAAC,IAAI,CACN,CAE6B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useRecursiveTimeout/index.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nconst useRecursiveTimeout = <T>(\n callback: () => Promise<T> | (() => void),\n delay: number | null,\n) => {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n let id: NodeJS.Timeout;\n\n function tick() {\n const ret = savedCallback.current();\n\n if (ret instanceof Promise) {\n ret.then(() => {\n if (delay) {\n id = setTimeout(tick, delay);\n }\n });\n } else {\n if (delay) {\n id = setTimeout(tick, delay);\n }\n }\n }\n\n if (delay) {\n id = setTimeout(tick, delay);\n return () => id && clearTimeout(id);\n }\n }, [delay]);\n};\n\nexport default useRecursiveTimeout;\n"],"mappings":";;;AAEA,MAAM,uBACJ,UACA,UACG;CACH,MAAM,gBAAgB,OAAO,SAAS;AAEtC,iBAAgB;AACd,gBAAc,UAAU;IACvB,CAAC,SAAS,CAAC;AAEd,iBAAgB;EACd,IAAI;EAEJ,SAAS,OAAO;GACd,MAAM,MAAM,cAAc,SAAS;AAEnC,OAAI,eAAe,QACjB,KAAI,WAAW;AACb,QAAI,MACF,MAAK,WAAW,MAAM,MAAM;KAE9B;YAEE,MACF,MAAK,WAAW,MAAM,MAAM;;AAKlC,MAAI,OAAO;AACT,QAAK,WAAW,MAAM,MAAM;AAC5B,gBAAa,MAAM,aAAa,GAAG;;IAEpC,CAAC,MAAM,CAAC"}