@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.
- package/README.ko.md +18 -10
- package/README.md +16 -10
- package/dist/hooks/index.d.mts +13 -0
- package/dist/hooks/index.mjs +15 -0
- package/dist/hooks/useBodyScrollLock/index.d.mts +5 -0
- package/dist/hooks/useBodyScrollLock/index.mjs +115 -0
- package/dist/hooks/useBodyScrollLock/index.mjs.map +1 -0
- package/dist/hooks/useDebounce/index.d.mts +12 -0
- package/dist/hooks/useDebounce/index.mjs +41 -0
- package/dist/hooks/useDebounce/index.mjs.map +1 -0
- package/dist/hooks/useElementPosition/index.d.mts +8 -0
- package/dist/hooks/useElementPosition/index.mjs +32 -0
- package/dist/hooks/useElementPosition/index.mjs.map +1 -0
- package/dist/hooks/useElementScroll/index.d.mts +15 -0
- package/dist/hooks/useElementScroll/index.mjs +68 -0
- package/dist/hooks/useElementScroll/index.mjs.map +1 -0
- package/dist/hooks/useImage/index.d.mts +14 -0
- package/dist/hooks/useImage/index.mjs +56 -0
- package/dist/hooks/useImage/index.mjs.map +1 -0
- package/dist/hooks/useLocalStorage/index.d.mts +5 -0
- package/dist/hooks/useLocalStorage/index.mjs +40 -0
- package/dist/hooks/useLocalStorage/index.mjs.map +1 -0
- package/dist/hooks/useRecursiveTimeout/index.d.mts +5 -0
- package/dist/hooks/useRecursiveTimeout/index.mjs +27 -0
- package/dist/hooks/useRecursiveTimeout/index.mjs.map +1 -0
- package/dist/hooks/useResponsiveSize/index.d.mts +26 -0
- package/dist/hooks/useResponsiveSize/index.mjs +108 -0
- package/dist/hooks/useResponsiveSize/index.mjs.map +1 -0
- package/dist/hooks/useScrollToElements/index.d.mts +14 -0
- package/dist/hooks/useScrollToElements/index.mjs +34 -0
- package/dist/hooks/useScrollToElements/index.mjs.map +1 -0
- package/dist/hooks/useThrottle/index.d.mts +5 -0
- package/dist/hooks/useThrottle/index.mjs +42 -0
- package/dist/hooks/useThrottle/index.mjs.map +1 -0
- package/dist/hooks/useTimeline/index.d.mts +50 -0
- package/dist/hooks/useTimeline/index.mjs +175 -0
- package/dist/hooks/useTimeline/index.mjs.map +1 -0
- package/dist/hooks/useViewport/index.d.mts +18 -0
- package/dist/hooks/useViewport/index.mjs +87 -0
- package/dist/hooks/useViewport/index.mjs.map +1 -0
- package/dist/hooks/useWindowScroll/index.d.mts +12 -0
- package/dist/hooks/useWindowScroll/index.mjs +60 -0
- package/dist/hooks/useWindowScroll/index.mjs.map +1 -0
- package/dist/index.d.mts +15 -0
- package/dist/index.mjs +16 -0
- package/package.json +7 -8
- package/dist/index.cjs +0 -1
- package/dist/index.d.ts +0 -106
- package/dist/index.js +0 -424
- package/dist/vite.svg +0 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/useViewport/index.ts
|
|
4
|
+
const useViewport = (options = {}) => {
|
|
5
|
+
const { isInApp = false, debounce = 100 } = options;
|
|
6
|
+
const [viewport, setViewport] = useState({
|
|
7
|
+
width: 0,
|
|
8
|
+
height: 0,
|
|
9
|
+
offsetLeft: 0,
|
|
10
|
+
offsetTop: 0,
|
|
11
|
+
pageLeft: 0,
|
|
12
|
+
pageTop: 0,
|
|
13
|
+
scale: 1
|
|
14
|
+
});
|
|
15
|
+
const getAppViewHeight = useCallback(() => {
|
|
16
|
+
const windowHeight = window.innerHeight;
|
|
17
|
+
const visualHeight = window.visualViewport?.height || windowHeight;
|
|
18
|
+
const documentHeight = document.documentElement.clientHeight;
|
|
19
|
+
const bodyHeight = document.body.clientHeight;
|
|
20
|
+
if (window.visualViewport && Math.abs(visualHeight - windowHeight) > 100) return visualHeight;
|
|
21
|
+
return Math.max(windowHeight, documentHeight, bodyHeight);
|
|
22
|
+
}, []);
|
|
23
|
+
const readViewport = useCallback(() => {
|
|
24
|
+
if (window.visualViewport && !isInApp) return window.visualViewport;
|
|
25
|
+
return {
|
|
26
|
+
width: window.visualViewport?.width || window.innerWidth,
|
|
27
|
+
height: isInApp ? getAppViewHeight() : window.visualViewport?.height || window.innerHeight,
|
|
28
|
+
offsetLeft: window.visualViewport?.offsetLeft || 0,
|
|
29
|
+
offsetTop: window.visualViewport?.offsetTop || 0,
|
|
30
|
+
pageLeft: window.scrollX ?? window.pageXOffset ?? 0,
|
|
31
|
+
pageTop: window.scrollY ?? window.pageYOffset ?? 0,
|
|
32
|
+
scale: window.visualViewport?.scale || 1
|
|
33
|
+
};
|
|
34
|
+
}, [isInApp, getAppViewHeight]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
let timeoutId;
|
|
37
|
+
const debouncedUpdate = () => {
|
|
38
|
+
clearTimeout(timeoutId);
|
|
39
|
+
timeoutId = setTimeout(() => {
|
|
40
|
+
setViewport(readViewport());
|
|
41
|
+
}, debounce);
|
|
42
|
+
};
|
|
43
|
+
const immediateUpdate = () => setViewport(readViewport());
|
|
44
|
+
immediateUpdate();
|
|
45
|
+
const events = ["resize", "orientationchange"];
|
|
46
|
+
if (isInApp) events.push("focus", "blur", "touchstart", "touchend");
|
|
47
|
+
events.forEach((event) => {
|
|
48
|
+
if (event === "resize" || event === "orientationchange") window.addEventListener(event, debouncedUpdate);
|
|
49
|
+
else window.addEventListener(event, immediateUpdate, { passive: true });
|
|
50
|
+
});
|
|
51
|
+
if (window.visualViewport) {
|
|
52
|
+
window.visualViewport.addEventListener("resize", immediateUpdate);
|
|
53
|
+
window.visualViewport.addEventListener("scroll", immediateUpdate);
|
|
54
|
+
}
|
|
55
|
+
let intervalId;
|
|
56
|
+
if (isInApp) {
|
|
57
|
+
let lastHeight = readViewport().height;
|
|
58
|
+
intervalId = setInterval(() => {
|
|
59
|
+
const currentHeight = readViewport().height;
|
|
60
|
+
if (Math.abs(currentHeight - lastHeight) > 50) {
|
|
61
|
+
lastHeight = currentHeight;
|
|
62
|
+
immediateUpdate();
|
|
63
|
+
}
|
|
64
|
+
}, 500);
|
|
65
|
+
}
|
|
66
|
+
return () => {
|
|
67
|
+
clearTimeout(timeoutId);
|
|
68
|
+
if (intervalId) clearInterval(intervalId);
|
|
69
|
+
events.forEach((event) => {
|
|
70
|
+
window.removeEventListener(event, event === "resize" || event === "orientationchange" ? debouncedUpdate : immediateUpdate);
|
|
71
|
+
});
|
|
72
|
+
if (window.visualViewport) {
|
|
73
|
+
window.visualViewport.removeEventListener("resize", immediateUpdate);
|
|
74
|
+
window.visualViewport.removeEventListener("scroll", immediateUpdate);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}, [
|
|
78
|
+
readViewport,
|
|
79
|
+
isInApp,
|
|
80
|
+
debounce
|
|
81
|
+
]);
|
|
82
|
+
return viewport;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { useViewport as default };
|
|
87
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useViewport/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: NodeJS.Timeout;\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: NodeJS.Timeout;\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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/useWindowScroll/index.ts
|
|
4
|
+
const useWindowScroll = () => {
|
|
5
|
+
const [state, setState] = useState({
|
|
6
|
+
x: 0,
|
|
7
|
+
y: 0,
|
|
8
|
+
percent: {
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const calculate = () => {
|
|
15
|
+
const x = window.scrollX || 0;
|
|
16
|
+
const y = window.scrollY || 0;
|
|
17
|
+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
18
|
+
const visualViewport = window.visualViewport;
|
|
19
|
+
const viewportWidth = isIOS && visualViewport ? visualViewport.width : window.innerWidth;
|
|
20
|
+
const viewportHeight = isIOS && visualViewport ? visualViewport.height : window.innerHeight;
|
|
21
|
+
const maxScrollX = Math.max(0, document.documentElement.scrollWidth - viewportWidth);
|
|
22
|
+
const maxScrollY = Math.max(0, document.documentElement.scrollHeight - viewportHeight);
|
|
23
|
+
const percentX = maxScrollX === 0 ? 0 : Math.min(100, x / maxScrollX * 100);
|
|
24
|
+
const percentY = maxScrollY === 0 ? 0 : Math.min(100, y / maxScrollY * 100);
|
|
25
|
+
setState({
|
|
26
|
+
x,
|
|
27
|
+
y,
|
|
28
|
+
percent: {
|
|
29
|
+
x: Math.floor(Math.max(0, percentX)),
|
|
30
|
+
y: Math.floor(Math.max(0, percentY))
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
calculate();
|
|
35
|
+
const onScroll = () => {
|
|
36
|
+
calculate();
|
|
37
|
+
};
|
|
38
|
+
const onResize = () => {
|
|
39
|
+
setTimeout(calculate, 100);
|
|
40
|
+
};
|
|
41
|
+
const onVisualViewportChange = () => {
|
|
42
|
+
setTimeout(calculate, 50);
|
|
43
|
+
};
|
|
44
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
45
|
+
window.addEventListener("resize", onResize);
|
|
46
|
+
window.addEventListener("orientationchange", onResize);
|
|
47
|
+
if (window.visualViewport) window.visualViewport.addEventListener("resize", onVisualViewportChange);
|
|
48
|
+
return () => {
|
|
49
|
+
window.removeEventListener("scroll", onScroll);
|
|
50
|
+
window.removeEventListener("resize", onResize);
|
|
51
|
+
window.removeEventListener("orientationchange", onResize);
|
|
52
|
+
if (window.visualViewport) window.visualViewport.removeEventListener("resize", onVisualViewportChange);
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
55
|
+
return state;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { useWindowScroll as default };
|
|
60
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/hooks/useWindowScroll/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
ADDED
|
@@ -0,0 +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 { useTimeline } from "./hooks/useTimeline/index.mjs";
|
|
12
|
+
import { useWindowScroll } from "./hooks/useWindowScroll/index.mjs";
|
|
13
|
+
import { useViewport } from "./hooks/useViewport/index.mjs";
|
|
14
|
+
import "./hooks/index.mjs";
|
|
15
|
+
export { useBodyScrollLock, useDebounce, useElementPosition, useElementScroll, useImage, useLocalStorage, useRecursiveTimeout, useResponsiveSize, useScrollToElements, useThrottle, useTimeline, useViewport, useWindowScroll };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import useDebounce from "./hooks/useDebounce/index.mjs";
|
|
2
|
+
import useBodyScrollLock from "./hooks/useBodyScrollLock/index.mjs";
|
|
3
|
+
import useElementPosition from "./hooks/useElementPosition/index.mjs";
|
|
4
|
+
import useElementScroll from "./hooks/useElementScroll/index.mjs";
|
|
5
|
+
import useResponsiveSize from "./hooks/useResponsiveSize/index.mjs";
|
|
6
|
+
import useImage from "./hooks/useImage/index.mjs";
|
|
7
|
+
import useLocalStorage from "./hooks/useLocalStorage/index.mjs";
|
|
8
|
+
import useRecursiveTimeout from "./hooks/useRecursiveTimeout/index.mjs";
|
|
9
|
+
import useScrollToElements from "./hooks/useScrollToElements/index.mjs";
|
|
10
|
+
import useThrottle from "./hooks/useThrottle/index.mjs";
|
|
11
|
+
import useTimeline from "./hooks/useTimeline/index.mjs";
|
|
12
|
+
import useWindowScroll from "./hooks/useWindowScroll/index.mjs";
|
|
13
|
+
import useViewport from "./hooks/useViewport/index.mjs";
|
|
14
|
+
import "./hooks/index.mjs";
|
|
15
|
+
|
|
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.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A collection of reusable React 19 hooks for common UI and interaction patterns",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -22,15 +22,13 @@
|
|
|
22
22
|
},
|
|
23
23
|
"private": false,
|
|
24
24
|
"type": "module",
|
|
25
|
-
"main": "./dist/index.
|
|
26
|
-
"
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
25
|
+
"main": "./dist/index.mjs",
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
28
27
|
"exports": {
|
|
29
28
|
".": {
|
|
30
29
|
"source": "./src/index.ts",
|
|
31
|
-
"types": "./dist/index.d.
|
|
32
|
-
"import": "./dist/index.
|
|
33
|
-
"require": "./dist/index.cjs"
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
31
|
+
"import": "./dist/index.mjs"
|
|
34
32
|
}
|
|
35
33
|
},
|
|
36
34
|
"files": [
|
|
@@ -60,6 +58,7 @@
|
|
|
60
58
|
"prettier-plugin-tailwindcss": "^0.6.14",
|
|
61
59
|
"react": "^19.1.1",
|
|
62
60
|
"react-dom": "^19.1.1",
|
|
61
|
+
"tsdown": "^0.20.3",
|
|
63
62
|
"typescript": "~5.8.3",
|
|
64
63
|
"typescript-eslint": "^8.39.1",
|
|
65
64
|
"vite": "^7.1.2",
|
|
@@ -74,7 +73,7 @@
|
|
|
74
73
|
},
|
|
75
74
|
"scripts": {
|
|
76
75
|
"dev": "vite",
|
|
77
|
-
"build": "tsc -b &&
|
|
76
|
+
"build": "tsc -b && tsdown",
|
|
78
77
|
"lint": "eslint .",
|
|
79
78
|
"preview": "vite preview",
|
|
80
79
|
"changeset": "changeset"
|
package/dist/index.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react"),L=(e,{delay:o=100,autoInvoke:d=!0},t=[])=>{const s=n.useRef(null),c=n.useRef(e),i=n.useRef(t),l=n.useRef(void 0);n.useEffect(()=>{c.current=e}),n.useEffect(()=>{i.current=t});const r=n.useRef(null);return r.current||(r.current=((...u)=>{s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{c.current(...u)},o)})),n.useEffect(()=>{const u=l.current===void 0||l.current.length!==t.length||l.current.some((w,a)=>w!==t[a]);u&&s.current&&clearTimeout(s.current),d&&u&&(l.current===void 0?c.current():r.current&&r.current()),l.current=t}),n.useEffect(()=>()=>{s.current&&clearTimeout(s.current)},[]),r.current},T=(e=!0)=>{n.useEffect(()=>{if(!e)return;const o=window.scrollY,d=/iPad|iPhone|iPod/.test(navigator.userAgent),t={documentElement:{overflow:document.documentElement.style.overflow,height:document.documentElement.style.height,position:document.documentElement.style.position,width:document.documentElement.style.width},body:{overflow:document.body.style.overflow,height:document.body.style.height,position:document.body.style.position,top:document.body.style.top,left:document.body.style.left,right:document.body.style.right,width:document.body.style.width,webkitOverflowScrolling:document.body.style.getPropertyValue("-webkit-overflow-scrolling")}};if(document.documentElement.style.overflow="hidden",document.documentElement.style.height="100%",document.documentElement.style.position="fixed",document.documentElement.style.width="100%",document.body.style.overflow="hidden",document.body.style.height="100%",document.body.style.position="fixed",document.body.style.top=`-${o}px`,document.body.style.left="0",document.body.style.right="0",document.body.style.width="100%",d){document.body.style.setProperty("-webkit-overflow-scrolling","touch");const s=r=>{(r.target===document.body||r.target===document.documentElement||r.target===window)&&(r.preventDefault(),r.stopPropagation(),r.stopImmediatePropagation())},c=()=>{window.scrollTo(0,0),document.body.scrollTop=0,document.documentElement.scrollTop=0},i=["scroll","touchmove","touchstart","touchend"];i.forEach(r=>{window.addEventListener(r,s,{passive:!1,capture:!0}),document.addEventListener(r,s,{passive:!1,capture:!0}),document.body.addEventListener(r,s,{passive:!1,capture:!0})});const l=setInterval(c,16);return()=>{clearInterval(l),i.forEach(r=>{window.removeEventListener(r,s,{capture:!0}),document.removeEventListener(r,s,{capture:!0}),document.body.removeEventListener(r,s,{capture:!0})}),document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,t.body.webkitOverflowScrolling?document.body.style.setProperty("-webkit-overflow-scrolling",t.body.webkitOverflowScrolling):document.body.style.removeProperty("-webkit-overflow-scrolling"),window.scrollTo(0,o)}}return()=>{document.documentElement.style.overflow=t.documentElement.overflow,document.documentElement.style.height=t.documentElement.height,document.documentElement.style.position=t.documentElement.position,document.documentElement.style.width=t.documentElement.width,document.body.style.overflow=t.body.overflow,document.body.style.height=t.body.height,document.body.style.position=t.body.position,document.body.style.top=t.body.top,document.body.style.left=t.body.left,document.body.style.right=t.body.right,document.body.style.width=t.body.width,window.scrollTo(0,o)}},[e])},x=e=>{const[o,d]=n.useState(null);return n.useEffect(()=>{const t=i=>typeof i=="string"?document.querySelector(i):i.current,s=()=>{const i=t(e);d(i?i.getBoundingClientRect():null)},c=()=>{requestAnimationFrame(s)};return s(),window.addEventListener("scroll",c,{passive:!0}),window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("scroll",c),window.removeEventListener("resize",c)}},[e]),o},R=()=>{const[e,o]=n.useState(null),[d,t]=n.useState({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!1,scrollableHeight:0,clientHeight:0,scrollHeight:0}),s=n.useCallback(c=>{o(c)},[]);return n.useEffect(()=>{if(!e)return;const c=()=>{const{scrollTop:r,scrollHeight:u,clientHeight:w}=e,a=u-w;if(a<=0){t({scrollY:0,scrollPercentage:0,isAtTop:!0,isAtBottom:!0,scrollableHeight:0,clientHeight:w,scrollHeight:u});return}const m=Math.min(100,Math.max(0,r/a*100));t({scrollY:r,scrollPercentage:m,isAtTop:r<=0,isAtBottom:r>=a-1,scrollableHeight:a,clientHeight:w,scrollHeight:u})};c();const i=()=>{c()};e.addEventListener("scroll",i,{passive:!0});const l=new ResizeObserver(()=>{c()});return l.observe(e),()=>{e.removeEventListener("scroll",i),l.unobserve(e)}},[e]),{...d,element:e,setRef:s}},f={sm:640,md:768,lg:1024,xl:1280,"2xl":1536},V=e=>{let o="xs";return e>=f["2xl"]?o="2xl":e>=f.xl?o="xl":e>=f.lg?o="lg":e>=f.md?o="md":e>=f.sm?o="sm":o="xs",{current:o,xs:e<f.sm,sm:e>=f.sm&&e<f.md,md:e>=f.md&&e<f.lg,lg:e>=f.lg&&e<f.xl,xl:e>=f.xl&&e<f["2xl"],"2xl":e>=f["2xl"]}},z=e=>{const{delay:o=100,container:d}=e||{},[t,s]=n.useState({width:0,height:0}),[c,i]=n.useState({current:"xs",xs:!0,sm:!1,md:!1,lg:!1,xl:!1,"2xl":!1}),[l,r]=n.useState({width:0,height:0}),[u,w]=n.useState(null),a=n.useRef(null),m=n.useCallback(h=>{w(h)},[]);return L(()=>{r(t)},{delay:o},[t]),n.useEffect(()=>{const h=()=>{const y=d??u??document.body;if(!y)return;const{offsetWidth:b,offsetHeight:E}=y;s(p=>p.width!==b||p.height!==E?{width:b,height:E}:p),i(p=>{const S=V(b);return p.current!==S.current?S:p})},g=()=>{const y=d??u??document.body;y&&(h(),a.current&&a.current.disconnect(),a.current=new ResizeObserver(()=>{requestAnimationFrame(()=>{h()})}),a.current.observe(y))},v=()=>{a.current&&(a.current.disconnect(),a.current=null)};return g(),()=>{v()}},[d,u]),{size:l,breakpoint:c,ref:m}},P=(e,o={})=>{const{retryCount:d=0,retryDelay:t=1e3}=o,[s,c]=n.useState(!0),[i,l]=n.useState(null),[r,u]=n.useState(!1),[w,a]=n.useState(0),m=n.useCallback(()=>{if(!e){c(!1),u(!1);return}c(!0),l(null);const g=new Image;g.src=e,g.onload=()=>{c(!1),u(!0),l(null),a(0)},g.onerror=v=>{c(!1),u(!1),l(v),w<d&&setTimeout(()=>{a(y=>y+1)},t)}},[e,w,d,t]);n.useEffect(()=>{m()},[m]);const h=n.useCallback(()=>{a(0),m()},[m]);return{loading:s,error:i,loaded:r,retry:h}},H=(e,o)=>{const d=n.useRef(o),[t,s]=n.useState(()=>{if(typeof window>"u")return o;try{const i=window.localStorage.getItem(e);return i?JSON.parse(i):o}catch{return o}});n.useEffect(()=>{if(!(typeof window>"u"))try{const i=window.localStorage.getItem(e);i?s(JSON.parse(i)):window.localStorage.setItem(e,JSON.stringify(d.current))}catch(i){console.error(`Error reading localStorage key "${e}":`,i)}},[e]);const c=n.useCallback(i=>{try{s(l=>{const r=i instanceof Function?i(l):i;return localStorage.setItem(e,JSON.stringify(r)),r})}catch(l){console.error(`Error setting localStorage key "${e}":`,l)}},[e]);return[t,c]},I=(e,o)=>{const d=n.useRef(e);n.useEffect(()=>{d.current=e},[e]),n.useEffect(()=>{let t;function s(){const c=d.current();c instanceof Promise?c.then(()=>{o&&(t=setTimeout(s,o))}):o&&(t=setTimeout(s,o))}if(o)return t=setTimeout(s,o),()=>t&&clearTimeout(t)},[o])},k=e=>{const o=n.useRef([]),d=n.useCallback(s=>{if(o.current[s]&&(o.current[s].scrollIntoView({behavior:"smooth",block:"start",inline:"start",...e}),e?.offset)){const c=o.current[s].getBoundingClientRect().top+window.scrollY-e.offset;window.scrollTo({top:c,behavior:e.behavior||"smooth"})}},[e]),t=n.useCallback((s,c)=>{o.current[c]=s},[]);return{elementRefs:o,setElementRef:t,scrollToElement:d}},C=()=>{const[e,o]=n.useState({x:0,y:0,percent:{x:0,y:0}});return n.useEffect(()=>{const d=()=>{const i=window.scrollX||0,l=window.scrollY||0,r=/iPad|iPhone|iPod/.test(navigator.userAgent),u=window.visualViewport,w=r&&u?u.width:window.innerWidth,a=r&&u?u.height:window.innerHeight,m=Math.max(0,document.documentElement.scrollWidth-w),h=Math.max(0,document.documentElement.scrollHeight-a),g=m===0?0:Math.min(100,i/m*100),v=h===0?0:Math.min(100,l/h*100);o({x:i,y:l,percent:{x:Math.floor(Math.max(0,g)),y:Math.floor(Math.max(0,v))}})};d();const t=()=>{d()},s=()=>{setTimeout(d,100)},c=()=>{setTimeout(d,50)};return window.addEventListener("scroll",t,{passive:!0}),window.addEventListener("resize",s),window.addEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.addEventListener("resize",c),()=>{window.removeEventListener("scroll",t),window.removeEventListener("resize",s),window.removeEventListener("orientationchange",s),window.visualViewport&&window.visualViewport.removeEventListener("resize",c)}},[]),e},O=(e={})=>{const{isInApp:o=!1,debounce:d=100}=e,[t,s]=n.useState({width:0,height:0,offsetLeft:0,offsetTop:0,pageLeft:0,pageTop:0,scale:1}),c=n.useCallback(()=>{const l=window.innerHeight,r=window.visualViewport?.height||l,u=document.documentElement.clientHeight,w=document.body.clientHeight;return window.visualViewport&&Math.abs(r-l)>100?r:Math.max(l,u,w)},[]),i=n.useCallback(()=>{if(window.visualViewport&&!o)return window.visualViewport;const l=window.visualViewport?.width||window.innerWidth,r=o?c():window.visualViewport?.height||window.innerHeight;return{width:l,height:r,offsetLeft:window.visualViewport?.offsetLeft||0,offsetTop:window.visualViewport?.offsetTop||0,pageLeft:window.scrollX??window.pageXOffset??0,pageTop:window.scrollY??window.pageYOffset??0,scale:window.visualViewport?.scale||1}},[o,c]);return n.useEffect(()=>{let l;const r=()=>{clearTimeout(l),l=setTimeout(()=>{s(i())},d)},u=()=>s(i());u();const w=["resize","orientationchange"];o&&w.push("focus","blur","touchstart","touchend"),w.forEach(m=>{m==="resize"||m==="orientationchange"?window.addEventListener(m,r):window.addEventListener(m,u,{passive:!0})}),window.visualViewport&&(window.visualViewport.addEventListener("resize",u),window.visualViewport.addEventListener("scroll",u));let a;if(o){let m=i().height;a=setInterval(()=>{const h=i().height;Math.abs(h-m)>50&&(m=h,u())},500)}return()=>{clearTimeout(l),a&&clearInterval(a),w.forEach(m=>{window.removeEventListener(m,m==="resize"||m==="orientationchange"?r:u)}),window.visualViewport&&(window.visualViewport.removeEventListener("resize",u),window.visualViewport.removeEventListener("scroll",u))}},[i,o,d]),t};exports.useBodyScrollLock=T;exports.useDebounce=L;exports.useElementPosition=x;exports.useElementScroll=R;exports.useImage=P;exports.useLocalStorage=H;exports.useRecursiveTimeout=I;exports.useResponsiveSize=z;exports.useScrollToElements=k;exports.useViewport=O;exports.useWindowScroll=C;
|
package/dist/index.d.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
|
|
3
|
-
declare type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
4
|
-
|
|
5
|
-
declare interface BreakpointInfo {
|
|
6
|
-
current: Breakpoint;
|
|
7
|
-
xs: boolean;
|
|
8
|
-
sm: boolean;
|
|
9
|
-
md: boolean;
|
|
10
|
-
lg: boolean;
|
|
11
|
-
xl: boolean;
|
|
12
|
-
'2xl': boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
declare type ElementReference<T> = string | RefObject<T>;
|
|
16
|
-
|
|
17
|
-
declare interface Options {
|
|
18
|
-
delay?: number;
|
|
19
|
-
autoInvoke?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
declare interface Options_2 {
|
|
23
|
-
delay?: number;
|
|
24
|
-
container?: HTMLElement | null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
declare interface Options_3 {
|
|
28
|
-
retryCount?: number;
|
|
29
|
-
retryDelay?: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
declare interface Options_4 extends ScrollIntoViewOptions {
|
|
33
|
-
offset?: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
declare interface Options_5 {
|
|
37
|
-
isInApp?: boolean;
|
|
38
|
-
debounce?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export declare const useBodyScrollLock: (enabled?: boolean) => void;
|
|
42
|
-
|
|
43
|
-
export declare const useDebounce: <T extends (...args: unknown[]) => unknown>(callback: T, { delay, autoInvoke }: Options, deps?: React.DependencyList) => T;
|
|
44
|
-
|
|
45
|
-
export declare const useElementPosition: <T>(elementRef: ElementReference<T>) => DOMRect | null;
|
|
46
|
-
|
|
47
|
-
export declare const useElementScroll: () => {
|
|
48
|
-
element: HTMLElement | null;
|
|
49
|
-
setRef: (el: HTMLElement | null) => void;
|
|
50
|
-
scrollY: number;
|
|
51
|
-
scrollPercentage: number;
|
|
52
|
-
isAtTop: boolean;
|
|
53
|
-
isAtBottom: boolean;
|
|
54
|
-
scrollableHeight: number;
|
|
55
|
-
clientHeight: number;
|
|
56
|
-
scrollHeight: number;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export declare const useImage: (src: string, options?: Options_3) => {
|
|
60
|
-
loading: boolean;
|
|
61
|
-
error: string | Event | null;
|
|
62
|
-
loaded: boolean;
|
|
63
|
-
retry: () => void;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export declare const useLocalStorage: <T>(key: string, initialValue: T) => readonly [T, (value: T | ((val: T) => T)) => void];
|
|
67
|
-
|
|
68
|
-
export declare const useRecursiveTimeout: <T>(callback: () => Promise<T> | (() => void), delay: number | null) => void;
|
|
69
|
-
|
|
70
|
-
export declare const useResponsiveSize: <T extends HTMLElement>(options?: Options_2) => {
|
|
71
|
-
size: {
|
|
72
|
-
width: number;
|
|
73
|
-
height: number;
|
|
74
|
-
};
|
|
75
|
-
breakpoint: BreakpointInfo;
|
|
76
|
-
ref: (node: T | null) => void;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export declare const useScrollToElements: (options?: Options_4) => {
|
|
80
|
-
elementRefs: RefObject<HTMLElement[]>;
|
|
81
|
-
setElementRef: (element: HTMLElement, index: number) => void;
|
|
82
|
-
scrollToElement: (index: number) => void;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export declare const useViewport: (options?: Options_5) => ViewportInfo;
|
|
86
|
-
|
|
87
|
-
export declare const useWindowScroll: () => {
|
|
88
|
-
x: number;
|
|
89
|
-
y: number;
|
|
90
|
-
percent: {
|
|
91
|
-
x: number;
|
|
92
|
-
y: number;
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
declare type ViewportInfo = VisualViewport | {
|
|
97
|
-
width: number;
|
|
98
|
-
height: number;
|
|
99
|
-
offsetLeft: number;
|
|
100
|
-
offsetTop: number;
|
|
101
|
-
pageLeft: number;
|
|
102
|
-
pageTop: number;
|
|
103
|
-
scale: number;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
export { }
|