@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 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: