@angular-helpers/browser-web-apis 21.2.0 → 21.3.0
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.es.md +105 -0
- package/README.md +190 -0
- package/fesm2022/angular-helpers-browser-web-apis.mjs +894 -8
- package/package.json +1 -1
- package/types/angular-helpers-browser-web-apis.d.ts +472 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, computed, ElementRef, makeEnvironmentProviders } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, DestroyRef, PLATFORM_ID, signal, computed, isSignal, effect, ElementRef, makeEnvironmentProviders } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
|
|
4
4
|
import { Observable, fromEvent, Subject, of, map as map$1 } from 'rxjs';
|
|
5
5
|
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
@@ -493,6 +493,18 @@ const BROWSER_CAPABILITIES = [
|
|
|
493
493
|
{ id: 'serverSentEvents', label: 'Server-Sent Events', requiresSecureContext: false },
|
|
494
494
|
{ id: 'vibration', label: 'Vibration API', requiresSecureContext: false },
|
|
495
495
|
{ id: 'speechSynthesis', label: 'Speech Synthesis API', requiresSecureContext: false },
|
|
496
|
+
{ id: 'mutationObserver', label: 'Mutation Observer', requiresSecureContext: false },
|
|
497
|
+
{ id: 'performanceObserver', label: 'Performance Observer', requiresSecureContext: false },
|
|
498
|
+
{ id: 'idleDetector', label: 'Idle Detection API', requiresSecureContext: true },
|
|
499
|
+
{ id: 'eyeDropper', label: 'EyeDropper API', requiresSecureContext: true },
|
|
500
|
+
{ id: 'barcodeDetector', label: 'Barcode Detection API', requiresSecureContext: true },
|
|
501
|
+
{ id: 'webAudio', label: 'Web Audio API', requiresSecureContext: false },
|
|
502
|
+
{ id: 'gamepad', label: 'Gamepad API', requiresSecureContext: true },
|
|
503
|
+
{ id: 'webBluetooth', label: 'Web Bluetooth API', requiresSecureContext: true },
|
|
504
|
+
{ id: 'webUsb', label: 'WebUSB API', requiresSecureContext: true },
|
|
505
|
+
{ id: 'webNfc', label: 'Web NFC API', requiresSecureContext: true },
|
|
506
|
+
{ id: 'paymentRequest', label: 'Payment Request API', requiresSecureContext: true },
|
|
507
|
+
{ id: 'credentialManagement', label: 'Credential Management API', requiresSecureContext: true },
|
|
496
508
|
];
|
|
497
509
|
class BrowserCapabilityService {
|
|
498
510
|
getCapabilities() {
|
|
@@ -553,6 +565,30 @@ class BrowserCapabilityService {
|
|
|
553
565
|
return typeof navigator !== 'undefined' && 'vibrate' in navigator;
|
|
554
566
|
case 'speechSynthesis':
|
|
555
567
|
return typeof window !== 'undefined' && 'speechSynthesis' in window;
|
|
568
|
+
case 'mutationObserver':
|
|
569
|
+
return typeof MutationObserver !== 'undefined';
|
|
570
|
+
case 'performanceObserver':
|
|
571
|
+
return typeof PerformanceObserver !== 'undefined';
|
|
572
|
+
case 'idleDetector':
|
|
573
|
+
return typeof window !== 'undefined' && 'IdleDetector' in window;
|
|
574
|
+
case 'eyeDropper':
|
|
575
|
+
return typeof window !== 'undefined' && 'EyeDropper' in window;
|
|
576
|
+
case 'barcodeDetector':
|
|
577
|
+
return typeof window !== 'undefined' && 'BarcodeDetector' in window;
|
|
578
|
+
case 'webAudio':
|
|
579
|
+
return typeof window !== 'undefined' && 'AudioContext' in window;
|
|
580
|
+
case 'gamepad':
|
|
581
|
+
return typeof navigator !== 'undefined' && 'getGamepads' in navigator;
|
|
582
|
+
case 'webBluetooth':
|
|
583
|
+
return typeof navigator !== 'undefined' && 'bluetooth' in navigator;
|
|
584
|
+
case 'webUsb':
|
|
585
|
+
return typeof navigator !== 'undefined' && 'usb' in navigator;
|
|
586
|
+
case 'webNfc':
|
|
587
|
+
return typeof window !== 'undefined' && 'NDEFReader' in window;
|
|
588
|
+
case 'paymentRequest':
|
|
589
|
+
return typeof window !== 'undefined' && 'PaymentRequest' in window;
|
|
590
|
+
case 'credentialManagement':
|
|
591
|
+
return typeof navigator !== 'undefined' && 'credentials' in navigator;
|
|
556
592
|
default:
|
|
557
593
|
return false;
|
|
558
594
|
}
|
|
@@ -2237,6 +2273,672 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
2237
2273
|
type: Injectable
|
|
2238
2274
|
}] });
|
|
2239
2275
|
|
|
2276
|
+
const DEFAULT_OPTIONS = {
|
|
2277
|
+
childList: true,
|
|
2278
|
+
attributes: true,
|
|
2279
|
+
characterData: false,
|
|
2280
|
+
subtree: true,
|
|
2281
|
+
};
|
|
2282
|
+
function isMutationObserverSupported() {
|
|
2283
|
+
return typeof MutationObserver !== 'undefined';
|
|
2284
|
+
}
|
|
2285
|
+
function mutationObserverStream(element, options = DEFAULT_OPTIONS) {
|
|
2286
|
+
return new Observable((subscriber) => {
|
|
2287
|
+
const observer = new MutationObserver((mutations) => {
|
|
2288
|
+
subscriber.next(mutations);
|
|
2289
|
+
});
|
|
2290
|
+
observer.observe(element, options);
|
|
2291
|
+
return () => observer.disconnect();
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
class MutationObserverService {
|
|
2296
|
+
platformId = inject(PLATFORM_ID);
|
|
2297
|
+
isSupported() {
|
|
2298
|
+
return isPlatformBrowser(this.platformId) && isMutationObserverSupported();
|
|
2299
|
+
}
|
|
2300
|
+
observe(target, options) {
|
|
2301
|
+
if (!this.isSupported()) {
|
|
2302
|
+
return new Observable((o) => o.error(new Error('MutationObserver API not supported')));
|
|
2303
|
+
}
|
|
2304
|
+
return mutationObserverStream(target, options);
|
|
2305
|
+
}
|
|
2306
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2307
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService });
|
|
2308
|
+
}
|
|
2309
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: MutationObserverService, decorators: [{
|
|
2310
|
+
type: Injectable
|
|
2311
|
+
}] });
|
|
2312
|
+
|
|
2313
|
+
function isPerformanceObserverSupported() {
|
|
2314
|
+
return typeof PerformanceObserver !== 'undefined';
|
|
2315
|
+
}
|
|
2316
|
+
function performanceObserverStream(config) {
|
|
2317
|
+
return new Observable((subscriber) => {
|
|
2318
|
+
const observer = new PerformanceObserver((list) => {
|
|
2319
|
+
subscriber.next(list.getEntries());
|
|
2320
|
+
});
|
|
2321
|
+
if (config.type) {
|
|
2322
|
+
observer.observe({ type: config.type, buffered: config.buffered ?? true });
|
|
2323
|
+
}
|
|
2324
|
+
else if (config.entryTypes) {
|
|
2325
|
+
observer.observe({ entryTypes: config.entryTypes });
|
|
2326
|
+
}
|
|
2327
|
+
return () => observer.disconnect();
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
class PerformanceObserverService {
|
|
2332
|
+
platformId = inject(PLATFORM_ID);
|
|
2333
|
+
isSupported() {
|
|
2334
|
+
return isPlatformBrowser(this.platformId) && isPerformanceObserverSupported();
|
|
2335
|
+
}
|
|
2336
|
+
observe(config) {
|
|
2337
|
+
if (!this.isSupported()) {
|
|
2338
|
+
return new Observable((o) => o.error(new Error('PerformanceObserver API not supported')));
|
|
2339
|
+
}
|
|
2340
|
+
return performanceObserverStream(config);
|
|
2341
|
+
}
|
|
2342
|
+
observeByType(type, buffered = true) {
|
|
2343
|
+
return this.observe({ type, buffered });
|
|
2344
|
+
}
|
|
2345
|
+
getSupportedEntryTypes() {
|
|
2346
|
+
if (!this.isSupported())
|
|
2347
|
+
return [];
|
|
2348
|
+
return (PerformanceObserver.supportedEntryTypes ?? []);
|
|
2349
|
+
}
|
|
2350
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2351
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService });
|
|
2352
|
+
}
|
|
2353
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PerformanceObserverService, decorators: [{
|
|
2354
|
+
type: Injectable
|
|
2355
|
+
}] });
|
|
2356
|
+
|
|
2357
|
+
function getIdleDetectorClass$1() {
|
|
2358
|
+
return window.IdleDetector;
|
|
2359
|
+
}
|
|
2360
|
+
class IdleDetectorService {
|
|
2361
|
+
platformId = inject(PLATFORM_ID);
|
|
2362
|
+
isSupported() {
|
|
2363
|
+
return isPlatformBrowser(this.platformId) && 'IdleDetector' in window;
|
|
2364
|
+
}
|
|
2365
|
+
async requestPermission() {
|
|
2366
|
+
if (!this.isSupported()) {
|
|
2367
|
+
throw new Error('IdleDetector API not supported');
|
|
2368
|
+
}
|
|
2369
|
+
return getIdleDetectorClass$1().requestPermission();
|
|
2370
|
+
}
|
|
2371
|
+
watch(options = {}) {
|
|
2372
|
+
if (!this.isSupported()) {
|
|
2373
|
+
return new Observable((o) => o.error(new Error('IdleDetector API not supported')));
|
|
2374
|
+
}
|
|
2375
|
+
return new Observable((subscriber) => {
|
|
2376
|
+
const abortController = new AbortController();
|
|
2377
|
+
const detector = new (getIdleDetectorClass$1())();
|
|
2378
|
+
detector.addEventListener('change', () => {
|
|
2379
|
+
subscriber.next({
|
|
2380
|
+
user: detector.userState,
|
|
2381
|
+
screen: detector.screenState,
|
|
2382
|
+
});
|
|
2383
|
+
});
|
|
2384
|
+
detector
|
|
2385
|
+
.start({
|
|
2386
|
+
threshold: options.threshold ?? 60_000,
|
|
2387
|
+
signal: abortController.signal,
|
|
2388
|
+
})
|
|
2389
|
+
.catch((err) => subscriber.error(err));
|
|
2390
|
+
return () => abortController.abort();
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2394
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService });
|
|
2395
|
+
}
|
|
2396
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: IdleDetectorService, decorators: [{
|
|
2397
|
+
type: Injectable
|
|
2398
|
+
}] });
|
|
2399
|
+
|
|
2400
|
+
function getEyeDropperClass() {
|
|
2401
|
+
return window.EyeDropper;
|
|
2402
|
+
}
|
|
2403
|
+
class EyeDropperService {
|
|
2404
|
+
platformId = inject(PLATFORM_ID);
|
|
2405
|
+
isSupported() {
|
|
2406
|
+
return isPlatformBrowser(this.platformId) && 'EyeDropper' in window;
|
|
2407
|
+
}
|
|
2408
|
+
async open(signal) {
|
|
2409
|
+
if (!this.isSupported()) {
|
|
2410
|
+
throw new Error('EyeDropper API not supported');
|
|
2411
|
+
}
|
|
2412
|
+
const dropper = new (getEyeDropperClass())();
|
|
2413
|
+
return dropper.open(signal ? { signal } : undefined);
|
|
2414
|
+
}
|
|
2415
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2416
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService });
|
|
2417
|
+
}
|
|
2418
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: EyeDropperService, decorators: [{
|
|
2419
|
+
type: Injectable
|
|
2420
|
+
}] });
|
|
2421
|
+
|
|
2422
|
+
function getBarcodeDetectorClass() {
|
|
2423
|
+
return window.BarcodeDetector;
|
|
2424
|
+
}
|
|
2425
|
+
class BarcodeDetectorService {
|
|
2426
|
+
platformId = inject(PLATFORM_ID);
|
|
2427
|
+
isSupported() {
|
|
2428
|
+
return isPlatformBrowser(this.platformId) && 'BarcodeDetector' in window;
|
|
2429
|
+
}
|
|
2430
|
+
async getSupportedFormats() {
|
|
2431
|
+
if (!this.isSupported())
|
|
2432
|
+
return [];
|
|
2433
|
+
return getBarcodeDetectorClass().getSupportedFormats();
|
|
2434
|
+
}
|
|
2435
|
+
async detect(image, formats) {
|
|
2436
|
+
if (!this.isSupported()) {
|
|
2437
|
+
throw new Error('BarcodeDetector API not supported');
|
|
2438
|
+
}
|
|
2439
|
+
const detector = formats
|
|
2440
|
+
? new (getBarcodeDetectorClass())({ formats })
|
|
2441
|
+
: new (getBarcodeDetectorClass())();
|
|
2442
|
+
return detector.detect(image);
|
|
2443
|
+
}
|
|
2444
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2445
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService });
|
|
2446
|
+
}
|
|
2447
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: BarcodeDetectorService, decorators: [{
|
|
2448
|
+
type: Injectable
|
|
2449
|
+
}] });
|
|
2450
|
+
|
|
2451
|
+
class WebAudioService {
|
|
2452
|
+
platformId = inject(PLATFORM_ID);
|
|
2453
|
+
destroyRef = inject(DestroyRef);
|
|
2454
|
+
context = null;
|
|
2455
|
+
isSupported() {
|
|
2456
|
+
return isPlatformBrowser(this.platformId) && 'AudioContext' in window;
|
|
2457
|
+
}
|
|
2458
|
+
getContext() {
|
|
2459
|
+
if (!this.isSupported()) {
|
|
2460
|
+
throw new Error('Web Audio API not supported');
|
|
2461
|
+
}
|
|
2462
|
+
if (!this.context || this.context.state === 'closed') {
|
|
2463
|
+
this.context = new AudioContext();
|
|
2464
|
+
this.destroyRef.onDestroy(() => this.close());
|
|
2465
|
+
}
|
|
2466
|
+
return this.context;
|
|
2467
|
+
}
|
|
2468
|
+
async resume() {
|
|
2469
|
+
const ctx = this.getContext();
|
|
2470
|
+
if (ctx.state === 'suspended') {
|
|
2471
|
+
await ctx.resume();
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
async close() {
|
|
2475
|
+
if (this.context && this.context.state !== 'closed') {
|
|
2476
|
+
await this.context.close();
|
|
2477
|
+
this.context = null;
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
getState() {
|
|
2481
|
+
return (this.context?.state ?? 'closed');
|
|
2482
|
+
}
|
|
2483
|
+
createOscillator(type = 'sine', frequency = 440) {
|
|
2484
|
+
const ctx = this.getContext();
|
|
2485
|
+
const oscillator = ctx.createOscillator();
|
|
2486
|
+
oscillator.type = type;
|
|
2487
|
+
oscillator.frequency.value = frequency;
|
|
2488
|
+
return oscillator;
|
|
2489
|
+
}
|
|
2490
|
+
createGain(value = 1) {
|
|
2491
|
+
const ctx = this.getContext();
|
|
2492
|
+
const gain = ctx.createGain();
|
|
2493
|
+
gain.gain.value = value;
|
|
2494
|
+
return gain;
|
|
2495
|
+
}
|
|
2496
|
+
createAnalyser(fftSize = 2048) {
|
|
2497
|
+
const ctx = this.getContext();
|
|
2498
|
+
const analyser = ctx.createAnalyser();
|
|
2499
|
+
analyser.fftSize = fftSize;
|
|
2500
|
+
return analyser;
|
|
2501
|
+
}
|
|
2502
|
+
watchAnalyser(analyser, intervalMs = 50) {
|
|
2503
|
+
return new Observable((subscriber) => {
|
|
2504
|
+
const frequencyData = new Uint8Array(analyser.frequencyBinCount);
|
|
2505
|
+
const timeDomainData = new Uint8Array(analyser.frequencyBinCount);
|
|
2506
|
+
const interval = setInterval(() => {
|
|
2507
|
+
analyser.getByteFrequencyData(frequencyData);
|
|
2508
|
+
analyser.getByteTimeDomainData(timeDomainData);
|
|
2509
|
+
subscriber.next({
|
|
2510
|
+
frequencyData: new Uint8Array(frequencyData),
|
|
2511
|
+
timeDomainData: new Uint8Array(timeDomainData),
|
|
2512
|
+
});
|
|
2513
|
+
}, intervalMs);
|
|
2514
|
+
return () => clearInterval(interval);
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
async decodeAudioData(arrayBuffer) {
|
|
2518
|
+
const ctx = this.getContext();
|
|
2519
|
+
return ctx.decodeAudioData(arrayBuffer);
|
|
2520
|
+
}
|
|
2521
|
+
playBuffer(buffer, loop = false) {
|
|
2522
|
+
const ctx = this.getContext();
|
|
2523
|
+
const source = ctx.createBufferSource();
|
|
2524
|
+
source.buffer = buffer;
|
|
2525
|
+
source.loop = loop;
|
|
2526
|
+
source.connect(ctx.destination);
|
|
2527
|
+
source.start(0);
|
|
2528
|
+
return source;
|
|
2529
|
+
}
|
|
2530
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2531
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService });
|
|
2532
|
+
}
|
|
2533
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebAudioService, decorators: [{
|
|
2534
|
+
type: Injectable
|
|
2535
|
+
}] });
|
|
2536
|
+
|
|
2537
|
+
function isGamepadSupported() {
|
|
2538
|
+
return typeof navigator !== 'undefined' && 'getGamepads' in navigator;
|
|
2539
|
+
}
|
|
2540
|
+
function gamepadSnapshot(index) {
|
|
2541
|
+
const gp = navigator.getGamepads()[index];
|
|
2542
|
+
if (!gp)
|
|
2543
|
+
return null;
|
|
2544
|
+
return {
|
|
2545
|
+
id: gp.id,
|
|
2546
|
+
index: gp.index,
|
|
2547
|
+
connected: gp.connected,
|
|
2548
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2549
|
+
axes: Array.from(gp.axes),
|
|
2550
|
+
timestamp: gp.timestamp,
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
function gamepadConnectionStream() {
|
|
2554
|
+
return new Observable((subscriber) => {
|
|
2555
|
+
const onConnect = (e) => {
|
|
2556
|
+
const gp = e.gamepad;
|
|
2557
|
+
subscriber.next({
|
|
2558
|
+
type: 'connected',
|
|
2559
|
+
gamepad: {
|
|
2560
|
+
id: gp.id,
|
|
2561
|
+
index: gp.index,
|
|
2562
|
+
connected: true,
|
|
2563
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2564
|
+
axes: Array.from(gp.axes),
|
|
2565
|
+
timestamp: gp.timestamp,
|
|
2566
|
+
},
|
|
2567
|
+
});
|
|
2568
|
+
};
|
|
2569
|
+
const onDisconnect = (e) => {
|
|
2570
|
+
subscriber.next({
|
|
2571
|
+
type: 'disconnected',
|
|
2572
|
+
gamepad: {
|
|
2573
|
+
id: e.gamepad.id,
|
|
2574
|
+
index: e.gamepad.index,
|
|
2575
|
+
connected: false,
|
|
2576
|
+
buttons: [],
|
|
2577
|
+
axes: [],
|
|
2578
|
+
timestamp: e.gamepad.timestamp,
|
|
2579
|
+
},
|
|
2580
|
+
});
|
|
2581
|
+
};
|
|
2582
|
+
window.addEventListener('gamepadconnected', onConnect);
|
|
2583
|
+
window.addEventListener('gamepaddisconnected', onDisconnect);
|
|
2584
|
+
return () => {
|
|
2585
|
+
window.removeEventListener('gamepadconnected', onConnect);
|
|
2586
|
+
window.removeEventListener('gamepaddisconnected', onDisconnect);
|
|
2587
|
+
};
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
function gamepadPollStream(index, intervalMs = 16) {
|
|
2591
|
+
return new Observable((subscriber) => {
|
|
2592
|
+
let rafId;
|
|
2593
|
+
const poll = () => {
|
|
2594
|
+
const state = gamepadSnapshot(index);
|
|
2595
|
+
if (state) {
|
|
2596
|
+
subscriber.next(state);
|
|
2597
|
+
}
|
|
2598
|
+
rafId = requestAnimationFrame(poll);
|
|
2599
|
+
};
|
|
2600
|
+
if (intervalMs <= 16) {
|
|
2601
|
+
rafId = requestAnimationFrame(poll);
|
|
2602
|
+
return () => cancelAnimationFrame(rafId);
|
|
2603
|
+
}
|
|
2604
|
+
const intervalId = setInterval(() => {
|
|
2605
|
+
const state = gamepadSnapshot(index);
|
|
2606
|
+
if (state)
|
|
2607
|
+
subscriber.next(state);
|
|
2608
|
+
}, intervalMs);
|
|
2609
|
+
return () => clearInterval(intervalId);
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
class GamepadService {
|
|
2614
|
+
platformId = inject(PLATFORM_ID);
|
|
2615
|
+
isSupported() {
|
|
2616
|
+
return isPlatformBrowser(this.platformId) && isGamepadSupported();
|
|
2617
|
+
}
|
|
2618
|
+
getSnapshot(index) {
|
|
2619
|
+
if (!this.isSupported())
|
|
2620
|
+
return null;
|
|
2621
|
+
return gamepadSnapshot(index);
|
|
2622
|
+
}
|
|
2623
|
+
getConnectedGamepads() {
|
|
2624
|
+
if (!this.isSupported())
|
|
2625
|
+
return [];
|
|
2626
|
+
return navigator
|
|
2627
|
+
.getGamepads()
|
|
2628
|
+
.filter((gp) => gp !== null)
|
|
2629
|
+
.map((gp) => ({
|
|
2630
|
+
id: gp.id,
|
|
2631
|
+
index: gp.index,
|
|
2632
|
+
connected: gp.connected,
|
|
2633
|
+
buttons: gp.buttons.map((b) => ({ pressed: b.pressed, value: b.value })),
|
|
2634
|
+
axes: Array.from(gp.axes),
|
|
2635
|
+
timestamp: gp.timestamp,
|
|
2636
|
+
}));
|
|
2637
|
+
}
|
|
2638
|
+
watchConnections() {
|
|
2639
|
+
if (!this.isSupported()) {
|
|
2640
|
+
return new Observable((o) => o.error(new Error('Gamepad API not supported')));
|
|
2641
|
+
}
|
|
2642
|
+
return gamepadConnectionStream();
|
|
2643
|
+
}
|
|
2644
|
+
poll(index, intervalMs = 16) {
|
|
2645
|
+
if (!this.isSupported()) {
|
|
2646
|
+
return new Observable((o) => o.error(new Error('Gamepad API not supported')));
|
|
2647
|
+
}
|
|
2648
|
+
return gamepadPollStream(index, intervalMs);
|
|
2649
|
+
}
|
|
2650
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2651
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService });
|
|
2652
|
+
}
|
|
2653
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: GamepadService, decorators: [{
|
|
2654
|
+
type: Injectable
|
|
2655
|
+
}] });
|
|
2656
|
+
|
|
2657
|
+
function getBluetooth() {
|
|
2658
|
+
return navigator.bluetooth;
|
|
2659
|
+
}
|
|
2660
|
+
class WebBluetoothService {
|
|
2661
|
+
platformId = inject(PLATFORM_ID);
|
|
2662
|
+
isSupported() {
|
|
2663
|
+
return isPlatformBrowser(this.platformId) && !!getBluetooth();
|
|
2664
|
+
}
|
|
2665
|
+
async requestDevice(options = { acceptAllDevices: true }) {
|
|
2666
|
+
if (!this.isSupported()) {
|
|
2667
|
+
throw new Error('Web Bluetooth API not supported');
|
|
2668
|
+
}
|
|
2669
|
+
return getBluetooth().requestDevice(options);
|
|
2670
|
+
}
|
|
2671
|
+
async connect(device) {
|
|
2672
|
+
if (!device.gatt) {
|
|
2673
|
+
throw new Error('GATT server not available on this device');
|
|
2674
|
+
}
|
|
2675
|
+
return device.gatt.connect();
|
|
2676
|
+
}
|
|
2677
|
+
disconnect(device) {
|
|
2678
|
+
device.gatt?.disconnect();
|
|
2679
|
+
}
|
|
2680
|
+
watchDisconnection(device) {
|
|
2681
|
+
return new Observable((subscriber) => {
|
|
2682
|
+
const handler = () => subscriber.next();
|
|
2683
|
+
device.addEventListener('gattserverdisconnected', handler);
|
|
2684
|
+
return () => device.removeEventListener('gattserverdisconnected', handler);
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
async readCharacteristic(server, serviceUuid, characteristicUuid) {
|
|
2688
|
+
const service = await server.getPrimaryService(serviceUuid);
|
|
2689
|
+
const characteristic = await service.getCharacteristic(characteristicUuid);
|
|
2690
|
+
return characteristic.readValue();
|
|
2691
|
+
}
|
|
2692
|
+
async writeCharacteristic(server, serviceUuid, characteristicUuid, value) {
|
|
2693
|
+
const service = await server.getPrimaryService(serviceUuid);
|
|
2694
|
+
const characteristic = await service.getCharacteristic(characteristicUuid);
|
|
2695
|
+
await characteristic.writeValue(value);
|
|
2696
|
+
}
|
|
2697
|
+
watchCharacteristic(server, serviceUuid, characteristicUuid) {
|
|
2698
|
+
return new Observable((subscriber) => {
|
|
2699
|
+
let characteristic;
|
|
2700
|
+
server
|
|
2701
|
+
.getPrimaryService(serviceUuid)
|
|
2702
|
+
.then((service) => service.getCharacteristic(characteristicUuid))
|
|
2703
|
+
.then((char) => {
|
|
2704
|
+
characteristic = char;
|
|
2705
|
+
const handler = (event) => {
|
|
2706
|
+
const target = event.target;
|
|
2707
|
+
if (target.value)
|
|
2708
|
+
subscriber.next(target.value);
|
|
2709
|
+
};
|
|
2710
|
+
characteristic.addEventListener('characteristicvaluechanged', handler);
|
|
2711
|
+
return characteristic.startNotifications();
|
|
2712
|
+
})
|
|
2713
|
+
.catch((err) => subscriber.error(err));
|
|
2714
|
+
return () => {
|
|
2715
|
+
characteristic?.stopNotifications().catch(() => { });
|
|
2716
|
+
};
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2720
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService });
|
|
2721
|
+
}
|
|
2722
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebBluetoothService, decorators: [{
|
|
2723
|
+
type: Injectable
|
|
2724
|
+
}] });
|
|
2725
|
+
|
|
2726
|
+
function getUsb() {
|
|
2727
|
+
return navigator.usb;
|
|
2728
|
+
}
|
|
2729
|
+
class WebUsbService {
|
|
2730
|
+
platformId = inject(PLATFORM_ID);
|
|
2731
|
+
isSupported() {
|
|
2732
|
+
return isPlatformBrowser(this.platformId) && !!getUsb();
|
|
2733
|
+
}
|
|
2734
|
+
async requestDevice(filters = []) {
|
|
2735
|
+
if (!this.isSupported()) {
|
|
2736
|
+
throw new Error('WebUSB API not supported');
|
|
2737
|
+
}
|
|
2738
|
+
return getUsb().requestDevice({ filters });
|
|
2739
|
+
}
|
|
2740
|
+
async getDevices() {
|
|
2741
|
+
if (!this.isSupported())
|
|
2742
|
+
return [];
|
|
2743
|
+
return getUsb().getDevices();
|
|
2744
|
+
}
|
|
2745
|
+
async open(device) {
|
|
2746
|
+
await device.open();
|
|
2747
|
+
}
|
|
2748
|
+
async close(device) {
|
|
2749
|
+
await device.close();
|
|
2750
|
+
}
|
|
2751
|
+
async selectConfiguration(device, configurationValue) {
|
|
2752
|
+
await device.selectConfiguration(configurationValue);
|
|
2753
|
+
}
|
|
2754
|
+
async claimInterface(device, interfaceNumber) {
|
|
2755
|
+
await device.claimInterface(interfaceNumber);
|
|
2756
|
+
}
|
|
2757
|
+
async releaseInterface(device, interfaceNumber) {
|
|
2758
|
+
await device.releaseInterface(interfaceNumber);
|
|
2759
|
+
}
|
|
2760
|
+
async transferIn(device, endpointNumber, length) {
|
|
2761
|
+
return device.transferIn(endpointNumber, length);
|
|
2762
|
+
}
|
|
2763
|
+
async transferOut(device, endpointNumber, data) {
|
|
2764
|
+
return device.transferOut(endpointNumber, data);
|
|
2765
|
+
}
|
|
2766
|
+
watchConnection() {
|
|
2767
|
+
if (!this.isSupported()) {
|
|
2768
|
+
return new Observable((o) => o.error(new Error('WebUSB API not supported')));
|
|
2769
|
+
}
|
|
2770
|
+
return new Observable((subscriber) => {
|
|
2771
|
+
const usb = getUsb();
|
|
2772
|
+
const onConnect = (e) => subscriber.next({ device: e.device, type: 'connect' });
|
|
2773
|
+
const onDisconnect = (e) => subscriber.next({ device: e.device, type: 'disconnect' });
|
|
2774
|
+
usb.addEventListener('connect', onConnect);
|
|
2775
|
+
usb.addEventListener('disconnect', onDisconnect);
|
|
2776
|
+
return () => {
|
|
2777
|
+
usb.removeEventListener('connect', onConnect);
|
|
2778
|
+
usb.removeEventListener('disconnect', onDisconnect);
|
|
2779
|
+
};
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
getDeviceInfo(device) {
|
|
2783
|
+
return {
|
|
2784
|
+
vendorId: device.vendorId,
|
|
2785
|
+
productId: device.productId,
|
|
2786
|
+
productName: device.productName,
|
|
2787
|
+
manufacturerName: device.manufacturerName,
|
|
2788
|
+
serialNumber: device.serialNumber,
|
|
2789
|
+
opened: device.opened,
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2793
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService });
|
|
2794
|
+
}
|
|
2795
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebUsbService, decorators: [{
|
|
2796
|
+
type: Injectable
|
|
2797
|
+
}] });
|
|
2798
|
+
|
|
2799
|
+
function getNdefReaderClass() {
|
|
2800
|
+
return window.NDEFReader;
|
|
2801
|
+
}
|
|
2802
|
+
class WebNfcService {
|
|
2803
|
+
platformId = inject(PLATFORM_ID);
|
|
2804
|
+
isSupported() {
|
|
2805
|
+
return isPlatformBrowser(this.platformId) && 'NDEFReader' in window;
|
|
2806
|
+
}
|
|
2807
|
+
scan() {
|
|
2808
|
+
if (!this.isSupported()) {
|
|
2809
|
+
return new Observable((o) => o.error(new Error('Web NFC API not supported')));
|
|
2810
|
+
}
|
|
2811
|
+
return new Observable((subscriber) => {
|
|
2812
|
+
const abortController = new AbortController();
|
|
2813
|
+
const reader = new (getNdefReaderClass())();
|
|
2814
|
+
const onReading = (event) => {
|
|
2815
|
+
const e = event;
|
|
2816
|
+
subscriber.next({
|
|
2817
|
+
serialNumber: e.serialNumber,
|
|
2818
|
+
message: e.message,
|
|
2819
|
+
});
|
|
2820
|
+
};
|
|
2821
|
+
const onError = (event) => {
|
|
2822
|
+
subscriber.error(event.error ?? new Error('NFC read error'));
|
|
2823
|
+
};
|
|
2824
|
+
reader.addEventListener('reading', onReading);
|
|
2825
|
+
reader.addEventListener('readingerror', onError);
|
|
2826
|
+
reader
|
|
2827
|
+
.scan({ signal: abortController.signal })
|
|
2828
|
+
.catch((err) => subscriber.error(err));
|
|
2829
|
+
return () => abortController.abort();
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
async write(message, options) {
|
|
2833
|
+
if (!this.isSupported()) {
|
|
2834
|
+
throw new Error('Web NFC API not supported');
|
|
2835
|
+
}
|
|
2836
|
+
const reader = new (getNdefReaderClass())();
|
|
2837
|
+
await reader.write(message, options);
|
|
2838
|
+
}
|
|
2839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2840
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService });
|
|
2841
|
+
}
|
|
2842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: WebNfcService, decorators: [{
|
|
2843
|
+
type: Injectable
|
|
2844
|
+
}] });
|
|
2845
|
+
|
|
2846
|
+
class PaymentRequestService {
|
|
2847
|
+
platformId = inject(PLATFORM_ID);
|
|
2848
|
+
isSupported() {
|
|
2849
|
+
return isPlatformBrowser(this.platformId) && 'PaymentRequest' in window;
|
|
2850
|
+
}
|
|
2851
|
+
async canMakePayment(methods, details) {
|
|
2852
|
+
if (!this.isSupported())
|
|
2853
|
+
return false;
|
|
2854
|
+
const request = new PaymentRequest(methods, details);
|
|
2855
|
+
return request.canMakePayment();
|
|
2856
|
+
}
|
|
2857
|
+
async show(methods, details, options) {
|
|
2858
|
+
if (!this.isSupported()) {
|
|
2859
|
+
throw new Error('Payment Request API not supported');
|
|
2860
|
+
}
|
|
2861
|
+
const request = new PaymentRequest(methods, details, options);
|
|
2862
|
+
const response = await request.show();
|
|
2863
|
+
const result = {
|
|
2864
|
+
methodName: response.methodName,
|
|
2865
|
+
details: response.details,
|
|
2866
|
+
payerName: response.payerName ?? null,
|
|
2867
|
+
payerEmail: response.payerEmail ?? null,
|
|
2868
|
+
payerPhone: response.payerPhone ?? null,
|
|
2869
|
+
};
|
|
2870
|
+
await response.complete('success');
|
|
2871
|
+
return result;
|
|
2872
|
+
}
|
|
2873
|
+
async abort(methods, details) {
|
|
2874
|
+
if (!this.isSupported())
|
|
2875
|
+
return;
|
|
2876
|
+
const request = new PaymentRequest(methods, details);
|
|
2877
|
+
await request.abort();
|
|
2878
|
+
}
|
|
2879
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2880
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService });
|
|
2881
|
+
}
|
|
2882
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PaymentRequestService, decorators: [{
|
|
2883
|
+
type: Injectable
|
|
2884
|
+
}] });
|
|
2885
|
+
|
|
2886
|
+
class CredentialManagementService {
|
|
2887
|
+
platformId = inject(PLATFORM_ID);
|
|
2888
|
+
isSupported() {
|
|
2889
|
+
return isPlatformBrowser(this.platformId) && 'credentials' in navigator;
|
|
2890
|
+
}
|
|
2891
|
+
isPublicKeySupported() {
|
|
2892
|
+
return this.isSupported() && 'PublicKeyCredential' in window;
|
|
2893
|
+
}
|
|
2894
|
+
async get(options) {
|
|
2895
|
+
if (!this.isSupported()) {
|
|
2896
|
+
throw new Error('Credential Management API not supported');
|
|
2897
|
+
}
|
|
2898
|
+
return navigator.credentials.get(options);
|
|
2899
|
+
}
|
|
2900
|
+
async store(credential) {
|
|
2901
|
+
if (!this.isSupported()) {
|
|
2902
|
+
throw new Error('Credential Management API not supported');
|
|
2903
|
+
}
|
|
2904
|
+
await navigator.credentials.store(credential);
|
|
2905
|
+
}
|
|
2906
|
+
async createPasswordCredential(data) {
|
|
2907
|
+
if (!this.isSupported()) {
|
|
2908
|
+
throw new Error('Credential Management API not supported');
|
|
2909
|
+
}
|
|
2910
|
+
return navigator.credentials.create({
|
|
2911
|
+
password: data,
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
async createPublicKeyCredential(options) {
|
|
2915
|
+
if (!this.isPublicKeySupported()) {
|
|
2916
|
+
throw new Error('PublicKeyCredential API not supported');
|
|
2917
|
+
}
|
|
2918
|
+
return navigator.credentials.create({
|
|
2919
|
+
publicKey: options,
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
async preventSilentAccess() {
|
|
2923
|
+
if (!this.isSupported())
|
|
2924
|
+
return;
|
|
2925
|
+
await navigator.credentials.preventSilentAccess();
|
|
2926
|
+
}
|
|
2927
|
+
async isConditionalMediationAvailable() {
|
|
2928
|
+
if (!this.isPublicKeySupported())
|
|
2929
|
+
return false;
|
|
2930
|
+
if ('isConditionalMediationAvailable' in PublicKeyCredential) {
|
|
2931
|
+
return PublicKeyCredential.isConditionalMediationAvailable();
|
|
2932
|
+
}
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2936
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService });
|
|
2937
|
+
}
|
|
2938
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CredentialManagementService, decorators: [{
|
|
2939
|
+
type: Injectable
|
|
2940
|
+
}] });
|
|
2941
|
+
|
|
2240
2942
|
// Common types for browser APIs
|
|
2241
2943
|
|
|
2242
2944
|
function injectPageVisibility() {
|
|
@@ -2260,9 +2962,23 @@ function injectResizeObserver(elementOrRef, options) {
|
|
|
2260
2962
|
const platformId = inject(PLATFORM_ID);
|
|
2261
2963
|
const size = signal(null, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2262
2964
|
if (isPlatformBrowser(platformId) && isResizeObserverSupported()) {
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2965
|
+
if (isSignal(elementOrRef)) {
|
|
2966
|
+
let sub;
|
|
2967
|
+
effect((onCleanup) => {
|
|
2968
|
+
sub?.unsubscribe();
|
|
2969
|
+
const raw = elementOrRef();
|
|
2970
|
+
if (raw) {
|
|
2971
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
2972
|
+
sub = resizeObserverStream(el, options).subscribe((s) => size.set(s));
|
|
2973
|
+
}
|
|
2974
|
+
onCleanup(() => sub?.unsubscribe());
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
else {
|
|
2978
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
2979
|
+
const sub = resizeObserverStream(el, options).subscribe((s) => size.set(s));
|
|
2980
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
2981
|
+
}
|
|
2266
2982
|
}
|
|
2267
2983
|
return {
|
|
2268
2984
|
size: size.asReadonly(),
|
|
@@ -2278,9 +2994,23 @@ function injectIntersectionObserver(elementOrRef, options) {
|
|
|
2278
2994
|
const platformId = inject(PLATFORM_ID);
|
|
2279
2995
|
const isIntersecting = signal(false, ...(ngDevMode ? [{ debugName: "isIntersecting" }] : /* istanbul ignore next */ []));
|
|
2280
2996
|
if (isPlatformBrowser(platformId) && isIntersectionObserverSupported()) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2997
|
+
if (isSignal(elementOrRef)) {
|
|
2998
|
+
let sub;
|
|
2999
|
+
effect((onCleanup) => {
|
|
3000
|
+
sub?.unsubscribe();
|
|
3001
|
+
const raw = elementOrRef();
|
|
3002
|
+
if (raw) {
|
|
3003
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
3004
|
+
sub = intersectionObserverStream(el, options).subscribe((v) => isIntersecting.set(v));
|
|
3005
|
+
}
|
|
3006
|
+
onCleanup(() => sub?.unsubscribe());
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
else {
|
|
3010
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
3011
|
+
const sub = intersectionObserverStream(el, options).subscribe((v) => isIntersecting.set(v));
|
|
3012
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3013
|
+
}
|
|
2284
3014
|
}
|
|
2285
3015
|
return {
|
|
2286
3016
|
isIntersecting: isIntersecting.asReadonly(),
|
|
@@ -2328,6 +3058,102 @@ function injectScreenOrientation() {
|
|
|
2328
3058
|
};
|
|
2329
3059
|
}
|
|
2330
3060
|
|
|
3061
|
+
function injectMutationObserver(elementOrRef, options) {
|
|
3062
|
+
const destroyRef = inject(DestroyRef);
|
|
3063
|
+
const platformId = inject(PLATFORM_ID);
|
|
3064
|
+
const mutations = signal([], ...(ngDevMode ? [{ debugName: "mutations" }] : /* istanbul ignore next */ []));
|
|
3065
|
+
if (isPlatformBrowser(platformId) && isMutationObserverSupported()) {
|
|
3066
|
+
if (isSignal(elementOrRef)) {
|
|
3067
|
+
let sub;
|
|
3068
|
+
effect((onCleanup) => {
|
|
3069
|
+
sub?.unsubscribe();
|
|
3070
|
+
const raw = elementOrRef();
|
|
3071
|
+
if (raw) {
|
|
3072
|
+
const el = raw instanceof ElementRef ? raw.nativeElement : raw;
|
|
3073
|
+
sub = mutationObserverStream(el, options).subscribe((m) => mutations.set(m));
|
|
3074
|
+
}
|
|
3075
|
+
onCleanup(() => sub?.unsubscribe());
|
|
3076
|
+
});
|
|
3077
|
+
}
|
|
3078
|
+
else {
|
|
3079
|
+
const el = elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
|
|
3080
|
+
const sub = mutationObserverStream(el, options).subscribe((m) => mutations.set(m));
|
|
3081
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
return {
|
|
3085
|
+
mutations: mutations.asReadonly(),
|
|
3086
|
+
mutationCount: computed(() => mutations().length),
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
function injectPerformanceObserver(config) {
|
|
3091
|
+
const destroyRef = inject(DestroyRef);
|
|
3092
|
+
const platformId = inject(PLATFORM_ID);
|
|
3093
|
+
const entries = signal([], ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
|
|
3094
|
+
if (isPlatformBrowser(platformId) && isPerformanceObserverSupported()) {
|
|
3095
|
+
const sub = performanceObserverStream(config).subscribe((e) => entries.set(e));
|
|
3096
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3097
|
+
}
|
|
3098
|
+
return {
|
|
3099
|
+
entries: entries.asReadonly(),
|
|
3100
|
+
entryCount: computed(() => entries().length),
|
|
3101
|
+
latestEntry: computed(() => entries().at(-1)),
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
function getIdleDetectorClass() {
|
|
3106
|
+
return window.IdleDetector;
|
|
3107
|
+
}
|
|
3108
|
+
function injectIdleDetector(options = {}) {
|
|
3109
|
+
const destroyRef = inject(DestroyRef);
|
|
3110
|
+
const platformId = inject(PLATFORM_ID);
|
|
3111
|
+
const defaultState = { user: 'active', screen: 'unlocked' };
|
|
3112
|
+
const state = signal(defaultState, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
3113
|
+
if (isPlatformBrowser(platformId) && 'IdleDetector' in window) {
|
|
3114
|
+
const abortController = new AbortController();
|
|
3115
|
+
const detector = new (getIdleDetectorClass())();
|
|
3116
|
+
detector.addEventListener('change', () => {
|
|
3117
|
+
state.set({
|
|
3118
|
+
user: detector.userState,
|
|
3119
|
+
screen: detector.screenState,
|
|
3120
|
+
});
|
|
3121
|
+
});
|
|
3122
|
+
detector
|
|
3123
|
+
.start({
|
|
3124
|
+
threshold: options.threshold ?? 60_000,
|
|
3125
|
+
signal: abortController.signal,
|
|
3126
|
+
})
|
|
3127
|
+
.catch(() => {
|
|
3128
|
+
/* permission denied or unsupported — keep defaults */
|
|
3129
|
+
});
|
|
3130
|
+
destroyRef.onDestroy(() => abortController.abort());
|
|
3131
|
+
}
|
|
3132
|
+
return {
|
|
3133
|
+
state: state.asReadonly(),
|
|
3134
|
+
userState: computed(() => state().user),
|
|
3135
|
+
screenState: computed(() => state().screen),
|
|
3136
|
+
isUserIdle: computed(() => state().user === 'idle'),
|
|
3137
|
+
isScreenLocked: computed(() => state().screen === 'locked'),
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
function injectGamepad(index, intervalMs = 16) {
|
|
3142
|
+
const destroyRef = inject(DestroyRef);
|
|
3143
|
+
const platformId = inject(PLATFORM_ID);
|
|
3144
|
+
const state = signal(null, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
3145
|
+
if (isPlatformBrowser(platformId) && isGamepadSupported()) {
|
|
3146
|
+
const sub = gamepadPollStream(index, intervalMs).subscribe((s) => state.set(s));
|
|
3147
|
+
destroyRef.onDestroy(() => sub.unsubscribe());
|
|
3148
|
+
}
|
|
3149
|
+
return {
|
|
3150
|
+
state: state.asReadonly(),
|
|
3151
|
+
connected: computed(() => state()?.connected ?? false),
|
|
3152
|
+
buttons: computed(() => state()?.buttons ?? []),
|
|
3153
|
+
axes: computed(() => state()?.axes ?? []),
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
|
|
2331
3157
|
class BrowserSupportUtil {
|
|
2332
3158
|
static isSupported(feature) {
|
|
2333
3159
|
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
@@ -2466,6 +3292,18 @@ const defaultBrowserWebApisConfig = {
|
|
|
2466
3292
|
enableServerSentEvents: false,
|
|
2467
3293
|
enableVibration: false,
|
|
2468
3294
|
enableSpeechSynthesis: false,
|
|
3295
|
+
enableMutationObserver: false,
|
|
3296
|
+
enablePerformanceObserver: false,
|
|
3297
|
+
enableIdleDetector: false,
|
|
3298
|
+
enableEyeDropper: false,
|
|
3299
|
+
enableBarcodeDetector: false,
|
|
3300
|
+
enableWebAudio: false,
|
|
3301
|
+
enableGamepad: false,
|
|
3302
|
+
enableWebBluetooth: false,
|
|
3303
|
+
enableWebUsb: false,
|
|
3304
|
+
enableWebNfc: false,
|
|
3305
|
+
enablePaymentRequest: false,
|
|
3306
|
+
enableCredentialManagement: false,
|
|
2469
3307
|
};
|
|
2470
3308
|
function provideBrowserWebApis(config = {}) {
|
|
2471
3309
|
const mergedConfig = { ...defaultBrowserWebApisConfig, ...config };
|
|
@@ -2494,6 +3332,18 @@ function provideBrowserWebApis(config = {}) {
|
|
|
2494
3332
|
[mergedConfig.enableServerSentEvents, ServerSentEventsService],
|
|
2495
3333
|
[mergedConfig.enableVibration, VibrationService],
|
|
2496
3334
|
[mergedConfig.enableSpeechSynthesis, SpeechSynthesisService],
|
|
3335
|
+
[mergedConfig.enableMutationObserver, MutationObserverService],
|
|
3336
|
+
[mergedConfig.enablePerformanceObserver, PerformanceObserverService],
|
|
3337
|
+
[mergedConfig.enableIdleDetector, IdleDetectorService],
|
|
3338
|
+
[mergedConfig.enableEyeDropper, EyeDropperService],
|
|
3339
|
+
[mergedConfig.enableBarcodeDetector, BarcodeDetectorService],
|
|
3340
|
+
[mergedConfig.enableWebAudio, WebAudioService],
|
|
3341
|
+
[mergedConfig.enableGamepad, GamepadService],
|
|
3342
|
+
[mergedConfig.enableWebBluetooth, WebBluetoothService],
|
|
3343
|
+
[mergedConfig.enableWebUsb, WebUsbService],
|
|
3344
|
+
[mergedConfig.enableWebNfc, WebNfcService],
|
|
3345
|
+
[mergedConfig.enablePaymentRequest, PaymentRequestService],
|
|
3346
|
+
[mergedConfig.enableCredentialManagement, CredentialManagementService],
|
|
2497
3347
|
];
|
|
2498
3348
|
for (const [enabled, provider] of conditionalProviders) {
|
|
2499
3349
|
if (enabled) {
|
|
@@ -2593,6 +3443,42 @@ function provideVibration() {
|
|
|
2593
3443
|
function provideSpeechSynthesis() {
|
|
2594
3444
|
return makeEnvironmentProviders([SpeechSynthesisService]);
|
|
2595
3445
|
}
|
|
3446
|
+
function provideMutationObserver() {
|
|
3447
|
+
return makeEnvironmentProviders([MutationObserverService]);
|
|
3448
|
+
}
|
|
3449
|
+
function providePerformanceObserver() {
|
|
3450
|
+
return makeEnvironmentProviders([PerformanceObserverService]);
|
|
3451
|
+
}
|
|
3452
|
+
function provideIdleDetector() {
|
|
3453
|
+
return makeEnvironmentProviders([PermissionsService, IdleDetectorService]);
|
|
3454
|
+
}
|
|
3455
|
+
function provideEyeDropper() {
|
|
3456
|
+
return makeEnvironmentProviders([EyeDropperService]);
|
|
3457
|
+
}
|
|
3458
|
+
function provideBarcodeDetector() {
|
|
3459
|
+
return makeEnvironmentProviders([BarcodeDetectorService]);
|
|
3460
|
+
}
|
|
3461
|
+
function provideWebAudio() {
|
|
3462
|
+
return makeEnvironmentProviders([WebAudioService]);
|
|
3463
|
+
}
|
|
3464
|
+
function provideGamepad() {
|
|
3465
|
+
return makeEnvironmentProviders([GamepadService]);
|
|
3466
|
+
}
|
|
3467
|
+
function provideWebBluetooth() {
|
|
3468
|
+
return makeEnvironmentProviders([WebBluetoothService]);
|
|
3469
|
+
}
|
|
3470
|
+
function provideWebUsb() {
|
|
3471
|
+
return makeEnvironmentProviders([WebUsbService]);
|
|
3472
|
+
}
|
|
3473
|
+
function provideWebNfc() {
|
|
3474
|
+
return makeEnvironmentProviders([WebNfcService]);
|
|
3475
|
+
}
|
|
3476
|
+
function providePaymentRequest() {
|
|
3477
|
+
return makeEnvironmentProviders([PaymentRequestService]);
|
|
3478
|
+
}
|
|
3479
|
+
function provideCredentialManagement() {
|
|
3480
|
+
return makeEnvironmentProviders([CredentialManagementService]);
|
|
3481
|
+
}
|
|
2596
3482
|
|
|
2597
3483
|
// Browser Web APIs Services
|
|
2598
3484
|
// Version
|
|
@@ -2602,4 +3488,4 @@ const version = '0.1.0';
|
|
|
2602
3488
|
* Generated bundle index. Do not edit.
|
|
2603
3489
|
*/
|
|
2604
3490
|
|
|
2605
|
-
export { BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, FileSystemAccessService, FullscreenService, GeolocationService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, NetworkInformationService, NotificationService, PageVisibilityService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebShareService, WebSocketService, WebStorageService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectIntersectionObserver, injectNetworkInformation, injectPageVisibility, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideFileSystemAccess, provideFullscreen, provideGeolocation, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideNetworkInformation, provideNotifications, providePageVisibility, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebShare, provideWebSocket, provideWebStorage, provideWebWorker, version };
|
|
3491
|
+
export { BarcodeDetectorService, BatteryService, BroadcastChannelService, BrowserApiBaseService, BrowserCapabilityService, BrowserSupportUtil, CameraService, ClipboardService, CredentialManagementService, EyeDropperService, FileSystemAccessService, FullscreenService, GamepadService, GeolocationService, IdleDetectorService, IntersectionObserverService, MediaDevicesService, MediaRecorderService, MutationObserverService, NetworkInformationService, NotificationService, PageVisibilityService, PaymentRequestService, PerformanceObserverService, PermissionsService, ResizeObserverService, ScreenOrientationService, ScreenWakeLockService, ServerSentEventsService, SpeechSynthesisService, VibrationService, WebAudioService, WebBluetoothService, WebNfcService, WebShareService, WebSocketService, WebStorageService, WebUsbService, WebWorkerService, permissionGuard as createPermissionGuard, defaultBrowserWebApisConfig, injectGamepad, injectIdleDetector, injectIntersectionObserver, injectMutationObserver, injectNetworkInformation, injectPageVisibility, injectPerformanceObserver, injectResizeObserver, injectScreenOrientation, permissionGuard, provideBarcodeDetector, provideBattery, provideBroadcastChannel, provideBrowserWebApis, provideCamera, provideClipboard, provideCommunicationApis, provideCredentialManagement, provideEyeDropper, provideFileSystemAccess, provideFullscreen, provideGamepad, provideGeolocation, provideIdleDetector, provideIntersectionObserver, provideLocationApis, provideMediaApis, provideMediaDevices, provideMediaRecorder, provideMutationObserver, provideNetworkInformation, provideNotifications, providePageVisibility, providePaymentRequest, providePerformanceObserver, providePermissions, provideResizeObserver, provideScreenOrientation, provideScreenWakeLock, provideServerSentEvents, provideSpeechSynthesis, provideStorageApis, provideVibration, provideWebAudio, provideWebBluetooth, provideWebNfc, provideWebShare, provideWebSocket, provideWebStorage, provideWebUsb, provideWebWorker, version };
|