UNPKG

@progressivewebcomponents/pwa-install

Version:

A tiny vanilla (zero-dependency) non-visual native browser web component (plug-n-play custom HTML element and extensible class) that helps implement custom patterns for promoting progressive web apps (PWA) installation

325 lines (298 loc) 7.18 kB
export class PWAInstall extends HTMLElement { static get is() { /** * @customElement pwa-install */ return 'pwa-install'; } get isInstallSupported() { return this._isInstallSupported; } set isInstallSupported(value) { this._isInstallSupported = value; /** * @attribute is-install-supported * @type {?boolean} * @readonly */ if (value) { this.setAttribute('is-install-supported', ''); } else { this.removeAttribute('is-install-supported'); } /** * @event is-install-supported-changed */ this.dispatchEvent( new CustomEvent('is-install-supported-changed', { detail: { value, }, }) ); } get isInstallAvailable() { return this._isInstallAvailable; } set isInstallAvailable(value) { this._isInstallAvailable = value; /** * @attribute is-install-available * @type {?boolean} * @readonly */ if (value) { this.setAttribute('is-install-available', ''); } else { this.removeAttribute('is-install-available'); } /** * @event is-install-available-changed */ this.dispatchEvent( new CustomEvent('is-install-available-changed', { detail: { value, }, }) ); } get platforms() { return this._platforms; } set platforms(value) { this._platforms = value; /** * @event platforms-changed */ this.dispatchEvent( new CustomEvent('platforms-changed', { detail: { value, }, }) ); } get choiceResult() { return this._choiceResult; } set choiceResult(value) { this._choiceResult = value; /** * @event choice-result-changed */ this.dispatchEvent( new CustomEvent('choice-result-changed', { detail: { value, }, }) ); } get isGetInstalledRelatedAppsSupported() { return this._isGetInstalledRelatedAppsSupported; } set isGetInstalledRelatedAppsSupported(value) { this._isGetInstalledRelatedAppsSupported = value; /** * @attribute is-get-installed-related-apps-supported * @type {?boolean} * @readonly */ if (value) { this.setAttribute('is-get-installed-related-apps-supported', ''); } else { this.removeAttribute('is-get-installed-related-apps-supported'); } /** * @event is-get-installed-related-apps-supported-changed */ this.dispatchEvent( new CustomEvent('is-get-installed-related-apps-supported-changed', { detail: { value, }, }) ); } get relatedApps() { return this._relatedApps; } set relatedApps(value) { this._relatedApps = value; /** * @event related-apps-changed */ this.dispatchEvent( new CustomEvent('related-apps-changed', { detail: { value, }, }) ); } _onbeforeinstallprompt(event) { event.preventDefault(); window.deferredInstallEvent = event; this.platforms = event.platforms; this.isInstallAvailable = true; /** * @event pwa-install-available */ this.dispatchEvent( new CustomEvent('pwa-install-available', { detail: { value: event.platforms, }, bubbles: true, composed: true, }) ); } _onappinstalled(event) { window.deferredInstallEvent = null; this.isInstallAvailable = false; /** * @event pwa-install-installed */ this.dispatchEvent( new CustomEvent('pwa-install-installed', { detail: { value: this.choiceResult, }, bubbles: true, composed: true, }) ); } /** * @async * @method prompt * @return {?Promise<Object>} */ async prompt() { if (this.isInstallSupported) { let choiceResult; try { this.isInstallAvailable = false; choiceResult = await window.deferredInstallEvent?.prompt(); this.choiceResult = choiceResult; /** * @event pwa-install-installing */ this.dispatchEvent( new CustomEvent('pwa-install-installing', { detail: { value: choiceResult, }, bubbles: true, composed: true, }) ); return choiceResult; } catch (error) { /** * @event pwa-install-error */ this.dispatchEvent( new CustomEvent('pwa-install-error', { detail: { value: choiceResult, message: { error, }, }, bubbles: true, composed: true, }) ); throw error; } finally { window.deferredInstallEvent = null; } } } /** * @async * @method getInstalledRelatedApps * @return {?Promise<Array>} */ async getInstalledRelatedApps() { if (this.isGetInstalledRelatedAppsSupported) { try { const relatedApps = await navigator.getInstalledRelatedApps(); this.relatedApps = relatedApps; return relatedApps; } catch (error) { /** * @event pwa-install-error */ this.dispatchEvent( new CustomEvent('pwa-install-error', { detail: { message: { error, }, }, bubbles: true, composed: true, }) ); throw error; } } } constructor() { super(); /** * @property isInstallSupported * @type {?boolean} * @readonly */ this.isInstallSupported; /** * @property isInstallAvailable * @type {?boolean} * @readonly */ this.isInstallAvailable; /** * @property platforms * @type {?Array} * @readonly */ this.platforms; /** * @property choiceResult * @type {?Object} * @readonly */ this.choiceResult; /** * @property isGetInstalledRelatedAppsSupported * @type {?boolean} * @readonly */ this.isGetInstalledRelatedAppsSupported; /** * @property relatedApps * @type {?Array} * @readonly */ this.relatedApps; this._onbeforeinstallprompt = this._onbeforeinstallprompt.bind(this); this._onappinstalled = this._onappinstalled.bind(this); } connectedCallback() { // Set property values in `connectedCallback()` instead of `constructor()` for compatibility with Google Polymer library data binding this.isInstallSupported = 'BeforeInstallPromptEvent' in window; this.isGetInstalledRelatedAppsSupported = 'getInstalledRelatedApps' in navigator; this.getInstalledRelatedApps(); window.addEventListener('beforeinstallprompt', this._onbeforeinstallprompt); window.addEventListener('appinstalled', this._onappinstalled); } disconnectedCallback() { window.removeEventListener('beforeinstallprompt', this._onbeforeinstallprompt); window.removeEventListener('appinstalled', this._onappinstalled); } }