@jbpark/use-hooks 2.1.0 → 2.2.1

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 (59) hide show
  1. package/README.ko.md +17 -27
  2. package/README.md +17 -27
  3. package/dist/hooks/index.d.mts +13 -12
  4. package/dist/hooks/index.mjs +13 -12
  5. package/dist/hooks/{useBodyScrollLock → use-body-scroll-lock}/index.d.mts +1 -1
  6. package/dist/hooks/{useBodyScrollLock → use-body-scroll-lock}/index.mjs +45 -36
  7. package/dist/hooks/use-body-scroll-lock/index.mjs.map +1 -0
  8. package/dist/hooks/{useDebounce → use-debounce}/index.d.mts +1 -1
  9. package/dist/hooks/{useDebounce → use-debounce}/index.mjs +1 -5
  10. package/dist/hooks/use-debounce/index.mjs.map +1 -0
  11. package/dist/hooks/{useElementPosition → use-element-position}/index.d.mts +1 -1
  12. package/dist/hooks/{useElementPosition → use-element-position}/index.mjs +1 -1
  13. package/dist/hooks/use-element-position/index.mjs.map +1 -0
  14. package/dist/hooks/{useElementScroll → use-element-scroll}/index.d.mts +1 -1
  15. package/dist/hooks/{useElementScroll → use-element-scroll}/index.mjs +1 -1
  16. package/dist/hooks/use-element-scroll/index.mjs.map +1 -0
  17. package/dist/hooks/{useImage → use-image}/index.d.mts +1 -1
  18. package/dist/hooks/{useImage → use-image}/index.mjs +19 -11
  19. package/dist/hooks/use-image/index.mjs.map +1 -0
  20. package/dist/hooks/{useLocalStorage → use-local-storage}/index.d.mts +1 -1
  21. package/dist/hooks/{useLocalStorage → use-local-storage}/index.mjs +19 -3
  22. package/dist/hooks/use-local-storage/index.mjs.map +1 -0
  23. package/dist/hooks/{useRecursiveTimeout → use-recursive-timeout}/index.d.mts +1 -1
  24. package/dist/hooks/{useRecursiveTimeout → use-recursive-timeout}/index.mjs +4 -2
  25. package/dist/hooks/use-recursive-timeout/index.mjs.map +1 -0
  26. package/dist/hooks/{useResponsiveSize → use-responsive-size}/index.d.mts +1 -1
  27. package/dist/hooks/{useResponsiveSize → use-responsive-size}/index.mjs +2 -2
  28. package/dist/hooks/use-responsive-size/index.mjs.map +1 -0
  29. package/dist/hooks/{useScrollToElements → use-scroll-to-elements}/index.d.mts +3 -3
  30. package/dist/hooks/use-scroll-to-elements/index.mjs +34 -0
  31. package/dist/hooks/use-scroll-to-elements/index.mjs.map +1 -0
  32. package/dist/hooks/{useThrottle → use-throttle}/index.d.mts +1 -1
  33. package/dist/hooks/{useThrottle → use-throttle}/index.mjs +1 -1
  34. package/dist/hooks/use-throttle/index.mjs.map +1 -0
  35. package/dist/hooks/use-timeline/index.d.mts +50 -0
  36. package/dist/hooks/use-timeline/index.mjs +176 -0
  37. package/dist/hooks/use-timeline/index.mjs.map +1 -0
  38. package/dist/hooks/{useViewport → use-viewport}/index.d.mts +1 -1
  39. package/dist/hooks/{useViewport → use-viewport}/index.mjs +1 -1
  40. package/dist/hooks/use-viewport/index.mjs.map +1 -0
  41. package/dist/hooks/{useWindowScroll → use-window-scroll}/index.d.mts +1 -1
  42. package/dist/hooks/{useWindowScroll → use-window-scroll}/index.mjs +1 -1
  43. package/dist/hooks/use-window-scroll/index.mjs.map +1 -0
  44. package/dist/index.d.mts +14 -13
  45. package/dist/index.mjs +14 -13
  46. package/package.json +14 -10
  47. package/dist/hooks/useBodyScrollLock/index.mjs.map +0 -1
  48. package/dist/hooks/useDebounce/index.mjs.map +0 -1
  49. package/dist/hooks/useElementPosition/index.mjs.map +0 -1
  50. package/dist/hooks/useElementScroll/index.mjs.map +0 -1
  51. package/dist/hooks/useImage/index.mjs.map +0 -1
  52. package/dist/hooks/useLocalStorage/index.mjs.map +0 -1
  53. package/dist/hooks/useRecursiveTimeout/index.mjs.map +0 -1
  54. package/dist/hooks/useResponsiveSize/index.mjs.map +0 -1
  55. package/dist/hooks/useScrollToElements/index.mjs +0 -34
  56. package/dist/hooks/useScrollToElements/index.mjs.map +0 -1
  57. package/dist/hooks/useThrottle/index.mjs.map +0 -1
  58. package/dist/hooks/useViewport/index.mjs.map +0 -1
  59. package/dist/hooks/useWindowScroll/index.mjs.map +0 -1
@@ -1,12 +1,12 @@
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/index.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
@@ -0,0 +1,34 @@
1
+ import { useCallback, useRef } from "react";
2
+
3
+ //#region src/hooks/use-scroll-to-elements/index.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=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/use-scroll-to-elements/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 | 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,4 +1,4 @@
1
- //#region src/hooks/useThrottle/index.d.ts
1
+ //#region src/hooks/use-throttle/index.d.ts
2
2
  declare const useThrottle: <T>(value: T, delay?: number) => T;
3
3
  //#endregion
4
4
  export { useThrottle };
