@develemit/web-hooks 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +145 -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-JG3GPTMY.js +101 -0
- package/dist/chunk-TNEJ34T5.js +86 -0
- package/dist/chunk-UJ366T3Y.js +146 -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 +609 -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 +201 -0
- package/dist/push.d.cts +37 -0
- package/dist/push.d.ts +37 -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 +128 -0
- package/dist/service-worker.d.cts +23 -0
- package/dist/service-worker.d.ts +23 -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/push.cjs
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
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/push/index.ts
|
|
22
|
+
var push_exports = {};
|
|
23
|
+
__export(push_exports, {
|
|
24
|
+
getPushSupport: () => getPushSupport,
|
|
25
|
+
shouldResubscribe: () => shouldResubscribe,
|
|
26
|
+
urlBase64ToUint8Array: () => urlBase64ToUint8Array,
|
|
27
|
+
usePushSubscription: () => usePushSubscription
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(push_exports);
|
|
30
|
+
|
|
31
|
+
// src/push/use-push-subscription.ts
|
|
32
|
+
var import_react = require("react");
|
|
33
|
+
|
|
34
|
+
// src/pwa/detect.ts
|
|
35
|
+
var IOS_UA = /iPhone|iPad|iPod/;
|
|
36
|
+
var IOS_OTHER_BROWSER = /CriOS|FxiOS|EdgiOS|OPiOS/;
|
|
37
|
+
var IN_APP_WEBVIEW = /FBAN|FBAV|Instagram/;
|
|
38
|
+
var STANDALONE_QUERY = "(display-mode: standalone)";
|
|
39
|
+
function detectPlatform(env) {
|
|
40
|
+
const isIos2 = IOS_UA.test(env.userAgent) || env.platform === "MacIntel" && env.maxTouchPoints > 1;
|
|
41
|
+
const isIosSafari = isIos2 && !IOS_OTHER_BROWSER.test(env.userAgent) && !IN_APP_WEBVIEW.test(env.userAgent);
|
|
42
|
+
return { isIos: isIos2, isIosSafari, isStandalone: env.standaloneMedia || env.navigatorStandalone };
|
|
43
|
+
}
|
|
44
|
+
function readStandaloneMedia() {
|
|
45
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
46
|
+
return window.matchMedia(STANDALONE_QUERY).matches;
|
|
47
|
+
}
|
|
48
|
+
function readNavigatorStandalone() {
|
|
49
|
+
if (typeof navigator === "undefined") return false;
|
|
50
|
+
return navigator.standalone === true;
|
|
51
|
+
}
|
|
52
|
+
function readPlatform() {
|
|
53
|
+
if (typeof navigator === "undefined") return { isIos: false, isIosSafari: false, isStandalone: false };
|
|
54
|
+
return detectPlatform({
|
|
55
|
+
userAgent: navigator.userAgent ?? "",
|
|
56
|
+
platform: navigator.platform ?? "",
|
|
57
|
+
maxTouchPoints: navigator.maxTouchPoints ?? 0,
|
|
58
|
+
standaloneMedia: readStandaloneMedia(),
|
|
59
|
+
navigatorStandalone: readNavigatorStandalone()
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
var isStandalone = () => readPlatform().isStandalone;
|
|
63
|
+
var isIos = () => readPlatform().isIos;
|
|
64
|
+
|
|
65
|
+
// src/push/support.ts
|
|
66
|
+
function getPushSupport(env = readPushEnv()) {
|
|
67
|
+
if (env.isIos && !env.isStandalone) return "ios-needs-install";
|
|
68
|
+
if (!env.hasPushManager || !env.hasServiceWorker || !env.hasNotification) return "unsupported";
|
|
69
|
+
return "supported";
|
|
70
|
+
}
|
|
71
|
+
function readPushEnv() {
|
|
72
|
+
const browser = typeof window !== "undefined" && typeof navigator !== "undefined";
|
|
73
|
+
return {
|
|
74
|
+
hasPushManager: browser && "PushManager" in window,
|
|
75
|
+
hasServiceWorker: browser && "serviceWorker" in navigator,
|
|
76
|
+
hasNotification: browser && "Notification" in window,
|
|
77
|
+
isIos: browser && isIos(),
|
|
78
|
+
isStandalone: browser && isStandalone()
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function readPermission() {
|
|
82
|
+
if (typeof window === "undefined" || !("Notification" in window)) return "unsupported";
|
|
83
|
+
return Notification.permission;
|
|
84
|
+
}
|
|
85
|
+
function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }) {
|
|
86
|
+
return resubscribeOnLoad && permission === "granted" && !hasSubscription;
|
|
87
|
+
}
|
|
88
|
+
function isGone(error) {
|
|
89
|
+
return typeof error === "object" && error !== null && error.status === 410;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/push/vapid.ts
|
|
93
|
+
function urlBase64ToUint8Array(key) {
|
|
94
|
+
const padding = "=".repeat((4 - key.length % 4) % 4);
|
|
95
|
+
const base64 = (key + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
96
|
+
const raw = atob(base64);
|
|
97
|
+
const out = new Uint8Array(raw.length);
|
|
98
|
+
for (let i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/push/register.ts
|
|
103
|
+
function subscribeFresh(reg, vapidPublicKey) {
|
|
104
|
+
return reg.pushManager.subscribe({
|
|
105
|
+
userVisibleOnly: true,
|
|
106
|
+
// lib.dom wants ArrayBufferView<ArrayBuffer>; a Uint8Array satisfies the runtime contract.
|
|
107
|
+
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async function ensureSubscribed(reg, { vapidPublicKey, onSubscribe }, existing) {
|
|
111
|
+
let sub = existing ?? await reg.pushManager.getSubscription() ?? await subscribeFresh(reg, vapidPublicKey);
|
|
112
|
+
try {
|
|
113
|
+
await onSubscribe(sub.toJSON());
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (!isGone(error)) throw error;
|
|
116
|
+
await sub.unsubscribe();
|
|
117
|
+
sub = await subscribeFresh(reg, vapidPublicKey);
|
|
118
|
+
await onSubscribe(sub.toJSON());
|
|
119
|
+
}
|
|
120
|
+
return sub;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/push/use-push-subscription.ts
|
|
124
|
+
var messageOf = (error, fallback) => error instanceof Error ? error.message : fallback;
|
|
125
|
+
function usePushSubscription(options) {
|
|
126
|
+
const { resubscribeOnLoad = true } = options;
|
|
127
|
+
const [support, setSupport] = (0, import_react.useState)("unsupported");
|
|
128
|
+
const [permission, setPermission] = (0, import_react.useState)("unsupported");
|
|
129
|
+
const [subscribed, setSubscribed] = (0, import_react.useState)(false);
|
|
130
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
131
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
132
|
+
const latest = (0, import_react.useRef)(options);
|
|
133
|
+
latest.current = options;
|
|
134
|
+
(0, import_react.useEffect)(() => {
|
|
135
|
+
const current = getPushSupport();
|
|
136
|
+
setSupport(current);
|
|
137
|
+
setPermission(readPermission());
|
|
138
|
+
if (current !== "supported") return;
|
|
139
|
+
let cancelled = false;
|
|
140
|
+
(async () => {
|
|
141
|
+
try {
|
|
142
|
+
const reg = await navigator.serviceWorker.ready;
|
|
143
|
+
const existing = await reg.pushManager.getSubscription();
|
|
144
|
+
if (cancelled) return;
|
|
145
|
+
const permissionNow = readPermission();
|
|
146
|
+
setPermission(permissionNow);
|
|
147
|
+
if (existing) return setSubscribed(true);
|
|
148
|
+
if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad })) return;
|
|
149
|
+
await ensureSubscribed(reg, latest.current);
|
|
150
|
+
if (!cancelled) setSubscribed(true);
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
})();
|
|
154
|
+
return () => {
|
|
155
|
+
cancelled = true;
|
|
156
|
+
};
|
|
157
|
+
}, [resubscribeOnLoad]);
|
|
158
|
+
const subscribe = (0, import_react.useCallback)(async () => {
|
|
159
|
+
if (getPushSupport() !== "supported") return;
|
|
160
|
+
setError(null);
|
|
161
|
+
setBusy(true);
|
|
162
|
+
try {
|
|
163
|
+
const result = await Notification.requestPermission();
|
|
164
|
+
setPermission(result);
|
|
165
|
+
if (result !== "granted") return;
|
|
166
|
+
const reg = await navigator.serviceWorker.ready;
|
|
167
|
+
await ensureSubscribed(reg, latest.current);
|
|
168
|
+
setSubscribed(true);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
setError(messageOf(e, "subscribe failed"));
|
|
171
|
+
} finally {
|
|
172
|
+
setBusy(false);
|
|
173
|
+
}
|
|
174
|
+
}, []);
|
|
175
|
+
const unsubscribe = (0, import_react.useCallback)(async () => {
|
|
176
|
+
if (getPushSupport() !== "supported") return;
|
|
177
|
+
setError(null);
|
|
178
|
+
setBusy(true);
|
|
179
|
+
try {
|
|
180
|
+
const reg = await navigator.serviceWorker.ready;
|
|
181
|
+
const sub = await reg.pushManager.getSubscription();
|
|
182
|
+
if (sub) {
|
|
183
|
+
await latest.current.onUnsubscribe(sub.endpoint);
|
|
184
|
+
await sub.unsubscribe();
|
|
185
|
+
}
|
|
186
|
+
setSubscribed(false);
|
|
187
|
+
} catch (e) {
|
|
188
|
+
setError(messageOf(e, "unsubscribe failed"));
|
|
189
|
+
} finally {
|
|
190
|
+
setBusy(false);
|
|
191
|
+
}
|
|
192
|
+
}, []);
|
|
193
|
+
return { support, permission, subscribed, busy, error, subscribe, unsubscribe };
|
|
194
|
+
}
|
|
195
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
196
|
+
0 && (module.exports = {
|
|
197
|
+
getPushSupport,
|
|
198
|
+
shouldResubscribe,
|
|
199
|
+
urlBase64ToUint8Array,
|
|
200
|
+
usePushSubscription
|
|
201
|
+
});
|
package/dist/push.d.cts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type PushSupport = 'supported' | 'unsupported' | 'ios-needs-install';
|
|
2
|
+
type PushPermission = NotificationPermission | 'unsupported';
|
|
3
|
+
interface PushEnv {
|
|
4
|
+
hasPushManager: boolean;
|
|
5
|
+
hasServiceWorker: boolean;
|
|
6
|
+
hasNotification: boolean;
|
|
7
|
+
isIos: boolean;
|
|
8
|
+
isStandalone: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function getPushSupport(env?: PushEnv): PushSupport;
|
|
11
|
+
interface ResubscribeInput {
|
|
12
|
+
permission: PushPermission;
|
|
13
|
+
hasSubscription: boolean;
|
|
14
|
+
resubscribeOnLoad: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }: ResubscribeInput): boolean;
|
|
17
|
+
|
|
18
|
+
interface UsePushSubscriptionOptions {
|
|
19
|
+
vapidPublicKey: string;
|
|
20
|
+
onSubscribe: (subscription: PushSubscriptionJSON) => Promise<unknown> | unknown;
|
|
21
|
+
onUnsubscribe: (endpoint: string) => Promise<unknown> | unknown;
|
|
22
|
+
resubscribeOnLoad?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface PushSubscriptionState {
|
|
25
|
+
support: PushSupport;
|
|
26
|
+
permission: PushPermission;
|
|
27
|
+
subscribed: boolean;
|
|
28
|
+
busy: boolean;
|
|
29
|
+
error: string | null;
|
|
30
|
+
subscribe: () => Promise<void>;
|
|
31
|
+
unsubscribe: () => Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
declare function usePushSubscription(options: UsePushSubscriptionOptions): PushSubscriptionState;
|
|
34
|
+
|
|
35
|
+
declare function urlBase64ToUint8Array(key: string): Uint8Array;
|
|
36
|
+
|
|
37
|
+
export { type PushEnv, type PushPermission, type PushSubscriptionState, type PushSupport, type ResubscribeInput, type UsePushSubscriptionOptions, getPushSupport, shouldResubscribe, urlBase64ToUint8Array, usePushSubscription };
|
package/dist/push.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type PushSupport = 'supported' | 'unsupported' | 'ios-needs-install';
|
|
2
|
+
type PushPermission = NotificationPermission | 'unsupported';
|
|
3
|
+
interface PushEnv {
|
|
4
|
+
hasPushManager: boolean;
|
|
5
|
+
hasServiceWorker: boolean;
|
|
6
|
+
hasNotification: boolean;
|
|
7
|
+
isIos: boolean;
|
|
8
|
+
isStandalone: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function getPushSupport(env?: PushEnv): PushSupport;
|
|
11
|
+
interface ResubscribeInput {
|
|
12
|
+
permission: PushPermission;
|
|
13
|
+
hasSubscription: boolean;
|
|
14
|
+
resubscribeOnLoad: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }: ResubscribeInput): boolean;
|
|
17
|
+
|
|
18
|
+
interface UsePushSubscriptionOptions {
|
|
19
|
+
vapidPublicKey: string;
|
|
20
|
+
onSubscribe: (subscription: PushSubscriptionJSON) => Promise<unknown> | unknown;
|
|
21
|
+
onUnsubscribe: (endpoint: string) => Promise<unknown> | unknown;
|
|
22
|
+
resubscribeOnLoad?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface PushSubscriptionState {
|
|
25
|
+
support: PushSupport;
|
|
26
|
+
permission: PushPermission;
|
|
27
|
+
subscribed: boolean;
|
|
28
|
+
busy: boolean;
|
|
29
|
+
error: string | null;
|
|
30
|
+
subscribe: () => Promise<void>;
|
|
31
|
+
unsubscribe: () => Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
declare function usePushSubscription(options: UsePushSubscriptionOptions): PushSubscriptionState;
|
|
34
|
+
|
|
35
|
+
declare function urlBase64ToUint8Array(key: string): Uint8Array;
|
|
36
|
+
|
|
37
|
+
export { type PushEnv, type PushPermission, type PushSubscriptionState, type PushSupport, type ResubscribeInput, type UsePushSubscriptionOptions, getPushSupport, shouldResubscribe, urlBase64ToUint8Array, usePushSubscription };
|
package/dist/push.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
getPushSupport,
|
|
4
|
+
shouldResubscribe,
|
|
5
|
+
urlBase64ToUint8Array,
|
|
6
|
+
usePushSubscription
|
|
7
|
+
} from "./chunk-UJ366T3Y.js";
|
|
8
|
+
import "./chunk-YFMMSLMB.js";
|
|
9
|
+
export {
|
|
10
|
+
getPushSupport,
|
|
11
|
+
shouldResubscribe,
|
|
12
|
+
urlBase64ToUint8Array,
|
|
13
|
+
usePushSubscription
|
|
14
|
+
};
|
package/dist/pwa.cjs
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
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/pwa/index.ts
|
|
22
|
+
var pwa_exports = {};
|
|
23
|
+
__export(pwa_exports, {
|
|
24
|
+
detectPlatform: () => detectPlatform,
|
|
25
|
+
isIos: () => isIos,
|
|
26
|
+
isIosSafari: () => isIosSafari,
|
|
27
|
+
isStandalone: () => isStandalone,
|
|
28
|
+
startInstallPromptCapture: () => startInstallPromptCapture,
|
|
29
|
+
useInstallPrompt: () => useInstallPrompt,
|
|
30
|
+
useIsStandalone: () => useIsStandalone
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(pwa_exports);
|
|
33
|
+
|
|
34
|
+
// src/pwa/use-is-standalone.ts
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
|
|
37
|
+
// src/media-query/media-query.ts
|
|
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 subscribe(query, onChange) {
|
|
55
|
+
const list = getList(query);
|
|
56
|
+
if (!list) return () => {
|
|
57
|
+
};
|
|
58
|
+
if (typeof list.addEventListener === "function") {
|
|
59
|
+
list.addEventListener("change", onChange);
|
|
60
|
+
return () => list.removeEventListener("change", onChange);
|
|
61
|
+
}
|
|
62
|
+
list.addListener(onChange);
|
|
63
|
+
return () => list.removeListener(onChange);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/pwa/detect.ts
|
|
67
|
+
var IOS_UA = /iPhone|iPad|iPod/;
|
|
68
|
+
var IOS_OTHER_BROWSER = /CriOS|FxiOS|EdgiOS|OPiOS/;
|
|
69
|
+
var IN_APP_WEBVIEW = /FBAN|FBAV|Instagram/;
|
|
70
|
+
var STANDALONE_QUERY = "(display-mode: standalone)";
|
|
71
|
+
function detectPlatform(env) {
|
|
72
|
+
const isIos2 = IOS_UA.test(env.userAgent) || env.platform === "MacIntel" && env.maxTouchPoints > 1;
|
|
73
|
+
const isIosSafari2 = isIos2 && !IOS_OTHER_BROWSER.test(env.userAgent) && !IN_APP_WEBVIEW.test(env.userAgent);
|
|
74
|
+
return { isIos: isIos2, isIosSafari: isIosSafari2, isStandalone: env.standaloneMedia || env.navigatorStandalone };
|
|
75
|
+
}
|
|
76
|
+
function readStandaloneMedia() {
|
|
77
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
78
|
+
return window.matchMedia(STANDALONE_QUERY).matches;
|
|
79
|
+
}
|
|
80
|
+
function readNavigatorStandalone() {
|
|
81
|
+
if (typeof navigator === "undefined") return false;
|
|
82
|
+
return navigator.standalone === true;
|
|
83
|
+
}
|
|
84
|
+
function readPlatform() {
|
|
85
|
+
if (typeof navigator === "undefined") return { isIos: false, isIosSafari: false, isStandalone: false };
|
|
86
|
+
return detectPlatform({
|
|
87
|
+
userAgent: navigator.userAgent ?? "",
|
|
88
|
+
platform: navigator.platform ?? "",
|
|
89
|
+
maxTouchPoints: navigator.maxTouchPoints ?? 0,
|
|
90
|
+
standaloneMedia: readStandaloneMedia(),
|
|
91
|
+
navigatorStandalone: readNavigatorStandalone()
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
var isStandalone = () => readPlatform().isStandalone;
|
|
95
|
+
var isIos = () => readPlatform().isIos;
|
|
96
|
+
var isIosSafari = () => readPlatform().isIosSafari;
|
|
97
|
+
|
|
98
|
+
// src/pwa/use-is-standalone.ts
|
|
99
|
+
function useIsStandalone() {
|
|
100
|
+
const subscribeToMode = (0, import_react.useCallback)((onChange) => subscribe(STANDALONE_QUERY, onChange), []);
|
|
101
|
+
return (0, import_react.useSyncExternalStore)(subscribeToMode, isStandalone, () => false);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/pwa/use-install-prompt.ts
|
|
105
|
+
var import_react2 = require("react");
|
|
106
|
+
|
|
107
|
+
// src/pwa/install-store.ts
|
|
108
|
+
var state = { event: null, installed: false };
|
|
109
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
110
|
+
var permanent = false;
|
|
111
|
+
var holders = 0;
|
|
112
|
+
var attached = false;
|
|
113
|
+
function set(next) {
|
|
114
|
+
state = next;
|
|
115
|
+
subscribers.forEach((fn) => fn());
|
|
116
|
+
}
|
|
117
|
+
function onBeforeInstallPrompt(e) {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
set({ ...state, event: e });
|
|
120
|
+
}
|
|
121
|
+
function onAppInstalled() {
|
|
122
|
+
set({ event: null, installed: true });
|
|
123
|
+
}
|
|
124
|
+
function sync() {
|
|
125
|
+
const wanted = permanent || holders > 0;
|
|
126
|
+
if (wanted === attached || typeof window === "undefined") return;
|
|
127
|
+
attached = wanted;
|
|
128
|
+
const toggle = wanted ? window.addEventListener : window.removeEventListener;
|
|
129
|
+
toggle.call(window, "beforeinstallprompt", onBeforeInstallPrompt);
|
|
130
|
+
toggle.call(window, "appinstalled", onAppInstalled);
|
|
131
|
+
}
|
|
132
|
+
function startInstallPromptCapture() {
|
|
133
|
+
permanent = true;
|
|
134
|
+
sync();
|
|
135
|
+
}
|
|
136
|
+
function acquireCapture() {
|
|
137
|
+
holders += 1;
|
|
138
|
+
sync();
|
|
139
|
+
let released = false;
|
|
140
|
+
return () => {
|
|
141
|
+
if (released) return;
|
|
142
|
+
released = true;
|
|
143
|
+
holders -= 1;
|
|
144
|
+
sync();
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function getInstallState() {
|
|
148
|
+
return state;
|
|
149
|
+
}
|
|
150
|
+
function subscribeInstallState(onChange) {
|
|
151
|
+
subscribers.add(onChange);
|
|
152
|
+
return () => {
|
|
153
|
+
subscribers.delete(onChange);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async function promptInstall() {
|
|
157
|
+
const event = state.event;
|
|
158
|
+
if (!event) return "unavailable";
|
|
159
|
+
set({ ...state, event: null });
|
|
160
|
+
try {
|
|
161
|
+
await event.prompt();
|
|
162
|
+
const { outcome } = await event.userChoice;
|
|
163
|
+
return outcome;
|
|
164
|
+
} catch {
|
|
165
|
+
return "dismissed";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/pwa/use-install-prompt.ts
|
|
170
|
+
var serverState = { event: null, installed: false };
|
|
171
|
+
function useInstallPrompt() {
|
|
172
|
+
const state2 = (0, import_react2.useSyncExternalStore)(subscribeInstallState, getInstallState, () => serverState);
|
|
173
|
+
const standalone = useIsStandalone();
|
|
174
|
+
const iosSafari = (0, import_react2.useSyncExternalStore)(
|
|
175
|
+
() => () => {
|
|
176
|
+
},
|
|
177
|
+
isIosSafari,
|
|
178
|
+
() => false
|
|
179
|
+
);
|
|
180
|
+
(0, import_react2.useEffect)(() => acquireCapture(), []);
|
|
181
|
+
const installed = state2.installed || standalone;
|
|
182
|
+
return {
|
|
183
|
+
canPrompt: state2.event !== null && !installed,
|
|
184
|
+
prompt: promptInstall,
|
|
185
|
+
installed,
|
|
186
|
+
needsIosInstructions: iosSafari && !installed
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
190
|
+
0 && (module.exports = {
|
|
191
|
+
detectPlatform,
|
|
192
|
+
isIos,
|
|
193
|
+
isIosSafari,
|
|
194
|
+
isStandalone,
|
|
195
|
+
startInstallPromptCapture,
|
|
196
|
+
useInstallPrompt,
|
|
197
|
+
useIsStandalone
|
|
198
|
+
});
|
package/dist/pwa.d.cts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
declare function useIsStandalone(): boolean;
|
|
2
|
+
|
|
3
|
+
/** Listens for the install events for the life of the page. Safe to call more than once. */
|
|
4
|
+
declare function startInstallPromptCapture(): void;
|
|
5
|
+
type PromptOutcome = 'accepted' | 'dismissed' | 'unavailable';
|
|
6
|
+
|
|
7
|
+
interface InstallPrompt {
|
|
8
|
+
/** A captured `beforeinstallprompt` is waiting, so `prompt()` can show the browser dialog. */
|
|
9
|
+
canPrompt: boolean;
|
|
10
|
+
prompt: () => Promise<PromptOutcome>;
|
|
11
|
+
/** Running as an installed app, or `appinstalled` fired. */
|
|
12
|
+
installed: boolean;
|
|
13
|
+
/** iOS Safari has no install event: show "Share, then Add to Home Screen". */
|
|
14
|
+
needsIosInstructions: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function useInstallPrompt(): InstallPrompt;
|
|
17
|
+
|
|
18
|
+
interface PlatformEnv {
|
|
19
|
+
userAgent: string;
|
|
20
|
+
platform: string;
|
|
21
|
+
maxTouchPoints: number;
|
|
22
|
+
standaloneMedia: boolean;
|
|
23
|
+
navigatorStandalone: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface Platform {
|
|
26
|
+
isIos: boolean;
|
|
27
|
+
isIosSafari: boolean;
|
|
28
|
+
isStandalone: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare function detectPlatform(env: PlatformEnv): Platform;
|
|
31
|
+
declare const isStandalone: () => boolean;
|
|
32
|
+
declare const isIos: () => boolean;
|
|
33
|
+
declare const isIosSafari: () => boolean;
|
|
34
|
+
|
|
35
|
+
export { type InstallPrompt, type Platform, type PlatformEnv, type PromptOutcome, detectPlatform, isIos, isIosSafari, isStandalone, startInstallPromptCapture, useInstallPrompt, useIsStandalone };
|
package/dist/pwa.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
declare function useIsStandalone(): boolean;
|
|
2
|
+
|
|
3
|
+
/** Listens for the install events for the life of the page. Safe to call more than once. */
|
|
4
|
+
declare function startInstallPromptCapture(): void;
|
|
5
|
+
type PromptOutcome = 'accepted' | 'dismissed' | 'unavailable';
|
|
6
|
+
|
|
7
|
+
interface InstallPrompt {
|
|
8
|
+
/** A captured `beforeinstallprompt` is waiting, so `prompt()` can show the browser dialog. */
|
|
9
|
+
canPrompt: boolean;
|
|
10
|
+
prompt: () => Promise<PromptOutcome>;
|
|
11
|
+
/** Running as an installed app, or `appinstalled` fired. */
|
|
12
|
+
installed: boolean;
|
|
13
|
+
/** iOS Safari has no install event: show "Share, then Add to Home Screen". */
|
|
14
|
+
needsIosInstructions: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare function useInstallPrompt(): InstallPrompt;
|
|
17
|
+
|
|
18
|
+
interface PlatformEnv {
|
|
19
|
+
userAgent: string;
|
|
20
|
+
platform: string;
|
|
21
|
+
maxTouchPoints: number;
|
|
22
|
+
standaloneMedia: boolean;
|
|
23
|
+
navigatorStandalone: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface Platform {
|
|
26
|
+
isIos: boolean;
|
|
27
|
+
isIosSafari: boolean;
|
|
28
|
+
isStandalone: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare function detectPlatform(env: PlatformEnv): Platform;
|
|
31
|
+
declare const isStandalone: () => boolean;
|
|
32
|
+
declare const isIos: () => boolean;
|
|
33
|
+
declare const isIosSafari: () => boolean;
|
|
34
|
+
|
|
35
|
+
export { type InstallPrompt, type Platform, type PlatformEnv, type PromptOutcome, detectPlatform, isIos, isIosSafari, isStandalone, startInstallPromptCapture, useInstallPrompt, useIsStandalone };
|
package/dist/pwa.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
startInstallPromptCapture,
|
|
4
|
+
useInstallPrompt,
|
|
5
|
+
useIsStandalone
|
|
6
|
+
} from "./chunk-Z3X27PCA.js";
|
|
7
|
+
import {
|
|
8
|
+
detectPlatform,
|
|
9
|
+
isIos,
|
|
10
|
+
isIosSafari,
|
|
11
|
+
isStandalone
|
|
12
|
+
} from "./chunk-YFMMSLMB.js";
|
|
13
|
+
import "./chunk-WVM2LTWQ.js";
|
|
14
|
+
export {
|
|
15
|
+
detectPlatform,
|
|
16
|
+
isIos,
|
|
17
|
+
isIosSafari,
|
|
18
|
+
isStandalone,
|
|
19
|
+
startInstallPromptCapture,
|
|
20
|
+
useInstallPrompt,
|
|
21
|
+
useIsStandalone
|
|
22
|
+
};
|