@develemit/web-hooks 0.2.0 → 0.3.1
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/CHANGELOG.md +18 -0
- package/README.md +157 -0
- package/dist/chunk-4PVVTQ5V.js +74 -0
- package/dist/{chunk-OZ4PU4E3.js → chunk-5XRVPZHD.js} +14 -4
- package/dist/{chunk-3UGRXQIA.js → chunk-DQBKU7HI.js} +10 -3
- package/dist/chunk-EXEJI4FK.js +43 -0
- package/dist/{chunk-3CACI4OQ.js → chunk-FE3BQD2I.js} +1 -25
- package/dist/chunk-HTVNN2NM.js +29 -0
- package/dist/chunk-R2PFNE3U.js +154 -0
- package/dist/chunk-TNEJ34T5.js +86 -0
- package/dist/chunk-UVJBJETY.js +121 -0
- package/dist/{chunk-UZADAINO.js → chunk-WVM2LTWQ.js} +2 -21
- package/dist/chunk-WXL22EWK.js +21 -0
- package/dist/chunk-YFMMSLMB.js +41 -0
- package/dist/chunk-Z3X27PCA.js +108 -0
- package/dist/clipboard.cjs +13 -0
- package/dist/clipboard.d.cts +10 -1
- package/dist/clipboard.d.ts +10 -1
- package/dist/clipboard.js +6 -2
- package/dist/drawer-swipe.cjs +16 -4
- package/dist/drawer-swipe.d.cts +7 -3
- package/dist/drawer-swipe.d.ts +7 -3
- package/dist/drawer-swipe.js +5 -1
- package/dist/index.cjs +637 -19
- package/dist/index.d.cts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +77 -7
- package/dist/keyboard-inset.cjs +113 -0
- package/dist/keyboard-inset.d.cts +25 -0
- package/dist/keyboard-inset.d.ts +25 -0
- package/dist/keyboard-inset.js +11 -0
- package/dist/media-query.js +5 -3
- package/dist/online-status.cjs +46 -0
- package/dist/online-status.d.cts +3 -0
- package/dist/online-status.d.ts +3 -0
- package/dist/online-status.js +7 -0
- package/dist/outside-press.cjs +10 -3
- package/dist/outside-press.d.cts +4 -2
- package/dist/outside-press.d.ts +4 -2
- package/dist/outside-press.js +1 -1
- package/dist/push.cjs +209 -0
- package/dist/push.d.cts +38 -0
- package/dist/push.d.ts +38 -0
- package/dist/push.js +14 -0
- package/dist/pwa.cjs +198 -0
- package/dist/pwa.d.cts +35 -0
- package/dist/pwa.d.ts +35 -0
- package/dist/pwa.js +22 -0
- package/dist/service-worker.cjs +148 -0
- package/dist/service-worker.d.cts +24 -0
- package/dist/service-worker.d.ts +24 -0
- package/dist/service-worker.js +11 -0
- package/dist/share.cjs +139 -0
- package/dist/share.d.cts +23 -0
- package/dist/share.d.ts +23 -0
- package/dist/share.js +16 -0
- package/package.json +31 -1
package/dist/index.cjs
CHANGED
|
@@ -24,30 +24,49 @@ __export(src_exports, {
|
|
|
24
24
|
BACK_ZONE_PX: () => BACK_ZONE_PX,
|
|
25
25
|
CLOSE_DISTANCE_PX: () => CLOSE_DISTANCE_PX,
|
|
26
26
|
COARSE_POINTER_QUERY: () => COARSE_POINTER_QUERY,
|
|
27
|
+
DEFAULT_IGNORE_SELECTOR: () => DEFAULT_IGNORE_SELECTOR,
|
|
27
28
|
FOCUSABLE_SELECTOR: () => FOCUSABLE_SELECTOR,
|
|
28
29
|
FORWARD_ZONE_PX: () => FORWARD_ZONE_PX,
|
|
29
30
|
MAX_SWIPE_DURATION_MS: () => MAX_SWIPE_DURATION_MS,
|
|
30
31
|
OPEN_DISTANCE_PX: () => OPEN_DISTANCE_PX,
|
|
31
32
|
REDUCED_MOTION_QUERY: () => REDUCED_MOTION_QUERY,
|
|
32
33
|
VERTICAL_CANCEL_PX: () => VERTICAL_CANCEL_PX,
|
|
34
|
+
canShareFiles: () => canShareFiles,
|
|
35
|
+
computeKeyboardInset: () => computeKeyboardInset,
|
|
33
36
|
copyText: () => copyText,
|
|
34
37
|
createDebouncer: () => createDebouncer,
|
|
38
|
+
deriveUpdateState: () => deriveUpdateState,
|
|
35
39
|
detectApple: () => detectApple,
|
|
40
|
+
detectPlatform: () => detectPlatform,
|
|
36
41
|
focusableWithin: () => focusableWithin,
|
|
42
|
+
getPushSupport: () => getPushSupport,
|
|
37
43
|
handleBeforeUnload: () => handleBeforeUnload,
|
|
44
|
+
isEditableElement: () => isEditableElement,
|
|
38
45
|
isEditableTarget: () => isEditableTarget,
|
|
46
|
+
isInIgnoredRegion: () => isInIgnoredRegion,
|
|
39
47
|
isInOpenZone: () => isInOpenZone,
|
|
40
48
|
isInsideHorizontalScroller: () => isInsideHorizontalScroller,
|
|
49
|
+
isIos: () => isIos,
|
|
50
|
+
isIosSafari: () => isIosSafari,
|
|
41
51
|
isOutside: () => isOutside,
|
|
42
52
|
isPrimaryPress: () => isPrimaryPress,
|
|
53
|
+
isShareCancel: () => isShareCancel,
|
|
54
|
+
isStandalone: () => isStandalone,
|
|
43
55
|
lockScroll: () => lockScroll,
|
|
44
56
|
matchHotkey: () => matchHotkey,
|
|
45
57
|
nextDelay: () => nextDelay,
|
|
46
58
|
nextFocusTarget: () => nextFocusTarget,
|
|
47
59
|
nextHeight: () => nextHeight,
|
|
48
60
|
parseHotkey: () => parseHotkey,
|
|
61
|
+
readText: () => readText,
|
|
49
62
|
resolveSwipeIntent: () => resolveSwipeIntent,
|
|
63
|
+
shareOrCopy: () => shareOrCopy,
|
|
64
|
+
shareTextFor: () => shareTextFor,
|
|
65
|
+
shouldResubscribe: () => shouldResubscribe,
|
|
66
|
+
startInstallPromptCapture: () => startInstallPromptCapture,
|
|
50
67
|
unlockScroll: () => unlockScroll,
|
|
68
|
+
unregisterAll: () => unregisterAll,
|
|
69
|
+
urlBase64ToUint8Array: () => urlBase64ToUint8Array,
|
|
51
70
|
useAutoGrowTextarea: () => useAutoGrowTextarea,
|
|
52
71
|
useCoarsePointer: () => useCoarsePointer,
|
|
53
72
|
useCopyFeedback: () => useCopyFeedback,
|
|
@@ -57,10 +76,17 @@ __export(src_exports, {
|
|
|
57
76
|
useEscape: () => useEscape,
|
|
58
77
|
useFocusTrap: () => useFocusTrap,
|
|
59
78
|
useHotkey: () => useHotkey,
|
|
79
|
+
useInstallPrompt: () => useInstallPrompt,
|
|
80
|
+
useIsStandalone: () => useIsStandalone,
|
|
81
|
+
useKeyboardInset: () => useKeyboardInset,
|
|
60
82
|
useMediaQuery: () => useMediaQuery,
|
|
83
|
+
useOnlineStatus: () => useOnlineStatus,
|
|
61
84
|
useOutsidePress: () => useOutsidePress,
|
|
85
|
+
usePushSubscription: () => usePushSubscription,
|
|
62
86
|
useReducedMotion: () => useReducedMotion,
|
|
63
87
|
useScrollLock: () => useScrollLock,
|
|
88
|
+
useServiceWorker: () => useServiceWorker,
|
|
89
|
+
useShareFeedback: () => useShareFeedback,
|
|
64
90
|
useStorageState: () => useStorageState,
|
|
65
91
|
useUnsavedChangesGuard: () => useUnsavedChangesGuard,
|
|
66
92
|
useVisibilityPolling: () => useVisibilityPolling
|
|
@@ -78,7 +104,8 @@ var HORIZONTAL_DOMINANCE = 1.5;
|
|
|
78
104
|
function isInOpenZone(x, viewportWidth) {
|
|
79
105
|
return x > BACK_ZONE_PX && x < viewportWidth - FORWARD_ZONE_PX;
|
|
80
106
|
}
|
|
81
|
-
function resolveSwipeIntent(start, end, drawerOpen, viewportWidth) {
|
|
107
|
+
function resolveSwipeIntent(start, end, drawerOpen, viewportWidth, startedInIgnoredRegion = false) {
|
|
108
|
+
if (startedInIgnoredRegion) return null;
|
|
82
109
|
const dx = end.x - start.x;
|
|
83
110
|
const dy = end.y - start.y;
|
|
84
111
|
if (end.time - start.time > MAX_SWIPE_DURATION_MS) return null;
|
|
@@ -100,6 +127,11 @@ function isInsideHorizontalScroller(target) {
|
|
|
100
127
|
}
|
|
101
128
|
return false;
|
|
102
129
|
}
|
|
130
|
+
var DEFAULT_IGNORE_SELECTOR = "[data-no-swipe]";
|
|
131
|
+
function isInIgnoredRegion(target, selector) {
|
|
132
|
+
if (!selector || !(target instanceof Element)) return false;
|
|
133
|
+
return target.closest(selector) !== null;
|
|
134
|
+
}
|
|
103
135
|
|
|
104
136
|
// src/drawer-swipe/use-drawer-swipe.ts
|
|
105
137
|
var import_react = require("react");
|
|
@@ -111,17 +143,19 @@ function useDrawerSwipe({
|
|
|
111
143
|
onOpen,
|
|
112
144
|
onClose,
|
|
113
145
|
enabled = true,
|
|
114
|
-
maxViewportWidth = 768
|
|
146
|
+
maxViewportWidth = 768,
|
|
147
|
+
ignoreSelector = DEFAULT_IGNORE_SELECTOR
|
|
115
148
|
}) {
|
|
116
149
|
const start = (0, import_react.useRef)(null);
|
|
117
|
-
const handlers = (0, import_react.useRef)({ drawerOpen, onOpen, onClose, maxViewportWidth });
|
|
118
|
-
handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth };
|
|
150
|
+
const handlers = (0, import_react.useRef)({ drawerOpen, onOpen, onClose, maxViewportWidth, ignoreSelector });
|
|
151
|
+
handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth, ignoreSelector };
|
|
119
152
|
(0, import_react.useEffect)(() => {
|
|
120
153
|
if (!enabled) return;
|
|
121
154
|
function handleStart(event) {
|
|
122
155
|
start.current = null;
|
|
123
156
|
if (event.touches.length !== 1) return;
|
|
124
157
|
if (isWideViewport(handlers.current.maxViewportWidth)) return;
|
|
158
|
+
if (isInIgnoredRegion(event.target, handlers.current.ignoreSelector)) return;
|
|
125
159
|
if (!handlers.current.drawerOpen && isInsideHorizontalScroller(event.target)) {
|
|
126
160
|
return;
|
|
127
161
|
}
|
|
@@ -322,6 +356,17 @@ function useCopyFeedback({ resetMs = 1500 } = {}) {
|
|
|
322
356
|
return { copy, status };
|
|
323
357
|
}
|
|
324
358
|
|
|
359
|
+
// src/clipboard/read-text.ts
|
|
360
|
+
async function readText() {
|
|
361
|
+
const hasClipboardApi = typeof navigator !== "undefined" && !!navigator.clipboard?.readText && typeof window !== "undefined" && window.isSecureContext;
|
|
362
|
+
if (!hasClipboardApi) return { ok: false, reason: "unavailable" };
|
|
363
|
+
try {
|
|
364
|
+
return { ok: true, text: await navigator.clipboard.readText() };
|
|
365
|
+
} catch {
|
|
366
|
+
return { ok: false, reason: "denied" };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
325
370
|
// src/scroll-lock/use-scroll-lock.ts
|
|
326
371
|
var import_react5 = require("react");
|
|
327
372
|
|
|
@@ -436,9 +481,9 @@ function subscribe(query, onChange) {
|
|
|
436
481
|
function useMediaQuery(query, options = {}) {
|
|
437
482
|
const serverDefault = options.serverDefault ?? false;
|
|
438
483
|
const subscribeToQuery = (0, import_react6.useCallback)((onChange) => subscribe(query, onChange), [query]);
|
|
439
|
-
const
|
|
440
|
-
const
|
|
441
|
-
return (0, import_react6.useSyncExternalStore)(subscribeToQuery,
|
|
484
|
+
const getSnapshot2 = (0, import_react6.useCallback)(() => getMatches(query) ?? serverDefault, [query, serverDefault]);
|
|
485
|
+
const getServerSnapshot2 = (0, import_react6.useCallback)(() => serverDefault, [serverDefault]);
|
|
486
|
+
return (0, import_react6.useSyncExternalStore)(subscribeToQuery, getSnapshot2, getServerSnapshot2);
|
|
442
487
|
}
|
|
443
488
|
function useReducedMotion(options) {
|
|
444
489
|
return useMediaQuery(REDUCED_MOTION_QUERY, options);
|
|
@@ -448,21 +493,28 @@ function useCoarsePointer(options) {
|
|
|
448
493
|
}
|
|
449
494
|
|
|
450
495
|
// src/outside-press/outside-press.ts
|
|
451
|
-
function isOutside(target, elements) {
|
|
496
|
+
function isOutside(target, elements, ignoreSelector) {
|
|
452
497
|
if (!target) return false;
|
|
453
498
|
if (!target.isConnected) return false;
|
|
499
|
+
if (ignoreSelector && isInIgnoredRegion2(target, ignoreSelector)) return false;
|
|
454
500
|
return !elements.some((el) => el?.contains(target));
|
|
455
501
|
}
|
|
456
502
|
function isPrimaryPress(event) {
|
|
457
503
|
return !(event.pointerType === "mouse" && event.button !== 0);
|
|
458
504
|
}
|
|
505
|
+
function isInIgnoredRegion2(target, selector) {
|
|
506
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
507
|
+
return element?.closest(selector) != null;
|
|
508
|
+
}
|
|
459
509
|
|
|
460
510
|
// src/outside-press/use-outside-press.ts
|
|
461
511
|
var import_react7 = require("react");
|
|
462
|
-
function useOutsidePress(refs, onOutsidePress, { enabled = true } = {}) {
|
|
512
|
+
function useOutsidePress(refs, onOutsidePress, { enabled = true, ignore } = {}) {
|
|
463
513
|
const refsRef = (0, import_react7.useRef)(refs);
|
|
464
514
|
const handlerRef = (0, import_react7.useRef)(onOutsidePress);
|
|
515
|
+
const ignoreRef = (0, import_react7.useRef)(ignore);
|
|
465
516
|
(0, import_react7.useEffect)(() => {
|
|
517
|
+
ignoreRef.current = ignore;
|
|
466
518
|
refsRef.current = refs;
|
|
467
519
|
handlerRef.current = onOutsidePress;
|
|
468
520
|
});
|
|
@@ -472,7 +524,7 @@ function useOutsidePress(refs, onOutsidePress, { enabled = true } = {}) {
|
|
|
472
524
|
if (!isPrimaryPress(event)) return;
|
|
473
525
|
const list = Array.isArray(refsRef.current) ? refsRef.current : [refsRef.current];
|
|
474
526
|
const elements = list.map((ref) => ref.current);
|
|
475
|
-
if (isOutside(event.target, elements)) handlerRef.current(event);
|
|
527
|
+
if (isOutside(event.target, elements, ignoreRef.current)) handlerRef.current(event);
|
|
476
528
|
}
|
|
477
529
|
document.addEventListener("pointerdown", onPointerDown, true);
|
|
478
530
|
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
@@ -690,9 +742,9 @@ function onStorageEvent(event) {
|
|
|
690
742
|
function subscribeToKey(kind, key, listener) {
|
|
691
743
|
const id = slot(kind, key);
|
|
692
744
|
const wasEmpty = listeners.size === 0;
|
|
693
|
-
let
|
|
694
|
-
if (!
|
|
695
|
-
|
|
745
|
+
let set2 = listeners.get(id);
|
|
746
|
+
if (!set2) listeners.set(id, set2 = /* @__PURE__ */ new Set());
|
|
747
|
+
set2.add(listener);
|
|
696
748
|
if (wasEmpty) window.addEventListener("storage", onStorageEvent);
|
|
697
749
|
return () => {
|
|
698
750
|
const current = listeners.get(id);
|
|
@@ -712,8 +764,8 @@ function useStorageState(key, defaultValue, options = {}) {
|
|
|
712
764
|
latest.current = { serialize, parse, defaultValue };
|
|
713
765
|
});
|
|
714
766
|
const cache = (0, import_react11.useRef)(null);
|
|
715
|
-
const
|
|
716
|
-
const
|
|
767
|
+
const subscribe3 = (0, import_react11.useCallback)((onChange) => subscribeToKey(kind, key, onChange), [kind, key]);
|
|
768
|
+
const getSnapshot2 = (0, import_react11.useCallback)(() => {
|
|
717
769
|
const raw = readCurrent(kind, key);
|
|
718
770
|
const hit = cache.current;
|
|
719
771
|
if (hit && hit.kind === kind && hit.key === key && hit.raw === raw && hit.parse === parse) return hit.value;
|
|
@@ -721,9 +773,9 @@ function useStorageState(key, defaultValue, options = {}) {
|
|
|
721
773
|
cache.current = { kind, key, raw, parse, value: value2 };
|
|
722
774
|
return value2;
|
|
723
775
|
}, [kind, key, parse, defaultValue]);
|
|
724
|
-
const
|
|
725
|
-
const value = (0, import_react11.useSyncExternalStore)(
|
|
726
|
-
const
|
|
776
|
+
const getServerSnapshot2 = (0, import_react11.useCallback)(() => defaultValue, [defaultValue]);
|
|
777
|
+
const value = (0, import_react11.useSyncExternalStore)(subscribe3, getSnapshot2, getServerSnapshot2);
|
|
778
|
+
const set2 = (0, import_react11.useCallback)(
|
|
727
779
|
(next) => {
|
|
728
780
|
const { serialize: encode, parse: decode, defaultValue: fallback } = latest.current;
|
|
729
781
|
try {
|
|
@@ -735,7 +787,7 @@ function useStorageState(key, defaultValue, options = {}) {
|
|
|
735
787
|
[kind, key]
|
|
736
788
|
);
|
|
737
789
|
const remove = (0, import_react11.useCallback)(() => removeCurrent(kind, key), [kind, key]);
|
|
738
|
-
return [value,
|
|
790
|
+
return [value, set2, remove];
|
|
739
791
|
}
|
|
740
792
|
|
|
741
793
|
// src/unsaved-guard/handle-before-unload.ts
|
|
@@ -870,35 +922,594 @@ function useAutoGrowTextarea(ref, value, { maxHeight } = {}) {
|
|
|
870
922
|
return () => target.removeEventListener("resize", resize);
|
|
871
923
|
}, [resize]);
|
|
872
924
|
}
|
|
925
|
+
|
|
926
|
+
// src/pwa/use-is-standalone.ts
|
|
927
|
+
var import_react15 = require("react");
|
|
928
|
+
|
|
929
|
+
// src/pwa/detect.ts
|
|
930
|
+
var IOS_UA = /iPhone|iPad|iPod/;
|
|
931
|
+
var IOS_OTHER_BROWSER = /CriOS|FxiOS|EdgiOS|OPiOS/;
|
|
932
|
+
var IN_APP_WEBVIEW = /FBAN|FBAV|Instagram/;
|
|
933
|
+
var STANDALONE_QUERY = "(display-mode: standalone)";
|
|
934
|
+
function detectPlatform(env) {
|
|
935
|
+
const isIos2 = IOS_UA.test(env.userAgent) || env.platform === "MacIntel" && env.maxTouchPoints > 1;
|
|
936
|
+
const isIosSafari2 = isIos2 && !IOS_OTHER_BROWSER.test(env.userAgent) && !IN_APP_WEBVIEW.test(env.userAgent);
|
|
937
|
+
return { isIos: isIos2, isIosSafari: isIosSafari2, isStandalone: env.standaloneMedia || env.navigatorStandalone };
|
|
938
|
+
}
|
|
939
|
+
function readStandaloneMedia() {
|
|
940
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
941
|
+
return window.matchMedia(STANDALONE_QUERY).matches;
|
|
942
|
+
}
|
|
943
|
+
function readNavigatorStandalone() {
|
|
944
|
+
if (typeof navigator === "undefined") return false;
|
|
945
|
+
return navigator.standalone === true;
|
|
946
|
+
}
|
|
947
|
+
function readPlatform() {
|
|
948
|
+
if (typeof navigator === "undefined") return { isIos: false, isIosSafari: false, isStandalone: false };
|
|
949
|
+
return detectPlatform({
|
|
950
|
+
userAgent: navigator.userAgent ?? "",
|
|
951
|
+
platform: navigator.platform ?? "",
|
|
952
|
+
maxTouchPoints: navigator.maxTouchPoints ?? 0,
|
|
953
|
+
standaloneMedia: readStandaloneMedia(),
|
|
954
|
+
navigatorStandalone: readNavigatorStandalone()
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
var isStandalone = () => readPlatform().isStandalone;
|
|
958
|
+
var isIos = () => readPlatform().isIos;
|
|
959
|
+
var isIosSafari = () => readPlatform().isIosSafari;
|
|
960
|
+
|
|
961
|
+
// src/pwa/use-is-standalone.ts
|
|
962
|
+
function useIsStandalone() {
|
|
963
|
+
const subscribeToMode = (0, import_react15.useCallback)((onChange) => subscribe(STANDALONE_QUERY, onChange), []);
|
|
964
|
+
return (0, import_react15.useSyncExternalStore)(subscribeToMode, isStandalone, () => false);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/pwa/use-install-prompt.ts
|
|
968
|
+
var import_react16 = require("react");
|
|
969
|
+
|
|
970
|
+
// src/pwa/install-store.ts
|
|
971
|
+
var state = { event: null, installed: false };
|
|
972
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
973
|
+
var permanent = false;
|
|
974
|
+
var holders = 0;
|
|
975
|
+
var attached = false;
|
|
976
|
+
function set(next) {
|
|
977
|
+
state = next;
|
|
978
|
+
subscribers.forEach((fn) => fn());
|
|
979
|
+
}
|
|
980
|
+
function onBeforeInstallPrompt(e) {
|
|
981
|
+
e.preventDefault();
|
|
982
|
+
set({ ...state, event: e });
|
|
983
|
+
}
|
|
984
|
+
function onAppInstalled() {
|
|
985
|
+
set({ event: null, installed: true });
|
|
986
|
+
}
|
|
987
|
+
function sync() {
|
|
988
|
+
const wanted = permanent || holders > 0;
|
|
989
|
+
if (wanted === attached || typeof window === "undefined") return;
|
|
990
|
+
attached = wanted;
|
|
991
|
+
const toggle = wanted ? window.addEventListener : window.removeEventListener;
|
|
992
|
+
toggle.call(window, "beforeinstallprompt", onBeforeInstallPrompt);
|
|
993
|
+
toggle.call(window, "appinstalled", onAppInstalled);
|
|
994
|
+
}
|
|
995
|
+
function startInstallPromptCapture() {
|
|
996
|
+
permanent = true;
|
|
997
|
+
sync();
|
|
998
|
+
}
|
|
999
|
+
function acquireCapture() {
|
|
1000
|
+
holders += 1;
|
|
1001
|
+
sync();
|
|
1002
|
+
let released = false;
|
|
1003
|
+
return () => {
|
|
1004
|
+
if (released) return;
|
|
1005
|
+
released = true;
|
|
1006
|
+
holders -= 1;
|
|
1007
|
+
sync();
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function getInstallState() {
|
|
1011
|
+
return state;
|
|
1012
|
+
}
|
|
1013
|
+
function subscribeInstallState(onChange) {
|
|
1014
|
+
subscribers.add(onChange);
|
|
1015
|
+
return () => {
|
|
1016
|
+
subscribers.delete(onChange);
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
async function promptInstall() {
|
|
1020
|
+
const event = state.event;
|
|
1021
|
+
if (!event) return "unavailable";
|
|
1022
|
+
set({ ...state, event: null });
|
|
1023
|
+
try {
|
|
1024
|
+
await event.prompt();
|
|
1025
|
+
const { outcome } = await event.userChoice;
|
|
1026
|
+
return outcome;
|
|
1027
|
+
} catch {
|
|
1028
|
+
return "dismissed";
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// src/pwa/use-install-prompt.ts
|
|
1033
|
+
var serverState = { event: null, installed: false };
|
|
1034
|
+
function useInstallPrompt() {
|
|
1035
|
+
const state2 = (0, import_react16.useSyncExternalStore)(subscribeInstallState, getInstallState, () => serverState);
|
|
1036
|
+
const standalone = useIsStandalone();
|
|
1037
|
+
const iosSafari = (0, import_react16.useSyncExternalStore)(
|
|
1038
|
+
() => () => {
|
|
1039
|
+
},
|
|
1040
|
+
isIosSafari,
|
|
1041
|
+
() => false
|
|
1042
|
+
);
|
|
1043
|
+
(0, import_react16.useEffect)(() => acquireCapture(), []);
|
|
1044
|
+
const installed = state2.installed || standalone;
|
|
1045
|
+
return {
|
|
1046
|
+
canPrompt: state2.event !== null && !installed,
|
|
1047
|
+
prompt: promptInstall,
|
|
1048
|
+
installed,
|
|
1049
|
+
needsIosInstructions: iosSafari && !installed
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// src/online-status/use-online-status.ts
|
|
1054
|
+
var import_react17 = require("react");
|
|
1055
|
+
function subscribe2(callback) {
|
|
1056
|
+
window.addEventListener("online", callback);
|
|
1057
|
+
window.addEventListener("offline", callback);
|
|
1058
|
+
return () => {
|
|
1059
|
+
window.removeEventListener("online", callback);
|
|
1060
|
+
window.removeEventListener("offline", callback);
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
var getSnapshot = () => navigator.onLine;
|
|
1064
|
+
var getServerSnapshot = () => true;
|
|
1065
|
+
function useOnlineStatus() {
|
|
1066
|
+
return (0, import_react17.useSyncExternalStore)(subscribe2, getSnapshot, getServerSnapshot);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// src/service-worker/use-service-worker.ts
|
|
1070
|
+
var import_react18 = require("react");
|
|
1071
|
+
|
|
1072
|
+
// src/service-worker/update-state.ts
|
|
1073
|
+
function deriveUpdateState({ hasController: hasController2, waiting, installingState }) {
|
|
1074
|
+
if (!hasController2) return false;
|
|
1075
|
+
return waiting || installingState === "installed";
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// src/service-worker/register.ts
|
|
1079
|
+
var reloaded = false;
|
|
1080
|
+
function isServiceWorkerSupported() {
|
|
1081
|
+
return typeof navigator !== "undefined" && "serviceWorker" in navigator;
|
|
1082
|
+
}
|
|
1083
|
+
var hasController = () => Boolean(navigator.serviceWorker.controller);
|
|
1084
|
+
async function unregisterAll() {
|
|
1085
|
+
if (!isServiceWorkerSupported()) return;
|
|
1086
|
+
try {
|
|
1087
|
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
|
1088
|
+
await Promise.all(registrations.map((r) => r.unregister()));
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function registerServiceWorker({ url, scope, onUpdateAvailable, onError }, { reload = () => window.location.reload() } = {}) {
|
|
1093
|
+
let registration;
|
|
1094
|
+
let disposed = false;
|
|
1095
|
+
let applying = false;
|
|
1096
|
+
const cleanups = [];
|
|
1097
|
+
const controlledAtStart = hasController();
|
|
1098
|
+
let activatedUnasked = false;
|
|
1099
|
+
const reloadOnce = () => {
|
|
1100
|
+
if (reloaded) return;
|
|
1101
|
+
reloaded = true;
|
|
1102
|
+
reload();
|
|
1103
|
+
};
|
|
1104
|
+
const onControllerChange = () => {
|
|
1105
|
+
if (applying) return reloadOnce();
|
|
1106
|
+
if (!controlledAtStart || activatedUnasked) return;
|
|
1107
|
+
activatedUnasked = true;
|
|
1108
|
+
onUpdateAvailable();
|
|
1109
|
+
};
|
|
1110
|
+
navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
|
|
1111
|
+
cleanups.push(() => navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange));
|
|
1112
|
+
const watchInstalling = (reg) => {
|
|
1113
|
+
const worker = reg.installing;
|
|
1114
|
+
if (!worker) return;
|
|
1115
|
+
const onState = () => {
|
|
1116
|
+
if (deriveUpdateState({ hasController: hasController(), waiting: false, installingState: worker.state })) {
|
|
1117
|
+
onUpdateAvailable();
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
worker.addEventListener("statechange", onState);
|
|
1121
|
+
cleanups.push(() => worker.removeEventListener("statechange", onState));
|
|
1122
|
+
};
|
|
1123
|
+
navigator.serviceWorker.register(url, scope === void 0 ? void 0 : { scope }).then((reg) => {
|
|
1124
|
+
if (disposed) return;
|
|
1125
|
+
registration = reg;
|
|
1126
|
+
if (deriveUpdateState({ hasController: hasController(), waiting: Boolean(reg.waiting) })) {
|
|
1127
|
+
onUpdateAvailable();
|
|
1128
|
+
}
|
|
1129
|
+
const onUpdateFound = () => watchInstalling(reg);
|
|
1130
|
+
reg.addEventListener("updatefound", onUpdateFound);
|
|
1131
|
+
cleanups.push(() => reg.removeEventListener("updatefound", onUpdateFound));
|
|
1132
|
+
}).catch((error) => {
|
|
1133
|
+
if (disposed) return;
|
|
1134
|
+
try {
|
|
1135
|
+
onError?.(error);
|
|
1136
|
+
} catch {
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
return {
|
|
1140
|
+
applyUpdate() {
|
|
1141
|
+
if (activatedUnasked) return reloadOnce();
|
|
1142
|
+
const waiting = registration?.waiting;
|
|
1143
|
+
if (!waiting) return;
|
|
1144
|
+
applying = true;
|
|
1145
|
+
waiting.postMessage({ type: "SKIP_WAITING" });
|
|
1146
|
+
},
|
|
1147
|
+
dispose() {
|
|
1148
|
+
disposed = true;
|
|
1149
|
+
cleanups.splice(0).forEach((fn) => fn());
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// src/service-worker/use-service-worker.ts
|
|
1155
|
+
function useServiceWorker({ url, scope, enabled = true, onError }) {
|
|
1156
|
+
const [supported, setSupported] = (0, import_react18.useState)(true);
|
|
1157
|
+
const [updateAvailable, setUpdateAvailable] = (0, import_react18.useState)(false);
|
|
1158
|
+
const onErrorRef = (0, import_react18.useRef)(onError);
|
|
1159
|
+
onErrorRef.current = onError;
|
|
1160
|
+
const handle = (0, import_react18.useRef)(void 0);
|
|
1161
|
+
(0, import_react18.useEffect)(() => {
|
|
1162
|
+
if (!enabled) return;
|
|
1163
|
+
if (!isServiceWorkerSupported()) {
|
|
1164
|
+
setSupported(false);
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
const registered = registerServiceWorker({
|
|
1168
|
+
url,
|
|
1169
|
+
scope,
|
|
1170
|
+
onUpdateAvailable: () => setUpdateAvailable(true),
|
|
1171
|
+
onError: (error) => onErrorRef.current?.(error)
|
|
1172
|
+
});
|
|
1173
|
+
handle.current = registered;
|
|
1174
|
+
return () => {
|
|
1175
|
+
registered.dispose();
|
|
1176
|
+
handle.current = void 0;
|
|
1177
|
+
};
|
|
1178
|
+
}, [url, scope, enabled]);
|
|
1179
|
+
const applyUpdate = (0, import_react18.useCallback)(() => handle.current?.applyUpdate(), []);
|
|
1180
|
+
return { supported, updateAvailable, applyUpdate };
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// src/share/share-text.ts
|
|
1184
|
+
function shareTextFor({ text, url }) {
|
|
1185
|
+
return [text, url].filter((part) => !!part).join("\n");
|
|
1186
|
+
}
|
|
1187
|
+
function isShareCancel(error) {
|
|
1188
|
+
return typeof error === "object" && error !== null && error.name === "AbortError";
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// src/share/share-or-copy.ts
|
|
1192
|
+
async function shareOrCopy(data) {
|
|
1193
|
+
if (canShareNatively(data)) {
|
|
1194
|
+
try {
|
|
1195
|
+
await navigator.share(data);
|
|
1196
|
+
return { status: "shared" };
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
if (isShareCancel(error)) return { status: "cancelled" };
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
const result = await copyText(shareTextFor(data));
|
|
1202
|
+
return { status: result.ok ? "copied" : "failed" };
|
|
1203
|
+
}
|
|
1204
|
+
function canShareFiles(files) {
|
|
1205
|
+
if (typeof navigator === "undefined" || typeof navigator.canShare !== "function") return false;
|
|
1206
|
+
try {
|
|
1207
|
+
return navigator.canShare({ files });
|
|
1208
|
+
} catch {
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
function canShareNatively(data) {
|
|
1213
|
+
if (typeof navigator === "undefined" || typeof navigator.share !== "function") return false;
|
|
1214
|
+
if (typeof navigator.canShare !== "function") return true;
|
|
1215
|
+
try {
|
|
1216
|
+
return navigator.canShare(data);
|
|
1217
|
+
} catch {
|
|
1218
|
+
return false;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// src/share/use-share-feedback.ts
|
|
1223
|
+
var import_react19 = require("react");
|
|
1224
|
+
function useShareFeedback({ resetMs = 1500 } = {}) {
|
|
1225
|
+
const [status, setStatus] = (0, import_react19.useState)("idle");
|
|
1226
|
+
const timerRef = (0, import_react19.useRef)(void 0);
|
|
1227
|
+
const clearTimer = (0, import_react19.useCallback)(() => {
|
|
1228
|
+
if (timerRef.current !== void 0) clearTimeout(timerRef.current);
|
|
1229
|
+
timerRef.current = void 0;
|
|
1230
|
+
}, []);
|
|
1231
|
+
(0, import_react19.useEffect)(() => clearTimer, [clearTimer]);
|
|
1232
|
+
const share = (0, import_react19.useCallback)(
|
|
1233
|
+
async (data) => {
|
|
1234
|
+
const result = await shareOrCopy(data);
|
|
1235
|
+
clearTimer();
|
|
1236
|
+
setStatus(result.status);
|
|
1237
|
+
timerRef.current = setTimeout(() => setStatus("idle"), resetMs);
|
|
1238
|
+
return result;
|
|
1239
|
+
},
|
|
1240
|
+
[clearTimer, resetMs]
|
|
1241
|
+
);
|
|
1242
|
+
return { share, status };
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// src/keyboard-inset/use-keyboard-inset.ts
|
|
1246
|
+
var import_react20 = require("react");
|
|
1247
|
+
|
|
1248
|
+
// src/keyboard-inset/compute-inset.ts
|
|
1249
|
+
var DEFAULT_MIN_INSET = 150;
|
|
1250
|
+
function computeKeyboardInset(r) {
|
|
1251
|
+
if (!r.editableFocused) return 0;
|
|
1252
|
+
const occluded = r.layoutHeight - r.visualHeight - r.visualOffsetTop;
|
|
1253
|
+
return occluded >= (r.minInset ?? DEFAULT_MIN_INSET) ? Math.round(occluded) : 0;
|
|
1254
|
+
}
|
|
1255
|
+
var NON_TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
1256
|
+
"button",
|
|
1257
|
+
"checkbox",
|
|
1258
|
+
"radio",
|
|
1259
|
+
"range",
|
|
1260
|
+
"submit",
|
|
1261
|
+
"reset",
|
|
1262
|
+
"file",
|
|
1263
|
+
"color",
|
|
1264
|
+
"image",
|
|
1265
|
+
"hidden"
|
|
1266
|
+
]);
|
|
1267
|
+
function isEditableElement(el) {
|
|
1268
|
+
if (!el) return false;
|
|
1269
|
+
const tag = el.tagName.toLowerCase();
|
|
1270
|
+
if (tag === "select") return !el.disabled;
|
|
1271
|
+
if (tag === "textarea" || tag === "input") {
|
|
1272
|
+
const field = el;
|
|
1273
|
+
if (field.readOnly || field.disabled) return false;
|
|
1274
|
+
return tag === "textarea" || !NON_TEXT_INPUT_TYPES.has(field.type);
|
|
1275
|
+
}
|
|
1276
|
+
if (el.isContentEditable === true) return true;
|
|
1277
|
+
const attr = el.getAttribute("contenteditable");
|
|
1278
|
+
return attr !== null && attr !== "false";
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// src/keyboard-inset/use-keyboard-inset.ts
|
|
1282
|
+
function useKeyboardInset({ minInset = DEFAULT_MIN_INSET, enabled = true } = {}) {
|
|
1283
|
+
const [inset, setInset] = (0, import_react20.useState)(0);
|
|
1284
|
+
(0, import_react20.useEffect)(() => {
|
|
1285
|
+
const vv = typeof window === "undefined" ? null : window.visualViewport;
|
|
1286
|
+
if (!enabled || !vv) {
|
|
1287
|
+
setInset(0);
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
const update = () => setInset(
|
|
1291
|
+
computeKeyboardInset({
|
|
1292
|
+
layoutHeight: window.innerHeight,
|
|
1293
|
+
visualHeight: vv.height,
|
|
1294
|
+
visualOffsetTop: vv.offsetTop,
|
|
1295
|
+
editableFocused: isEditableElement(document.activeElement),
|
|
1296
|
+
minInset
|
|
1297
|
+
})
|
|
1298
|
+
);
|
|
1299
|
+
let frame = 0;
|
|
1300
|
+
const onFocusOut = () => {
|
|
1301
|
+
cancelAnimationFrame(frame);
|
|
1302
|
+
frame = requestAnimationFrame(update);
|
|
1303
|
+
};
|
|
1304
|
+
const onFocusIn = () => {
|
|
1305
|
+
cancelAnimationFrame(frame);
|
|
1306
|
+
update();
|
|
1307
|
+
};
|
|
1308
|
+
vv.addEventListener("resize", update);
|
|
1309
|
+
vv.addEventListener("scroll", update);
|
|
1310
|
+
document.addEventListener("focusin", onFocusIn);
|
|
1311
|
+
document.addEventListener("focusout", onFocusOut);
|
|
1312
|
+
update();
|
|
1313
|
+
return () => {
|
|
1314
|
+
cancelAnimationFrame(frame);
|
|
1315
|
+
vv.removeEventListener("resize", update);
|
|
1316
|
+
vv.removeEventListener("scroll", update);
|
|
1317
|
+
document.removeEventListener("focusin", onFocusIn);
|
|
1318
|
+
document.removeEventListener("focusout", onFocusOut);
|
|
1319
|
+
};
|
|
1320
|
+
}, [enabled, minInset]);
|
|
1321
|
+
return inset;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/push/use-push-subscription.ts
|
|
1325
|
+
var import_react21 = require("react");
|
|
1326
|
+
|
|
1327
|
+
// src/push/support.ts
|
|
1328
|
+
function getPushSupport(env = readPushEnv()) {
|
|
1329
|
+
if (env.isIos && !env.isStandalone) return "ios-needs-install";
|
|
1330
|
+
if (!env.hasPushManager || !env.hasServiceWorker || !env.hasNotification) return "unsupported";
|
|
1331
|
+
return "supported";
|
|
1332
|
+
}
|
|
1333
|
+
function readPushEnv() {
|
|
1334
|
+
const browser = typeof window !== "undefined" && typeof navigator !== "undefined";
|
|
1335
|
+
return {
|
|
1336
|
+
hasPushManager: browser && "PushManager" in window,
|
|
1337
|
+
hasServiceWorker: browser && "serviceWorker" in navigator,
|
|
1338
|
+
hasNotification: browser && "Notification" in window,
|
|
1339
|
+
isIos: browser && isIos(),
|
|
1340
|
+
isStandalone: browser && isStandalone()
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
function readPermission() {
|
|
1344
|
+
if (typeof window === "undefined" || !("Notification" in window)) return "unsupported";
|
|
1345
|
+
return Notification.permission;
|
|
1346
|
+
}
|
|
1347
|
+
function isKeyReady(key) {
|
|
1348
|
+
return key.trim().length > 0;
|
|
1349
|
+
}
|
|
1350
|
+
function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey = true }) {
|
|
1351
|
+
return hasKey && resubscribeOnLoad && permission === "granted" && !hasSubscription;
|
|
1352
|
+
}
|
|
1353
|
+
function isGone(error) {
|
|
1354
|
+
return typeof error === "object" && error !== null && error.status === 410;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// src/push/vapid.ts
|
|
1358
|
+
function urlBase64ToUint8Array(key) {
|
|
1359
|
+
const padding = "=".repeat((4 - key.length % 4) % 4);
|
|
1360
|
+
const base64 = (key + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
1361
|
+
const raw = atob(base64);
|
|
1362
|
+
const out = new Uint8Array(raw.length);
|
|
1363
|
+
for (let i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
|
|
1364
|
+
return out;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// src/push/register.ts
|
|
1368
|
+
function subscribeFresh(reg, vapidPublicKey) {
|
|
1369
|
+
return reg.pushManager.subscribe({
|
|
1370
|
+
userVisibleOnly: true,
|
|
1371
|
+
// lib.dom wants ArrayBufferView<ArrayBuffer>; a Uint8Array satisfies the runtime contract.
|
|
1372
|
+
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
async function ensureSubscribed(reg, { vapidPublicKey, onSubscribe }, existing) {
|
|
1376
|
+
let sub = existing ?? await reg.pushManager.getSubscription() ?? await subscribeFresh(reg, vapidPublicKey);
|
|
1377
|
+
try {
|
|
1378
|
+
await onSubscribe(sub.toJSON());
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
if (!isGone(error)) throw error;
|
|
1381
|
+
await sub.unsubscribe();
|
|
1382
|
+
sub = await subscribeFresh(reg, vapidPublicKey);
|
|
1383
|
+
await onSubscribe(sub.toJSON());
|
|
1384
|
+
}
|
|
1385
|
+
return sub;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// src/push/use-push-subscription.ts
|
|
1389
|
+
var messageOf = (error, fallback) => error instanceof Error ? error.message : fallback;
|
|
1390
|
+
function usePushSubscription(options) {
|
|
1391
|
+
const { resubscribeOnLoad = true } = options;
|
|
1392
|
+
const [support, setSupport] = (0, import_react21.useState)("unsupported");
|
|
1393
|
+
const [permission, setPermission] = (0, import_react21.useState)("unsupported");
|
|
1394
|
+
const [subscribed, setSubscribed] = (0, import_react21.useState)(false);
|
|
1395
|
+
const [busy, setBusy] = (0, import_react21.useState)(false);
|
|
1396
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
1397
|
+
const hasKey = isKeyReady(options.vapidPublicKey);
|
|
1398
|
+
const latest = (0, import_react21.useRef)(options);
|
|
1399
|
+
latest.current = options;
|
|
1400
|
+
(0, import_react21.useEffect)(() => {
|
|
1401
|
+
const current = getPushSupport();
|
|
1402
|
+
setSupport(current);
|
|
1403
|
+
setPermission(readPermission());
|
|
1404
|
+
if (current !== "supported") return;
|
|
1405
|
+
let cancelled = false;
|
|
1406
|
+
(async () => {
|
|
1407
|
+
try {
|
|
1408
|
+
const reg = await navigator.serviceWorker.ready;
|
|
1409
|
+
const existing = await reg.pushManager.getSubscription();
|
|
1410
|
+
if (cancelled) return;
|
|
1411
|
+
const permissionNow = readPermission();
|
|
1412
|
+
setPermission(permissionNow);
|
|
1413
|
+
if (existing) return setSubscribed(true);
|
|
1414
|
+
if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad, hasKey })) return;
|
|
1415
|
+
await ensureSubscribed(reg, latest.current);
|
|
1416
|
+
if (!cancelled) setSubscribed(true);
|
|
1417
|
+
} catch {
|
|
1418
|
+
}
|
|
1419
|
+
})();
|
|
1420
|
+
return () => {
|
|
1421
|
+
cancelled = true;
|
|
1422
|
+
};
|
|
1423
|
+
}, [resubscribeOnLoad, hasKey]);
|
|
1424
|
+
const subscribe3 = (0, import_react21.useCallback)(async () => {
|
|
1425
|
+
if (getPushSupport() !== "supported") return;
|
|
1426
|
+
if (!isKeyReady(latest.current.vapidPublicKey)) {
|
|
1427
|
+
setError("push key not ready");
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
setError(null);
|
|
1431
|
+
setBusy(true);
|
|
1432
|
+
try {
|
|
1433
|
+
const result = await Notification.requestPermission();
|
|
1434
|
+
setPermission(result);
|
|
1435
|
+
if (result !== "granted") return;
|
|
1436
|
+
const reg = await navigator.serviceWorker.ready;
|
|
1437
|
+
await ensureSubscribed(reg, latest.current);
|
|
1438
|
+
setSubscribed(true);
|
|
1439
|
+
} catch (e) {
|
|
1440
|
+
setError(messageOf(e, "subscribe failed"));
|
|
1441
|
+
} finally {
|
|
1442
|
+
setBusy(false);
|
|
1443
|
+
}
|
|
1444
|
+
}, []);
|
|
1445
|
+
const unsubscribe = (0, import_react21.useCallback)(async () => {
|
|
1446
|
+
if (getPushSupport() !== "supported") return;
|
|
1447
|
+
setError(null);
|
|
1448
|
+
setBusy(true);
|
|
1449
|
+
try {
|
|
1450
|
+
const reg = await navigator.serviceWorker.ready;
|
|
1451
|
+
const sub = await reg.pushManager.getSubscription();
|
|
1452
|
+
if (sub) {
|
|
1453
|
+
await latest.current.onUnsubscribe(sub.endpoint);
|
|
1454
|
+
await sub.unsubscribe();
|
|
1455
|
+
}
|
|
1456
|
+
setSubscribed(false);
|
|
1457
|
+
} catch (e) {
|
|
1458
|
+
setError(messageOf(e, "unsubscribe failed"));
|
|
1459
|
+
} finally {
|
|
1460
|
+
setBusy(false);
|
|
1461
|
+
}
|
|
1462
|
+
}, []);
|
|
1463
|
+
return { support, permission, subscribed, busy, error, subscribe: subscribe3, unsubscribe };
|
|
1464
|
+
}
|
|
873
1465
|
// Annotate the CommonJS export names for ESM import in node:
|
|
874
1466
|
0 && (module.exports = {
|
|
875
1467
|
BACK_ZONE_PX,
|
|
876
1468
|
CLOSE_DISTANCE_PX,
|
|
877
1469
|
COARSE_POINTER_QUERY,
|
|
1470
|
+
DEFAULT_IGNORE_SELECTOR,
|
|
878
1471
|
FOCUSABLE_SELECTOR,
|
|
879
1472
|
FORWARD_ZONE_PX,
|
|
880
1473
|
MAX_SWIPE_DURATION_MS,
|
|
881
1474
|
OPEN_DISTANCE_PX,
|
|
882
1475
|
REDUCED_MOTION_QUERY,
|
|
883
1476
|
VERTICAL_CANCEL_PX,
|
|
1477
|
+
canShareFiles,
|
|
1478
|
+
computeKeyboardInset,
|
|
884
1479
|
copyText,
|
|
885
1480
|
createDebouncer,
|
|
1481
|
+
deriveUpdateState,
|
|
886
1482
|
detectApple,
|
|
1483
|
+
detectPlatform,
|
|
887
1484
|
focusableWithin,
|
|
1485
|
+
getPushSupport,
|
|
888
1486
|
handleBeforeUnload,
|
|
1487
|
+
isEditableElement,
|
|
889
1488
|
isEditableTarget,
|
|
1489
|
+
isInIgnoredRegion,
|
|
890
1490
|
isInOpenZone,
|
|
891
1491
|
isInsideHorizontalScroller,
|
|
1492
|
+
isIos,
|
|
1493
|
+
isIosSafari,
|
|
892
1494
|
isOutside,
|
|
893
1495
|
isPrimaryPress,
|
|
1496
|
+
isShareCancel,
|
|
1497
|
+
isStandalone,
|
|
894
1498
|
lockScroll,
|
|
895
1499
|
matchHotkey,
|
|
896
1500
|
nextDelay,
|
|
897
1501
|
nextFocusTarget,
|
|
898
1502
|
nextHeight,
|
|
899
1503
|
parseHotkey,
|
|
1504
|
+
readText,
|
|
900
1505
|
resolveSwipeIntent,
|
|
1506
|
+
shareOrCopy,
|
|
1507
|
+
shareTextFor,
|
|
1508
|
+
shouldResubscribe,
|
|
1509
|
+
startInstallPromptCapture,
|
|
901
1510
|
unlockScroll,
|
|
1511
|
+
unregisterAll,
|
|
1512
|
+
urlBase64ToUint8Array,
|
|
902
1513
|
useAutoGrowTextarea,
|
|
903
1514
|
useCoarsePointer,
|
|
904
1515
|
useCopyFeedback,
|
|
@@ -908,10 +1519,17 @@ function useAutoGrowTextarea(ref, value, { maxHeight } = {}) {
|
|
|
908
1519
|
useEscape,
|
|
909
1520
|
useFocusTrap,
|
|
910
1521
|
useHotkey,
|
|
1522
|
+
useInstallPrompt,
|
|
1523
|
+
useIsStandalone,
|
|
1524
|
+
useKeyboardInset,
|
|
911
1525
|
useMediaQuery,
|
|
1526
|
+
useOnlineStatus,
|
|
912
1527
|
useOutsidePress,
|
|
1528
|
+
usePushSubscription,
|
|
913
1529
|
useReducedMotion,
|
|
914
1530
|
useScrollLock,
|
|
1531
|
+
useServiceWorker,
|
|
1532
|
+
useShareFeedback,
|
|
915
1533
|
useStorageState,
|
|
916
1534
|
useUnsavedChangesGuard,
|
|
917
1535
|
useVisibilityPolling
|