@@ -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/index.ts
4
4
  const useThrottle = (value, delay = 100) => {
5
5
  const [throttledValue, setThrottledValue] = useState(value);
6
6
  const lastExecutedRef = useRef(0);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/use-throttle/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/use-timeline/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,176 @@
1
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/use-timeline/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
+ const rafId = requestAnimationFrame(() => {
140
+ timeline[slotIndex]?.forEach((step) => {
141
+ const stepTimers = applyStep(container, step);
142
+ if (stepTimers) timers.push(...stepTimers);
143
+ });
144
+ });
145
+ return () => {
146
+ cancelAnimationFrame(rafId);
147
+ timers.forEach(clearTimeout);
148
+ };
149
+ }, [
150
+ immediate,
151
+ slotIndex,
152
+ timeline
153
+ ]);
154
+ useEffect(() => {
155
+ if (immediate || loop || slotIndex < 0 || slotIndex < timeline.length - 1 || !timeline.length) return;
156
+ const lastSlot = timeline[slotIndex];
157
+ const maxDuration = Math.max(...lastSlot?.map((s) => s.transition.duration) ?? [0]);
158
+ const timerId = window.setTimeout(() => {
159
+ setCompleted(true);
160
+ }, maxDuration);
161
+ return () => clearTimeout(timerId);
162
+ }, [
163
+ slotIndex,
164
+ timeline,
165
+ immediate,
166
+ loop
167
+ ]);
168
+ return {
169
+ ref,
170
+ completed
171
+ };
172
+ };
173
+
174
+ //#endregion
175
+ export { useTimeline as default };
176
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/use-timeline/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 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/index.d.ts
2
2
  type ViewportInfo = VisualViewport | {
3
3
  width: number;
4
4
  height: number;
@@ -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/index.ts
4
4
  const useViewport = (options = {}) => {
5
5
  const { isInApp = false, debounce = 100 } = options;
6
6
  const [viewport, setViewport] = useState({
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/use-viewport/index.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/index.d.ts
2
2
  declare const useWindowScroll: () => {
3
3
  x: number;
4
4
  y: number;
@@ -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/index.ts
4
4
  const useWindowScroll = () => {
5
5
  const [state, setState] = useState({
6
6
  x: 0,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/use-window-scroll/index.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,14 +1,15 @@
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 { useWindowScroll } from "./hooks/useWindowScroll/index.mjs";
12
- import { useViewport } from "./hooks/useViewport/index.mjs";
1
+ import { useDebounce } from "./hooks/use-debounce/index.mjs";
2
+ import { useBodyScrollLock } from "./hooks/use-body-scroll-lock/index.mjs";
3
+ import { useElementPosition } from "./hooks/use-element-position/index.mjs";
4
+ import { useElementScroll } from "./hooks/use-element-scroll/index.mjs";
5
+ import { useResponsiveSize } from "./hooks/use-responsive-size/index.mjs";
6
+ import { useImage } from "./hooks/use-image/index.mjs";
7
+ import { useLocalStorage } from "./hooks/use-local-storage/index.mjs";
8
+ import { useRecursiveTimeout } from "./hooks/use-recursive-timeout/index.mjs";
9
+ import { useScrollToElements } from "./hooks/use-scroll-to-elements/index.mjs";
10
+ import { useThrottle } from "./hooks/use-throttle/index.mjs";
11
+ import { useTimeline } from "./hooks/use-timeline/index.mjs";
12
+ import { useWindowScroll } from "./hooks/use-window-scroll/index.mjs";
13
+ import { useViewport } from "./hooks/use-viewport/index.mjs";
13
14
  import "./hooks/index.mjs";
14
- export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useViewport, useWindowScroll };
15
+ export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
package/dist/index.mjs 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 useWindowScroll from "./hooks/useWindowScroll/index.mjs";
12
- import useViewport from "./hooks/useViewport/index.mjs";
1
+ import useDebounce from "./hooks/use-debounce/index.mjs";
2
+ import useBodyScrollLock from "./hooks/use-body-scroll-lock/index.mjs";
3
+ import useElementPosition from "./hooks/use-element-position/index.mjs";
4
+ import useElementScroll from "./hooks/use-element-scroll/index.mjs";
5
+ import useResponsiveSize from "./hooks/use-responsive-size/index.mjs";
6
+ import useImage from "./hooks/use-image/index.mjs";
7
+ import useLocalStorage from "./hooks/use-local-storage/index.mjs";
8
+ import useRecursiveTimeout from "./hooks/use-recursive-timeout/index.mjs";
9
+ import useScrollToElements from "./hooks/use-scroll-to-elements/index.mjs";
10
+ import useThrottle from "./hooks/use-throttle/index.mjs";
11
+ import useTimeline from "./hooks/use-timeline/index.mjs";
12
+ import useWindowScroll from "./hooks/use-window-scroll/index.mjs";
13
+ import useViewport from "./hooks/use-viewport/index.mjs";
13
14
  import "./hooks/index.mjs";
14
15
 
15
- export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useViewport, useWindowScroll };
16
+ export { useBodyScrollLock, 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.1.0",
3
+ "version": "2.2.1",
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,12 +38,19 @@
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",
44
55
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
45
56
  "@types/node": "^24.5.2",
@@ -70,12 +81,5 @@
70
81
  "bash -c 'pnpm lint'",
71
82
  "bash -c 'tsc -b'"
72
83
  ]
73
- },
74
- "scripts": {
75
- "dev": "vite",
76
- "build": "tsc -b && tsdown",
77
- "lint": "eslint .",
78
- "preview": "vite preview",
79
- "changeset": "changeset"
80
84
  }
81
- }
85
+ }
@@ -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"}
@@ -1 +0,0 @@
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"}