@mohasinac/react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +758 -0
- package/dist/index.d.cts +366 -0
- package/dist/index.d.ts +366 -0
- package/dist/index.js +722 -0
- package/package.json +36 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
useBreakpoint: () => useBreakpoint,
|
|
24
|
+
useCamera: () => useCamera,
|
|
25
|
+
useClickOutside: () => useClickOutside,
|
|
26
|
+
useCountdown: () => useCountdown,
|
|
27
|
+
useGesture: () => useGesture,
|
|
28
|
+
useKeyPress: () => useKeyPress,
|
|
29
|
+
useLongPress: () => useLongPress,
|
|
30
|
+
useMediaQuery: () => useMediaQuery,
|
|
31
|
+
usePullToRefresh: () => usePullToRefresh,
|
|
32
|
+
useSwipe: () => useSwipe
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/hooks/useMediaQuery.ts
|
|
37
|
+
var import_react = require("react");
|
|
38
|
+
function useMediaQuery(query) {
|
|
39
|
+
const [matches, setMatches] = (0, import_react.useState)(
|
|
40
|
+
// Lazy initializer: use real value on first client render, suppressing the flash.
|
|
41
|
+
// Returns false on server (no window) — consistent with no-match default.
|
|
42
|
+
() => typeof window !== "undefined" && window.matchMedia(query).matches
|
|
43
|
+
);
|
|
44
|
+
(0, import_react.useEffect)(() => {
|
|
45
|
+
if (typeof window === "undefined") return;
|
|
46
|
+
const media = window.matchMedia(query);
|
|
47
|
+
setMatches(media.matches);
|
|
48
|
+
const listener = (e) => setMatches(e.matches);
|
|
49
|
+
media.addEventListener("change", listener);
|
|
50
|
+
return () => media.removeEventListener("change", listener);
|
|
51
|
+
}, [query]);
|
|
52
|
+
return matches;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/hooks/useBreakpoint.ts
|
|
56
|
+
function useBreakpoint() {
|
|
57
|
+
const isMobile = useMediaQuery("(max-width: 767px)");
|
|
58
|
+
const isTablet = useMediaQuery("(min-width: 768px) and (max-width: 1023px)");
|
|
59
|
+
const isDesktop = useMediaQuery("(min-width: 1024px)");
|
|
60
|
+
const breakpoint = isMobile ? "mobile" : isTablet ? "tablet" : "desktop";
|
|
61
|
+
return {
|
|
62
|
+
isMobile,
|
|
63
|
+
isTablet,
|
|
64
|
+
isDesktop,
|
|
65
|
+
breakpoint
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/hooks/useClickOutside.ts
|
|
70
|
+
var import_react2 = require("react");
|
|
71
|
+
var EMPTY_REFS = [];
|
|
72
|
+
function useClickOutside(ref, callback, options = {}) {
|
|
73
|
+
const {
|
|
74
|
+
enabled = true,
|
|
75
|
+
eventType = "mousedown",
|
|
76
|
+
additionalRefs = EMPTY_REFS
|
|
77
|
+
} = options;
|
|
78
|
+
const callbackRef = (0, import_react2.useRef)(callback);
|
|
79
|
+
(0, import_react2.useEffect)(() => {
|
|
80
|
+
callbackRef.current = callback;
|
|
81
|
+
}, [callback]);
|
|
82
|
+
(0, import_react2.useEffect)(() => {
|
|
83
|
+
if (!enabled) return;
|
|
84
|
+
const handleClickOutside = (event) => {
|
|
85
|
+
if (ref.current && !ref.current.contains(event.target)) {
|
|
86
|
+
const isOutsideAll = additionalRefs.every(
|
|
87
|
+
(additionalRef) => !additionalRef.current || !additionalRef.current.contains(event.target)
|
|
88
|
+
);
|
|
89
|
+
if (isOutsideAll) {
|
|
90
|
+
callbackRef.current(event);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
document.addEventListener(eventType, handleClickOutside);
|
|
95
|
+
document.addEventListener("touchstart", handleClickOutside);
|
|
96
|
+
return () => {
|
|
97
|
+
document.removeEventListener(eventType, handleClickOutside);
|
|
98
|
+
document.removeEventListener("touchstart", handleClickOutside);
|
|
99
|
+
};
|
|
100
|
+
}, [ref, enabled, eventType, additionalRefs]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/hooks/useKeyPress.ts
|
|
104
|
+
var import_react3 = require("react");
|
|
105
|
+
function useKeyPress(key, callback, options = {}) {
|
|
106
|
+
const {
|
|
107
|
+
enabled = true,
|
|
108
|
+
eventType = "keydown",
|
|
109
|
+
preventDefault = false,
|
|
110
|
+
ctrl = false,
|
|
111
|
+
shift = false,
|
|
112
|
+
alt = false,
|
|
113
|
+
meta = false,
|
|
114
|
+
target = typeof document !== "undefined" ? document : null
|
|
115
|
+
} = options;
|
|
116
|
+
const keys = (0, import_react3.useMemo)(() => Array.isArray(key) ? key : [key], [key]);
|
|
117
|
+
const callbackRef = (0, import_react3.useRef)(callback);
|
|
118
|
+
(0, import_react3.useEffect)(() => {
|
|
119
|
+
callbackRef.current = callback;
|
|
120
|
+
}, [callback]);
|
|
121
|
+
const handleKeyPress = (0, import_react3.useCallback)(
|
|
122
|
+
(event) => {
|
|
123
|
+
const isKeyMatch = keys.some((k) => event.key === k || event.code === k);
|
|
124
|
+
if (!isKeyMatch) return;
|
|
125
|
+
const modifiersMatch = event.ctrlKey === ctrl && event.shiftKey === shift && event.altKey === alt && event.metaKey === meta;
|
|
126
|
+
if (!modifiersMatch) return;
|
|
127
|
+
if (preventDefault) {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
}
|
|
130
|
+
callbackRef.current(event);
|
|
131
|
+
},
|
|
132
|
+
[keys, ctrl, shift, alt, meta, preventDefault]
|
|
133
|
+
);
|
|
134
|
+
(0, import_react3.useEffect)(() => {
|
|
135
|
+
if (!enabled || !target) return;
|
|
136
|
+
target.addEventListener(eventType, handleKeyPress);
|
|
137
|
+
return () => {
|
|
138
|
+
target.removeEventListener(eventType, handleKeyPress);
|
|
139
|
+
};
|
|
140
|
+
}, [enabled, eventType, handleKeyPress, target]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/hooks/useLongPress.ts
|
|
144
|
+
var import_react4 = require("react");
|
|
145
|
+
function useLongPress(callback, ms = 500) {
|
|
146
|
+
const timerRef = (0, import_react4.useRef)(null);
|
|
147
|
+
const callbackRef = (0, import_react4.useRef)(callback);
|
|
148
|
+
(0, import_react4.useEffect)(() => {
|
|
149
|
+
callbackRef.current = callback;
|
|
150
|
+
}, [callback]);
|
|
151
|
+
const start = (0, import_react4.useCallback)(() => {
|
|
152
|
+
timerRef.current = setTimeout(() => {
|
|
153
|
+
callbackRef.current();
|
|
154
|
+
}, ms);
|
|
155
|
+
}, [ms]);
|
|
156
|
+
const cancel = (0, import_react4.useCallback)(() => {
|
|
157
|
+
if (timerRef.current !== null) {
|
|
158
|
+
clearTimeout(timerRef.current);
|
|
159
|
+
timerRef.current = null;
|
|
160
|
+
}
|
|
161
|
+
}, []);
|
|
162
|
+
(0, import_react4.useEffect)(() => {
|
|
163
|
+
return () => {
|
|
164
|
+
if (timerRef.current !== null) {
|
|
165
|
+
clearTimeout(timerRef.current);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}, []);
|
|
169
|
+
return {
|
|
170
|
+
onMouseDown: start,
|
|
171
|
+
onMouseUp: cancel,
|
|
172
|
+
onMouseLeave: cancel,
|
|
173
|
+
onTouchStart: start,
|
|
174
|
+
onTouchEnd: cancel
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/hooks/useGesture.ts
|
|
179
|
+
var import_react5 = require("react");
|
|
180
|
+
function useGesture(ref, options = {}) {
|
|
181
|
+
const {
|
|
182
|
+
onTap,
|
|
183
|
+
onDoubleTap,
|
|
184
|
+
onPinch,
|
|
185
|
+
onPinching,
|
|
186
|
+
onRotate,
|
|
187
|
+
onRotating,
|
|
188
|
+
doubleTapDelay = 300,
|
|
189
|
+
tapMovementThreshold = 10,
|
|
190
|
+
preventDefault = false
|
|
191
|
+
} = options;
|
|
192
|
+
const touchStartRef = (0, import_react5.useRef)(
|
|
193
|
+
null
|
|
194
|
+
);
|
|
195
|
+
const lastTapRef = (0, import_react5.useRef)(0);
|
|
196
|
+
const initialPinchDistanceRef = (0, import_react5.useRef)(0);
|
|
197
|
+
const initialRotationRef = (0, import_react5.useRef)(0);
|
|
198
|
+
const onTapRef = (0, import_react5.useRef)(onTap);
|
|
199
|
+
const onDoubleTapRef = (0, import_react5.useRef)(onDoubleTap);
|
|
200
|
+
const onPinchRef = (0, import_react5.useRef)(onPinch);
|
|
201
|
+
const onPinchingRef = (0, import_react5.useRef)(onPinching);
|
|
202
|
+
const onRotateRef = (0, import_react5.useRef)(onRotate);
|
|
203
|
+
const onRotatingRef = (0, import_react5.useRef)(onRotating);
|
|
204
|
+
(0, import_react5.useEffect)(() => {
|
|
205
|
+
onTapRef.current = onTap;
|
|
206
|
+
}, [onTap]);
|
|
207
|
+
(0, import_react5.useEffect)(() => {
|
|
208
|
+
onDoubleTapRef.current = onDoubleTap;
|
|
209
|
+
}, [onDoubleTap]);
|
|
210
|
+
(0, import_react5.useEffect)(() => {
|
|
211
|
+
onPinchRef.current = onPinch;
|
|
212
|
+
}, [onPinch]);
|
|
213
|
+
(0, import_react5.useEffect)(() => {
|
|
214
|
+
onPinchingRef.current = onPinching;
|
|
215
|
+
}, [onPinching]);
|
|
216
|
+
(0, import_react5.useEffect)(() => {
|
|
217
|
+
onRotateRef.current = onRotate;
|
|
218
|
+
}, [onRotate]);
|
|
219
|
+
(0, import_react5.useEffect)(() => {
|
|
220
|
+
onRotatingRef.current = onRotating;
|
|
221
|
+
}, [onRotating]);
|
|
222
|
+
(0, import_react5.useEffect)(() => {
|
|
223
|
+
const element = ref.current;
|
|
224
|
+
if (!element) return;
|
|
225
|
+
const getDistance = (touch1, touch2) => {
|
|
226
|
+
const dx = touch1.clientX - touch2.clientX;
|
|
227
|
+
const dy = touch1.clientY - touch2.clientY;
|
|
228
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
229
|
+
};
|
|
230
|
+
const getAngle = (touch1, touch2) => {
|
|
231
|
+
const dx = touch1.clientX - touch2.clientX;
|
|
232
|
+
const dy = touch1.clientY - touch2.clientY;
|
|
233
|
+
return Math.atan2(dy, dx) * (180 / Math.PI);
|
|
234
|
+
};
|
|
235
|
+
const handleTouchStart = (e) => {
|
|
236
|
+
if (preventDefault) e.preventDefault();
|
|
237
|
+
const touch = e.touches[0];
|
|
238
|
+
touchStartRef.current = {
|
|
239
|
+
x: touch.clientX,
|
|
240
|
+
y: touch.clientY,
|
|
241
|
+
time: Date.now()
|
|
242
|
+
};
|
|
243
|
+
if (e.touches.length === 2) {
|
|
244
|
+
initialPinchDistanceRef.current = getDistance(
|
|
245
|
+
e.touches[0],
|
|
246
|
+
e.touches[1]
|
|
247
|
+
);
|
|
248
|
+
initialRotationRef.current = getAngle(e.touches[0], e.touches[1]);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const handleTouchMove = (e) => {
|
|
252
|
+
var _a, _b;
|
|
253
|
+
if (!touchStartRef.current) return;
|
|
254
|
+
if (e.touches.length === 2 && (onPinchRef.current || onPinchingRef.current || onRotateRef.current || onRotatingRef.current)) {
|
|
255
|
+
if (preventDefault) e.preventDefault();
|
|
256
|
+
const currentDistance = getDistance(e.touches[0], e.touches[1]);
|
|
257
|
+
const currentAngle = getAngle(e.touches[0], e.touches[1]);
|
|
258
|
+
if (initialPinchDistanceRef.current > 0) {
|
|
259
|
+
(_a = onPinchingRef.current) == null ? void 0 : _a.call(
|
|
260
|
+
onPinchingRef,
|
|
261
|
+
currentDistance / initialPinchDistanceRef.current
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
if (initialRotationRef.current !== 0) {
|
|
265
|
+
(_b = onRotatingRef.current) == null ? void 0 : _b.call(onRotatingRef, currentAngle - initialRotationRef.current);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
const handleTouchEnd = (e) => {
|
|
270
|
+
var _a, _b, _c;
|
|
271
|
+
if (!touchStartRef.current) return;
|
|
272
|
+
if (preventDefault) e.preventDefault();
|
|
273
|
+
const touch = e.changedTouches[0];
|
|
274
|
+
const deltaX = Math.abs(touch.clientX - touchStartRef.current.x);
|
|
275
|
+
const deltaY = Math.abs(touch.clientY - touchStartRef.current.y);
|
|
276
|
+
if (deltaX < tapMovementThreshold && deltaY < tapMovementThreshold) {
|
|
277
|
+
const now = Date.now();
|
|
278
|
+
const timeSinceLastTap = now - lastTapRef.current;
|
|
279
|
+
if (onDoubleTapRef.current && timeSinceLastTap < doubleTapDelay) {
|
|
280
|
+
onDoubleTapRef.current(
|
|
281
|
+
touchStartRef.current.x,
|
|
282
|
+
touchStartRef.current.y
|
|
283
|
+
);
|
|
284
|
+
lastTapRef.current = 0;
|
|
285
|
+
} else {
|
|
286
|
+
(_a = onTapRef.current) == null ? void 0 : _a.call(onTapRef, touchStartRef.current.x, touchStartRef.current.y);
|
|
287
|
+
lastTapRef.current = now;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (e.touches.length === 0 && initialPinchDistanceRef.current > 0) {
|
|
291
|
+
const currentDistance = getDistance(
|
|
292
|
+
e.changedTouches[0],
|
|
293
|
+
e.changedTouches[1] || e.changedTouches[0]
|
|
294
|
+
);
|
|
295
|
+
(_b = onPinchRef.current) == null ? void 0 : _b.call(
|
|
296
|
+
onPinchRef,
|
|
297
|
+
currentDistance / initialPinchDistanceRef.current,
|
|
298
|
+
currentDistance
|
|
299
|
+
);
|
|
300
|
+
initialPinchDistanceRef.current = 0;
|
|
301
|
+
}
|
|
302
|
+
if (e.touches.length === 0 && initialRotationRef.current !== 0) {
|
|
303
|
+
const currentAngle = getAngle(
|
|
304
|
+
e.changedTouches[0],
|
|
305
|
+
e.changedTouches[1] || e.changedTouches[0]
|
|
306
|
+
);
|
|
307
|
+
(_c = onRotateRef.current) == null ? void 0 : _c.call(onRotateRef, currentAngle - initialRotationRef.current);
|
|
308
|
+
initialRotationRef.current = 0;
|
|
309
|
+
}
|
|
310
|
+
touchStartRef.current = null;
|
|
311
|
+
};
|
|
312
|
+
const handleMouseDown = (e) => {
|
|
313
|
+
if (preventDefault) e.preventDefault();
|
|
314
|
+
touchStartRef.current = { x: e.clientX, y: e.clientY, time: Date.now() };
|
|
315
|
+
};
|
|
316
|
+
const handleMouseUp = (e) => {
|
|
317
|
+
var _a;
|
|
318
|
+
if (!touchStartRef.current) return;
|
|
319
|
+
if (preventDefault) e.preventDefault();
|
|
320
|
+
const deltaX = Math.abs(e.clientX - touchStartRef.current.x);
|
|
321
|
+
const deltaY = Math.abs(e.clientY - touchStartRef.current.y);
|
|
322
|
+
if (deltaX < tapMovementThreshold && deltaY < tapMovementThreshold) {
|
|
323
|
+
const now = Date.now();
|
|
324
|
+
const timeSinceLastTap = now - lastTapRef.current;
|
|
325
|
+
if (onDoubleTapRef.current && timeSinceLastTap < doubleTapDelay) {
|
|
326
|
+
onDoubleTapRef.current(
|
|
327
|
+
touchStartRef.current.x,
|
|
328
|
+
touchStartRef.current.y
|
|
329
|
+
);
|
|
330
|
+
lastTapRef.current = 0;
|
|
331
|
+
} else {
|
|
332
|
+
(_a = onTapRef.current) == null ? void 0 : _a.call(onTapRef, touchStartRef.current.x, touchStartRef.current.y);
|
|
333
|
+
lastTapRef.current = now;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
touchStartRef.current = null;
|
|
337
|
+
};
|
|
338
|
+
element.addEventListener("touchstart", handleTouchStart, {
|
|
339
|
+
passive: !preventDefault
|
|
340
|
+
});
|
|
341
|
+
element.addEventListener("touchmove", handleTouchMove, {
|
|
342
|
+
passive: !preventDefault
|
|
343
|
+
});
|
|
344
|
+
element.addEventListener("touchend", handleTouchEnd, {
|
|
345
|
+
passive: !preventDefault
|
|
346
|
+
});
|
|
347
|
+
element.addEventListener("mousedown", handleMouseDown);
|
|
348
|
+
element.addEventListener("mouseup", handleMouseUp);
|
|
349
|
+
return () => {
|
|
350
|
+
element.removeEventListener("touchstart", handleTouchStart);
|
|
351
|
+
element.removeEventListener("touchmove", handleTouchMove);
|
|
352
|
+
element.removeEventListener("touchend", handleTouchEnd);
|
|
353
|
+
element.removeEventListener("mousedown", handleMouseDown);
|
|
354
|
+
element.removeEventListener("mouseup", handleMouseUp);
|
|
355
|
+
};
|
|
356
|
+
}, [ref, doubleTapDelay, tapMovementThreshold, preventDefault]);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/hooks/useSwipe.ts
|
|
360
|
+
var import_react6 = require("react");
|
|
361
|
+
function useSwipe(ref, options = {}) {
|
|
362
|
+
const {
|
|
363
|
+
minSwipeDistance = 50,
|
|
364
|
+
maxSwipeTime = 300,
|
|
365
|
+
velocityThreshold = 0.3,
|
|
366
|
+
onSwipe,
|
|
367
|
+
onSwipeLeft,
|
|
368
|
+
onSwipeRight,
|
|
369
|
+
onSwipeUp,
|
|
370
|
+
onSwipeDown,
|
|
371
|
+
onSwiping,
|
|
372
|
+
onSwipeStart,
|
|
373
|
+
onSwipeEnd,
|
|
374
|
+
preventDefault = false
|
|
375
|
+
} = options;
|
|
376
|
+
const touchStartRef = (0, import_react6.useRef)(
|
|
377
|
+
null
|
|
378
|
+
);
|
|
379
|
+
const isSwiping = (0, import_react6.useRef)(false);
|
|
380
|
+
const onSwipeRef = (0, import_react6.useRef)(onSwipe);
|
|
381
|
+
const onSwipeLeftRef = (0, import_react6.useRef)(onSwipeLeft);
|
|
382
|
+
const onSwipeRightRef = (0, import_react6.useRef)(onSwipeRight);
|
|
383
|
+
const onSwipeUpRef = (0, import_react6.useRef)(onSwipeUp);
|
|
384
|
+
const onSwipeDownRef = (0, import_react6.useRef)(onSwipeDown);
|
|
385
|
+
const onSwipingRef = (0, import_react6.useRef)(onSwiping);
|
|
386
|
+
const onSwipeStartRef = (0, import_react6.useRef)(onSwipeStart);
|
|
387
|
+
const onSwipeEndRef = (0, import_react6.useRef)(onSwipeEnd);
|
|
388
|
+
(0, import_react6.useEffect)(() => {
|
|
389
|
+
onSwipeRef.current = onSwipe;
|
|
390
|
+
}, [onSwipe]);
|
|
391
|
+
(0, import_react6.useEffect)(() => {
|
|
392
|
+
onSwipeLeftRef.current = onSwipeLeft;
|
|
393
|
+
}, [onSwipeLeft]);
|
|
394
|
+
(0, import_react6.useEffect)(() => {
|
|
395
|
+
onSwipeRightRef.current = onSwipeRight;
|
|
396
|
+
}, [onSwipeRight]);
|
|
397
|
+
(0, import_react6.useEffect)(() => {
|
|
398
|
+
onSwipeUpRef.current = onSwipeUp;
|
|
399
|
+
}, [onSwipeUp]);
|
|
400
|
+
(0, import_react6.useEffect)(() => {
|
|
401
|
+
onSwipeDownRef.current = onSwipeDown;
|
|
402
|
+
}, [onSwipeDown]);
|
|
403
|
+
(0, import_react6.useEffect)(() => {
|
|
404
|
+
onSwipingRef.current = onSwiping;
|
|
405
|
+
}, [onSwiping]);
|
|
406
|
+
(0, import_react6.useEffect)(() => {
|
|
407
|
+
onSwipeStartRef.current = onSwipeStart;
|
|
408
|
+
}, [onSwipeStart]);
|
|
409
|
+
(0, import_react6.useEffect)(() => {
|
|
410
|
+
onSwipeEndRef.current = onSwipeEnd;
|
|
411
|
+
}, [onSwipeEnd]);
|
|
412
|
+
(0, import_react6.useEffect)(() => {
|
|
413
|
+
const element = ref.current;
|
|
414
|
+
if (!element) return;
|
|
415
|
+
const processSwipe = (deltaX, deltaY, deltaTime) => {
|
|
416
|
+
var _a, _b, _c, _d, _e;
|
|
417
|
+
const absX = Math.abs(deltaX);
|
|
418
|
+
const absY = Math.abs(deltaY);
|
|
419
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
420
|
+
const velocity = distance / deltaTime;
|
|
421
|
+
if (distance < minSwipeDistance || deltaTime > maxSwipeTime || velocity < velocityThreshold)
|
|
422
|
+
return;
|
|
423
|
+
let direction;
|
|
424
|
+
if (absX > absY) {
|
|
425
|
+
direction = deltaX > 0 ? "right" : "left";
|
|
426
|
+
if (direction === "left") (_a = onSwipeLeftRef.current) == null ? void 0 : _a.call(onSwipeLeftRef, distance, velocity);
|
|
427
|
+
else (_b = onSwipeRightRef.current) == null ? void 0 : _b.call(onSwipeRightRef, distance, velocity);
|
|
428
|
+
} else {
|
|
429
|
+
direction = deltaY > 0 ? "down" : "up";
|
|
430
|
+
if (direction === "up") (_c = onSwipeUpRef.current) == null ? void 0 : _c.call(onSwipeUpRef, distance, velocity);
|
|
431
|
+
else (_d = onSwipeDownRef.current) == null ? void 0 : _d.call(onSwipeDownRef, distance, velocity);
|
|
432
|
+
}
|
|
433
|
+
(_e = onSwipeRef.current) == null ? void 0 : _e.call(onSwipeRef, direction, distance, velocity);
|
|
434
|
+
};
|
|
435
|
+
const handleTouchStart = (e) => {
|
|
436
|
+
var _a;
|
|
437
|
+
if (preventDefault) e.preventDefault();
|
|
438
|
+
const touch = e.touches[0];
|
|
439
|
+
touchStartRef.current = {
|
|
440
|
+
x: touch.clientX,
|
|
441
|
+
y: touch.clientY,
|
|
442
|
+
time: Date.now()
|
|
443
|
+
};
|
|
444
|
+
isSwiping.current = true;
|
|
445
|
+
(_a = onSwipeStartRef.current) == null ? void 0 : _a.call(onSwipeStartRef);
|
|
446
|
+
};
|
|
447
|
+
const handleTouchMove = (e) => {
|
|
448
|
+
var _a;
|
|
449
|
+
if (!touchStartRef.current || !isSwiping.current) return;
|
|
450
|
+
if (preventDefault) e.preventDefault();
|
|
451
|
+
(_a = onSwipingRef.current) == null ? void 0 : _a.call(
|
|
452
|
+
onSwipingRef,
|
|
453
|
+
e.touches[0].clientX - touchStartRef.current.x,
|
|
454
|
+
e.touches[0].clientY - touchStartRef.current.y
|
|
455
|
+
);
|
|
456
|
+
};
|
|
457
|
+
const handleTouchEnd = (e) => {
|
|
458
|
+
var _a;
|
|
459
|
+
if (!touchStartRef.current || !isSwiping.current) return;
|
|
460
|
+
if (preventDefault) e.preventDefault();
|
|
461
|
+
const touch = e.changedTouches[0];
|
|
462
|
+
processSwipe(
|
|
463
|
+
touch.clientX - touchStartRef.current.x,
|
|
464
|
+
touch.clientY - touchStartRef.current.y,
|
|
465
|
+
Date.now() - touchStartRef.current.time
|
|
466
|
+
);
|
|
467
|
+
touchStartRef.current = null;
|
|
468
|
+
isSwiping.current = false;
|
|
469
|
+
(_a = onSwipeEndRef.current) == null ? void 0 : _a.call(onSwipeEndRef);
|
|
470
|
+
};
|
|
471
|
+
const handleMouseDown = (e) => {
|
|
472
|
+
var _a;
|
|
473
|
+
if (preventDefault) e.preventDefault();
|
|
474
|
+
touchStartRef.current = { x: e.clientX, y: e.clientY, time: Date.now() };
|
|
475
|
+
isSwiping.current = true;
|
|
476
|
+
(_a = onSwipeStartRef.current) == null ? void 0 : _a.call(onSwipeStartRef);
|
|
477
|
+
};
|
|
478
|
+
const handleMouseMove = (e) => {
|
|
479
|
+
var _a;
|
|
480
|
+
if (!touchStartRef.current || !isSwiping.current) return;
|
|
481
|
+
(_a = onSwipingRef.current) == null ? void 0 : _a.call(
|
|
482
|
+
onSwipingRef,
|
|
483
|
+
e.clientX - touchStartRef.current.x,
|
|
484
|
+
e.clientY - touchStartRef.current.y
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
const handleMouseUp = (e) => {
|
|
488
|
+
var _a;
|
|
489
|
+
if (!touchStartRef.current || !isSwiping.current) return;
|
|
490
|
+
if (preventDefault) e.preventDefault();
|
|
491
|
+
processSwipe(
|
|
492
|
+
e.clientX - touchStartRef.current.x,
|
|
493
|
+
e.clientY - touchStartRef.current.y,
|
|
494
|
+
Date.now() - touchStartRef.current.time
|
|
495
|
+
);
|
|
496
|
+
touchStartRef.current = null;
|
|
497
|
+
isSwiping.current = false;
|
|
498
|
+
(_a = onSwipeEndRef.current) == null ? void 0 : _a.call(onSwipeEndRef);
|
|
499
|
+
};
|
|
500
|
+
element.addEventListener("touchstart", handleTouchStart, {
|
|
501
|
+
passive: !preventDefault
|
|
502
|
+
});
|
|
503
|
+
element.addEventListener("touchmove", handleTouchMove, {
|
|
504
|
+
passive: !preventDefault
|
|
505
|
+
});
|
|
506
|
+
element.addEventListener("touchend", handleTouchEnd, {
|
|
507
|
+
passive: !preventDefault
|
|
508
|
+
});
|
|
509
|
+
element.addEventListener("mousedown", handleMouseDown);
|
|
510
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
511
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
512
|
+
return () => {
|
|
513
|
+
element.removeEventListener("touchstart", handleTouchStart);
|
|
514
|
+
element.removeEventListener("touchmove", handleTouchMove);
|
|
515
|
+
element.removeEventListener("touchend", handleTouchEnd);
|
|
516
|
+
element.removeEventListener("mousedown", handleMouseDown);
|
|
517
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
518
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
519
|
+
};
|
|
520
|
+
}, [ref, minSwipeDistance, maxSwipeTime, velocityThreshold, preventDefault]);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/hooks/usePullToRefresh.ts
|
|
524
|
+
var import_react7 = require("react");
|
|
525
|
+
function usePullToRefresh(onRefresh, options = {}) {
|
|
526
|
+
const { threshold = 80 } = options;
|
|
527
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
528
|
+
const [isPulling, setIsPulling] = (0, import_react7.useState)(false);
|
|
529
|
+
const [progress, setProgress] = (0, import_react7.useState)(0);
|
|
530
|
+
const startYRef = (0, import_react7.useRef)(null);
|
|
531
|
+
const thresholdReachedRef = (0, import_react7.useRef)(false);
|
|
532
|
+
const onRefreshRef = (0, import_react7.useRef)(onRefresh);
|
|
533
|
+
(0, import_react7.useEffect)(() => {
|
|
534
|
+
onRefreshRef.current = onRefresh;
|
|
535
|
+
}, [onRefresh]);
|
|
536
|
+
const handleTouchStart = (0, import_react7.useCallback)((e) => {
|
|
537
|
+
const el = containerRef.current;
|
|
538
|
+
if (!el || el.scrollTop > 0) return;
|
|
539
|
+
startYRef.current = e.touches[0].clientY;
|
|
540
|
+
thresholdReachedRef.current = false;
|
|
541
|
+
}, []);
|
|
542
|
+
const handleTouchMove = (0, import_react7.useCallback)(
|
|
543
|
+
(e) => {
|
|
544
|
+
if (startYRef.current === null) return;
|
|
545
|
+
const delta = e.touches[0].clientY - startYRef.current;
|
|
546
|
+
if (delta <= 0) {
|
|
547
|
+
setProgress(0);
|
|
548
|
+
setIsPulling(false);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const prog = Math.min(delta / threshold, 1);
|
|
552
|
+
setProgress(prog);
|
|
553
|
+
setIsPulling(true);
|
|
554
|
+
thresholdReachedRef.current = prog >= 1;
|
|
555
|
+
},
|
|
556
|
+
[threshold]
|
|
557
|
+
);
|
|
558
|
+
const handleTouchEnd = (0, import_react7.useCallback)(async () => {
|
|
559
|
+
setIsPulling(false);
|
|
560
|
+
setProgress(0);
|
|
561
|
+
startYRef.current = null;
|
|
562
|
+
if (thresholdReachedRef.current) {
|
|
563
|
+
thresholdReachedRef.current = false;
|
|
564
|
+
await onRefreshRef.current();
|
|
565
|
+
}
|
|
566
|
+
}, []);
|
|
567
|
+
(0, import_react7.useEffect)(() => {
|
|
568
|
+
const el = containerRef.current;
|
|
569
|
+
if (!el) return;
|
|
570
|
+
el.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
571
|
+
el.addEventListener("touchmove", handleTouchMove, { passive: true });
|
|
572
|
+
el.addEventListener("touchend", handleTouchEnd);
|
|
573
|
+
return () => {
|
|
574
|
+
el.removeEventListener("touchstart", handleTouchStart);
|
|
575
|
+
el.removeEventListener("touchmove", handleTouchMove);
|
|
576
|
+
el.removeEventListener("touchend", handleTouchEnd);
|
|
577
|
+
};
|
|
578
|
+
}, [handleTouchStart, handleTouchMove, handleTouchEnd]);
|
|
579
|
+
return { containerRef, isPulling, progress };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/hooks/useCountdown.ts
|
|
583
|
+
var import_react8 = require("react");
|
|
584
|
+
function resolveMs(endDate) {
|
|
585
|
+
if (!endDate) return NaN;
|
|
586
|
+
if (endDate instanceof Date) return endDate.getTime();
|
|
587
|
+
if (typeof endDate === "object" && endDate !== null && "_seconds" in endDate && typeof endDate._seconds === "number") {
|
|
588
|
+
return endDate._seconds * 1e3;
|
|
589
|
+
}
|
|
590
|
+
return new Date(endDate).getTime();
|
|
591
|
+
}
|
|
592
|
+
function useCountdown(endDate) {
|
|
593
|
+
const getRemaining = () => {
|
|
594
|
+
if (!endDate) return null;
|
|
595
|
+
const ms = resolveMs(endDate);
|
|
596
|
+
if (Number.isNaN(ms)) return null;
|
|
597
|
+
const diff = ms - Date.now();
|
|
598
|
+
if (diff <= 0) return null;
|
|
599
|
+
return {
|
|
600
|
+
days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
|
|
601
|
+
hours: Math.floor(diff % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60)),
|
|
602
|
+
minutes: Math.floor(diff % (1e3 * 60 * 60) / (1e3 * 60)),
|
|
603
|
+
seconds: Math.floor(diff % (1e3 * 60) / 1e3)
|
|
604
|
+
};
|
|
605
|
+
};
|
|
606
|
+
const [remaining, setRemaining] = (0, import_react8.useState)(
|
|
607
|
+
getRemaining
|
|
608
|
+
);
|
|
609
|
+
(0, import_react8.useEffect)(() => {
|
|
610
|
+
const id = setInterval(() => setRemaining(getRemaining()), 1e3);
|
|
611
|
+
return () => clearInterval(id);
|
|
612
|
+
}, [endDate]);
|
|
613
|
+
return remaining;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/hooks/useCamera.ts
|
|
617
|
+
var import_react9 = require("react");
|
|
618
|
+
function useCamera() {
|
|
619
|
+
const isSupported = typeof navigator !== "undefined" && typeof navigator.mediaDevices !== "undefined" && typeof navigator.mediaDevices.getUserMedia === "function";
|
|
620
|
+
const videoRef = (0, import_react9.useRef)(null);
|
|
621
|
+
const streamRef = (0, import_react9.useRef)(null);
|
|
622
|
+
const mediaRecorderRef = (0, import_react9.useRef)(null);
|
|
623
|
+
const chunksRef = (0, import_react9.useRef)([]);
|
|
624
|
+
const currentFacingModeRef = (0, import_react9.useRef)("environment");
|
|
625
|
+
const stopRecordingResolveRef = (0, import_react9.useRef)(null);
|
|
626
|
+
const [stream, setStream] = (0, import_react9.useState)(null);
|
|
627
|
+
const [isActive, setIsActive] = (0, import_react9.useState)(false);
|
|
628
|
+
const [isCapturing, setIsCapturing] = (0, import_react9.useState)(false);
|
|
629
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
630
|
+
const stopCamera = (0, import_react9.useCallback)(() => {
|
|
631
|
+
if (streamRef.current) {
|
|
632
|
+
streamRef.current.getTracks().forEach((t) => t.stop());
|
|
633
|
+
streamRef.current = null;
|
|
634
|
+
}
|
|
635
|
+
if (videoRef.current) {
|
|
636
|
+
videoRef.current.srcObject = null;
|
|
637
|
+
}
|
|
638
|
+
setStream(null);
|
|
639
|
+
setIsActive(false);
|
|
640
|
+
setIsCapturing(false);
|
|
641
|
+
}, []);
|
|
642
|
+
(0, import_react9.useEffect)(() => {
|
|
643
|
+
return () => {
|
|
644
|
+
stopCamera();
|
|
645
|
+
};
|
|
646
|
+
}, [stopCamera]);
|
|
647
|
+
const startCamera = (0, import_react9.useCallback)(
|
|
648
|
+
async (options) => {
|
|
649
|
+
var _a, _b;
|
|
650
|
+
if (!isSupported) {
|
|
651
|
+
setError("Camera is not supported on this device");
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
setError(null);
|
|
655
|
+
stopCamera();
|
|
656
|
+
const facingMode = (_a = options == null ? void 0 : options.facingMode) != null ? _a : "environment";
|
|
657
|
+
currentFacingModeRef.current = facingMode;
|
|
658
|
+
const videoConstraints = (options == null ? void 0 : options.video) !== void 0 ? options.video : { facingMode };
|
|
659
|
+
try {
|
|
660
|
+
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
661
|
+
video: videoConstraints,
|
|
662
|
+
audio: (_b = options == null ? void 0 : options.audio) != null ? _b : false
|
|
663
|
+
});
|
|
664
|
+
streamRef.current = mediaStream;
|
|
665
|
+
setStream(mediaStream);
|
|
666
|
+
setIsActive(true);
|
|
667
|
+
if (videoRef.current) {
|
|
668
|
+
videoRef.current.srcObject = mediaStream;
|
|
669
|
+
}
|
|
670
|
+
} catch (err) {
|
|
671
|
+
const message = err instanceof DOMException && err.name === "NotAllowedError" ? "Camera permission denied. Please allow access in your browser settings." : "Camera unavailable";
|
|
672
|
+
setError(message);
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
[isSupported, stopCamera]
|
|
676
|
+
);
|
|
677
|
+
const takePhoto = (0, import_react9.useCallback)(() => {
|
|
678
|
+
const video = videoRef.current;
|
|
679
|
+
if (!video || !isActive) return null;
|
|
680
|
+
const canvas = document.createElement("canvas");
|
|
681
|
+
canvas.width = video.videoWidth;
|
|
682
|
+
canvas.height = video.videoHeight;
|
|
683
|
+
const ctx = canvas.getContext("2d");
|
|
684
|
+
if (!ctx) return null;
|
|
685
|
+
ctx.drawImage(video, 0, 0);
|
|
686
|
+
let result = null;
|
|
687
|
+
canvas.toBlob(
|
|
688
|
+
(blob) => {
|
|
689
|
+
result = blob;
|
|
690
|
+
},
|
|
691
|
+
"image/webp",
|
|
692
|
+
0.92
|
|
693
|
+
);
|
|
694
|
+
return result;
|
|
695
|
+
}, [isActive]);
|
|
696
|
+
const startRecording = (0, import_react9.useCallback)(() => {
|
|
697
|
+
if (!streamRef.current || !isActive) return;
|
|
698
|
+
chunksRef.current = [];
|
|
699
|
+
const recorder = new MediaRecorder(streamRef.current, {
|
|
700
|
+
mimeType: "video/webm"
|
|
701
|
+
});
|
|
702
|
+
recorder.ondataavailable = (e) => {
|
|
703
|
+
if (e.data.size > 0) chunksRef.current.push(e.data);
|
|
704
|
+
};
|
|
705
|
+
recorder.onstop = () => {
|
|
706
|
+
const blob = new Blob(chunksRef.current, { type: "video/webm" });
|
|
707
|
+
setIsCapturing(false);
|
|
708
|
+
if (stopRecordingResolveRef.current) {
|
|
709
|
+
stopRecordingResolveRef.current(blob);
|
|
710
|
+
stopRecordingResolveRef.current = null;
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
mediaRecorderRef.current = recorder;
|
|
714
|
+
recorder.start();
|
|
715
|
+
setIsCapturing(true);
|
|
716
|
+
}, [isActive]);
|
|
717
|
+
const stopRecording = (0, import_react9.useCallback)(() => {
|
|
718
|
+
return new Promise((resolve) => {
|
|
719
|
+
stopRecordingResolveRef.current = resolve;
|
|
720
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
721
|
+
mediaRecorderRef.current.stop();
|
|
722
|
+
} else {
|
|
723
|
+
resolve(new Blob([], { type: "video/webm" }));
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
}, []);
|
|
727
|
+
const switchCamera = (0, import_react9.useCallback)(async () => {
|
|
728
|
+
const next = currentFacingModeRef.current === "environment" ? "user" : "environment";
|
|
729
|
+
await startCamera({ facingMode: next });
|
|
730
|
+
}, [startCamera]);
|
|
731
|
+
return {
|
|
732
|
+
isSupported,
|
|
733
|
+
isActive,
|
|
734
|
+
isCapturing,
|
|
735
|
+
stream,
|
|
736
|
+
error,
|
|
737
|
+
videoRef,
|
|
738
|
+
startCamera,
|
|
739
|
+
stopCamera,
|
|
740
|
+
takePhoto,
|
|
741
|
+
startRecording,
|
|
742
|
+
stopRecording,
|
|
743
|
+
switchCamera
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
747
|
+
0 && (module.exports = {
|
|
748
|
+
useBreakpoint,
|
|
749
|
+
useCamera,
|
|
750
|
+
useClickOutside,
|
|
751
|
+
useCountdown,
|
|
752
|
+
useGesture,
|
|
753
|
+
useKeyPress,
|
|
754
|
+
useLongPress,
|
|
755
|
+
useMediaQuery,
|
|
756
|
+
usePullToRefresh,
|
|
757
|
+
useSwipe
|
|
758
|
+
});
|