@ox0/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 (54) hide show
  1. package/dist/index.d.ts +26 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +634 -9
  4. package/dist/use-before-unload-warning.d.ts +6 -0
  5. package/dist/use-before-unload-warning.d.ts.map +1 -0
  6. package/dist/use-breakpoint.d.ts +12 -0
  7. package/dist/use-breakpoint.d.ts.map +1 -0
  8. package/dist/use-container-size.d.ts +18 -0
  9. package/dist/use-container-size.d.ts.map +1 -0
  10. package/dist/use-controllable-state.d.ts +7 -0
  11. package/dist/use-controllable-state.d.ts.map +1 -0
  12. package/dist/use-copy-to-clipboard.d.ts +6 -0
  13. package/dist/use-copy-to-clipboard.d.ts.map +1 -0
  14. package/dist/use-debounced-value.d.ts +2 -0
  15. package/dist/use-debounced-value.d.ts.map +1 -0
  16. package/dist/use-deferred-presence.d.ts +15 -0
  17. package/dist/use-deferred-presence.d.ts.map +1 -0
  18. package/dist/use-disclosure.d.ts +8 -0
  19. package/dist/use-disclosure.d.ts.map +1 -0
  20. package/dist/use-event-listener.d.ts +5 -0
  21. package/dist/use-event-listener.d.ts.map +1 -0
  22. package/dist/use-hover.d.ts +5 -0
  23. package/dist/use-hover.d.ts.map +1 -0
  24. package/dist/use-interval.d.ts +2 -0
  25. package/dist/use-interval.d.ts.map +1 -0
  26. package/dist/use-key-down.d.ts +9 -0
  27. package/dist/use-key-down.d.ts.map +1 -0
  28. package/dist/use-long-press.d.ts +23 -0
  29. package/dist/use-long-press.d.ts.map +1 -0
  30. package/dist/use-media-query.d.ts +2 -0
  31. package/dist/use-media-query.d.ts.map +1 -0
  32. package/dist/use-navigator-online.d.ts +3 -0
  33. package/dist/use-navigator-online.d.ts.map +1 -0
  34. package/dist/use-now.d.ts +6 -0
  35. package/dist/use-now.d.ts.map +1 -0
  36. package/dist/use-os.d.ts +8 -0
  37. package/dist/use-os.d.ts.map +1 -0
  38. package/dist/use-pointer-coarse.d.ts +3 -0
  39. package/dist/use-pointer-coarse.d.ts.map +1 -0
  40. package/dist/use-prefers-reduced-motion.d.ts +3 -0
  41. package/dist/use-prefers-reduced-motion.d.ts.map +1 -0
  42. package/dist/use-press.d.ts +3 -0
  43. package/dist/use-press.d.ts.map +1 -0
  44. package/dist/use-previous.d.ts +2 -0
  45. package/dist/use-previous.d.ts.map +1 -0
  46. package/dist/use-stored-state.d.ts +23 -0
  47. package/dist/use-stored-state.d.ts.map +1 -0
  48. package/dist/use-timeout.d.ts +2 -0
  49. package/dist/use-timeout.d.ts.map +1 -0
  50. package/dist/use-viewport.d.ts +12 -0
  51. package/dist/use-viewport.d.ts.map +1 -0
  52. package/dist/use-window-size.d.ts +7 -0
  53. package/dist/use-window-size.d.ts.map +1 -0
  54. package/package.json +6 -2
@@ -0,0 +1,26 @@
1
+ export * from "./use-before-unload-warning";
2
+ export * from "./use-breakpoint";
3
+ export * from "./use-container-size";
4
+ export * from "./use-controllable-state";
5
+ export * from "./use-copy-to-clipboard";
6
+ export * from "./use-debounced-value";
7
+ export * from "./use-deferred-presence";
8
+ export * from "./use-disclosure";
9
+ export * from "./use-event-listener";
10
+ export * from "./use-hover";
11
+ export * from "./use-interval";
12
+ export * from "./use-key-down";
13
+ export * from "./use-stored-state";
14
+ export * from "./use-long-press";
15
+ export * from "./use-press";
16
+ export * from "./use-media-query";
17
+ export * from "./use-navigator-online";
18
+ export * from "./use-now";
19
+ export * from "./use-os";
20
+ export * from "./use-pointer-coarse";
21
+ export * from "./use-prefers-reduced-motion";
22
+ export * from "./use-previous";
23
+ export * from "./use-timeout";
24
+ export * from "./use-viewport";
25
+ export * from "./use-window-size";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,87 @@
1
1
  import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
