@develemit/web-hooks 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +166 -0
  3. package/dist/auto-grow.cjs +60 -0
  4. package/dist/auto-grow.d.cts +14 -0
  5. package/dist/auto-grow.d.ts +14 -0
  6. package/dist/auto-grow.js +9 -0
  7. package/dist/chunk-3CACI4OQ.js +68 -0
  8. package/dist/chunk-3UGRXQIA.js +39 -0
  9. package/dist/chunk-5CA5RIMH.js +34 -0
  10. package/dist/chunk-5KIH2XLV.js +136 -0
  11. package/dist/chunk-6KCRVSLS.js +80 -0
  12. package/dist/chunk-DNU57XEJ.js +82 -0
  13. package/dist/chunk-IWQDAJEP.js +69 -0
  14. package/dist/chunk-LZKAGDER.js +22 -0
  15. package/dist/chunk-NKLEB5TR.js +98 -0
  16. package/dist/chunk-OZ4PU4E3.js +115 -0
  17. package/dist/chunk-S4YKMGQE.js +23 -0
  18. package/dist/chunk-UPVNSGIK.js +72 -0
  19. package/dist/chunk-UZADAINO.js +61 -0
  20. package/dist/clipboard.cjs +5 -0
  21. package/dist/clipboard.js +4 -57
  22. package/dist/debounce.cjs +96 -0
  23. package/dist/debounce.d.cts +21 -0
  24. package/dist/debounce.d.ts +21 -0
  25. package/dist/debounce.js +11 -0
  26. package/dist/drawer-swipe.js +12 -101
  27. package/dist/escape.cjs +1 -0
  28. package/dist/escape.js +3 -17
  29. package/dist/focus-trap.cjs +3 -1
  30. package/dist/focus-trap.js +6 -72
  31. package/dist/hotkey.cjs +127 -0
  32. package/dist/hotkey.d.cts +31 -0
  33. package/dist/hotkey.d.ts +31 -0
  34. package/dist/hotkey.js +15 -0
  35. package/dist/index.cjs +613 -3
  36. package/dist/index.d.cts +14 -60
  37. package/dist/index.d.ts +14 -60
  38. package/dist/index.js +97 -247
  39. package/dist/media-query.cjs +90 -0
  40. package/dist/media-query.d.cts +12 -0
  41. package/dist/media-query.d.ts +12 -0
  42. package/dist/media-query.js +15 -0
  43. package/dist/outside-press.cjs +66 -0
  44. package/dist/outside-press.d.cts +15 -0
  45. package/dist/outside-press.d.ts +15 -0
  46. package/dist/outside-press.js +11 -0
  47. package/dist/scroll-lock.cjs +107 -0
  48. package/dist/scroll-lock.d.cts +8 -0
  49. package/dist/scroll-lock.d.ts +8 -0
  50. package/dist/scroll-lock.js +11 -0
  51. package/dist/storage-state.cjs +161 -0
  52. package/dist/storage-state.d.cts +14 -0
  53. package/dist/storage-state.d.ts +14 -0
  54. package/dist/storage-state.js +7 -0
  55. package/dist/unsaved-guard.cjs +48 -0
  56. package/dist/unsaved-guard.d.cts +5 -0
  57. package/dist/unsaved-guard.d.ts +5 -0
  58. package/dist/unsaved-guard.js +9 -0
  59. package/dist/visibility-polling.cjs +98 -0
  60. package/dist/visibility-polling.d.cts +14 -0
  61. package/dist/visibility-polling.d.ts +14 -0
  62. package/dist/visibility-polling.js +9 -0
  63. package/package.json +55 -2
package/dist/index.d.cts CHANGED
@@ -1,60 +1,14 @@
1
- import { RefObject } from 'react';
2
-
3
- type SwipePoint = {
4
- x: number;
5
- y: number;
6
- time: number;
7
- };
8
- declare const BACK_ZONE_PX = 60;
9
- declare const FORWARD_ZONE_PX = 30;
10
- declare const OPEN_DISTANCE_PX = 80;
11
- declare const CLOSE_DISTANCE_PX = 60;
12
- declare const VERTICAL_CANCEL_PX = 40;
13
- declare const MAX_SWIPE_DURATION_MS = 450;
14
- type SwipeIntent = 'open' | 'close' | null;
15
- declare function isInOpenZone(x: number, viewportWidth: number): boolean;
16
- declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number): SwipeIntent;
17
- declare function isInsideHorizontalScroller(target: EventTarget | null): boolean;
18
-
19
- type UseDrawerSwipeOptions = {
20
- drawerOpen: boolean;
21
- onOpen: () => void;
22
- onClose: () => void;
23
- enabled?: boolean;
24
- maxViewportWidth?: number;
25
- };
26
- declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, }: UseDrawerSwipeOptions): void;
27
-
28
- declare const FOCUSABLE_SELECTOR = "a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
29
- declare function focusableWithin(container: HTMLElement): HTMLElement[];
30
- /** The element Tab must be redirected to, or null when the browser's own move is fine. */
31
- declare function nextFocusTarget(items: HTMLElement[], current: Element | null, shiftKey: boolean, container: HTMLElement): HTMLElement | null;
32
-
33
- type UseFocusTrapOptions = {
34
- active: boolean;
35
- initialFocusRef?: RefObject<HTMLElement | null>;
36
- /** Wins over the captured opener. Safari leaves <body> focused after a tap on a button. */
37
- returnFocusRef?: RefObject<HTMLElement | null>;
38
- restoreFocus?: boolean;
39
- };
40
- declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, { active, initialFocusRef, returnFocusRef, restoreFocus, }: UseFocusTrapOptions): void;
41
-
42
- declare function useEscape(onEscape: () => void, active?: boolean): void;
43
-
44
- type CopyResult = {
45
- ok: true;
46
- } | {
47
- ok: false;
48
- reason: 'unavailable' | 'denied';
49
- };
50
- declare function copyText(text: string): Promise<CopyResult>;
51
-
52
- type CopyStatus = 'idle' | 'copied' | 'failed';
53
- declare function useCopyFeedback({ resetMs }?: {
54
- resetMs?: number;
55
- }): {
56
- copy: (text: string) => Promise<CopyResult>;
57
- status: CopyStatus;
58
- };
59
-
60
- export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, type CopyResult, type CopyStatus, FOCUSABLE_SELECTOR, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, type UseFocusTrapOptions, VERTICAL_CANCEL_PX, copyText, focusableWithin, isInOpenZone, isInsideHorizontalScroller, nextFocusTarget, resolveSwipeIntent, useCopyFeedback, useDrawerSwipe, useEscape, useFocusTrap };
1
+ export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, SwipeIntent, SwipePoint, UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe } from './drawer-swipe.cjs';
2
+ export { FOCUSABLE_SELECTOR, UseFocusTrapOptions, focusableWithin, nextFocusTarget, useFocusTrap } from './focus-trap.cjs';
3
+ export { useEscape } from './escape.cjs';
4
+ export { CopyResult, CopyStatus, copyText, useCopyFeedback } from './clipboard.cjs';
5
+ export { lockScroll, unlockScroll, useScrollLock } from './scroll-lock.cjs';
6
+ export { COARSE_POINTER_QUERY, REDUCED_MOTION_QUERY, UseMediaQueryOptions, useCoarsePointer, useMediaQuery, useReducedMotion } from './media-query.cjs';
7
+ export { UseOutsidePressOptions, isOutside, isPrimaryPress, useOutsidePress } from './outside-press.cjs';
8
+ export { UseVisibilityPollingOptions, nextDelay, useVisibilityPolling } from './visibility-polling.cjs';
9
+ export { DebouncedCallback, Debouncer, createDebouncer, useDebouncedCallback, useDebouncedValue } from './debounce.cjs';
10
+ export { StorageKind, StorageStateSetter, UseStorageStateOptions, useStorageState } from './storage-state.cjs';
11
+ export { handleBeforeUnload, useUnsavedChangesGuard } from './unsaved-guard.cjs';
12
+ export { ParsedHotkey, UseHotkeyOptions, detectApple, isEditableTarget, matchHotkey, parseHotkey, useHotkey } from './hotkey.cjs';
13
+ export { NextHeight, UseAutoGrowTextareaOptions, nextHeight, useAutoGrowTextarea } from './auto-grow.cjs';
14
+ import 'react';
package/dist/index.d.ts CHANGED
@@ -1,60 +1,14 @@
1
- import { RefObject } from 'react';
2
-
3
- type SwipePoint = {
4
- x: number;
5
- y: number;
6
- time: number;
7
- };
8
- declare const BACK_ZONE_PX = 60;
9
- declare const FORWARD_ZONE_PX = 30;
10
- declare const OPEN_DISTANCE_PX = 80;
11
- declare const CLOSE_DISTANCE_PX = 60;
12
- declare const VERTICAL_CANCEL_PX = 40;
13
- declare const MAX_SWIPE_DURATION_MS = 450;
14
- type SwipeIntent = 'open' | 'close' | null;
15
- declare function isInOpenZone(x: number, viewportWidth: number): boolean;
16
- declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number): SwipeIntent;
17
- declare function isInsideHorizontalScroller(target: EventTarget | null): boolean;
18
-
19
- type UseDrawerSwipeOptions = {
20
- drawerOpen: boolean;
21
- onOpen: () => void;
22
- onClose: () => void;
23
- enabled?: boolean;
24
- maxViewportWidth?: number;
25
- };
26
- declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, }: UseDrawerSwipeOptions): void;
27
-
28
- declare const FOCUSABLE_SELECTOR = "a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
29
- declare function focusableWithin(container: HTMLElement): HTMLElement[];
30
- /** The element Tab must be redirected to, or null when the browser's own move is fine. */
31
- declare function nextFocusTarget(items: HTMLElement[], current: Element | null, shiftKey: boolean, container: HTMLElement): HTMLElement | null;
32
-
33
- type UseFocusTrapOptions = {
34
- active: boolean;
35
- initialFocusRef?: RefObject<HTMLElement | null>;
36
- /** Wins over the captured opener. Safari leaves <body> focused after a tap on a button. */
37
- returnFocusRef?: RefObject<HTMLElement | null>;
38
- restoreFocus?: boolean;
39
- };
40
- declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, { active, initialFocusRef, returnFocusRef, restoreFocus, }: UseFocusTrapOptions): void;
41
-
42
- declare function useEscape(onEscape: () => void, active?: boolean): void;
43
-
44
- type CopyResult = {
45
- ok: true;
46
- } | {
47
- ok: false;
48
- reason: 'unavailable' | 'denied';
49
- };
50
- declare function copyText(text: string): Promise<CopyResult>;
51
-
52
- type CopyStatus = 'idle' | 'copied' | 'failed';
53
- declare function useCopyFeedback({ resetMs }?: {
54
- resetMs?: number;
55
- }): {
56
- copy: (text: string) => Promise<CopyResult>;
57
- status: CopyStatus;
58
- };
59
-
60
- export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, type CopyResult, type CopyStatus, FOCUSABLE_SELECTOR, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, type UseFocusTrapOptions, VERTICAL_CANCEL_PX, copyText, focusableWithin, isInOpenZone, isInsideHorizontalScroller, nextFocusTarget, resolveSwipeIntent, useCopyFeedback, useDrawerSwipe, useEscape, useFocusTrap };
1
+ export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, SwipeIntent, SwipePoint, UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe } from './drawer-swipe.js';
2
+ export { FOCUSABLE_SELECTOR, UseFocusTrapOptions, focusableWithin, nextFocusTarget, useFocusTrap } from './focus-trap.js';
3
+ export { useEscape } from './escape.js';
4
+ export { CopyResult, CopyStatus, copyText, useCopyFeedback } from './clipboard.js';
5
+ export { lockScroll, unlockScroll, useScrollLock } from './scroll-lock.js';
6
+ export { COARSE_POINTER_QUERY, REDUCED_MOTION_QUERY, UseMediaQueryOptions, useCoarsePointer, useMediaQuery, useReducedMotion } from './media-query.js';
7
+ export { UseOutsidePressOptions, isOutside, isPrimaryPress, useOutsidePress } from './outside-press.js';
8
+ export { UseVisibilityPollingOptions, nextDelay, useVisibilityPolling } from './visibility-polling.js';
9
+ export { DebouncedCallback, Debouncer, createDebouncer, useDebouncedCallback, useDebouncedValue } from './debounce.js';
10
+ export { StorageKind, StorageStateSetter, UseStorageStateOptions, useStorageState } from './storage-state.js';
11
+ export { handleBeforeUnload, useUnsavedChangesGuard } from './unsaved-guard.js';
12
+ export { ParsedHotkey, UseHotkeyOptions, detectApple, isEditableTarget, matchHotkey, parseHotkey, useHotkey } from './hotkey.js';
13
+ export { NextHeight, UseAutoGrowTextareaOptions, nextHeight, useAutoGrowTextarea } from './auto-grow.js';
14
+ import 'react';
package/dist/index.js CHANGED
@@ -1,265 +1,115 @@
1
- // src/drawer-swipe/swipe-intent.ts
2
- var BACK_ZONE_PX = 60;
3
- var FORWARD_ZONE_PX = 30;
4
- var OPEN_DISTANCE_PX = 80;
5
- var CLOSE_DISTANCE_PX = 60;
6
- var VERTICAL_CANCEL_PX = 40;
7
- var MAX_SWIPE_DURATION_MS = 450;
8
- var HORIZONTAL_DOMINANCE = 1.5;
9
- function isInOpenZone(x, viewportWidth) {
10
- return x > BACK_ZONE_PX && x < viewportWidth - FORWARD_ZONE_PX;
11
- }
12
- function resolveSwipeIntent(start, end, drawerOpen, viewportWidth) {
13
- const dx = end.x - start.x;
14
- const dy = end.y - start.y;
15
- if (end.time - start.time > MAX_SWIPE_DURATION_MS) return null;
16
- if (Math.abs(dx) < Math.abs(dy) * HORIZONTAL_DOMINANCE) return null;
17
- if (drawerOpen) {
18
- return dx <= -CLOSE_DISTANCE_PX ? "close" : null;
19
- }
20
- if (dx < OPEN_DISTANCE_PX) return null;
21
- return isInOpenZone(start.x, viewportWidth) ? "open" : null;
22
- }
23
- function isInsideHorizontalScroller(target) {
24
- let node = target instanceof Element ? target : null;
25
- while (node && node !== document.body) {
26
- const { overflowX } = window.getComputedStyle(node);
27
- if ((overflowX === "auto" || overflowX === "scroll") && node.scrollWidth > node.clientWidth) {
28
- return true;
29
- }
30
- node = node.parentElement;
31
- }
32
- return false;
33
- }
34
-
35
- // src/drawer-swipe/use-drawer-swipe.ts
36
- import { useEffect, useRef } from "react";
37
- function isWideViewport(maxViewportWidth) {
38
- return window.matchMedia(`(min-width: ${maxViewportWidth}px)`).matches;
39
- }
40
- function useDrawerSwipe({
41
- drawerOpen,
42
- onOpen,
43
- onClose,
44
- enabled = true,
45
- maxViewportWidth = 768
46
- }) {
47
- const start = useRef(null);
48
- const handlers = useRef({ drawerOpen, onOpen, onClose, maxViewportWidth });
49
- handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth };
50
- useEffect(() => {
51
- if (!enabled) return;
52
- function handleStart(event) {
53
- start.current = null;
54
- if (event.touches.length !== 1) return;
55
- if (isWideViewport(handlers.current.maxViewportWidth)) return;
56
- if (!handlers.current.drawerOpen && isInsideHorizontalScroller(event.target)) {
57
- return;
58
- }
59
- const touch = event.touches[0];
60
- if (!touch) return;
61
- start.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
62
- }
63
- function handleMove(event) {
64
- const origin = start.current;
65
- const touch = event.touches[0];
66
- if (!origin || !touch) return;
67
- if (Math.abs(touch.clientY - origin.y) > VERTICAL_CANCEL_PX) {
68
- start.current = null;
69
- }
70
- }
71
- function handleEnd(event) {
72
- const origin = start.current;
73
- start.current = null;
74
- const touch = event.changedTouches[0];
75
- if (!origin || !touch) return;
76
- const { drawerOpen: drawerOpen2, onOpen: onOpen2, onClose: onClose2 } = handlers.current;
77
- const intent = resolveSwipeIntent(
78
- origin,
79
- { x: touch.clientX, y: touch.clientY, time: Date.now() },
80
- drawerOpen2,
81
- window.innerWidth
82
- );
83
- if (intent === "open") onOpen2();
84
- if (intent === "close") onClose2();
85
- }
86
- function handleCancel() {
87
- start.current = null;
88
- }
89
- document.addEventListener("touchstart", handleStart, { passive: true });
90
- document.addEventListener("touchmove", handleMove, { passive: true });
91
- document.addEventListener("touchend", handleEnd, { passive: true });
92
- document.addEventListener("touchcancel", handleCancel, { passive: true });
93
- return () => {
94
- document.removeEventListener("touchstart", handleStart);
95
- document.removeEventListener("touchmove", handleMove);
96
- document.removeEventListener("touchend", handleEnd);
97
- document.removeEventListener("touchcancel", handleCancel);
98
- };
99
- }, [enabled]);
100
- }
101
-
102
- // src/focus-trap/focusables.ts
103
- var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
104
- function focusableWithin(container) {
105
- return Array.from(
106
- container.querySelectorAll(FOCUSABLE_SELECTOR)
107
- ).filter((el) => !el.closest("[hidden], [inert]"));
108
- }
109
- function nextFocusTarget(items, current, shiftKey, container) {
110
- const first = items[0];
111
- const last = items[items.length - 1];
112
- if (!first || !last) return null;
113
- if (!current || !container.contains(current)) return shiftKey ? last : first;
114
- if (shiftKey && (current === first || current === container)) return last;
115
- if (!shiftKey && current === last) return first;
116
- return null;
117
- }
118
-
119
- // src/focus-trap/use-focus-trap.ts
120
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
121
- var activeTraps = [];
122
- function useFocusTrap(containerRef, {
123
- active,
124
- initialFocusRef,
125
- returnFocusRef,
126
- restoreFocus = true
127
- }) {
128
- const openerRef = useRef2(null);
129
- if (active && !openerRef.current && typeof document !== "undefined") {
130
- openerRef.current = document.activeElement;
131
- }
132
- useEffect2(() => {
133
- const container = containerRef.current;
134
- if (!active || !container) return;
135
- const token = {};
136
- activeTraps.push(token);
137
- if (!container.contains(document.activeElement)) {
138
- const target = initialFocusRef?.current ?? focusableWithin(container)[0] ?? container;
139
- if (target === container && !container.hasAttribute("tabindex")) {
140
- container.setAttribute("tabindex", "-1");
141
- }
142
- target.focus();
143
- }
144
- function onKeyDown(event) {
145
- if (event.key !== "Tab" || !container) return;
146
- if (activeTraps[activeTraps.length - 1] !== token) return;
147
- const items = focusableWithin(container);
148
- if (items.length === 0) {
149
- event.preventDefault();
150
- return;
151
- }
152
- const target = nextFocusTarget(
153
- items,
154
- document.activeElement,
155
- event.shiftKey,
156
- container
157
- );
158
- if (target) {
159
- event.preventDefault();
160
- target.focus();
161
- }
162
- }
163
- document.addEventListener("keydown", onKeyDown);
164
- return () => {
165
- document.removeEventListener("keydown", onKeyDown);
166
- activeTraps.splice(activeTraps.indexOf(token), 1);
167
- const opener = returnFocusRef?.current ?? openerRef.current;
168
- openerRef.current = null;
169
- if (restoreFocus && opener?.isConnected) opener.focus();
170
- };
171
- }, [active, containerRef, initialFocusRef, returnFocusRef, restoreFocus]);
172
- }
173
-
174
- // src/escape/use-escape.ts
175
- import { useEffect as useEffect3, useRef as useRef3 } from "react";
176
- function useEscape(onEscape, active = true) {
177
- const handlerRef = useRef3(onEscape);
178
- useEffect3(() => {
179
- handlerRef.current = onEscape;
180
- });
181
- useEffect3(() => {
182
- if (!active) return;
183
- function onKeyDown(event) {
184
- if (event.key === "Escape") handlerRef.current();
185
- }
186
- document.addEventListener("keydown", onKeyDown);
187
- return () => document.removeEventListener("keydown", onKeyDown);
188
- }, [active]);
189
- }
190
-
191
- // src/clipboard/copy-text.ts
192
- async function copyText(text) {
193
- const hasClipboardApi = typeof navigator !== "undefined" && !!navigator.clipboard?.writeText && typeof window !== "undefined" && window.isSecureContext;
194
- if (hasClipboardApi) {
195
- try {
196
- await navigator.clipboard.writeText(text);
197
- return { ok: true };
198
- } catch {
199
- }
200
- }
201
- if (execCommandCopy(text)) return { ok: true };
202
- return { ok: false, reason: hasClipboardApi ? "denied" : "unavailable" };
203
- }
204
- function execCommandCopy(text) {
205
- if (typeof document === "undefined") return false;
206
- const textarea = document.createElement("textarea");
207
- textarea.value = text;
208
- textarea.readOnly = true;
209
- textarea.style.position = "fixed";
210
- textarea.style.top = "-1000px";
211
- textarea.style.left = "-1000px";
212
- textarea.style.fontSize = "16px";
213
- document.body.appendChild(textarea);
214
- try {
215
- textarea.select();
216
- textarea.setSelectionRange(0, text.length);
217
- return document.execCommand("copy");
218
- } catch {
219
- return false;
220
- } finally {
221
- document.body.removeChild(textarea);
222
- }
223
- }
224
-
225
- // src/clipboard/use-copy-feedback.ts
226
- import { useCallback, useEffect as useEffect4, useRef as useRef4, useState } from "react";
227
- function useCopyFeedback({ resetMs = 1500 } = {}) {
228
- const [status, setStatus] = useState("idle");
229
- const timerRef = useRef4(void 0);
230
- const clearTimer = useCallback(() => {
231
- if (timerRef.current !== void 0) clearTimeout(timerRef.current);
232
- timerRef.current = void 0;
233
- }, []);
234
- useEffect4(() => clearTimer, [clearTimer]);
235
- const copy = useCallback(
236
- async (text) => {
237
- const result = await copyText(text);
238
- clearTimer();
239
- setStatus(result.ok ? "copied" : "failed");
240
- timerRef.current = setTimeout(() => setStatus("idle"), resetMs);
241
- return result;
242
- },
243
- [clearTimer, resetMs]
244
- );
245
- return { copy, status };
246
- }
1
+ "use client";
2
+ import {
3
+ nextDelay,
4
+ useVisibilityPolling
5
+ } from "./chunk-UPVNSGIK.js";
6
+ import {
7
+ createDebouncer,
8
+ useDebouncedCallback,
9
+ useDebouncedValue
10
+ } from "./chunk-IWQDAJEP.js";
11
+ import {
12
+ useStorageState
13
+ } from "./chunk-5KIH2XLV.js";
14
+ import {
15
+ handleBeforeUnload,
16
+ useUnsavedChangesGuard
17
+ } from "./chunk-LZKAGDER.js";
18
+ import {
19
+ detectApple,
20
+ isEditableTarget,
21
+ matchHotkey,
22
+ parseHotkey,
23
+ useHotkey
24
+ } from "./chunk-NKLEB5TR.js";
25
+ import {
26
+ nextHeight,
27
+ useAutoGrowTextarea
28
+ } from "./chunk-5CA5RIMH.js";
29
+ import {
30
+ BACK_ZONE_PX,
31
+ CLOSE_DISTANCE_PX,
32
+ FORWARD_ZONE_PX,
33
+ MAX_SWIPE_DURATION_MS,
34
+ OPEN_DISTANCE_PX,
35
+ VERTICAL_CANCEL_PX,
36
+ isInOpenZone,
37
+ isInsideHorizontalScroller,
38
+ resolveSwipeIntent,
39
+ useDrawerSwipe
40
+ } from "./chunk-OZ4PU4E3.js";
41
+ import {
42
+ FOCUSABLE_SELECTOR,
43
+ focusableWithin,
44
+ nextFocusTarget,
45
+ useFocusTrap
46
+ } from "./chunk-DNU57XEJ.js";
47
+ import {
48
+ useEscape
49
+ } from "./chunk-S4YKMGQE.js";
50
+ import {
51
+ copyText,
52
+ useCopyFeedback
53
+ } from "./chunk-3CACI4OQ.js";
54
+ import {
55
+ lockScroll,
56
+ unlockScroll,
57
+ useScrollLock
58
+ } from "./chunk-6KCRVSLS.js";
59
+ import {
60
+ COARSE_POINTER_QUERY,
61
+ REDUCED_MOTION_QUERY,
62
+ useCoarsePointer,
63
+ useMediaQuery,
64
+ useReducedMotion
65
+ } from "./chunk-UZADAINO.js";
66
+ import {
67
+ isOutside,
68
+ isPrimaryPress,
69
+ useOutsidePress
70
+ } from "./chunk-3UGRXQIA.js";
247
71
  export {
248
72
  BACK_ZONE_PX,
249
73
  CLOSE_DISTANCE_PX,
74
+ COARSE_POINTER_QUERY,
250
75
  FOCUSABLE_SELECTOR,
251
76
  FORWARD_ZONE_PX,
252
77
  MAX_SWIPE_DURATION_MS,
253
78
  OPEN_DISTANCE_PX,
79
+ REDUCED_MOTION_QUERY,
254
80
  VERTICAL_CANCEL_PX,
255
81
  copyText,
82
+ createDebouncer,
83
+ detectApple,
256
84
  focusableWithin,
85
+ handleBeforeUnload,
86
+ isEditableTarget,
257
87
  isInOpenZone,
258
88
  isInsideHorizontalScroller,
89
+ isOutside,
90
+ isPrimaryPress,
91
+ lockScroll,
92
+ matchHotkey,
93
+ nextDelay,
259
94
  nextFocusTarget,
95
+ nextHeight,
96
+ parseHotkey,
260
97
  resolveSwipeIntent,
98
+ unlockScroll,
99
+ useAutoGrowTextarea,
100
+ useCoarsePointer,
261
101
  useCopyFeedback,
102
+ useDebouncedCallback,
103
+ useDebouncedValue,
262
104
  useDrawerSwipe,
263
105
  useEscape,
264
- useFocusTrap
106
+ useFocusTrap,
107
+ useHotkey,
108
+ useMediaQuery,
109
+ useOutsidePress,
110
+ useReducedMotion,
111
+ useScrollLock,
112
+ useStorageState,
113
+ useUnsavedChangesGuard,
114
+ useVisibilityPolling
265
115
  };
