@angular-helpers/browser-web-apis 21.2.0 → 21.4.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 +1123 -140
- package/package.json +9 -1
- package/types/angular-helpers-browser-web-apis.d.ts +576 -54
package/README.es.md
CHANGED
|
@@ -550,6 +550,111 @@ export class WorkerComponent {
|
|
|
550
550
|
}
|
|
551
551
|
```
|
|
552
552
|
|
|
553
|
+
## Primitivas Signal Fn
|
|
554
|
+
|
|
555
|
+
Alternativas reactivas sin boilerplate a los servicios basados en RxJS. Cada funcion `inject*` retorna un objeto ref con signals de solo lectura y maneja la limpieza automaticamente via `DestroyRef`.
|
|
556
|
+
|
|
557
|
+
### injectPageVisibility
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import { injectPageVisibility } from '@angular-helpers/browser-web-apis';
|
|
561
|
+
|
|
562
|
+
@Component({...})
|
|
563
|
+
export class MyComponent {
|
|
564
|
+
readonly visibility = injectPageVisibility();
|
|
565
|
+
|
|
566
|
+
// visibility.state() → 'visible' | 'hidden'
|
|
567
|
+
// visibility.isVisible() → boolean
|
|
568
|
+
// visibility.isHidden() → boolean
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### injectResizeObserver
|
|
573
|
+
|
|
574
|
+
Acepta `Element`, `ElementRef`, o un **`Signal<ElementRef | undefined>`** (ej. de `viewChild`). Cuando se pasa un signal, el observer inicia automaticamente cuando el elemento esta disponible.
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
import { injectResizeObserver } from '@angular-helpers/browser-web-apis';
|
|
578
|
+
|
|
579
|
+
@Component({...})
|
|
580
|
+
export class MyComponent {
|
|
581
|
+
readonly boxRef = viewChild<ElementRef>('box');
|
|
582
|
+
readonly resize = injectResizeObserver(this.boxRef);
|
|
583
|
+
|
|
584
|
+
// resize.width() → number
|
|
585
|
+
// resize.height() → number
|
|
586
|
+
// resize.inlineSize() → number (logico)
|
|
587
|
+
// resize.blockSize() → number (logico)
|
|
588
|
+
// resize.size() → ElementSize | null
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### injectIntersectionObserver
|
|
593
|
+
|
|
594
|
+
Misma flexibilidad con `ElementInput` — funciona con signals de `viewChild` directamente.
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
import { injectIntersectionObserver } from '@angular-helpers/browser-web-apis';
|
|
598
|
+
|
|
599
|
+
@Component({...})
|
|
600
|
+
export class MyComponent {
|
|
601
|
+
readonly targetRef = viewChild<ElementRef>('target');
|
|
602
|
+
readonly inView = injectIntersectionObserver(this.targetRef, { threshold: 0.25 });
|
|
603
|
+
|
|
604
|
+
// inView.isIntersecting() → boolean
|
|
605
|
+
// inView.isVisible() → boolean
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### injectNetworkInformation
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
import { injectNetworkInformation } from '@angular-helpers/browser-web-apis';
|
|
613
|
+
|
|
614
|
+
@Component({...})
|
|
615
|
+
export class MyComponent {
|
|
616
|
+
readonly net = injectNetworkInformation();
|
|
617
|
+
|
|
618
|
+
// net.online() → boolean
|
|
619
|
+
// net.effectiveType() → '4g' | '3g' | '2g' | 'slow-2g' | undefined
|
|
620
|
+
// net.downlink() → number | undefined (Mbps)
|
|
621
|
+
// net.rtt() → number | undefined (ms)
|
|
622
|
+
// net.type() → ConnectionType | undefined
|
|
623
|
+
// net.saveData() → boolean | undefined
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### injectScreenOrientation
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
import { injectScreenOrientation } from '@angular-helpers/browser-web-apis';
|
|
631
|
+
|
|
632
|
+
@Component({...})
|
|
633
|
+
export class MyComponent {
|
|
634
|
+
readonly orientation = injectScreenOrientation();
|
|
635
|
+
|
|
636
|
+
// orientation.type() → OrientationType
|
|
637
|
+
// orientation.angle() → number
|
|
638
|
+
// orientation.isPortrait() → boolean
|
|
639
|
+
// orientation.isLandscape() → boolean
|
|
640
|
+
// orientation.lock('landscape') → Promise<void>
|
|
641
|
+
// orientation.unlock()
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### Tipo ElementInput
|
|
646
|
+
|
|
647
|
+
Tanto `injectResizeObserver` como `injectIntersectionObserver` aceptan el tipo `ElementInput`:
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
type ElementInput =
|
|
651
|
+
| Element
|
|
652
|
+
| ElementRef<Element>
|
|
653
|
+
| Signal<Element | ElementRef<Element> | undefined>;
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
Esto permite pasar un signal de `viewChild` directamente — la funcion usa internamente un `effect` para comenzar a observar cuando el elemento se renderiza, con limpieza automatica.
|
|
657
|
+
|
|
553
658
|
## Soporte de navegadores
|
|
554
659
|
|
|
555
660
|
Los servicios validan automaticamente el soporte del navegador y el manejo de rutas no soportadas:
|
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ Angular services package for a structured and secure access layer over browser W
|
|
|
29
29
|
|
|
30
30
|
- `IntersectionObserverService` - Detect when elements enter/exit viewport
|
|
31
31
|
- `ResizeObserverService` - Watch for element size changes
|
|
32
|
+
- `MutationObserverService` - Watch for DOM mutations
|
|
33
|
+
- `PerformanceObserverService` - Monitor performance entries (LCP, CLS, etc.)
|
|
32
34
|
|
|
33
35
|
### System APIs
|
|
34
36
|
|
|
@@ -39,6 +41,9 @@ Angular services package for a structured and secure access layer over browser W
|
|
|
39
41
|
- `FullscreenService` - Toggle fullscreen mode for elements
|
|
40
42
|
- `VibrationService` - Trigger haptic feedback patterns
|
|
41
43
|
- `SpeechSynthesisService` - Text-to-speech with voice selection
|
|
44
|
+
- `IdleDetectorService` - Detect user idle state and screen lock
|
|
45
|
+
- `GamepadService` - Game controller input polling
|
|
46
|
+
- `WebAudioService` - Audio context, oscillators, and analysers
|
|
42
47
|
|
|
43
48
|
### Network APIs
|
|
44
49
|
|
|
@@ -58,6 +63,22 @@ Angular services package for a structured and secure access layer over browser W
|
|
|
58
63
|
|
|
59
64
|
- `WebWorkerService` - Web Worker management
|
|
60
65
|
|
|
66
|
+
### Device APIs
|
|
67
|
+
|
|
68
|
+
- `WebBluetoothService` - Bluetooth Low Energy device communication
|
|
69
|
+
- `WebUsbService` - USB device I/O from the browser
|
|
70
|
+
- `WebNfcService` - NFC tag reading and writing
|
|
71
|
+
|
|
72
|
+
### Detection APIs
|
|
73
|
+
|
|
74
|
+
- `EyeDropperService` - Screen color picker
|
|
75
|
+
- `BarcodeDetectorService` - QR code and barcode scanning
|
|
76
|
+
|
|
77
|
+
### Commerce & Identity APIs
|
|
78
|
+
|
|
79
|
+
- `PaymentRequestService` - Native payment flows
|
|
80
|
+
- `CredentialManagementService` - Passwords, passkeys (WebAuthn)
|
|
81
|
+
|
|
61
82
|
### Security & Capabilities
|
|
62
83
|
|
|
63
84
|
- `PermissionsService` - Centralized browser permissions handling
|
|
@@ -519,6 +540,175 @@ export class WorkerComponent {
|
|
|
519
540
|
}
|
|
520
541
|
```
|
|
521
542
|
|
|
543
|
+
## Signal Fn Primitives
|
|
544
|
+
|
|
545
|
+
Zero-boilerplate reactive alternatives to the RxJS-based services. Each `inject*` function returns a ref object with read-only signals and handles cleanup automatically via `DestroyRef`.
|
|
546
|
+
|
|
547
|
+
### injectPageVisibility
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
import { injectPageVisibility } from '@angular-helpers/browser-web-apis';
|
|
551
|
+
|
|
552
|
+
@Component({...})
|
|
553
|
+
export class MyComponent {
|
|
554
|
+
readonly visibility = injectPageVisibility();
|
|
555
|
+
|
|
556
|
+
// visibility.state() → 'visible' | 'hidden'
|
|
557
|
+
// visibility.isVisible() → boolean
|
|
558
|
+
// visibility.isHidden() → boolean
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### injectResizeObserver
|
|
563
|
+
|
|
564
|
+
Accepts `Element`, `ElementRef`, or a **`Signal<ElementRef | undefined>`** (e.g. from `viewChild`). When a signal is passed, the observer automatically starts when the element becomes available.
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
import { injectResizeObserver } from '@angular-helpers/browser-web-apis';
|
|
568
|
+
|
|
569
|
+
@Component({...})
|
|
570
|
+
export class MyComponent {
|
|
571
|
+
readonly boxRef = viewChild<ElementRef>('box');
|
|
572
|
+
readonly resize = injectResizeObserver(this.boxRef);
|
|
573
|
+
|
|
574
|
+
// resize.width() → number
|
|
575
|
+
// resize.height() → number
|
|
576
|
+
// resize.inlineSize() → number (logical)
|
|
577
|
+
// resize.blockSize() → number (logical)
|
|
578
|
+
// resize.size() → ElementSize | null
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### injectIntersectionObserver
|
|
583
|
+
|
|
584
|
+
Same `ElementInput` flexibility — works with `viewChild` signals out of the box.
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
import { injectIntersectionObserver } from '@angular-helpers/browser-web-apis';
|
|
588
|
+
|
|
589
|
+
@Component({...})
|
|
590
|
+
export class MyComponent {
|
|
591
|
+
readonly targetRef = viewChild<ElementRef>('target');
|
|
592
|
+
readonly inView = injectIntersectionObserver(this.targetRef, { threshold: 0.25 });
|
|
593
|
+
|
|
594
|
+
// inView.isIntersecting() → boolean
|
|
595
|
+
// inView.isVisible() → boolean
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### injectNetworkInformation
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
import { injectNetworkInformation } from '@angular-helpers/browser-web-apis';
|
|
603
|
+
|
|
604
|
+
@Component({...})
|
|
605
|
+
export class MyComponent {
|
|
606
|
+
readonly net = injectNetworkInformation();
|
|
607
|
+
|
|
608
|
+
// net.online() → boolean
|
|
609
|
+
// net.effectiveType() → '4g' | '3g' | '2g' | 'slow-2g' | undefined
|
|
610
|
+
// net.downlink() → number | undefined (Mbps)
|
|
611
|
+
// net.rtt() → number | undefined (ms)
|
|
612
|
+
// net.type() → ConnectionType | undefined
|
|
613
|
+
// net.saveData() → boolean | undefined
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### injectScreenOrientation
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
import { injectScreenOrientation } from '@angular-helpers/browser-web-apis';
|
|
621
|
+
|
|
622
|
+
@Component({...})
|
|
623
|
+
export class MyComponent {
|
|
624
|
+
readonly orientation = injectScreenOrientation();
|
|
625
|
+
|
|
626
|
+
// orientation.type() → OrientationType
|
|
627
|
+
// orientation.angle() → number
|
|
628
|
+
// orientation.isPortrait() → boolean
|
|
629
|
+
// orientation.isLandscape() → boolean
|
|
630
|
+
// orientation.lock('landscape') → Promise<void>
|
|
631
|
+
// orientation.unlock()
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### injectMutationObserver
|
|
636
|
+
|
|
637
|
+
Accepts the same `ElementInput` type — works with `viewChild` signals.
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
import { injectMutationObserver } from '@angular-helpers/browser-web-apis';
|
|
641
|
+
|
|
642
|
+
@Component({...})
|
|
643
|
+
export class MyComponent {
|
|
644
|
+
readonly targetRef = viewChild<ElementRef>('target');
|
|
645
|
+
readonly mo = injectMutationObserver(this.targetRef, { childList: true });
|
|
646
|
+
|
|
647
|
+
// mo.mutations() → MutationRecord[]
|
|
648
|
+
// mo.mutationCount() → number
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### injectPerformanceObserver
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
import { injectPerformanceObserver } from '@angular-helpers/browser-web-apis';
|
|
656
|
+
|
|
657
|
+
@Component({...})
|
|
658
|
+
export class MyComponent {
|
|
659
|
+
readonly perf = injectPerformanceObserver({ type: 'navigation', buffered: true });
|
|
660
|
+
|
|
661
|
+
// perf.entries() → PerformanceEntryList
|
|
662
|
+
// perf.entryCount() → number
|
|
663
|
+
// perf.latestEntry() → PerformanceEntry | undefined
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### injectIdleDetector
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
import { injectIdleDetector } from '@angular-helpers/browser-web-apis';
|
|
671
|
+
|
|
672
|
+
@Component({...})
|
|
673
|
+
export class MyComponent {
|
|
674
|
+
readonly idle = injectIdleDetector({ threshold: 120_000 });
|
|
675
|
+
|
|
676
|
+
// idle.userState() → 'active' | 'idle'
|
|
677
|
+
// idle.screenState() → 'locked' | 'unlocked'
|
|
678
|
+
// idle.isUserIdle() → boolean
|
|
679
|
+
// idle.isScreenLocked() → boolean
|
|
680
|
+
}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
### injectGamepad
|
|
684
|
+
|
|
685
|
+
```typescript
|
|
686
|
+
import { injectGamepad } from '@angular-helpers/browser-web-apis';
|
|
687
|
+
|
|
688
|
+
@Component({...})
|
|
689
|
+
export class MyComponent {
|
|
690
|
+
readonly gp = injectGamepad(0);
|
|
691
|
+
|
|
692
|
+
// gp.connected() → boolean
|
|
693
|
+
// gp.buttons() → ReadonlyArray<{ pressed: boolean; value: number }>
|
|
694
|
+
// gp.axes() → readonly number[]
|
|
695
|
+
// gp.state() → GamepadState | null
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### ElementInput type
|
|
700
|
+
|
|
701
|
+
Both `injectResizeObserver` and `injectIntersectionObserver` accept the `ElementInput` type:
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
type ElementInput =
|
|
705
|
+
| Element
|
|
706
|
+
| ElementRef<Element>
|
|
707
|
+
| Signal<Element | ElementRef<Element> | undefined>;
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
This means you can pass a `viewChild` signal directly — the function will internally use an `effect` to start observing once the element is rendered, with automatic cleanup.
|
|
711
|
+
|
|
522
712
|
## Browser Support
|
|
523
713
|
|
|
524
714
|
The services automatically validate browser support and unsupported-path handling:
|