@asteby/metacore-pwa 0.5.1 → 0.6.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/dist/components/install-prompt.d.ts +8 -10
- package/dist/components/install-prompt.d.ts.map +1 -1
- package/dist/components/install-prompt.js +37 -32
- package/dist/components/install-prompt.js.map +1 -1
- package/dist/components/notification-permission-prompt.d.ts +6 -10
- package/dist/components/notification-permission-prompt.d.ts.map +1 -1
- package/dist/components/notification-permission-prompt.js +53 -45
- package/dist/components/notification-permission-prompt.js.map +1 -1
- package/dist/components/update-prompt.d.ts +8 -9
- package/dist/components/update-prompt.d.ts.map +1 -1
- package/dist/components/update-prompt.js +31 -16
- package/dist/components/update-prompt.js.map +1 -1
- package/package.json +3 -2
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ComponentType, type ReactNode } from 'react';
|
|
2
1
|
export interface InstallPromptMessages {
|
|
3
2
|
title?: string;
|
|
4
3
|
description?: string;
|
|
@@ -6,15 +5,14 @@ export interface InstallPromptMessages {
|
|
|
6
5
|
dismissLabel?: string;
|
|
7
6
|
}
|
|
8
7
|
export interface InstallPromptProps {
|
|
9
|
-
/** Optional custom button to render — receives onClick, children, variant and size. */
|
|
10
|
-
ButtonComponent?: ComponentType<{
|
|
11
|
-
onClick?: () => void;
|
|
12
|
-
children?: ReactNode;
|
|
13
|
-
variant?: 'default' | 'outline';
|
|
14
|
-
size?: 'sm';
|
|
15
|
-
}>;
|
|
16
8
|
messages?: InstallPromptMessages;
|
|
17
|
-
|
|
9
|
+
/** How long the toast stays before auto-dismissing (ms). Default: 10000. */
|
|
10
|
+
duration?: number;
|
|
18
11
|
}
|
|
19
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Renders through the shared notification toast (same card as bell/WS/SSE)
|
|
14
|
+
* instead of its own fixed-position banner, so it stacks with every other
|
|
15
|
+
* app notification rather than competing for a corner of the screen.
|
|
16
|
+
*/
|
|
17
|
+
export declare function PWAInstallPrompt({ messages, duration }?: InstallPromptProps): null;
|
|
20
18
|
//# sourceMappingURL=install-prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-prompt.d.ts","sourceRoot":"","sources":["../../src/components/install-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"install-prompt.d.ts","sourceRoot":"","sources":["../../src/components/install-prompt.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,qBAAqB,CAAA;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AASD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,GAAE,kBAAuB,QAmCvF"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { showNotificationToast } from '@asteby/metacore-notifications';
|
|
4
3
|
import { usePWAContext } from '../provider';
|
|
5
4
|
const DEFAULTS = {
|
|
6
5
|
title: 'Instalar App',
|
|
@@ -8,38 +7,44 @@ const DEFAULTS = {
|
|
|
8
7
|
installLabel: 'Instalar',
|
|
9
8
|
dismissLabel: 'Ahora no',
|
|
10
9
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return (_jsx("button", { type: "button", onClick: onClick, className: `${base} ${sizeClass} ${variantClass}`, children: children }));
|
|
18
|
-
}
|
|
19
|
-
export function PWAInstallPrompt({ ButtonComponent = DefaultButton, messages, className, } = {}) {
|
|
10
|
+
/**
|
|
11
|
+
* Renders through the shared notification toast (same card as bell/WS/SSE)
|
|
12
|
+
* instead of its own fixed-position banner, so it stacks with every other
|
|
13
|
+
* app notification rather than competing for a corner of the screen.
|
|
14
|
+
*/
|
|
15
|
+
export function PWAInstallPrompt({ messages, duration = 10000 } = {}) {
|
|
20
16
|
const { isInstallable, installApp } = usePWAContext();
|
|
21
|
-
const [show, setShow] = useState(false);
|
|
22
17
|
const msgs = { ...DEFAULTS, ...messages };
|
|
18
|
+
const shown = useRef(false);
|
|
23
19
|
useEffect(() => {
|
|
24
|
-
if (isInstallable)
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
if (!isInstallable || shown.current)
|
|
21
|
+
return;
|
|
22
|
+
if (typeof localStorage !== 'undefined' && localStorage.getItem('pwa-install-dismissed'))
|
|
23
|
+
return;
|
|
24
|
+
shown.current = true;
|
|
25
|
+
showNotificationToast({
|
|
26
|
+
title: msgs.title,
|
|
27
|
+
body: msgs.description,
|
|
28
|
+
type: 'info',
|
|
29
|
+
icon: 'download',
|
|
30
|
+
duration,
|
|
31
|
+
action: {
|
|
32
|
+
label: msgs.installLabel,
|
|
33
|
+
onClick: () => {
|
|
34
|
+
void installApp();
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
cancel: {
|
|
38
|
+
label: msgs.dismissLabel,
|
|
39
|
+
onClick: () => {
|
|
40
|
+
if (typeof localStorage !== 'undefined') {
|
|
41
|
+
localStorage.setItem('pwa-install-dismissed', 'true');
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
27
47
|
}, [isInstallable]);
|
|
28
|
-
|
|
29
|
-
const installed = await installApp();
|
|
30
|
-
if (installed) {
|
|
31
|
-
setShow(false);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
const handleDismiss = () => {
|
|
35
|
-
setShow(false);
|
|
36
|
-
if (typeof localStorage !== 'undefined') {
|
|
37
|
-
localStorage.setItem('pwa-install-dismissed', 'true');
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
if (!show || !isInstallable)
|
|
41
|
-
return null;
|
|
42
|
-
return (_jsxs("div", { className: className ??
|
|
43
|
-
'fixed top-4 right-4 z-50 max-w-sm rounded-lg border bg-background p-4 shadow-lg', children: [_jsx("button", { type: "button", onClick: handleDismiss, className: "absolute right-2 top-2 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100", "aria-label": "Dismiss", children: _jsx(X, { className: "h-4 w-4" }) }), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Download, { className: "h-5 w-5 mt-0.5" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "font-semibold", children: msgs.title }), _jsx("p", { className: "text-sm text-muted-foreground mt-1", children: msgs.description }), _jsxs("div", { className: "flex gap-2 mt-3", children: [_jsx(ButtonComponent, { onClick: handleInstall, size: "sm", children: msgs.installLabel }), _jsx(ButtonComponent, { onClick: handleDismiss, variant: "outline", size: "sm", children: msgs.dismissLabel })] })] })] })] }));
|
|
48
|
+
return null;
|
|
44
49
|
}
|
|
45
50
|
//# sourceMappingURL=install-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-prompt.js","sourceRoot":"","sources":["../../src/components/install-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"install-prompt.js","sourceRoot":"","sources":["../../src/components/install-prompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAe3C,MAAM,QAAQ,GAAoC;IAChD,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,2DAA2D;IACxE,YAAY,EAAE,UAAU;IACxB,YAAY,EAAE,UAAU;CACzB,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,KAAK,KAAyB,EAAE;IACtF,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,CAAA;IACrD,MAAM,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,aAAa,IAAI,KAAK,CAAC,OAAO;YAAE,OAAM;QAC3C,IAAI,OAAO,YAAY,KAAK,WAAW,IAAI,YAAY,CAAC,OAAO,CAAC,uBAAuB,CAAC;YAAE,OAAM;QAChG,KAAK,CAAC,OAAO,GAAG,IAAI,CAAA;QAEpB,qBAAqB,CAAC;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,UAAU;YAChB,QAAQ;YACR,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI,CAAC,YAAY;gBACxB,OAAO,EAAE,GAAG,EAAE;oBACZ,KAAK,UAAU,EAAE,CAAA;gBACnB,CAAC;aACF;YACD,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI,CAAC,YAAY;gBACxB,OAAO,EAAE,GAAG,EAAE;oBACZ,IAAI,OAAO,YAAY,KAAK,WAAW,EAAE,CAAC;wBACxC,YAAY,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAA;oBACvD,CAAC;gBACH,CAAC;aACF;SACF,CAAC,CAAA;QACF,uDAAuD;IACzD,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IAEnB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ComponentType, type ReactNode } from 'react';
|
|
2
1
|
export interface NotificationPermissionPromptMessages {
|
|
3
2
|
title?: string;
|
|
4
3
|
description?: string;
|
|
@@ -9,19 +8,16 @@ export interface NotificationPermissionPromptMessages {
|
|
|
9
8
|
blockedDescription?: string;
|
|
10
9
|
}
|
|
11
10
|
export interface NotificationPermissionPromptProps {
|
|
12
|
-
ButtonComponent?: ComponentType<{
|
|
13
|
-
onClick?: () => void;
|
|
14
|
-
children?: ReactNode;
|
|
15
|
-
variant?: 'default' | 'outline';
|
|
16
|
-
size?: 'sm';
|
|
17
|
-
className?: string;
|
|
18
|
-
}>;
|
|
19
11
|
messages?: NotificationPermissionPromptMessages;
|
|
20
12
|
/** Delay before auto-showing the prompt on mount (ms). Default: 2000. */
|
|
21
13
|
autoShowDelayMs?: number;
|
|
22
14
|
/** Reload the page after granting to sync state. Default: true. */
|
|
23
15
|
reloadOnGrant?: boolean;
|
|
24
|
-
className?: string;
|
|
25
16
|
}
|
|
26
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Renders through the shared notification toast instead of its own
|
|
19
|
+
* fixed-position banner, so it stacks with every other app notification
|
|
20
|
+
* rather than competing for a corner of the screen.
|
|
21
|
+
*/
|
|
22
|
+
export declare function NotificationPermissionPrompt({ messages, autoShowDelayMs, reloadOnGrant, }?: NotificationPermissionPromptProps): null;
|
|
27
23
|
//# sourceMappingURL=notification-permission-prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-permission-prompt.d.ts","sourceRoot":"","sources":["../../src/components/notification-permission-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"notification-permission-prompt.d.ts","sourceRoot":"","sources":["../../src/components/notification-permission-prompt.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,oCAAoC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,EAAE,oCAAoC,CAAA;IAC/C,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAcD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,eAAsB,EACtB,aAAoB,GACrB,GAAE,iCAAsC,QA2ExC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { showNotificationToast } from '@asteby/metacore-notifications';
|
|
4
3
|
import { toast } from 'sonner';
|
|
5
4
|
const DEFAULTS = {
|
|
6
5
|
title: 'Activar Notificaciones',
|
|
@@ -11,42 +10,15 @@ const DEFAULTS = {
|
|
|
11
10
|
blockedTitle: 'Notificaciones bloqueadas por el navegador',
|
|
12
11
|
blockedDescription: 'Debes habilitarlas manualmente: Click en el ícono de la barra de direcciones → Permisos → Notificaciones → Permitir',
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return (_jsx("button", { type: "button", onClick: onClick, className: `${base} ${sizeClass} ${variantClass} ${className ?? ''}`, children: children }));
|
|
21
|
-
}
|
|
22
|
-
export function NotificationPermissionPrompt({ ButtonComponent = DefaultButton, messages, autoShowDelayMs = 2000, reloadOnGrant = true, className, } = {}) {
|
|
23
|
-
const [show, setShow] = useState(false);
|
|
13
|
+
/**
|
|
14
|
+
* Renders through the shared notification toast instead of its own
|
|
15
|
+
* fixed-position banner, so it stacks with every other app notification
|
|
16
|
+
* rather than competing for a corner of the screen.
|
|
17
|
+
*/
|
|
18
|
+
export function NotificationPermissionPrompt({ messages, autoShowDelayMs = 2000, reloadOnGrant = true, } = {}) {
|
|
24
19
|
const msgs = { ...DEFAULTS, ...messages };
|
|
25
|
-
|
|
26
|
-
if (typeof window === 'undefined')
|
|
27
|
-
return;
|
|
28
|
-
if ('Notification' in window && Notification.permission === 'default') {
|
|
29
|
-
const timer = setTimeout(() => setShow(true), autoShowDelayMs);
|
|
30
|
-
return () => clearTimeout(timer);
|
|
31
|
-
}
|
|
32
|
-
return undefined;
|
|
33
|
-
}, [autoShowDelayMs]);
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (typeof window === 'undefined')
|
|
36
|
-
return;
|
|
37
|
-
const handleTrigger = () => {
|
|
38
|
-
if (!('Notification' in window))
|
|
39
|
-
return;
|
|
40
|
-
if (Notification.permission !== 'granted') {
|
|
41
|
-
setShow(true);
|
|
42
|
-
sessionStorage.removeItem('notification-prompt-dismissed');
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
window.addEventListener('show-notification-prompt', handleTrigger);
|
|
46
|
-
return () => window.removeEventListener('show-notification-prompt', handleTrigger);
|
|
47
|
-
}, []);
|
|
20
|
+
const shownRef = useRef(false);
|
|
48
21
|
const handleAllow = async () => {
|
|
49
|
-
setShow(false);
|
|
50
22
|
try {
|
|
51
23
|
const permission = await Notification.requestPermission();
|
|
52
24
|
if (permission === 'granted') {
|
|
@@ -68,17 +40,53 @@ export function NotificationPermissionPrompt({ ButtonComponent = DefaultButton,
|
|
|
68
40
|
}
|
|
69
41
|
};
|
|
70
42
|
const handleDismiss = () => {
|
|
71
|
-
setShow(false);
|
|
72
43
|
if (typeof sessionStorage !== 'undefined') {
|
|
73
44
|
sessionStorage.setItem('notification-prompt-dismissed', 'true');
|
|
74
45
|
}
|
|
75
46
|
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
47
|
+
const show = () => {
|
|
48
|
+
if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem('notification-prompt-dismissed')) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
showNotificationToast({
|
|
52
|
+
title: msgs.title,
|
|
53
|
+
body: msgs.description,
|
|
54
|
+
type: 'info',
|
|
55
|
+
icon: 'bell',
|
|
56
|
+
duration: 15000,
|
|
57
|
+
action: { label: msgs.allowLabel, onClick: () => void handleAllow() },
|
|
58
|
+
cancel: { label: msgs.dismissLabel, onClick: handleDismiss },
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (typeof window === 'undefined')
|
|
63
|
+
return;
|
|
64
|
+
if (!('Notification' in window) || Notification.permission !== 'default')
|
|
65
|
+
return;
|
|
66
|
+
if (shownRef.current)
|
|
67
|
+
return;
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
shownRef.current = true;
|
|
70
|
+
show();
|
|
71
|
+
}, autoShowDelayMs);
|
|
72
|
+
return () => clearTimeout(timer);
|
|
73
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
74
|
+
}, [autoShowDelayMs]);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (typeof window === 'undefined')
|
|
77
|
+
return;
|
|
78
|
+
const handleTrigger = () => {
|
|
79
|
+
if (!('Notification' in window))
|
|
80
|
+
return;
|
|
81
|
+
if (Notification.permission !== 'granted') {
|
|
82
|
+
sessionStorage.removeItem('notification-prompt-dismissed');
|
|
83
|
+
show();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
window.addEventListener('show-notification-prompt', handleTrigger);
|
|
87
|
+
return () => window.removeEventListener('show-notification-prompt', handleTrigger);
|
|
88
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
89
|
+
}, []);
|
|
90
|
+
return null;
|
|
83
91
|
}
|
|
84
92
|
//# sourceMappingURL=notification-permission-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-permission-prompt.js","sourceRoot":"","sources":["../../src/components/notification-permission-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"notification-permission-prompt.js","sourceRoot":"","sources":["../../src/components/notification-permission-prompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAoB9B,MAAM,QAAQ,GAAmD;IAC/D,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EACT,uFAAuF;IACzF,UAAU,EAAE,UAAU;IACtB,YAAY,EAAE,UAAU;IACxB,cAAc,EAAE,4BAA4B;IAC5C,YAAY,EAAE,4CAA4C;IAC1D,kBAAkB,EAChB,qHAAqH;CACxH,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,EAC3C,QAAQ,EACR,eAAe,GAAG,IAAI,EACtB,aAAa,GAAG,IAAI,MACiB,EAAE;IACvC,MAAM,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAA;IACzC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE9B,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,iBAAiB,EAAE,CAAA;YAEzD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBAClC,IAAI,aAAa,EAAE,CAAC;oBAClB,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAA;gBAClD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE;oBAC7B,WAAW,EAAE,IAAI,CAAC,kBAAkB;oBACpC,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;YAC1C,cAAc,CAAC,OAAO,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAA;QACjE,CAAC;IACH,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,IAAI,OAAO,cAAc,KAAK,WAAW,IAAI,cAAc,CAAC,OAAO,CAAC,+BAA+B,CAAC,EAAE,CAAC;YACrG,OAAM;QACR,CAAC;QACD,qBAAqB,CAAC;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,WAAW,EAAE,EAAE;YACrE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE;SAC7D,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAM;QACzC,IAAI,CAAC,CAAC,cAAc,IAAI,MAAM,CAAC,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS;YAAE,OAAM;QAChF,IAAI,QAAQ,CAAC,OAAO;YAAE,OAAM;QAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAA;YACvB,IAAI,EAAE,CAAA;QACR,CAAC,EAAE,eAAe,CAAC,CAAA;QACnB,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAChC,uDAAuD;IACzD,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAA;IAErB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAM;QAEzC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,CAAC,cAAc,IAAI,MAAM,CAAC;gBAAE,OAAM;YACvC,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC1C,cAAc,CAAC,UAAU,CAAC,+BAA+B,CAAC,CAAA;gBAC1D,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAA;QAClE,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAA;QAClF,uDAAuD;IACzD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ComponentType, type ReactNode } from 'react';
|
|
2
1
|
export interface UpdatePromptMessages {
|
|
3
2
|
title?: string;
|
|
4
3
|
description?: string;
|
|
@@ -6,14 +5,14 @@ export interface UpdatePromptMessages {
|
|
|
6
5
|
dismissLabel?: string;
|
|
7
6
|
}
|
|
8
7
|
export interface UpdatePromptProps {
|
|
9
|
-
ButtonComponent?: ComponentType<{
|
|
10
|
-
onClick?: () => void;
|
|
11
|
-
children?: ReactNode;
|
|
12
|
-
variant?: 'default' | 'outline';
|
|
13
|
-
size?: 'sm';
|
|
14
|
-
}>;
|
|
15
8
|
messages?: UpdatePromptMessages;
|
|
16
|
-
|
|
9
|
+
/** How long the toast stays before auto-dismissing (ms). Default: 0 (sticky). */
|
|
10
|
+
duration?: number;
|
|
17
11
|
}
|
|
18
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Renders through the shared notification toast instead of its own
|
|
14
|
+
* fixed-position banner, so it stacks with every other app notification
|
|
15
|
+
* rather than competing for a corner of the screen.
|
|
16
|
+
*/
|
|
17
|
+
export declare function PWAUpdatePrompt({ messages, duration }?: UpdatePromptProps): null;
|
|
19
18
|
//# sourceMappingURL=update-prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-prompt.d.ts","sourceRoot":"","sources":["../../src/components/update-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update-prompt.d.ts","sourceRoot":"","sources":["../../src/components/update-prompt.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,oBAAoB,CAAA;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AASD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAY,EAAE,GAAE,iBAAsB,QA4BjF"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {} from 'react';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { showNotificationToast } from '@asteby/metacore-notifications';
|
|
4
3
|
import { usePWAContext } from '../provider';
|
|
5
4
|
const DEFAULTS = {
|
|
6
5
|
title: 'Actualización disponible',
|
|
@@ -8,20 +7,36 @@ const DEFAULTS = {
|
|
|
8
7
|
updateLabel: 'Actualizar',
|
|
9
8
|
dismissLabel: 'Después',
|
|
10
9
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return (_jsx("button", { type: "button", onClick: onClick, className: `${base} ${sizeClass} ${variantClass}`, children: children }));
|
|
18
|
-
}
|
|
19
|
-
export function PWAUpdatePrompt({ ButtonComponent = DefaultButton, messages, className, } = {}) {
|
|
10
|
+
/**
|
|
11
|
+
* Renders through the shared notification toast instead of its own
|
|
12
|
+
* fixed-position banner, so it stacks with every other app notification
|
|
13
|
+
* rather than competing for a corner of the screen.
|
|
14
|
+
*/
|
|
15
|
+
export function PWAUpdatePrompt({ messages, duration = 0 } = {}) {
|
|
20
16
|
const { needRefresh, updateApp, closeUpdatePrompt } = usePWAContext();
|
|
21
17
|
const msgs = { ...DEFAULTS, ...messages };
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const shown = useRef(false);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!needRefresh || shown.current)
|
|
21
|
+
return;
|
|
22
|
+
shown.current = true;
|
|
23
|
+
showNotificationToast({
|
|
24
|
+
title: msgs.title,
|
|
25
|
+
body: msgs.description,
|
|
26
|
+
type: 'info',
|
|
27
|
+
icon: 'refresh-cw',
|
|
28
|
+
duration: duration || Infinity,
|
|
29
|
+
action: {
|
|
30
|
+
label: msgs.updateLabel,
|
|
31
|
+
onClick: updateApp,
|
|
32
|
+
},
|
|
33
|
+
cancel: {
|
|
34
|
+
label: msgs.dismissLabel,
|
|
35
|
+
onClick: closeUpdatePrompt,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
39
|
+
}, [needRefresh]);
|
|
40
|
+
return null;
|
|
26
41
|
}
|
|
27
42
|
//# sourceMappingURL=update-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-prompt.js","sourceRoot":"","sources":["../../src/components/update-prompt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update-prompt.js","sourceRoot":"","sources":["../../src/components/update-prompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAe3C,MAAM,QAAQ,GAAmC;IAC/C,KAAK,EAAE,0BAA0B;IACjC,WAAW,EAAE,kCAAkC;IAC/C,WAAW,EAAE,YAAY;IACzB,YAAY,EAAE,SAAS;CACxB,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,CAAC,KAAwB,EAAE;IAChF,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAA;IACrE,MAAM,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO;YAAE,OAAM;QACzC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAA;QAEpB,qBAAqB,CAAC;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,QAAQ,IAAI,QAAQ;YAC9B,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI,CAAC,WAAW;gBACvB,OAAO,EAAE,SAAS;aACnB;YACD,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI,CAAC,YAAY;gBACxB,OAAO,EAAE,iBAAiB;aAC3B;SACF,CAAC,CAAA;QACF,uDAAuD;IACzD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEjB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asteby/metacore-pwa",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Metacore PWA helpers — vite plugin wrapper, install/update prompts, push notifications, offline indicator",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"vite-plugin-pwa": ">=1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"lucide-react": "^1.0.0"
|
|
51
|
+
"lucide-react": "^1.0.0",
|
|
52
|
+
"@asteby/metacore-notifications": "26.0.0"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/react": "^19.0.0",
|