@pol-studios/hooks 1.0.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/dist/_utils/index.js +29 -0
- package/dist/chunk-AIS4L5ID.js +151 -0
- package/dist/chunk-BHNC4MM6.js +29 -0
- package/dist/chunk-BKB34ZQJ.js +41 -0
- package/dist/chunk-EVE7TM7O.js +67 -0
- package/dist/chunk-EZXGO56T.js +370 -0
- package/dist/chunk-GKXIKVGH.js +157 -0
- package/dist/chunk-IFSEJVAF.js +135 -0
- package/dist/chunk-MMIPLCL4.js +4149 -0
- package/dist/chunk-OF7JZIAL.js +39 -0
- package/dist/chunk-QGM4M3NI.js +37 -0
- package/dist/chunk-RX4FIJI6.js +130 -0
- package/dist/chunk-VVFZ7HTT.js +133 -0
- package/dist/chunk-XIISC67B.js +67 -0
- package/dist/debug/index.js +14 -0
- package/dist/device/index.js +24 -0
- package/dist/file/index.js +12 -0
- package/dist/form/index.js +13 -0
- package/dist/index.js +192 -0
- package/dist/lifecycle/index.js +12 -0
- package/dist/network/index.js +12 -0
- package/dist/scroll/index.js +16 -0
- package/dist/state/index.js +21 -0
- package/dist/storage/index.js +38 -0
- package/dist/toast/index.js +15 -0
- package/package.json +50 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isUsable
|
|
3
|
+
} from "./chunk-MMIPLCL4.js";
|
|
4
|
+
|
|
5
|
+
// src/scroll/useScrollPosition.ts
|
|
6
|
+
import { useState, useEffect, useMemo } from "react";
|
|
7
|
+
function useScrollPosition(elementRef) {
|
|
8
|
+
const [scrollY, setScrollY] = useState(0);
|
|
9
|
+
const [scrollHeight, setHeight] = useState(0);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (isUsable(elementRef)) {
|
|
12
|
+
const element = elementRef.current;
|
|
13
|
+
if (element === null) return;
|
|
14
|
+
const handleScroll = () => {
|
|
15
|
+
const newScrollPosition = element.scrollTop;
|
|
16
|
+
setScrollY(newScrollPosition);
|
|
17
|
+
setHeight(element.scrollHeight);
|
|
18
|
+
};
|
|
19
|
+
element.addEventListener("scroll", handleScroll);
|
|
20
|
+
return () => {
|
|
21
|
+
element.removeEventListener("scroll", handleScroll);
|
|
22
|
+
};
|
|
23
|
+
} else {
|
|
24
|
+
const handleScroll = () => {
|
|
25
|
+
setScrollY(window.scrollY);
|
|
26
|
+
setHeight(document.body.scrollHeight - window.innerHeight);
|
|
27
|
+
};
|
|
28
|
+
window.addEventListener("scroll", handleScroll);
|
|
29
|
+
return () => {
|
|
30
|
+
window.removeEventListener("scroll", handleScroll);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}, [elementRef]);
|
|
34
|
+
return useMemo(() => {
|
|
35
|
+
return { scrollY, scrollHeight };
|
|
36
|
+
}, [scrollY, scrollHeight]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/scroll/useScrollDirection.ts
|
|
40
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
41
|
+
function useScrollDirection(elementRef, threshold) {
|
|
42
|
+
const [isUserScrollingUp, setIsUserScrollingUp] = useState2(true);
|
|
43
|
+
const [lastScrollTop, setLastScrollTop] = useState2(0);
|
|
44
|
+
useEffect2(() => {
|
|
45
|
+
if (elementRef.current === null) return;
|
|
46
|
+
const element = elementRef.current;
|
|
47
|
+
const handleScroll = () => {
|
|
48
|
+
const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
49
|
+
if (currentScrollTop > lastScrollTop) {
|
|
50
|
+
if (currentScrollTop > threshold && isUserScrollingUp) {
|
|
51
|
+
setIsUserScrollingUp(false);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
if (currentScrollTop < threshold && !isUserScrollingUp) {
|
|
55
|
+
setIsUserScrollingUp(true);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
setLastScrollTop(currentScrollTop <= 0 ? 0 : currentScrollTop);
|
|
59
|
+
};
|
|
60
|
+
element.addEventListener("scroll", handleScroll);
|
|
61
|
+
return () => {
|
|
62
|
+
element.removeEventListener("scroll", handleScroll);
|
|
63
|
+
};
|
|
64
|
+
}, [lastScrollTop, isUserScrollingUp, threshold, elementRef]);
|
|
65
|
+
return isUserScrollingUp;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/scroll/useScrollRestoration.ts
|
|
69
|
+
import { debounce } from "lodash";
|
|
70
|
+
import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
|
|
71
|
+
function useScrollRestoration(scrollAreaId, ref) {
|
|
72
|
+
const key = `sp-${scrollAreaId}`;
|
|
73
|
+
const item = ref ? ref.current : window;
|
|
74
|
+
const [savedPosition] = useState3(() => parseInt(sessionStorage.getItem(key) || ""));
|
|
75
|
+
const saveScrollPosition = useCallback(
|
|
76
|
+
debounce(() => {
|
|
77
|
+
if (item !== window) {
|
|
78
|
+
sessionStorage.setItem(key, item.scrollTop.toString());
|
|
79
|
+
} else {
|
|
80
|
+
sessionStorage.setItem(key, window.scrollY.toString());
|
|
81
|
+
}
|
|
82
|
+
}, 200),
|
|
83
|
+
[ref, scrollAreaId]
|
|
84
|
+
);
|
|
85
|
+
useEffect3(() => {
|
|
86
|
+
if (savedPosition && item) {
|
|
87
|
+
if (item !== window) {
|
|
88
|
+
item.scrollTop = savedPosition;
|
|
89
|
+
} else {
|
|
90
|
+
window.scrollTo(0, savedPosition);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}, [ref]);
|
|
94
|
+
useEffect3(() => {
|
|
95
|
+
if (isUsable(scrollAreaId) === false || scrollAreaId === "" || item === null)
|
|
96
|
+
return;
|
|
97
|
+
item.addEventListener("scroll", saveScrollPosition);
|
|
98
|
+
return () => {
|
|
99
|
+
item?.removeEventListener("scroll", saveScrollPosition);
|
|
100
|
+
};
|
|
101
|
+
}, [ref, scrollAreaId]);
|
|
102
|
+
return savedPosition;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/scroll/useHideOnScroll.ts
|
|
106
|
+
import { useMotionValue } from "framer-motion";
|
|
107
|
+
import { useRef, useState as useState4, useEffect as useEffect4 } from "react";
|
|
108
|
+
function useHideOnScroll({ height, scrollRef, initialPercentVisible = 1 }) {
|
|
109
|
+
const scrollY = useScrollPosition(scrollRef).scrollY;
|
|
110
|
+
const element = scrollRef ? scrollRef.current : window;
|
|
111
|
+
const clientHeight = scrollRef ? scrollRef.current?.clientHeight : document.body.scrollHeight;
|
|
112
|
+
const percentVisible = useMotionValue(initialPercentVisible);
|
|
113
|
+
const [totalScrolled, setTotalScrolled] = useState4(0);
|
|
114
|
+
const [baseLine, setBaseLine] = useState4(scrollY);
|
|
115
|
+
const componentReady = useRef(false);
|
|
116
|
+
useEffect4(() => {
|
|
117
|
+
componentReady.current = false;
|
|
118
|
+
new Promise((resolve) => setTimeout(resolve, 1e3)).then(() => {
|
|
119
|
+
componentReady.current = true;
|
|
120
|
+
});
|
|
121
|
+
}, [element]);
|
|
122
|
+
const [scrollStartTime, setScrollStartTime] = useState4(null);
|
|
123
|
+
useEffect4(() => {
|
|
124
|
+
if (element === null) return;
|
|
125
|
+
if (componentReady.current === false) return;
|
|
126
|
+
const amountScrolled = baseLine - scrollY;
|
|
127
|
+
if (Math.abs(totalScrolled - amountScrolled) < 5) return;
|
|
128
|
+
const isScrollingUp = amountScrolled > 0;
|
|
129
|
+
const isAtBottom = scrollY >= (clientHeight ?? 0) - window.innerHeight;
|
|
130
|
+
if (isScrollingUp && amountScrolled > -height && isAtBottom == false) {
|
|
131
|
+
const percentScrolled = amountScrolled / height;
|
|
132
|
+
const newOpacity = Math.min(1, Math.max(0, percentVisible.get() + percentScrolled));
|
|
133
|
+
percentVisible.set(newOpacity);
|
|
134
|
+
} else if (!isScrollingUp && amountScrolled < 0 && totalScrolled < height && scrollY > height * 5) {
|
|
135
|
+
const percentScrolled = Math.abs(amountScrolled) / height;
|
|
136
|
+
const newOpacity = Math.max(0, Math.min(1, percentVisible.get() - percentScrolled));
|
|
137
|
+
percentVisible.set(newOpacity);
|
|
138
|
+
}
|
|
139
|
+
if (isScrollingUp || amountScrolled === 0) {
|
|
140
|
+
setScrollStartTime(null);
|
|
141
|
+
} else if (scrollStartTime === null && Math.abs(amountScrolled) >= height) {
|
|
142
|
+
setScrollStartTime((/* @__PURE__ */ new Date()).getTime());
|
|
143
|
+
}
|
|
144
|
+
setBaseLine(scrollY);
|
|
145
|
+
setTotalScrolled((x) => x + amountScrolled);
|
|
146
|
+
}, [scrollY]);
|
|
147
|
+
return percentVisible.get() ?? 1;
|
|
148
|
+
}
|
|
149
|
+
var useHidingOnScroll = useHideOnScroll;
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
useScrollPosition,
|
|
153
|
+
useScrollDirection,
|
|
154
|
+
useScrollRestoration,
|
|
155
|
+
useHideOnScroll,
|
|
156
|
+
useHidingOnScroll
|
|
157
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useLocalStorageService
|
|
3
|
+
} from "./chunk-OF7JZIAL.js";
|
|
4
|
+
|
|
5
|
+
// src/network/useOnline.ts
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
import { onlineManager } from "@tanstack/react-query";
|
|
8
|
+
function useOnline() {
|
|
9
|
+
const [isOnline, setIsOnline] = useState(() => onlineManager.isOnline());
|
|
10
|
+
const [wasOffline, setWasOffline] = useState(false);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const unsubscribe = onlineManager.subscribe((online) => {
|
|
13
|
+
const wasOfflineBefore = !isOnline;
|
|
14
|
+
setIsOnline(online);
|
|
15
|
+
if (wasOfflineBefore && online) {
|
|
16
|
+
setWasOffline(true);
|
|
17
|
+
setTimeout(() => setWasOffline(false), 2e3);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return unsubscribe;
|
|
21
|
+
}, [isOnline]);
|
|
22
|
+
return {
|
|
23
|
+
isOnline,
|
|
24
|
+
isOffline: !isOnline,
|
|
25
|
+
wasOffline
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
var useNetworkStatus = useOnline;
|
|
29
|
+
|
|
30
|
+
// src/network/useMutationQueue.ts
|
|
31
|
+
import { useEffect as useEffect2, useRef, useState as useState2, useCallback } from "react";
|
|
32
|
+
var QUEUE_STORAGE_KEY = "pol-offline-mutation-queue";
|
|
33
|
+
var MAX_RETRIES = 3;
|
|
34
|
+
function useMutationQueue() {
|
|
35
|
+
const { isOnline } = useOnline();
|
|
36
|
+
const localStorageService = useLocalStorageService();
|
|
37
|
+
const [queuedMutations, setQueuedMutations] = useState2([]);
|
|
38
|
+
const isProcessingRef = useRef(false);
|
|
39
|
+
useEffect2(() => {
|
|
40
|
+
try {
|
|
41
|
+
const stored = localStorageService.getItem(QUEUE_STORAGE_KEY);
|
|
42
|
+
if (stored) {
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
}
|
|
46
|
+
}, [localStorageService]);
|
|
47
|
+
useEffect2(() => {
|
|
48
|
+
try {
|
|
49
|
+
localStorageService.setItem(
|
|
50
|
+
QUEUE_STORAGE_KEY,
|
|
51
|
+
JSON.stringify({ count: queuedMutations.length })
|
|
52
|
+
);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
}
|
|
55
|
+
}, [queuedMutations.length, localStorageService]);
|
|
56
|
+
const processQueue = useCallback(async () => {
|
|
57
|
+
if (!isOnline || isProcessingRef.current) return;
|
|
58
|
+
isProcessingRef.current = true;
|
|
59
|
+
try {
|
|
60
|
+
let mutationsToProcess = [];
|
|
61
|
+
setQueuedMutations((prev) => {
|
|
62
|
+
mutationsToProcess = [...prev];
|
|
63
|
+
return prev;
|
|
64
|
+
});
|
|
65
|
+
for (const queuedMutation of mutationsToProcess) {
|
|
66
|
+
try {
|
|
67
|
+
await queuedMutation.mutationFn();
|
|
68
|
+
setQueuedMutations(
|
|
69
|
+
(prev) => prev.filter((m) => m.id !== queuedMutation.id)
|
|
70
|
+
);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const updatedMutation = {
|
|
73
|
+
...queuedMutation,
|
|
74
|
+
retryCount: queuedMutation.retryCount + 1,
|
|
75
|
+
error
|
|
76
|
+
};
|
|
77
|
+
if (updatedMutation.retryCount >= MAX_RETRIES) {
|
|
78
|
+
setQueuedMutations(
|
|
79
|
+
(prev) => prev.filter((m) => m.id !== queuedMutation.id)
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
setQueuedMutations(
|
|
83
|
+
(prev) => prev.map((m) => m.id === queuedMutation.id ? updatedMutation : m)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
isProcessingRef.current = false;
|
|
90
|
+
}
|
|
91
|
+
}, [isOnline]);
|
|
92
|
+
useEffect2(() => {
|
|
93
|
+
if (isOnline && queuedMutations.length > 0 && !isProcessingRef.current) {
|
|
94
|
+
processQueue();
|
|
95
|
+
}
|
|
96
|
+
}, [isOnline, queuedMutations.length, processQueue]);
|
|
97
|
+
const queueMutation = (mutationKey, mutationFn, variables) => {
|
|
98
|
+
const queuedMutation = {
|
|
99
|
+
id: crypto.randomUUID(),
|
|
100
|
+
mutationKey,
|
|
101
|
+
mutationFn,
|
|
102
|
+
variables,
|
|
103
|
+
timestamp: Date.now(),
|
|
104
|
+
retryCount: 0
|
|
105
|
+
};
|
|
106
|
+
setQueuedMutations((prev) => [...prev, queuedMutation]);
|
|
107
|
+
if (isOnline && !isProcessingRef.current) {
|
|
108
|
+
processQueue();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const removeQueuedMutation = (id) => {
|
|
112
|
+
setQueuedMutations((prev) => prev.filter((m) => m.id !== id));
|
|
113
|
+
};
|
|
114
|
+
const clearQueue = () => {
|
|
115
|
+
setQueuedMutations([]);
|
|
116
|
+
try {
|
|
117
|
+
localStorageService.removeItem(QUEUE_STORAGE_KEY);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
queuedMutations,
|
|
123
|
+
queueMutation,
|
|
124
|
+
removeQueuedMutation,
|
|
125
|
+
clearQueue,
|
|
126
|
+
processQueue,
|
|
127
|
+
queueCount: queuedMutations.length
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
useOnline,
|
|
133
|
+
useNetworkStatus,
|
|
134
|
+
useMutationQueue
|
|
135
|
+
};
|