@jbpark/use-hooks 2.0.2 → 2.2.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 (50) hide show
  1. package/README.ko.md +18 -10
  2. package/README.md +16 -10
  3. package/dist/hooks/index.d.mts +13 -0
  4. package/dist/hooks/index.mjs +15 -0
  5. package/dist/hooks/useBodyScrollLock/index.d.mts +5 -0
  6. package/dist/hooks/useBodyScrollLock/index.mjs +115 -0
  7. package/dist/hooks/useBodyScrollLock/index.mjs.map +1 -0
  8. package/dist/hooks/useDebounce/index.d.mts +12 -0
  9. package/dist/hooks/useDebounce/index.mjs +41 -0
  10. package/dist/hooks/useDebounce/index.mjs.map +1 -0
  11. package/dist/hooks/useElementPosition/index.d.mts +8 -0
  12. package/dist/hooks/useElementPosition/index.mjs +32 -0
  13. package/dist/hooks/useElementPosition/index.mjs.map +1 -0
  14. package/dist/hooks/useElementScroll/index.d.mts +15 -0
  15. package/dist/hooks/useElementScroll/index.mjs +68 -0
  16. package/dist/hooks/useElementScroll/index.mjs.map +1 -0
  17. package/dist/hooks/useImage/index.d.mts +14 -0
  18. package/dist/hooks/useImage/index.mjs +56 -0
  19. package/dist/hooks/useImage/index.mjs.map +1 -0
  20. package/dist/hooks/useLocalStorage/index.d.mts +5 -0
  21. package/dist/hooks/useLocalStorage/index.mjs +40 -0
  22. package/dist/hooks/useLocalStorage/index.mjs.map +1 -0
  23. package/dist/hooks/useRecursiveTimeout/index.d.mts +5 -0
  24. package/dist/hooks/useRecursiveTimeout/index.mjs +27 -0
  25. package/dist/hooks/useRecursiveTimeout/index.mjs.map +1 -0
  26. package/dist/hooks/useResponsiveSize/index.d.mts +26 -0
  27. package/dist/hooks/useResponsiveSize/index.mjs +108 -0
  28. package/dist/hooks/useResponsiveSize/index.mjs.map +1 -0
  29. package/dist/hooks/useScrollToElements/index.d.mts +14 -0
  30. package/dist/hooks/useScrollToElements/index.mjs +34 -0
  31. package/dist/hooks/useScrollToElements/index.mjs.map +1 -0
  32. package/dist/hooks/useThrottle/index.d.mts +5 -0
  33. package/dist/hooks/useThrottle/index.mjs +42 -0
  34. package/dist/hooks/useThrottle/index.mjs.map +1 -0
  35. package/dist/hooks/useTimeline/index.d.mts +50 -0
  36. package/dist/hooks/useTimeline/index.mjs +175 -0
  37. package/dist/hooks/useTimeline/index.mjs.map +1 -0
  38. package/dist/hooks/useViewport/index.d.mts +18 -0
  39. package/dist/hooks/useViewport/index.mjs +87 -0
  40. package/dist/hooks/useViewport/index.mjs.map +1 -0
  41. package/dist/hooks/useWindowScroll/index.d.mts +12 -0
  42. package/dist/hooks/useWindowScroll/index.mjs +60 -0
  43. package/dist/hooks/useWindowScroll/index.mjs.map +1 -0
  44. package/dist/index.d.mts +15 -0
  45. package/dist/index.mjs +16 -0
  46. package/package.json +7 -8
  47. package/dist/index.cjs +0 -1
  48. package/dist/index.d.ts +0 -106
  49. package/dist/index.js +0 -424
  50. package/dist/vite.svg +0 -1