2
+ import * as __WEBPACK_EXTERNAL_MODULE__react_aria_interactions_8422cce9__ from "@react-aria/interactions";
3
+ function useBeforeUnloadWarning(enabled) {
4
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
5
+ if (!enabled || "undefined" == typeof window) return;
6
+ const handle = (event)=>{
7
+ event.preventDefault();
8
+ event.returnValue = "";
9
+ };
10
+ window.addEventListener("beforeunload", handle);
11
+ return ()=>window.removeEventListener("beforeunload", handle);
12
+ }, [
13
+ enabled
14
+ ]);
15
+ }
16
+ const MOBILE_MAX = 767;
17
+ const TABLET_MAX = 1023;
18
+ function getBreakpoint() {
19
+ if ("undefined" == typeof window) return "desktop";
20
+ if (window.matchMedia(`(max-width: ${MOBILE_MAX}px)`).matches) return "mobile";
21
+ if (window.matchMedia(`(max-width: ${TABLET_MAX}px)`).matches) return "tablet";
22
+ return "desktop";
23
+ }
24
+ function toState(breakpoint) {
25
+ return {
26
+ breakpoint,
27
+ isMobile: "mobile" === breakpoint,
28
+ isTablet: "tablet" === breakpoint,
29
+ isDesktop: "desktop" === breakpoint,
30
+ isMobileOrTablet: "desktop" !== breakpoint,
31
+ isTabletOrDesktop: "mobile" !== breakpoint
32
+ };
33
+ }
34
+ function useBreakpoint() {
35
+ const [state, setState] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>toState(getBreakpoint()));
36
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
37
+ if ("undefined" == typeof window) return;
38
+ const mobileQuery = window.matchMedia(`(max-width: ${MOBILE_MAX}px)`);
39
+ const tabletQuery = window.matchMedia(`(max-width: ${TABLET_MAX}px)`);
40
+ const handleChange = ()=>{
41
+ setState((prev)=>{
42
+ const next = getBreakpoint();
43
+ return prev.breakpoint === next ? prev : toState(next);
44
+ });
45
+ };
46
+ handleChange();
47
+ mobileQuery.addEventListener("change", handleChange);
48
+ tabletQuery.addEventListener("change", handleChange);
49
+ return ()=>{
50
+ mobileQuery.removeEventListener("change", handleChange);
51
+ tabletQuery.removeEventListener("change", handleChange);
52
+ };
53
+ }, []);
54
+ return state;
55
+ }
56
+ function useContainerSize() {
57
+ const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
58
+ const [size, setSize] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)({
59
+ width: 0,
60
+ height: 0
61
+ });
62
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
63
+ const el = ref.current;
64
+ if (!el) return;
65
+ const observer = new ResizeObserver((entries)=>{
66
+ const rect = entries[0]?.contentRect;
67
+ if (rect) setSize({
68
+ width: rect.width,
69
+ height: rect.height
70
+ });
71
+ });
72
+ observer.observe(el);
73
+ const rect = el.getBoundingClientRect();
74
+ setSize({
75
+ width: rect.width,
76
+ height: rect.height
77
+ });
78
+ return ()=>observer.disconnect();
79
+ }, []);
80
+ return [
81
+ ref,
82
+ size
83
+ ];
84
+ }
2
85
  function useControllableState(options) {
3
86
  const { defaultValue, onChange, value } = options;
4
87
  const [uncontrolledValue, setUncontrolledValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(defaultValue);
@@ -19,6 +102,27 @@ function useControllableState(options) {
19
102
  setValue
20
103
  ];
21
104
  }
105
+ function useCopyToClipboard(resetMs = 2000) {
106
+ const [copied, setCopied] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
107
+ const timerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
108
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>()=>{
109
+ if (null !== timerRef.current) clearTimeout(timerRef.current);
110
+ }, []);
111
+ const copy = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(async (text)=>{
112
+ try {
113
+ await navigator.clipboard.writeText(text);
114
+ setCopied(true);
115
+ if (null !== timerRef.current) clearTimeout(timerRef.current);
116
+ timerRef.current = setTimeout(()=>setCopied(false), resetMs);
117
+ } catch {}
118
+ }, [
119
+ resetMs
120
+ ]);
121
+ return {
122
+ copy,
123
+ copied
124
+ };
125
+ }
22
126
  function useDebouncedValue(value, delay = 200) {
23
127
  const [debouncedValue, setDebouncedValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(value);
24
128
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
@@ -34,6 +138,50 @@ function useDebouncedValue(value, delay = 200) {
34
138
  ]);
35
139
  return debouncedValue;
36
140
  }
141
+ function useDeferredPresence(isPresent, { delayMs, exitMs, minimumVisibleMs }) {
142
+ const [state, setState] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)({
143
+ phase: "hidden"
144
+ });
145
+ const timerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(void 0);
146
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
147
+ clearTimeout(timerRef.current);
148
+ if (isPresent) {
149
+ if ("visible" === state.phase) return;
150
+ if ("exiting" === state.phase) {
151
+ setState({
152
+ phase: "visible",
153
+ shownAt: state.shownAt
154
+ });
155
+ return;
156
+ }
157
+ timerRef.current = window.setTimeout(()=>{
158
+ setState({
159
+ phase: "visible",
160
+ shownAt: Date.now()
161
+ });
162
+ }, delayMs);
163
+ } else if ("visible" === state.phase) {
164
+ const visibleMs = Date.now() - state.shownAt;
165
+ const delay = Math.max(0, minimumVisibleMs - visibleMs);
166
+ timerRef.current = window.setTimeout(()=>{
167
+ setState({
168
+ phase: "exiting",
169
+ shownAt: state.shownAt
170
+ });
171
+ }, delay);
172
+ } else if ("exiting" === state.phase) timerRef.current = window.setTimeout(()=>setState({
173
+ phase: "hidden"
174
+ }), exitMs);
175
+ return ()=>clearTimeout(timerRef.current);
176
+ }, [
177
+ delayMs,
178
+ exitMs,
179
+ isPresent,
180
+ minimumVisibleMs,
181
+ state
182
+ ]);
183
+ return state.phase;
184
+ }
37
185
  function useDisclosure(initialOpen = false) {
38
186
  const [isOpen, setIsOpen] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(initialOpen);
39
187
  const onClose = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
@@ -52,24 +200,368 @@ function useDisclosure(initialOpen = false) {
52
200
  onToggle
53
201
  };
54
202
  }
