@ngutil/pwa 0.0.24
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/README.md +18 -0
- package/esm2022/index.mjs +2 -0
- package/esm2022/ngutil-pwa.mjs +5 -0
- package/esm2022/services/installer-prompt.service.mjs +57 -0
- package/fesm2022/ngutil-pwa.mjs +64 -0
- package/fesm2022/ngutil-pwa.mjs.map +1 -0
- package/index.d.ts +1 -0
- package/package.json +30 -0
- package/services/installer-prompt.service.d.ts +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# PWA
|
|
2
|
+
|
|
3
|
+
This codebase includes utilities and tools specifically designed to assist in the development of Progressive Web Applications (PWAs).
|
|
4
|
+
|
|
5
|
+
## Installer prompt
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// config.ts
|
|
9
|
+
|
|
10
|
+
import { provideInstallerPrompt } from "@ngutil/pwa"
|
|
11
|
+
|
|
12
|
+
export const appConfig: ApplicationConfig = {
|
|
13
|
+
providers: [
|
|
14
|
+
// ...
|
|
15
|
+
provideInstallerPrompt()
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
```
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { InstallerPromptService, provideInstallerPrompt } from "./services/installer-prompt.service";
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wYWNrYWdlcy9wd2Evc3JjL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDSCxzQkFBc0IsRUFFdEIsc0JBQXNCLEVBQ3pCLE1BQU0scUNBQXFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQge1xuICAgIEluc3RhbGxlclByb21wdFNlcnZpY2UsXG4gICAgSW5zdGFsbGVyUHJvbXB0VXNlckNob2ljZSxcbiAgICBwcm92aWRlSW5zdGFsbGVyUHJvbXB0XG59IGZyb20gXCIuL3NlcnZpY2VzL2luc3RhbGxlci1wcm9tcHQuc2VydmljZVwiXG4iXX0=
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './index';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd1dGlsLXB3YS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BhY2thZ2VzL3B3YS9zcmMvbmd1dGlsLXB3YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ==
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { inject, Injectable } from "@angular/core";
|
|
2
|
+
import { BehaviorSubject, combineLatest, exhaustMap, from, map, of, shareReplay, take } from "rxjs";
|
|
3
|
+
import { MediaWatcher } from "@ngutil/style";
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export class DeferredPromptRef extends BehaviorSubject {
|
|
6
|
+
}
|
|
7
|
+
// "(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)"
|
|
8
|
+
const IS_STANDALONE = "(display-mode: standalone)";
|
|
9
|
+
export class InstallerPromptService {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.#mw = inject(MediaWatcher);
|
|
12
|
+
this.#prompt = inject(DeferredPromptRef);
|
|
13
|
+
this.hasPrompt$ = this.#prompt.pipe(map(value => !!value));
|
|
14
|
+
this.#isStandalone = this.#mw.watch(IS_STANDALONE);
|
|
15
|
+
this.isStandalone$ = this.#isStandalone.pipe(map(isStandalone => isStandalone || ("standalone" in window.navigator && window.navigator["standalone"])));
|
|
16
|
+
// TODO: https://web.dev/articles/get-installed-related-apps#check-pwa-in-scope
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated NOT IMPLEMENTED
|
|
19
|
+
*/
|
|
20
|
+
this.isInstalled$ = of(false);
|
|
21
|
+
this.isSupported$ = combineLatest({
|
|
22
|
+
isStandalone: this.isStandalone$,
|
|
23
|
+
hasPrompt: this.hasPrompt$
|
|
24
|
+
}).pipe(map(({ isStandalone, hasPrompt }) => !isStandalone && hasPrompt), shareReplay(1));
|
|
25
|
+
}
|
|
26
|
+
#mw;
|
|
27
|
+
#prompt;
|
|
28
|
+
#isStandalone;
|
|
29
|
+
install() {
|
|
30
|
+
return this.#prompt.pipe(take(1), exhaustMap(prompt => {
|
|
31
|
+
if (prompt == null) {
|
|
32
|
+
return of("expired");
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
prompt.prompt();
|
|
36
|
+
// You can only call prompt() on the deferred event once.
|
|
37
|
+
this.#prompt.next(null);
|
|
38
|
+
return from(prompt.userChoice).pipe(map(v => v.outcome));
|
|
39
|
+
}
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
43
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, providedIn: "root" }); }
|
|
44
|
+
}
|
|
45
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, decorators: [{
|
|
46
|
+
type: Injectable,
|
|
47
|
+
args: [{ providedIn: "root" }]
|
|
48
|
+
}] });
|
|
49
|
+
export function provideInstallerPrompt() {
|
|
50
|
+
const deferredPromptRef = new DeferredPromptRef(null);
|
|
51
|
+
window.addEventListener("beforeinstallprompt", event => {
|
|
52
|
+
deferredPromptRef.next(event);
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
});
|
|
55
|
+
return [{ provide: DeferredPromptRef, useValue: deferredPromptRef }, InstallerPromptService];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbGVyLXByb21wdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvcHdhL3NyYy9zZXJ2aWNlcy9pbnN0YWxsZXItcHJvbXB0LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQVksTUFBTSxlQUFlLENBQUE7QUFFNUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQWMsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFFL0csT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQTs7QUFZNUMsTUFBTSxPQUFPLGlCQUFrQixTQUFRLGVBQTZEO0NBQUc7QUFJdkcsb0dBQW9HO0FBQ3BHLE1BQU0sYUFBYSxHQUFHLDRCQUE0QixDQUFBO0FBR2xELE1BQU0sT0FBTyxzQkFBc0I7SUFEbkM7UUFFYSxRQUFHLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFBO1FBRTFCLFlBQU8sR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtRQUNuQyxlQUFVLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7UUFFckQsa0JBQWEsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQTtRQUM3QyxrQkFBYSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUM1QyxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQyxZQUFZLElBQUksQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLFNBQVMsSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FDNUcsQ0FBQTtRQUVELCtFQUErRTtRQUMvRTs7V0FFRztRQUNNLGlCQUFZLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBRXhCLGlCQUFZLEdBQUcsYUFBYSxDQUFDO1lBQ2xDLFlBQVksRUFBRSxJQUFJLENBQUMsYUFBYTtZQUNoQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVU7U0FDN0IsQ0FBQyxDQUFDLElBQUksQ0FDSCxHQUFHLENBQUMsQ0FBQyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxZQUFZLElBQUksU0FBUyxDQUFDLEVBQ2hFLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FDakIsQ0FBQTtLQWlCSjtJQXZDWSxHQUFHLENBQXVCO0lBRTFCLE9BQU8sQ0FBNEI7SUFHbkMsYUFBYSxDQUFnQztJQW1CdEQsT0FBTztRQUNILE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQ3BCLElBQUksQ0FBQyxDQUFDLENBQUMsRUFDUCxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDaEIsSUFBSSxNQUFNLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ2pCLE9BQU8sRUFBRSxDQUFDLFNBQXNDLENBQUMsQ0FBQTtZQUNyRCxDQUFDO2lCQUFNLENBQUM7Z0JBQ0osTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFBO2dCQUNmLHlEQUF5RDtnQkFDekQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7Z0JBQ3ZCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7WUFDNUQsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUNMLENBQUE7SUFDTCxDQUFDOzhHQXZDUSxzQkFBc0I7a0hBQXRCLHNCQUFzQixjQURULE1BQU07OzJGQUNuQixzQkFBc0I7a0JBRGxDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOztBQTJDbEMsTUFBTSxVQUFVLHNCQUFzQjtJQUNsQyxNQUFNLGlCQUFpQixHQUFHLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDckQsTUFBTSxDQUFDLGdCQUFnQixDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxFQUFFO1FBQ25ELGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFZLENBQUMsQ0FBQTtRQUNwQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUE7SUFDMUIsQ0FBQyxDQUFDLENBQUE7SUFFRixPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsUUFBUSxFQUFFLGlCQUFpQixFQUFFLEVBQUUsc0JBQXNCLENBQUMsQ0FBQTtBQUNoRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBJbmplY3RhYmxlLCBQcm92aWRlciB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCJcblxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBleGhhdXN0TWFwLCBmcm9tLCBtYXAsIE9ic2VydmFibGUsIG9mLCBzaGFyZVJlcGxheSwgdGFrZSB9IGZyb20gXCJyeGpzXCJcblxuaW1wb3J0IHsgTWVkaWFXYXRjaGVyIH0gZnJvbSBcIkBuZ3V0aWwvc3R5bGVcIlxuXG5leHBvcnQgdHlwZSBCZWZvcmVJbnN0YWxsUHJvbXB0RXZlbnRfRXhwZXJpbWVudGFsID0gRXZlbnQgJiB7XG4gICAgcHJvbXB0OiAoKSA9PiB2b2lkXG4gICAgdXNlckNob2ljZTogUHJvbWlzZTxCZWZvcmVJbnN0YWxsUHJvbXB0RXZlbnRfVXNlckNob2ljZT5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBCZWZvcmVJbnN0YWxsUHJvbXB0RXZlbnRfVXNlckNob2ljZSB7XG4gICAgb3V0Y29tZTogXCJhY2NlcHRlZFwiIHwgXCJkaXNtaXNzZWRcIlxuICAgIHBsYXRmb3JtOiBhbnlcbn1cblxuZXhwb3J0IGNsYXNzIERlZmVycmVkUHJvbXB0UmVmIGV4dGVuZHMgQmVoYXZpb3JTdWJqZWN0PEJlZm9yZUluc3RhbGxQcm9tcHRFdmVudF9FeHBlcmltZW50YWwgfCBudWxsPiB7fVxuXG5leHBvcnQgdHlwZSBJbnN0YWxsZXJQcm9tcHRVc2VyQ2hvaWNlID0gQmVmb3JlSW5zdGFsbFByb21wdEV2ZW50X1VzZXJDaG9pY2VbXCJvdXRjb21lXCJdIHwgXCJleHBpcmVkXCJcblxuLy8gXCIoZGlzcGxheS1tb2RlOiBzdGFuZGFsb25lKSwgKGRpc3BsYXktbW9kZTogbWluaW1hbC11aSksIChkaXNwbGF5LW1vZGU6IHdpbmRvdy1jb250cm9scy1vdmVybGF5KVwiXG5jb25zdCBJU19TVEFOREFMT05FID0gXCIoZGlzcGxheS1tb2RlOiBzdGFuZGFsb25lKVwiXG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogXCJyb290XCIgfSlcbmV4cG9ydCBjbGFzcyBJbnN0YWxsZXJQcm9tcHRTZXJ2aWNlIHtcbiAgICByZWFkb25seSAjbXcgPSBpbmplY3QoTWVkaWFXYXRjaGVyKVxuXG4gICAgcmVhZG9ubHkgI3Byb21wdCA9IGluamVjdChEZWZlcnJlZFByb21wdFJlZilcbiAgICByZWFkb25seSBoYXNQcm9tcHQkID0gdGhpcy4jcHJvbXB0LnBpcGUobWFwKHZhbHVlID0+ICEhdmFsdWUpKVxuXG4gICAgcmVhZG9ubHkgI2lzU3RhbmRhbG9uZSA9IHRoaXMuI213LndhdGNoKElTX1NUQU5EQUxPTkUpXG4gICAgcmVhZG9ubHkgaXNTdGFuZGFsb25lJCA9IHRoaXMuI2lzU3RhbmRhbG9uZS5waXBlKFxuICAgICAgICBtYXAoaXNTdGFuZGFsb25lID0+IGlzU3RhbmRhbG9uZSB8fCAoXCJzdGFuZGFsb25lXCIgaW4gd2luZG93Lm5hdmlnYXRvciAmJiB3aW5kb3cubmF2aWdhdG9yW1wic3RhbmRhbG9uZVwiXSkpXG4gICAgKVxuXG4gICAgLy8gVE9ETzogaHR0cHM6Ly93ZWIuZGV2L2FydGljbGVzL2dldC1pbnN0YWxsZWQtcmVsYXRlZC1hcHBzI2NoZWNrLXB3YS1pbi1zY29wZVxuICAgIC8qKlxuICAgICAqIEBkZXByZWNhdGVkIE5PVCBJTVBMRU1FTlRFRFxuICAgICAqL1xuICAgIHJlYWRvbmx5IGlzSW5zdGFsbGVkJCA9IG9mKGZhbHNlKVxuXG4gICAgcmVhZG9ubHkgaXNTdXBwb3J0ZWQkID0gY29tYmluZUxhdGVzdCh7XG4gICAgICAgIGlzU3RhbmRhbG9uZTogdGhpcy5pc1N0YW5kYWxvbmUkLFxuICAgICAgICBoYXNQcm9tcHQ6IHRoaXMuaGFzUHJvbXB0JFxuICAgIH0pLnBpcGUoXG4gICAgICAgIG1hcCgoeyBpc1N0YW5kYWxvbmUsIGhhc1Byb21wdCB9KSA9PiAhaXNTdGFuZGFsb25lICYmIGhhc1Byb21wdCksXG4gICAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKVxuXG4gICAgaW5zdGFsbCgpOiBPYnNlcnZhYmxlPEluc3RhbGxlclByb21wdFVzZXJDaG9pY2U+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuI3Byb21wdC5waXBlKFxuICAgICAgICAgICAgdGFrZSgxKSxcbiAgICAgICAgICAgIGV4aGF1c3RNYXAocHJvbXB0ID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocHJvbXB0ID09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKFwiZXhwaXJlZFwiIGFzIEluc3RhbGxlclByb21wdFVzZXJDaG9pY2UpXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0LnByb21wdCgpXG4gICAgICAgICAgICAgICAgICAgIC8vIFlvdSBjYW4gb25seSBjYWxsIHByb21wdCgpIG9uIHRoZSBkZWZlcnJlZCBldmVudCBvbmNlLlxuICAgICAgICAgICAgICAgICAgICB0aGlzLiNwcm9tcHQubmV4dChudWxsKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZnJvbShwcm9tcHQudXNlckNob2ljZSkucGlwZShtYXAodiA9PiB2Lm91dGNvbWUpKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwcm92aWRlSW5zdGFsbGVyUHJvbXB0KCk6IFByb3ZpZGVyW10ge1xuICAgIGNvbnN0IGRlZmVycmVkUHJvbXB0UmVmID0gbmV3IERlZmVycmVkUHJvbXB0UmVmKG51bGwpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJiZWZvcmVpbnN0YWxscHJvbXB0XCIsIGV2ZW50ID0+IHtcbiAgICAgICAgZGVmZXJyZWRQcm9tcHRSZWYubmV4dChldmVudCBhcyBhbnkpXG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KClcbiAgICB9KVxuXG4gICAgcmV0dXJuIFt7IHByb3ZpZGU6IERlZmVycmVkUHJvbXB0UmVmLCB1c2VWYWx1ZTogZGVmZXJyZWRQcm9tcHRSZWYgfSwgSW5zdGFsbGVyUHJvbXB0U2VydmljZV1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject, map, of, combineLatest, shareReplay, take, exhaustMap, from } from 'rxjs';
|
|
4
|
+
import { MediaWatcher } from '@ngutil/style';
|
|
5
|
+
|
|
6
|
+
class DeferredPromptRef extends BehaviorSubject {
|
|
7
|
+
}
|
|
8
|
+
// "(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)"
|
|
9
|
+
const IS_STANDALONE = "(display-mode: standalone)";
|
|
10
|
+
class InstallerPromptService {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.#mw = inject(MediaWatcher);
|
|
13
|
+
this.#prompt = inject(DeferredPromptRef);
|
|
14
|
+
this.hasPrompt$ = this.#prompt.pipe(map(value => !!value));
|
|
15
|
+
this.#isStandalone = this.#mw.watch(IS_STANDALONE);
|
|
16
|
+
this.isStandalone$ = this.#isStandalone.pipe(map(isStandalone => isStandalone || ("standalone" in window.navigator && window.navigator["standalone"])));
|
|
17
|
+
// TODO: https://web.dev/articles/get-installed-related-apps#check-pwa-in-scope
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated NOT IMPLEMENTED
|
|
20
|
+
*/
|
|
21
|
+
this.isInstalled$ = of(false);
|
|
22
|
+
this.isSupported$ = combineLatest({
|
|
23
|
+
isStandalone: this.isStandalone$,
|
|
24
|
+
hasPrompt: this.hasPrompt$
|
|
25
|
+
}).pipe(map(({ isStandalone, hasPrompt }) => !isStandalone && hasPrompt), shareReplay(1));
|
|
26
|
+
}
|
|
27
|
+
#mw;
|
|
28
|
+
#prompt;
|
|
29
|
+
#isStandalone;
|
|
30
|
+
install() {
|
|
31
|
+
return this.#prompt.pipe(take(1), exhaustMap(prompt => {
|
|
32
|
+
if (prompt == null) {
|
|
33
|
+
return of("expired");
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
prompt.prompt();
|
|
37
|
+
// You can only call prompt() on the deferred event once.
|
|
38
|
+
this.#prompt.next(null);
|
|
39
|
+
return from(prompt.userChoice).pipe(map(v => v.outcome));
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
44
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, providedIn: "root" }); }
|
|
45
|
+
}
|
|
46
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: InstallerPromptService, decorators: [{
|
|
47
|
+
type: Injectable,
|
|
48
|
+
args: [{ providedIn: "root" }]
|
|
49
|
+
}] });
|
|
50
|
+
function provideInstallerPrompt() {
|
|
51
|
+
const deferredPromptRef = new DeferredPromptRef(null);
|
|
52
|
+
window.addEventListener("beforeinstallprompt", event => {
|
|
53
|
+
deferredPromptRef.next(event);
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
});
|
|
56
|
+
return [{ provide: DeferredPromptRef, useValue: deferredPromptRef }, InstallerPromptService];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Generated bundle index. Do not edit.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
export { InstallerPromptService, provideInstallerPrompt };
|
|
64
|
+
//# sourceMappingURL=ngutil-pwa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngutil-pwa.mjs","sources":["../../../../packages/pwa/src/services/installer-prompt.service.ts","../../../../packages/pwa/src/ngutil-pwa.ts"],"sourcesContent":["import { inject, Injectable, Provider } from \"@angular/core\"\n\nimport { BehaviorSubject, combineLatest, exhaustMap, from, map, Observable, of, shareReplay, take } from \"rxjs\"\n\nimport { MediaWatcher } from \"@ngutil/style\"\n\nexport type BeforeInstallPromptEvent_Experimental = Event & {\n prompt: () => void\n userChoice: Promise<BeforeInstallPromptEvent_UserChoice>\n}\n\nexport interface BeforeInstallPromptEvent_UserChoice {\n outcome: \"accepted\" | \"dismissed\"\n platform: any\n}\n\nexport class DeferredPromptRef extends BehaviorSubject<BeforeInstallPromptEvent_Experimental | null> {}\n\nexport type InstallerPromptUserChoice = BeforeInstallPromptEvent_UserChoice[\"outcome\"] | \"expired\"\n\n// \"(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)\"\nconst IS_STANDALONE = \"(display-mode: standalone)\"\n\n@Injectable({ providedIn: \"root\" })\nexport class InstallerPromptService {\n readonly #mw = inject(MediaWatcher)\n\n readonly #prompt = inject(DeferredPromptRef)\n readonly hasPrompt$ = this.#prompt.pipe(map(value => !!value))\n\n readonly #isStandalone = this.#mw.watch(IS_STANDALONE)\n readonly isStandalone$ = this.#isStandalone.pipe(\n map(isStandalone => isStandalone || (\"standalone\" in window.navigator && window.navigator[\"standalone\"]))\n )\n\n // TODO: https://web.dev/articles/get-installed-related-apps#check-pwa-in-scope\n /**\n * @deprecated NOT IMPLEMENTED\n */\n readonly isInstalled$ = of(false)\n\n readonly isSupported$ = combineLatest({\n isStandalone: this.isStandalone$,\n hasPrompt: this.hasPrompt$\n }).pipe(\n map(({ isStandalone, hasPrompt }) => !isStandalone && hasPrompt),\n shareReplay(1)\n )\n\n install(): Observable<InstallerPromptUserChoice> {\n return this.#prompt.pipe(\n take(1),\n exhaustMap(prompt => {\n if (prompt == null) {\n return of(\"expired\" as InstallerPromptUserChoice)\n } else {\n prompt.prompt()\n // You can only call prompt() on the deferred event once.\n this.#prompt.next(null)\n return from(prompt.userChoice).pipe(map(v => v.outcome))\n }\n })\n )\n }\n}\n\nexport function provideInstallerPrompt(): Provider[] {\n const deferredPromptRef = new DeferredPromptRef(null)\n window.addEventListener(\"beforeinstallprompt\", event => {\n deferredPromptRef.next(event as any)\n event.preventDefault()\n })\n\n return [{ provide: DeferredPromptRef, useValue: deferredPromptRef }, InstallerPromptService]\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InstallerPromptService, InstallerPromptUserChoice, provideInstallerPrompt } from "./services/installer-prompt.service";
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ngutil/pwa",
|
|
3
|
+
"version": "0.0.24",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"tslib": "^2.6.2"
|
|
6
|
+
},
|
|
7
|
+
"peerDependencies": {
|
|
8
|
+
"@angular/common": "^17.3.6",
|
|
9
|
+
"@angular/core": "^17.3.6",
|
|
10
|
+
"@ngutil/common": "0.0.24"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"directory": "../../dist/packages/pwa/"
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"module": "fesm2022/ngutil-pwa.mjs",
|
|
18
|
+
"typings": "index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
"./package.json": {
|
|
21
|
+
"default": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"esm2022": "./esm2022/ngutil-pwa.mjs",
|
|
26
|
+
"esm": "./esm2022/ngutil-pwa.mjs",
|
|
27
|
+
"default": "./fesm2022/ngutil-pwa.mjs"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Provider } from "@angular/core";
|
|
2
|
+
import { BehaviorSubject, Observable } from "rxjs";
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export type BeforeInstallPromptEvent_Experimental = Event & {
|
|
5
|
+
prompt: () => void;
|
|
6
|
+
userChoice: Promise<BeforeInstallPromptEvent_UserChoice>;
|
|
7
|
+
};
|
|
8
|
+
export interface BeforeInstallPromptEvent_UserChoice {
|
|
9
|
+
outcome: "accepted" | "dismissed";
|
|
10
|
+
platform: any;
|
|
11
|
+
}
|
|
12
|
+
export declare class DeferredPromptRef extends BehaviorSubject<BeforeInstallPromptEvent_Experimental | null> {
|
|
13
|
+
}
|
|
14
|
+
export type InstallerPromptUserChoice = BeforeInstallPromptEvent_UserChoice["outcome"] | "expired";
|
|
15
|
+
export declare class InstallerPromptService {
|
|
16
|
+
#private;
|
|
17
|
+
readonly hasPrompt$: Observable<boolean>;
|
|
18
|
+
readonly isStandalone$: Observable<unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated NOT IMPLEMENTED
|
|
21
|
+
*/
|
|
22
|
+
readonly isInstalled$: Observable<boolean>;
|
|
23
|
+
readonly isSupported$: Observable<boolean>;
|
|
24
|
+
install(): Observable<InstallerPromptUserChoice>;
|
|
25
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<InstallerPromptService, never>;
|
|
26
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<InstallerPromptService>;
|
|
27
|
+
}
|
|
28
|
+
export declare function provideInstallerPrompt(): Provider[];
|