@angular-helpers/browser-web-apis 21.0.2 → 21.2.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 ADDED
@@ -0,0 +1,572 @@
1
+ # @angular-helpers/browser-web-apis
2
+
3
+ Paquete de servicios Angular para acceder de forma estructurada y segura a Browser Web APIs.
4
+
5
+ 🌐 **Documentación y Demo**: https://gaspar1992.github.io/angular-helpers/
6
+
7
+ [Read in English](./README.md)
8
+
9
+ ## Caracteristicas
10
+
11
+ - Seguridad integrada con prevencion de ReDoS usando Web Workers
12
+ - Acceso unificado a APIs del navegador mediante servicios tipados
13
+ - Arquitectura tree-shakable
14
+ - Configuracion modular para habilitar solo lo necesario
15
+ - APIs reactivas con signals y observables
16
+ - Integracion segura con el ciclo de vida usando `destroyRef`
17
+
18
+ ## Servicios disponibles
19
+
20
+ ### APIs de medios y dispositivo
21
+
22
+ - `CameraService` - Acceso a camara con gestion de permisos
23
+ - `MediaDevicesService` - Enumeracion y gestion de dispositivos multimedia
24
+ - `GeolocationService` - Acceso a la API de geolocalizacion
25
+ - `NotificationService` - API de notificaciones del navegador
26
+ - `MediaRecorderService` - Grabar audio/video desde MediaStream
27
+
28
+ ### APIs de observadores
29
+
30
+ - `IntersectionObserverService` - Detectar cuando elementos entran/salen del viewport
31
+ - `ResizeObserverService` - Observar cambios de tamano de elementos
32
+
33
+ ### APIs de sistema
34
+
35
+ - `BatteryService` - Monitorear estado de bateria y carga
36
+ - `PageVisibilityService` - Rastrear cambios de visibilidad del documento
37
+ - `ScreenWakeLockService` - Evitar que la pantalla se atenue o bloquee
38
+ - `ScreenOrientationService` - Leer y bloquear orientacion de pantalla
39
+ - `FullscreenService` - Alternar modo pantalla completa para elementos
40
+ - `VibrationService` - Activar patrones de retroalimentacion tactil
41
+ - `SpeechSynthesisService` - Texto a voz con seleccion de voz
42
+
43
+ ### APIs de red
44
+
45
+ - `WebSocketService` - Gestion de conexiones WebSocket
46
+ - `ServerSentEventsService` - Cliente de Server-Sent Events
47
+ - `BroadcastChannelService` - Comunicacion entre pestanas
48
+ - `NetworkInformationService` - Informacion de conexion y estado online
49
+
50
+ ### APIs de almacenamiento y E/S
51
+
52
+ - `WebStorageService` - Helpers para LocalStorage y SessionStorage
53
+ - `WebShareService` - Soporte para Web Share API nativa
54
+ - `ClipboardService` - Acceso al portapapeles del sistema
55
+ - `FileSystemAccessService` - Abrir/guardar archivos via selector nativo
56
+
57
+ ### Web APIs
58
+
59
+ - `WebWorkerService` - Gestion de Web Workers
60
+
61
+ ### Seguridad y capacidades
62
+
63
+ - `PermissionsService` - Gestion centralizada de permisos del navegador
64
+ - `BrowserCapabilityService` - Deteccion de soporte de APIs del navegador
65
+
66
+ ### Utilidades
67
+
68
+ - `BrowserApiBaseService` - Clase base compartida para servicios de Browser APIs
69
+
70
+ ## Instalacion
71
+
72
+ ```bash
73
+ npm install @angular-helpers/browser-web-apis
74
+ ```
75
+
76
+ ## Configuracion rapida
77
+
78
+ ```typescript
79
+ import { provideBrowserWebApis } from '@angular-helpers/browser-web-apis';
80
+
81
+ bootstrapApplication(AppComponent, {
82
+ providers: [
83
+ provideBrowserWebApis({
84
+ enableCamera: true,
85
+ enableGeolocation: true,
86
+ enableNotifications: true,
87
+ }),
88
+ ],
89
+ });
90
+ ```
91
+
92
+ ## Uso por servicio
93
+
94
+ ### CameraService
95
+
96
+ ```typescript
97
+ import { CameraService } from '@angular-helpers/browser-web-apis';
98
+
99
+ export class PhotoComponent {
100
+ private cameraService = inject(CameraService);
101
+
102
+ async takePhoto() {
103
+ try {
104
+ const stream = await this.cameraService.startCamera({
105
+ video: true,
106
+ audio: false,
107
+ });
108
+
109
+ // Usa el stream para captura de foto o video
110
+ } catch (error) {
111
+ console.error('Error accessing camera:', error);
112
+ }
113
+ }
114
+
115
+ async stopCamera() {
116
+ await this.cameraService.stopCamera();
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### BrowserCapabilityService
122
+
123
+ ```typescript
124
+ import { BrowserCapabilityService } from '@angular-helpers/browser-web-apis';
125
+
126
+ export class MyComponent {
127
+ private capability = inject(BrowserCapabilityService);
128
+
129
+ ngOnInit() {
130
+ if (this.capability.isSupported('geolocation')) {
131
+ console.log('La geolocalizacion esta disponible');
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ > Para prevención de ReDoS, usa el paquete `@angular-helpers/security`.
138
+
139
+ ### GeolocationService
140
+
141
+ ```typescript
142
+ import { GeolocationService } from '@angular-helpers/browser-web-apis';
143
+
144
+ export class LocationComponent {
145
+ private geolocation = inject(GeolocationService);
146
+
147
+ async getCurrentLocation() {
148
+ try {
149
+ const position = await this.geolocation.getCurrentPosition({
150
+ enableHighAccuracy: true,
151
+ timeout: 10000,
152
+ maximumAge: 60000,
153
+ });
154
+
155
+ console.log('Position:', position.coords);
156
+ } catch (error) {
157
+ console.error('Error getting location:', error);
158
+ }
159
+ }
160
+ }
161
+ ```
162
+
163
+ ### IntersectionObserverService
164
+
165
+ ```typescript
166
+ import { IntersectionObserverService } from '@angular-helpers/browser-web-apis';
167
+
168
+ export class LazyImageComponent {
169
+ private intersectionService = inject(IntersectionObserverService);
170
+ private elementRef = inject(ElementRef);
171
+
172
+ isVisible = signal(false);
173
+
174
+ ngAfterViewInit() {
175
+ this.intersectionService
176
+ .observeVisibility(this.elementRef.nativeElement, { threshold: 0.5 })
177
+ .subscribe((visible) => this.isVisible.set(visible));
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### ResizeObserverService
183
+
184
+ ```typescript
185
+ import { ResizeObserverService } from '@angular-helpers/browser-web-apis';
186
+
187
+ export class ResponsiveComponent {
188
+ private resizeService = inject(ResizeObserverService);
189
+ private elementRef = inject(ElementRef);
190
+
191
+ elementSize = signal<ElementSize | null>(null);
192
+
193
+ ngAfterViewInit() {
194
+ this.resizeService
195
+ .observeSize(this.elementRef.nativeElement)
196
+ .subscribe((size) => this.elementSize.set(size));
197
+ }
198
+ }
199
+ ```
200
+
201
+ ### PageVisibilityService
202
+
203
+ ```typescript
204
+ import { PageVisibilityService } from '@angular-helpers/browser-web-apis';
205
+
206
+ export class AnalyticsComponent {
207
+ private visibilityService = inject(PageVisibilityService);
208
+
209
+ ngOnInit() {
210
+ this.visibilityService.watch().subscribe((state) => {
211
+ console.log('La pagina ahora esta:', state);
212
+ });
213
+ }
214
+ }
215
+ ```
216
+
217
+ ### FullscreenService
218
+
219
+ ```typescript
220
+ import { FullscreenService } from '@angular-helpers/browser-web-apis';
221
+
222
+ export class VideoPlayerComponent {
223
+ private fullscreenService = inject(FullscreenService);
224
+
225
+ async toggleFullscreen() {
226
+ await this.fullscreenService.toggle();
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### ScreenWakeLockService
232
+
233
+ ```typescript
234
+ import { ScreenWakeLockService } from '@angular-helpers/browser-web-apis';
235
+
236
+ export class PresentationComponent {
237
+ private wakeLockService = inject(ScreenWakeLockService);
238
+
239
+ async keepScreenOn() {
240
+ await this.wakeLockService.request();
241
+ }
242
+
243
+ async releaseScreen() {
244
+ await this.wakeLockService.release();
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### BroadcastChannelService
250
+
251
+ ```typescript
252
+ import { BroadcastChannelService } from '@angular-helpers/browser-web-apis';
253
+
254
+ export class SyncComponent {
255
+ private broadcastService = inject(BroadcastChannelService);
256
+
257
+ ngOnInit() {
258
+ // Escuchar mensajes de otras pestanas
259
+ this.broadcastService.open<string>('app-sync').subscribe((msg) => {
260
+ console.log('Recibido:', msg);
261
+ });
262
+ }
263
+
264
+ sendMessage(data: string) {
265
+ this.broadcastService.post('app-sync', data);
266
+ }
267
+ }
268
+ ```
269
+
270
+ ### ServerSentEventsService
271
+
272
+ ```typescript
273
+ import { ServerSentEventsService } from '@angular-helpers/browser-web-apis';
274
+
275
+ export class LiveFeedComponent {
276
+ private sseService = inject(ServerSentEventsService);
277
+
278
+ connectToEvents() {
279
+ this.sseService.connect('https://api.example.com/events').subscribe({
280
+ next: (message) => console.log('Evento:', message),
281
+ error: (err) => console.error('Error SSE:', err),
282
+ });
283
+ }
284
+ }
285
+ ```
286
+
287
+ ### VibrationService
288
+
289
+ ```typescript
290
+ import { VibrationService } from '@angular-helpers/browser-web-apis';
291
+
292
+ export class FeedbackComponent {
293
+ private vibrationService = inject(VibrationService);
294
+
295
+ onSuccess() {
296
+ this.vibrationService.success();
297
+ }
298
+
299
+ onError() {
300
+ this.vibrationService.error();
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### SpeechSynthesisService
306
+
307
+ ```typescript
308
+ import { SpeechSynthesisService } from '@angular-helpers/browser-web-apis';
309
+
310
+ export class VoiceComponent {
311
+ private speechService = inject(SpeechSynthesisService);
312
+
313
+ speakText(text: string) {
314
+ this.speechService.speak(text).subscribe((state) => {
315
+ console.log('Estado de voz:', state);
316
+ });
317
+ }
318
+ }
319
+ ```
320
+
321
+ ### ScreenOrientationService
322
+
323
+ ```typescript
324
+ import { ScreenOrientationService } from '@angular-helpers/browser-web-apis';
325
+
326
+ export class MobileComponent {
327
+ private orientationService = inject(ScreenOrientationService);
328
+
329
+ ngOnInit() {
330
+ // Observar cambios de orientacion
331
+ this.orientationService.watch().subscribe((orientation) => {
332
+ console.log('Orientacion:', orientation.type, 'Angulo:', orientation.angle);
333
+ });
334
+ }
335
+
336
+ async lockPortrait() {
337
+ try {
338
+ await this.orientationService.lock('portrait');
339
+ } catch (error) {
340
+ console.error('No se pudo bloquear la orientacion:', error);
341
+ }
342
+ }
343
+
344
+ unlockOrientation() {
345
+ this.orientationService.unlock();
346
+ }
347
+ }
348
+ ```
349
+
350
+ ### BatteryService
351
+
352
+ ```typescript
353
+ import { BatteryService } from '@angular-helpers/browser-web-apis';
354
+
355
+ export class PowerComponent {
356
+ private batteryService = inject(BatteryService);
357
+
358
+ async ngOnInit() {
359
+ try {
360
+ // Inicializar y obtener informacion inicial de la bateria
361
+ const batteryInfo = await this.batteryService.initialize();
362
+ console.log('Nivel de bateria:', batteryInfo.level);
363
+ console.log('Esta cargando:', batteryInfo.charging);
364
+
365
+ // Observar cambios de bateria
366
+ this.batteryService.watchBatteryInfo().subscribe((info) => {
367
+ console.log('Bateria actualizada:', info);
368
+ });
369
+ } catch (error) {
370
+ console.error('Battery API no soportada:', error);
371
+ }
372
+ }
373
+ }
374
+ ```
375
+
376
+ ### ClipboardService
377
+
378
+ ```typescript
379
+ import { ClipboardService } from '@angular-helpers/browser-web-apis';
380
+
381
+ export class CopyComponent {
382
+ private clipboardService = inject(ClipboardService);
383
+
384
+ async copyToClipboard(text: string) {
385
+ try {
386
+ await this.clipboardService.writeText(text);
387
+ console.log('Copiado exitosamente');
388
+ } catch (error) {
389
+ console.error('Error al copiar:', error);
390
+ }
391
+ }
392
+
393
+ async pasteFromClipboard(): Promise<string> {
394
+ try {
395
+ const text = await this.clipboardService.readText();
396
+ return text;
397
+ } catch (error) {
398
+ console.error('Error al leer el portapapeles:', error);
399
+ return '';
400
+ }
401
+ }
402
+ }
403
+ ```
404
+
405
+ ### FileSystemAccessService
406
+
407
+ ```typescript
408
+ import { FileSystemAccessService } from '@angular-helpers/browser-web-apis';
409
+
410
+ export class FileManagerComponent {
411
+ private fileService = inject(FileSystemAccessService);
412
+
413
+ async openFiles() {
414
+ try {
415
+ const files = await this.fileService.openFile({
416
+ multiple: true,
417
+ types: [
418
+ {
419
+ description: 'Archivos de texto',
420
+ accept: { 'text/plain': ['.txt'] },
421
+ },
422
+ ],
423
+ });
424
+ console.log('Archivos seleccionados:', files);
425
+ } catch (error) {
426
+ console.error('Error al abrir archivos:', error);
427
+ }
428
+ }
429
+
430
+ async saveContent(content: string) {
431
+ try {
432
+ await this.fileService.saveFile(content, {
433
+ suggestedName: 'documento.txt',
434
+ });
435
+ } catch (error) {
436
+ console.error('Error al guardar archivo:', error);
437
+ }
438
+ }
439
+ }
440
+ ```
441
+
442
+ ### MediaRecorderService
443
+
444
+ ```typescript
445
+ import { MediaRecorderService } from '@angular-helpers/browser-web-apis';
446
+
447
+ export class RecorderComponent {
448
+ private recorderService = inject(MediaRecorderService);
449
+ private stream: MediaStream | null = null;
450
+
451
+ async startRecording() {
452
+ try {
453
+ this.stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
454
+ await this.recorderService.start(this.stream, { mimeType: 'video/webm' });
455
+ } catch (error) {
456
+ console.error('Error al iniciar la grabacion:', error);
457
+ }
458
+ }
459
+
460
+ stopRecording() {
461
+ const result = this.recorderService.stop();
462
+ if (result) {
463
+ console.log('Grabacion guardada, URL del blob:', result.url);
464
+ }
465
+ }
466
+ }
467
+ ```
468
+
469
+ ### WebSocketService
470
+
471
+ ```typescript
472
+ import { WebSocketService } from '@angular-helpers/browser-web-apis';
473
+
474
+ export class LiveComponent {
475
+ private wsService = inject(WebSocketService);
476
+
477
+ connect() {
478
+ this.wsService
479
+ .connect({
480
+ url: 'wss://example.com/socket',
481
+ reconnectInterval: 3000,
482
+ maxReconnectAttempts: 5,
483
+ })
484
+ .subscribe((status) => {
485
+ console.log('Estado de conexion:', status);
486
+ });
487
+
488
+ this.wsService.getMessages().subscribe((message) => {
489
+ console.log('Recibido:', message);
490
+ });
491
+ }
492
+
493
+ sendMessage(data: unknown) {
494
+ this.wsService.send({ type: 'message', data });
495
+ }
496
+ }
497
+ ```
498
+
499
+ ### WebStorageService
500
+
501
+ ```typescript
502
+ import { WebStorageService } from '@angular-helpers/browser-web-apis';
503
+
504
+ export class SettingsComponent {
505
+ private storageService = inject(WebStorageService);
506
+
507
+ saveSetting(key: string, value: unknown) {
508
+ this.storageService.setLocalStorage(key, value);
509
+ }
510
+
511
+ getSetting<T>(key: string): T | null {
512
+ return this.storageService.getLocalStorage<T>(key);
513
+ }
514
+
515
+ watchSetting<T>(key: string) {
516
+ return this.storageService.watchLocalStorage<T>(key).subscribe((value) => {
517
+ console.log('Configuracion cambiada:', value);
518
+ });
519
+ }
520
+ }
521
+ ```
522
+
523
+ ### WebWorkerService
524
+
525
+ ```typescript
526
+ import { WebWorkerService } from '@angular-helpers/browser-web-apis';
527
+
528
+ export class WorkerComponent {
529
+ private workerService = inject(WebWorkerService);
530
+
531
+ async createWorker() {
532
+ this.workerService
533
+ .createWorker('calc-worker', '/assets/workers/calc.worker.js')
534
+ .subscribe((status) => {
535
+ console.log('Estado del worker:', status);
536
+ });
537
+
538
+ this.workerService.getMessages('calc-worker').subscribe((message) => {
539
+ console.log('Respuesta del worker:', message);
540
+ });
541
+ }
542
+
543
+ sendTask(data: unknown) {
544
+ this.workerService.postMessage('calc-worker', {
545
+ id: 'task-1',
546
+ type: 'CALCULATE',
547
+ data,
548
+ });
549
+ }
550
+ }
551
+ ```
552
+
553
+ ## Soporte de navegadores
554
+
555
+ Los servicios validan automaticamente el soporte del navegador y el manejo de rutas no soportadas:
556
+
557
+ - Chrome: soporte completo
558
+ - Firefox: soporte completo
559
+ - Safari: soporte parcial
560
+ - Edge: soporte completo
561
+ - Navegadores moviles: depende de plataforma y API
562
+
563
+ ## Notas
564
+
565
+ - Varias APIs requieren contexto seguro (HTTPS)
566
+ - Algunas APIs requieren interaccion explicita del usuario
567
+ - El comportamiento de permisos varia segun el navegador
568
+ - Implementa siempre manejo de errores y fallback
569
+
570
+ ## Licencia
571
+
572
+ MIT