55
- function useLocalStorage(key, initialValue) {
56
- const [value, setValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>{
57
- if ("undefined" == typeof window) return initialValue;
58
- const storedValue = window.localStorage.getItem(key);
59
- return storedValue ? JSON.parse(storedValue) : initialValue;
60
- });
203
+ function useEventListener(type, listener, target) {
204
+ const listenerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(listener);
61
205
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
62
- if ("undefined" == typeof window) return;
63
- window.localStorage.setItem(key, JSON.stringify(value));
206
+ listenerRef.current = listener;
207
+ }, [
208
+ listener
209
+ ]);
210
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
211
+ const el = void 0 === target ? window : target && "current" in target ? target.current : target;
212
+ if (!el) return;
213
+ const handler = (e)=>listenerRef.current(e);
214
+ el.addEventListener(type, handler);
215
+ return ()=>el.removeEventListener(type, handler);
64
216
  }, [
217
+ type,
218
+ target
219
+ ]);
220
+ }
221
+ function useHover() {
222
+ const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
223
+ const [hovered, setHovered] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
224
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
225
+ const el = ref.current;
226
+ if (!el) return;
227
+ const enter = ()=>setHovered(true);
228
+ const leave = ()=>setHovered(false);
229
+ el.addEventListener("pointerenter", enter);
230
+ el.addEventListener("pointerleave", leave);
231
+ return ()=>{
232
+ el.removeEventListener("pointerenter", enter);
233
+ el.removeEventListener("pointerleave", leave);
234
+ };
235
+ }, []);
236
+ return [
237
+ ref,
238
+ hovered
239
+ ];
240
+ }
241
+ function useInterval(callback, delay) {
242
+ const callbackRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(callback);
243
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
244
+ callbackRef.current = callback;
245
+ }, [
246
+ callback
247
+ ]);
248
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
249
+ if (null === delay) return;
250
+ const id = window.setInterval(()=>callbackRef.current(), delay);
251
+ return ()=>window.clearInterval(id);
252
+ }, [
253
+ delay
254
+ ]);
255
+ }
256
+ function useKeyDown(key, callback, { ctrl = false, meta = false, shift = false, alt = false, enabled = true } = {}) {
257
+ const callbackRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(callback);
258
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
259
+ callbackRef.current = callback;
260
+ }, [
261
+ callback
262
+ ]);
263
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
264
+ if (!enabled) return;
265
+ const handler = (e)=>{
266
+ if (e.key !== key) return;
267
+ if (ctrl && !e.ctrlKey) return;
268
+ if (meta && !e.metaKey) return;
269
+ if (shift && !e.shiftKey) return;
270
+ if (alt && !e.altKey) return;
271
+ callbackRef.current(e);
272
+ };
273
+ window.addEventListener("keydown", handler);
274
+ return ()=>window.removeEventListener("keydown", handler);
275
+ }, [
276
+ key,
277
+ ctrl,
278
+ meta,
279
+ shift,
280
+ alt,
281
+ enabled
282
+ ]);
283
+ }
284
+ const instanceId = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
285
+ const tabSubscribers = new Map();
286
+ function tabSubscribe(key, fn) {
287
+ if (!tabSubscribers.has(key)) tabSubscribers.set(key, new Set());
288
+ tabSubscribers.get(key).add(fn);
289
+ return ()=>{
290
+ const set = tabSubscribers.get(key);
291
+ set?.delete(fn);
292
+ if (set?.size === 0) tabSubscribers.delete(key);
293
+ };
294
+ }
295
+ function tabNotify(key, value) {
296
+ tabSubscribers.get(key)?.forEach((fn)=>fn(value));
297
+ }
298
+ const crossTabSubscribers = new Map();
299
+ let broadcastChannel = null;
300
+ function getChannel() {
301
+ if ("undefined" == typeof window || "undefined" == typeof BroadcastChannel) return null;
302
+ if (!broadcastChannel) {
303
+ broadcastChannel = new BroadcastChannel("ox0:storage");
304
+ broadcastChannel.addEventListener("message", (e)=>{
305
+ crossTabSubscribers.get(e.data.key)?.forEach((fn)=>fn(e.data));
306
+ });
307
+ }
308
+ return broadcastChannel;
309
+ }
310
+ function crossTabSubscribe(key, fn) {
311
+ if (!crossTabSubscribers.has(key)) crossTabSubscribers.set(key, new Set());
312
+ crossTabSubscribers.get(key).add(fn);
313
+ getChannel();
314
+ return ()=>{
315
+ const set = crossTabSubscribers.get(key);
316
+ set?.delete(fn);
317
+ if (set?.size === 0) crossTabSubscribers.delete(key);
318
+ };
319
+ }
320
+ function getTabId() {
321
+ if ("undefined" == typeof sessionStorage) return instanceId;
322
+ const existing = sessionStorage.getItem("ox0:tab-id");
323
+ if (existing) return existing;
324
+ const next = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
325
+ sessionStorage.setItem("ox0:tab-id", next);
326
+ return next;
327
+ }
328
+ function getStorage(kind) {
329
+ if ("undefined" == typeof window) return null;
330
+ return "persistent" === kind ? window.localStorage : window.sessionStorage;
331
+ }
332
+ function makeStorageKey(key, kind, shared, scope) {
333
+ const scoped = null !== scope ? `${scope}:${key}` : key;
334
+ const base = "session" === kind ? `session:${scoped}` : scoped;
335
+ return shared ? base : `${base}::${getTabId()}`;
336
+ }
337
+ function readSafe(raw, parser, defaultValue, version, migrate) {
338
+ if (null === raw) return {
339
+ value: defaultValue,
340
+ migrated: false
341
+ };
342
+ try {
343
+ const parsed = JSON.parse(raw);
344
+ if (!parsed || "object" != typeof parsed || !("v" in parsed) || !("value" in parsed)) return {
345
+ value: defaultValue,
346
+ migrated: false
347
+ };
348
+ if (parsed.v !== version) return migrate ? {
349
+ value: migrate(parsed.value, parsed.v),
350
+ migrated: true
351
+ } : {
352
+ value: defaultValue,
353
+ migrated: false
354
+ };
355
+ return {
356
+ value: parser.parse(parsed.value),
357
+ migrated: false
358
+ };
359
+ } catch {
360
+ return {
361
+ value: defaultValue,
362
+ migrated: false
363
+ };
364
+ }
365
+ }
366
+ function writeStorage(storage, key, value, version) {
367
+ const payload = {
368
+ v: version,
369
+ value
370
+ };
371
+ const raw = JSON.stringify(payload);
372
+ try {
373
+ storage?.setItem(key, raw);
374
+ } catch {}
375
+ return raw;
376
+ }
377
+ const StorageScopeContext = (0, __WEBPACK_EXTERNAL_MODULE_react__.createContext)(void 0);
378
+ function StorageProvider({ scope, children }) {
379
+ return (0, __WEBPACK_EXTERNAL_MODULE_react__.createElement)(StorageScopeContext.Provider, {
380
+ value: scope
381
+ }, children);
382
+ }
383
+ function useStorageScope() {
384
+ const scope = (0, __WEBPACK_EXTERNAL_MODULE_react__.useContext)(StorageScopeContext);
385
+ if (void 0 === scope) throw new Error("useStoredState: no StorageProvider found. Wrap your app with <StorageProvider scope={userId ?? null}>.");
386
+ return scope;
387
+ }
388
+ function useStoredState(kind, key, parser, { defaultValue, version = 1, migrate }, shared) {
389
+ const scope = useStorageScope();
390
+ const storage = getStorage(kind);
391
+ const storageKey = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>makeStorageKey(key, kind, shared, scope), [
65
392
  key,
393
+ kind,
394
+ shared,
395
+ scope
396
+ ]);
397
+ const parserRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(parser);
398
+ const defaultValueRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(defaultValue);
399
+ const versionRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(version);
400
+ const migrateRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(migrate);
401
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
402
+ parserRef.current = parser;
403
+ defaultValueRef.current = defaultValue;
404
+ versionRef.current = version;
405
+ migrateRef.current = migrate;
406
+ });
407
+ const [value, setValueState] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>{
408
+ const raw = storage?.getItem(storageKey) ?? null;
409
+ const result = readSafe(raw, parser, defaultValue, version, migrate);
410
+ if (result.migrated) writeStorage(storage, storageKey, result.value, version);
411
+ return result.value;
412
+ });
413
+ const valueRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(value);
414
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
415
+ valueRef.current = value;
416
+ }, [
66
417
  value
67
418
  ]);