@@ -0,0 +1,5 @@
1
+ //#region src/hooks/useLocalStorage/index.d.ts
2
+ declare const useLocalStorage: <T>(key: string, initialValue: T) => readonly [T, (value: T | ((val: T) => T)) => void];
3
+ //#endregion
4
+ export { useLocalStorage };
5
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,40 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/useLocalStorage/index.ts
4
+ const useLocalStorage = (key, initialValue) => {
5
+ const initialRef = useRef(initialValue);
6
+ const [storedValue, setStoredValue] = useState(() => {
7
+ if (typeof window === "undefined") return initialValue;
8
+ try {
9
+ const item = window.localStorage.getItem(key);
10
+ return item ? JSON.parse(item) : initialValue;
11
+ } catch {
12
+ return initialValue;
13
+ }
14
+ });
15
+ useEffect(() => {
16
+ if (typeof window === "undefined") return;
17
+ try {
18
+ const item = window.localStorage.getItem(key);
19
+ if (item) setStoredValue(JSON.parse(item));
20
+ else window.localStorage.setItem(key, JSON.stringify(initialRef.current));
21
+ } catch (e) {
22
+ console.error(`Error reading localStorage key "${key}":`, e);
23
+ }
24
+ }, [key]);
25
+ return [storedValue, useCallback((value) => {
26
+ try {
27
+ setStoredValue((prev) => {
28
+ const valueToStore = value instanceof Function ? value(prev) : value;
29
+ localStorage.setItem(key, JSON.stringify(valueToStore));
30
+ return valueToStore;
31
+ });
32
+ } catch (e) {
33
+ console.error(`Error setting localStorage key "${key}":`, e);
34
+ }
35
+ }, [key])];
36
+ };
37
+
38
+ //#endregion
39
+ export { useLocalStorage as default };
40
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,5 @@
1
+ //#region src/hooks/useRecursiveTimeout/index.d.ts
2
+ declare const useRecursiveTimeout: <T>(callback: () => Promise<T> | (() => void), delay: number | null) => void;
3
+ //#endregion
4
+ export { useRecursiveTimeout };
5
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,27 @@
1
+ import { useEffect, useRef } from "react";
2
+
3
+ //#region src/hooks/useRecursiveTimeout/index.ts
4
+ const useRecursiveTimeout = (callback, delay) => {
5
+ const savedCallback = useRef(callback);
6
+ useEffect(() => {
7
+ savedCallback.current = callback;
8
+ }, [callback]);
9
+ useEffect(() => {
10
+ let id;
11
+ function tick() {
12
+ const ret = savedCallback.current();
13
+ if (ret instanceof Promise) ret.then(() => {
14
+ if (delay) id = setTimeout(tick, delay);
15
+ });
16
+ else if (delay) id = setTimeout(tick, delay);
17
+ }
18
+ if (delay) {
19
+ id = setTimeout(tick, delay);
20
+ return () => id && clearTimeout(id);
21
+ }
22
+ }, [delay]);
23
+ };
24
+
25
+ //#endregion
26
+ export { useRecursiveTimeout as default };
27
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,26 @@
1
+ //#region src/hooks/useResponsiveSize/index.d.ts
2
+ type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
3
+ interface BreakpointInfo {
4
+ current: Breakpoint;
5
+ xs: boolean;
6
+ sm: boolean;
7
+ md: boolean;
8
+ lg: boolean;
9
+ xl: boolean;
10
+ '2xl': boolean;
11
+ }
12
+ interface Options {
13
+ delay?: number;
14
+ container?: HTMLElement | null;
15
+ }
16
+ declare const useResponsiveSize: <T extends HTMLElement>(options?: Options) => {
17
+ size: {
18
+ width: number;
19
+ height: number;
20
+ };
21
+ breakpoint: BreakpointInfo;
22
+ ref: (node: T | null) => void;
23
+ };
24
+ //#endregion
25
+ export { useResponsiveSize };
26
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,108 @@
1
+ import useDebounce from "../useDebounce/index.mjs";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+
4
+ //#region src/hooks/useResponsiveSize/index.ts
5
+ const BREAKPOINTS = {
6
+ xs: 0,
7
+ sm: 640,
8
+ md: 768,
9
+ lg: 1024,
10
+ xl: 1280,
11
+ "2xl": 1536
12
+ };
13
+ const getBreakpointInfo = (width) => {
14
+ let current = "xs";
15
+ if (width >= BREAKPOINTS["2xl"]) current = "2xl";
16
+ else if (width >= BREAKPOINTS.xl) current = "xl";
17
+ else if (width >= BREAKPOINTS.lg) current = "lg";
18
+ else if (width >= BREAKPOINTS.md) current = "md";
19
+ else if (width >= BREAKPOINTS.sm) current = "sm";
20
+ else current = "xs";
21
+ return {
22
+ current,
23
+ xs: width < BREAKPOINTS.sm,
24
+ sm: width >= BREAKPOINTS.sm && width < BREAKPOINTS.md,
25
+ md: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,
26
+ lg: width >= BREAKPOINTS.lg && width < BREAKPOINTS.xl,
27
+ xl: width >= BREAKPOINTS.xl && width < BREAKPOINTS["2xl"],
28
+ "2xl": width >= BREAKPOINTS["2xl"]
29
+ };
30
+ };
31
+ const useResponsiveSize = (options) => {
32
+ const { delay = 100, container } = options || {};
33
+ const [size, setSize] = useState({
34
+ width: 0,
35
+ height: 0
36
+ });
37
+ const [breakpoint, setBreakpoint] = useState({
38
+ current: "xs",
39
+ xs: true,
40
+ sm: false,
41
+ md: false,
42
+ lg: false,
43
+ xl: false,
44
+ "2xl": false
45
+ });
46
+ const [debouncedSize, setDebouncedSize] = useState({
47
+ width: 0,
48
+ height: 0
49
+ });
50
+ const [element, setElement] = useState(null);
51
+ const observerRef = useRef(null);
52
+ const ref = useCallback((node) => {
53
+ setElement(node);
54
+ }, []);
55
+ useDebounce(() => {
56
+ setDebouncedSize(size);
57
+ }, { delay }, [size]);
58
+ useEffect(() => {
59
+ const updateSize = () => {
60
+ const target = container ?? element ?? document.body;
61
+ if (!target) return;
62
+ const { offsetWidth, offsetHeight } = target;
63
+ setSize((prev) => {
64
+ if (prev.width !== offsetWidth || prev.height !== offsetHeight) return {
65
+ width: offsetWidth,
66
+ height: offsetHeight
67
+ };
68
+ return prev;
69
+ });
70
+ setBreakpoint((prev) => {
71
+ const next = getBreakpointInfo(offsetWidth);
72
+ if (prev.current !== next.current) return next;
73
+ return prev;
74
+ });
75
+ };
76
+ const connect = () => {
77
+ const target = container ?? element ?? document.body;
78
+ if (!target) return;
79
+ updateSize();
80
+ if (observerRef.current) observerRef.current.disconnect();
81
+ observerRef.current = new ResizeObserver(() => {
82
+ requestAnimationFrame(() => {
83
+ updateSize();
84
+ });
85
+ });
86
+ observerRef.current.observe(target);
87
+ };
88
+ const disconnect = () => {
89
+ if (observerRef.current) {
90
+ observerRef.current.disconnect();
91
+ observerRef.current = null;
92
+ }
93
+ };
94
+ connect();
95
+ return () => {
96
+ disconnect();
97
+ };
98
+ }, [container, element]);
99
+ return {
100
+ size: debouncedSize,
101
+ breakpoint,
102
+ ref
103
+ };
104
+ };
105
+
106
+ //#endregion
107
+ export { useResponsiveSize as default };
108
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useResponsiveSize/index.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport useDebounce from '../useDebounce';\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"}
@@ -0,0 +1,14 @@
1
+ import * as react from "react";
2
+
3
+ //#region src/hooks/useScrollToElements/index.d.ts
4
+ interface Options extends ScrollIntoViewOptions {
5
+ offset?: number;
6
+ }
7
+ declare const useScrollToElements: (options?: Options) => {
8
+ elementRefs: react.RefObject<HTMLElement[]>;
9
+ setElementRef: (element: HTMLElement, index: number) => void;
10
+ scrollToElement: (index: number) => void;
11
+ };
12
+ //#endregion
13
+ export { useScrollToElements };
14
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,34 @@
1
+ import { useCallback, useRef } from "react";
2
+
3
+ //#region src/hooks/useScrollToElements/index.ts
4
+ const useScrollToElements = (options) => {
5
+ const elementRefs = useRef([]);
6
+ const scrollToElement = useCallback((index) => {
7
+ if (elementRefs.current[index]) {
8
+ elementRefs.current[index].scrollIntoView({
9
+ behavior: "smooth",
10
+ block: "start",
11
+ inline: "start",
12
+ ...options
13
+ });
14
+ if (options?.offset) {
15
+ const top = elementRefs.current[index].getBoundingClientRect().top + window.scrollY - options.offset;
16
+ window.scrollTo({
17
+ top,
18
+ behavior: options.behavior || "smooth"
19
+ });
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=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useScrollToElements/index.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[]>([]);\n\n const scrollToElement = useCallback(\n (index: number) => {\n if (elementRefs.current[index]) {\n elementRefs.current[index].scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n inline: 'start',\n ...options,\n });\n\n if (options?.offset) {\n const top =\n elementRefs.current[index].getBoundingClientRect().top +\n window.scrollY -\n options.offset;\n\n window.scrollTo({\n top,\n behavior: options.behavior || 'smooth',\n });\n }\n }\n },\n [options],\n );\n\n const setElementRef = useCallback((element: HTMLElement, index: number) => {\n elementRefs.current[index] = element;\n }, []);\n\n return { elementRefs, setElementRef, scrollToElement };\n};\n\nexport default useScrollToElements;\n"],"mappings":";;;AAKA,MAAM,uBAAuB,YAAsB;CACjD,MAAM,cAAc,OAAsB,EAAE,CAAC;CAE7C,MAAM,kBAAkB,aACrB,UAAkB;AACjB,MAAI,YAAY,QAAQ,QAAQ;AAC9B,eAAY,QAAQ,OAAO,eAAe;IACxC,UAAU;IACV,OAAO;IACP,QAAQ;IACR,GAAG;IACJ,CAAC;AAEF,OAAI,SAAS,QAAQ;IACnB,MAAM,MACJ,YAAY,QAAQ,OAAO,uBAAuB,CAAC,MACnD,OAAO,UACP,QAAQ;AAEV,WAAO,SAAS;KACd;KACA,UAAU,QAAQ,YAAY;KAC/B,CAAC;;;IAIR,CAAC,QAAQ,CACV;AAMD,QAAO;EAAE;EAAa,eAJA,aAAa,SAAsB,UAAkB;AACzE,eAAY,QAAQ,SAAS;KAC5B,EAAE,CAAC;EAE+B;EAAiB"}
@@ -0,0 +1,5 @@
1
+ //#region src/hooks/useThrottle/index.d.ts
2
+ declare const useThrottle: <T>(value: T, delay?: number) => T;
3
+ //#endregion
4
+ export { useThrottle };
5
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,42 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/useThrottle/index.ts
4
+ const useThrottle = (value, delay = 100) => {
5
+ const [throttledValue, setThrottledValue] = useState(value);
6
+ const lastExecutedRef = useRef(0);
7
+ const timeoutRef = useRef(null);
8
+ const latestValueRef = useRef(value);
9
+ useEffect(() => {
10
+ latestValueRef.current = value;
11
+ }, [value]);
12
+ useEffect(() => {
13
+ const now = Date.now();
14
+ const elapsed = now - lastExecutedRef.current;
15
+ if (elapsed >= delay) {
16
+ if (timeoutRef.current) {
17
+ clearTimeout(timeoutRef.current);
18
+ timeoutRef.current = null;
19
+ }
20
+ lastExecutedRef.current = now;
21
+ setThrottledValue(latestValueRef.current);
22
+ return;
23
+ }
24
+ const remaining = delay - elapsed;
25
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
26
+ timeoutRef.current = setTimeout(() => {
27
+ lastExecutedRef.current = Date.now();
28
+ setThrottledValue(latestValueRef.current);
29
+ }, remaining);
30
+ return () => {
31
+ if (timeoutRef.current) {
32
+ clearTimeout(timeoutRef.current);
33
+ timeoutRef.current = null;
34
+ }
35
+ };
36
+ }, [value, delay]);
37
+ return throttledValue;
38
+ };
39
+
40
+ //#endregion
41
+ export { useThrottle as default };
42
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useThrottle/index.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"}
@@ -0,0 +1,50 @@
1
+ import * as react from "react";
2
+
3
+ //#region src/hooks/useTimeline/index.d.ts
4
+ interface TimelineStep {
5
+ scale?: number;
6
+ rotate?: {
7
+ x?: number;
8
+ y?: number;
9
+ z?: number;
10
+ };
11
+ position?: {
12
+ x?: number;
13
+ y?: number;
14
+ };
15
+ top?: number;
16
+ left?: number;
17
+ width?: number;
18
+ height?: number;
19
+ zIndex?: number;
20
+ filter?: string;
21
+ backgroundColor?: string;
22
+ opacity?: number;
23
+ selector: string;
24
+ transition: Transition;
25
+ }
26
+ interface Transition {
27
+ duration: number;
28
+ ease?: string;
29
+ delay?: number;
30
+ easeX?: string;
31
+ easeY?: string;
32
+ }
33
+ interface Options {
34
+ steps?: TimelineStep[];
35
+ loading?: boolean;
36
+ immediate?: boolean;
37
+ loop?: boolean;
38
+ }
39
+ declare const useTimeline: ({
40
+ steps,
41
+ loading,
42
+ immediate,
43
+ loop
44
+ }: Options) => {
45
+ ref: react.RefObject<HTMLDivElement | null>;
46
+ completed: boolean;
47
+ };
48
+ //#endregion
49
+ export { useTimeline };
50
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,175 @@
1
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/useTimeline/index.ts
4
+ const registeredProperties = /* @__PURE__ */ new Set();
5
+ const registerCSSProperty = (name, syntax = "<length>", initialValue = "0px") => {
6
+ if (registeredProperties.has(name) || typeof CSS === "undefined" || !CSS.registerProperty) return;
7
+ try {
8
+ CSS.registerProperty({
9
+ name,
10
+ syntax,
11
+ inherits: false,
12
+ initialValue
13
+ });
14
+ registeredProperties.add(name);
15
+ } catch {}
16
+ };
17
+ const buildTimeline = (steps) => {
18
+ const groups = [];
19
+ for (const step of steps) if (step.transition.delay === 0 && groups.length > 0) groups[groups.length - 1]?.push(step);
20
+ else groups.push([step]);
21
+ return groups;
22
+ };
23
+ const buildTransform = (step) => {
24
+ const parts = [];
25
+ if (step.position?.x != null || step.position?.y != null) parts.push(`translate(${step.position.x ?? 0}px, ${step.position.y ?? 0}px)`);
26
+ if (step.scale != null) parts.push(`scale(${step.scale})`);
27
+ if (step.rotate?.x != null) parts.push(`rotateX(${step.rotate.x}deg)`);
28
+ if (step.rotate?.y != null) parts.push(`rotateY(${step.rotate.y}deg)`);
29
+ if (step.rotate?.z != null) parts.push(`rotateZ(${step.rotate.z}deg)`);
30
+ return parts.join(" ") || void 0;
31
+ };
32
+ const applyStep = (container, step, skipTransition) => {
33
+ const elements = container.matches(step.selector) ? [container] : Array.from(container.querySelectorAll(step.selector));
34
+ if (!elements.length) return;
35
+ const dur = `${step.transition.duration}ms`;
36
+ const eas = step.transition.ease ?? "ease-out";
37
+ const easX = step.transition.easeX;
38
+ const easY = step.transition.easeY;
39
+ const hasCurve = !!(easX || easY);
40
+ const timers = [];
41
+ elements.forEach((el) => {
42
+ if (skipTransition) el.style.transition = "none";
43
+ else if (hasCurve) {
44
+ const xEase = easX ?? eas;
45
+ const yEase = easY ?? eas;
46
+ el.style.transition = [
47
+ `--tx ${dur} ${xEase}`,
48
+ `--ty ${dur} ${yEase}`,
49
+ `--s ${dur} ${eas}`,
50
+ `rotate ${dur} ${eas}`,
51
+ `width ${dur} ${eas}`,
52
+ `height ${dur} ${eas}`,
53
+ `filter ${dur} ${eas}`,
54
+ `opacity ${dur} ${eas}`
55
+ ].join(", ");
56
+ } else el.style.transition = `all ${dur} ${eas}`;
57
+ if (step.backgroundColor) el.style.backgroundColor = step.backgroundColor;
58
+ if (step.opacity !== void 0) el.style.opacity = String(step.opacity);
59
+ if (step.top !== void 0) el.style.top = `${step.top}px`;
60
+ if (step.left !== void 0) el.style.left = `${step.left}px`;
61
+ if (step.width !== void 0) el.style.width = `${step.width}px`;
62
+ if (step.height !== void 0) el.style.height = `${step.height}px`;
63
+ if (step.zIndex !== void 0) if (skipTransition) el.style.zIndex = String(step.zIndex);
64
+ else {
65
+ const timerId = setTimeout(() => {
66
+ el.style.zIndex = String(step.zIndex);
67
+ }, step.transition.duration / 2);
68
+ timers.push(timerId);
69
+ }
70
+ if (step.filter !== void 0) el.style.filter = step.filter;
71
+ if (step.rotate?.z !== void 0) el.style.rotate = `${step.rotate.z}deg`;
72
+ if (hasCurve) {
73
+ if (step.position?.x != null || step.position?.y != null) {
74
+ el.style.setProperty("--tx", `${step.position.x ?? 0}px`);
75
+ el.style.setProperty("--ty", `${step.position.y ?? 0}px`);
76
+ }
77
+ if (step.scale != null) el.style.setProperty("--s", String(step.scale));
78
+ el.style.transform = `translate(var(--tx), var(--ty)) scale(var(--s, 1))`;
79
+ } else {
80
+ const transform = buildTransform(step);
81
+ if (transform) el.style.transform = transform;
82
+ }
83
+ });
84
+ return timers;
85
+ };
86
+ const useTimeline = ({ steps = [], loading, immediate, loop }) => {
87
+ const [slotIndex, setSlotIndex] = useState(-1);
88
+ const [completed, setCompleted] = useState(() => !!immediate);
89
+ const ref = useRef(null);
90
+ const timeline = useMemo(() => buildTimeline(steps), [steps]);
91
+ const hasCurveSteps = useMemo(() => steps.some((s) => s.transition.easeX || s.transition.easeY), [steps]);
92
+ useLayoutEffect(() => {
93
+ if (hasCurveSteps) {
94
+ registerCSSProperty("--tx");
95
+ registerCSSProperty("--ty");
96
+ registerCSSProperty("--s", "<number>", "1");
97
+ }
98
+ }, [hasCurveSteps]);
99
+ useLayoutEffect(() => {
100
+ if (!immediate || !ref.current || !steps.length) return;
101
+ const container = ref.current;
102
+ steps.forEach((step) => applyStep(container, step, true));
103
+ }, [immediate, steps]);
104
+ useEffect(() => {
105
+ if (immediate || loading || !timeline.length) return;
106
+ const firstDelay = timeline[0]?.[0]?.transition.delay ?? 0;
107
+ const timerId = window.setTimeout(() => {
108
+ requestAnimationFrame(() => setSlotIndex(0));
109
+ }, firstDelay);
110
+ return () => clearTimeout(timerId);
111
+ }, [
112
+ loading,
113
+ timeline,
114
+ immediate
115
+ ]);
116
+ useEffect(() => {
117
+ if (immediate || loading || slotIndex < 0) return;
118
+ const isLast = slotIndex >= timeline.length - 1;
119
+ if (isLast && !loop) return;
120
+ const currentSlot = timeline[slotIndex];
121
+ const maxDuration = Math.max(...currentSlot?.map((s) => s.transition.duration) ?? [0]);
122
+ const nextIndex = isLast ? 0 : slotIndex + 1;
123
+ const nextDelay = timeline[nextIndex]?.[0]?.transition.delay ?? 0;
124
+ const timerId = window.setTimeout(() => {
125
+ setSlotIndex(nextIndex);
126
+ }, maxDuration + nextDelay);
127
+ return () => clearTimeout(timerId);
128
+ }, [
129
+ loading,
130
+ slotIndex,
131
+ timeline,
132
+ immediate,
133
+ loop
134
+ ]);
135
+ useEffect(() => {
136
+ if (immediate || slotIndex < 0 || !ref.current) return;
137
+ const container = ref.current;
138
+ const timers = [];
139
+ requestAnimationFrame(() => {
140
+ timeline[slotIndex]?.forEach((step) => {
141
+ const stepTimers = applyStep(container, step);
142
+ if (stepTimers) timers.push(...stepTimers);
143
+ });
144
+ });
145
+ return () => {
146
+ timers.forEach(clearTimeout);
147
+ };
148
+ }, [
149
+ immediate,
150
+ slotIndex,
151
+ timeline
152
+ ]);
153
+ useEffect(() => {
154
+ if (immediate || loop || slotIndex < 0 || slotIndex < timeline.length - 1 || !timeline.length) return;
155
+ const lastSlot = timeline[slotIndex];
156
+ const maxDuration = Math.max(...lastSlot?.map((s) => s.transition.duration) ?? [0]);
157
+ const timerId = window.setTimeout(() => {
158
+ setCompleted(true);
159
+ }, maxDuration);
160
+ return () => clearTimeout(timerId);
161
+ }, [
162
+ slotIndex,
163
+ timeline,
164
+ immediate,
165
+ loop
166
+ ]);
167
+ return {
168
+ ref,
169
+ completed
170
+ };
171
+ };
172
+
173
+ //#endregion
174
+ export { useTimeline as default };
175
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useTimeline/index.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 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 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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"}
@@ -0,0 +1,18 @@
1
+ //#region src/hooks/useViewport/index.d.ts
2
+ type ViewportInfo = VisualViewport | {
3
+ width: number;
4
+ height: number;
5
+ offsetLeft: number;
6
+ offsetTop: number;
7
+ pageLeft: number;
8
+ pageTop: number;
9
+ scale: number;
10
+ };
11
+ interface Options {
12
+ isInApp?: boolean;
13
+ debounce?: number;
14
+ }
15
+ declare const useViewport: (options?: Options) => ViewportInfo;
16
+ //#endregion
17
+ export { useViewport };
18
+ //# sourceMappingURL=index.d.mts.map