@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 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
+ });