419
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
420
+ const raw = storage?.getItem(storageKey) ?? null;
421
+ const result = readSafe(raw, parserRef.current, defaultValueRef.current, versionRef.current, migrateRef.current);
422
+ setValueState((prev)=>Object.is(prev, result.value) ? prev : result.value);
423
+ if (result.migrated) writeStorage(storage, storageKey, result.value, versionRef.current);
424
+ }, [
425
+ storage,
426
+ storageKey
427
+ ]);
428
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>tabSubscribe(storageKey, (next)=>{
429
+ setValueState((prev)=>Object.is(prev, next) ? prev : next);
430
+ }), [
431
+ storageKey
432
+ ]);
433
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
434
+ if (!shared) return;
435
+ return crossTabSubscribe(storageKey, (msg)=>{
436
+ if (msg.storage !== kind || msg.sourceId === instanceId) return;
437
+ const result = readSafe(msg.payload, parserRef.current, defaultValueRef.current, versionRef.current, migrateRef.current);
438
+ setValueState((prev)=>Object.is(prev, result.value) ? prev : result.value);
439
+ tabNotify(storageKey, result.value);
440
+ if (result.migrated) writeStorage(storage, storageKey, result.value, versionRef.current);
441
+ });
442
+ }, [
443
+ kind,
444
+ shared,
445
+ storage,
446
+ storageKey
447
+ ]);
448
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
449
+ if (!shared || "persistent" !== kind || "undefined" == typeof window) return;
450
+ const handler = (event)=>{
451
+ if (event.key !== storageKey) return;
452
+ const result = readSafe(event.newValue, parserRef.current, defaultValueRef.current, versionRef.current, migrateRef.current);
453
+ setValueState((prev)=>Object.is(prev, result.value) ? prev : result.value);
454
+ tabNotify(storageKey, result.value);
455
+ if (result.migrated) writeStorage(storage, storageKey, result.value, versionRef.current);
456
+ };
457
+ window.addEventListener("storage", handler);
458
+ return ()=>window.removeEventListener("storage", handler);
459
+ }, [
460
+ kind,
461
+ shared,
462
+ storage,
463
+ storageKey
464
+ ]);
465
+ const setValue = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((next)=>{
466
+ const resolved = "function" == typeof next ? next(valueRef.current) : next;
467
+ if (Object.is(valueRef.current, resolved)) return;
468
+ valueRef.current = resolved;
469
+ setValueState(resolved);
470
+ const raw = writeStorage(storage, storageKey, resolved, versionRef.current);
471
+ tabNotify(storageKey, resolved);
472
+ if (shared) getChannel()?.postMessage({
473
+ key: storageKey,
474
+ payload: raw,
475
+ storage: kind,
476
+ sourceId: instanceId
477
+ });
478
+ }, [
479
+ kind,
480
+ shared,
481
+ storage,
482
+ storageKey
483
+ ]);
68
484
  return [
69
485
  value,
70
486
  setValue
71
487
  ];
72
488
  }
489
+ function usePersistentState(key, parser, options) {
490
+ return useStoredState("persistent", key, parser, options, false);
491
+ }
492
+ function usePersistentSharedState(key, parser, options) {
493
+ return useStoredState("persistent", key, parser, options, true);
494
+ }
495
+ function useSessionState(key, parser, options) {
496
+ return useStoredState("session", key, parser, options, false);
497
+ }
498
+ function useSessionSharedState(key, parser, options) {
499
+ return useStoredState("session", key, parser, options, true);
500
+ }
501
+ function useLongPress({ delayMs = 500, moveThresholdPx = 8, disabled = false, onLongPress }) {
502
+ const timerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
503
+ const pointerIdRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
504
+ const startRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
505
+ const triggeredRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(false);
506
+ const clearTimer = ()=>{
507
+ if (null == timerRef.current) return;
508
+ window.clearTimeout(timerRef.current);
509
+ timerRef.current = null;
510
+ };
511
+ const reset = ()=>{
512
+ clearTimer();
513
+ pointerIdRef.current = null;
514
+ startRef.current = null;
515
+ };
516
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
517
+ if (disabled) {
518
+ triggeredRef.current = false;
519
+ reset();
520
+ }
521
+ }, [
522
+ disabled
523
+ ]);
524
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>()=>clearTimer(), []);
525
+ return {
526
+ onPointerDown (event) {
527
+ if (disabled || 0 !== event.button) return;
528
+ const target = event.target instanceof HTMLElement ? event.target : null;
529
+ if (target?.closest("button,a,input,select,textarea")) return;
530
+ triggeredRef.current = false;
531
+ pointerIdRef.current = event.pointerId;
532
+ startRef.current = {
533
+ x: event.clientX,
534
+ y: event.clientY
535
+ };
536
+ clearTimer();
537
+ timerRef.current = window.setTimeout(()=>{
538
+ triggeredRef.current = true;
539
+ onLongPress();
540
+ }, delayMs);
541
+ },
542
+ onPointerMove (event) {
543
+ if (pointerIdRef.current !== event.pointerId || !startRef.current) return;
544
+ const dx = event.clientX - startRef.current.x;
545
+ const dy = event.clientY - startRef.current.y;
546
+ if (Math.hypot(dx, dy) > moveThresholdPx) reset();
547
+ },
548
+ onPointerUp (event) {
549
+ if (pointerIdRef.current !== event.pointerId) return;
550
+ clearTimer();
551
+ },
552
+ onPointerCancel (event) {
553
+ if (pointerIdRef.current !== event.pointerId) return;
554
+ reset();
555
+ },
556
+ onClickCapture (event) {
557
+ if (!triggeredRef.current) return;
558
+ event.preventDefault();
559
+ event.stopPropagation();
560
+ triggeredRef.current = false;
561
+ reset();
562
+ }
563
+ };
564
+ }
73
565
  function useMediaQuery(query) {
74
566
  const getMatches = ()=>"undefined" != typeof window && window.matchMedia(query).matches;
75
567
  const [matches, setMatches] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(getMatches);
@@ -89,4 +581,137 @@ function useMediaQuery(query) {
89
581
  ]);
