hookery 0.0.1 → 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/README.md +72 -11
- package/dist/bridges/auth0.d.mts +16 -0
- package/dist/bridges/auth0.d.ts +16 -0
- package/dist/bridges/auth0.js +3015 -0
- package/dist/bridges/auth0.js.map +1 -0
- package/dist/bridges/auth0.mjs +2977 -0
- package/dist/bridges/auth0.mjs.map +1 -0
- package/dist/bridges/axios.d.mts +17 -0
- package/dist/bridges/axios.d.ts +17 -0
- package/dist/bridges/axios.js +15351 -0
- package/dist/bridges/axios.js.map +1 -0
- package/dist/bridges/axios.mjs +15347 -0
- package/dist/bridges/axios.mjs.map +1 -0
- package/dist/bridges/clerk.d.mts +1 -0
- package/dist/bridges/clerk.d.ts +1 -0
- package/dist/bridges/clerk.js +5991 -0
- package/dist/bridges/clerk.js.map +1 -0
- package/dist/bridges/clerk.mjs +5985 -0
- package/dist/bridges/clerk.mjs.map +1 -0
- package/dist/bridges/firebase.d.mts +14 -0
- package/dist/bridges/firebase.d.ts +14 -0
- package/dist/bridges/firebase.js +52 -0
- package/dist/bridges/firebase.js.map +1 -0
- package/dist/bridges/firebase.mjs +25 -0
- package/dist/bridges/firebase.mjs.map +1 -0
- package/dist/bridges/jotai.d.mts +11 -0
- package/dist/bridges/jotai.d.ts +11 -0
- package/dist/bridges/jotai.js +870 -0
- package/dist/bridges/jotai.js.map +1 -0
- package/dist/bridges/jotai.mjs +827 -0
- package/dist/bridges/jotai.mjs.map +1 -0
- package/dist/bridges/motion.d.mts +6 -0
- package/dist/bridges/motion.d.ts +6 -0
- package/dist/bridges/motion.js +3752 -0
- package/dist/bridges/motion.js.map +1 -0
- package/dist/bridges/motion.mjs +3721 -0
- package/dist/bridges/motion.mjs.map +1 -0
- package/dist/bridges/next.d.mts +10 -0
- package/dist/bridges/next.d.ts +10 -0
- package/dist/bridges/next.js +2588 -0
- package/dist/bridges/next.js.map +1 -0
- package/dist/bridges/next.mjs +2582 -0
- package/dist/bridges/next.mjs.map +1 -0
- package/dist/bridges/redux.d.mts +15 -0
- package/dist/bridges/redux.d.ts +15 -0
- package/dist/bridges/redux.js +410 -0
- package/dist/bridges/redux.js.map +1 -0
- package/dist/bridges/redux.mjs +402 -0
- package/dist/bridges/redux.mjs.map +1 -0
- package/dist/bridges/remix.d.mts +1 -0
- package/dist/bridges/remix.d.ts +1 -0
- package/dist/bridges/remix.js +2215 -0
- package/dist/bridges/remix.js.map +1 -0
- package/dist/bridges/remix.mjs +2174 -0
- package/dist/bridges/remix.mjs.map +1 -0
- package/dist/bridges/stripe.d.mts +15 -0
- package/dist/bridges/stripe.d.ts +15 -0
- package/dist/bridges/stripe.js +1572 -0
- package/dist/bridges/stripe.js.map +1 -0
- package/dist/bridges/stripe.mjs +1556 -0
- package/dist/bridges/stripe.mjs.map +1 -0
- package/dist/bridges/supabase.d.mts +13 -0
- package/dist/bridges/supabase.d.ts +13 -0
- package/dist/bridges/supabase.js +51 -0
- package/dist/bridges/supabase.js.map +1 -0
- package/dist/bridges/supabase.mjs +24 -0
- package/dist/bridges/supabase.mjs.map +1 -0
- package/dist/bridges/tanstack.d.mts +3 -0
- package/dist/bridges/tanstack.d.ts +3 -0
- package/dist/bridges/tanstack.js +1319 -0
- package/dist/bridges/tanstack.js.map +1 -0
- package/dist/bridges/tanstack.mjs +1281 -0
- package/dist/bridges/tanstack.mjs.map +1 -0
- package/dist/bridges/yup.d.mts +16 -0
- package/dist/bridges/yup.d.ts +16 -0
- package/dist/bridges/yup.js +80 -0
- package/dist/bridges/yup.js.map +1 -0
- package/dist/bridges/yup.mjs +43 -0
- package/dist/bridges/yup.mjs.map +1 -0
- package/dist/bridges/zod.d.mts +19 -0
- package/dist/bridges/zod.d.ts +19 -0
- package/dist/bridges/zod.js +66 -0
- package/dist/bridges/zod.js.map +1 -0
- package/dist/bridges/zod.mjs +39 -0
- package/dist/bridges/zod.mjs.map +1 -0
- package/dist/bridges/zustand.d.mts +14 -0
- package/dist/bridges/zustand.d.ts +14 -0
- package/dist/bridges/zustand.js +58 -0
- package/dist/bridges/zustand.js.map +1 -0
- package/dist/bridges/zustand.mjs +21 -0
- package/dist/bridges/zustand.mjs.map +1 -0
- package/dist/index.d.mts +3124 -8
- package/dist/index.d.ts +3124 -8
- package/dist/index.js +4290 -10
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4172 -7
- package/dist/index.mjs.map +1 -0
- package/package.json +131 -6
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,22 +17,4300 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
isBrowser: () => isBrowser,
|
|
34
|
+
isServer: () => isServer,
|
|
35
|
+
noop: () => noop,
|
|
36
|
+
useAnimate: () => useAnimate,
|
|
37
|
+
useAnthropic: () => useAnthropic,
|
|
38
|
+
useAsync: () => useAsync,
|
|
39
|
+
useAudioRef: () => useAudioRef,
|
|
40
|
+
useBattery: () => useBattery,
|
|
41
|
+
useBluetooth: () => useBluetooth,
|
|
42
|
+
useBroadcastChannel: () => useBroadcastChannel,
|
|
43
|
+
useCalendar: () => useCalendar,
|
|
44
|
+
useCanvas: () => useCanvas,
|
|
45
|
+
useClickAnywhere: () => useClickAnywhere,
|
|
46
|
+
useClickOutside: () => useClickOutside,
|
|
47
|
+
useCopyToClipboard: () => useCopyToClipboard,
|
|
48
|
+
useCountdown: () => useCountdown,
|
|
49
|
+
useCounter: () => useCounter,
|
|
50
|
+
useDebounce: () => useDebounce,
|
|
51
|
+
useDebounceCallback: () => useDebounceCallback,
|
|
52
|
+
useDocumentTitle: () => useDocumentTitle,
|
|
53
|
+
useDragAndDrop: () => useDragAndDrop,
|
|
54
|
+
useEmbeddings: () => useEmbeddings,
|
|
55
|
+
useEvent: () => useEvent,
|
|
56
|
+
useEyeDropper: () => useEyeDropper,
|
|
57
|
+
useFetch: () => useFetch,
|
|
58
|
+
useFileProcessing: () => useFileProcessing,
|
|
59
|
+
useFileSystem: () => useFileSystem,
|
|
60
|
+
useForm: () => useForm,
|
|
61
|
+
useFrameRate: () => useFrameRate,
|
|
62
|
+
useFullscreen: () => useFullscreen,
|
|
63
|
+
useGamepad: () => useGamepad,
|
|
64
|
+
useGemini: () => useGemini,
|
|
65
|
+
useHistory: () => useHistory,
|
|
66
|
+
useHover: () => useHover,
|
|
67
|
+
useIndexedDB: () => useIndexedDB,
|
|
68
|
+
useInfiniteScroll: () => useInfiniteScroll,
|
|
69
|
+
useIntersection: () => useIntersection,
|
|
70
|
+
useInterval: () => useInterval,
|
|
71
|
+
useIsClient: () => useIsClient,
|
|
72
|
+
useIsMounted: () => useIsMounted,
|
|
73
|
+
useIsomorphicLayoutEffect: () => useIsomorphicLayoutEffect,
|
|
74
|
+
useKeyPress: () => useKeyPress,
|
|
75
|
+
useLLMStream: () => useLLMStream,
|
|
76
|
+
useList: () => useList,
|
|
77
|
+
useLocalStorage: () => useLocalStorage,
|
|
78
|
+
useLockBodyScroll: () => useLockBodyScroll,
|
|
79
|
+
useLongPress: () => useLongPress,
|
|
80
|
+
useLottie: () => useLottie,
|
|
81
|
+
useMachine: () => useMachine,
|
|
82
|
+
useMap: () => useMap,
|
|
83
|
+
useMarkdown: () => useMarkdown,
|
|
84
|
+
useMediaDevices: () => useMediaDevices,
|
|
85
|
+
useMediaQuery: () => useMediaQuery,
|
|
86
|
+
useMediaRecorder: () => useMediaRecorder,
|
|
87
|
+
useMount: () => useMount,
|
|
88
|
+
useMutationObserver: () => useMutationObserver,
|
|
89
|
+
useNetworkState: () => useNetworkState,
|
|
90
|
+
useOnline: () => useOnline,
|
|
91
|
+
useOpenAI: () => useOpenAI,
|
|
92
|
+
usePDF: () => usePDF,
|
|
93
|
+
usePageLeave: () => usePageLeave,
|
|
94
|
+
usePagination: () => usePagination,
|
|
95
|
+
useParallax: () => useParallax,
|
|
96
|
+
usePermissions: () => usePermissions,
|
|
97
|
+
usePresence: () => usePresence,
|
|
98
|
+
usePrevious: () => usePrevious,
|
|
99
|
+
useQueue: () => useQueue,
|
|
100
|
+
useRAG: () => useRAG,
|
|
101
|
+
useRealtimeCollab: () => useRealtimeCollab,
|
|
102
|
+
useResizeObserver: () => useResizeObserver,
|
|
103
|
+
useSTT: () => useSTT,
|
|
104
|
+
useSVGAnimation: () => useSVGAnimation,
|
|
105
|
+
useScreen: () => useScreen,
|
|
106
|
+
useScript: () => useScript,
|
|
107
|
+
useScroll: () => useScroll,
|
|
108
|
+
useSearchHighlight: () => useSearchHighlight,
|
|
109
|
+
useSemanticSearch: () => useSemanticSearch,
|
|
110
|
+
useSessionStorage: () => useSessionStorage,
|
|
111
|
+
useSet: () => useSet,
|
|
112
|
+
useShare: () => useShare,
|
|
113
|
+
useShortcuts: () => useShortcuts,
|
|
114
|
+
useSortable: () => useSortable,
|
|
115
|
+
useSpreadsheet: () => useSpreadsheet,
|
|
116
|
+
useSpringCore: () => useSpringCore,
|
|
117
|
+
useStableCallback: () => useStableCallback,
|
|
118
|
+
useStep: () => useStep,
|
|
119
|
+
useStorageEstimate: () => useStorageEstimate,
|
|
120
|
+
useTTS: () => useTTS,
|
|
121
|
+
useTable: () => useTable,
|
|
122
|
+
useTheme: () => useTheme,
|
|
123
|
+
useThreeJS: () => useThreeJS,
|
|
124
|
+
useThrottle: () => useThrottle,
|
|
125
|
+
useTimeout: () => useTimeout,
|
|
126
|
+
useToggle: () => useToggle,
|
|
127
|
+
useUnmount: () => useUnmount,
|
|
128
|
+
useUpdateEffect: () => useUpdateEffect,
|
|
129
|
+
useVideoRef: () => useVideoRef,
|
|
130
|
+
useVirtualList: () => useVirtualList,
|
|
131
|
+
useWakeLock: () => useWakeLock,
|
|
132
|
+
useWebRTC: () => useWebRTC,
|
|
133
|
+
useWebSocket: () => useWebSocket,
|
|
134
|
+
useWindowFocus: () => useWindowFocus,
|
|
135
|
+
useWindowSize: () => useWindowSize,
|
|
136
|
+
useWorker: () => useWorker
|
|
25
137
|
});
|
|
26
|
-
module.exports = __toCommonJS(
|
|
27
|
-
|
|
28
|
-
|
|
138
|
+
module.exports = __toCommonJS(src_exports);
|
|
139
|
+
|
|
140
|
+
// src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.ts
|
|
141
|
+
var import_react = require("react");
|
|
142
|
+
|
|
143
|
+
// src/utils/index.ts
|
|
144
|
+
var isServer = typeof window === "undefined";
|
|
145
|
+
var isBrowser = !isServer;
|
|
146
|
+
var noop = () => {
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.ts
|
|
150
|
+
var useIsomorphicLayoutEffect = isServer ? import_react.useEffect : import_react.useLayoutEffect;
|
|
151
|
+
|
|
152
|
+
// src/hooks/useToggle/useToggle.ts
|
|
153
|
+
var import_react2 = require("react");
|
|
154
|
+
function useToggle(options = {}) {
|
|
155
|
+
const { initialValue = false } = options;
|
|
156
|
+
const [value, setValue] = (0, import_react2.useState)(initialValue);
|
|
157
|
+
const toggle = (0, import_react2.useCallback)(() => setValue((prev) => !prev), []);
|
|
158
|
+
const setTrue = (0, import_react2.useCallback)(() => setValue(true), []);
|
|
159
|
+
const setFalse = (0, import_react2.useCallback)(() => setValue(false), []);
|
|
160
|
+
return {
|
|
161
|
+
value,
|
|
162
|
+
toggle,
|
|
163
|
+
setTrue,
|
|
164
|
+
setFalse,
|
|
165
|
+
setValue
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/hooks/useCounter/useCounter.ts
|
|
170
|
+
var import_react3 = require("react");
|
|
171
|
+
function useCounter(options = {}) {
|
|
172
|
+
const { initialValue = 0, min, max, step = 1 } = options;
|
|
173
|
+
const clamp = (0, import_react3.useCallback)(
|
|
174
|
+
(value) => {
|
|
175
|
+
let result = value;
|
|
176
|
+
if (min !== void 0 && result < min) result = min;
|
|
177
|
+
if (max !== void 0 && result > max) result = max;
|
|
178
|
+
return result;
|
|
179
|
+
},
|
|
180
|
+
[min, max]
|
|
181
|
+
);
|
|
182
|
+
const [count, setCount] = (0, import_react3.useState)(() => clamp(initialValue));
|
|
183
|
+
const increment = (0, import_react3.useCallback)(() => {
|
|
184
|
+
setCount((prev) => clamp(prev + step));
|
|
185
|
+
}, [clamp, step]);
|
|
186
|
+
const decrement = (0, import_react3.useCallback)(() => {
|
|
187
|
+
setCount((prev) => clamp(prev - step));
|
|
188
|
+
}, [clamp, step]);
|
|
189
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
190
|
+
setCount(clamp(initialValue));
|
|
191
|
+
}, [clamp, initialValue]);
|
|
192
|
+
const set = (0, import_react3.useCallback)(
|
|
193
|
+
(value) => {
|
|
194
|
+
setCount(clamp(value));
|
|
195
|
+
},
|
|
196
|
+
[clamp]
|
|
197
|
+
);
|
|
198
|
+
return {
|
|
199
|
+
count,
|
|
200
|
+
increment,
|
|
201
|
+
decrement,
|
|
202
|
+
reset,
|
|
203
|
+
set
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/hooks/usePrevious/usePrevious.ts
|
|
208
|
+
var import_react4 = require("react");
|
|
209
|
+
function usePrevious(value) {
|
|
210
|
+
const ref = (0, import_react4.useRef)(void 0);
|
|
211
|
+
(0, import_react4.useEffect)(() => {
|
|
212
|
+
ref.current = value;
|
|
213
|
+
}, [value]);
|
|
214
|
+
return ref.current;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/hooks/useMount/useMount.ts
|
|
218
|
+
var import_react5 = require("react");
|
|
219
|
+
function useMount(callback) {
|
|
220
|
+
const callbackRef = (0, import_react5.useRef)(callback);
|
|
221
|
+
callbackRef.current = callback;
|
|
222
|
+
(0, import_react5.useEffect)(() => {
|
|
223
|
+
return callbackRef.current();
|
|
224
|
+
}, []);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/hooks/useUnmount/useUnmount.ts
|
|
228
|
+
var import_react6 = require("react");
|
|
229
|
+
function useUnmount(callback) {
|
|
230
|
+
const callbackRef = (0, import_react6.useRef)(callback);
|
|
231
|
+
callbackRef.current = callback;
|
|
232
|
+
(0, import_react6.useEffect)(() => {
|
|
233
|
+
return () => {
|
|
234
|
+
callbackRef.current();
|
|
235
|
+
};
|
|
236
|
+
}, []);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/hooks/useDebounce/useDebounce.ts
|
|
240
|
+
var import_react7 = require("react");
|
|
241
|
+
function useDebounce(value, options = {}) {
|
|
242
|
+
const { delay = 500, leading = false, trailing = true } = options;
|
|
243
|
+
const [debouncedValue, setDebouncedValue] = (0, import_react7.useState)(value);
|
|
244
|
+
const [isPending, setIsPending] = (0, import_react7.useState)(false);
|
|
245
|
+
const timeoutRef = (0, import_react7.useRef)(null);
|
|
246
|
+
const leadingRef = (0, import_react7.useRef)(true);
|
|
247
|
+
const latestValueRef = (0, import_react7.useRef)(value);
|
|
248
|
+
latestValueRef.current = value;
|
|
249
|
+
const cancel = (0, import_react7.useCallback)(() => {
|
|
250
|
+
if (timeoutRef.current) {
|
|
251
|
+
clearTimeout(timeoutRef.current);
|
|
252
|
+
timeoutRef.current = null;
|
|
253
|
+
}
|
|
254
|
+
setIsPending(false);
|
|
255
|
+
}, []);
|
|
256
|
+
const flush = (0, import_react7.useCallback)(() => {
|
|
257
|
+
cancel();
|
|
258
|
+
setDebouncedValue(latestValueRef.current);
|
|
259
|
+
}, [cancel]);
|
|
260
|
+
(0, import_react7.useEffect)(() => {
|
|
261
|
+
if (leading && leadingRef.current) {
|
|
262
|
+
leadingRef.current = false;
|
|
263
|
+
setDebouncedValue(value);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
setIsPending(true);
|
|
267
|
+
if (timeoutRef.current) {
|
|
268
|
+
clearTimeout(timeoutRef.current);
|
|
269
|
+
}
|
|
270
|
+
timeoutRef.current = setTimeout(() => {
|
|
271
|
+
if (trailing) {
|
|
272
|
+
setDebouncedValue(value);
|
|
273
|
+
}
|
|
274
|
+
setIsPending(false);
|
|
275
|
+
timeoutRef.current = null;
|
|
276
|
+
}, delay);
|
|
277
|
+
return () => {
|
|
278
|
+
if (timeoutRef.current) {
|
|
279
|
+
clearTimeout(timeoutRef.current);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}, [value, delay, leading, trailing]);
|
|
283
|
+
(0, import_react7.useEffect)(() => {
|
|
284
|
+
return () => {
|
|
285
|
+
if (timeoutRef.current) {
|
|
286
|
+
clearTimeout(timeoutRef.current);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}, []);
|
|
290
|
+
return {
|
|
291
|
+
debouncedValue,
|
|
292
|
+
isPending,
|
|
293
|
+
cancel,
|
|
294
|
+
flush
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/hooks/useThrottle/useThrottle.ts
|
|
299
|
+
var import_react8 = require("react");
|
|
300
|
+
function useThrottle(value, options = {}) {
|
|
301
|
+
const { interval = 500, leading = true, trailing = true } = options;
|
|
302
|
+
const [throttledValue, setThrottledValue] = (0, import_react8.useState)(value);
|
|
303
|
+
const [isPending, setIsPending] = (0, import_react8.useState)(false);
|
|
304
|
+
const lastExecuted = (0, import_react8.useRef)(0);
|
|
305
|
+
const timeoutRef = (0, import_react8.useRef)(null);
|
|
306
|
+
const latestValue = (0, import_react8.useRef)(value);
|
|
307
|
+
const isFirstRun = (0, import_react8.useRef)(true);
|
|
308
|
+
latestValue.current = value;
|
|
309
|
+
(0, import_react8.useEffect)(() => {
|
|
310
|
+
const now = Date.now();
|
|
311
|
+
const elapsed = now - lastExecuted.current;
|
|
312
|
+
if (isFirstRun.current && leading) {
|
|
313
|
+
isFirstRun.current = false;
|
|
314
|
+
setThrottledValue(value);
|
|
315
|
+
lastExecuted.current = now;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
isFirstRun.current = false;
|
|
319
|
+
if (elapsed >= interval) {
|
|
320
|
+
if (timeoutRef.current) {
|
|
321
|
+
clearTimeout(timeoutRef.current);
|
|
322
|
+
timeoutRef.current = null;
|
|
323
|
+
}
|
|
324
|
+
setThrottledValue(value);
|
|
325
|
+
lastExecuted.current = now;
|
|
326
|
+
setIsPending(false);
|
|
327
|
+
} else if (trailing) {
|
|
328
|
+
setIsPending(true);
|
|
329
|
+
if (timeoutRef.current) {
|
|
330
|
+
clearTimeout(timeoutRef.current);
|
|
331
|
+
}
|
|
332
|
+
timeoutRef.current = setTimeout(() => {
|
|
333
|
+
setThrottledValue(latestValue.current);
|
|
334
|
+
lastExecuted.current = Date.now();
|
|
335
|
+
setIsPending(false);
|
|
336
|
+
timeoutRef.current = null;
|
|
337
|
+
}, interval - elapsed);
|
|
338
|
+
}
|
|
339
|
+
return () => {
|
|
340
|
+
if (timeoutRef.current) {
|
|
341
|
+
clearTimeout(timeoutRef.current);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}, [value, interval, leading, trailing]);
|
|
345
|
+
(0, import_react8.useEffect)(() => {
|
|
346
|
+
return () => {
|
|
347
|
+
if (timeoutRef.current) {
|
|
348
|
+
clearTimeout(timeoutRef.current);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}, []);
|
|
352
|
+
return {
|
|
353
|
+
throttledValue,
|
|
354
|
+
isPending
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/hooks/useLocalStorage/useLocalStorage.ts
|
|
359
|
+
var import_react9 = require("react");
|
|
360
|
+
function useLocalStorage(key, initialValue, options = {}) {
|
|
361
|
+
const {
|
|
362
|
+
serializer = JSON.stringify,
|
|
363
|
+
deserializer = JSON.parse,
|
|
364
|
+
syncAcrossTabs = true
|
|
365
|
+
} = options;
|
|
366
|
+
const readValue = (0, import_react9.useCallback)(() => {
|
|
367
|
+
if (isServer) {
|
|
368
|
+
return initialValue;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
const item = window.localStorage.getItem(key);
|
|
372
|
+
return item !== null ? deserializer(item) : initialValue;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.warn(`Error reading localStorage key "${key}":`, error);
|
|
375
|
+
return initialValue;
|
|
376
|
+
}
|
|
377
|
+
}, [key, initialValue, deserializer]);
|
|
378
|
+
const [storedValue, setStoredValue] = (0, import_react9.useState)(readValue);
|
|
379
|
+
const [exists, setExists] = (0, import_react9.useState)(() => {
|
|
380
|
+
if (isServer) return false;
|
|
381
|
+
return window.localStorage.getItem(key) !== null;
|
|
382
|
+
});
|
|
383
|
+
const setValue = (0, import_react9.useCallback)(
|
|
384
|
+
(value) => {
|
|
385
|
+
try {
|
|
386
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
387
|
+
setStoredValue(valueToStore);
|
|
388
|
+
setExists(true);
|
|
389
|
+
if (!isServer) {
|
|
390
|
+
window.localStorage.setItem(key, serializer(valueToStore));
|
|
391
|
+
window.dispatchEvent(
|
|
392
|
+
new StorageEvent("storage", {
|
|
393
|
+
key,
|
|
394
|
+
newValue: serializer(valueToStore)
|
|
395
|
+
})
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
} catch (error) {
|
|
399
|
+
console.warn(`Error setting localStorage key "${key}":`, error);
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
[key, serializer, storedValue]
|
|
403
|
+
);
|
|
404
|
+
const remove = (0, import_react9.useCallback)(() => {
|
|
405
|
+
try {
|
|
406
|
+
setStoredValue(initialValue);
|
|
407
|
+
setExists(false);
|
|
408
|
+
if (!isServer) {
|
|
409
|
+
window.localStorage.removeItem(key);
|
|
410
|
+
}
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.warn(`Error removing localStorage key "${key}":`, error);
|
|
413
|
+
}
|
|
414
|
+
}, [key, initialValue]);
|
|
415
|
+
(0, import_react9.useEffect)(() => {
|
|
416
|
+
if (isServer || !syncAcrossTabs) return;
|
|
417
|
+
const handleStorageChange = (event) => {
|
|
418
|
+
if (event.key === key && event.newValue !== null) {
|
|
419
|
+
try {
|
|
420
|
+
setStoredValue(deserializer(event.newValue));
|
|
421
|
+
setExists(true);
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
} else if (event.key === key && event.newValue === null) {
|
|
425
|
+
setStoredValue(initialValue);
|
|
426
|
+
setExists(false);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
window.addEventListener("storage", handleStorageChange);
|
|
430
|
+
return () => {
|
|
431
|
+
window.removeEventListener("storage", handleStorageChange);
|
|
432
|
+
};
|
|
433
|
+
}, [key, initialValue, deserializer, syncAcrossTabs]);
|
|
434
|
+
return {
|
|
435
|
+
value: storedValue,
|
|
436
|
+
setValue,
|
|
437
|
+
remove,
|
|
438
|
+
exists
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// src/hooks/useSessionStorage/useSessionStorage.ts
|
|
443
|
+
var import_react10 = require("react");
|
|
444
|
+
function useSessionStorage(key, initialValue, options = {}) {
|
|
445
|
+
const {
|
|
446
|
+
serializer = JSON.stringify,
|
|
447
|
+
deserializer = JSON.parse,
|
|
448
|
+
initializeWithValue = false
|
|
449
|
+
} = options;
|
|
450
|
+
const [storedValue, setStoredValue] = (0, import_react10.useState)(() => {
|
|
451
|
+
if (isServer) {
|
|
452
|
+
return typeof initialValue === "function" ? initialValue() : initialValue;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
const item = window.sessionStorage.getItem(key);
|
|
456
|
+
if (item && !initializeWithValue) {
|
|
457
|
+
return deserializer(item);
|
|
458
|
+
}
|
|
459
|
+
const value = typeof initialValue === "function" ? initialValue() : initialValue;
|
|
460
|
+
if (initializeWithValue) {
|
|
461
|
+
window.sessionStorage.setItem(key, serializer(value));
|
|
462
|
+
}
|
|
463
|
+
return value;
|
|
464
|
+
} catch (error) {
|
|
465
|
+
console.error(`Error reading sessionStorage key "${key}":`, error);
|
|
466
|
+
return typeof initialValue === "function" ? initialValue() : initialValue;
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
const setValue = (0, import_react10.useCallback)(
|
|
470
|
+
(value) => {
|
|
471
|
+
try {
|
|
472
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
473
|
+
setStoredValue(valueToStore);
|
|
474
|
+
if (!isServer) {
|
|
475
|
+
window.sessionStorage.setItem(key, serializer(valueToStore));
|
|
476
|
+
window.dispatchEvent(new Event("session-storage"));
|
|
477
|
+
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
console.error(`Error setting sessionStorage key "${key}":`, error);
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
[key, storedValue, serializer]
|
|
483
|
+
);
|
|
484
|
+
const removeValue = (0, import_react10.useCallback)(() => {
|
|
485
|
+
try {
|
|
486
|
+
setStoredValue(
|
|
487
|
+
typeof initialValue === "function" ? initialValue() : initialValue
|
|
488
|
+
);
|
|
489
|
+
if (!isServer) {
|
|
490
|
+
window.sessionStorage.removeItem(key);
|
|
491
|
+
window.dispatchEvent(new Event("session-storage"));
|
|
492
|
+
}
|
|
493
|
+
} catch (error) {
|
|
494
|
+
console.error(`Error removing sessionStorage key "${key}":`, error);
|
|
495
|
+
}
|
|
496
|
+
}, [key, initialValue]);
|
|
497
|
+
(0, import_react10.useEffect)(() => {
|
|
498
|
+
if (isServer) return;
|
|
499
|
+
const handleStorageChange = (e) => {
|
|
500
|
+
if (e.key === key && e.storageArea === window.sessionStorage) {
|
|
501
|
+
try {
|
|
502
|
+
if (e.newValue === null) {
|
|
503
|
+
setStoredValue(
|
|
504
|
+
typeof initialValue === "function" ? initialValue() : initialValue
|
|
505
|
+
);
|
|
506
|
+
} else {
|
|
507
|
+
setStoredValue(deserializer(e.newValue));
|
|
508
|
+
}
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error(`Error syncing sessionStorage key "${key}":`, error);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
window.addEventListener("storage", handleStorageChange);
|
|
515
|
+
return () => window.removeEventListener("storage", handleStorageChange);
|
|
516
|
+
}, [key, initialValue, deserializer]);
|
|
517
|
+
return [storedValue, setValue, removeValue];
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// src/hooks/useTimeout/useTimeout.ts
|
|
521
|
+
var import_react11 = require("react");
|
|
522
|
+
function useTimeout(callback, options) {
|
|
523
|
+
const { delay, autoStart = true } = options;
|
|
524
|
+
const [isRunning, setIsRunning] = (0, import_react11.useState)(autoStart);
|
|
525
|
+
const [isComplete, setIsComplete] = (0, import_react11.useState)(false);
|
|
526
|
+
const callbackRef = (0, import_react11.useRef)(callback);
|
|
527
|
+
const timeoutRef = (0, import_react11.useRef)(null);
|
|
528
|
+
callbackRef.current = callback;
|
|
529
|
+
const stop = (0, import_react11.useCallback)(() => {
|
|
530
|
+
if (timeoutRef.current) {
|
|
531
|
+
clearTimeout(timeoutRef.current);
|
|
532
|
+
timeoutRef.current = null;
|
|
533
|
+
}
|
|
534
|
+
setIsRunning(false);
|
|
535
|
+
}, []);
|
|
536
|
+
const start = (0, import_react11.useCallback)(() => {
|
|
537
|
+
stop();
|
|
538
|
+
setIsComplete(false);
|
|
539
|
+
setIsRunning(true);
|
|
540
|
+
timeoutRef.current = setTimeout(() => {
|
|
541
|
+
callbackRef.current();
|
|
542
|
+
setIsRunning(false);
|
|
543
|
+
setIsComplete(true);
|
|
544
|
+
timeoutRef.current = null;
|
|
545
|
+
}, delay);
|
|
546
|
+
}, [delay, stop]);
|
|
547
|
+
const reset = (0, import_react11.useCallback)(() => {
|
|
548
|
+
stop();
|
|
549
|
+
setIsComplete(false);
|
|
550
|
+
}, [stop]);
|
|
551
|
+
(0, import_react11.useEffect)(() => {
|
|
552
|
+
if (autoStart) {
|
|
553
|
+
start();
|
|
554
|
+
}
|
|
555
|
+
return () => {
|
|
556
|
+
if (timeoutRef.current) {
|
|
557
|
+
clearTimeout(timeoutRef.current);
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
}, [delay]);
|
|
561
|
+
return {
|
|
562
|
+
isRunning,
|
|
563
|
+
isComplete,
|
|
564
|
+
start,
|
|
565
|
+
stop,
|
|
566
|
+
reset
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/hooks/useInterval/useInterval.ts
|
|
571
|
+
var import_react12 = require("react");
|
|
572
|
+
function useInterval(callback, options) {
|
|
573
|
+
const { delay, autoStart = true, immediate = false } = options;
|
|
574
|
+
const [isRunning, setIsRunning] = (0, import_react12.useState)(autoStart);
|
|
575
|
+
const [count, setCount] = (0, import_react12.useState)(0);
|
|
576
|
+
const callbackRef = (0, import_react12.useRef)(callback);
|
|
577
|
+
const intervalRef = (0, import_react12.useRef)(null);
|
|
578
|
+
callbackRef.current = callback;
|
|
579
|
+
const stop = (0, import_react12.useCallback)(() => {
|
|
580
|
+
if (intervalRef.current) {
|
|
581
|
+
clearInterval(intervalRef.current);
|
|
582
|
+
intervalRef.current = null;
|
|
583
|
+
}
|
|
584
|
+
setIsRunning(false);
|
|
585
|
+
}, []);
|
|
586
|
+
const start = (0, import_react12.useCallback)(() => {
|
|
587
|
+
stop();
|
|
588
|
+
setIsRunning(true);
|
|
589
|
+
if (immediate) {
|
|
590
|
+
callbackRef.current();
|
|
591
|
+
setCount((c) => c + 1);
|
|
592
|
+
}
|
|
593
|
+
intervalRef.current = setInterval(() => {
|
|
594
|
+
callbackRef.current();
|
|
595
|
+
setCount((c) => c + 1);
|
|
596
|
+
}, delay);
|
|
597
|
+
}, [delay, immediate, stop]);
|
|
598
|
+
const reset = (0, import_react12.useCallback)(() => {
|
|
599
|
+
setCount(0);
|
|
600
|
+
}, []);
|
|
601
|
+
(0, import_react12.useEffect)(() => {
|
|
602
|
+
if (autoStart) {
|
|
603
|
+
start();
|
|
604
|
+
}
|
|
605
|
+
return () => {
|
|
606
|
+
if (intervalRef.current) {
|
|
607
|
+
clearInterval(intervalRef.current);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
}, [delay]);
|
|
611
|
+
return {
|
|
612
|
+
isRunning,
|
|
613
|
+
count,
|
|
614
|
+
start,
|
|
615
|
+
stop,
|
|
616
|
+
reset
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/hooks/useUpdateEffect/useUpdateEffect.ts
|
|
621
|
+
var import_react13 = require("react");
|
|
622
|
+
function useUpdateEffect(effect, deps) {
|
|
623
|
+
const isFirstMount = (0, import_react13.useRef)(true);
|
|
624
|
+
(0, import_react13.useEffect)(() => {
|
|
625
|
+
if (isFirstMount.current) {
|
|
626
|
+
isFirstMount.current = false;
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
return effect();
|
|
630
|
+
}, deps);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// src/hooks/useIsMounted/useIsMounted.ts
|
|
634
|
+
var import_react14 = require("react");
|
|
635
|
+
function useIsMounted() {
|
|
636
|
+
const isMountedRef = (0, import_react14.useRef)(false);
|
|
637
|
+
(0, import_react14.useEffect)(() => {
|
|
638
|
+
isMountedRef.current = true;
|
|
639
|
+
return () => {
|
|
640
|
+
isMountedRef.current = false;
|
|
641
|
+
};
|
|
642
|
+
}, []);
|
|
643
|
+
return (0, import_react14.useCallback)(() => isMountedRef.current, []);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/hooks/useStableCallback/useStableCallback.ts
|
|
647
|
+
var import_react15 = require("react");
|
|
648
|
+
function useStableCallback(callback) {
|
|
649
|
+
const callbackRef = (0, import_react15.useRef)(callback);
|
|
650
|
+
(0, import_react15.useEffect)(() => {
|
|
651
|
+
callbackRef.current = callback;
|
|
652
|
+
});
|
|
653
|
+
return (0, import_react15.useCallback)((...args) => {
|
|
654
|
+
return callbackRef.current(...args);
|
|
655
|
+
}, []);
|
|
656
|
+
}
|
|
657
|
+
var useStableCallback_default = useStableCallback;
|
|
658
|
+
|
|
659
|
+
// src/hooks/useMediaQuery/useMediaQuery.ts
|
|
660
|
+
var import_react16 = require("react");
|
|
661
|
+
function useMediaQuery(query, options = {}) {
|
|
662
|
+
const { defaultValue = false, initializeOnMount = false } = options;
|
|
663
|
+
const getMatches = (0, import_react16.useCallback)(() => {
|
|
664
|
+
if (isServer) {
|
|
665
|
+
return defaultValue;
|
|
666
|
+
}
|
|
667
|
+
return window.matchMedia(query).matches;
|
|
668
|
+
}, [query, defaultValue]);
|
|
669
|
+
const [matches, setMatches] = (0, import_react16.useState)(() => {
|
|
670
|
+
if (initializeOnMount) {
|
|
671
|
+
return defaultValue;
|
|
672
|
+
}
|
|
673
|
+
return getMatches();
|
|
674
|
+
});
|
|
675
|
+
(0, import_react16.useEffect)(() => {
|
|
676
|
+
if (isServer) return;
|
|
677
|
+
const mediaQueryList = window.matchMedia(query);
|
|
678
|
+
setMatches(mediaQueryList.matches);
|
|
679
|
+
const handleChange = (event) => {
|
|
680
|
+
setMatches(event.matches);
|
|
681
|
+
};
|
|
682
|
+
if (mediaQueryList.addEventListener) {
|
|
683
|
+
mediaQueryList.addEventListener("change", handleChange);
|
|
684
|
+
} else {
|
|
685
|
+
mediaQueryList.addListener(handleChange);
|
|
686
|
+
}
|
|
687
|
+
return () => {
|
|
688
|
+
if (mediaQueryList.removeEventListener) {
|
|
689
|
+
mediaQueryList.removeEventListener("change", handleChange);
|
|
690
|
+
} else {
|
|
691
|
+
mediaQueryList.removeListener(handleChange);
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
}, [query]);
|
|
695
|
+
return matches;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/hooks/useWindowSize/useWindowSize.ts
|
|
699
|
+
var import_react17 = require("react");
|
|
700
|
+
function useWindowSize(options = {}) {
|
|
701
|
+
const { debounce = 0, initialWidth = 0, initialHeight = 0 } = options;
|
|
702
|
+
const getSize = (0, import_react17.useCallback)(() => {
|
|
703
|
+
if (isServer) {
|
|
704
|
+
return { width: initialWidth, height: initialHeight };
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
width: window.innerWidth,
|
|
708
|
+
height: window.innerHeight
|
|
709
|
+
};
|
|
710
|
+
}, [initialWidth, initialHeight]);
|
|
711
|
+
const [windowSize, setWindowSize] = (0, import_react17.useState)(getSize);
|
|
712
|
+
(0, import_react17.useEffect)(() => {
|
|
713
|
+
if (isServer) return;
|
|
714
|
+
let timeoutId = null;
|
|
715
|
+
const handleResize = () => {
|
|
716
|
+
if (debounce > 0) {
|
|
717
|
+
if (timeoutId) {
|
|
718
|
+
clearTimeout(timeoutId);
|
|
719
|
+
}
|
|
720
|
+
timeoutId = setTimeout(() => {
|
|
721
|
+
setWindowSize(getSize());
|
|
722
|
+
}, debounce);
|
|
723
|
+
} else {
|
|
724
|
+
setWindowSize(getSize());
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
setWindowSize(getSize());
|
|
728
|
+
window.addEventListener("resize", handleResize);
|
|
729
|
+
return () => {
|
|
730
|
+
window.removeEventListener("resize", handleResize);
|
|
731
|
+
if (timeoutId) {
|
|
732
|
+
clearTimeout(timeoutId);
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
}, [debounce, getSize]);
|
|
736
|
+
return windowSize;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// src/hooks/useClickOutside/useClickOutside.ts
|
|
740
|
+
var import_react18 = require("react");
|
|
741
|
+
function useClickOutside(ref, callback, options = {}) {
|
|
742
|
+
const { events = ["mousedown", "touchstart"], enabled = true } = options;
|
|
743
|
+
const callbackRef = (0, import_react18.useRef)(callback);
|
|
744
|
+
callbackRef.current = callback;
|
|
745
|
+
(0, import_react18.useEffect)(() => {
|
|
746
|
+
if (isServer || !enabled) return;
|
|
747
|
+
const handleClick = (event) => {
|
|
748
|
+
const el = ref.current;
|
|
749
|
+
if (!el || el.contains(event.target)) {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
callbackRef.current(event);
|
|
753
|
+
};
|
|
754
|
+
events.forEach((eventName) => {
|
|
755
|
+
document.addEventListener(eventName, handleClick);
|
|
756
|
+
});
|
|
757
|
+
return () => {
|
|
758
|
+
events.forEach((eventName) => {
|
|
759
|
+
document.removeEventListener(eventName, handleClick);
|
|
760
|
+
});
|
|
761
|
+
};
|
|
762
|
+
}, [ref, events, enabled]);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/hooks/useHover/useHover.ts
|
|
766
|
+
var import_react19 = require("react");
|
|
767
|
+
function useHover() {
|
|
768
|
+
const [isHovered, setIsHovered] = (0, import_react19.useState)(false);
|
|
769
|
+
const nodeRef = (0, import_react19.useRef)(null);
|
|
770
|
+
const handleMouseEnter = (0, import_react19.useCallback)(() => {
|
|
771
|
+
setIsHovered(true);
|
|
772
|
+
}, []);
|
|
773
|
+
const handleMouseLeave = (0, import_react19.useCallback)(() => {
|
|
774
|
+
setIsHovered(false);
|
|
775
|
+
}, []);
|
|
776
|
+
const ref = (0, import_react19.useCallback)(
|
|
777
|
+
(node) => {
|
|
778
|
+
if (nodeRef.current) {
|
|
779
|
+
nodeRef.current.removeEventListener("mouseenter", handleMouseEnter);
|
|
780
|
+
nodeRef.current.removeEventListener("mouseleave", handleMouseLeave);
|
|
781
|
+
}
|
|
782
|
+
if (node) {
|
|
783
|
+
node.addEventListener("mouseenter", handleMouseEnter);
|
|
784
|
+
node.addEventListener("mouseleave", handleMouseLeave);
|
|
785
|
+
}
|
|
786
|
+
nodeRef.current = node;
|
|
787
|
+
},
|
|
788
|
+
[handleMouseEnter, handleMouseLeave]
|
|
789
|
+
);
|
|
790
|
+
return {
|
|
791
|
+
isHovered,
|
|
792
|
+
ref,
|
|
793
|
+
hoverProps: {
|
|
794
|
+
onMouseEnter: handleMouseEnter,
|
|
795
|
+
onMouseLeave: handleMouseLeave
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/hooks/useKeyPress/useKeyPress.ts
|
|
801
|
+
var import_react20 = require("react");
|
|
802
|
+
function useKeyPress(targetKey, callback, options = {}) {
|
|
803
|
+
const {
|
|
804
|
+
target = "window",
|
|
805
|
+
event = "keydown",
|
|
806
|
+
preventDefault = false,
|
|
807
|
+
enabled = true
|
|
808
|
+
} = options;
|
|
809
|
+
const [isPressed, setIsPressed] = (0, import_react20.useState)(false);
|
|
810
|
+
const callbackRef = (0, import_react20.useCallback)(
|
|
811
|
+
(e) => {
|
|
812
|
+
callback?.(e);
|
|
813
|
+
},
|
|
814
|
+
[callback]
|
|
815
|
+
);
|
|
816
|
+
(0, import_react20.useEffect)(() => {
|
|
817
|
+
if (isServer || !enabled) return;
|
|
818
|
+
const targetElement = target === "document" ? document : window;
|
|
819
|
+
const handleKeyDown = (e) => {
|
|
820
|
+
const event2 = e;
|
|
821
|
+
if (event2.key === targetKey) {
|
|
822
|
+
if (preventDefault) {
|
|
823
|
+
event2.preventDefault();
|
|
824
|
+
}
|
|
825
|
+
setIsPressed(true);
|
|
826
|
+
callbackRef(event2);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
const handleKeyUp = (e) => {
|
|
830
|
+
const event2 = e;
|
|
831
|
+
if (event2.key === targetKey) {
|
|
832
|
+
setIsPressed(false);
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
targetElement.addEventListener(event, handleKeyDown);
|
|
836
|
+
if (event === "keydown") {
|
|
837
|
+
targetElement.addEventListener("keyup", handleKeyUp);
|
|
838
|
+
}
|
|
839
|
+
return () => {
|
|
840
|
+
targetElement.removeEventListener(event, handleKeyDown);
|
|
841
|
+
if (event === "keydown") {
|
|
842
|
+
targetElement.removeEventListener("keyup", handleKeyUp);
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
}, [targetKey, target, event, preventDefault, enabled, callbackRef]);
|
|
846
|
+
return isPressed;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// src/hooks/useScroll/useScroll.ts
|
|
850
|
+
var import_react21 = require("react");
|
|
851
|
+
function useScroll(ref, options = {}) {
|
|
852
|
+
const { throttle = 0 } = options;
|
|
853
|
+
const [position, setPosition] = (0, import_react21.useState)({ x: 0, y: 0 });
|
|
854
|
+
const [direction, setDirection] = (0, import_react21.useState)(null);
|
|
855
|
+
const [boundaries, setBoundaries] = (0, import_react21.useState)({
|
|
856
|
+
isAtTop: true,
|
|
857
|
+
isAtBottom: false,
|
|
858
|
+
isAtLeft: true,
|
|
859
|
+
isAtRight: false
|
|
860
|
+
});
|
|
861
|
+
const lastPositionRef = (0, import_react21.useRef)({ x: 0, y: 0 });
|
|
862
|
+
const throttleTimerRef = (0, import_react21.useRef)(null);
|
|
863
|
+
(0, import_react21.useEffect)(() => {
|
|
864
|
+
if (isServer) return;
|
|
865
|
+
const target = ref?.current ?? window;
|
|
866
|
+
const isWindow = target === window;
|
|
867
|
+
const getScrollPosition = () => {
|
|
868
|
+
if (isWindow) {
|
|
869
|
+
return {
|
|
870
|
+
x: window.scrollX ?? window.pageXOffset,
|
|
871
|
+
y: window.scrollY ?? window.pageYOffset
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
const element = target;
|
|
875
|
+
return {
|
|
876
|
+
x: element.scrollLeft,
|
|
877
|
+
y: element.scrollTop
|
|
878
|
+
};
|
|
879
|
+
};
|
|
880
|
+
const getBoundaries = () => {
|
|
881
|
+
if (isWindow) {
|
|
882
|
+
const scrollHeight = document.documentElement.scrollHeight;
|
|
883
|
+
const scrollWidth = document.documentElement.scrollWidth;
|
|
884
|
+
const clientHeight = window.innerHeight;
|
|
885
|
+
const clientWidth = window.innerWidth;
|
|
886
|
+
const { x, y } = getScrollPosition();
|
|
887
|
+
return {
|
|
888
|
+
isAtTop: y <= 0,
|
|
889
|
+
isAtBottom: y + clientHeight >= scrollHeight - 1,
|
|
890
|
+
isAtLeft: x <= 0,
|
|
891
|
+
isAtRight: x + clientWidth >= scrollWidth - 1
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
const element = target;
|
|
895
|
+
return {
|
|
896
|
+
isAtTop: element.scrollTop <= 0,
|
|
897
|
+
isAtBottom: element.scrollTop + element.clientHeight >= element.scrollHeight - 1,
|
|
898
|
+
isAtLeft: element.scrollLeft <= 0,
|
|
899
|
+
isAtRight: element.scrollLeft + element.clientWidth >= element.scrollWidth - 1
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
const handleScroll = () => {
|
|
903
|
+
const execute = () => {
|
|
904
|
+
const newPosition = getScrollPosition();
|
|
905
|
+
const lastPosition = lastPositionRef.current;
|
|
906
|
+
if (newPosition.y !== lastPosition.y) {
|
|
907
|
+
setDirection(newPosition.y > lastPosition.y ? "down" : "up");
|
|
908
|
+
} else if (newPosition.x !== lastPosition.x) {
|
|
909
|
+
setDirection(newPosition.x > lastPosition.x ? "right" : "left");
|
|
910
|
+
}
|
|
911
|
+
lastPositionRef.current = newPosition;
|
|
912
|
+
setPosition(newPosition);
|
|
913
|
+
setBoundaries(getBoundaries());
|
|
914
|
+
};
|
|
915
|
+
if (throttle > 0) {
|
|
916
|
+
if (!throttleTimerRef.current) {
|
|
917
|
+
throttleTimerRef.current = setTimeout(() => {
|
|
918
|
+
execute();
|
|
919
|
+
throttleTimerRef.current = null;
|
|
920
|
+
}, throttle);
|
|
921
|
+
}
|
|
922
|
+
} else {
|
|
923
|
+
execute();
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
setPosition(getScrollPosition());
|
|
927
|
+
setBoundaries(getBoundaries());
|
|
928
|
+
target.addEventListener("scroll", handleScroll, { passive: true });
|
|
929
|
+
return () => {
|
|
930
|
+
target.removeEventListener("scroll", handleScroll);
|
|
931
|
+
if (throttleTimerRef.current) {
|
|
932
|
+
clearTimeout(throttleTimerRef.current);
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}, [ref, throttle]);
|
|
936
|
+
return {
|
|
937
|
+
...position,
|
|
938
|
+
...boundaries,
|
|
939
|
+
direction
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// src/hooks/useIntersection/useIntersection.ts
|
|
944
|
+
var import_react22 = require("react");
|
|
945
|
+
function useIntersection(options = {}) {
|
|
946
|
+
const {
|
|
947
|
+
root = null,
|
|
948
|
+
rootMargin = "0px",
|
|
949
|
+
threshold = 0,
|
|
950
|
+
triggerOnce = false,
|
|
951
|
+
enabled = true
|
|
952
|
+
} = options;
|
|
953
|
+
const [entry, setEntry] = (0, import_react22.useState)(null);
|
|
954
|
+
const [isIntersecting, setIsIntersecting] = (0, import_react22.useState)(false);
|
|
955
|
+
const ref = (0, import_react22.useRef)(null);
|
|
956
|
+
const hasTriggeredRef = (0, import_react22.useRef)(false);
|
|
957
|
+
(0, import_react22.useEffect)(() => {
|
|
958
|
+
if (isServer || !enabled) return;
|
|
959
|
+
const element = ref.current;
|
|
960
|
+
if (!element) return;
|
|
961
|
+
if (triggerOnce && hasTriggeredRef.current) return;
|
|
962
|
+
const observer = new IntersectionObserver(
|
|
963
|
+
([observerEntry]) => {
|
|
964
|
+
setEntry(observerEntry);
|
|
965
|
+
setIsIntersecting(observerEntry.isIntersecting);
|
|
966
|
+
if (observerEntry.isIntersecting && triggerOnce) {
|
|
967
|
+
hasTriggeredRef.current = true;
|
|
968
|
+
observer.unobserve(element);
|
|
969
|
+
}
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
root,
|
|
973
|
+
rootMargin,
|
|
974
|
+
threshold
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
observer.observe(element);
|
|
978
|
+
return () => {
|
|
979
|
+
observer.disconnect();
|
|
980
|
+
};
|
|
981
|
+
}, [root, rootMargin, threshold, triggerOnce, enabled]);
|
|
982
|
+
return {
|
|
983
|
+
isIntersecting,
|
|
984
|
+
entry,
|
|
985
|
+
ref
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/hooks/useCopyToClipboard/useCopyToClipboard.ts
|
|
990
|
+
var import_react23 = require("react");
|
|
991
|
+
function useCopyToClipboard() {
|
|
992
|
+
const [copiedValue, setCopiedValue] = (0, import_react23.useState)(null);
|
|
993
|
+
const [isSuccess, setIsSuccess] = (0, import_react23.useState)(false);
|
|
994
|
+
const [error, setError] = (0, import_react23.useState)(null);
|
|
995
|
+
const copy = (0, import_react23.useCallback)(async (text) => {
|
|
996
|
+
if (isServer) {
|
|
997
|
+
console.warn("Clipboard is not available on the server");
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
1000
|
+
if (navigator?.clipboard?.writeText) {
|
|
1001
|
+
try {
|
|
1002
|
+
await navigator.clipboard.writeText(text);
|
|
1003
|
+
setCopiedValue(text);
|
|
1004
|
+
setIsSuccess(true);
|
|
1005
|
+
setError(null);
|
|
1006
|
+
return true;
|
|
1007
|
+
} catch (err) {
|
|
1008
|
+
setError(err instanceof Error ? err : new Error("Failed to copy"));
|
|
1009
|
+
setIsSuccess(false);
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
try {
|
|
1014
|
+
const textArea = document.createElement("textarea");
|
|
1015
|
+
textArea.value = text;
|
|
1016
|
+
textArea.style.position = "fixed";
|
|
1017
|
+
textArea.style.left = "-9999px";
|
|
1018
|
+
textArea.style.top = "-9999px";
|
|
1019
|
+
document.body.appendChild(textArea);
|
|
1020
|
+
textArea.focus();
|
|
1021
|
+
textArea.select();
|
|
1022
|
+
const successful = document.execCommand("copy");
|
|
1023
|
+
document.body.removeChild(textArea);
|
|
1024
|
+
if (successful) {
|
|
1025
|
+
setCopiedValue(text);
|
|
1026
|
+
setIsSuccess(true);
|
|
1027
|
+
setError(null);
|
|
1028
|
+
return true;
|
|
1029
|
+
} else {
|
|
1030
|
+
throw new Error('execCommand("copy") failed');
|
|
1031
|
+
}
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
setError(err instanceof Error ? err : new Error("Failed to copy"));
|
|
1034
|
+
setIsSuccess(false);
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
}, []);
|
|
1038
|
+
const reset = (0, import_react23.useCallback)(() => {
|
|
1039
|
+
setCopiedValue(null);
|
|
1040
|
+
setIsSuccess(false);
|
|
1041
|
+
setError(null);
|
|
1042
|
+
}, []);
|
|
1043
|
+
return {
|
|
1044
|
+
copiedValue,
|
|
1045
|
+
isSuccess,
|
|
1046
|
+
error,
|
|
1047
|
+
copy,
|
|
1048
|
+
reset
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/hooks/useDocumentTitle/useDocumentTitle.ts
|
|
1053
|
+
var import_react24 = require("react");
|
|
1054
|
+
function useDocumentTitle(title, options = {}) {
|
|
1055
|
+
const { restoreOnUnmount = true } = options;
|
|
1056
|
+
const previousTitleRef = (0, import_react24.useRef)(null);
|
|
1057
|
+
(0, import_react24.useEffect)(() => {
|
|
1058
|
+
if (isServer) return;
|
|
1059
|
+
if (previousTitleRef.current === null) {
|
|
1060
|
+
previousTitleRef.current = document.title;
|
|
1061
|
+
}
|
|
1062
|
+
document.title = title;
|
|
1063
|
+
return () => {
|
|
1064
|
+
if (restoreOnUnmount && previousTitleRef.current !== null) {
|
|
1065
|
+
document.title = previousTitleRef.current;
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
}, [title, restoreOnUnmount]);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// src/hooks/useLockBodyScroll/useLockBodyScroll.ts
|
|
1072
|
+
var import_react25 = require("react");
|
|
1073
|
+
function useLockBodyScroll(lock = true) {
|
|
1074
|
+
(0, import_react25.useEffect)(() => {
|
|
1075
|
+
if (isServer || !lock) return;
|
|
1076
|
+
const originalOverflow = document.body.style.overflow;
|
|
1077
|
+
const originalPaddingRight = document.body.style.paddingRight;
|
|
1078
|
+
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
1079
|
+
document.body.style.overflow = "hidden";
|
|
1080
|
+
if (scrollbarWidth > 0) {
|
|
1081
|
+
document.body.style.paddingRight = `${scrollbarWidth}px`;
|
|
1082
|
+
}
|
|
1083
|
+
return () => {
|
|
1084
|
+
document.body.style.overflow = originalOverflow;
|
|
1085
|
+
document.body.style.paddingRight = originalPaddingRight;
|
|
1086
|
+
};
|
|
1087
|
+
}, [lock]);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// src/hooks/useTheme/useTheme.ts
|
|
1091
|
+
var import_react26 = require("react");
|
|
1092
|
+
function useTheme(options = {}) {
|
|
1093
|
+
const {
|
|
1094
|
+
storageKey = "theme",
|
|
1095
|
+
attribute = "data-theme",
|
|
1096
|
+
defaultTheme = "system",
|
|
1097
|
+
disableTransitionOnChange = true
|
|
1098
|
+
} = options;
|
|
1099
|
+
const { value: theme, setValue: setTheme } = useLocalStorage(
|
|
1100
|
+
storageKey,
|
|
1101
|
+
defaultTheme
|
|
1102
|
+
);
|
|
1103
|
+
const systemPrefersDark = useMediaQuery("(prefers-color-scheme: dark)");
|
|
1104
|
+
const resolvedTheme = (0, import_react26.useMemo)(() => {
|
|
1105
|
+
if (theme === "system") {
|
|
1106
|
+
return systemPrefersDark ? "dark" : "light";
|
|
1107
|
+
}
|
|
1108
|
+
return theme === "dark" ? "dark" : "light";
|
|
1109
|
+
}, [theme, systemPrefersDark]);
|
|
1110
|
+
const applyTheme = (0, import_react26.useCallback)(() => {
|
|
1111
|
+
if (isServer) return;
|
|
1112
|
+
const root = document.documentElement;
|
|
1113
|
+
if (disableTransitionOnChange) {
|
|
1114
|
+
const css = document.createElement("style");
|
|
1115
|
+
css.appendChild(
|
|
1116
|
+
document.createTextNode(
|
|
1117
|
+
`* {
|
|
1118
|
+
-webkit-transition: none !important;
|
|
1119
|
+
-moz-transition: none !important;
|
|
1120
|
+
-o-transition: none !important;
|
|
1121
|
+
-ms-transition: none !important;
|
|
1122
|
+
transition: none !important;
|
|
1123
|
+
}`
|
|
1124
|
+
)
|
|
1125
|
+
);
|
|
1126
|
+
document.head.appendChild(css);
|
|
1127
|
+
setTimeout(() => {
|
|
1128
|
+
(() => window.getComputedStyle(document.body))();
|
|
1129
|
+
setTimeout(() => {
|
|
1130
|
+
document.head.removeChild(css);
|
|
1131
|
+
}, 1);
|
|
1132
|
+
}, 1);
|
|
1133
|
+
}
|
|
1134
|
+
if (attribute === "class") {
|
|
1135
|
+
root.classList.remove("light", "dark");
|
|
1136
|
+
root.classList.add(resolvedTheme);
|
|
1137
|
+
} else {
|
|
1138
|
+
root.setAttribute(attribute, resolvedTheme);
|
|
1139
|
+
}
|
|
1140
|
+
}, [resolvedTheme, attribute, disableTransitionOnChange]);
|
|
1141
|
+
useIsomorphicLayoutEffect(() => {
|
|
1142
|
+
applyTheme();
|
|
1143
|
+
}, [applyTheme]);
|
|
1144
|
+
const toggleTheme = (0, import_react26.useCallback)(() => {
|
|
1145
|
+
setTheme((prev) => {
|
|
1146
|
+
if (prev === "system") return resolvedTheme === "dark" ? "light" : "dark";
|
|
1147
|
+
return prev === "dark" ? "light" : "dark";
|
|
1148
|
+
});
|
|
1149
|
+
}, [setTheme, resolvedTheme]);
|
|
1150
|
+
return {
|
|
1151
|
+
theme,
|
|
1152
|
+
resolvedTheme,
|
|
1153
|
+
setTheme,
|
|
1154
|
+
toggleTheme
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// src/hooks/useEvent/useEvent.ts
|
|
1159
|
+
var import_react27 = require("react");
|
|
1160
|
+
function useEvent(name, handler, target = isServer ? null : window, options = {}) {
|
|
1161
|
+
const handlerRef = (0, import_react27.useRef)(handler);
|
|
1162
|
+
handlerRef.current = handler;
|
|
1163
|
+
(0, import_react27.useEffect)(() => {
|
|
1164
|
+
if (!target) return;
|
|
1165
|
+
const eventListener = (event) => {
|
|
1166
|
+
if (typeof handlerRef.current === "function") {
|
|
1167
|
+
handlerRef.current(event);
|
|
1168
|
+
} else {
|
|
1169
|
+
handlerRef.current.handleEvent(event);
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
target.addEventListener(name, eventListener, options);
|
|
1173
|
+
return () => {
|
|
1174
|
+
target.removeEventListener(name, eventListener, options);
|
|
1175
|
+
};
|
|
1176
|
+
}, [name, target, options?.capture, options?.passive, options?.once]);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// src/hooks/useLongPress/useLongPress.ts
|
|
1180
|
+
var import_react28 = require("react");
|
|
1181
|
+
function useLongPress(onLongPress, options = {}) {
|
|
1182
|
+
const {
|
|
1183
|
+
threshold = 500,
|
|
1184
|
+
cancelOnMove = true,
|
|
1185
|
+
onStart,
|
|
1186
|
+
onFinish,
|
|
1187
|
+
onCancel
|
|
1188
|
+
} = options;
|
|
1189
|
+
const callbackRef = (0, import_react28.useRef)(onLongPress);
|
|
1190
|
+
const onStartRef = (0, import_react28.useRef)(onStart);
|
|
1191
|
+
const onFinishRef = (0, import_react28.useRef)(onFinish);
|
|
1192
|
+
const onCancelRef = (0, import_react28.useRef)(onCancel);
|
|
1193
|
+
callbackRef.current = onLongPress;
|
|
1194
|
+
onStartRef.current = onStart;
|
|
1195
|
+
onFinishRef.current = onFinish;
|
|
1196
|
+
onCancelRef.current = onCancel;
|
|
1197
|
+
const timerRef = (0, import_react28.useRef)(null);
|
|
1198
|
+
const isLongPressActive = (0, import_react28.useRef)(false);
|
|
1199
|
+
const start = (0, import_react28.useCallback)(
|
|
1200
|
+
(event) => {
|
|
1201
|
+
onStartRef.current?.(event);
|
|
1202
|
+
isLongPressActive.current = false;
|
|
1203
|
+
timerRef.current = setTimeout(() => {
|
|
1204
|
+
isLongPressActive.current = true;
|
|
1205
|
+
callbackRef.current(event);
|
|
1206
|
+
onFinishRef.current?.(event);
|
|
1207
|
+
}, threshold);
|
|
1208
|
+
},
|
|
1209
|
+
[threshold]
|
|
1210
|
+
);
|
|
1211
|
+
const cancel = (0, import_react28.useCallback)(
|
|
1212
|
+
(event) => {
|
|
1213
|
+
if (timerRef.current) {
|
|
1214
|
+
clearTimeout(timerRef.current);
|
|
1215
|
+
timerRef.current = null;
|
|
1216
|
+
if (!isLongPressActive.current) {
|
|
1217
|
+
onCancelRef.current?.(event);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
isLongPressActive.current = false;
|
|
1221
|
+
},
|
|
1222
|
+
[]
|
|
1223
|
+
);
|
|
1224
|
+
return {
|
|
1225
|
+
onMouseDown: (e) => start(e),
|
|
1226
|
+
onTouchStart: (e) => start(e),
|
|
1227
|
+
onMouseUp: (e) => cancel(e),
|
|
1228
|
+
onMouseLeave: (e) => cancel(e),
|
|
1229
|
+
onTouchEnd: (e) => cancel(e)
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/hooks/useWindowFocus/useWindowFocus.ts
|
|
1234
|
+
var import_react29 = require("react");
|
|
1235
|
+
function useWindowFocus() {
|
|
1236
|
+
const [isFocused, setIsFocused] = (0, import_react29.useState)(
|
|
1237
|
+
() => !isServer && typeof document !== "undefined" ? document.hasFocus() : true
|
|
1238
|
+
);
|
|
1239
|
+
(0, import_react29.useEffect)(() => {
|
|
1240
|
+
if (isServer) return;
|
|
1241
|
+
const onFocus = () => setIsFocused(true);
|
|
1242
|
+
const onBlur = () => setIsFocused(false);
|
|
1243
|
+
window.addEventListener("focus", onFocus);
|
|
1244
|
+
window.addEventListener("blur", onBlur);
|
|
1245
|
+
setIsFocused(document.hasFocus());
|
|
1246
|
+
return () => {
|
|
1247
|
+
window.removeEventListener("focus", onFocus);
|
|
1248
|
+
window.removeEventListener("blur", onBlur);
|
|
1249
|
+
};
|
|
1250
|
+
}, []);
|
|
1251
|
+
return isFocused;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// src/hooks/useResizeObserver/useResizeObserver.ts
|
|
1255
|
+
var import_react30 = require("react");
|
|
1256
|
+
function useResizeObserver(ref, options = {}) {
|
|
1257
|
+
const { throttle = 0 } = options;
|
|
1258
|
+
const [contentRect, setContentRect] = (0, import_react30.useState)();
|
|
1259
|
+
const throttleTimerRef = (0, import_react30.useRef)(null);
|
|
1260
|
+
(0, import_react30.useEffect)(() => {
|
|
1261
|
+
if (isServer) return;
|
|
1262
|
+
const element = ref.current;
|
|
1263
|
+
if (!element) return;
|
|
1264
|
+
if (!window.ResizeObserver) {
|
|
1265
|
+
console.warn("ResizeObserver is not supported in this browser");
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
const observer = new ResizeObserver((entries) => {
|
|
1269
|
+
const entry = entries[0];
|
|
1270
|
+
if (!entry) return;
|
|
1271
|
+
const update = () => {
|
|
1272
|
+
setContentRect(entry.contentRect);
|
|
1273
|
+
};
|
|
1274
|
+
if (throttle > 0) {
|
|
1275
|
+
if (!throttleTimerRef.current) {
|
|
1276
|
+
throttleTimerRef.current = setTimeout(() => {
|
|
1277
|
+
update();
|
|
1278
|
+
throttleTimerRef.current = null;
|
|
1279
|
+
}, throttle);
|
|
1280
|
+
}
|
|
1281
|
+
} else {
|
|
1282
|
+
update();
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
observer.observe(element);
|
|
1286
|
+
return () => {
|
|
1287
|
+
observer.disconnect();
|
|
1288
|
+
if (throttleTimerRef.current) {
|
|
1289
|
+
clearTimeout(throttleTimerRef.current);
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
}, [ref, throttle]);
|
|
1293
|
+
return contentRect;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// src/hooks/useMutationObserver/useMutationObserver.ts
|
|
1297
|
+
var import_react31 = require("react");
|
|
1298
|
+
function useMutationObserver(ref, callback, options = {
|
|
1299
|
+
attributes: true,
|
|
1300
|
+
characterData: true,
|
|
1301
|
+
childList: true,
|
|
1302
|
+
subtree: true
|
|
1303
|
+
}) {
|
|
1304
|
+
const callbackRef = (0, import_react31.useRef)(callback);
|
|
1305
|
+
callbackRef.current = callback;
|
|
1306
|
+
const optionsRef = (0, import_react31.useRef)(options);
|
|
1307
|
+
optionsRef.current = options;
|
|
1308
|
+
(0, import_react31.useEffect)(() => {
|
|
1309
|
+
if (isServer) return;
|
|
1310
|
+
const element = ref.current;
|
|
1311
|
+
if (!element) return;
|
|
1312
|
+
if (!window.MutationObserver) {
|
|
1313
|
+
console.warn("MutationObserver is not supported");
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
const observer = new MutationObserver((mutations, obs) => {
|
|
1317
|
+
callbackRef.current(mutations, obs);
|
|
1318
|
+
});
|
|
1319
|
+
observer.observe(element, optionsRef.current);
|
|
1320
|
+
return () => {
|
|
1321
|
+
observer.disconnect();
|
|
1322
|
+
};
|
|
1323
|
+
}, [ref]);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// src/hooks/usePageLeave/usePageLeave.ts
|
|
1327
|
+
var import_react32 = require("react");
|
|
1328
|
+
function usePageLeave(onPageLeave) {
|
|
1329
|
+
(0, import_react32.useEffect)(() => {
|
|
1330
|
+
if (isServer) return;
|
|
1331
|
+
const handler = (event) => {
|
|
1332
|
+
event = event || window.event;
|
|
1333
|
+
const from = event.relatedTarget || event.toElement;
|
|
1334
|
+
if (!from || from.nodeName === "HTML") {
|
|
1335
|
+
if (event.clientY <= 0) {
|
|
1336
|
+
onPageLeave();
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
const simpleHandler = (event) => {
|
|
1341
|
+
if (event.clientY <= 0) {
|
|
1342
|
+
onPageLeave();
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
document.addEventListener("mouseleave", simpleHandler);
|
|
1346
|
+
return () => {
|
|
1347
|
+
document.removeEventListener("mouseleave", simpleHandler);
|
|
1348
|
+
};
|
|
1349
|
+
}, [onPageLeave]);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// src/hooks/useEyeDropper/useEyeDropper.ts
|
|
1353
|
+
var import_react33 = require("react");
|
|
1354
|
+
function useEyeDropper() {
|
|
1355
|
+
const isSupported = !isServer && "EyeDropper" in window;
|
|
1356
|
+
const open = (0, import_react33.useCallback)(async (options) => {
|
|
1357
|
+
if (!isSupported) {
|
|
1358
|
+
throw new Error("EyeDropper is not supported");
|
|
1359
|
+
}
|
|
1360
|
+
const eyeDropper = new window.EyeDropper();
|
|
1361
|
+
return eyeDropper.open(options);
|
|
1362
|
+
}, [isSupported]);
|
|
1363
|
+
return {
|
|
1364
|
+
isSupported,
|
|
1365
|
+
open
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// src/hooks/useOnline/useOnline.ts
|
|
1370
|
+
var import_react34 = require("react");
|
|
1371
|
+
function useOnline() {
|
|
1372
|
+
const [isOnline, setIsOnline] = (0, import_react34.useState)(() => {
|
|
1373
|
+
if (isServer) return true;
|
|
1374
|
+
return navigator.onLine;
|
|
1375
|
+
});
|
|
1376
|
+
const [since, setSince] = (0, import_react34.useState)(null);
|
|
1377
|
+
const handleOnline = (0, import_react34.useCallback)(() => {
|
|
1378
|
+
setIsOnline(true);
|
|
1379
|
+
setSince(Date.now());
|
|
1380
|
+
}, []);
|
|
1381
|
+
const handleOffline = (0, import_react34.useCallback)(() => {
|
|
1382
|
+
setIsOnline(false);
|
|
1383
|
+
setSince(Date.now());
|
|
1384
|
+
}, []);
|
|
1385
|
+
(0, import_react34.useEffect)(() => {
|
|
1386
|
+
if (isServer) return;
|
|
1387
|
+
setIsOnline(navigator.onLine);
|
|
1388
|
+
window.addEventListener("online", handleOnline);
|
|
1389
|
+
window.addEventListener("offline", handleOffline);
|
|
1390
|
+
return () => {
|
|
1391
|
+
window.removeEventListener("online", handleOnline);
|
|
1392
|
+
window.removeEventListener("offline", handleOffline);
|
|
1393
|
+
};
|
|
1394
|
+
}, [handleOnline, handleOffline]);
|
|
1395
|
+
return {
|
|
1396
|
+
isOnline,
|
|
1397
|
+
isOffline: !isOnline,
|
|
1398
|
+
since
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// src/hooks/useNetworkState/useNetworkState.ts
|
|
1403
|
+
var import_react35 = require("react");
|
|
1404
|
+
function useNetworkState() {
|
|
1405
|
+
const [state, setState] = (0, import_react35.useState)({
|
|
1406
|
+
online: true
|
|
1407
|
+
});
|
|
1408
|
+
(0, import_react35.useEffect)(() => {
|
|
1409
|
+
if (isServer) return;
|
|
1410
|
+
const nav = navigator;
|
|
1411
|
+
const connection = nav.connection || nav.mozConnection || nav.webkitConnection;
|
|
1412
|
+
const updateState = () => {
|
|
1413
|
+
setState({
|
|
1414
|
+
online: navigator.onLine,
|
|
1415
|
+
downlink: connection?.downlink,
|
|
1416
|
+
downlinkMax: connection?.downlinkMax,
|
|
1417
|
+
effectiveType: connection?.effectiveType,
|
|
1418
|
+
rtt: connection?.rtt,
|
|
1419
|
+
saveData: connection?.saveData,
|
|
1420
|
+
type: connection?.type
|
|
1421
|
+
});
|
|
1422
|
+
};
|
|
1423
|
+
updateState();
|
|
1424
|
+
window.addEventListener("online", updateState);
|
|
1425
|
+
window.addEventListener("offline", updateState);
|
|
1426
|
+
if (connection) {
|
|
1427
|
+
connection.addEventListener("change", updateState);
|
|
1428
|
+
}
|
|
1429
|
+
return () => {
|
|
1430
|
+
window.removeEventListener("online", updateState);
|
|
1431
|
+
window.removeEventListener("offline", updateState);
|
|
1432
|
+
if (connection) {
|
|
1433
|
+
connection.removeEventListener("change", updateState);
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
}, []);
|
|
1437
|
+
return state;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// src/hooks/useFullscreen/useFullscreen.ts
|
|
1441
|
+
var import_react36 = require("react");
|
|
1442
|
+
function useFullscreen(ref) {
|
|
1443
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react36.useState)(false);
|
|
1444
|
+
const isSupported = !isServer && !!document.fullscreenEnabled;
|
|
1445
|
+
const getElement = (0, import_react36.useCallback)(() => {
|
|
1446
|
+
return ref?.current ?? document.documentElement;
|
|
1447
|
+
}, [ref]);
|
|
1448
|
+
const enter = (0, import_react36.useCallback)(async () => {
|
|
1449
|
+
if (isServer || !isSupported) return;
|
|
1450
|
+
const element = getElement();
|
|
1451
|
+
if (!element) return;
|
|
1452
|
+
try {
|
|
1453
|
+
await element.requestFullscreen();
|
|
1454
|
+
} catch (error) {
|
|
1455
|
+
console.error("Failed to enter fullscreen:", error);
|
|
1456
|
+
}
|
|
1457
|
+
}, [isSupported, getElement]);
|
|
1458
|
+
const exit = (0, import_react36.useCallback)(async () => {
|
|
1459
|
+
if (isServer || !isSupported) return;
|
|
1460
|
+
try {
|
|
1461
|
+
await document.exitFullscreen();
|
|
1462
|
+
} catch (error) {
|
|
1463
|
+
console.error("Failed to exit fullscreen:", error);
|
|
1464
|
+
}
|
|
1465
|
+
}, [isSupported]);
|
|
1466
|
+
const toggle = (0, import_react36.useCallback)(async () => {
|
|
1467
|
+
if (isFullscreen) {
|
|
1468
|
+
await exit();
|
|
1469
|
+
} else {
|
|
1470
|
+
await enter();
|
|
1471
|
+
}
|
|
1472
|
+
}, [isFullscreen, enter, exit]);
|
|
1473
|
+
(0, import_react36.useEffect)(() => {
|
|
1474
|
+
if (isServer) return;
|
|
1475
|
+
const handleChange = () => {
|
|
1476
|
+
setIsFullscreen(!!document.fullscreenElement);
|
|
1477
|
+
};
|
|
1478
|
+
document.addEventListener("fullscreenchange", handleChange);
|
|
1479
|
+
return () => {
|
|
1480
|
+
document.removeEventListener("fullscreenchange", handleChange);
|
|
1481
|
+
};
|
|
1482
|
+
}, []);
|
|
1483
|
+
return {
|
|
1484
|
+
isFullscreen,
|
|
1485
|
+
isSupported,
|
|
1486
|
+
enter,
|
|
1487
|
+
exit,
|
|
1488
|
+
toggle
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/hooks/useShare/useShare.ts
|
|
1493
|
+
var import_react37 = require("react");
|
|
1494
|
+
function useShare() {
|
|
1495
|
+
const [isSharing, setIsSharing] = (0, import_react37.useState)(false);
|
|
1496
|
+
const [isSuccess, setIsSuccess] = (0, import_react37.useState)(false);
|
|
1497
|
+
const [error, setError] = (0, import_react37.useState)(null);
|
|
1498
|
+
const isSupported = !isServer && !!navigator.share;
|
|
1499
|
+
const canShare = (0, import_react37.useCallback)(
|
|
1500
|
+
(data) => {
|
|
1501
|
+
if (isServer || !navigator.canShare) return isSupported;
|
|
1502
|
+
if (!data) return isSupported;
|
|
1503
|
+
return navigator.canShare(data);
|
|
1504
|
+
},
|
|
1505
|
+
[isSupported]
|
|
1506
|
+
);
|
|
1507
|
+
const share = (0, import_react37.useCallback)(
|
|
1508
|
+
async (data) => {
|
|
1509
|
+
if (isServer || !isSupported) {
|
|
1510
|
+
setError(new Error("Web Share API is not supported"));
|
|
1511
|
+
return false;
|
|
1512
|
+
}
|
|
1513
|
+
setIsSharing(true);
|
|
1514
|
+
setIsSuccess(false);
|
|
1515
|
+
setError(null);
|
|
1516
|
+
try {
|
|
1517
|
+
await navigator.share(data);
|
|
1518
|
+
setIsSuccess(true);
|
|
1519
|
+
return true;
|
|
1520
|
+
} catch (err) {
|
|
1521
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
1522
|
+
setIsSuccess(false);
|
|
1523
|
+
return false;
|
|
1524
|
+
}
|
|
1525
|
+
const error2 = err instanceof Error ? err : new Error("Share failed");
|
|
1526
|
+
setError(error2);
|
|
1527
|
+
return false;
|
|
1528
|
+
} finally {
|
|
1529
|
+
setIsSharing(false);
|
|
1530
|
+
}
|
|
1531
|
+
},
|
|
1532
|
+
[isSupported]
|
|
1533
|
+
);
|
|
1534
|
+
return {
|
|
1535
|
+
isSupported,
|
|
1536
|
+
isSharing,
|
|
1537
|
+
isSuccess,
|
|
1538
|
+
error,
|
|
1539
|
+
share,
|
|
1540
|
+
canShare
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// src/hooks/usePermissions/usePermissions.ts
|
|
1545
|
+
var import_react38 = require("react");
|
|
1546
|
+
function usePermissions(name) {
|
|
1547
|
+
const [state, setState] = (0, import_react38.useState)("unknown");
|
|
1548
|
+
(0, import_react38.useEffect)(() => {
|
|
1549
|
+
if (isServer || !navigator.permissions) return;
|
|
1550
|
+
let mounted = true;
|
|
1551
|
+
let permissionStatus = null;
|
|
1552
|
+
const handleChange = () => {
|
|
1553
|
+
if (mounted && permissionStatus) {
|
|
1554
|
+
setState(permissionStatus.state);
|
|
1555
|
+
}
|
|
1556
|
+
};
|
|
1557
|
+
navigator.permissions.query({ name }).then((status) => {
|
|
1558
|
+
if (!mounted) return;
|
|
1559
|
+
permissionStatus = status;
|
|
1560
|
+
setState(permissionStatus.state);
|
|
1561
|
+
status.addEventListener("change", handleChange);
|
|
1562
|
+
}).catch(() => {
|
|
1563
|
+
if (mounted) setState("unknown");
|
|
1564
|
+
});
|
|
1565
|
+
return () => {
|
|
1566
|
+
mounted = false;
|
|
1567
|
+
if (permissionStatus) {
|
|
1568
|
+
permissionStatus.removeEventListener("change", handleChange);
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
}, [name]);
|
|
1572
|
+
return state;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// src/hooks/useWakeLock/useWakeLock.ts
|
|
1576
|
+
var import_react39 = require("react");
|
|
1577
|
+
function useWakeLock({
|
|
1578
|
+
onRequest,
|
|
1579
|
+
onRelease,
|
|
1580
|
+
onError
|
|
1581
|
+
} = {}) {
|
|
1582
|
+
const [released, setReleased] = (0, import_react39.useState)();
|
|
1583
|
+
const wakeLockRef = (0, import_react39.useRef)(null);
|
|
1584
|
+
const isSupported = !isServer && "wakeLock" in navigator;
|
|
1585
|
+
const release = (0, import_react39.useCallback)(async () => {
|
|
1586
|
+
if (!wakeLockRef.current) return;
|
|
1587
|
+
try {
|
|
1588
|
+
await wakeLockRef.current.release();
|
|
1589
|
+
wakeLockRef.current = null;
|
|
1590
|
+
} catch (err) {
|
|
1591
|
+
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
1592
|
+
}
|
|
1593
|
+
}, [onError]);
|
|
1594
|
+
const request = (0, import_react39.useCallback)(async () => {
|
|
1595
|
+
if (!isSupported) return;
|
|
1596
|
+
try {
|
|
1597
|
+
const wakeLock = await navigator.wakeLock.request("screen");
|
|
1598
|
+
wakeLock.addEventListener("release", () => {
|
|
1599
|
+
setReleased(true);
|
|
1600
|
+
onRelease?.();
|
|
1601
|
+
wakeLockRef.current = null;
|
|
1602
|
+
});
|
|
1603
|
+
wakeLockRef.current = wakeLock;
|
|
1604
|
+
setReleased(false);
|
|
1605
|
+
onRequest?.();
|
|
1606
|
+
} catch (err) {
|
|
1607
|
+
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
1608
|
+
}
|
|
1609
|
+
}, [isSupported, onRequest, onRelease, onError]);
|
|
1610
|
+
(0, import_react39.useEffect)(() => {
|
|
1611
|
+
return () => {
|
|
1612
|
+
release();
|
|
1613
|
+
};
|
|
1614
|
+
}, [release]);
|
|
1615
|
+
(0, import_react39.useEffect)(() => {
|
|
1616
|
+
const handleVisibilityChange = async () => {
|
|
1617
|
+
if (wakeLockRef.current !== null && document.visibilityState === "visible") {
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1621
|
+
return () => {
|
|
1622
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1623
|
+
};
|
|
1624
|
+
}, []);
|
|
1625
|
+
return {
|
|
1626
|
+
isSupported,
|
|
1627
|
+
released: released ?? true,
|
|
1628
|
+
// Default to true (released) initially
|
|
1629
|
+
request,
|
|
1630
|
+
release
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// src/hooks/useMediaDevices/useMediaDevices.ts
|
|
1635
|
+
var import_react40 = require("react");
|
|
1636
|
+
function useMediaDevices() {
|
|
1637
|
+
const [devices, setDevices] = (0, import_react40.useState)([]);
|
|
1638
|
+
const [isLoading, setIsLoading] = (0, import_react40.useState)(true);
|
|
1639
|
+
const [error, setError] = (0, import_react40.useState)(null);
|
|
1640
|
+
const isSupported = !isServer && !!navigator.mediaDevices?.enumerateDevices;
|
|
1641
|
+
const getDevices = useStableCallback_default(async () => {
|
|
1642
|
+
if (!isSupported) {
|
|
1643
|
+
setIsLoading(false);
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
try {
|
|
1647
|
+
const allDevices = await navigator.mediaDevices.enumerateDevices();
|
|
1648
|
+
setDevices(allDevices);
|
|
1649
|
+
setError(null);
|
|
1650
|
+
} catch (err) {
|
|
1651
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1652
|
+
} finally {
|
|
1653
|
+
setIsLoading(false);
|
|
1654
|
+
}
|
|
1655
|
+
});
|
|
1656
|
+
(0, import_react40.useEffect)(() => {
|
|
1657
|
+
getDevices();
|
|
1658
|
+
if (isSupported) {
|
|
1659
|
+
navigator.mediaDevices.addEventListener("devicechange", getDevices);
|
|
1660
|
+
return () => {
|
|
1661
|
+
navigator.mediaDevices.removeEventListener("devicechange", getDevices);
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
}, [getDevices, isSupported]);
|
|
1665
|
+
return {
|
|
1666
|
+
devices,
|
|
1667
|
+
isLoading,
|
|
1668
|
+
error,
|
|
1669
|
+
isSupported
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// src/hooks/useMediaRecorder/useMediaRecorder.ts
|
|
1674
|
+
var import_react41 = require("react");
|
|
1675
|
+
function useMediaRecorder(stream, options) {
|
|
1676
|
+
const [status, setStatus] = (0, import_react41.useState)("idle");
|
|
1677
|
+
const [mediaBlob, setMediaBlob] = (0, import_react41.useState)();
|
|
1678
|
+
const [mediaUrl, setMediaUrl] = (0, import_react41.useState)();
|
|
1679
|
+
const [error, setError] = (0, import_react41.useState)(null);
|
|
1680
|
+
const mediaRecorderRef = (0, import_react41.useRef)(null);
|
|
1681
|
+
const chunksRef = (0, import_react41.useRef)([]);
|
|
1682
|
+
const start = (0, import_react41.useCallback)(
|
|
1683
|
+
(timeSlice) => {
|
|
1684
|
+
if (!stream) return;
|
|
1685
|
+
try {
|
|
1686
|
+
if (!mediaRecorderRef.current) {
|
|
1687
|
+
mediaRecorderRef.current = new MediaRecorder(stream, options);
|
|
1688
|
+
mediaRecorderRef.current.ondataavailable = (event) => {
|
|
1689
|
+
if (event.data && event.data.size > 0) {
|
|
1690
|
+
chunksRef.current.push(event.data);
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
mediaRecorderRef.current.onerror = (event) => {
|
|
1694
|
+
setError(event.error);
|
|
1695
|
+
setStatus("idle");
|
|
1696
|
+
};
|
|
1697
|
+
mediaRecorderRef.current.onstop = () => {
|
|
1698
|
+
const blob = new Blob(chunksRef.current, { type: options?.mimeType || "video/webm" });
|
|
1699
|
+
setMediaBlob(blob);
|
|
1700
|
+
const url = URL.createObjectURL(blob);
|
|
1701
|
+
setMediaUrl(url);
|
|
1702
|
+
chunksRef.current = [];
|
|
1703
|
+
setStatus("stopped");
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
if (mediaRecorderRef.current.state !== "recording") {
|
|
1707
|
+
mediaRecorderRef.current.start(timeSlice);
|
|
1708
|
+
setStatus("recording");
|
|
1709
|
+
}
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
[stream, options]
|
|
1715
|
+
);
|
|
1716
|
+
const stop = (0, import_react41.useCallback)(() => {
|
|
1717
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
1718
|
+
mediaRecorderRef.current.stop();
|
|
1719
|
+
}
|
|
1720
|
+
}, []);
|
|
1721
|
+
const pause = (0, import_react41.useCallback)(() => {
|
|
1722
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state === "recording") {
|
|
1723
|
+
mediaRecorderRef.current.pause();
|
|
1724
|
+
setStatus("paused");
|
|
1725
|
+
}
|
|
1726
|
+
}, []);
|
|
1727
|
+
const resume = (0, import_react41.useCallback)(() => {
|
|
1728
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state === "paused") {
|
|
1729
|
+
mediaRecorderRef.current.resume();
|
|
1730
|
+
setStatus("recording");
|
|
1731
|
+
}
|
|
1732
|
+
}, []);
|
|
1733
|
+
const clear = (0, import_react41.useCallback)(() => {
|
|
1734
|
+
if (mediaUrl) {
|
|
1735
|
+
URL.revokeObjectURL(mediaUrl);
|
|
1736
|
+
}
|
|
1737
|
+
setMediaBlob(void 0);
|
|
1738
|
+
setMediaUrl(void 0);
|
|
1739
|
+
setError(null);
|
|
1740
|
+
setStatus("idle");
|
|
1741
|
+
}, [mediaUrl]);
|
|
1742
|
+
return {
|
|
1743
|
+
status,
|
|
1744
|
+
start,
|
|
1745
|
+
stop,
|
|
1746
|
+
pause,
|
|
1747
|
+
resume,
|
|
1748
|
+
isRecording: status === "recording",
|
|
1749
|
+
mediaBlob,
|
|
1750
|
+
mediaUrl,
|
|
1751
|
+
clear,
|
|
1752
|
+
error
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// src/hooks/useBattery/useBattery.ts
|
|
1757
|
+
var import_react42 = require("react");
|
|
1758
|
+
function useBattery() {
|
|
1759
|
+
const [state, setState] = (0, import_react42.useState)({
|
|
1760
|
+
supported: false,
|
|
1761
|
+
loading: true,
|
|
1762
|
+
level: 1,
|
|
1763
|
+
charging: false,
|
|
1764
|
+
chargingTime: 0,
|
|
1765
|
+
dischargingTime: Infinity
|
|
1766
|
+
});
|
|
1767
|
+
(0, import_react42.useEffect)(() => {
|
|
1768
|
+
if (isServer || !("getBattery" in navigator)) {
|
|
1769
|
+
setState((s) => ({ ...s, loading: false, supported: false }));
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
let mounted = true;
|
|
1773
|
+
let battery = null;
|
|
1774
|
+
const handleChange = () => {
|
|
1775
|
+
if (!mounted || !battery) return;
|
|
1776
|
+
setState({
|
|
1777
|
+
supported: true,
|
|
1778
|
+
loading: false,
|
|
1779
|
+
level: battery.level,
|
|
1780
|
+
charging: battery.charging,
|
|
1781
|
+
chargingTime: battery.chargingTime,
|
|
1782
|
+
dischargingTime: battery.dischargingTime
|
|
1783
|
+
});
|
|
1784
|
+
};
|
|
1785
|
+
navigator.getBattery().then((bat) => {
|
|
1786
|
+
if (!mounted) return;
|
|
1787
|
+
battery = bat;
|
|
1788
|
+
handleChange();
|
|
1789
|
+
battery.addEventListener("levelchange", handleChange);
|
|
1790
|
+
battery.addEventListener("chargingchange", handleChange);
|
|
1791
|
+
battery.addEventListener("chargingtimechange", handleChange);
|
|
1792
|
+
battery.addEventListener("dischargingtimechange", handleChange);
|
|
1793
|
+
});
|
|
1794
|
+
return () => {
|
|
1795
|
+
mounted = false;
|
|
1796
|
+
if (battery) {
|
|
1797
|
+
battery.removeEventListener("levelchange", handleChange);
|
|
1798
|
+
battery.removeEventListener("chargingchange", handleChange);
|
|
1799
|
+
battery.removeEventListener("chargingtimechange", handleChange);
|
|
1800
|
+
battery.removeEventListener("dischargingtimechange", handleChange);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
}, []);
|
|
1804
|
+
return state;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// src/hooks/useBluetooth/useBluetooth.ts
|
|
1808
|
+
var import_react43 = require("react");
|
|
1809
|
+
function useBluetooth() {
|
|
1810
|
+
const [device, setDevice] = (0, import_react43.useState)(null);
|
|
1811
|
+
const [server, setServer] = (0, import_react43.useState)(null);
|
|
1812
|
+
const [error, setError] = (0, import_react43.useState)(null);
|
|
1813
|
+
const [isConnecting, setIsConnecting] = (0, import_react43.useState)(false);
|
|
1814
|
+
const isSupported = !isServer && "bluetooth" in navigator;
|
|
1815
|
+
const disconnect = (0, import_react43.useCallback)(() => {
|
|
1816
|
+
if (device && device.gatt?.connected) {
|
|
1817
|
+
device.gatt.disconnect();
|
|
1818
|
+
}
|
|
1819
|
+
setDevice(null);
|
|
1820
|
+
setServer(null);
|
|
1821
|
+
setIsConnecting(false);
|
|
1822
|
+
}, [device]);
|
|
1823
|
+
const requestDevice = (0, import_react43.useCallback)(
|
|
1824
|
+
async (options) => {
|
|
1825
|
+
if (!isSupported) {
|
|
1826
|
+
setError(new Error("Bluetooth API not supported"));
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
setIsConnecting(true);
|
|
1830
|
+
setError(null);
|
|
1831
|
+
try {
|
|
1832
|
+
const device2 = await navigator.bluetooth.requestDevice(options || { acceptAllDevices: true });
|
|
1833
|
+
setDevice(device2);
|
|
1834
|
+
device2.addEventListener("gattserverdisconnected", () => {
|
|
1835
|
+
setServer(null);
|
|
1836
|
+
});
|
|
1837
|
+
if (device2.gatt) {
|
|
1838
|
+
const server2 = await device2.gatt.connect();
|
|
1839
|
+
setServer(server2);
|
|
1840
|
+
}
|
|
1841
|
+
} catch (err) {
|
|
1842
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1843
|
+
} finally {
|
|
1844
|
+
setIsConnecting(false);
|
|
1845
|
+
}
|
|
1846
|
+
},
|
|
1847
|
+
[isSupported]
|
|
1848
|
+
);
|
|
1849
|
+
return {
|
|
1850
|
+
isSupported,
|
|
1851
|
+
isConnected: !!server?.connected,
|
|
1852
|
+
isConnecting,
|
|
1853
|
+
device,
|
|
1854
|
+
server,
|
|
1855
|
+
error,
|
|
1856
|
+
requestDevice,
|
|
1857
|
+
disconnect
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// src/hooks/useGamepad/useGamepad.ts
|
|
1862
|
+
var import_react44 = require("react");
|
|
1863
|
+
function useGamepad(options = {}) {
|
|
1864
|
+
const { enabled = true } = options;
|
|
1865
|
+
const [gamepads, setGamepads] = (0, import_react44.useState)([]);
|
|
1866
|
+
const requestRef = (0, import_react44.useRef)(null);
|
|
1867
|
+
const scanGamepads = () => {
|
|
1868
|
+
if (isServer) return;
|
|
1869
|
+
const detectedGamepads = navigator.getGamepads ? navigator.getGamepads() : [];
|
|
1870
|
+
const gamepadArray = Array.from(detectedGamepads);
|
|
1871
|
+
setGamepads(gamepadArray);
|
|
1872
|
+
};
|
|
1873
|
+
(0, import_react44.useEffect)(() => {
|
|
1874
|
+
if (isServer) return;
|
|
1875
|
+
window.addEventListener("gamepadconnected", scanGamepads);
|
|
1876
|
+
window.addEventListener("gamepaddisconnected", scanGamepads);
|
|
1877
|
+
return () => {
|
|
1878
|
+
window.removeEventListener("gamepadconnected", scanGamepads);
|
|
1879
|
+
window.removeEventListener("gamepaddisconnected", scanGamepads);
|
|
1880
|
+
};
|
|
1881
|
+
}, []);
|
|
1882
|
+
(0, import_react44.useEffect)(() => {
|
|
1883
|
+
if (isServer || !enabled) return;
|
|
1884
|
+
const tick = () => {
|
|
1885
|
+
scanGamepads();
|
|
1886
|
+
requestRef.current = requestAnimationFrame(tick);
|
|
1887
|
+
};
|
|
1888
|
+
requestRef.current = requestAnimationFrame(tick);
|
|
1889
|
+
return () => {
|
|
1890
|
+
if (requestRef.current) {
|
|
1891
|
+
cancelAnimationFrame(requestRef.current);
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
}, [enabled]);
|
|
1895
|
+
return { gamepads };
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// src/hooks/useFileSystem/useFileSystem.ts
|
|
1899
|
+
var import_react45 = require("react");
|
|
1900
|
+
function useFileSystem() {
|
|
1901
|
+
const [file, setFile] = (0, import_react45.useState)(null);
|
|
1902
|
+
const [fileHandle, setFileHandle] = (0, import_react45.useState)(null);
|
|
1903
|
+
const [error, setError] = (0, import_react45.useState)(null);
|
|
1904
|
+
const isSupported = !isServer && "showOpenFilePicker" in window;
|
|
1905
|
+
const openFile = (0, import_react45.useCallback)(async (options) => {
|
|
1906
|
+
if (!isSupported) {
|
|
1907
|
+
setError(new Error("File System Access API not supported"));
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
try {
|
|
1911
|
+
const handles = await window.showOpenFilePicker(options);
|
|
1912
|
+
const handle = handles[0];
|
|
1913
|
+
const file2 = await handle.getFile();
|
|
1914
|
+
setFileHandle(handle);
|
|
1915
|
+
setFile(file2);
|
|
1916
|
+
setError(null);
|
|
1917
|
+
} catch (err) {
|
|
1918
|
+
if (err.name !== "AbortError") {
|
|
1919
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}, [isSupported]);
|
|
1923
|
+
const saveFile = (0, import_react45.useCallback)(async (data, options) => {
|
|
1924
|
+
if (!isSupported) {
|
|
1925
|
+
setError(new Error("File System Access API not supported"));
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
try {
|
|
1929
|
+
const handle = await window.showSaveFilePicker(options);
|
|
1930
|
+
const writable = await handle.createWritable();
|
|
1931
|
+
await writable.write(data);
|
|
1932
|
+
await writable.close();
|
|
1933
|
+
setError(null);
|
|
1934
|
+
} catch (err) {
|
|
1935
|
+
if (err.name !== "AbortError") {
|
|
1936
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
}, [isSupported]);
|
|
1940
|
+
return {
|
|
1941
|
+
isSupported,
|
|
1942
|
+
file,
|
|
1943
|
+
fileHandle,
|
|
1944
|
+
openFile,
|
|
1945
|
+
saveFile,
|
|
1946
|
+
error
|
|
1947
|
+
};
|
|
29
1948
|
}
|
|
30
|
-
|
|
31
|
-
|
|
1949
|
+
|
|
1950
|
+
// src/hooks/useStorageEstimate/useStorageEstimate.ts
|
|
1951
|
+
var import_react46 = require("react");
|
|
1952
|
+
function useStorageEstimate() {
|
|
1953
|
+
const [estimate, setEstimate] = (0, import_react46.useState)({
|
|
1954
|
+
quota: void 0,
|
|
1955
|
+
usage: void 0,
|
|
1956
|
+
supported: false,
|
|
1957
|
+
loading: true
|
|
1958
|
+
});
|
|
1959
|
+
(0, import_react46.useEffect)(() => {
|
|
1960
|
+
if (isServer || !navigator.storage?.estimate) {
|
|
1961
|
+
setEstimate((s) => ({ ...s, loading: false, supported: false }));
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
navigator.storage.estimate().then(({ quota, usage }) => {
|
|
1965
|
+
setEstimate({
|
|
1966
|
+
quota,
|
|
1967
|
+
usage,
|
|
1968
|
+
supported: true,
|
|
1969
|
+
loading: false
|
|
1970
|
+
});
|
|
1971
|
+
}).catch(() => {
|
|
1972
|
+
setEstimate((s) => ({ ...s, loading: false }));
|
|
1973
|
+
});
|
|
1974
|
+
}, []);
|
|
1975
|
+
return estimate;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
// src/hooks/useAsync/useAsync.ts
|
|
1979
|
+
var import_react47 = require("react");
|
|
1980
|
+
function useAsync(asyncFunction, options = {}) {
|
|
1981
|
+
const { immediate = false, initialData, onSuccess, onError } = options;
|
|
1982
|
+
const [status, setStatus] = (0, import_react47.useState)("idle");
|
|
1983
|
+
const [data, setData] = (0, import_react47.useState)(initialData);
|
|
1984
|
+
const [error, setError] = (0, import_react47.useState)(null);
|
|
1985
|
+
const isMountedRef = (0, import_react47.useRef)(true);
|
|
1986
|
+
const asyncFunctionRef = (0, import_react47.useRef)(asyncFunction);
|
|
1987
|
+
asyncFunctionRef.current = asyncFunction;
|
|
1988
|
+
const execute = (0, import_react47.useCallback)(
|
|
1989
|
+
async (...args) => {
|
|
1990
|
+
setStatus("pending");
|
|
1991
|
+
setError(null);
|
|
1992
|
+
try {
|
|
1993
|
+
const result = await asyncFunctionRef.current(...args);
|
|
1994
|
+
if (isMountedRef.current) {
|
|
1995
|
+
setData(result);
|
|
1996
|
+
setStatus("success");
|
|
1997
|
+
onSuccess?.(result);
|
|
1998
|
+
}
|
|
1999
|
+
return result;
|
|
2000
|
+
} catch (err) {
|
|
2001
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2002
|
+
if (isMountedRef.current) {
|
|
2003
|
+
setError(error2);
|
|
2004
|
+
setStatus("error");
|
|
2005
|
+
onError?.(error2);
|
|
2006
|
+
}
|
|
2007
|
+
return void 0;
|
|
2008
|
+
}
|
|
2009
|
+
},
|
|
2010
|
+
[onSuccess, onError]
|
|
2011
|
+
);
|
|
2012
|
+
const reset = (0, import_react47.useCallback)(() => {
|
|
2013
|
+
setStatus("idle");
|
|
2014
|
+
setData(initialData);
|
|
2015
|
+
setError(null);
|
|
2016
|
+
}, [initialData]);
|
|
2017
|
+
(0, import_react47.useEffect)(() => {
|
|
2018
|
+
if (immediate) {
|
|
2019
|
+
execute(...[]);
|
|
2020
|
+
}
|
|
2021
|
+
}, []);
|
|
2022
|
+
(0, import_react47.useEffect)(() => {
|
|
2023
|
+
isMountedRef.current = true;
|
|
2024
|
+
return () => {
|
|
2025
|
+
isMountedRef.current = false;
|
|
2026
|
+
};
|
|
2027
|
+
}, []);
|
|
2028
|
+
return {
|
|
2029
|
+
data,
|
|
2030
|
+
error,
|
|
2031
|
+
status,
|
|
2032
|
+
isLoading: status === "pending",
|
|
2033
|
+
isSuccess: status === "success",
|
|
2034
|
+
isError: status === "error",
|
|
2035
|
+
execute,
|
|
2036
|
+
reset
|
|
2037
|
+
};
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// src/hooks/useFetch/useFetch.ts
|
|
2041
|
+
var import_react48 = require("react");
|
|
2042
|
+
function useFetch(url, options = {}) {
|
|
2043
|
+
const {
|
|
2044
|
+
immediate = true,
|
|
2045
|
+
initialData,
|
|
2046
|
+
transform,
|
|
2047
|
+
retries = 0,
|
|
2048
|
+
retryDelay = 1e3,
|
|
2049
|
+
onSuccess,
|
|
2050
|
+
onError,
|
|
2051
|
+
abortPrevious = true,
|
|
2052
|
+
...fetchOptions
|
|
2053
|
+
} = options;
|
|
2054
|
+
const [data, setData] = (0, import_react48.useState)(initialData);
|
|
2055
|
+
const [error, setError] = (0, import_react48.useState)(null);
|
|
2056
|
+
const [status, setStatus] = (0, import_react48.useState)("idle");
|
|
2057
|
+
const abortControllerRef = (0, import_react48.useRef)(null);
|
|
2058
|
+
const isMountedRef = (0, import_react48.useRef)(true);
|
|
2059
|
+
const retryCountRef = (0, import_react48.useRef)(0);
|
|
2060
|
+
const abort = (0, import_react48.useCallback)(() => {
|
|
2061
|
+
abortControllerRef.current?.abort();
|
|
2062
|
+
}, []);
|
|
2063
|
+
const optionsRef = (0, import_react48.useRef)(fetchOptions);
|
|
2064
|
+
optionsRef.current = fetchOptions;
|
|
2065
|
+
const onSuccessRef = (0, import_react48.useRef)(onSuccess);
|
|
2066
|
+
onSuccessRef.current = onSuccess;
|
|
2067
|
+
const onErrorRef = (0, import_react48.useRef)(onError);
|
|
2068
|
+
onErrorRef.current = onError;
|
|
2069
|
+
const transformRef = (0, import_react48.useRef)(transform);
|
|
2070
|
+
transformRef.current = transform;
|
|
2071
|
+
const fetchData = (0, import_react48.useCallback)(async () => {
|
|
2072
|
+
if (!url) return;
|
|
2073
|
+
if (abortPrevious) {
|
|
2074
|
+
abort();
|
|
2075
|
+
}
|
|
2076
|
+
const controller = new AbortController();
|
|
2077
|
+
abortControllerRef.current = controller;
|
|
2078
|
+
setStatus("loading");
|
|
2079
|
+
setError(null);
|
|
2080
|
+
const attemptFetch = async (attempt) => {
|
|
2081
|
+
try {
|
|
2082
|
+
const response = await fetch(url, {
|
|
2083
|
+
...optionsRef.current,
|
|
2084
|
+
signal: controller.signal
|
|
2085
|
+
});
|
|
2086
|
+
if (!response.ok) {
|
|
2087
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
2088
|
+
}
|
|
2089
|
+
const result = transformRef.current ? await transformRef.current(response) : await response.json();
|
|
2090
|
+
if (isMountedRef.current && !controller.signal.aborted) {
|
|
2091
|
+
setData(result);
|
|
2092
|
+
setStatus("success");
|
|
2093
|
+
setError(null);
|
|
2094
|
+
retryCountRef.current = 0;
|
|
2095
|
+
onSuccessRef.current?.(result);
|
|
2096
|
+
}
|
|
2097
|
+
} catch (err) {
|
|
2098
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2102
|
+
if (attempt < retries && isMountedRef.current) {
|
|
2103
|
+
retryCountRef.current = attempt + 1;
|
|
2104
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
2105
|
+
if (!controller.signal.aborted) {
|
|
2106
|
+
return attemptFetch(attempt + 1);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
if (isMountedRef.current && !controller.signal.aborted) {
|
|
2110
|
+
setError(error2);
|
|
2111
|
+
setStatus("error");
|
|
2112
|
+
retryCountRef.current = 0;
|
|
2113
|
+
onErrorRef.current?.(error2);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
2117
|
+
await attemptFetch(0);
|
|
2118
|
+
}, [url, retries, retryDelay, abort, abortPrevious]);
|
|
2119
|
+
(0, import_react48.useEffect)(() => {
|
|
2120
|
+
if (immediate && url) {
|
|
2121
|
+
fetchData();
|
|
2122
|
+
}
|
|
2123
|
+
return () => {
|
|
2124
|
+
abort();
|
|
2125
|
+
};
|
|
2126
|
+
}, [url, immediate]);
|
|
2127
|
+
(0, import_react48.useEffect)(() => {
|
|
2128
|
+
isMountedRef.current = true;
|
|
2129
|
+
return () => {
|
|
2130
|
+
isMountedRef.current = false;
|
|
2131
|
+
};
|
|
2132
|
+
}, []);
|
|
2133
|
+
return {
|
|
2134
|
+
data,
|
|
2135
|
+
error,
|
|
2136
|
+
status,
|
|
2137
|
+
isLoading: status === "loading",
|
|
2138
|
+
isSuccess: status === "success",
|
|
2139
|
+
isError: status === "error",
|
|
2140
|
+
refetch: fetchData,
|
|
2141
|
+
abort
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
// src/hooks/useScript/useScript.ts
|
|
2146
|
+
var import_react49 = require("react");
|
|
2147
|
+
var scriptCache = /* @__PURE__ */ new Map();
|
|
2148
|
+
function useScript(src, options = {}) {
|
|
2149
|
+
const { immediate = true, removeOnUnmount = false, attributes = {} } = options;
|
|
2150
|
+
const [status, setStatus] = (0, import_react49.useState)(() => {
|
|
2151
|
+
if (isServer) return "idle";
|
|
2152
|
+
const cached = scriptCache.get(src);
|
|
2153
|
+
if (cached) return cached;
|
|
2154
|
+
const existingScript = document.querySelector(`script[src="${src}"]`);
|
|
2155
|
+
if (existingScript) {
|
|
2156
|
+
return "ready";
|
|
2157
|
+
}
|
|
2158
|
+
return "idle";
|
|
2159
|
+
});
|
|
2160
|
+
const hasLoaded = (0, import_react49.useRef)(false);
|
|
2161
|
+
const load = () => {
|
|
2162
|
+
if (isServer || hasLoaded.current) return;
|
|
2163
|
+
const cached = scriptCache.get(src);
|
|
2164
|
+
if (cached === "ready") {
|
|
2165
|
+
setStatus("ready");
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
const existingScript = document.querySelector(`script[src="${src}"]`);
|
|
2169
|
+
if (existingScript) {
|
|
2170
|
+
setStatus("ready");
|
|
2171
|
+
scriptCache.set(src, "ready");
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
hasLoaded.current = true;
|
|
2175
|
+
setStatus("loading");
|
|
2176
|
+
scriptCache.set(src, "loading");
|
|
2177
|
+
const script = document.createElement("script");
|
|
2178
|
+
script.src = src;
|
|
2179
|
+
script.async = true;
|
|
2180
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
2181
|
+
script.setAttribute(key, value);
|
|
2182
|
+
});
|
|
2183
|
+
const handleLoad = () => {
|
|
2184
|
+
setStatus("ready");
|
|
2185
|
+
scriptCache.set(src, "ready");
|
|
2186
|
+
};
|
|
2187
|
+
const handleError = () => {
|
|
2188
|
+
setStatus("error");
|
|
2189
|
+
scriptCache.set(src, "error");
|
|
2190
|
+
script.remove();
|
|
2191
|
+
};
|
|
2192
|
+
script.addEventListener("load", handleLoad);
|
|
2193
|
+
script.addEventListener("error", handleError);
|
|
2194
|
+
document.body.appendChild(script);
|
|
2195
|
+
};
|
|
2196
|
+
(0, import_react49.useEffect)(() => {
|
|
2197
|
+
if (immediate && status === "idle") {
|
|
2198
|
+
load();
|
|
2199
|
+
}
|
|
2200
|
+
return () => {
|
|
2201
|
+
if (removeOnUnmount && !isServer) {
|
|
2202
|
+
const script = document.querySelector(`script[src="${src}"]`);
|
|
2203
|
+
if (script) {
|
|
2204
|
+
script.remove();
|
|
2205
|
+
scriptCache.delete(src);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
};
|
|
2209
|
+
}, [src, immediate]);
|
|
2210
|
+
return {
|
|
2211
|
+
status,
|
|
2212
|
+
isLoading: status === "loading",
|
|
2213
|
+
isReady: status === "ready",
|
|
2214
|
+
isError: status === "error",
|
|
2215
|
+
load
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
// src/hooks/useWorker/useWorker.ts
|
|
2220
|
+
var import_react50 = require("react");
|
|
2221
|
+
function useWorker(workerScript) {
|
|
2222
|
+
const [result, setResult] = (0, import_react50.useState)();
|
|
2223
|
+
const [error, setError] = (0, import_react50.useState)(null);
|
|
2224
|
+
const [status, setStatus] = (0, import_react50.useState)("idle");
|
|
2225
|
+
const workerRef = (0, import_react50.useRef)(null);
|
|
2226
|
+
const workerUrlRef = (0, import_react50.useRef)(null);
|
|
2227
|
+
(0, import_react50.useEffect)(() => {
|
|
2228
|
+
if (isServer) return;
|
|
2229
|
+
const createWorker = () => {
|
|
2230
|
+
try {
|
|
2231
|
+
let worker;
|
|
2232
|
+
if (typeof workerScript === "string") {
|
|
2233
|
+
worker = new Worker(workerScript);
|
|
2234
|
+
} else {
|
|
2235
|
+
const code = `
|
|
2236
|
+
self.onmessage = function(e) {
|
|
2237
|
+
const result = (${workerScript.toString()})(e.data);
|
|
2238
|
+
self.postMessage(result);
|
|
2239
|
+
}
|
|
2240
|
+
`;
|
|
2241
|
+
const blob = new Blob([code], { type: "application/javascript" });
|
|
2242
|
+
const url = URL.createObjectURL(blob);
|
|
2243
|
+
workerUrlRef.current = url;
|
|
2244
|
+
worker = new Worker(url);
|
|
2245
|
+
}
|
|
2246
|
+
worker.onmessage = (e) => {
|
|
2247
|
+
setResult(e.data);
|
|
2248
|
+
setStatus("success");
|
|
2249
|
+
};
|
|
2250
|
+
worker.onerror = (e) => {
|
|
2251
|
+
setError(new Error(e.message));
|
|
2252
|
+
setStatus("error");
|
|
2253
|
+
};
|
|
2254
|
+
workerRef.current = worker;
|
|
2255
|
+
} catch (err) {
|
|
2256
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2257
|
+
setStatus("error");
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
createWorker();
|
|
2261
|
+
return () => {
|
|
2262
|
+
workerRef.current?.terminate();
|
|
2263
|
+
if (workerUrlRef.current) {
|
|
2264
|
+
URL.revokeObjectURL(workerUrlRef.current);
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
}, [workerScript]);
|
|
2268
|
+
const run = (0, import_react50.useCallback)((input) => {
|
|
2269
|
+
if (workerRef.current) {
|
|
2270
|
+
setStatus("running");
|
|
2271
|
+
setError(null);
|
|
2272
|
+
workerRef.current.postMessage(input);
|
|
2273
|
+
}
|
|
2274
|
+
}, []);
|
|
2275
|
+
const terminate = (0, import_react50.useCallback)(() => {
|
|
2276
|
+
workerRef.current?.terminate();
|
|
2277
|
+
setStatus("idle");
|
|
2278
|
+
}, []);
|
|
2279
|
+
return {
|
|
2280
|
+
result,
|
|
2281
|
+
error,
|
|
2282
|
+
status,
|
|
2283
|
+
run,
|
|
2284
|
+
terminate
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
// src/hooks/useIndexedDB/useIndexedDB.ts
|
|
2289
|
+
var import_react51 = require("react");
|
|
2290
|
+
function useIndexedDB(dbName, storeName, key) {
|
|
2291
|
+
const [value, setValue] = (0, import_react51.useState)();
|
|
2292
|
+
const [error, setError] = (0, import_react51.useState)(null);
|
|
2293
|
+
const [isLoading, setIsLoading] = (0, import_react51.useState)(true);
|
|
2294
|
+
const openDB = (0, import_react51.useCallback)(() => {
|
|
2295
|
+
return new Promise((resolve, reject) => {
|
|
2296
|
+
const request = indexedDB.open(dbName, 1);
|
|
2297
|
+
request.onupgradeneeded = (event) => {
|
|
2298
|
+
const db = event.target.result;
|
|
2299
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
2300
|
+
db.createObjectStore(storeName);
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
request.onsuccess = () => resolve(request.result);
|
|
2304
|
+
request.onerror = () => reject(request.error);
|
|
2305
|
+
});
|
|
2306
|
+
}, [dbName, storeName]);
|
|
2307
|
+
const load = (0, import_react51.useCallback)(async () => {
|
|
2308
|
+
if (isServer) {
|
|
2309
|
+
setIsLoading(false);
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
try {
|
|
2313
|
+
const db = await openDB();
|
|
2314
|
+
const tx = db.transaction(storeName, "readonly");
|
|
2315
|
+
const store = tx.objectStore(storeName);
|
|
2316
|
+
const request = store.get(key);
|
|
2317
|
+
request.onsuccess = () => {
|
|
2318
|
+
setValue(request.result);
|
|
2319
|
+
setIsLoading(false);
|
|
2320
|
+
};
|
|
2321
|
+
request.onerror = () => {
|
|
2322
|
+
throw request.error;
|
|
2323
|
+
};
|
|
2324
|
+
} catch (err) {
|
|
2325
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2326
|
+
setIsLoading(false);
|
|
2327
|
+
}
|
|
2328
|
+
}, [key, storeName, openDB]);
|
|
2329
|
+
(0, import_react51.useEffect)(() => {
|
|
2330
|
+
load();
|
|
2331
|
+
}, [load]);
|
|
2332
|
+
const set = (0, import_react51.useCallback)(async (newValue) => {
|
|
2333
|
+
try {
|
|
2334
|
+
const db = await openDB();
|
|
2335
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
2336
|
+
const store = tx.objectStore(storeName);
|
|
2337
|
+
return new Promise((resolve, reject) => {
|
|
2338
|
+
const req = store.put(newValue, key);
|
|
2339
|
+
req.onsuccess = () => {
|
|
2340
|
+
setValue(newValue);
|
|
2341
|
+
resolve();
|
|
2342
|
+
};
|
|
2343
|
+
req.onerror = () => reject(req.error);
|
|
2344
|
+
});
|
|
2345
|
+
} catch (err) {
|
|
2346
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2347
|
+
throw err;
|
|
2348
|
+
}
|
|
2349
|
+
}, [openDB, storeName, key]);
|
|
2350
|
+
const remove = (0, import_react51.useCallback)(async () => {
|
|
2351
|
+
try {
|
|
2352
|
+
const db = await openDB();
|
|
2353
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
2354
|
+
const store = tx.objectStore(storeName);
|
|
2355
|
+
return new Promise((resolve, reject) => {
|
|
2356
|
+
const req = store.delete(key);
|
|
2357
|
+
req.onsuccess = () => {
|
|
2358
|
+
setValue(void 0);
|
|
2359
|
+
resolve();
|
|
2360
|
+
};
|
|
2361
|
+
req.onerror = () => reject(req.error);
|
|
2362
|
+
});
|
|
2363
|
+
} catch (err) {
|
|
2364
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2365
|
+
throw err;
|
|
2366
|
+
}
|
|
2367
|
+
}, [openDB, storeName, key]);
|
|
2368
|
+
return {
|
|
2369
|
+
value,
|
|
2370
|
+
set,
|
|
2371
|
+
remove,
|
|
2372
|
+
error,
|
|
2373
|
+
isLoading
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
// src/hooks/useHistory/useHistory.ts
|
|
2378
|
+
var import_react52 = require("react");
|
|
2379
|
+
function useHistory(initialValue, options = {}) {
|
|
2380
|
+
const { maxSize = 100 } = options;
|
|
2381
|
+
const [state, setState] = (0, import_react52.useState)({
|
|
2382
|
+
history: [initialValue],
|
|
2383
|
+
position: 0
|
|
2384
|
+
});
|
|
2385
|
+
const { history, position } = state;
|
|
2386
|
+
const value = history[position];
|
|
2387
|
+
const set = (0, import_react52.useCallback)(
|
|
2388
|
+
(newValue) => {
|
|
2389
|
+
setState((currentState) => {
|
|
2390
|
+
const { history: currentHistory, position: currentPosition } = currentState;
|
|
2391
|
+
const resolvedValue = typeof newValue === "function" ? newValue(currentHistory[currentPosition]) : newValue;
|
|
2392
|
+
const slicedHistory = currentHistory.slice(0, currentPosition + 1);
|
|
2393
|
+
const newHistory = [...slicedHistory, resolvedValue];
|
|
2394
|
+
if (newHistory.length > maxSize) {
|
|
2395
|
+
const trimmedHistory = newHistory.slice(newHistory.length - maxSize);
|
|
2396
|
+
return {
|
|
2397
|
+
history: trimmedHistory,
|
|
2398
|
+
position: trimmedHistory.length - 1
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
return {
|
|
2402
|
+
history: newHistory,
|
|
2403
|
+
position: newHistory.length - 1
|
|
2404
|
+
};
|
|
2405
|
+
});
|
|
2406
|
+
},
|
|
2407
|
+
[maxSize]
|
|
2408
|
+
);
|
|
2409
|
+
const undo = (0, import_react52.useCallback)(() => {
|
|
2410
|
+
setState((prev) => ({
|
|
2411
|
+
...prev,
|
|
2412
|
+
position: Math.max(0, prev.position - 1)
|
|
2413
|
+
}));
|
|
2414
|
+
}, []);
|
|
2415
|
+
const redo = (0, import_react52.useCallback)(() => {
|
|
2416
|
+
setState((prev) => ({
|
|
2417
|
+
...prev,
|
|
2418
|
+
position: Math.min(prev.history.length - 1, prev.position + 1)
|
|
2419
|
+
}));
|
|
2420
|
+
}, []);
|
|
2421
|
+
const reset = (0, import_react52.useCallback)((value2) => {
|
|
2422
|
+
setState({
|
|
2423
|
+
history: [value2],
|
|
2424
|
+
position: 0
|
|
2425
|
+
});
|
|
2426
|
+
}, []);
|
|
2427
|
+
const go = (0, import_react52.useCallback)((newPosition) => {
|
|
2428
|
+
setState((prev) => {
|
|
2429
|
+
const maxPosition = prev.history.length - 1;
|
|
2430
|
+
return {
|
|
2431
|
+
...prev,
|
|
2432
|
+
position: Math.max(0, Math.min(maxPosition, newPosition))
|
|
2433
|
+
};
|
|
2434
|
+
});
|
|
2435
|
+
}, []);
|
|
2436
|
+
const canUndo = position > 0;
|
|
2437
|
+
const canRedo = position < history.length - 1;
|
|
2438
|
+
return {
|
|
2439
|
+
value,
|
|
2440
|
+
set,
|
|
2441
|
+
undo,
|
|
2442
|
+
redo,
|
|
2443
|
+
reset,
|
|
2444
|
+
canUndo,
|
|
2445
|
+
canRedo,
|
|
2446
|
+
history,
|
|
2447
|
+
position,
|
|
2448
|
+
go
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
// src/hooks/useStep/useStep.ts
|
|
2453
|
+
var import_react53 = require("react");
|
|
2454
|
+
function useStep(options) {
|
|
2455
|
+
const { initialStep = 0, maxStep } = options;
|
|
2456
|
+
const [currentStep, setCurrentStep] = (0, import_react53.useState)(
|
|
2457
|
+
() => Math.max(0, Math.min(initialStep, maxStep - 1))
|
|
2458
|
+
);
|
|
2459
|
+
const next = (0, import_react53.useCallback)(() => {
|
|
2460
|
+
setCurrentStep((prev2) => Math.min(prev2 + 1, maxStep - 1));
|
|
2461
|
+
}, [maxStep]);
|
|
2462
|
+
const prev = (0, import_react53.useCallback)(() => {
|
|
2463
|
+
setCurrentStep((prev2) => Math.max(prev2 - 1, 0));
|
|
2464
|
+
}, []);
|
|
2465
|
+
const goTo = (0, import_react53.useCallback)(
|
|
2466
|
+
(step) => {
|
|
2467
|
+
setCurrentStep(Math.max(0, Math.min(step, maxStep - 1)));
|
|
2468
|
+
},
|
|
2469
|
+
[maxStep]
|
|
2470
|
+
);
|
|
2471
|
+
const reset = (0, import_react53.useCallback)(() => {
|
|
2472
|
+
setCurrentStep(Math.max(0, Math.min(initialStep, maxStep - 1)));
|
|
2473
|
+
}, [initialStep, maxStep]);
|
|
2474
|
+
const isStepComplete = (0, import_react53.useCallback)(
|
|
2475
|
+
(step) => {
|
|
2476
|
+
return step < currentStep;
|
|
2477
|
+
},
|
|
2478
|
+
[currentStep]
|
|
2479
|
+
);
|
|
2480
|
+
const isFirst = currentStep === 0;
|
|
2481
|
+
const isLast = currentStep === maxStep - 1;
|
|
2482
|
+
const progress = (0, import_react53.useMemo)(
|
|
2483
|
+
() => (currentStep + 1) / maxStep * 100,
|
|
2484
|
+
[currentStep, maxStep]
|
|
2485
|
+
);
|
|
2486
|
+
return {
|
|
2487
|
+
currentStep,
|
|
2488
|
+
step: currentStep + 1,
|
|
2489
|
+
next,
|
|
2490
|
+
prev,
|
|
2491
|
+
goTo,
|
|
2492
|
+
reset,
|
|
2493
|
+
isFirst,
|
|
2494
|
+
isLast,
|
|
2495
|
+
progress,
|
|
2496
|
+
totalSteps: maxStep,
|
|
2497
|
+
isStepComplete
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
// src/hooks/usePagination/usePagination.ts
|
|
2502
|
+
var import_react54 = require("react");
|
|
2503
|
+
function usePagination(options) {
|
|
2504
|
+
const {
|
|
2505
|
+
totalItems,
|
|
2506
|
+
pageSize: initialPageSize = 10,
|
|
2507
|
+
initialPage = 1,
|
|
2508
|
+
siblings = 1
|
|
2509
|
+
} = options;
|
|
2510
|
+
const [page, setPage] = (0, import_react54.useState)(() => Math.max(1, initialPage));
|
|
2511
|
+
const [pageSize, setPageSizeState] = (0, import_react54.useState)(initialPageSize);
|
|
2512
|
+
const totalPages = (0, import_react54.useMemo)(
|
|
2513
|
+
() => Math.max(1, Math.ceil(totalItems / pageSize)),
|
|
2514
|
+
[totalItems, pageSize]
|
|
2515
|
+
);
|
|
2516
|
+
const boundedPage = (0, import_react54.useMemo)(
|
|
2517
|
+
() => Math.min(page, totalPages),
|
|
2518
|
+
[page, totalPages]
|
|
2519
|
+
);
|
|
2520
|
+
const next = (0, import_react54.useCallback)(() => {
|
|
2521
|
+
setPage((prev2) => Math.min(prev2 + 1, totalPages));
|
|
2522
|
+
}, [totalPages]);
|
|
2523
|
+
const prev = (0, import_react54.useCallback)(() => {
|
|
2524
|
+
setPage((prev2) => Math.max(prev2 - 1, 1));
|
|
2525
|
+
}, []);
|
|
2526
|
+
const goTo = (0, import_react54.useCallback)(
|
|
2527
|
+
(newPage) => {
|
|
2528
|
+
setPage(Math.max(1, Math.min(newPage, totalPages)));
|
|
2529
|
+
},
|
|
2530
|
+
[totalPages]
|
|
2531
|
+
);
|
|
2532
|
+
const first = (0, import_react54.useCallback)(() => {
|
|
2533
|
+
setPage(1);
|
|
2534
|
+
}, []);
|
|
2535
|
+
const last = (0, import_react54.useCallback)(() => {
|
|
2536
|
+
setPage(totalPages);
|
|
2537
|
+
}, [totalPages]);
|
|
2538
|
+
const setPageSize = (0, import_react54.useCallback)(
|
|
2539
|
+
(size) => {
|
|
2540
|
+
const newTotalPages = Math.max(1, Math.ceil(totalItems / size));
|
|
2541
|
+
setPageSizeState(size);
|
|
2542
|
+
setPage((prev2) => Math.min(prev2, newTotalPages));
|
|
2543
|
+
},
|
|
2544
|
+
[totalItems]
|
|
2545
|
+
);
|
|
2546
|
+
const startIndex = (boundedPage - 1) * pageSize;
|
|
2547
|
+
const endIndex = Math.min(startIndex + pageSize, totalItems);
|
|
2548
|
+
const range = (0, import_react54.useMemo)(() => {
|
|
2549
|
+
const totalPageNumbers = siblings * 2 + 5;
|
|
2550
|
+
if (totalPageNumbers >= totalPages) {
|
|
2551
|
+
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
2552
|
+
}
|
|
2553
|
+
const leftSiblingIndex = Math.max(boundedPage - siblings, 1);
|
|
2554
|
+
const rightSiblingIndex = Math.min(boundedPage + siblings, totalPages);
|
|
2555
|
+
const showLeftDots = leftSiblingIndex > 2;
|
|
2556
|
+
const showRightDots = rightSiblingIndex < totalPages - 1;
|
|
2557
|
+
if (!showLeftDots && showRightDots) {
|
|
2558
|
+
const leftItemCount = 3 + 2 * siblings;
|
|
2559
|
+
const leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
|
2560
|
+
return [...leftRange, "dots", totalPages];
|
|
2561
|
+
}
|
|
2562
|
+
if (showLeftDots && !showRightDots) {
|
|
2563
|
+
const rightItemCount = 3 + 2 * siblings;
|
|
2564
|
+
const rightRange = Array.from(
|
|
2565
|
+
{ length: rightItemCount },
|
|
2566
|
+
(_, i) => totalPages - rightItemCount + i + 1
|
|
2567
|
+
);
|
|
2568
|
+
return [1, "dots", ...rightRange];
|
|
2569
|
+
}
|
|
2570
|
+
const middleRange = Array.from(
|
|
2571
|
+
{ length: rightSiblingIndex - leftSiblingIndex + 1 },
|
|
2572
|
+
(_, i) => leftSiblingIndex + i
|
|
2573
|
+
);
|
|
2574
|
+
return [1, "dots", ...middleRange, "dots", totalPages];
|
|
2575
|
+
}, [boundedPage, totalPages, siblings]);
|
|
2576
|
+
return {
|
|
2577
|
+
page: boundedPage,
|
|
2578
|
+
totalPages,
|
|
2579
|
+
pageSize,
|
|
2580
|
+
next,
|
|
2581
|
+
prev,
|
|
2582
|
+
goTo,
|
|
2583
|
+
first,
|
|
2584
|
+
last,
|
|
2585
|
+
isFirst: boundedPage === 1,
|
|
2586
|
+
isLast: boundedPage === totalPages,
|
|
2587
|
+
startIndex,
|
|
2588
|
+
endIndex,
|
|
2589
|
+
range,
|
|
2590
|
+
setPageSize
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
// src/hooks/useMachine/useMachine.ts
|
|
2595
|
+
var import_react55 = require("react");
|
|
2596
|
+
function useMachine(config) {
|
|
2597
|
+
const [state, dispatch] = (0, import_react55.useReducer)(
|
|
2598
|
+
(currentState, event) => {
|
|
2599
|
+
const stateConfig = config.states[currentState];
|
|
2600
|
+
const transition = stateConfig?.on?.[event];
|
|
2601
|
+
if (!transition) {
|
|
2602
|
+
return currentState;
|
|
2603
|
+
}
|
|
2604
|
+
if (typeof transition === "string") {
|
|
2605
|
+
return transition;
|
|
2606
|
+
}
|
|
2607
|
+
if (transition.action) {
|
|
2608
|
+
transition.action();
|
|
2609
|
+
}
|
|
2610
|
+
return transition.target;
|
|
2611
|
+
},
|
|
2612
|
+
config.initial
|
|
2613
|
+
);
|
|
2614
|
+
return [state, dispatch];
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
// src/hooks/useVirtualList/useVirtualList.ts
|
|
2618
|
+
var import_react56 = require("react");
|
|
2619
|
+
function useVirtualList(options) {
|
|
2620
|
+
const { itemHeight, itemCount, containerHeight, overscan = 3 } = options;
|
|
2621
|
+
const [scrollTop, setScrollTop] = (0, import_react56.useState)(0);
|
|
2622
|
+
const totalHeight = itemCount * itemHeight;
|
|
2623
|
+
const onScroll = (0, import_react56.useCallback)((event) => {
|
|
2624
|
+
setScrollTop(event.currentTarget.scrollTop);
|
|
2625
|
+
}, []);
|
|
2626
|
+
const items = (0, import_react56.useMemo)(() => {
|
|
2627
|
+
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
|
|
2628
|
+
const endIndex = Math.min(
|
|
2629
|
+
itemCount - 1,
|
|
2630
|
+
Math.floor((scrollTop + containerHeight) / itemHeight) + overscan
|
|
2631
|
+
);
|
|
2632
|
+
const virtualItems = [];
|
|
2633
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2634
|
+
virtualItems.push({
|
|
2635
|
+
index: i,
|
|
2636
|
+
style: {
|
|
2637
|
+
position: "absolute",
|
|
2638
|
+
top: i * itemHeight,
|
|
2639
|
+
height: itemHeight,
|
|
2640
|
+
width: "100%"
|
|
2641
|
+
}
|
|
2642
|
+
});
|
|
2643
|
+
}
|
|
2644
|
+
return virtualItems;
|
|
2645
|
+
}, [scrollTop, itemHeight, itemCount, containerHeight, overscan]);
|
|
2646
|
+
return {
|
|
2647
|
+
items,
|
|
2648
|
+
totalHeight,
|
|
2649
|
+
onScroll
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
// src/hooks/useInfiniteScroll/useInfiniteScroll.ts
|
|
2654
|
+
var import_react57 = require("react");
|
|
2655
|
+
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
2656
|
+
const {
|
|
2657
|
+
threshold = 0,
|
|
2658
|
+
rootMargin = "0px",
|
|
2659
|
+
isLoading = false,
|
|
2660
|
+
hasMore = true,
|
|
2661
|
+
disabled = false
|
|
2662
|
+
} = options;
|
|
2663
|
+
const targetRef = (0, import_react57.useRef)(null);
|
|
2664
|
+
const onLoadMoreStable = useStableCallback_default(onLoadMore);
|
|
2665
|
+
(0, import_react57.useEffect)(() => {
|
|
2666
|
+
if (disabled || isLoading || !hasMore || !targetRef.current) return;
|
|
2667
|
+
const observer = new IntersectionObserver(
|
|
2668
|
+
(entries) => {
|
|
2669
|
+
const entry = entries[0];
|
|
2670
|
+
if (entry.isIntersecting) {
|
|
2671
|
+
onLoadMoreStable();
|
|
2672
|
+
}
|
|
2673
|
+
},
|
|
2674
|
+
{ threshold, rootMargin }
|
|
2675
|
+
);
|
|
2676
|
+
observer.observe(targetRef.current);
|
|
2677
|
+
return () => {
|
|
2678
|
+
observer.disconnect();
|
|
2679
|
+
};
|
|
2680
|
+
}, [disabled, isLoading, hasMore, threshold, rootMargin, onLoadMoreStable]);
|
|
2681
|
+
return targetRef;
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// src/hooks/useAnthropic/useAnthropic.ts
|
|
2685
|
+
var import_react58 = require("react");
|
|
2686
|
+
function useAnthropic(options = {}) {
|
|
2687
|
+
const {
|
|
2688
|
+
apiKey,
|
|
2689
|
+
model = "claude-3-haiku-20240307",
|
|
2690
|
+
maxTokens = 1024,
|
|
2691
|
+
temperature = 0.7
|
|
2692
|
+
} = options;
|
|
2693
|
+
const [loading, setLoading] = (0, import_react58.useState)(false);
|
|
2694
|
+
const [response, setResponse] = (0, import_react58.useState)(null);
|
|
2695
|
+
const [error, setError] = (0, import_react58.useState)(null);
|
|
2696
|
+
const chat = (0, import_react58.useCallback)(async (messages) => {
|
|
2697
|
+
setLoading(true);
|
|
2698
|
+
setResponse(null);
|
|
2699
|
+
setError(null);
|
|
2700
|
+
try {
|
|
2701
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
2702
|
+
method: "POST",
|
|
2703
|
+
headers: {
|
|
2704
|
+
"x-api-key": apiKey || "",
|
|
2705
|
+
"anthropic-version": "2023-06-01",
|
|
2706
|
+
"content-type": "application/json"
|
|
2707
|
+
},
|
|
2708
|
+
body: JSON.stringify({
|
|
2709
|
+
model,
|
|
2710
|
+
messages,
|
|
2711
|
+
max_tokens: maxTokens,
|
|
2712
|
+
temperature
|
|
2713
|
+
})
|
|
2714
|
+
});
|
|
2715
|
+
if (!res.ok) {
|
|
2716
|
+
const err = await res.json();
|
|
2717
|
+
throw new Error(err.error?.message || "Anthropic API Error");
|
|
2718
|
+
}
|
|
2719
|
+
const data = await res.json();
|
|
2720
|
+
const content = data.content?.[0]?.text || "";
|
|
2721
|
+
setResponse(content);
|
|
2722
|
+
return content;
|
|
2723
|
+
} catch (err) {
|
|
2724
|
+
setError(err);
|
|
2725
|
+
throw err;
|
|
2726
|
+
} finally {
|
|
2727
|
+
setLoading(false);
|
|
2728
|
+
}
|
|
2729
|
+
}, [apiKey, model, maxTokens, temperature]);
|
|
2730
|
+
return { chat, response, loading, error };
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// src/hooks/useEmbeddings/useEmbeddings.ts
|
|
2734
|
+
var import_react59 = require("react");
|
|
2735
|
+
function useEmbeddings(fetcher) {
|
|
2736
|
+
const [embeddings, setEmbeddings] = (0, import_react59.useState)(null);
|
|
2737
|
+
const [loading, setLoading] = (0, import_react59.useState)(false);
|
|
2738
|
+
const [error, setError] = (0, import_react59.useState)(null);
|
|
2739
|
+
const generate = (0, import_react59.useCallback)(async (texts) => {
|
|
2740
|
+
setLoading(true);
|
|
2741
|
+
setError(null);
|
|
2742
|
+
try {
|
|
2743
|
+
const result = await fetcher(texts);
|
|
2744
|
+
setEmbeddings(result);
|
|
2745
|
+
return result;
|
|
2746
|
+
} catch (err) {
|
|
2747
|
+
setError(err);
|
|
2748
|
+
throw err;
|
|
2749
|
+
} finally {
|
|
2750
|
+
setLoading(false);
|
|
2751
|
+
}
|
|
2752
|
+
}, [fetcher]);
|
|
2753
|
+
return { embeddings, loading, error, generate };
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
// src/hooks/useGemini/useGemini.ts
|
|
2757
|
+
var import_react60 = require("react");
|
|
2758
|
+
function useGemini(options = {}) {
|
|
2759
|
+
const {
|
|
2760
|
+
apiKey,
|
|
2761
|
+
model = "gemini-pro"
|
|
2762
|
+
} = options;
|
|
2763
|
+
const [loading, setLoading] = (0, import_react60.useState)(false);
|
|
2764
|
+
const [response, setResponse] = (0, import_react60.useState)(null);
|
|
2765
|
+
const [error, setError] = (0, import_react60.useState)(null);
|
|
2766
|
+
const chat = (0, import_react60.useCallback)(async (contents) => {
|
|
2767
|
+
setLoading(true);
|
|
2768
|
+
setResponse(null);
|
|
2769
|
+
setError(null);
|
|
2770
|
+
try {
|
|
2771
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
|
|
2772
|
+
const res = await fetch(url, {
|
|
2773
|
+
method: "POST",
|
|
2774
|
+
headers: {
|
|
2775
|
+
"Content-Type": "application/json"
|
|
2776
|
+
},
|
|
2777
|
+
body: JSON.stringify({ contents })
|
|
2778
|
+
});
|
|
2779
|
+
if (!res.ok) {
|
|
2780
|
+
const err = await res.json();
|
|
2781
|
+
throw new Error(err.error?.message || "Gemini API Error");
|
|
2782
|
+
}
|
|
2783
|
+
const data = await res.json();
|
|
2784
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
2785
|
+
setResponse(text);
|
|
2786
|
+
return text;
|
|
2787
|
+
} catch (err) {
|
|
2788
|
+
setError(err);
|
|
2789
|
+
throw err;
|
|
2790
|
+
} finally {
|
|
2791
|
+
setLoading(false);
|
|
2792
|
+
}
|
|
2793
|
+
}, [apiKey, model]);
|
|
2794
|
+
return { chat, response, loading, error };
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
// src/hooks/useLLMStream/useLLMStream.ts
|
|
2798
|
+
var import_react61 = require("react");
|
|
2799
|
+
function useLLMStream(options = {}) {
|
|
2800
|
+
const [data, setData] = (0, import_react61.useState)("");
|
|
2801
|
+
const [loading, setLoading] = (0, import_react61.useState)(false);
|
|
2802
|
+
const [error, setError] = (0, import_react61.useState)(null);
|
|
2803
|
+
const abortControllerRef = (0, import_react61.useRef)(null);
|
|
2804
|
+
const stream = (0, import_react61.useCallback)(async (url, fetchOptions = {}) => {
|
|
2805
|
+
try {
|
|
2806
|
+
if (abortControllerRef.current) {
|
|
2807
|
+
abortControllerRef.current.abort();
|
|
2808
|
+
}
|
|
2809
|
+
const controller = new AbortController();
|
|
2810
|
+
abortControllerRef.current = controller;
|
|
2811
|
+
setLoading(true);
|
|
2812
|
+
setError(null);
|
|
2813
|
+
setData("");
|
|
2814
|
+
const response = await fetch(url, {
|
|
2815
|
+
...fetchOptions,
|
|
2816
|
+
signal: controller.signal
|
|
2817
|
+
});
|
|
2818
|
+
if (!response.ok) {
|
|
2819
|
+
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
|
|
2820
|
+
}
|
|
2821
|
+
const reader = response.body?.getReader();
|
|
2822
|
+
const decoder = new TextDecoder();
|
|
2823
|
+
if (!reader) {
|
|
2824
|
+
throw new Error("Response body is not readable");
|
|
2825
|
+
}
|
|
2826
|
+
let accumulatedText = "";
|
|
2827
|
+
while (true) {
|
|
2828
|
+
const { done, value } = await reader.read();
|
|
2829
|
+
if (done) break;
|
|
2830
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
2831
|
+
accumulatedText += chunk;
|
|
2832
|
+
setData((prev) => prev + chunk);
|
|
2833
|
+
options.onToken?.(chunk, accumulatedText);
|
|
2834
|
+
}
|
|
2835
|
+
options.onComplete?.(accumulatedText);
|
|
2836
|
+
} catch (err) {
|
|
2837
|
+
if (err.name === "AbortError") return;
|
|
2838
|
+
setError(err);
|
|
2839
|
+
options.onError?.(err);
|
|
2840
|
+
} finally {
|
|
2841
|
+
setLoading(false);
|
|
2842
|
+
abortControllerRef.current = null;
|
|
2843
|
+
}
|
|
2844
|
+
}, [options]);
|
|
2845
|
+
const cancel = (0, import_react61.useCallback)(() => {
|
|
2846
|
+
if (abortControllerRef.current) {
|
|
2847
|
+
abortControllerRef.current.abort();
|
|
2848
|
+
abortControllerRef.current = null;
|
|
2849
|
+
setLoading(false);
|
|
2850
|
+
}
|
|
2851
|
+
}, []);
|
|
2852
|
+
return {
|
|
2853
|
+
stream,
|
|
2854
|
+
cancel,
|
|
2855
|
+
data,
|
|
2856
|
+
loading,
|
|
2857
|
+
error
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// src/hooks/useOpenAI/useOpenAI.ts
|
|
2862
|
+
var import_react62 = require("react");
|
|
2863
|
+
function useOpenAI(options = {}) {
|
|
2864
|
+
const {
|
|
2865
|
+
apiKey,
|
|
2866
|
+
apiBase = "https://api.openai.com/v1",
|
|
2867
|
+
model = "gpt-3.5-turbo",
|
|
2868
|
+
temperature = 0.7,
|
|
2869
|
+
stream = false
|
|
2870
|
+
} = options;
|
|
2871
|
+
const [loading, setLoading] = (0, import_react62.useState)(false);
|
|
2872
|
+
const [response, setResponse] = (0, import_react62.useState)(null);
|
|
2873
|
+
const [error, setError] = (0, import_react62.useState)(null);
|
|
2874
|
+
const chat = (0, import_react62.useCallback)(async (messages) => {
|
|
2875
|
+
setLoading(true);
|
|
2876
|
+
setResponse(null);
|
|
2877
|
+
setError(null);
|
|
2878
|
+
try {
|
|
2879
|
+
const res = await fetch(`${apiBase}/chat/completions`, {
|
|
2880
|
+
method: "POST",
|
|
2881
|
+
headers: {
|
|
2882
|
+
"Content-Type": "application/json",
|
|
2883
|
+
"Authorization": `Bearer ${apiKey}`
|
|
2884
|
+
},
|
|
2885
|
+
body: JSON.stringify({
|
|
2886
|
+
model,
|
|
2887
|
+
messages,
|
|
2888
|
+
temperature,
|
|
2889
|
+
stream: false
|
|
2890
|
+
// Streaming strictly not supported in this basic version, useLLMStream for that
|
|
2891
|
+
})
|
|
2892
|
+
});
|
|
2893
|
+
if (!res.ok) {
|
|
2894
|
+
const err = await res.json();
|
|
2895
|
+
throw new Error(err.error?.message || "OpenAI API Error");
|
|
2896
|
+
}
|
|
2897
|
+
const data = await res.json();
|
|
2898
|
+
const content = data.choices?.[0]?.message?.content || "";
|
|
2899
|
+
setResponse(content);
|
|
2900
|
+
return content;
|
|
2901
|
+
} catch (err) {
|
|
2902
|
+
setError(err);
|
|
2903
|
+
throw err;
|
|
2904
|
+
} finally {
|
|
2905
|
+
setLoading(false);
|
|
2906
|
+
}
|
|
2907
|
+
}, [apiKey, apiBase, model, temperature]);
|
|
2908
|
+
return {
|
|
2909
|
+
chat,
|
|
2910
|
+
response,
|
|
2911
|
+
loading,
|
|
2912
|
+
error
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
// src/hooks/useRAG/useRAG.ts
|
|
2917
|
+
var import_react63 = require("react");
|
|
2918
|
+
function useRAG(options) {
|
|
2919
|
+
const [loading, setLoading] = (0, import_react63.useState)(false);
|
|
2920
|
+
const [answer, setAnswer] = (0, import_react63.useState)(null);
|
|
2921
|
+
const [retrievedDocs, setRetrievedDocs] = (0, import_react63.useState)([]);
|
|
2922
|
+
const [error, setError] = (0, import_react63.useState)(null);
|
|
2923
|
+
const ask = (0, import_react63.useCallback)(async (query) => {
|
|
2924
|
+
setLoading(true);
|
|
2925
|
+
setError(null);
|
|
2926
|
+
setAnswer(null);
|
|
2927
|
+
setRetrievedDocs([]);
|
|
2928
|
+
try {
|
|
2929
|
+
const docs = await options.retrieve(query);
|
|
2930
|
+
setRetrievedDocs(docs);
|
|
2931
|
+
const contextPrompt = `
|
|
2932
|
+
Context documents:
|
|
2933
|
+
${docs.map((d) => `- ${d.content}`).join("\n")}
|
|
2934
|
+
|
|
2935
|
+
Query: ${query}
|
|
2936
|
+
`;
|
|
2937
|
+
const result = await options.generate(contextPrompt, docs);
|
|
2938
|
+
setAnswer(result);
|
|
2939
|
+
return result;
|
|
2940
|
+
} catch (err) {
|
|
2941
|
+
setError(err);
|
|
2942
|
+
throw err;
|
|
2943
|
+
} finally {
|
|
2944
|
+
setLoading(false);
|
|
2945
|
+
}
|
|
2946
|
+
}, [options]);
|
|
2947
|
+
return { ask, answer, retrievedDocs, loading, error };
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// src/hooks/useSearchHighlight/useSearchHighlight.ts
|
|
2951
|
+
var import_react64 = require("react");
|
|
2952
|
+
function useSearchHighlight(text, query, options = {}) {
|
|
2953
|
+
const { caseSensitive = false } = options;
|
|
2954
|
+
return (0, import_react64.useMemo)(() => {
|
|
2955
|
+
if (!query) {
|
|
2956
|
+
return [{ text, isMatch: false }];
|
|
2957
|
+
}
|
|
2958
|
+
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2959
|
+
const flags = caseSensitive ? "g" : "gi";
|
|
2960
|
+
const regex = new RegExp(`(${escapedQuery})`, flags);
|
|
2961
|
+
const parts = text.split(regex);
|
|
2962
|
+
return parts.filter((part) => part).map((part) => {
|
|
2963
|
+
const isMatch = caseSensitive ? part === query : part.toLowerCase() === query.toLowerCase();
|
|
2964
|
+
return {
|
|
2965
|
+
text: part,
|
|
2966
|
+
isMatch
|
|
2967
|
+
};
|
|
2968
|
+
});
|
|
2969
|
+
}, [text, query, caseSensitive]);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
// src/hooks/useSemanticSearch/useSemanticSearch.ts
|
|
2973
|
+
var import_react65 = require("react");
|
|
2974
|
+
function useSemanticSearch(queryEmbedding, items, getItemEmbedding, topK = 5) {
|
|
2975
|
+
return (0, import_react65.useMemo)(() => {
|
|
2976
|
+
if (!queryEmbedding || items.length === 0) return [];
|
|
2977
|
+
const results = items.map((item) => {
|
|
2978
|
+
const itemEmbedding = getItemEmbedding(item);
|
|
2979
|
+
const score = cosineSimilarity(queryEmbedding, itemEmbedding);
|
|
2980
|
+
return { item, score };
|
|
2981
|
+
});
|
|
2982
|
+
return results.sort((a, b) => b.score - a.score).slice(0, topK);
|
|
2983
|
+
}, [queryEmbedding, items, getItemEmbedding, topK]);
|
|
2984
|
+
}
|
|
2985
|
+
function cosineSimilarity(a, b) {
|
|
2986
|
+
if (a.length !== b.length) return 0;
|
|
2987
|
+
let dotProduct = 0;
|
|
2988
|
+
let magnitudeA = 0;
|
|
2989
|
+
let magnitudeB = 0;
|
|
2990
|
+
for (let i = 0; i < a.length; i++) {
|
|
2991
|
+
dotProduct += a[i] * b[i];
|
|
2992
|
+
magnitudeA += a[i] * a[i];
|
|
2993
|
+
magnitudeB += b[i] * b[i];
|
|
2994
|
+
}
|
|
2995
|
+
magnitudeA = Math.sqrt(magnitudeA);
|
|
2996
|
+
magnitudeB = Math.sqrt(magnitudeB);
|
|
2997
|
+
if (magnitudeA === 0 || magnitudeB === 0) return 0;
|
|
2998
|
+
return dotProduct / (magnitudeA * magnitudeB);
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
// src/hooks/useSTT/useSTT.ts
|
|
3002
|
+
var import_react66 = require("react");
|
|
3003
|
+
function useSTT(options = {}) {
|
|
3004
|
+
const [listening, setListening] = (0, import_react66.useState)(false);
|
|
3005
|
+
const [transcript, setTranscript] = (0, import_react66.useState)("");
|
|
3006
|
+
const [supported, setSupported] = (0, import_react66.useState)(false);
|
|
3007
|
+
const recognitionRef = (0, import_react66.useRef)(null);
|
|
3008
|
+
const optionsRef = (0, import_react66.useRef)(options);
|
|
3009
|
+
optionsRef.current = options;
|
|
3010
|
+
(0, import_react66.useEffect)(() => {
|
|
3011
|
+
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
3012
|
+
if (SpeechRecognition) {
|
|
3013
|
+
setSupported(true);
|
|
3014
|
+
recognitionRef.current = new SpeechRecognition();
|
|
3015
|
+
}
|
|
3016
|
+
}, []);
|
|
3017
|
+
const listen = (0, import_react66.useCallback)(() => {
|
|
3018
|
+
if (!recognitionRef.current) return;
|
|
3019
|
+
const recognition = recognitionRef.current;
|
|
3020
|
+
const opts = optionsRef.current;
|
|
3021
|
+
recognition.continuous = opts.continuous ?? false;
|
|
3022
|
+
recognition.interimResults = opts.interimResults ?? false;
|
|
3023
|
+
recognition.lang = opts.lang || "en-US";
|
|
3024
|
+
recognition.onstart = () => setListening(true);
|
|
3025
|
+
recognition.onresult = (event) => {
|
|
3026
|
+
let finalTranscript = "";
|
|
3027
|
+
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
|
3028
|
+
if (event.results[i].isFinal) {
|
|
3029
|
+
finalTranscript += event.results[i][0].transcript;
|
|
3030
|
+
} else if (opts.interimResults) {
|
|
3031
|
+
finalTranscript += event.results[i][0].transcript;
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
setTranscript(finalTranscript);
|
|
3035
|
+
opts.onResult?.(finalTranscript);
|
|
3036
|
+
};
|
|
3037
|
+
recognition.onerror = (event) => {
|
|
3038
|
+
setListening(false);
|
|
3039
|
+
opts.onError?.(event.error);
|
|
3040
|
+
};
|
|
3041
|
+
recognition.onend = () => {
|
|
3042
|
+
setListening(false);
|
|
3043
|
+
opts.onEnd?.();
|
|
3044
|
+
};
|
|
3045
|
+
try {
|
|
3046
|
+
recognition.start();
|
|
3047
|
+
} catch (e) {
|
|
3048
|
+
}
|
|
3049
|
+
}, []);
|
|
3050
|
+
const stop = (0, import_react66.useCallback)(() => {
|
|
3051
|
+
recognitionRef.current?.stop();
|
|
3052
|
+
setListening(false);
|
|
3053
|
+
}, []);
|
|
3054
|
+
const abort = (0, import_react66.useCallback)(() => {
|
|
3055
|
+
recognitionRef.current?.abort();
|
|
3056
|
+
setListening(false);
|
|
3057
|
+
}, []);
|
|
3058
|
+
return {
|
|
3059
|
+
listen,
|
|
3060
|
+
stop,
|
|
3061
|
+
abort,
|
|
3062
|
+
listening,
|
|
3063
|
+
transcript,
|
|
3064
|
+
supported
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
// src/hooks/useTTS/useTTS.ts
|
|
3069
|
+
var import_react67 = require("react");
|
|
3070
|
+
function useTTS(options = {}) {
|
|
3071
|
+
const [speaking, setSpeaking] = (0, import_react67.useState)(false);
|
|
3072
|
+
const [supported, setSupported] = (0, import_react67.useState)(false);
|
|
3073
|
+
const [voices, setVoices] = (0, import_react67.useState)([]);
|
|
3074
|
+
const optionsRef = (0, import_react67.useRef)(options);
|
|
3075
|
+
optionsRef.current = options;
|
|
3076
|
+
(0, import_react67.useEffect)(() => {
|
|
3077
|
+
if (typeof window !== "undefined" && "speechSynthesis" in window) {
|
|
3078
|
+
setSupported(true);
|
|
3079
|
+
const updateVoices = () => {
|
|
3080
|
+
setVoices(window.speechSynthesis.getVoices());
|
|
3081
|
+
};
|
|
3082
|
+
updateVoices();
|
|
3083
|
+
window.speechSynthesis.onvoiceschanged = updateVoices;
|
|
3084
|
+
}
|
|
3085
|
+
}, []);
|
|
3086
|
+
const cancel = (0, import_react67.useCallback)(() => {
|
|
3087
|
+
if (!supported) return;
|
|
3088
|
+
window.speechSynthesis.cancel();
|
|
3089
|
+
setSpeaking(false);
|
|
3090
|
+
}, [supported]);
|
|
3091
|
+
const speak = (0, import_react67.useCallback)((text, overrideOptions = {}) => {
|
|
3092
|
+
if (!supported) return;
|
|
3093
|
+
cancel();
|
|
3094
|
+
const opts = { ...optionsRef.current, ...overrideOptions };
|
|
3095
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
3096
|
+
if (opts.volume !== void 0) utterance.volume = opts.volume;
|
|
3097
|
+
if (opts.rate !== void 0) utterance.rate = opts.rate;
|
|
3098
|
+
if (opts.pitch !== void 0) utterance.pitch = opts.pitch;
|
|
3099
|
+
if (opts.voiceURI) {
|
|
3100
|
+
const voice = voices.find((v) => v.voiceURI === opts.voiceURI);
|
|
3101
|
+
if (voice) utterance.voice = voice;
|
|
3102
|
+
}
|
|
3103
|
+
utterance.onstart = () => {
|
|
3104
|
+
setSpeaking(true);
|
|
3105
|
+
opts.onStart?.();
|
|
3106
|
+
};
|
|
3107
|
+
utterance.onend = () => {
|
|
3108
|
+
setSpeaking(false);
|
|
3109
|
+
opts.onEnd?.();
|
|
3110
|
+
};
|
|
3111
|
+
utterance.onerror = (event) => {
|
|
3112
|
+
setSpeaking(false);
|
|
3113
|
+
opts.onError?.(event);
|
|
3114
|
+
};
|
|
3115
|
+
window.speechSynthesis.speak(utterance);
|
|
3116
|
+
}, [supported, voices, cancel]);
|
|
3117
|
+
(0, import_react67.useEffect)(() => {
|
|
3118
|
+
return () => {
|
|
3119
|
+
if (supported) {
|
|
3120
|
+
window.speechSynthesis.cancel();
|
|
3121
|
+
}
|
|
3122
|
+
};
|
|
3123
|
+
}, [supported]);
|
|
3124
|
+
return {
|
|
3125
|
+
speak,
|
|
3126
|
+
cancel,
|
|
3127
|
+
speaking,
|
|
3128
|
+
supported,
|
|
3129
|
+
voices
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
// src/hooks/useAnimate/useAnimate.ts
|
|
3134
|
+
var import_react68 = require("react");
|
|
3135
|
+
function useAnimate(callback, running = true) {
|
|
3136
|
+
const requestRef = (0, import_react68.useRef)();
|
|
3137
|
+
const previousTimeRef = (0, import_react68.useRef)();
|
|
3138
|
+
const savedCallback = useStableCallback(callback);
|
|
3139
|
+
const animate = (0, import_react68.useCallback)((time) => {
|
|
3140
|
+
if (previousTimeRef.current !== void 0) {
|
|
3141
|
+
const deltaTime = time - previousTimeRef.current;
|
|
3142
|
+
savedCallback(time, deltaTime);
|
|
3143
|
+
}
|
|
3144
|
+
previousTimeRef.current = time;
|
|
3145
|
+
requestRef.current = requestAnimationFrame(animate);
|
|
3146
|
+
}, [savedCallback]);
|
|
3147
|
+
(0, import_react68.useEffect)(() => {
|
|
3148
|
+
if (running) {
|
|
3149
|
+
requestRef.current = requestAnimationFrame(animate);
|
|
3150
|
+
} else {
|
|
3151
|
+
previousTimeRef.current = void 0;
|
|
3152
|
+
if (requestRef.current) {
|
|
3153
|
+
cancelAnimationFrame(requestRef.current);
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
return () => {
|
|
3157
|
+
if (requestRef.current) {
|
|
3158
|
+
cancelAnimationFrame(requestRef.current);
|
|
3159
|
+
}
|
|
3160
|
+
};
|
|
3161
|
+
}, [running, animate]);
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
// src/hooks/useVideoRef/useVideoRef.ts
|
|
3165
|
+
var import_react69 = require("react");
|
|
3166
|
+
function useMediaRef() {
|
|
3167
|
+
const ref = (0, import_react69.useRef)(null);
|
|
3168
|
+
const [state, setState] = (0, import_react69.useState)({
|
|
3169
|
+
playing: false,
|
|
3170
|
+
paused: true,
|
|
3171
|
+
muted: false,
|
|
3172
|
+
volume: 1,
|
|
3173
|
+
time: 0,
|
|
3174
|
+
duration: 0,
|
|
3175
|
+
buffered: 0,
|
|
3176
|
+
waiting: false,
|
|
3177
|
+
ended: false
|
|
3178
|
+
});
|
|
3179
|
+
const updateState = (0, import_react69.useCallback)(() => {
|
|
3180
|
+
const el = ref.current;
|
|
3181
|
+
if (!el) return;
|
|
3182
|
+
setState({
|
|
3183
|
+
playing: !el.paused && !el.ended && el.readyState > 2,
|
|
3184
|
+
paused: el.paused,
|
|
3185
|
+
muted: el.muted,
|
|
3186
|
+
volume: el.volume,
|
|
3187
|
+
time: el.currentTime,
|
|
3188
|
+
duration: el.duration || 0,
|
|
3189
|
+
buffered: el.buffered.length > 0 ? el.buffered.end(el.buffered.length - 1) : 0,
|
|
3190
|
+
waiting: el.readyState < 3,
|
|
3191
|
+
// HAVE_FUTURE_DATA
|
|
3192
|
+
ended: el.ended
|
|
3193
|
+
});
|
|
3194
|
+
}, []);
|
|
3195
|
+
(0, import_react69.useEffect)(() => {
|
|
3196
|
+
const el = ref.current;
|
|
3197
|
+
if (!el) return;
|
|
3198
|
+
const events = [
|
|
3199
|
+
"loadstart",
|
|
3200
|
+
"loadedmetadata",
|
|
3201
|
+
"canplay",
|
|
3202
|
+
"play",
|
|
3203
|
+
"playing",
|
|
3204
|
+
"pause",
|
|
3205
|
+
"waiting",
|
|
3206
|
+
"seeking",
|
|
3207
|
+
"seeked",
|
|
3208
|
+
"ended",
|
|
3209
|
+
"durationchange",
|
|
3210
|
+
"timeupdate",
|
|
3211
|
+
"progress",
|
|
3212
|
+
"volumechange"
|
|
3213
|
+
];
|
|
3214
|
+
events.forEach((ev) => el.addEventListener(ev, updateState));
|
|
3215
|
+
updateState();
|
|
3216
|
+
return () => {
|
|
3217
|
+
events.forEach((ev) => el.removeEventListener(ev, updateState));
|
|
3218
|
+
};
|
|
3219
|
+
}, [updateState]);
|
|
3220
|
+
const controls = {
|
|
3221
|
+
play: async () => {
|
|
3222
|
+
await ref.current?.play();
|
|
3223
|
+
},
|
|
3224
|
+
pause: () => {
|
|
3225
|
+
ref.current?.pause();
|
|
3226
|
+
},
|
|
3227
|
+
toggle: () => {
|
|
3228
|
+
const el = ref.current;
|
|
3229
|
+
if (el) el.paused ? el.play() : el.pause();
|
|
3230
|
+
},
|
|
3231
|
+
seek: (time) => {
|
|
3232
|
+
if (ref.current) ref.current.currentTime = time;
|
|
3233
|
+
},
|
|
3234
|
+
mute: () => {
|
|
3235
|
+
if (ref.current) ref.current.muted = true;
|
|
3236
|
+
},
|
|
3237
|
+
unmute: () => {
|
|
3238
|
+
if (ref.current) ref.current.muted = false;
|
|
3239
|
+
},
|
|
3240
|
+
setVolume: (val) => {
|
|
3241
|
+
if (ref.current) ref.current.volume = Math.max(0, Math.min(1, val));
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
return { ref, controls, state };
|
|
3245
|
+
}
|
|
3246
|
+
function useVideoRef() {
|
|
3247
|
+
return useMediaRef();
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
// src/hooks/useAudioRef/useAudioRef.ts
|
|
3251
|
+
function useAudioRef() {
|
|
3252
|
+
return useMediaRef();
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
// src/hooks/useCanvas/useCanvas.ts
|
|
3256
|
+
var import_react70 = require("react");
|
|
3257
|
+
function useCanvas(options = {}) {
|
|
3258
|
+
const canvasRef = (0, import_react70.useRef)(null);
|
|
3259
|
+
const requestRef = (0, import_react70.useRef)();
|
|
3260
|
+
const frameCountRef = (0, import_react70.useRef)(0);
|
|
3261
|
+
(0, import_react70.useEffect)(() => {
|
|
3262
|
+
const canvas = canvasRef.current;
|
|
3263
|
+
if (!canvas) return;
|
|
3264
|
+
const context = canvas.getContext("2d");
|
|
3265
|
+
if (!context) return;
|
|
3266
|
+
const dpr = window.devicePixelRatio || 1;
|
|
3267
|
+
const rect = canvas.getBoundingClientRect();
|
|
3268
|
+
const width = options.width ?? rect.width;
|
|
3269
|
+
const height = options.height ?? rect.height;
|
|
3270
|
+
canvas.width = width * dpr;
|
|
3271
|
+
canvas.height = height * dpr;
|
|
3272
|
+
context.scale(dpr, dpr);
|
|
3273
|
+
canvas.style.width = `${width}px`;
|
|
3274
|
+
canvas.style.height = `${height}px`;
|
|
3275
|
+
const render = () => {
|
|
3276
|
+
frameCountRef.current++;
|
|
3277
|
+
if (options.animate) {
|
|
3278
|
+
options.animate(context, frameCountRef.current);
|
|
3279
|
+
}
|
|
3280
|
+
requestRef.current = requestAnimationFrame(render);
|
|
3281
|
+
};
|
|
3282
|
+
if (options.animate) {
|
|
3283
|
+
render();
|
|
3284
|
+
}
|
|
3285
|
+
return () => {
|
|
3286
|
+
if (requestRef.current) cancelAnimationFrame(requestRef.current);
|
|
3287
|
+
};
|
|
3288
|
+
}, [options.width, options.height, options.animate]);
|
|
3289
|
+
return canvasRef;
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3292
|
+
// src/hooks/useFrameRate/useFrameRate.ts
|
|
3293
|
+
var import_react71 = require("react");
|
|
3294
|
+
function useFrameRate(running = true) {
|
|
3295
|
+
const [fps, setFps] = (0, import_react71.useState)(0);
|
|
3296
|
+
const frameCountRef = (0, import_react71.useRef)(0);
|
|
3297
|
+
const lastTimeRef = (0, import_react71.useRef)(performance.now());
|
|
3298
|
+
const requestRef = (0, import_react71.useRef)();
|
|
3299
|
+
(0, import_react71.useEffect)(() => {
|
|
3300
|
+
if (!running) return;
|
|
3301
|
+
const loop = (time) => {
|
|
3302
|
+
frameCountRef.current++;
|
|
3303
|
+
if (time - lastTimeRef.current >= 1e3) {
|
|
3304
|
+
setFps(frameCountRef.current);
|
|
3305
|
+
frameCountRef.current = 0;
|
|
3306
|
+
lastTimeRef.current = time;
|
|
3307
|
+
}
|
|
3308
|
+
requestRef.current = requestAnimationFrame(loop);
|
|
3309
|
+
};
|
|
3310
|
+
requestRef.current = requestAnimationFrame(loop);
|
|
3311
|
+
return () => {
|
|
3312
|
+
if (requestRef.current) cancelAnimationFrame(requestRef.current);
|
|
3313
|
+
};
|
|
3314
|
+
}, [running]);
|
|
3315
|
+
return fps;
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
// src/hooks/useLottie/useLottie.ts
|
|
3319
|
+
var import_lottie_web = __toESM(require("lottie-web"));
|
|
3320
|
+
var import_react72 = require("react");
|
|
3321
|
+
function useLottie(containerRef, options) {
|
|
3322
|
+
const animationRef = (0, import_react72.useRef)();
|
|
3323
|
+
(0, import_react72.useEffect)(() => {
|
|
3324
|
+
if (!containerRef.current) return;
|
|
3325
|
+
const anim = import_lottie_web.default.loadAnimation({
|
|
3326
|
+
container: containerRef.current,
|
|
3327
|
+
renderer: "svg",
|
|
3328
|
+
loop: options.loop ?? true,
|
|
3329
|
+
autoplay: options.autoplay ?? true,
|
|
3330
|
+
animationData: options.animationData,
|
|
3331
|
+
path: options.path
|
|
3332
|
+
});
|
|
3333
|
+
animationRef.current = anim;
|
|
3334
|
+
if (options.speed) anim.setSpeed(options.speed);
|
|
3335
|
+
if (options.direction) anim.setDirection(options.direction);
|
|
3336
|
+
return () => {
|
|
3337
|
+
anim.destroy();
|
|
3338
|
+
};
|
|
3339
|
+
}, [options.path, options.animationData]);
|
|
3340
|
+
(0, import_react72.useEffect)(() => {
|
|
3341
|
+
if (!animationRef.current) return;
|
|
3342
|
+
if (options.speed !== void 0) animationRef.current.setSpeed(options.speed);
|
|
3343
|
+
if (options.direction !== void 0) animationRef.current.setDirection(options.direction);
|
|
3344
|
+
if (options.isPlaying !== void 0) {
|
|
3345
|
+
options.isPlaying ? animationRef.current.play() : animationRef.current.pause();
|
|
3346
|
+
}
|
|
3347
|
+
}, [options.speed, options.direction, options.isPlaying]);
|
|
3348
|
+
return animationRef.current;
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
// src/hooks/useParallax/useParallax.ts
|
|
3352
|
+
var import_react73 = require("react");
|
|
3353
|
+
function useParallax(options = {}) {
|
|
3354
|
+
const { speed = 0.5, axis = "y" } = options;
|
|
3355
|
+
const [offset, setOffset] = (0, import_react73.useState)(0);
|
|
3356
|
+
const ref = (0, import_react73.useRef)(null);
|
|
3357
|
+
(0, import_react73.useEffect)(() => {
|
|
3358
|
+
const handleScroll = () => {
|
|
3359
|
+
if (!ref.current) return;
|
|
3360
|
+
const rect = ref.current.getBoundingClientRect();
|
|
3361
|
+
const scrollY = window.scrollY || window.pageYOffset;
|
|
3362
|
+
const scrollX = window.scrollX || window.pageXOffset;
|
|
3363
|
+
const val = axis === "y" ? scrollY : scrollX;
|
|
3364
|
+
setOffset(val * speed);
|
|
3365
|
+
};
|
|
3366
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
3367
|
+
handleScroll();
|
|
3368
|
+
return () => window.removeEventListener("scroll", handleScroll);
|
|
3369
|
+
}, [speed, axis]);
|
|
3370
|
+
return {
|
|
3371
|
+
ref,
|
|
3372
|
+
style: {
|
|
3373
|
+
transform: axis === "y" ? `translateY(${offset}px)` : `translateX(${offset}px)`,
|
|
3374
|
+
willChange: "transform"
|
|
3375
|
+
}
|
|
3376
|
+
};
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
// src/hooks/useSpringCore/useSpringCore.ts
|
|
3380
|
+
var import_react74 = require("react");
|
|
3381
|
+
var DEFAULT_CONFIG = {
|
|
3382
|
+
stiffness: 170,
|
|
3383
|
+
damping: 26,
|
|
3384
|
+
mass: 1
|
|
32
3385
|
};
|
|
3386
|
+
function useSpringCore(targetValue, options = {}) {
|
|
3387
|
+
const [value, setValue] = (0, import_react74.useState)(options.initialValue ?? targetValue);
|
|
3388
|
+
const velocityRef = (0, import_react74.useRef)(0);
|
|
3389
|
+
const valueRef = (0, import_react74.useRef)(options.initialValue ?? targetValue);
|
|
3390
|
+
const lastTimeRef = (0, import_react74.useRef)();
|
|
3391
|
+
const rafRef = (0, import_react74.useRef)();
|
|
3392
|
+
const config = { ...DEFAULT_CONFIG, ...options };
|
|
3393
|
+
(0, import_react74.useEffect)(() => {
|
|
3394
|
+
const animate = (time) => {
|
|
3395
|
+
if (lastTimeRef.current === void 0) {
|
|
3396
|
+
lastTimeRef.current = time;
|
|
3397
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
const deltaTime = (time - lastTimeRef.current) / 1e3;
|
|
3401
|
+
lastTimeRef.current = time;
|
|
3402
|
+
const dt = Math.min(deltaTime, 0.1);
|
|
3403
|
+
const force = -config.stiffness * (valueRef.current - targetValue);
|
|
3404
|
+
const dampingForce = -config.damping * velocityRef.current;
|
|
3405
|
+
const acceleration = (force + dampingForce) / config.mass;
|
|
3406
|
+
velocityRef.current += acceleration * dt;
|
|
3407
|
+
valueRef.current += velocityRef.current * dt;
|
|
3408
|
+
setValue(valueRef.current);
|
|
3409
|
+
if (Math.abs(velocityRef.current) < 0.01 && Math.abs(valueRef.current - targetValue) < 0.01) {
|
|
3410
|
+
setValue(targetValue);
|
|
3411
|
+
valueRef.current = targetValue;
|
|
3412
|
+
velocityRef.current = 0;
|
|
3413
|
+
return;
|
|
3414
|
+
}
|
|
3415
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
3416
|
+
};
|
|
3417
|
+
if (valueRef.current !== targetValue) {
|
|
3418
|
+
lastTimeRef.current = void 0;
|
|
3419
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
3420
|
+
}
|
|
3421
|
+
return () => {
|
|
3422
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
3423
|
+
};
|
|
3424
|
+
}, [targetValue, config.stiffness, config.damping, config.mass]);
|
|
3425
|
+
return value;
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
// src/hooks/useSVGAnimation/useSVGAnimation.ts
|
|
3429
|
+
var import_react75 = require("react");
|
|
3430
|
+
function useSVGAnimation(length, options = {}) {
|
|
3431
|
+
const [offset, setOffset] = (0, import_react75.useState)(length);
|
|
3432
|
+
const { duration = 1e3, delay = 0, easing = (t) => t } = options;
|
|
3433
|
+
(0, import_react75.useEffect)(() => {
|
|
3434
|
+
let start = null;
|
|
3435
|
+
let rafId;
|
|
3436
|
+
const animate = (time) => {
|
|
3437
|
+
if (!start) start = time;
|
|
3438
|
+
const elapsed = time - start;
|
|
3439
|
+
const progress = Math.min(Math.max((elapsed - delay) / duration, 0), 1);
|
|
3440
|
+
const easedProgress = easing(progress);
|
|
3441
|
+
setOffset(length * (1 - easedProgress));
|
|
3442
|
+
if (progress < 1) {
|
|
3443
|
+
rafId = requestAnimationFrame(animate);
|
|
3444
|
+
}
|
|
3445
|
+
};
|
|
3446
|
+
rafId = requestAnimationFrame(animate);
|
|
3447
|
+
return () => {
|
|
3448
|
+
cancelAnimationFrame(rafId);
|
|
3449
|
+
};
|
|
3450
|
+
}, [length, duration, delay]);
|
|
3451
|
+
return {
|
|
3452
|
+
strokeDasharray: length,
|
|
3453
|
+
strokeDashoffset: offset
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3457
|
+
// src/hooks/useThreeJS/useThreeJS.ts
|
|
3458
|
+
var import_react76 = require("react");
|
|
3459
|
+
var THREE = __toESM(require("three"));
|
|
3460
|
+
function useThreeJS(containerRef, options = {}) {
|
|
3461
|
+
const { init, animate, resize = true } = options;
|
|
3462
|
+
const rendererRef = (0, import_react76.useRef)();
|
|
3463
|
+
const sceneRef = (0, import_react76.useRef)();
|
|
3464
|
+
const cameraRef = (0, import_react76.useRef)();
|
|
3465
|
+
const requestRef = (0, import_react76.useRef)();
|
|
3466
|
+
(0, import_react76.useEffect)(() => {
|
|
3467
|
+
if (!containerRef.current) return;
|
|
3468
|
+
const width = containerRef.current.clientWidth;
|
|
3469
|
+
const height = containerRef.current.clientHeight;
|
|
3470
|
+
const scene = new THREE.Scene();
|
|
3471
|
+
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1e3);
|
|
3472
|
+
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
|
|
3473
|
+
renderer.setSize(width, height);
|
|
3474
|
+
containerRef.current.appendChild(renderer.domElement);
|
|
3475
|
+
sceneRef.current = scene;
|
|
3476
|
+
cameraRef.current = camera;
|
|
3477
|
+
rendererRef.current = renderer;
|
|
3478
|
+
if (init) {
|
|
3479
|
+
init(scene, camera, renderer);
|
|
3480
|
+
}
|
|
3481
|
+
const loop = (time) => {
|
|
3482
|
+
if (animate) {
|
|
3483
|
+
animate(time, scene, camera);
|
|
3484
|
+
}
|
|
3485
|
+
renderer.render(scene, camera);
|
|
3486
|
+
requestRef.current = requestAnimationFrame(loop);
|
|
3487
|
+
};
|
|
3488
|
+
loop(0);
|
|
3489
|
+
const handleResize = () => {
|
|
3490
|
+
if (!containerRef.current) return;
|
|
3491
|
+
const w = containerRef.current.clientWidth;
|
|
3492
|
+
const h = containerRef.current.clientHeight;
|
|
3493
|
+
camera.aspect = w / h;
|
|
3494
|
+
camera.updateProjectionMatrix();
|
|
3495
|
+
renderer.setSize(w, h);
|
|
3496
|
+
};
|
|
3497
|
+
if (resize) {
|
|
3498
|
+
window.addEventListener("resize", handleResize);
|
|
3499
|
+
}
|
|
3500
|
+
return () => {
|
|
3501
|
+
if (requestRef.current) cancelAnimationFrame(requestRef.current);
|
|
3502
|
+
if (resize) window.removeEventListener("resize", handleResize);
|
|
3503
|
+
renderer.dispose();
|
|
3504
|
+
if (containerRef.current) {
|
|
3505
|
+
containerRef.current.removeChild(renderer.domElement);
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
}, [init, animate, resize]);
|
|
3509
|
+
return { scene: sceneRef.current, camera: cameraRef.current, renderer: rendererRef.current };
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
// src/hooks/useBroadcastChannel/useBroadcastChannel.ts
|
|
3513
|
+
var import_react77 = require("react");
|
|
3514
|
+
function useBroadcastChannel(channelName) {
|
|
3515
|
+
const [lastMessage, setLastMessage] = (0, import_react77.useState)(null);
|
|
3516
|
+
const channelRef = (0, import_react77.useRef)(null);
|
|
3517
|
+
(0, import_react77.useEffect)(() => {
|
|
3518
|
+
const channel = new BroadcastChannel(channelName);
|
|
3519
|
+
channelRef.current = channel;
|
|
3520
|
+
channel.onmessage = (event) => {
|
|
3521
|
+
setLastMessage(event.data);
|
|
3522
|
+
};
|
|
3523
|
+
return () => {
|
|
3524
|
+
channel.close();
|
|
3525
|
+
};
|
|
3526
|
+
}, [channelName]);
|
|
3527
|
+
const postMessage = (0, import_react77.useCallback)((message) => {
|
|
3528
|
+
channelRef.current?.postMessage(message);
|
|
3529
|
+
}, []);
|
|
3530
|
+
return { postMessage, lastMessage };
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
// src/hooks/useCalendar/useCalendar.ts
|
|
3534
|
+
var import_react78 = require("react");
|
|
3535
|
+
function useCalendar(options = {}) {
|
|
3536
|
+
const [date, setDate] = (0, import_react78.useState)(options.initialDate || /* @__PURE__ */ new Date());
|
|
3537
|
+
const daysInMonth = (0, import_react78.useMemo)(() => {
|
|
3538
|
+
const year = date.getFullYear();
|
|
3539
|
+
const month = date.getMonth();
|
|
3540
|
+
return new Date(year, month + 1, 0).getDate();
|
|
3541
|
+
}, [date]);
|
|
3542
|
+
const firstDayOfMonth = (0, import_react78.useMemo)(() => {
|
|
3543
|
+
const year = date.getFullYear();
|
|
3544
|
+
const month = date.getMonth();
|
|
3545
|
+
return new Date(year, month, 1).getDay();
|
|
3546
|
+
}, [date]);
|
|
3547
|
+
const nextMonth = () => {
|
|
3548
|
+
setDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1));
|
|
3549
|
+
};
|
|
3550
|
+
const prevMonth = () => {
|
|
3551
|
+
setDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1));
|
|
3552
|
+
};
|
|
3553
|
+
return {
|
|
3554
|
+
date,
|
|
3555
|
+
daysInMonth,
|
|
3556
|
+
firstDayOfMonth,
|
|
3557
|
+
nextMonth,
|
|
3558
|
+
prevMonth,
|
|
3559
|
+
setHeader: setDate
|
|
3560
|
+
};
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
// src/hooks/useDragAndDrop/useDragAndDrop.ts
|
|
3564
|
+
var import_react79 = require("react");
|
|
3565
|
+
function useDragAndDrop(options = {}) {
|
|
3566
|
+
const [isDragging, setIsDragging] = (0, import_react79.useState)(false);
|
|
3567
|
+
const ref = (0, import_react79.useRef)(null);
|
|
3568
|
+
const handleDragEnter = (0, import_react79.useCallback)((e) => {
|
|
3569
|
+
e.preventDefault();
|
|
3570
|
+
e.stopPropagation();
|
|
3571
|
+
setIsDragging(true);
|
|
3572
|
+
}, []);
|
|
3573
|
+
const handleDragLeave = (0, import_react79.useCallback)((e) => {
|
|
3574
|
+
e.preventDefault();
|
|
3575
|
+
e.stopPropagation();
|
|
3576
|
+
setIsDragging(false);
|
|
3577
|
+
}, []);
|
|
3578
|
+
const handleDragOver = (0, import_react79.useCallback)((e) => {
|
|
3579
|
+
e.preventDefault();
|
|
3580
|
+
e.stopPropagation();
|
|
3581
|
+
}, []);
|
|
3582
|
+
const handleDrop = (0, import_react79.useCallback)((e) => {
|
|
3583
|
+
e.preventDefault();
|
|
3584
|
+
e.stopPropagation();
|
|
3585
|
+
setIsDragging(false);
|
|
3586
|
+
if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
3587
|
+
const files = Array.from(e.dataTransfer.files);
|
|
3588
|
+
options.onDrop?.(files);
|
|
3589
|
+
e.dataTransfer.clearData();
|
|
3590
|
+
}
|
|
3591
|
+
}, [options]);
|
|
3592
|
+
(0, import_react79.useEffect)(() => {
|
|
3593
|
+
const el = ref.current;
|
|
3594
|
+
if (!el) return;
|
|
3595
|
+
el.addEventListener("dragenter", handleDragEnter);
|
|
3596
|
+
el.addEventListener("dragleave", handleDragLeave);
|
|
3597
|
+
el.addEventListener("dragover", handleDragOver);
|
|
3598
|
+
el.addEventListener("drop", handleDrop);
|
|
3599
|
+
return () => {
|
|
3600
|
+
el.removeEventListener("dragenter", handleDragEnter);
|
|
3601
|
+
el.removeEventListener("dragleave", handleDragLeave);
|
|
3602
|
+
el.removeEventListener("dragover", handleDragOver);
|
|
3603
|
+
el.removeEventListener("drop", handleDrop);
|
|
3604
|
+
};
|
|
3605
|
+
}, [handleDragEnter, handleDragLeave, handleDragOver, handleDrop]);
|
|
3606
|
+
return { ref, isDragging };
|
|
3607
|
+
}
|
|
3608
|
+
|
|
3609
|
+
// src/hooks/useFileProcessing/useFileProcessing.ts
|
|
3610
|
+
var import_react80 = require("react");
|
|
3611
|
+
function useFileProcessing(options = {}) {
|
|
3612
|
+
const [processing, setProcessing] = (0, import_react80.useState)(false);
|
|
3613
|
+
const [error, setError] = (0, import_react80.useState)(null);
|
|
3614
|
+
const process = (0, import_react80.useCallback)(async (file) => {
|
|
3615
|
+
setProcessing(true);
|
|
3616
|
+
setError(null);
|
|
3617
|
+
try {
|
|
3618
|
+
if (options.limit && file.size > options.limit) {
|
|
3619
|
+
throw new Error("File too large");
|
|
3620
|
+
}
|
|
3621
|
+
const text = await file.text();
|
|
3622
|
+
return text;
|
|
3623
|
+
} catch (err) {
|
|
3624
|
+
setError(err.message);
|
|
3625
|
+
throw err;
|
|
3626
|
+
} finally {
|
|
3627
|
+
setProcessing(false);
|
|
3628
|
+
}
|
|
3629
|
+
}, [options.limit]);
|
|
3630
|
+
return { process, processing, error };
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
// src/hooks/useForm/useForm.ts
|
|
3634
|
+
var import_react81 = require("react");
|
|
3635
|
+
function useForm(options) {
|
|
3636
|
+
const [values, setValues] = (0, import_react81.useState)(options.initialValues);
|
|
3637
|
+
const [errors, setErrors] = (0, import_react81.useState)({});
|
|
3638
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react81.useState)(false);
|
|
3639
|
+
const [touched, setTouched] = (0, import_react81.useState)({});
|
|
3640
|
+
const handleChange = (0, import_react81.useCallback)((e) => {
|
|
3641
|
+
const { name, value, type } = e.target;
|
|
3642
|
+
const val = type === "checkbox" ? e.target.checked : value;
|
|
3643
|
+
setValues((prev) => ({ ...prev, [name]: val }));
|
|
3644
|
+
}, []);
|
|
3645
|
+
const setFieldValue = (0, import_react81.useCallback)((name, value) => {
|
|
3646
|
+
setValues((prev) => ({ ...prev, [name]: value }));
|
|
3647
|
+
}, []);
|
|
3648
|
+
const handleBlur = (0, import_react81.useCallback)((e) => {
|
|
3649
|
+
const { name } = e.target;
|
|
3650
|
+
setTouched((prev) => ({ ...prev, [name]: true }));
|
|
3651
|
+
}, []);
|
|
3652
|
+
const handleSubmit = (0, import_react81.useCallback)(async (e) => {
|
|
3653
|
+
e?.preventDefault();
|
|
3654
|
+
setIsSubmitting(true);
|
|
3655
|
+
setErrors({});
|
|
3656
|
+
if (options.validate) {
|
|
3657
|
+
const validationErrors = await options.validate(values);
|
|
3658
|
+
if (Object.keys(validationErrors).length > 0) {
|
|
3659
|
+
setErrors(validationErrors);
|
|
3660
|
+
setIsSubmitting(false);
|
|
3661
|
+
return;
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
try {
|
|
3665
|
+
await options.onSubmit(values);
|
|
3666
|
+
} catch (err) {
|
|
3667
|
+
} finally {
|
|
3668
|
+
setIsSubmitting(false);
|
|
3669
|
+
}
|
|
3670
|
+
}, [values, options]);
|
|
3671
|
+
return {
|
|
3672
|
+
values,
|
|
3673
|
+
errors,
|
|
3674
|
+
touched,
|
|
3675
|
+
isSubmitting,
|
|
3676
|
+
handleChange,
|
|
3677
|
+
handleBlur,
|
|
3678
|
+
handleSubmit,
|
|
3679
|
+
setFieldValue,
|
|
3680
|
+
setValues
|
|
3681
|
+
// expose for resets
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
// src/hooks/useMarkdown/useMarkdown.ts
|
|
3686
|
+
function useMarkdown() {
|
|
3687
|
+
const compile = (markdown) => {
|
|
3688
|
+
let html = markdown.replace(/^# (.*)/gm, "<h1>$1</h1>").replace(/^## (.*)/gm, "<h2>$1</h2>").replace(/\*\*(.*)\*\*/g, "<b>$1</b>");
|
|
3689
|
+
return html;
|
|
3690
|
+
};
|
|
3691
|
+
return { compile };
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
// src/hooks/usePDF/usePDF.ts
|
|
3695
|
+
var import_react82 = require("react");
|
|
3696
|
+
function usePDF() {
|
|
3697
|
+
const [generating, setGenerating] = (0, import_react82.useState)(false);
|
|
3698
|
+
const generate = (0, import_react82.useCallback)(async (content, filename = "document.pdf") => {
|
|
3699
|
+
setGenerating(true);
|
|
3700
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
3701
|
+
console.log("Generating PDF for:", filename);
|
|
3702
|
+
setGenerating(false);
|
|
3703
|
+
return true;
|
|
3704
|
+
}, []);
|
|
3705
|
+
return { generate, generating };
|
|
3706
|
+
}
|
|
3707
|
+
|
|
3708
|
+
// src/hooks/usePresence/usePresence.ts
|
|
3709
|
+
var import_react83 = require("react");
|
|
3710
|
+
function usePresence(heartbeatInterval = 5e3) {
|
|
3711
|
+
const [lastActive, setLastActive] = (0, import_react83.useState)(Date.now());
|
|
3712
|
+
const [isIdle, setIsIdle] = (0, import_react83.useState)(false);
|
|
3713
|
+
(0, import_react83.useEffect)(() => {
|
|
3714
|
+
const handleActivity = () => {
|
|
3715
|
+
setLastActive(Date.now());
|
|
3716
|
+
if (isIdle) setIsIdle(false);
|
|
3717
|
+
};
|
|
3718
|
+
window.addEventListener("mousemove", handleActivity);
|
|
3719
|
+
window.addEventListener("keydown", handleActivity);
|
|
3720
|
+
const interval = setInterval(() => {
|
|
3721
|
+
if (Date.now() - lastActive > heartbeatInterval * 2) {
|
|
3722
|
+
setIsIdle(true);
|
|
3723
|
+
}
|
|
3724
|
+
}, heartbeatInterval);
|
|
3725
|
+
return () => {
|
|
3726
|
+
window.removeEventListener("mousemove", handleActivity);
|
|
3727
|
+
window.removeEventListener("keydown", handleActivity);
|
|
3728
|
+
clearInterval(interval);
|
|
3729
|
+
};
|
|
3730
|
+
}, [heartbeatInterval, lastActive, isIdle]);
|
|
3731
|
+
return { isIdle, lastActive };
|
|
3732
|
+
}
|
|
3733
|
+
|
|
3734
|
+
// src/hooks/useRealtimeCollab/useRealtimeCollab.ts
|
|
3735
|
+
var import_react84 = require("react");
|
|
3736
|
+
function useRealtimeCollab(userId) {
|
|
3737
|
+
const [events, setEvents] = (0, import_react84.useState)([]);
|
|
3738
|
+
const emit = (0, import_react84.useCallback)((type, payload) => {
|
|
3739
|
+
const event = {
|
|
3740
|
+
type,
|
|
3741
|
+
payload,
|
|
3742
|
+
timestamp: Date.now(),
|
|
3743
|
+
userId
|
|
3744
|
+
};
|
|
3745
|
+
setEvents((prev) => [...prev, event]);
|
|
3746
|
+
}, [userId]);
|
|
3747
|
+
const applyRemote = (0, import_react84.useCallback)((event) => {
|
|
3748
|
+
setEvents((prev) => [...prev, event]);
|
|
3749
|
+
}, []);
|
|
3750
|
+
return { events, emit, applyRemote };
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
// src/hooks/useShortcuts/useShortcuts.ts
|
|
3754
|
+
var import_react85 = require("react");
|
|
3755
|
+
function useShortcuts(shortcuts) {
|
|
3756
|
+
(0, import_react85.useEffect)(() => {
|
|
3757
|
+
const handleKeyDown = (event) => {
|
|
3758
|
+
const parts = [];
|
|
3759
|
+
if (event.ctrlKey) parts.push("Control");
|
|
3760
|
+
if (event.metaKey) parts.push("Meta");
|
|
3761
|
+
if (event.altKey) parts.push("Alt");
|
|
3762
|
+
if (event.shiftKey) parts.push("Shift");
|
|
3763
|
+
if (["Control", "Meta", "Alt", "Shift"].includes(event.key)) {
|
|
3764
|
+
} else {
|
|
3765
|
+
parts.push(event.key);
|
|
3766
|
+
}
|
|
3767
|
+
const combo = parts.join("+");
|
|
3768
|
+
if (shortcuts[combo]) {
|
|
3769
|
+
shortcuts[combo](event);
|
|
3770
|
+
} else if (shortcuts[event.key]) {
|
|
3771
|
+
shortcuts[event.key](event);
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
3775
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3776
|
+
}, [shortcuts]);
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
// src/hooks/useSortable/useSortable.ts
|
|
3780
|
+
var import_react86 = require("react");
|
|
3781
|
+
function useSortable(options) {
|
|
3782
|
+
const [draggedIndex, setDraggedIndex] = (0, import_react86.useState)(null);
|
|
3783
|
+
const move = (0, import_react86.useCallback)((fromIndex, toIndex) => {
|
|
3784
|
+
if (fromIndex === toIndex) return;
|
|
3785
|
+
const newItems = [...options.items];
|
|
3786
|
+
const [removed] = newItems.splice(fromIndex, 1);
|
|
3787
|
+
newItems.splice(toIndex, 0, removed);
|
|
3788
|
+
options.onReorder(newItems);
|
|
3789
|
+
}, [options]);
|
|
3790
|
+
return {
|
|
3791
|
+
draggedIndex,
|
|
3792
|
+
setDraggedIndex,
|
|
3793
|
+
move
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// src/hooks/useSpreadsheet/useSpreadsheet.ts
|
|
3798
|
+
var import_react87 = require("react");
|
|
3799
|
+
function useSpreadsheet(options) {
|
|
3800
|
+
const { rows, cols, initialData } = options;
|
|
3801
|
+
const createGrid = () => {
|
|
3802
|
+
if (initialData) return initialData;
|
|
3803
|
+
return Array.from({ length: rows }, () => Array(cols).fill(null));
|
|
3804
|
+
};
|
|
3805
|
+
const [data, setData] = (0, import_react87.useState)(createGrid);
|
|
3806
|
+
const [selectedCell, setSelectedCell] = (0, import_react87.useState)(null);
|
|
3807
|
+
const setCell = (r, c, value) => {
|
|
3808
|
+
setData((prev) => {
|
|
3809
|
+
const next = [...prev];
|
|
3810
|
+
next[r] = [...next[r]];
|
|
3811
|
+
next[r][c] = value;
|
|
3812
|
+
return next;
|
|
3813
|
+
});
|
|
3814
|
+
};
|
|
3815
|
+
return {
|
|
3816
|
+
data,
|
|
3817
|
+
setCell,
|
|
3818
|
+
selectedCell,
|
|
3819
|
+
setSelectedCell
|
|
3820
|
+
};
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3823
|
+
// src/hooks/useTable/useTable.ts
|
|
3824
|
+
var import_react88 = require("react");
|
|
3825
|
+
function useTable(options) {
|
|
3826
|
+
const [sortConfig, setSortConfig] = (0, import_react88.useState)(
|
|
3827
|
+
options.initialSort || null
|
|
3828
|
+
);
|
|
3829
|
+
const requestSort = (key) => {
|
|
3830
|
+
let direction = "asc";
|
|
3831
|
+
if (sortConfig && sortConfig.key === key && sortConfig.direction === "asc") {
|
|
3832
|
+
direction = "desc";
|
|
3833
|
+
}
|
|
3834
|
+
setSortConfig({ key, direction });
|
|
3835
|
+
};
|
|
3836
|
+
const sortedData = (0, import_react88.useMemo)(() => {
|
|
3837
|
+
const sortableItems = [...options.data];
|
|
3838
|
+
if (sortConfig !== null) {
|
|
3839
|
+
sortableItems.sort((a, b) => {
|
|
3840
|
+
const valA = a[sortConfig.key];
|
|
3841
|
+
const valB = b[sortConfig.key];
|
|
3842
|
+
if (valA < valB) return sortConfig.direction === "asc" ? -1 : 1;
|
|
3843
|
+
if (valA > valB) return sortConfig.direction === "asc" ? 1 : -1;
|
|
3844
|
+
return 0;
|
|
3845
|
+
});
|
|
3846
|
+
}
|
|
3847
|
+
return sortableItems;
|
|
3848
|
+
}, [options.data, sortConfig]);
|
|
3849
|
+
return {
|
|
3850
|
+
items: sortedData,
|
|
3851
|
+
requestSort,
|
|
3852
|
+
sortConfig,
|
|
3853
|
+
columns: options.columns
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
// src/hooks/useWebRTC/useWebRTC.ts
|
|
3858
|
+
var import_react89 = require("react");
|
|
3859
|
+
function useWebRTC(options = {}) {
|
|
3860
|
+
const [connectionState, setConnectionState] = (0, import_react89.useState)("new");
|
|
3861
|
+
const [signalingState, setSignalingState] = (0, import_react89.useState)("stable");
|
|
3862
|
+
const pcRef = (0, import_react89.useRef)(null);
|
|
3863
|
+
(0, import_react89.useEffect)(() => {
|
|
3864
|
+
const pc = new RTCPeerConnection({
|
|
3865
|
+
iceServers: options.iceServers || [{ urls: "stun:stun.l.google.com:19302" }]
|
|
3866
|
+
});
|
|
3867
|
+
pcRef.current = pc;
|
|
3868
|
+
pc.onconnectionstatechange = () => setConnectionState(pc.connectionState);
|
|
3869
|
+
pc.onsignalingstatechange = () => setSignalingState(pc.signalingState);
|
|
3870
|
+
return () => {
|
|
3871
|
+
pc.close();
|
|
3872
|
+
};
|
|
3873
|
+
}, [options.iceServers]);
|
|
3874
|
+
return {
|
|
3875
|
+
pc: pcRef.current,
|
|
3876
|
+
connectionState,
|
|
3877
|
+
signalingState
|
|
3878
|
+
};
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
// src/hooks/useWebSocket/useWebSocket.ts
|
|
3882
|
+
var import_react90 = require("react");
|
|
3883
|
+
function useWebSocket(url, options = {}) {
|
|
3884
|
+
const {
|
|
3885
|
+
reconnect = true,
|
|
3886
|
+
reconnectAttempts = 5,
|
|
3887
|
+
reconnectInterval = 3e3
|
|
3888
|
+
} = options;
|
|
3889
|
+
const [isConnected, setIsConnected] = (0, import_react90.useState)(false);
|
|
3890
|
+
const [lastMessage, setLastMessage] = (0, import_react90.useState)(null);
|
|
3891
|
+
const wsRef = (0, import_react90.useRef)(null);
|
|
3892
|
+
const reconnectCountRef = (0, import_react90.useRef)(0);
|
|
3893
|
+
const reconnectTimerRef = (0, import_react90.useRef)();
|
|
3894
|
+
const connect = (0, import_react90.useCallback)(() => {
|
|
3895
|
+
if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current);
|
|
3896
|
+
const ws = new WebSocket(url);
|
|
3897
|
+
wsRef.current = ws;
|
|
3898
|
+
ws.onopen = (e) => {
|
|
3899
|
+
setIsConnected(true);
|
|
3900
|
+
reconnectCountRef.current = 0;
|
|
3901
|
+
options.onOpen?.(e);
|
|
3902
|
+
};
|
|
3903
|
+
ws.onclose = (e) => {
|
|
3904
|
+
setIsConnected(false);
|
|
3905
|
+
options.onClose?.(e);
|
|
3906
|
+
if (reconnect && reconnectCountRef.current < reconnectAttempts) {
|
|
3907
|
+
reconnectTimerRef.current = setTimeout(() => {
|
|
3908
|
+
reconnectCountRef.current++;
|
|
3909
|
+
connect();
|
|
3910
|
+
}, reconnectInterval);
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
ws.onmessage = (e) => {
|
|
3914
|
+
setLastMessage(e);
|
|
3915
|
+
options.onMessage?.(e);
|
|
3916
|
+
};
|
|
3917
|
+
ws.onerror = (e) => {
|
|
3918
|
+
options.onError?.(e);
|
|
3919
|
+
};
|
|
3920
|
+
}, [url, reconnect, reconnectAttempts, reconnectInterval, options]);
|
|
3921
|
+
(0, import_react90.useEffect)(() => {
|
|
3922
|
+
connect();
|
|
3923
|
+
return () => {
|
|
3924
|
+
if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current);
|
|
3925
|
+
wsRef.current?.close();
|
|
3926
|
+
};
|
|
3927
|
+
}, [connect]);
|
|
3928
|
+
const send = (0, import_react90.useCallback)((data) => {
|
|
3929
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
3930
|
+
wsRef.current.send(data);
|
|
3931
|
+
}
|
|
3932
|
+
}, []);
|
|
3933
|
+
return {
|
|
3934
|
+
send,
|
|
3935
|
+
lastMessage,
|
|
3936
|
+
isConnected,
|
|
3937
|
+
ws: wsRef.current
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
// src/hooks/useClickAnywhere/useClickAnywhere.ts
|
|
3942
|
+
function useClickAnywhere(handler) {
|
|
3943
|
+
useEvent("click", (event) => {
|
|
3944
|
+
handler(event);
|
|
3945
|
+
});
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
// src/hooks/useCountdown/useCountdown.ts
|
|
3949
|
+
var import_react91 = require("react");
|
|
3950
|
+
function useCountdown({
|
|
3951
|
+
countStart,
|
|
3952
|
+
intervalMs = 1e3,
|
|
3953
|
+
isIncrement = false,
|
|
3954
|
+
countStop = 0
|
|
3955
|
+
}) {
|
|
3956
|
+
const [count, setCount] = (0, import_react91.useState)(countStart);
|
|
3957
|
+
const [isRunning, setIsRunning] = (0, import_react91.useState)(false);
|
|
3958
|
+
const intervalRef = (0, import_react91.useRef)(null);
|
|
3959
|
+
const startCountdown = (0, import_react91.useCallback)(() => setIsRunning(true), []);
|
|
3960
|
+
const stopCountdown = (0, import_react91.useCallback)(() => setIsRunning(false), []);
|
|
3961
|
+
const resetCountdown = (0, import_react91.useCallback)(() => {
|
|
3962
|
+
setIsRunning(false);
|
|
3963
|
+
setCount(countStart);
|
|
3964
|
+
}, [countStart]);
|
|
3965
|
+
(0, import_react91.useEffect)(() => {
|
|
3966
|
+
if (!isRunning) {
|
|
3967
|
+
if (intervalRef.current) {
|
|
3968
|
+
clearInterval(intervalRef.current);
|
|
3969
|
+
intervalRef.current = null;
|
|
3970
|
+
}
|
|
3971
|
+
return;
|
|
3972
|
+
}
|
|
3973
|
+
intervalRef.current = setInterval(() => {
|
|
3974
|
+
setCount((prev) => {
|
|
3975
|
+
if (isIncrement) {
|
|
3976
|
+
if (prev < countStop) {
|
|
3977
|
+
return prev + 1;
|
|
3978
|
+
} else {
|
|
3979
|
+
setIsRunning(false);
|
|
3980
|
+
return prev;
|
|
3981
|
+
}
|
|
3982
|
+
} else {
|
|
3983
|
+
if (prev > countStop) {
|
|
3984
|
+
return prev - 1;
|
|
3985
|
+
} else {
|
|
3986
|
+
setIsRunning(false);
|
|
3987
|
+
return prev;
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
});
|
|
3991
|
+
}, intervalMs);
|
|
3992
|
+
return () => {
|
|
3993
|
+
if (intervalRef.current) {
|
|
3994
|
+
clearInterval(intervalRef.current);
|
|
3995
|
+
}
|
|
3996
|
+
};
|
|
3997
|
+
}, [isRunning, intervalMs, isIncrement, countStop]);
|
|
3998
|
+
return { count, startCountdown, stopCountdown, resetCountdown };
|
|
3999
|
+
}
|
|
4000
|
+
|
|
4001
|
+
// src/hooks/useDebounceCallback/useDebounceCallback.ts
|
|
4002
|
+
var import_react92 = require("react");
|
|
4003
|
+
function useDebounceCallback(func, wait = 0, options = {}) {
|
|
4004
|
+
const funcRef = (0, import_react92.useRef)(func);
|
|
4005
|
+
const timeoutRef = (0, import_react92.useRef)();
|
|
4006
|
+
(0, import_react92.useEffect)(() => {
|
|
4007
|
+
funcRef.current = func;
|
|
4008
|
+
}, [func]);
|
|
4009
|
+
const debounced = (0, import_react92.useMemo)(() => {
|
|
4010
|
+
const debouncedFunc = (...args) => {
|
|
4011
|
+
if (timeoutRef.current) {
|
|
4012
|
+
clearTimeout(timeoutRef.current);
|
|
4013
|
+
}
|
|
4014
|
+
timeoutRef.current = setTimeout(() => {
|
|
4015
|
+
funcRef.current(...args);
|
|
4016
|
+
}, wait);
|
|
4017
|
+
};
|
|
4018
|
+
const cancel = () => {
|
|
4019
|
+
if (timeoutRef.current) {
|
|
4020
|
+
clearTimeout(timeoutRef.current);
|
|
4021
|
+
}
|
|
4022
|
+
};
|
|
4023
|
+
const flush = () => {
|
|
4024
|
+
if (timeoutRef.current) {
|
|
4025
|
+
clearTimeout(timeoutRef.current);
|
|
4026
|
+
}
|
|
4027
|
+
};
|
|
4028
|
+
debouncedFunc.cancel = cancel;
|
|
4029
|
+
debouncedFunc.flush = flush;
|
|
4030
|
+
return debouncedFunc;
|
|
4031
|
+
}, [wait]);
|
|
4032
|
+
return debounced;
|
|
4033
|
+
}
|
|
4034
|
+
|
|
4035
|
+
// src/hooks/useIsClient/useIsClient.ts
|
|
4036
|
+
var import_react93 = require("react");
|
|
4037
|
+
function useIsClient() {
|
|
4038
|
+
const [isClient, setIsClient] = (0, import_react93.useState)(false);
|
|
4039
|
+
(0, import_react93.useEffect)(() => {
|
|
4040
|
+
setIsClient(true);
|
|
4041
|
+
}, []);
|
|
4042
|
+
return isClient;
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
// src/hooks/useList/useList.ts
|
|
4046
|
+
var import_react94 = require("react");
|
|
4047
|
+
function useList(initialList = []) {
|
|
4048
|
+
const [list, setList] = (0, import_react94.useState)(initialList);
|
|
4049
|
+
const actions = {
|
|
4050
|
+
set: (0, import_react94.useCallback)((l) => setList(l), []),
|
|
4051
|
+
push: (0, import_react94.useCallback)((element) => setList((l) => [...l, element]), []),
|
|
4052
|
+
updateAt: (0, import_react94.useCallback)(
|
|
4053
|
+
(index, element) => setList((l) => {
|
|
4054
|
+
const m = [...l];
|
|
4055
|
+
m[index] = element;
|
|
4056
|
+
return m;
|
|
4057
|
+
}),
|
|
4058
|
+
[]
|
|
4059
|
+
),
|
|
4060
|
+
insertAt: (0, import_react94.useCallback)(
|
|
4061
|
+
(index, element) => setList((l) => {
|
|
4062
|
+
const m = [...l];
|
|
4063
|
+
m.splice(index, 0, element);
|
|
4064
|
+
return m;
|
|
4065
|
+
}),
|
|
4066
|
+
[]
|
|
4067
|
+
),
|
|
4068
|
+
update: (0, import_react94.useCallback)(
|
|
4069
|
+
(predicate, newElement) => setList((l) => l.map((item) => predicate(item, newElement) ? newElement : item)),
|
|
4070
|
+
[]
|
|
4071
|
+
),
|
|
4072
|
+
removeAt: (0, import_react94.useCallback)(
|
|
4073
|
+
(index) => setList((l) => {
|
|
4074
|
+
const m = [...l];
|
|
4075
|
+
m.splice(index, 1);
|
|
4076
|
+
return m;
|
|
4077
|
+
}),
|
|
4078
|
+
[]
|
|
4079
|
+
),
|
|
4080
|
+
clear: (0, import_react94.useCallback)(() => setList([]), []),
|
|
4081
|
+
reset: (0, import_react94.useCallback)(() => setList(initialList), [initialList])
|
|
4082
|
+
};
|
|
4083
|
+
return [list, actions];
|
|
4084
|
+
}
|
|
4085
|
+
|
|
4086
|
+
// src/hooks/useMap/useMap.ts
|
|
4087
|
+
var import_react95 = require("react");
|
|
4088
|
+
function useMap(initialState = /* @__PURE__ */ new Map()) {
|
|
4089
|
+
const [map, setMap] = (0, import_react95.useState)(new Map(initialState));
|
|
4090
|
+
const actions = {
|
|
4091
|
+
set: (0, import_react95.useCallback)((key, value) => {
|
|
4092
|
+
setMap((prev) => {
|
|
4093
|
+
const copy = new Map(prev);
|
|
4094
|
+
copy.set(key, value);
|
|
4095
|
+
return copy;
|
|
4096
|
+
});
|
|
4097
|
+
}, []),
|
|
4098
|
+
setAll: (0, import_react95.useCallback)((entries) => {
|
|
4099
|
+
setMap(new Map(entries));
|
|
4100
|
+
}, []),
|
|
4101
|
+
remove: (0, import_react95.useCallback)((key) => {
|
|
4102
|
+
setMap((prev) => {
|
|
4103
|
+
const copy = new Map(prev);
|
|
4104
|
+
copy.delete(key);
|
|
4105
|
+
return copy;
|
|
4106
|
+
});
|
|
4107
|
+
}, []),
|
|
4108
|
+
reset: (0, import_react95.useCallback)(() => {
|
|
4109
|
+
setMap(new Map(initialState));
|
|
4110
|
+
}, [initialState])
|
|
4111
|
+
};
|
|
4112
|
+
return [map, actions];
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4115
|
+
// src/hooks/useQueue/useQueue.ts
|
|
4116
|
+
var import_react96 = require("react");
|
|
4117
|
+
function useQueue(initialValue = []) {
|
|
4118
|
+
const [queue, setQueue] = (0, import_react96.useState)(initialValue);
|
|
4119
|
+
const add = (0, import_react96.useCallback)((element) => {
|
|
4120
|
+
setQueue((q) => [...q, element]);
|
|
4121
|
+
}, []);
|
|
4122
|
+
const remove = (0, import_react96.useCallback)(() => {
|
|
4123
|
+
let removedElement;
|
|
4124
|
+
setQueue((q) => {
|
|
4125
|
+
const [first, ...rest] = q;
|
|
4126
|
+
removedElement = first;
|
|
4127
|
+
return rest;
|
|
4128
|
+
});
|
|
4129
|
+
return removedElement;
|
|
4130
|
+
}, []);
|
|
4131
|
+
const clear = (0, import_react96.useCallback)(() => {
|
|
4132
|
+
setQueue([]);
|
|
4133
|
+
}, []);
|
|
4134
|
+
return {
|
|
4135
|
+
queue,
|
|
4136
|
+
add,
|
|
4137
|
+
remove,
|
|
4138
|
+
clear,
|
|
4139
|
+
first: queue[0],
|
|
4140
|
+
last: queue[queue.length - 1],
|
|
4141
|
+
size: queue.length
|
|
4142
|
+
};
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
// src/hooks/useScreen/useScreen.ts
|
|
4146
|
+
var import_react97 = require("react");
|
|
4147
|
+
function useScreen() {
|
|
4148
|
+
const getScreen = () => {
|
|
4149
|
+
if (typeof window !== "undefined" && window.screen) {
|
|
4150
|
+
return window.screen;
|
|
4151
|
+
}
|
|
4152
|
+
return void 0;
|
|
4153
|
+
};
|
|
4154
|
+
const [screen, setScreen] = (0, import_react97.useState)(getScreen());
|
|
4155
|
+
const handleResize = () => {
|
|
4156
|
+
setScreen(getScreen());
|
|
4157
|
+
};
|
|
4158
|
+
useEvent("resize", handleResize);
|
|
4159
|
+
(0, import_react97.useEffect)(() => {
|
|
4160
|
+
setScreen(getScreen());
|
|
4161
|
+
}, []);
|
|
4162
|
+
return screen;
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
// src/hooks/useSet/useSet.ts
|
|
4166
|
+
var import_react98 = require("react");
|
|
4167
|
+
function useSet(initialSet = /* @__PURE__ */ new Set()) {
|
|
4168
|
+
const [set, setSet] = (0, import_react98.useState)(initialSet);
|
|
4169
|
+
const actions = {
|
|
4170
|
+
add: (0, import_react98.useCallback)((key) => {
|
|
4171
|
+
setSet((prev) => {
|
|
4172
|
+
const copy = new Set(prev);
|
|
4173
|
+
copy.add(key);
|
|
4174
|
+
return copy;
|
|
4175
|
+
});
|
|
4176
|
+
}, []),
|
|
4177
|
+
remove: (0, import_react98.useCallback)((key) => {
|
|
4178
|
+
setSet((prev) => {
|
|
4179
|
+
const copy = new Set(prev);
|
|
4180
|
+
copy.delete(key);
|
|
4181
|
+
return copy;
|
|
4182
|
+
});
|
|
4183
|
+
}, []),
|
|
4184
|
+
toggle: (0, import_react98.useCallback)((key) => {
|
|
4185
|
+
setSet((prev) => {
|
|
4186
|
+
const copy = new Set(prev);
|
|
4187
|
+
if (copy.has(key)) {
|
|
4188
|
+
copy.delete(key);
|
|
4189
|
+
} else {
|
|
4190
|
+
copy.add(key);
|
|
4191
|
+
}
|
|
4192
|
+
return copy;
|
|
4193
|
+
});
|
|
4194
|
+
}, []),
|
|
4195
|
+
reset: (0, import_react98.useCallback)(() => {
|
|
4196
|
+
setSet(initialSet);
|
|
4197
|
+
}, [initialSet]),
|
|
4198
|
+
clear: (0, import_react98.useCallback)(() => {
|
|
4199
|
+
setSet(/* @__PURE__ */ new Set());
|
|
4200
|
+
}, [])
|
|
4201
|
+
};
|
|
4202
|
+
return [set, actions];
|
|
4203
|
+
}
|
|
33
4204
|
// Annotate the CommonJS export names for ESM import in node:
|
|
34
4205
|
0 && (module.exports = {
|
|
35
|
-
|
|
4206
|
+
isBrowser,
|
|
4207
|
+
isServer,
|
|
4208
|
+
noop,
|
|
4209
|
+
useAnimate,
|
|
4210
|
+
useAnthropic,
|
|
4211
|
+
useAsync,
|
|
4212
|
+
useAudioRef,
|
|
4213
|
+
useBattery,
|
|
4214
|
+
useBluetooth,
|
|
4215
|
+
useBroadcastChannel,
|
|
4216
|
+
useCalendar,
|
|
4217
|
+
useCanvas,
|
|
4218
|
+
useClickAnywhere,
|
|
4219
|
+
useClickOutside,
|
|
4220
|
+
useCopyToClipboard,
|
|
4221
|
+
useCountdown,
|
|
4222
|
+
useCounter,
|
|
4223
|
+
useDebounce,
|
|
4224
|
+
useDebounceCallback,
|
|
4225
|
+
useDocumentTitle,
|
|
4226
|
+
useDragAndDrop,
|
|
4227
|
+
useEmbeddings,
|
|
4228
|
+
useEvent,
|
|
4229
|
+
useEyeDropper,
|
|
4230
|
+
useFetch,
|
|
4231
|
+
useFileProcessing,
|
|
4232
|
+
useFileSystem,
|
|
4233
|
+
useForm,
|
|
4234
|
+
useFrameRate,
|
|
4235
|
+
useFullscreen,
|
|
4236
|
+
useGamepad,
|
|
4237
|
+
useGemini,
|
|
4238
|
+
useHistory,
|
|
4239
|
+
useHover,
|
|
4240
|
+
useIndexedDB,
|
|
4241
|
+
useInfiniteScroll,
|
|
4242
|
+
useIntersection,
|
|
4243
|
+
useInterval,
|
|
4244
|
+
useIsClient,
|
|
4245
|
+
useIsMounted,
|
|
4246
|
+
useIsomorphicLayoutEffect,
|
|
4247
|
+
useKeyPress,
|
|
4248
|
+
useLLMStream,
|
|
4249
|
+
useList,
|
|
4250
|
+
useLocalStorage,
|
|
4251
|
+
useLockBodyScroll,
|
|
4252
|
+
useLongPress,
|
|
4253
|
+
useLottie,
|
|
4254
|
+
useMachine,
|
|
4255
|
+
useMap,
|
|
4256
|
+
useMarkdown,
|
|
4257
|
+
useMediaDevices,
|
|
4258
|
+
useMediaQuery,
|
|
4259
|
+
useMediaRecorder,
|
|
4260
|
+
useMount,
|
|
4261
|
+
useMutationObserver,
|
|
4262
|
+
useNetworkState,
|
|
4263
|
+
useOnline,
|
|
4264
|
+
useOpenAI,
|
|
4265
|
+
usePDF,
|
|
4266
|
+
usePageLeave,
|
|
4267
|
+
usePagination,
|
|
4268
|
+
useParallax,
|
|
4269
|
+
usePermissions,
|
|
4270
|
+
usePresence,
|
|
4271
|
+
usePrevious,
|
|
4272
|
+
useQueue,
|
|
4273
|
+
useRAG,
|
|
4274
|
+
useRealtimeCollab,
|
|
4275
|
+
useResizeObserver,
|
|
4276
|
+
useSTT,
|
|
4277
|
+
useSVGAnimation,
|
|
4278
|
+
useScreen,
|
|
4279
|
+
useScript,
|
|
4280
|
+
useScroll,
|
|
4281
|
+
useSearchHighlight,
|
|
4282
|
+
useSemanticSearch,
|
|
4283
|
+
useSessionStorage,
|
|
4284
|
+
useSet,
|
|
4285
|
+
useShare,
|
|
4286
|
+
useShortcuts,
|
|
4287
|
+
useSortable,
|
|
4288
|
+
useSpreadsheet,
|
|
4289
|
+
useSpringCore,
|
|
4290
|
+
useStableCallback,
|
|
4291
|
+
useStep,
|
|
4292
|
+
useStorageEstimate,
|
|
4293
|
+
useTTS,
|
|
4294
|
+
useTable,
|
|
4295
|
+
useTheme,
|
|
4296
|
+
useThreeJS,
|
|
4297
|
+
useThrottle,
|
|
4298
|
+
useTimeout,
|
|
4299
|
+
useToggle,
|
|
4300
|
+
useUnmount,
|
|
4301
|
+
useUpdateEffect,
|
|
4302
|
+
useVideoRef,
|
|
4303
|
+
useVirtualList,
|
|
4304
|
+
useWakeLock,
|
|
4305
|
+
useWebRTC,
|
|
4306
|
+
useWebSocket,
|
|
4307
|
+
useWindowFocus,
|
|
4308
|
+
useWindowSize,
|
|
4309
|
+
useWorker
|
|
36
4310
|
});
|
|
4311
|
+
/**
|
|
4312
|
+
* Hookery - A collection of high-quality React hooks
|
|
4313
|
+
* @version 0.0.1
|
|
4314
|
+
* @license MIT
|
|
4315
|
+
*/
|
|
4316
|
+
//# sourceMappingURL=index.js.map
|