@@ -0,0 +1,90 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/media-query/index.ts
22
+ var media_query_exports = {};
23
+ __export(media_query_exports, {
24
+ COARSE_POINTER_QUERY: () => COARSE_POINTER_QUERY,
25
+ REDUCED_MOTION_QUERY: () => REDUCED_MOTION_QUERY,
26
+ useCoarsePointer: () => useCoarsePointer,
27
+ useMediaQuery: () => useMediaQuery,
28
+ useReducedMotion: () => useReducedMotion
29
+ });
30
+ module.exports = __toCommonJS(media_query_exports);
31
+
32
+ // src/media-query/use-media-query.ts
33
+ var import_react = require("react");
34
+
35
+ // src/media-query/media-query.ts
36
+ var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
37
+ var COARSE_POINTER_QUERY = "(pointer: coarse)";
38
+ var lists = /* @__PURE__ */ new WeakMap();
39
+ function getList(query) {
40
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return null;
41
+ const owner = window.matchMedia;
42
+ let byQuery = lists.get(owner);
43
+ if (!byQuery) {
44
+ byQuery = /* @__PURE__ */ new Map();
45
+ lists.set(owner, byQuery);
46
+ }
47
+ let list = byQuery.get(query);
48
+ if (!list) {
49
+ list = owner.call(window, query);
50
+ byQuery.set(query, list);
51
+ }
52
+ return list;
53
+ }
54
+ function getMatches(query) {
55
+ return getList(query)?.matches ?? null;
56
+ }
57
+ function subscribe(query, onChange) {
58
+ const list = getList(query);
59
+ if (!list) return () => {
60
+ };
61
+ if (typeof list.addEventListener === "function") {
62
+ list.addEventListener("change", onChange);
63
+ return () => list.removeEventListener("change", onChange);
64
+ }
65
+ list.addListener(onChange);
66
+ return () => list.removeListener(onChange);
67
+ }
68
+
69
+ // src/media-query/use-media-query.ts
70
+ function useMediaQuery(query, options = {}) {
71
+ const serverDefault = options.serverDefault ?? false;
72
+ const subscribeToQuery = (0, import_react.useCallback)((onChange) => subscribe(query, onChange), [query]);
73
+ const getSnapshot = (0, import_react.useCallback)(() => getMatches(query) ?? serverDefault, [query, serverDefault]);
74
+ const getServerSnapshot = (0, import_react.useCallback)(() => serverDefault, [serverDefault]);
75
+ return (0, import_react.useSyncExternalStore)(subscribeToQuery, getSnapshot, getServerSnapshot);
76
+ }
77
+ function useReducedMotion(options) {
78
+ return useMediaQuery(REDUCED_MOTION_QUERY, options);
79
+ }
80
+ function useCoarsePointer(options) {
81
+ return useMediaQuery(COARSE_POINTER_QUERY, options);
82
+ }
83
+ // Annotate the CommonJS export names for ESM import in node:
84
+ 0 && (module.exports = {
85
+ COARSE_POINTER_QUERY,
86
+ REDUCED_MOTION_QUERY,
87
+ useCoarsePointer,
88
+ useMediaQuery,
89
+ useReducedMotion
90
+ });
@@ -0,0 +1,12 @@
1
+ interface UseMediaQueryOptions {
2
+ /** Value on the server, during hydration, and where `matchMedia` is missing. Default `false`. */
3
+ serverDefault?: boolean;
4
+ }
5
+ declare function useMediaQuery(query: string, options?: UseMediaQueryOptions): boolean;
6
+ declare function useReducedMotion(options?: UseMediaQueryOptions): boolean;
7
+ declare function useCoarsePointer(options?: UseMediaQueryOptions): boolean;
8
+
9
+ declare const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
10
+ declare const COARSE_POINTER_QUERY = "(pointer: coarse)";
11
+
12
+ export { COARSE_POINTER_QUERY, REDUCED_MOTION_QUERY, type UseMediaQueryOptions, useCoarsePointer, useMediaQuery, useReducedMotion };
@@ -0,0 +1,12 @@
1
+ interface UseMediaQueryOptions {
2
+ /** Value on the server, during hydration, and where `matchMedia` is missing. Default `false`. */
3
+ serverDefault?: boolean;
4
+ }
5
+ declare function useMediaQuery(query: string, options?: UseMediaQueryOptions): boolean;
6
+ declare function useReducedMotion(options?: UseMediaQueryOptions): boolean;
7
+ declare function useCoarsePointer(options?: UseMediaQueryOptions): boolean;
8
+
9
+ declare const REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
10
+ declare const COARSE_POINTER_QUERY = "(pointer: coarse)";
11
+
12
+ export { COARSE_POINTER_QUERY, REDUCED_MOTION_QUERY, type UseMediaQueryOptions, useCoarsePointer, useMediaQuery, useReducedMotion };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import {
3
+ COARSE_POINTER_QUERY,
4
+ REDUCED_MOTION_QUERY,
5
+ useCoarsePointer,
6
+ useMediaQuery,
7
+ useReducedMotion
8
+ } from "./chunk-UZADAINO.js";
9
+ export {
10
+ COARSE_POINTER_QUERY,
11
+ REDUCED_MOTION_QUERY,
12
+ useCoarsePointer,
13
+ useMediaQuery,
14
+ useReducedMotion
15
+ };