webapp-astro-pwa
Version:
A ready-to-use Astro component library for adding Progressive Web App (PWA) support to your Astro projects. This package provides drop-in components and utilities for manifest injection, service worker registration, install prompts, and more. Includes a w
92 lines (76 loc) • 3.23 kB
text/typescript
import { isPWAInstalled } from "./utilities";
/**
* Handles the installation prompt for Progressive Web Apps (PWAs).
*
* This class manages the display and behavior of the install button, and the installation process.
* It listens for the [`beforeinstallprompt`](https://developer.mozilla.org/docs/Web/API/BeforeInstallPromptEvent) and
* [`appinstalled`](https://developer.mozilla.org/docs/Web/API/Window/appinstalled_event) events to show or hide the install button.
* It also provides a method to check if the PWA is already installed.
*
* @class PWAInstallPrompt
* @param {string} btnId - The CSS selector for the button element that triggers the installation prompt.
* @property {BeforeInstallPromptEvent | null} installPrompt - The install prompt event object.
* @property {HTMLElement | null} btn - The button element that triggers the installation prompt.
*/
type BeforeInstallPromptEvent = Event & {
prompt: () => Promise<void>;
userChoice?: Promise<{ outcome: "accepted" | "dismissed" }>;
};
class PWAInstallPrompt {
btnId: string;
installPrompt: BeforeInstallPromptEvent | null;
btn: HTMLElement | null;
constructor(btnId: string) {
this.btnId = btnId;
this.installPrompt = null;
this.btn = document.querySelector(this.btnId);
}
checkIsPWAInstalled(): boolean {
if (isPWAInstalled()) {
console.log("PWA is installed and running in standalone mode.");
return true;
}
console.log("PWA is not installed or running in a browser tab.");
return false;
}
hideButton(btn: HTMLElement): void {
this.installPrompt = null;
btn.setAttribute("hidden", "");
}
installPWABtnHandler = async (): Promise<void> => {
if (!this.installPrompt) {
console.log("No install prompt available");
return;
}
await this.installPrompt.prompt();
if (this.installPrompt.userChoice) {
const result = await this.installPrompt.userChoice;
if (result.outcome === "dismissed" || result.outcome === "accepted") {
this.btn?.parentNode?.removeChild(this.btn);
const modal = document.getElementById("modal");
if (modal) modal.hidePopover();
}
console.log(`Install prompt was: ${result.outcome}`);
}
};
beforeInstallHandler = (event: Event, btn: HTMLElement): void => {
this.installPrompt = event as BeforeInstallPromptEvent;
btn.removeAttribute("hidden");
};
runEvents = (isPopup: boolean, popup?: HTMLElement): void => {
const installButton: HTMLElement | null = this.btn;
if (!installButton) return;
const beforeInstallPromptHandler = (e: Event) => {
this.beforeInstallHandler(e, installButton);
window.removeEventListener("beforeinstallprompt", beforeInstallPromptHandler);
};
const appinstalledHandler = () => {
if (isPopup && popup && typeof popup.hidePopover === "function") popup.hidePopover();
installButton?.parentNode?.removeChild(installButton);
window.removeEventListener("appinstalled", appinstalledHandler);
};
window.addEventListener("beforeinstallprompt", beforeInstallPromptHandler);
window.addEventListener("appinstalled", appinstalledHandler);
};
}
export default PWAInstallPrompt;