ez-vid-ang 0.0.6 → 0.0.7
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 +40 -8
- package/fesm2022/ez-vid-ang.mjs +324 -46
- package/fesm2022/ez-vid-ang.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ez-vid-ang.d.ts +192 -13
package/README.md
CHANGED
|
@@ -57,29 +57,61 @@ Add the required styles to your angular.json:
|
|
|
57
57
|
> *eva-icons-and-fonts.scss* is optional if you provide custom icons and fonts for all components. It includes a prepared *.woff* file and utility classes for default icon usage.
|
|
58
58
|
<br/>
|
|
59
59
|
|
|
60
|
-
Import the needed
|
|
60
|
+
Import the needed components and types into your standalone component or NgModule:
|
|
61
61
|
```
|
|
62
62
|
import { Component } from '@angular/core';
|
|
63
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
EvaActiveChapter,
|
|
65
|
+
EvaBackward,
|
|
66
|
+
EvaBuffering,
|
|
67
|
+
EvaChapterMarker,
|
|
68
|
+
EvaOverlayPlay,
|
|
69
|
+
EvaControlsContainer, EvaControlsDivider,
|
|
70
|
+
EvaForward, EvaFullscreen, EvaHlsDirective,
|
|
71
|
+
EvaMute, EvaMuteAria, EvaPlaybackSpeed, EvaPlayer,
|
|
72
|
+
EvaPlayPause, EvaQualitySelector, EvaScrubBar,
|
|
73
|
+
EvaScrubBarBufferingTime, EvaScrubBarCurrentTime,
|
|
74
|
+
EvaSubtitleDisplay,EvaPictureInPicture,
|
|
75
|
+
EvaTimeDisplay, EvaTrack, EvaTrackSelector,
|
|
76
|
+
EvaVideoElementConfiguration, EvaVideoSource, EvaVolume
|
|
77
|
+
} from "ez-vid-ang";
|
|
64
78
|
|
|
65
79
|
@Component({
|
|
66
80
|
selector: 'lt-home-page',
|
|
67
81
|
templateUrl: './home-page.html',
|
|
68
82
|
styleUrl: './home-page.scss',
|
|
69
83
|
imports: [
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
EvaActiveChapter,
|
|
85
|
+
EvaBackward,
|
|
86
|
+
EvaBuffering,
|
|
87
|
+
EvaOverlayPlay,
|
|
88
|
+
EvaControlsContainer,
|
|
89
|
+
EvaControlsDivider,
|
|
90
|
+
EvaForward,
|
|
91
|
+
EvaFullscreen,
|
|
92
|
+
EvaHlsDirective,
|
|
93
|
+
EvaMute,
|
|
94
|
+
EvaPlaybackSpeed,
|
|
95
|
+
EvaPlayer,
|
|
96
|
+
EvaPlayPause,
|
|
97
|
+
EvaPictureInPicture,
|
|
98
|
+
EvaQualitySelector,
|
|
99
|
+
EvaScrubBar,
|
|
100
|
+
EvaScrubBarBufferingTime,
|
|
101
|
+
EvaScrubBarCurrentTime,
|
|
102
|
+
EvaSubtitleDisplay,
|
|
103
|
+
EvaTimeDisplay,
|
|
104
|
+
EvaTrackSelector,
|
|
105
|
+
EvaVolume
|
|
74
106
|
]
|
|
75
107
|
})
|
|
76
108
|
export class HomePage {}
|
|
77
109
|
|
|
78
110
|
```
|
|
79
111
|
|
|
80
|
-
##
|
|
112
|
+
## Components
|
|
81
113
|
|
|
82
|
-
Library has four groups of
|
|
114
|
+
Library has four groups of components. You can click on the name to go to the documentation:
|
|
83
115
|
- [**EvaCore**](documentation/core) – Main player component, directives, and providers
|
|
84
116
|
- [**EvaControls**](documentation/controls) – Video control components and pipes
|
|
85
117
|
- [**EvaBuffering**](documentation/buffering) – Loading and buffering indicators
|
package/fesm2022/ez-vid-ang.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { EventEmitter, signal, Injectable, inject, input, ChangeDetectionStrategy, Component, output, computed, Pipe, ElementRef, NgZone, HostListener, Renderer2, viewChild, effect, Directive, viewChildren } from '@angular/core';
|
|
2
|
+
import { EventEmitter, signal, Injectable, inject, input, ChangeDetectionStrategy, Component, output, computed, Pipe, ElementRef, NgZone, HostListener, Renderer2, viewChild, effect, Directive, SecurityContext, viewChildren } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject, Subject, fromEvent, throttleTime, merge, takeUntil } from 'rxjs';
|
|
4
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Enum of all possible playback states the Eva player can be in.
|
|
@@ -28,6 +29,8 @@ var EvaVideoEvent;
|
|
|
28
29
|
EvaVideoEvent["CAN_PLAY_THROUGH"] = "canplaythrough";
|
|
29
30
|
EvaVideoEvent["COMPLETE"] = "complete";
|
|
30
31
|
EvaVideoEvent["DURATION_CHANGE"] = "durationchange";
|
|
32
|
+
EvaVideoEvent["ENTERED_PICTURE_IN_PICTURE"] = "enterpictureinpicture";
|
|
33
|
+
EvaVideoEvent["LEFT_PICTURE_IN_PICTURE"] = "leavepictureinpicture";
|
|
31
34
|
EvaVideoEvent["EMPTIED"] = "emptied";
|
|
32
35
|
EvaVideoEvent["ENCRYPTED"] = "encrypted";
|
|
33
36
|
EvaVideoEvent["ENDED"] = "ended";
|
|
@@ -195,6 +198,14 @@ class EvaApi {
|
|
|
195
198
|
*/
|
|
196
199
|
triggerUserInteraction = new Subject();
|
|
197
200
|
currentSubtitleCue = signal(null, ...(ngDevMode ? [{ debugName: "currentSubtitleCue" }] : []));
|
|
201
|
+
/** The active `PictureInPictureWindow` instance. `null` when PiP is not active. */
|
|
202
|
+
pipWindow = null;
|
|
203
|
+
/**
|
|
204
|
+
* Broadcasts the current Picture-in-Picture state.
|
|
205
|
+
* Emits `true` when the player enters PiP, `false` when it leaves.
|
|
206
|
+
* Subscribed to by `EvaPictureInPicture` to keep its icon state in sync.
|
|
207
|
+
*/
|
|
208
|
+
pictureInPictureSubject = new BehaviorSubject(false);
|
|
198
209
|
// ─── Buffering Detection ──────────────────────────────────────────────────
|
|
199
210
|
/** Timeout reference used by the position-polling buffering detection. Cleared on each `timeupdate`. */
|
|
200
211
|
bufferingTimeout;
|
|
@@ -685,6 +696,64 @@ class EvaApi {
|
|
|
685
696
|
this.isBuffering.set(true);
|
|
686
697
|
}
|
|
687
698
|
}
|
|
699
|
+
// ─── Picture in picture ────────────────────────────────────────────────────────────
|
|
700
|
+
/**
|
|
701
|
+
* Toggles Picture-in-Picture mode for the assigned video element.
|
|
702
|
+
*
|
|
703
|
+
* - If this player's video element is currently in PiP, exits PiP via
|
|
704
|
+
* `document.exitPictureInPicture()`.
|
|
705
|
+
* - If another element is currently in PiP, exits that first, then enters PiP
|
|
706
|
+
* on this player's video element.
|
|
707
|
+
* - If PiP is not active, enters PiP via `requestPictureInPicture()`.
|
|
708
|
+
*
|
|
709
|
+
* No-ops if:
|
|
710
|
+
* - The player is not yet ready.
|
|
711
|
+
* - `document.pictureInPictureEnabled` is `false` (API not supported or blocked).
|
|
712
|
+
* - `assignedVideoElement.disablePictureInPicture` is `true`.
|
|
713
|
+
*
|
|
714
|
+
* State is tracked via native `enterpictureinpicture` / `leavepictureinpicture`
|
|
715
|
+
* events, not by the Promise resolution, to correctly handle external PiP changes.
|
|
716
|
+
*
|
|
717
|
+
* @returns A `Promise<void>` that resolves when the PiP state change completes.
|
|
718
|
+
*/
|
|
719
|
+
async changePictureInPictureStatus() {
|
|
720
|
+
if (!this.validateVideoAndPlayerBeforeAction()) {
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (!document.pictureInPictureEnabled) {
|
|
724
|
+
console.warn('[EvaApi] Picture-in-Picture is not supported or is disabled in this browser.');
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (this.assignedVideoElement.disablePictureInPicture) {
|
|
728
|
+
console.warn('[EvaApi] Picture-in-Picture is disabled on this video element.');
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
if (document.pictureInPictureElement === this.assignedVideoElement) {
|
|
733
|
+
// This player is already in PiP — exit
|
|
734
|
+
await document.exitPictureInPicture();
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
// Another element may be in PiP — the browser handles exiting it automatically
|
|
738
|
+
// before entering PiP on a new element, but we exit explicitly for safety
|
|
739
|
+
if (document.pictureInPictureElement) {
|
|
740
|
+
await document.exitPictureInPicture();
|
|
741
|
+
}
|
|
742
|
+
await this.assignedVideoElement.requestPictureInPicture();
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
console.error('[EvaApi] Picture-in-Picture toggle failed:', error);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
assignPictureInPictureWindow(p) {
|
|
750
|
+
this.pipWindow = p.pictureInPictureWindow;
|
|
751
|
+
this.pictureInPictureSubject.next(true);
|
|
752
|
+
}
|
|
753
|
+
removePictureInPictureWindow(_p) {
|
|
754
|
+
this.pipWindow = null;
|
|
755
|
+
this.pictureInPictureSubject.next(false);
|
|
756
|
+
}
|
|
688
757
|
// ─── Utilities ────────────────────────────────────────────────────────────
|
|
689
758
|
/**
|
|
690
759
|
* Returns whether the current source is a live stream.
|
|
@@ -784,9 +853,13 @@ class EvaApi {
|
|
|
784
853
|
if (this.trackTimeout) {
|
|
785
854
|
clearTimeout(this.trackTimeout);
|
|
786
855
|
}
|
|
856
|
+
if (this.pipWindow) {
|
|
857
|
+
this.pipWindow = null;
|
|
858
|
+
}
|
|
787
859
|
// Clear the registered streaming quality function
|
|
788
860
|
this.qualityFn = null;
|
|
789
861
|
// Complete all subjects — notifies subscribers and prevents further emissions
|
|
862
|
+
this.pictureInPictureSubject.complete();
|
|
790
863
|
this.videoStateSubject.complete();
|
|
791
864
|
this.videoVolumeSubject.complete();
|
|
792
865
|
this.playbackRateSubject.complete();
|
|
@@ -961,6 +1034,24 @@ function transformEvaPlayPauseAria(v) {
|
|
|
961
1034
|
}
|
|
962
1035
|
};
|
|
963
1036
|
}
|
|
1037
|
+
function transformEvaPictureInPictureAria(v) {
|
|
1038
|
+
if (!v) {
|
|
1039
|
+
return {
|
|
1040
|
+
ariaLabel: "Picture in picture",
|
|
1041
|
+
ariaValueText: {
|
|
1042
|
+
ariaLabelActivated: "Picture in picture is active",
|
|
1043
|
+
ariaLabelDeactivated: "Picture in picture is invactive",
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
return {
|
|
1048
|
+
ariaLabel: v.ariaLabel ? v.ariaLabel : "Picture in picture",
|
|
1049
|
+
ariaValueText: {
|
|
1050
|
+
ariaLabelActivated: v.ariaValueText && v.ariaValueText.ariaLabelActivated ? v.ariaValueText.ariaLabelActivated : "Picture in picture is active",
|
|
1051
|
+
ariaLabelDeactivated: v.ariaValueText && v.ariaValueText.ariaLabelDeactivated ? v.ariaValueText.ariaLabelDeactivated : "Picture in picture is invactive",
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
964
1055
|
function validateAndTransformEvaForwardAndBackwardSeconds(v) {
|
|
965
1056
|
if (!v) {
|
|
966
1057
|
return 10;
|
|
@@ -2398,6 +2489,135 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
2398
2489
|
}, template: "<ng-content></ng-content>", styles: [":host{display:flex;align-items:center;justify-content:center;width:100%;height:calc(100% - var(--eva-control-element-height));cursor:pointer;color:var(--eva-icon-color);user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;position:absolute;top:0;left:0;transition:visibility var(--eva-transition-duration) linear,background-color var(--eva-transition-duration) linear,opacity var(--eva-transition-duration) linear;background-color:#0000;z-index:301;visibility:hidden;opacity:0}:host(.eva-display-overlay-play){background-color:var(--eva-overlay-play-background-color)!important;opacity:1!important;visibility:visible!important}\n"] }]
|
|
2399
2490
|
}], propDecorators: { evaOvelayPlayAria: [{ type: i0.Input, args: [{ isSignal: true, alias: "evaOvelayPlayAria", required: false }] }], evaCustomIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "evaCustomIcon", required: false }] }] } });
|
|
2400
2491
|
|
|
2492
|
+
/**
|
|
2493
|
+
* Picture-in-Picture toggle button for the Eva video player.
|
|
2494
|
+
*
|
|
2495
|
+
* Subscribes to `EvaApi.pictureInPictureSubject` to track whether the player is
|
|
2496
|
+
* currently in PiP mode and updates its icon and ARIA attributes accordingly.
|
|
2497
|
+
* Delegates the actual PiP toggle to `EvaApi.changePictureInPictureStatus()`, which
|
|
2498
|
+
* handles browser support checks, the `disablePictureInPicture` guard, and correctly
|
|
2499
|
+
* exiting another element's PiP session before entering a new one.
|
|
2500
|
+
*
|
|
2501
|
+
* State is kept in sync with native browser events (`enterpictureinpicture` /
|
|
2502
|
+
* `leavepictureinpicture`) registered by `EvaApi`, so the button correctly reflects
|
|
2503
|
+
* PiP changes triggered externally (e.g. by the browser's native controls or another
|
|
2504
|
+
* player instance).
|
|
2505
|
+
*
|
|
2506
|
+
* Keyboard support:
|
|
2507
|
+
* - `Enter` (13) and `Space` (32) trigger the same action as a click.
|
|
2508
|
+
*
|
|
2509
|
+
* @example
|
|
2510
|
+
* // Minimal usage
|
|
2511
|
+
* <eva-picture-in-picture />
|
|
2512
|
+
*
|
|
2513
|
+
* @example
|
|
2514
|
+
* // With custom ARIA labels
|
|
2515
|
+
* <eva-picture-in-picture
|
|
2516
|
+
* [evaAria]="{
|
|
2517
|
+
* ariaLabel: 'Picture in picture',
|
|
2518
|
+
* ariaValueText: {
|
|
2519
|
+
* ariaLabelActivated: 'Exit picture-in-picture',
|
|
2520
|
+
* ariaLabelDeactivated: 'Enter picture-in-picture'
|
|
2521
|
+
* }
|
|
2522
|
+
* }"
|
|
2523
|
+
* />
|
|
2524
|
+
*
|
|
2525
|
+
* @example
|
|
2526
|
+
* // With a custom icon
|
|
2527
|
+
* <eva-picture-in-picture [evaCustomIcon]="true">
|
|
2528
|
+
* <my-pip-icon />
|
|
2529
|
+
* </eva-picture-in-picture>
|
|
2530
|
+
*/
|
|
2531
|
+
class EvaPictureInPicture {
|
|
2532
|
+
evaApi = inject(EvaApi);
|
|
2533
|
+
/**
|
|
2534
|
+
* When `true`, suppresses all built-in icon classes so you can project a
|
|
2535
|
+
* custom icon via content projection.
|
|
2536
|
+
*
|
|
2537
|
+
* @default false
|
|
2538
|
+
*/
|
|
2539
|
+
evaCustomIcon = input(false, ...(ngDevMode ? [{ debugName: "evaCustomIcon" }] : []));
|
|
2540
|
+
/**
|
|
2541
|
+
* ARIA configuration for the PiP button.
|
|
2542
|
+
*
|
|
2543
|
+
* All properties are optional — defaults are applied via `transformEvaPictureInPictureAria`.
|
|
2544
|
+
* - `ariaLabel` — static label for the button element.
|
|
2545
|
+
* - `ariaValueText.ariaLabelActivated` — `aria-valuetext` when PiP is active.
|
|
2546
|
+
* - `ariaValueText.ariaLabelDeactivated` — `aria-valuetext` when PiP is inactive.
|
|
2547
|
+
*/
|
|
2548
|
+
evaAria = input(transformEvaPictureInPictureAria(undefined), { ...(ngDevMode ? { debugName: "evaAria" } : {}), transform: transformEvaPictureInPictureAria });
|
|
2549
|
+
/**
|
|
2550
|
+
* Whether this player's video element is currently in Picture-in-Picture mode.
|
|
2551
|
+
* Updated by subscribing to `EvaApi.pictureInPictureSubject`.
|
|
2552
|
+
*/
|
|
2553
|
+
isPictureInPictureActive = signal(false, ...(ngDevMode ? [{ debugName: "isPictureInPictureActive" }] : []));
|
|
2554
|
+
/**
|
|
2555
|
+
* Static `aria-label` for the host button element.
|
|
2556
|
+
* Sourced from `evaAria().ariaLabel` — does not change with PiP state.
|
|
2557
|
+
*/
|
|
2558
|
+
ariaLabel = computed(() => {
|
|
2559
|
+
return this.evaAria().ariaLabel;
|
|
2560
|
+
}, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
2561
|
+
/**
|
|
2562
|
+
* Dynamic `aria-valuetext` for the host element.
|
|
2563
|
+
* Switches between `ariaValueText.ariaLabelActivated` and
|
|
2564
|
+
* `ariaValueText.ariaLabelDeactivated` based on the current PiP state,
|
|
2565
|
+
* giving screen readers a meaningful description of the current button action.
|
|
2566
|
+
*/
|
|
2567
|
+
ariaValueText = computed(() => {
|
|
2568
|
+
return this.isPictureInPictureActive()
|
|
2569
|
+
? this.evaAria().ariaValueText.ariaLabelActivated
|
|
2570
|
+
: this.evaAria().ariaValueText.ariaLabelDeactivated;
|
|
2571
|
+
}, ...(ngDevMode ? [{ debugName: "ariaValueText" }] : []));
|
|
2572
|
+
/** Subscription to `EvaApi.pictureInPictureSubject`. Cleaned up in `ngOnDestroy`. */
|
|
2573
|
+
pip$ = null;
|
|
2574
|
+
/**
|
|
2575
|
+
* Subscribes to `EvaApi.pictureInPictureSubject` to keep `isPictureInPictureActive`
|
|
2576
|
+
* in sync with the native PiP state, including changes triggered externally by the browser.
|
|
2577
|
+
*/
|
|
2578
|
+
ngOnInit() {
|
|
2579
|
+
this.pip$ = this.evaApi.pictureInPictureSubject.subscribe((isActive) => {
|
|
2580
|
+
this.isPictureInPictureActive.set(isActive);
|
|
2581
|
+
});
|
|
2582
|
+
}
|
|
2583
|
+
/** Unsubscribes from `EvaApi.pictureInPictureSubject` to prevent memory leaks. */
|
|
2584
|
+
ngOnDestroy() {
|
|
2585
|
+
this.pip$?.unsubscribe();
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Delegates the PiP toggle to `EvaApi.changePictureInPictureStatus()`.
|
|
2589
|
+
* Called on host click and from `pipClickedKeyboard`.
|
|
2590
|
+
*/
|
|
2591
|
+
pipClicked() {
|
|
2592
|
+
this.evaApi.changePictureInPictureStatus();
|
|
2593
|
+
}
|
|
2594
|
+
/**
|
|
2595
|
+
* Handles keyboard events on the host element.
|
|
2596
|
+
* Triggers `pipClicked()` on `Enter` (13) or `Space` (32) keypress.
|
|
2597
|
+
*
|
|
2598
|
+
* @param k - The native `KeyboardEvent` from the host element.
|
|
2599
|
+
*/
|
|
2600
|
+
pipClickedKeyboard(k) {
|
|
2601
|
+
if (k.keyCode === 13 || k.keyCode === 32) {
|
|
2602
|
+
k.preventDefault();
|
|
2603
|
+
this.pipClicked();
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EvaPictureInPicture, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2607
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: EvaPictureInPicture, isStandalone: true, selector: "eva-picture-in-picture", inputs: { evaCustomIcon: { classPropertyName: "evaCustomIcon", publicName: "evaCustomIcon", isSignal: true, isRequired: false, transformFunction: null }, evaAria: { classPropertyName: "evaAria", publicName: "evaAria", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "tabindex": "0", "role": "button" }, listeners: { "click": "pipClicked()", "keydown": "pipClickedKeyboard($event)" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-valuetext": "ariaValueText()" } }, ngImport: i0, template: "@if(evaCustomIcon()){\n<ng-content></ng-content>\n}\n@else {\n<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"var(--eva-icon-color)\"\n\tstyle=\"width: 50%; height: 50%\">\n\t<path\n\t\td=\"M19,11H11V17H19V11M23,19V5C23,3.88 22.1,3 21,3H3A2,2 0 0,0 1,5V19A2,2 0 0,0 3,21H21A2,2 0 0,0 23,19M21,19H3V4.97H21V19Z\" />\n</svg>\n}", styles: [":host{display:flex;justify-content:center;align-items:center;height:var(--eva-control-element-height);width:50px;cursor:pointer;color:var(--eva-icon-color);user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}:host>svg{pointer-events:none!important;user-select:none!important;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2608
|
+
}
|
|
2609
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EvaPictureInPicture, decorators: [{
|
|
2610
|
+
type: Component,
|
|
2611
|
+
args: [{ selector: 'eva-picture-in-picture', changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
2612
|
+
"tabindex": "0",
|
|
2613
|
+
"role": "button",
|
|
2614
|
+
"[attr.aria-label]": "ariaLabel()",
|
|
2615
|
+
"[attr.aria-valuetext]": "ariaValueText()",
|
|
2616
|
+
"(click)": "pipClicked()",
|
|
2617
|
+
"(keydown)": "pipClickedKeyboard($event)"
|
|
2618
|
+
}, template: "@if(evaCustomIcon()){\n<ng-content></ng-content>\n}\n@else {\n<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"var(--eva-icon-color)\"\n\tstyle=\"width: 50%; height: 50%\">\n\t<path\n\t\td=\"M19,11H11V17H19V11M23,19V5C23,3.88 22.1,3 21,3H3A2,2 0 0,0 1,5V19A2,2 0 0,0 3,21H21A2,2 0 0,0 23,19M21,19H3V4.97H21V19Z\" />\n</svg>\n}", styles: [":host{display:flex;justify-content:center;align-items:center;height:var(--eva-control-element-height);width:50px;cursor:pointer;color:var(--eva-icon-color);user-select:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}:host>svg{pointer-events:none!important;user-select:none!important;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}\n"] }]
|
|
2619
|
+
}], propDecorators: { evaCustomIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "evaCustomIcon", required: false }] }], evaAria: [{ type: i0.Input, args: [{ isSignal: true, alias: "evaAria", required: false }] }] } });
|
|
2620
|
+
|
|
2401
2621
|
/**
|
|
2402
2622
|
* Pure pipe that formats a time value in seconds into a display string
|
|
2403
2623
|
* for use in Eva video player time displays.
|
|
@@ -3877,18 +4097,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
3877
4097
|
*
|
|
3878
4098
|
* Renders the currently active subtitle cue sourced directly from
|
|
3879
4099
|
* `EvaApi.currentSubtitleCue`. The component is visible only when a cue is active
|
|
3880
|
-
*
|
|
3881
|
-
*
|
|
4100
|
+
* AND the player is not in Picture-in-Picture mode. It automatically adjusts its
|
|
4101
|
+
* bottom position based on whether the controls container is visible, ensuring
|
|
4102
|
+
* subtitles never overlap the controls bar.
|
|
3882
4103
|
*
|
|
3883
4104
|
* Visibility and positioning are driven entirely by host class and style bindings:
|
|
3884
|
-
* - `eva-subtitle-display--visible` — applied when `currentSubtitleCue` is non-null
|
|
4105
|
+
* - `eva-subtitle-display--visible` — applied when `currentSubtitleCue` is non-null
|
|
4106
|
+
* AND `pipWindowActive` is `false`. When PiP is active, this class is suppressed
|
|
4107
|
+
* because `EvaApi.setupPipListeners()` switches the active `TextTrack` to
|
|
4108
|
+
* `mode="showing"`, handing subtitle rendering off to the browser's native PiP UI.
|
|
3885
4109
|
* - `padding-bottom` — switches between a minimal offset (`8px`) when controls are
|
|
3886
|
-
* hidden and a calculated offset
|
|
3887
|
-
*
|
|
4110
|
+
* hidden and a calculated offset (`--eva-control-element-height + --eva-scrub-bar-heights + 12px`)
|
|
4111
|
+
* when controls are visible.
|
|
3888
4112
|
*
|
|
3889
4113
|
* The `cue` signal is read directly from `EvaApi.currentSubtitleCue`, which is
|
|
3890
4114
|
* updated by `EvaCueChangeDirective` on each native `cuechange` event. No additional
|
|
3891
|
-
* subscription
|
|
4115
|
+
* subscription is required for the cue text itself.
|
|
3892
4116
|
*
|
|
3893
4117
|
* @example
|
|
3894
4118
|
* // Place inside eva-player to render active subtitle cues
|
|
@@ -3911,32 +4135,48 @@ class EvaSubtitleDisplay {
|
|
|
3911
4135
|
* Updated by subscribing to `EvaApi.componentsContainerVisibilityStateSubject`.
|
|
3912
4136
|
*/
|
|
3913
4137
|
controlsCointainerNotVisible = signal(false, ...(ngDevMode ? [{ debugName: "controlsCointainerNotVisible" }] : []));
|
|
4138
|
+
/**
|
|
4139
|
+
* Whether the player is currently in Picture-in-Picture mode.
|
|
4140
|
+
* When `true`, the `eva-subtitle-display--visible` class is suppressed so the
|
|
4141
|
+
* Angular subtitle overlay is hidden. The browser takes over subtitle rendering
|
|
4142
|
+
* inside the PiP window via the active `TextTrack` (mode switched to `"showing"`
|
|
4143
|
+
* by `EvaApi.setupPipListeners()`).
|
|
4144
|
+
* Updated by subscribing to `EvaApi.pictureInPictureSubject`.
|
|
4145
|
+
*/
|
|
4146
|
+
pipWindowActive = signal(false, ...(ngDevMode ? [{ debugName: "pipWindowActive" }] : []));
|
|
3914
4147
|
/** Subscription to controls container visibility changes. Cleaned up in `ngOnDestroy`. */
|
|
3915
|
-
|
|
4148
|
+
controlsVisibility$ = null;
|
|
4149
|
+
/** Subscription to Picture-in-Picture state changes. Cleaned up in `ngOnDestroy`. */
|
|
4150
|
+
pipWindowActive$ = null;
|
|
3916
4151
|
/**
|
|
3917
|
-
* Subscribes to
|
|
3918
|
-
*
|
|
3919
|
-
*
|
|
4152
|
+
* Subscribes to:
|
|
4153
|
+
* - `EvaApi.componentsContainerVisibilityStateSubject` — to adjust `padding-bottom`
|
|
4154
|
+
* based on controls bar visibility.
|
|
4155
|
+
* - `EvaApi.pictureInPictureSubject` — to suppress the subtitle overlay when PiP is active.
|
|
3920
4156
|
*/
|
|
3921
4157
|
ngOnInit() {
|
|
3922
|
-
this.
|
|
4158
|
+
this.controlsVisibility$ = this.evaAPI.componentsContainerVisibilityStateSubject.subscribe((a) => {
|
|
3923
4159
|
this.controlsCointainerNotVisible.set(a);
|
|
3924
4160
|
});
|
|
4161
|
+
this.pipWindowActive$ = this.evaAPI.pictureInPictureSubject.subscribe((a) => {
|
|
4162
|
+
this.pipWindowActive.set(a);
|
|
4163
|
+
});
|
|
3925
4164
|
}
|
|
3926
|
-
/** Unsubscribes from
|
|
4165
|
+
/** Unsubscribes from all active subscriptions to prevent memory leaks. */
|
|
3927
4166
|
ngOnDestroy() {
|
|
3928
|
-
this.
|
|
4167
|
+
this.controlsVisibility$?.unsubscribe();
|
|
4168
|
+
this.pipWindowActive$?.unsubscribe();
|
|
3929
4169
|
}
|
|
3930
4170
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EvaSubtitleDisplay, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3931
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: EvaSubtitleDisplay, isStandalone: true, selector: "eva-subtitle-display", host: { properties: { "class.eva-subtitle-display
|
|
4171
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: EvaSubtitleDisplay, isStandalone: true, selector: "eva-subtitle-display", host: { properties: { "class.eva-subtitle-display--visible": "cue() !== null && !pipWindowActive()", "style.padding-bottom": "controlsCointainerNotVisible() ? '8px' : 'calc(var(--eva-control-element-height) + var(--eva-scrub-bar-heights) + 12px)'" } }, ngImport: i0, template: "@if (cue() && !pipWindowActive()) {\n<span class=\"eva-subtitle-cue\" [innerHTML]=\"cue()\"></span>\n}", styles: [":host{display:none;visibility:hidden;position:absolute;inset-inline:0;bottom:0;pointer-events:none;text-align:center;z-index:10;transition:padding-bottom var(--eva-transition-duration) ease-in-out}:host(.eva-subtitle-display--visible){display:block!important;visibility:visible!important}.eva-subtitle-cue{display:inline-block;font-size:var(--eva-subtitle-font-size);line-height:1.4;font-family:var(--eva-subtitle-font-family);color:var(--eva-subtitle-color, #ffffff);background-color:var(--eva-subtitle-background, rgba(0, 0, 0, .72));padding:var(--eva-subtitle-padding);border-radius:3px;white-space:pre-line}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3932
4172
|
}
|
|
3933
4173
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EvaSubtitleDisplay, decorators: [{
|
|
3934
4174
|
type: Component,
|
|
3935
4175
|
args: [{ selector: "eva-subtitle-display", changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3936
|
-
|
|
3937
|
-
"[class.eva-subtitle-display--visible]": "cue() !== null",
|
|
4176
|
+
// Suppressed during PiP — the browser renders subtitles natively inside the PiP window
|
|
4177
|
+
"[class.eva-subtitle-display--visible]": "cue() !== null && !pipWindowActive()",
|
|
3938
4178
|
"[style.padding-bottom]": "controlsCointainerNotVisible() ? '8px' : 'calc(var(--eva-control-element-height) + var(--eva-scrub-bar-heights) + 12px)'"
|
|
3939
|
-
}, template: "@if (cue()) {\n<span class=\"eva-subtitle-cue\" [innerHTML]=\"cue()\"></span>\n}", styles: [":host{display:
|
|
4179
|
+
}, template: "@if (cue() && !pipWindowActive()) {\n<span class=\"eva-subtitle-cue\" [innerHTML]=\"cue()\"></span>\n}", styles: [":host{display:none;visibility:hidden;position:absolute;inset-inline:0;bottom:0;pointer-events:none;text-align:center;z-index:10;transition:padding-bottom var(--eva-transition-duration) ease-in-out}:host(.eva-subtitle-display--visible){display:block!important;visibility:visible!important}.eva-subtitle-cue{display:inline-block;font-size:var(--eva-subtitle-font-size);line-height:1.4;font-family:var(--eva-subtitle-font-family);color:var(--eva-subtitle-color, #ffffff);background-color:var(--eva-subtitle-background, rgba(0, 0, 0, .72));padding:var(--eva-subtitle-padding);border-radius:3px;white-space:pre-line}\n"] }]
|
|
3940
4180
|
}] });
|
|
3941
4181
|
|
|
3942
4182
|
/**
|
|
@@ -4958,6 +5198,8 @@ class EvaMediaEventListenersDirective {
|
|
|
4958
5198
|
canPlayThrough$ = null;
|
|
4959
5199
|
complete$ = null;
|
|
4960
5200
|
durationChange$ = null;
|
|
5201
|
+
enteredPiP$ = null;
|
|
5202
|
+
leftPiP$ = null;
|
|
4961
5203
|
emptied$ = null;
|
|
4962
5204
|
encrypted$ = null;
|
|
4963
5205
|
ended$ = null;
|
|
@@ -4987,6 +5229,8 @@ class EvaMediaEventListenersDirective {
|
|
|
4987
5229
|
completeSub = null;
|
|
4988
5230
|
durationChangeSub = null;
|
|
4989
5231
|
emptiedSub = null;
|
|
5232
|
+
enteredPipSub = null;
|
|
5233
|
+
leftPipSub = null;
|
|
4990
5234
|
encryptedSub = null;
|
|
4991
5235
|
endedSub = null;
|
|
4992
5236
|
errorSub = null;
|
|
@@ -5017,6 +5261,9 @@ class EvaMediaEventListenersDirective {
|
|
|
5017
5261
|
this.complete$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.COMPLETE);
|
|
5018
5262
|
this.durationChange$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.DURATION_CHANGE);
|
|
5019
5263
|
this.emptied$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.EMPTIED);
|
|
5264
|
+
this.enteredPiP$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.ENTERED_PICTURE_IN_PICTURE);
|
|
5265
|
+
this.leftPiP$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.LEFT_PICTURE_IN_PICTURE);
|
|
5266
|
+
this.emptied$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.EMPTIED);
|
|
5020
5267
|
this.encrypted$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.ENCRYPTED);
|
|
5021
5268
|
this.ended$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.ENDED);
|
|
5022
5269
|
this.error$ = fromEvent(this.elementRef.nativeElement, EvaVideoEvent.ERROR);
|
|
@@ -5059,6 +5306,14 @@ class EvaMediaEventListenersDirective {
|
|
|
5059
5306
|
/** Stub — no `EvaApi` side effect yet. */
|
|
5060
5307
|
this.emptiedSub = this.emptied$.subscribe(() => {
|
|
5061
5308
|
});
|
|
5309
|
+
this.enteredPipSub = this.enteredPiP$.subscribe((pip) => {
|
|
5310
|
+
this.evaAPI.assignPictureInPictureWindow(pip);
|
|
5311
|
+
});
|
|
5312
|
+
this.leftPipSub = this.leftPiP$.subscribe((pip) => {
|
|
5313
|
+
this.evaAPI.removePictureInPictureWindow(pip);
|
|
5314
|
+
});
|
|
5315
|
+
this.emptiedSub = this.emptied$.subscribe(() => {
|
|
5316
|
+
});
|
|
5062
5317
|
/** Stub — no `EvaApi` side effect yet. */
|
|
5063
5318
|
this.encryptedSub = this.encrypted$.subscribe(() => {
|
|
5064
5319
|
});
|
|
@@ -5156,6 +5411,8 @@ class EvaMediaEventListenersDirective {
|
|
|
5156
5411
|
this.completeSub?.unsubscribe();
|
|
5157
5412
|
this.durationChangeSub?.unsubscribe();
|
|
5158
5413
|
this.emptiedSub?.unsubscribe();
|
|
5414
|
+
this.enteredPipSub?.unsubscribe();
|
|
5415
|
+
this.leftPipSub?.unsubscribe();
|
|
5159
5416
|
this.encryptedSub?.unsubscribe();
|
|
5160
5417
|
this.endedSub?.unsubscribe();
|
|
5161
5418
|
this.errorSub?.unsubscribe();
|
|
@@ -5298,6 +5555,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
5298
5555
|
* `startingVolume`, which is validated and clamped via `validateAndPrepareStartingVideoVolume`
|
|
5299
5556
|
* before being assigned.
|
|
5300
5557
|
*
|
|
5558
|
+
* Sanitization strategy per property type:
|
|
5559
|
+
* - `poster` — sanitized with `SecurityContext.URL` as it is rendered as a resource URL.
|
|
5560
|
+
* - `width` / `height` / `startingVolume` — assigned as typed numbers; no sanitization needed.
|
|
5561
|
+
* - `autoplay` / `controls` / `loop` / `muted` / `playinline` /
|
|
5562
|
+
* `disablePictureInPicture` / `disableRemotePlayback` — assigned as typed booleans; no sanitization needed.
|
|
5563
|
+
* - `crossorigin` / `preload` — constrained enum strings assigned directly to typed DOM properties; no sanitization needed.
|
|
5564
|
+
*
|
|
5301
5565
|
* Supported configuration properties (all optional):
|
|
5302
5566
|
* - `width` / `height` — dimensions of the video element
|
|
5303
5567
|
* - `autoplay` — start playback automatically
|
|
@@ -5321,6 +5585,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
5321
5585
|
class EvaVideoConfigurationDirective {
|
|
5322
5586
|
evaAPI = inject(EvaApi);
|
|
5323
5587
|
elementRef = inject((ElementRef));
|
|
5588
|
+
sanitizer = inject(DomSanitizer);
|
|
5324
5589
|
/**
|
|
5325
5590
|
* The configuration object to apply to the native `<video>` element.
|
|
5326
5591
|
*
|
|
@@ -5341,7 +5606,6 @@ class EvaVideoConfigurationDirective {
|
|
|
5341
5606
|
* @param changes - The `SimpleChanges` map provided by Angular.
|
|
5342
5607
|
*/
|
|
5343
5608
|
ngOnChanges(changes) {
|
|
5344
|
-
// Only apply changes if view is initialized and videoConfig changed
|
|
5345
5609
|
if (this.isViewInitialized && changes['videoConfig']) {
|
|
5346
5610
|
this.applyConfiguration();
|
|
5347
5611
|
}
|
|
@@ -5358,6 +5622,11 @@ class EvaVideoConfigurationDirective {
|
|
|
5358
5622
|
* Iterates over all supported `EvaVideoElementConfiguration` properties and
|
|
5359
5623
|
* applies each one directly to the native `<video>` element if the value is truthy.
|
|
5360
5624
|
*
|
|
5625
|
+
* Sanitization is applied only where values are rendered as resource URLs:
|
|
5626
|
+
* - `poster` is sanitized with `SecurityContext.URL`.
|
|
5627
|
+
* - All other properties are typed DOM assignments (boolean, number, or constrained
|
|
5628
|
+
* enum string) and do not require sanitization.
|
|
5629
|
+
*
|
|
5361
5630
|
* `startingVolume` is passed through `validateAndPrepareStartingVideoVolume`
|
|
5362
5631
|
* before assignment to ensure it is clamped to a valid `[0, 1]` range.
|
|
5363
5632
|
*
|
|
@@ -5367,44 +5636,53 @@ class EvaVideoConfigurationDirective {
|
|
|
5367
5636
|
if (!this.evaVideoConfig()) {
|
|
5368
5637
|
return;
|
|
5369
5638
|
}
|
|
5370
|
-
|
|
5371
|
-
|
|
5639
|
+
const config = this.evaVideoConfig();
|
|
5640
|
+
// Numeric properties — assigned as typed numbers, no sanitization needed
|
|
5641
|
+
if (config.width) {
|
|
5642
|
+
this.elementRef.nativeElement.width = config.width;
|
|
5372
5643
|
}
|
|
5373
|
-
if (
|
|
5374
|
-
this.elementRef.nativeElement.height =
|
|
5644
|
+
if (config.height) {
|
|
5645
|
+
this.elementRef.nativeElement.height = config.height;
|
|
5375
5646
|
}
|
|
5376
|
-
|
|
5377
|
-
|
|
5647
|
+
// Boolean properties — assigned as typed booleans, no sanitization needed
|
|
5648
|
+
if (config.autoplay) {
|
|
5649
|
+
this.elementRef.nativeElement.autoplay = config.autoplay;
|
|
5378
5650
|
}
|
|
5379
|
-
if (
|
|
5380
|
-
this.elementRef.nativeElement.controls =
|
|
5651
|
+
if (config.controls) {
|
|
5652
|
+
this.elementRef.nativeElement.controls = config.controls;
|
|
5381
5653
|
}
|
|
5382
|
-
if (
|
|
5383
|
-
this.elementRef.nativeElement.
|
|
5654
|
+
if (config.disablePictureInPicture) {
|
|
5655
|
+
this.elementRef.nativeElement.disablePictureInPicture = config.disablePictureInPicture;
|
|
5384
5656
|
}
|
|
5385
|
-
if (
|
|
5386
|
-
this.elementRef.nativeElement.
|
|
5657
|
+
if (config.disableRemotePlayback) {
|
|
5658
|
+
this.elementRef.nativeElement.disableRemotePlayback = config.disableRemotePlayback;
|
|
5387
5659
|
}
|
|
5388
|
-
if (
|
|
5389
|
-
this.elementRef.nativeElement.
|
|
5660
|
+
if (config.loop) {
|
|
5661
|
+
this.elementRef.nativeElement.loop = config.loop;
|
|
5390
5662
|
}
|
|
5391
|
-
if (
|
|
5392
|
-
this.elementRef.nativeElement.
|
|
5663
|
+
if (config.muted) {
|
|
5664
|
+
this.elementRef.nativeElement.muted = config.muted;
|
|
5393
5665
|
}
|
|
5394
|
-
if (
|
|
5395
|
-
this.elementRef.nativeElement.
|
|
5666
|
+
if (config.playinline) {
|
|
5667
|
+
this.elementRef.nativeElement.playsInline = config.playinline;
|
|
5396
5668
|
}
|
|
5397
|
-
|
|
5398
|
-
|
|
5669
|
+
// Constrained enum strings — typed DOM properties with a fixed set of valid values,
|
|
5670
|
+
// no sanitization needed
|
|
5671
|
+
if (config.crossorigin) {
|
|
5672
|
+
this.elementRef.nativeElement.crossOrigin = config.crossorigin;
|
|
5399
5673
|
}
|
|
5400
|
-
if (
|
|
5401
|
-
this.elementRef.nativeElement.
|
|
5674
|
+
if (config.preload) {
|
|
5675
|
+
this.elementRef.nativeElement.preload = config.preload;
|
|
5402
5676
|
}
|
|
5403
|
-
|
|
5404
|
-
|
|
5677
|
+
// URL property — sanitized with SecurityContext.URL as the browser fetches this
|
|
5678
|
+
// as a resource and it is reflected in the DOM as an attribute
|
|
5679
|
+
if (config.poster) {
|
|
5680
|
+
this.elementRef.nativeElement.poster = this.sanitizer.sanitize(SecurityContext.URL, config.poster) ?? '';
|
|
5405
5681
|
}
|
|
5406
|
-
|
|
5407
|
-
|
|
5682
|
+
// Volume — validated and clamped to [0, 1] by validateAndPrepareStartingVideoVolume,
|
|
5683
|
+
// assigned as a typed number, no sanitization needed
|
|
5684
|
+
if (config.startingVolume) {
|
|
5685
|
+
this.elementRef.nativeElement.volume = validateAndPrepareStartingVideoVolume(config.startingVolume);
|
|
5408
5686
|
}
|
|
5409
5687
|
}
|
|
5410
5688
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EvaVideoConfigurationDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -5970,5 +6248,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
5970
6248
|
* Generated bundle index. Do not edit.
|
|
5971
6249
|
*/
|
|
5972
6250
|
|
|
5973
|
-
export { EvaActiveChapter, EvaBackward, EvaBuffering, EvaControlsContainer, EvaControlsDivider, EvaCueChangeDirective, EvaDashDirective, EvaForward, EvaFullscreen, EvaHlsDirective, EvaMediaEventListenersDirective, EvaMute, EvaOverlayPlay, EvaPlayPause, EvaPlaybackSpeed, EvaPlayer, EvaQualitySelector, EvaScrubBar, EvaScrubBarBufferingTime, EvaScrubBarCurrentTime, EvaState, EvaSubtitleDisplay, EvaTimeDisplay, EvaTimeDisplayPipe, EvaTrackSelector, EvaUserInteractionEventsDirective, EvaVideoConfigurationDirective, EvaVideoEvent, EvaVolume, isValidTrackKind, isValidVideoEvent, transformEvaActiveChaptedAria, transformEvaBackwardAria, transformEvaControlsDividerAria, transformEvaForwardAria, transformEvaFullscreenAria, transformEvaMuteAria, transformEvaOverlayPlayAria, transformEvaPlayPauseAria, transformEvaPlaybackSpeedAria, transformEvaScrubBarAria, transformEvaTimeDisplayAria, transformEvaVolumeAria, validateAndTransformEvaForwardAndBackwardSeconds, validateAndTransformVolumeRange };
|
|
6251
|
+
export { EvaActiveChapter, EvaBackward, EvaBuffering, EvaControlsContainer, EvaControlsDivider, EvaCueChangeDirective, EvaDashDirective, EvaForward, EvaFullscreen, EvaHlsDirective, EvaMediaEventListenersDirective, EvaMute, EvaOverlayPlay, EvaPictureInPicture, EvaPlayPause, EvaPlaybackSpeed, EvaPlayer, EvaQualitySelector, EvaScrubBar, EvaScrubBarBufferingTime, EvaScrubBarCurrentTime, EvaState, EvaSubtitleDisplay, EvaTimeDisplay, EvaTimeDisplayPipe, EvaTrackSelector, EvaUserInteractionEventsDirective, EvaVideoConfigurationDirective, EvaVideoEvent, EvaVolume, isValidTrackKind, isValidVideoEvent, transformEvaActiveChaptedAria, transformEvaBackwardAria, transformEvaControlsDividerAria, transformEvaForwardAria, transformEvaFullscreenAria, transformEvaMuteAria, transformEvaOverlayPlayAria, transformEvaPictureInPictureAria, transformEvaPlayPauseAria, transformEvaPlaybackSpeedAria, transformEvaScrubBarAria, transformEvaTimeDisplayAria, transformEvaVolumeAria, validateAndTransformEvaForwardAndBackwardSeconds, validateAndTransformVolumeRange };
|
|
5974
6252
|
//# sourceMappingURL=ez-vid-ang.mjs.map
|