@sinlungtech/push-client 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +139 -0
- package/dist/index.mjs +138 -0
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -86,6 +86,28 @@ interface PushProviderProps {
|
|
|
86
86
|
autoSubscribe?: boolean;
|
|
87
87
|
children: React.ReactNode;
|
|
88
88
|
}
|
|
89
|
+
interface PushStatusIndicatorProps {
|
|
90
|
+
/**
|
|
91
|
+
* Optional title shown in the indicator.
|
|
92
|
+
* Default: "Notifications"
|
|
93
|
+
*/
|
|
94
|
+
title?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Show indicator even when notifications are fully enabled.
|
|
97
|
+
* Default: true
|
|
98
|
+
*/
|
|
99
|
+
showWhenEnabled?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Corner placement for the floating indicator.
|
|
102
|
+
* Default: "bottom-right"
|
|
103
|
+
*/
|
|
104
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
105
|
+
/**
|
|
106
|
+
* Optional z-index override.
|
|
107
|
+
* Default: 2147483000
|
|
108
|
+
*/
|
|
109
|
+
zIndex?: number;
|
|
110
|
+
}
|
|
89
111
|
|
|
90
112
|
interface PushContextValue {
|
|
91
113
|
/** Whether the browser supports Web Push */
|
|
@@ -131,6 +153,8 @@ interface PushContextValue {
|
|
|
131
153
|
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, showInPageAlerts, inPageAlertDurationMs, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
132
154
|
declare function usePush(): PushContextValue;
|
|
133
155
|
|
|
156
|
+
declare function PushStatusIndicator({ title, showWhenEnabled, position, zIndex, }: PushStatusIndicatorProps): react_jsx_runtime.JSX.Element | null;
|
|
157
|
+
|
|
134
158
|
declare function urlBase64ToUint8Array(base64String: string): ArrayBuffer;
|
|
135
159
|
|
|
136
|
-
export { type PushPayload, PushProvider, type PushProviderProps, type PushSubscription, urlBase64ToUint8Array, usePush };
|
|
160
|
+
export { type PushPayload, PushProvider, type PushProviderProps, PushStatusIndicator, type PushStatusIndicatorProps, type PushSubscription, urlBase64ToUint8Array, usePush };
|
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,28 @@ interface PushProviderProps {
|
|
|
86
86
|
autoSubscribe?: boolean;
|
|
87
87
|
children: React.ReactNode;
|
|
88
88
|
}
|
|
89
|
+
interface PushStatusIndicatorProps {
|
|
90
|
+
/**
|
|
91
|
+
* Optional title shown in the indicator.
|
|
92
|
+
* Default: "Notifications"
|
|
93
|
+
*/
|
|
94
|
+
title?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Show indicator even when notifications are fully enabled.
|
|
97
|
+
* Default: true
|
|
98
|
+
*/
|
|
99
|
+
showWhenEnabled?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Corner placement for the floating indicator.
|
|
102
|
+
* Default: "bottom-right"
|
|
103
|
+
*/
|
|
104
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
105
|
+
/**
|
|
106
|
+
* Optional z-index override.
|
|
107
|
+
* Default: 2147483000
|
|
108
|
+
*/
|
|
109
|
+
zIndex?: number;
|
|
110
|
+
}
|
|
89
111
|
|
|
90
112
|
interface PushContextValue {
|
|
91
113
|
/** Whether the browser supports Web Push */
|
|
@@ -131,6 +153,8 @@ interface PushContextValue {
|
|
|
131
153
|
declare function PushProvider({ vapidKey, serviceWorkerPath, onSubscribe, onUnsubscribe, chatServerUrl, getToken, subscriptionsEndpoint, live, onLiveNotification, showInPageAlerts, inPageAlertDurationMs, autoSubscribe, children, }: PushProviderProps): react_jsx_runtime.JSX.Element;
|
|
132
154
|
declare function usePush(): PushContextValue;
|
|
133
155
|
|
|
156
|
+
declare function PushStatusIndicator({ title, showWhenEnabled, position, zIndex, }: PushStatusIndicatorProps): react_jsx_runtime.JSX.Element | null;
|
|
157
|
+
|
|
134
158
|
declare function urlBase64ToUint8Array(base64String: string): ArrayBuffer;
|
|
135
159
|
|
|
136
|
-
export { type PushPayload, PushProvider, type PushProviderProps, type PushSubscription, urlBase64ToUint8Array, usePush };
|
|
160
|
+
export { type PushPayload, PushProvider, type PushProviderProps, PushStatusIndicator, type PushStatusIndicatorProps, type PushSubscription, urlBase64ToUint8Array, usePush };
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
PushProvider: () => PushProvider,
|
|
34
|
+
PushStatusIndicator: () => PushStatusIndicator,
|
|
34
35
|
urlBase64ToUint8Array: () => urlBase64ToUint8Array,
|
|
35
36
|
usePush: () => usePush
|
|
36
37
|
});
|
|
@@ -383,9 +384,147 @@ function PushProvider({
|
|
|
383
384
|
function usePush() {
|
|
384
385
|
return (0, import_react.useContext)(PushContext);
|
|
385
386
|
}
|
|
387
|
+
|
|
388
|
+
// src/PushStatusIndicator.tsx
|
|
389
|
+
var import_react2 = require("react");
|
|
390
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
391
|
+
var POSITION_STYLES = {
|
|
392
|
+
"bottom-right": { right: 16, bottom: 16 },
|
|
393
|
+
"bottom-left": { left: 16, bottom: 16 },
|
|
394
|
+
"top-right": { right: 16, top: 16 },
|
|
395
|
+
"top-left": { left: 16, top: 16 }
|
|
396
|
+
};
|
|
397
|
+
function PushStatusIndicator({
|
|
398
|
+
title = "Notifications",
|
|
399
|
+
showWhenEnabled = true,
|
|
400
|
+
position = "bottom-right",
|
|
401
|
+
zIndex = 2147483e3
|
|
402
|
+
}) {
|
|
403
|
+
const { isSupported: isSupported2, permission, isSubscribed, subscribe, unsubscribe, error } = usePush();
|
|
404
|
+
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
405
|
+
const state = (0, import_react2.useMemo)(() => {
|
|
406
|
+
if (!isSupported2) return { label: "Not supported", tone: "#6b7280" };
|
|
407
|
+
if (permission === "denied") return { label: "Blocked in browser", tone: "#dc2626" };
|
|
408
|
+
if (permission === "granted" && isSubscribed) return { label: "Enabled", tone: "#16a34a" };
|
|
409
|
+
return { label: "Not enabled", tone: "#d97706" };
|
|
410
|
+
}, [isSupported2, permission, isSubscribed]);
|
|
411
|
+
if (!isSupported2) return null;
|
|
412
|
+
if (!showWhenEnabled && permission === "granted" && isSubscribed) return null;
|
|
413
|
+
const canEnable = permission !== "granted" || !isSubscribed;
|
|
414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
415
|
+
"div",
|
|
416
|
+
{
|
|
417
|
+
style: {
|
|
418
|
+
...POSITION_STYLES[position],
|
|
419
|
+
position: "fixed",
|
|
420
|
+
zIndex,
|
|
421
|
+
width: 320,
|
|
422
|
+
maxWidth: "calc(100vw - 32px)",
|
|
423
|
+
borderRadius: 12,
|
|
424
|
+
border: "1px solid #e5e7eb",
|
|
425
|
+
background: "#ffffff",
|
|
426
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.16)",
|
|
427
|
+
padding: 12,
|
|
428
|
+
fontFamily: "system-ui, sans-serif"
|
|
429
|
+
},
|
|
430
|
+
children: [
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }, children: [
|
|
432
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { margin: 0, fontSize: 13, fontWeight: 700, color: "#111827" }, children: title }),
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
434
|
+
"span",
|
|
435
|
+
{
|
|
436
|
+
style: {
|
|
437
|
+
display: "inline-flex",
|
|
438
|
+
alignItems: "center",
|
|
439
|
+
gap: 6,
|
|
440
|
+
fontSize: 11,
|
|
441
|
+
color: "#374151",
|
|
442
|
+
background: "#f9fafb",
|
|
443
|
+
border: "1px solid #e5e7eb",
|
|
444
|
+
borderRadius: 999,
|
|
445
|
+
padding: "2px 8px"
|
|
446
|
+
},
|
|
447
|
+
children: [
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
449
|
+
"span",
|
|
450
|
+
{
|
|
451
|
+
style: {
|
|
452
|
+
width: 8,
|
|
453
|
+
height: 8,
|
|
454
|
+
borderRadius: 999,
|
|
455
|
+
display: "inline-block",
|
|
456
|
+
background: state.tone
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
),
|
|
460
|
+
state.label
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
] }),
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { margin: "8px 0 0", fontSize: 12, color: "#6b7280", lineHeight: 1.35 }, children: permission === "denied" ? "Notifications are blocked. Re-enable in browser site settings, then click Retry." : "Enable notifications to receive alerts even when this tab is not active." }),
|
|
466
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { margin: "8px 0 0", fontSize: 12, color: "#dc2626", lineHeight: 1.35 }, children: error.message || "Push setup failed" }),
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 10, display: "flex", gap: 8 }, children: canEnable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
468
|
+
"button",
|
|
469
|
+
{
|
|
470
|
+
type: "button",
|
|
471
|
+
disabled: busy,
|
|
472
|
+
onClick: async () => {
|
|
473
|
+
setBusy(true);
|
|
474
|
+
try {
|
|
475
|
+
await subscribe();
|
|
476
|
+
} finally {
|
|
477
|
+
setBusy(false);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
style: {
|
|
481
|
+
border: "none",
|
|
482
|
+
borderRadius: 8,
|
|
483
|
+
padding: "7px 10px",
|
|
484
|
+
fontSize: 12,
|
|
485
|
+
fontWeight: 600,
|
|
486
|
+
color: "#fff",
|
|
487
|
+
background: "#111827",
|
|
488
|
+
cursor: busy ? "not-allowed" : "pointer",
|
|
489
|
+
opacity: busy ? 0.7 : 1
|
|
490
|
+
},
|
|
491
|
+
children: busy ? "Working..." : permission === "denied" ? "Retry" : "Enable"
|
|
492
|
+
}
|
|
493
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
494
|
+
"button",
|
|
495
|
+
{
|
|
496
|
+
type: "button",
|
|
497
|
+
disabled: busy,
|
|
498
|
+
onClick: async () => {
|
|
499
|
+
setBusy(true);
|
|
500
|
+
try {
|
|
501
|
+
await unsubscribe();
|
|
502
|
+
} finally {
|
|
503
|
+
setBusy(false);
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
style: {
|
|
507
|
+
border: "1px solid #e5e7eb",
|
|
508
|
+
borderRadius: 8,
|
|
509
|
+
padding: "7px 10px",
|
|
510
|
+
fontSize: 12,
|
|
511
|
+
fontWeight: 600,
|
|
512
|
+
color: "#374151",
|
|
513
|
+
background: "#fff",
|
|
514
|
+
cursor: busy ? "not-allowed" : "pointer",
|
|
515
|
+
opacity: busy ? 0.7 : 1
|
|
516
|
+
},
|
|
517
|
+
children: busy ? "Working..." : "Disable"
|
|
518
|
+
}
|
|
519
|
+
) })
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
);
|
|
523
|
+
}
|
|
386
524
|
// Annotate the CommonJS export names for ESM import in node:
|
|
387
525
|
0 && (module.exports = {
|
|
388
526
|
PushProvider,
|
|
527
|
+
PushStatusIndicator,
|
|
389
528
|
urlBase64ToUint8Array,
|
|
390
529
|
usePush
|
|
391
530
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -345,8 +345,146 @@ function PushProvider({
|
|
|
345
345
|
function usePush() {
|
|
346
346
|
return useContext(PushContext);
|
|
347
347
|
}
|
|
348
|
+
|
|
349
|
+
// src/PushStatusIndicator.tsx
|
|
350
|
+
import { useMemo, useState as useState2 } from "react";
|
|
351
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
352
|
+
var POSITION_STYLES = {
|
|
353
|
+
"bottom-right": { right: 16, bottom: 16 },
|
|
354
|
+
"bottom-left": { left: 16, bottom: 16 },
|
|
355
|
+
"top-right": { right: 16, top: 16 },
|
|
356
|
+
"top-left": { left: 16, top: 16 }
|
|
357
|
+
};
|
|
358
|
+
function PushStatusIndicator({
|
|
359
|
+
title = "Notifications",
|
|
360
|
+
showWhenEnabled = true,
|
|
361
|
+
position = "bottom-right",
|
|
362
|
+
zIndex = 2147483e3
|
|
363
|
+
}) {
|
|
364
|
+
const { isSupported: isSupported2, permission, isSubscribed, subscribe, unsubscribe, error } = usePush();
|
|
365
|
+
const [busy, setBusy] = useState2(false);
|
|
366
|
+
const state = useMemo(() => {
|
|
367
|
+
if (!isSupported2) return { label: "Not supported", tone: "#6b7280" };
|
|
368
|
+
if (permission === "denied") return { label: "Blocked in browser", tone: "#dc2626" };
|
|
369
|
+
if (permission === "granted" && isSubscribed) return { label: "Enabled", tone: "#16a34a" };
|
|
370
|
+
return { label: "Not enabled", tone: "#d97706" };
|
|
371
|
+
}, [isSupported2, permission, isSubscribed]);
|
|
372
|
+
if (!isSupported2) return null;
|
|
373
|
+
if (!showWhenEnabled && permission === "granted" && isSubscribed) return null;
|
|
374
|
+
const canEnable = permission !== "granted" || !isSubscribed;
|
|
375
|
+
return /* @__PURE__ */ jsxs2(
|
|
376
|
+
"div",
|
|
377
|
+
{
|
|
378
|
+
style: {
|
|
379
|
+
...POSITION_STYLES[position],
|
|
380
|
+
position: "fixed",
|
|
381
|
+
zIndex,
|
|
382
|
+
width: 320,
|
|
383
|
+
maxWidth: "calc(100vw - 32px)",
|
|
384
|
+
borderRadius: 12,
|
|
385
|
+
border: "1px solid #e5e7eb",
|
|
386
|
+
background: "#ffffff",
|
|
387
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.16)",
|
|
388
|
+
padding: 12,
|
|
389
|
+
fontFamily: "system-ui, sans-serif"
|
|
390
|
+
},
|
|
391
|
+
children: [
|
|
392
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }, children: [
|
|
393
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: 0, fontSize: 13, fontWeight: 700, color: "#111827" }, children: title }),
|
|
394
|
+
/* @__PURE__ */ jsxs2(
|
|
395
|
+
"span",
|
|
396
|
+
{
|
|
397
|
+
style: {
|
|
398
|
+
display: "inline-flex",
|
|
399
|
+
alignItems: "center",
|
|
400
|
+
gap: 6,
|
|
401
|
+
fontSize: 11,
|
|
402
|
+
color: "#374151",
|
|
403
|
+
background: "#f9fafb",
|
|
404
|
+
border: "1px solid #e5e7eb",
|
|
405
|
+
borderRadius: 999,
|
|
406
|
+
padding: "2px 8px"
|
|
407
|
+
},
|
|
408
|
+
children: [
|
|
409
|
+
/* @__PURE__ */ jsx2(
|
|
410
|
+
"span",
|
|
411
|
+
{
|
|
412
|
+
style: {
|
|
413
|
+
width: 8,
|
|
414
|
+
height: 8,
|
|
415
|
+
borderRadius: 999,
|
|
416
|
+
display: "inline-block",
|
|
417
|
+
background: state.tone
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
state.label
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
] }),
|
|
426
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0", fontSize: 12, color: "#6b7280", lineHeight: 1.35 }, children: permission === "denied" ? "Notifications are blocked. Re-enable in browser site settings, then click Retry." : "Enable notifications to receive alerts even when this tab is not active." }),
|
|
427
|
+
error && /* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0", fontSize: 12, color: "#dc2626", lineHeight: 1.35 }, children: error.message || "Push setup failed" }),
|
|
428
|
+
/* @__PURE__ */ jsx2("div", { style: { marginTop: 10, display: "flex", gap: 8 }, children: canEnable ? /* @__PURE__ */ jsx2(
|
|
429
|
+
"button",
|
|
430
|
+
{
|
|
431
|
+
type: "button",
|
|
432
|
+
disabled: busy,
|
|
433
|
+
onClick: async () => {
|
|
434
|
+
setBusy(true);
|
|
435
|
+
try {
|
|
436
|
+
await subscribe();
|
|
437
|
+
} finally {
|
|
438
|
+
setBusy(false);
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
style: {
|
|
442
|
+
border: "none",
|
|
443
|
+
borderRadius: 8,
|
|
444
|
+
padding: "7px 10px",
|
|
445
|
+
fontSize: 12,
|
|
446
|
+
fontWeight: 600,
|
|
447
|
+
color: "#fff",
|
|
448
|
+
background: "#111827",
|
|
449
|
+
cursor: busy ? "not-allowed" : "pointer",
|
|
450
|
+
opacity: busy ? 0.7 : 1
|
|
451
|
+
},
|
|
452
|
+
children: busy ? "Working..." : permission === "denied" ? "Retry" : "Enable"
|
|
453
|
+
}
|
|
454
|
+
) : /* @__PURE__ */ jsx2(
|
|
455
|
+
"button",
|
|
456
|
+
{
|
|
457
|
+
type: "button",
|
|
458
|
+
disabled: busy,
|
|
459
|
+
onClick: async () => {
|
|
460
|
+
setBusy(true);
|
|
461
|
+
try {
|
|
462
|
+
await unsubscribe();
|
|
463
|
+
} finally {
|
|
464
|
+
setBusy(false);
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
style: {
|
|
468
|
+
border: "1px solid #e5e7eb",
|
|
469
|
+
borderRadius: 8,
|
|
470
|
+
padding: "7px 10px",
|
|
471
|
+
fontSize: 12,
|
|
472
|
+
fontWeight: 600,
|
|
473
|
+
color: "#374151",
|
|
474
|
+
background: "#fff",
|
|
475
|
+
cursor: busy ? "not-allowed" : "pointer",
|
|
476
|
+
opacity: busy ? 0.7 : 1
|
|
477
|
+
},
|
|
478
|
+
children: busy ? "Working..." : "Disable"
|
|
479
|
+
}
|
|
480
|
+
) })
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
}
|
|
348
485
|
export {
|
|
349
486
|
PushProvider,
|
|
487
|
+
PushStatusIndicator,
|
|
350
488
|
urlBase64ToUint8Array,
|
|
351
489
|
usePush
|
|
352
490
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sinlungtech/push-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Web Push notification client for Next.js — service worker registration, permission handling, and subscription management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|