@sv-use/core
Version:
A collection of Svelte 5 utilities.
94 lines (93 loc) • 3.23 kB
JavaScript
import { onMount } from 'svelte';
/**
* Configure and display desktop notifications to the user.
* @warning Cannot be used in a lifecycle hook as it relies on `onMount`.
* @see https://svelte-librarian.github.io/sv-use/docs/core/create-web-notification
*/
export function createWebNotification(data = {}, options = {}) {
const { title = '', body = '', dir = 'auto', lang = '', tag = '', icon = '', requireInteraction = false, silent = false } = data;
const { autoRequestPermission = true, onShow = () => { }, onClick = () => { }, onClose = () => { }, onError = () => { } } = options;
let _isSupported = $state(false);
let _isPermissionGranted = $state(_isSupported && 'permission' in Notification && Notification.permission === 'granted');
let _notification = $state(null);
onMount(() => {
if (!window || !('Notification' in window)) {
_isSupported = false;
return;
}
if (Notification.permission === 'granted') {
_isSupported = true;
return;
}
// https://stackoverflow.com/questions/29774836/failed-to-construct-notification-illegal-constructor/29895431
// https://issues.chromium.org/issues/40415865
try {
const notification = new Notification('');
notification.onshow = () => {
notification.close();
};
}
catch (e) {
// Android Chrome: Uncaught TypeError: Failed to construct 'Notification': Illegal constructor. Use ServiceWorkerRegistration.showNotification() instead.
// @ts-expect-error catch TypeError
if (e.name === 'TypeError') {
_isSupported = false;
return;
}
}
_isSupported = true;
});
onMount(async () => {
if (!autoRequestPermission)
return;
await ensurePermissions();
});
async function ensurePermissions() {
if (!_isSupported)
return null;
if (!_isPermissionGranted && Notification.permission !== 'denied') {
const result = await Notification.requestPermission();
if (result === 'granted') {
_isPermissionGranted = true;
}
}
return _isPermissionGranted;
}
async function show() {
if (!_isSupported || !_isPermissionGranted)
return null;
_notification = new Notification(title, {
body,
dir,
lang,
tag,
icon,
requireInteraction,
silent
});
_notification.onshow = onShow;
_notification.onclick = onClick;
_notification.onclose = onClose;
_notification.onerror = onError;
return _notification;
}
function close() {
if (_notification) {
_notification.close();
}
_notification = null;
}
return {
get isSupported() {
return _isSupported;
},
get isPermissionGranted() {
return _isPermissionGranted;
},
get notification() {
return _notification;
},
show,
close
};
}