90
582
  return matches;
91
583
  }
92
- export { useControllableState, useDebouncedValue, useDisclosure, useLocalStorage, useMediaQuery };
584
+ function useNavigatorOnline() {
585
+ const [isOnline, setIsOnline] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>"undefined" == typeof navigator ? true : navigator.onLine);
586
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
587
+ if ("undefined" == typeof window) return;
588
+ const sync = ()=>setIsOnline(navigator.onLine);
589
+ window.addEventListener("online", sync);
590
+ window.addEventListener("offline", sync);
591
+ return ()=>{
592
+ window.removeEventListener("online", sync);
593
+ window.removeEventListener("offline", sync);
594
+ };
595
+ }, []);
596
+ return isOnline;
597
+ }
598
+ function useNow({ update = 1000 } = {}) {
599
+ const [now, setNow] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>Date.now());
600
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
601
+ if (false === update) return;
602
+ const id = window.setInterval(()=>setNow(Date.now()), update);
603
+ return ()=>window.clearInterval(id);
604
+ }, [
605
+ update
606
+ ]);
607
+ return now;
608
+ }
609
+ function detectOS() {
610
+ if ("undefined" == typeof navigator) return "windows";
611
+ const ua = navigator.userAgent.toLowerCase();
612
+ const platform = (navigator.platform ?? "").toLowerCase();
613
+ const combined = `${ua} ${platform}`;
614
+ if (/iphone|ipad|ipod|android|mobile/.test(combined)) return "mobile";
615
+ if (/mac|macintosh|mac os x/.test(combined)) return "mac";
616
+ if (/win|windows/.test(combined)) return "windows";
617
+ if (/linux|x11/.test(combined)) return "linux";
618
+ return "windows";
619
+ }
620
+ function useOS(override) {
621
+ return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>override ?? detectOS(), [
622
+ override
623
+ ]);
624
+ }
625
+ function usePointerCoarse() {
626
+ return useMediaQuery("(pointer: coarse)");
627
+ }
628
+ function usePrefersReducedMotion() {
629
+ return useMediaQuery("(prefers-reduced-motion: reduce)");
630
+ }
631
+ function usePrevious(value) {
632
+ const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(void 0);
633
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
634
+ ref.current = value;
635
+ }, [
636
+ value
637
+ ]);
638
+ return ref.current;
639
+ }
640
+ function useTimeout(callback, delay) {
641
+ const callbackRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(callback);
642
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
643
+ callbackRef.current = callback;
644
+ }, [
645
+ callback
646
+ ]);
647
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
648
+ if (null === delay) return;
649
+ const id = window.setTimeout(()=>callbackRef.current(), delay);
650
+ return ()=>window.clearTimeout(id);
651
+ }, [
652
+ delay
653
+ ]);
654
+ }
655
+ const KEYBOARD_OPEN_DELTA = 150;
656
+ function getViewportState() {
657
+ if ("undefined" == typeof window) return {
658
+ visualViewportHeight: 0,
659
+ keyboardOpen: false
660
+ };
661
+ const visual = window.visualViewport?.height ?? window.innerHeight;
662
+ const layout = window.innerHeight;
663
+ return {
664
+ visualViewportHeight: visual,
665
+ keyboardOpen: layout - visual > KEYBOARD_OPEN_DELTA
666
+ };
667
+ }
668
+ function useViewport() {
669
+ const [state, setState] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(()=>getViewportState());
670
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
671
+ if ("undefined" == typeof window) return;
672
+ const target = window.visualViewport ?? window;
673
+ const handleChange = ()=>{
674
+ setState((prev)=>{
675
+ const next = getViewportState();
676
+ return prev.visualViewportHeight === next.visualViewportHeight && prev.keyboardOpen === next.keyboardOpen ? prev : next;
677
+ });
678
+ };
679
+ handleChange();
680
+ target.addEventListener("resize", handleChange);
681
+ window.addEventListener("resize", handleChange);
682
+ return ()=>{
683
+ target.removeEventListener("resize", handleChange);
684
+ window.removeEventListener("resize", handleChange);
685
+ };
686
+ }, []);
687
+ return state;
688
+ }
689
+ function getWindowSize() {
690
+ if ("undefined" == typeof window) return {
691
+ width: 0,
692
+ height: 0
693
+ };
694
+ return {
695
+ width: window.innerWidth,
696
+ height: window.innerHeight
697
+ };
698
+ }
699
+ function useWindowSize() {
700
+ const [size, setSize] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(getWindowSize);
701
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
702
+ if ("undefined" == typeof window) return;
703
+ const handleResize = ()=>{
704
+ setSize((prev)=>{
705
+ const next = getWindowSize();
706
+ return prev.width === next.width && prev.height === next.height ? prev : next;
707
+ });
708
+ };
709
+ handleResize();
710
+ window.addEventListener("resize", handleResize);
711
+ return ()=>window.removeEventListener("resize", handleResize);
712
+ }, []);
713
+ return size;
714
+ }
715
+ var __webpack_exports__isFocusVisible = __WEBPACK_EXTERNAL_MODULE__react_aria_interactions_8422cce9__.isFocusVisible;
716
+ var __webpack_exports__usePress = __WEBPACK_EXTERNAL_MODULE__react_aria_interactions_8422cce9__.usePress;
717
+ export { StorageProvider, useBeforeUnloadWarning, useBreakpoint, useContainerSize, useControllableState, useCopyToClipboard, useDebouncedValue, useDeferredPresence, useDisclosure, useEventListener, useHover, useInterval, useKeyDown, useLongPress, useMediaQuery, useNavigatorOnline, useNow, useOS, usePersistentSharedState, usePersistentState, usePointerCoarse, usePrefersReducedMotion, usePrevious, useSessionSharedState, useSessionState, useTimeout, useViewport, useWindowSize, __webpack_exports__isFocusVisible as isFocusVisible, __webpack_exports__usePress as usePress };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shows the browser's native "leave page?" dialog when `enabled` is true.
3
+ * Useful for unsaved-changes guards.
4
+ */
5
+ export declare function useBeforeUnloadWarning(enabled: boolean): void;
6
+ //# sourceMappingURL=use-before-unload-warning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-before-unload-warning.d.ts","sourceRoot":"","sources":["../src/use-before-unload-warning.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU7D"}
@@ -0,0 +1,12 @@
1
+ export type Breakpoint = "mobile" | "tablet" | "desktop";
2
+ export interface BreakpointState {
3
+ breakpoint: Breakpoint;
4
+ isMobile: boolean;
5
+ isTablet: boolean;
6
+ isDesktop: boolean;
7
+ isMobileOrTablet: boolean;
8
+ isTabletOrDesktop: boolean;
9
+ }
10
+ /** Tracks the current responsive breakpoint with boolean helpers. */
11
+ export declare function useBreakpoint(): BreakpointState;
12
+ //# sourceMappingURL=use-breakpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-breakpoint.d.ts","sourceRoot":"","sources":["../src/use-breakpoint.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAExD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,EAAE,OAAO,CAAA;IACzB,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAuBD,qEAAqE;AACrE,wBAAgB,aAAa,IAAI,eAAe,CAyB/C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Measures the content size of a DOM element using ResizeObserver.
3
+ * Returns a [ref, { width, height }] tuple. Attach the ref to the element you
4
+ * want to observe. Both values start at 0 and update on every resize.
5
+ *
6
+ * @example
7
+ * const [ref, { width, height }] = useContainerSize<HTMLDivElement>()
8
+ * const columns = width >= 960 ? 3 : width >= 640 ? 2 : 1
9
+ * return <div ref={ref}>...</div>
10
+ */
11
+ export declare function useContainerSize<T extends HTMLElement = HTMLDivElement>(): [
12
+ React.RefObject<T | null>,
13
+ {
14
+ width: number;
15
+ height: number;
16
+ }
17
+ ];
18
+ //# sourceMappingURL=use-container-size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-container-size.d.ts","sourceRoot":"","sources":["../src/use-container-size.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,GAAG,cAAc,KAAK;IAC1E,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC;IACzB;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;CAClC,CAqBA"}
@@ -0,0 +1,7 @@
1
+ export interface UseControllableStateOptions<TValue> {
2
+ readonly defaultValue: TValue;
3
+ readonly onChange?: (value: TValue) => void;
4
+ readonly value?: TValue;
5
+ }
6
+ export declare function useControllableState<TValue>(options: UseControllableStateOptions<TValue>): [TValue, (nextValue: TValue) => void];
7
+ //# sourceMappingURL=use-controllable-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-controllable-state.d.ts","sourceRoot":"","sources":["../src/use-controllable-state.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,2BAA2B,CAAC,MAAM;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,OAAO,EAAE,2BAA2B,CAAC,MAAM,CAAC,GAC3C,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,CAoBvC"}
@@ -0,0 +1,6 @@
1
+ export interface CopyToClipboardState {
2
+ copy: (text: string) => Promise<void>;
3
+ copied: boolean;
4
+ }
5
+ export declare function useCopyToClipboard(resetMs?: number): CopyToClipboardState;
6
+ //# sourceMappingURL=use-copy-to-clipboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-copy-to-clipboard.d.ts","sourceRoot":"","sources":["../src/use-copy-to-clipboard.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,SAAO,GAAG,oBAAoB,CAwBvE"}
@@ -0,0 +1,2 @@
1
+ export declare function useDebouncedValue<TValue>(value: TValue, delay?: number): TValue;
2
+ //# sourceMappingURL=use-debounced-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-debounced-value.d.ts","sourceRoot":"","sources":["../src/use-debounced-value.ts"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,MAAM,CAc5E"}
@@ -0,0 +1,15 @@
1
+ export type DeferredPresencePhase = "hidden" | "visible" | "exiting";
2
+ export interface DeferredPresenceOptions {
3
+ /** Delay before showing, in ms. */
4
+ delayMs: number;
5
+ /** Duration of exit animation, in ms. */
6
+ exitMs: number;
7
+ /** Minimum time the element stays visible before it can exit, in ms. */
8
+ minimumVisibleMs: number;
9
+ }
10
+ /**
11
+ * Manages show/hide lifecycle with entry delay, minimum visible time, and exit
12
+ * duration — useful for tooltips, toasts, and animated presence patterns.
13
+ */
14
+ export declare function useDeferredPresence(isPresent: boolean, { delayMs, exitMs, minimumVisibleMs }: DeferredPresenceOptions): DeferredPresencePhase;
15
+ //# sourceMappingURL=use-deferred-presence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-deferred-presence.d.ts","sourceRoot":"","sources":["../src/use-deferred-presence.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;AAIpE,MAAM,WAAW,uBAAuB;IACtC,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAA;IACd,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,OAAO,EAClB,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,uBAAuB,GAC7D,qBAAqB,CA8BvB"}
@@ -0,0 +1,8 @@
1
+ export interface DisclosureState {
2
+ readonly isOpen: boolean;
3
+ readonly onClose: () => void;
4
+ readonly onOpen: () => void;
5
+ readonly onToggle: () => void;
6
+ }
7
+ export declare function useDisclosure(initialOpen?: boolean): DisclosureState;
8
+ //# sourceMappingURL=use-disclosure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-disclosure.d.ts","sourceRoot":"","sources":["../src/use-disclosure.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,wBAAgB,aAAa,CAAC,WAAW,UAAQ,GAAG,eAAe,CAgBlE"}
@@ -0,0 +1,5 @@
1
+ import type { RefObject } from "react";
2
+ type Target = Window | Document | HTMLElement | null;
3
+ export declare function useEventListener<K extends keyof WindowEventMap>(type: K, listener: (event: WindowEventMap[K]) => void, target?: RefObject<HTMLElement | null> | Target): void;
4
+ export {};
5
+ //# sourceMappingURL=use-event-listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-event-listener.d.ts","sourceRoot":"","sources":["../src/use-event-listener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,KAAK,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAA;AAEpD,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7D,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EAC5C,MAAM,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,MAAM,GAC9C,IAAI,CAcN"}
@@ -0,0 +1,5 @@
1
+ export declare function useHover<T extends HTMLElement = HTMLElement>(): [
2
+ React.RefObject<T | null>,
3
+ boolean
4
+ ];
5
+ //# sourceMappingURL=use-hover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hover.d.ts","sourceRoot":"","sources":["../src/use-hover.ts"],"names":[],"mappings":"AAEA,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,KAAK;IAC/D,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC;IACzB,OAAO;CACR,CAkBA"}
@@ -0,0 +1,2 @@
1
+ export declare function useInterval(callback: () => void, delay: number | null): void;
2
+ //# sourceMappingURL=use-interval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-interval.d.ts","sourceRoot":"","sources":["../src/use-interval.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAW5E"}
@@ -0,0 +1,9 @@
1
+ export interface KeyDownOptions {
2
+ ctrl?: boolean;
3
+ meta?: boolean;
4
+ shift?: boolean;
5
+ alt?: boolean;
6
+ enabled?: boolean;
7
+ }
8
+ export declare function useKeyDown(key: string, callback: (event: KeyboardEvent) => void, { ctrl, meta, shift, alt, enabled }?: KeyDownOptions): void;
9
+ //# sourceMappingURL=use-key-down.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-key-down.d.ts","sourceRoot":"","sources":["../src/use-key-down.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACxC,EAAE,IAAY,EAAE,IAAY,EAAE,KAAa,EAAE,GAAW,EAAE,OAAc,EAAE,GAAE,cAAmB,GAC9F,IAAI,CAmBN"}
@@ -0,0 +1,23 @@
1
+ import type { MouseEvent as ReactMouseEvent, PointerEvent as ReactPointerEvent } from "react";
2
+ export interface UseLongPressOptions {
3
+ /** How long to hold before triggering, in ms. Default: 500. */
4
+ delayMs?: number;
5
+ /** Max pointer movement before the press is cancelled, in px. Default: 8. */
6
+ moveThresholdPx?: number;
7
+ /** When true, no long-press events fire. */
8
+ disabled?: boolean;
9
+ onLongPress: () => void;
10
+ }
11
+ /**
12
+ * Returns pointer event handlers that fire `onLongPress` after the pointer has
13
+ * been held for `delayMs` without moving beyond `moveThresholdPx`. Cancels on
14
+ * pointer up, cancel, or excessive movement. Suppresses the subsequent click.
15
+ */
16
+ export declare function useLongPress({ delayMs, moveThresholdPx, disabled, onLongPress, }: UseLongPressOptions): {
17
+ onPointerDown(event: ReactPointerEvent<HTMLElement>): void;
18
+ onPointerMove(event: ReactPointerEvent<HTMLElement>): void;
19
+ onPointerUp(event: ReactPointerEvent<HTMLElement>): void;
20
+ onPointerCancel(event: ReactPointerEvent<HTMLElement>): void;
21
+ onClickCapture(event: ReactMouseEvent<HTMLElement>): void;
22
+ };
23
+ //# sourceMappingURL=use-long-press.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-long-press.d.ts","sourceRoot":"","sources":["../src/use-long-press.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,IAAI,eAAe,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAG7F,MAAM,WAAW,mBAAmB;IAClC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAa,EACb,eAAmB,EACnB,QAAgB,EAChB,WAAW,GACZ,EAAE,mBAAmB;yBA4BG,iBAAiB,CAAC,WAAW,CAAC;yBAc9B,iBAAiB,CAAC,WAAW,CAAC;uBAMhC,iBAAiB,CAAC,WAAW,CAAC;2BAI1B,iBAAiB,CAAC,WAAW,CAAC;0BAI/B,eAAe,CAAC,WAAW,CAAC;EAQrD"}
@@ -0,0 +1,2 @@
1
+ export declare function useMediaQuery(query: string): boolean;
2
+ //# sourceMappingURL=use-media-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-media-query.d.ts","sourceRoot":"","sources":["../src/use-media-query.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAyBpD"}
@@ -0,0 +1,3 @@
1
+ /** Returns `true` when the browser reports a network connection. */
2
+ export declare function useNavigatorOnline(): boolean;
3
+ //# sourceMappingURL=use-navigator-online.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-navigator-online.d.ts","sourceRoot":"","sources":["../src/use-navigator-online.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,wBAAgB,kBAAkB,IAAI,OAAO,CAiB5C"}
@@ -0,0 +1,6 @@
1
+ type Options = {
2
+ update?: number | false;
3
+ };
4
+ export declare function useNow({ update }?: Options): number;
5
+ export {};
6
+ //# sourceMappingURL=use-now.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-now.d.ts","sourceRoot":"","sources":["../src/use-now.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CACxB,CAAA;AAED,wBAAgB,MAAM,CAAC,EAAE,MAAa,EAAE,GAAE,OAAY,GAAG,MAAM,CAU9D"}
@@ -0,0 +1,8 @@
1
+ export type OS = "mac" | "windows" | "linux" | "mobile";
2
+ /**
3
+ * Detects the runtime OS for keyboard shortcut and UI adaptation.
4
+ * For layout decisions use `useBreakpoint` instead.
5
+ * Pass `override` to force a value (tests, playground demos).
6
+ */
7
+ export declare function useOS(override?: OS): OS;
8
+ //# sourceMappingURL=use-os.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-os.d.ts","sourceRoot":"","sources":["../src/use-os.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,EAAE,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAcvD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAEvC"}
@@ -0,0 +1,3 @@
1
+ /** Returns `true` when the primary pointer device is coarse (touch screen). */
2
+ export declare function usePointerCoarse(): boolean;
3
+ //# sourceMappingURL=use-pointer-coarse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-pointer-coarse.d.ts","sourceRoot":"","sources":["../src/use-pointer-coarse.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -0,0 +1,3 @@
1
+ /** Returns `true` when the user has requested reduced motion. */
2
+ export declare function usePrefersReducedMotion(): boolean;
3
+ //# sourceMappingURL=use-prefers-reduced-motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-prefers-reduced-motion.d.ts","sourceRoot":"","sources":["../src/use-prefers-reduced-motion.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD"}
@@ -0,0 +1,3 @@
1
+ export { isFocusVisible, usePress } from "@react-aria/interactions";
2
+ export type { PressEvent, PressHookProps, PressProps, PressResult } from "@react-aria/interactions";
3
+ //# sourceMappingURL=use-press.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-press.d.ts","sourceRoot":"","sources":["../src/use-press.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function usePrevious<T>(value: T): T | undefined;
2
+ //# sourceMappingURL=use-previous.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-previous.d.ts","sourceRoot":"","sources":["../src/use-previous.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAMtD"}
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+ /** Anything with a `.parse` method — Zod schemas satisfy this directly. */
3
+ export type Parser<T> = {
4
+ parse: (value: unknown) => T;
5
+ };
6
+ export type StoredStateOptions<T> = {
7
+ defaultValue: T;
8
+ version?: number;
9
+ migrate?: (value: unknown, fromVersion: number) => T;
10
+ };
11
+ export declare function StorageProvider({ scope, children, }: {
12
+ scope: string | null;
13
+ children: ReactNode;
14
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<string | null | undefined>>;
15
+ /** localStorage, tab-private. */
16
+ export declare function usePersistentState<T>(key: string, parser: Parser<T>, options: StoredStateOptions<T>): [T, (next: T | ((prev: T) => T)) => void];
17
+ /** localStorage, shared across tabs. */
18
+ export declare function usePersistentSharedState<T>(key: string, parser: Parser<T>, options: StoredStateOptions<T>): [T, (next: T | ((prev: T) => T)) => void];
19
+ /** sessionStorage, tab-private. */
20
+ export declare function useSessionState<T>(key: string, parser: Parser<T>, options: StoredStateOptions<T>): [T, (next: T | ((prev: T) => T)) => void];
21
+ /** sessionStorage, shared within tab. */
22
+ export declare function useSessionSharedState<T>(key: string, parser: Parser<T>, options: StoredStateOptions<T>): [T, (next: T | ((prev: T) => T)) => void];
23
+ //# sourceMappingURL=use-stored-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-stored-state.d.ts","sourceRoot":"","sources":["../src/use-stored-state.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,2EAA2E;AAC3E,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,CAAA;CAAE,CAAA;AAExD,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI;IAClC,YAAY,EAAE,CAAC,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC,CAAA;CACrD,CAAA;AAkHD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,SAAS,CAAA;CACpB,sGAEA;AAuID,iCAAiC;AACjC,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,uCAzHO,IAAI,EA4H1C;AAED,wCAAwC;AACxC,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,uCAlIO,IAAI,EAqI1C;AAED,mCAAmC;AACnC,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,uCAxI1D,IAAI,EA0I1C;AAED,yCAAyC;AACzC,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,uCAhJO,IAAI,EAmJ1C"}
@@ -0,0 +1,2 @@
1
+ export declare function useTimeout(callback: () => void, delay: number | null): void;
2
+ //# sourceMappingURL=use-timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-timeout.d.ts","sourceRoot":"","sources":["../src/use-timeout.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAW3E"}
@@ -0,0 +1,12 @@
1
+ export interface ViewportState {
2
+ /** Height of the visual viewport (shrinks when the soft keyboard opens). */
3
+ visualViewportHeight: number;
4
+ /** True when the on-screen keyboard is likely open (mobile). */
5
+ keyboardOpen: boolean;
6
+ }
7
+ /**
8
+ * Tracks visual viewport height and whether the on-screen keyboard is open.
9
+ * Useful for mobile layouts that must avoid the keyboard.
10
+ */
11
+ export declare function useViewport(): ViewportState;
12
+ //# sourceMappingURL=use-viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-viewport.d.ts","sourceRoot":"","sources":["../src/use-viewport.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gEAAgE;IAChE,YAAY,EAAE,OAAO,CAAA;CACtB;AAWD;;;GAGG;AACH,wBAAgB,WAAW,IAAI,aAAa,CA2B3C"}
@@ -0,0 +1,7 @@
1
+ export interface WindowSize {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ /** Tracks the layout viewport dimensions (window.innerWidth / window.innerHeight). */
6
+ export declare function useWindowSize(): WindowSize;
7
+ //# sourceMappingURL=use-window-size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-window-size.d.ts","sourceRoot":"","sources":["../src/use-window-size.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAOD,sFAAsF;AACtF,wBAAgB,aAAa,IAAI,UAAU,CAmB1C"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@ox0/hooks",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": {
10
+ "source": "./src/index.ts",
10
11
  "import": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts"
12
13
  }
@@ -15,10 +16,13 @@
15
16
  "access": "public"
16
17
  },
17
18
  "dependencies": {
19
+ "@react-aria/interactions": "^3.28.1"
20
+ },
21
+ "peerDependencies": {
18
22
  "react": "^19.0.0"
19
23
  },
20
24
  "scripts": {
21
- "build": "rslib build -c ../../rslib.config.ts",
25
+ "build": "rslib build -c ../../rslib.config.ts && tsc --build --force tsconfig.build.json",
22
26
  "typecheck": "tsc -p tsconfig.json",
23
27
  "lint": "oxlint .",
24
28
  "test": "vitest run"