@vime/core
Version:
Customizable, extensible, accessible and framework agnostic media player.
1,159 lines (1,124 loc) • 46.6 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const index = require('./index-86498cbd.js');
const withComponentRegistry = require('./withComponentRegistry-90ec334c.js');
const withPlayerContext = require('./withPlayerContext-77ea833f.js');
const PlayerDispatcher = require('./PlayerDispatcher-00dbedc9.js');
const withControlsCollisionDetection = require('./withControlsCollisionDetection-7c7e2319.js');
const formatters = require('./formatters-571a926a.js');
require('./PlayerEvents-79156eee.js');
const captionControlCss = ":host([hidden]){display:none}";
var __awaiter$6 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const CaptionControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.canToggleCaptionVisibility = false;
/**
* The URL to an SVG element or fragment to load.
*/
this.showIcon = 'captions-on';
/**
* The URL to an SVG element or fragment to load.
*/
this.hideIcon = 'captions-off';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @inheritdoc */
this.keys = 'c';
/** @internal */
this.i18n = {};
/** @internal */
this.playbackReady = false;
/** @internal */
this.textTracks = [];
/** @internal */
this.isTextTrackVisible = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, [
'i18n',
'textTracks',
'isTextTrackVisible',
'playbackReady',
]);
}
onTextTracksChange() {
var _a;
return __awaiter$6(this, void 0, void 0, function* () {
const player = withComponentRegistry.getPlayerFromRegistry(this);
this.canToggleCaptionVisibility =
this.textTracks.length > 0 &&
((_a = (yield (player === null || player === void 0 ? void 0 : player.canSetTextTrackVisibility()))) !== null && _a !== void 0 ? _a : false);
});
}
componentDidLoad() {
this.onTextTracksChange();
}
onClick() {
var _a;
const player = withComponentRegistry.getPlayerFromRegistry(this);
(_a = player === null || player === void 0 ? void 0 : player.setTextTrackVisibility) === null || _a === void 0 ? void 0 : _a.call(player, !this.isTextTrackVisible);
}
render() {
const tooltip = this.isTextTrackVisible
? this.i18n.disableCaptions
: this.i18n.enableCaptions;
const tooltipWithHint = !withComponentRegistry.isUndefined(this.keys)
? `${tooltip} (${this.keys})`
: tooltip;
return (index.h(index.Host, { hidden: !this.canToggleCaptionVisibility }, index.h("vm-control", { label: this.i18n.captions, keys: this.keys, hidden: !this.canToggleCaptionVisibility, pressed: this.isTextTrackVisible, onClick: this.onClick.bind(this) }, index.h("vm-icon", { name: this.isTextTrackVisible ? this.showIcon : this.hideIcon, library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip, position: this.tooltipPosition, direction: this.tooltipDirection }, tooltipWithHint))));
}
static get watchers() { return {
"textTracks": ["onTextTracksChange"],
"playbackReady": ["onTextTracksChange"]
}; }
};
CaptionControl.style = captionControlCss;
const controlGroupCss = ":host{width:100%}.controlGroup{position:relative;width:100%;display:flex;flex-wrap:wrap;flex-direction:inherit;align-items:inherit;justify-content:inherit;box-sizing:border-box}.controlGroup.spaceTop{margin-top:var(--vm-control-group-spacing)}.controlGroup.spaceBottom{margin-bottom:var(--vm-control-group-spacing)}::slotted(*){margin-left:var(--vm-controls-spacing)}::slotted(*:first-child){margin-left:0}";
const ControlNewLine = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/**
* Determines where to add spacing/margin. The amount of spacing is determined by the CSS variable
* `--control-group-spacing`.
*/
this.space = 'none';
withComponentRegistry.withComponentRegistry(this);
}
render() {
return (index.h("div", { class: {
controlGroup: true,
spaceTop: this.space !== 'none' && this.space !== 'bottom',
spaceBottom: this.space !== 'none' && this.space !== 'top',
} }, index.h("slot", null)));
}
get host() { return index.getElement(this); }
};
ControlNewLine.style = controlGroupCss;
const controlSpacerCss = ":host{flex:1}";
const ControlSpacer = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
withComponentRegistry.withComponentRegistry(this);
}
};
ControlSpacer.style = controlSpacerCss;
const debounce = (func, wait = 1000, immediate = false) => {
let timeout;
return function executedFunction(...args) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context = this;
const later = function delayedFunctionCall() {
timeout = undefined;
if (!immediate)
func.apply(context, args);
};
const callNow = immediate && withComponentRegistry.isUndefined(timeout);
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow)
func.apply(context, args);
};
};
const controlsCss = ":host{position:relative;width:100%;z-index:var(--vm-controls-z-index)}:host([video]){position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.controls{display:flex;width:100%;position:absolute;flex-wrap:wrap;pointer-events:auto;box-sizing:border-box;background:var(--vm-controls-bg);padding:var(--vm-controls-padding);border-radius:var(--vm-controls-border-radius);opacity:0;visibility:hidden;transition:var(--vm-fade-transition)}.controls.audio{position:relative}.controls.hidden{display:none}.controls.active{opacity:1;visibility:visible}.controls.fullWidth{width:100%}.controls.fullHeight{height:100%}::slotted(*:not(vm-control-group)){margin-left:var(--vm-controls-spacing)}::slotted(*:not(vm-control-group):first-child){margin-left:0}";
var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* We want to keep the controls active state in-sync per player.
*/
const playerRef = {};
const hideControlsTimeout = {};
const Controls = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.disposal = new withComponentRegistry.Disposal();
this.isInteracting = false;
/**
* Whether the controls are visible or not.
*/
this.hidden = false;
/**
* Whether the controls container should be 100% width. This has no effect if the view is of
* type `audio`.
*/
this.fullWidth = false;
/**
* Whether the controls container should be 100% height. This has no effect if the view is of
* type `audio`.
*/
this.fullHeight = false;
/**
* Sets the `flex-direction` property that manages the direction in which the controls are layed
* out.
*/
this.direction = 'row';
/**
* Sets the `align-items` flex property that aligns the individual controls on the cross-axis.
*/
this.align = 'center';
/**
* Sets the `justify-content` flex property that aligns the individual controls on the main-axis.
*/
this.justify = 'start';
/**
* Pins the controls to the defined position inside the video player. This has no effect when
* the view is of type `audio`.
*/
this.pin = 'bottomLeft';
/**
* The length in milliseconds that the controls are active for before fading out. Audio players
* are not effected by this prop.
*/
this.activeDuration = 2750;
/**
* Whether the controls should wait for playback to start before being shown. Audio players
* are not effected by this prop.
*/
this.waitForPlaybackStart = false;
/**
* Whether the controls should show/hide when paused. Audio players are not effected by this prop.
*/
this.hideWhenPaused = false;
/**
* Whether the controls should hide when the mouse leaves the player. Audio players are not
* effected by this prop.
*/
this.hideOnMouseLeave = false;
/** @internal */
this.isAudioView = false;
/** @internal */
this.isSettingsActive = false;
/** @internal */
this.playbackReady = false;
/** @internal */
this.isControlsActive = false;
/** @internal */
this.paused = true;
/** @internal */
this.playbackStarted = false;
withComponentRegistry.withComponentRegistry(this);
withControlsCollisionDetection.registerControlsForCollisionDetection(this);
withPlayerContext.withPlayerContext(this, [
'playbackReady',
'isAudioView',
'isControlsActive',
'isSettingsActive',
'paused',
'playbackStarted',
]);
}
connectedCallback() {
this.dispatch = PlayerDispatcher.createDispatcher(this);
this.onControlsChange();
this.setupPlayerListeners();
}
componentWillLoad() {
this.onControlsChange();
}
disconnectedCallback() {
this.disposal.empty();
delete hideControlsTimeout[playerRef[this]];
delete playerRef[this];
}
setupPlayerListeners() {
return __awaiter$5(this, void 0, void 0, function* () {
const player = yield withComponentRegistry.findPlayer(this);
if (withComponentRegistry.isUndefined(player))
return;
const events = ['focus', 'keydown', 'click', 'touchstart', 'mouseleave'];
events.forEach(event => {
this.disposal.add(withComponentRegistry.listen(player, event, this.onControlsChange.bind(this)));
});
this.disposal.add(withComponentRegistry.listen(player, 'mousemove', debounce(this.onControlsChange, 50, true).bind(this)));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
playerRef[this] = player;
});
}
show() {
this.dispatch('isControlsActive', true);
}
hide() {
this.dispatch('isControlsActive', false);
}
hideWithDelay() {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
clearTimeout(hideControlsTimeout[playerRef[this]]);
hideControlsTimeout[playerRef[this]] = setTimeout(() => {
this.hide();
}, this.activeDuration);
}
onControlsChange(event) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
clearTimeout(hideControlsTimeout[playerRef[this]]);
if (this.hidden || !this.playbackReady) {
this.hide();
return;
}
if (this.isAudioView) {
this.show();
return;
}
if (this.waitForPlaybackStart && !this.playbackStarted) {
this.hide();
return;
}
if (this.isInteracting || this.isSettingsActive) {
this.show();
return;
}
if (this.hideWhenPaused && this.paused) {
this.hideWithDelay();
return;
}
if (this.hideOnMouseLeave && !this.paused && (event === null || event === void 0 ? void 0 : event.type) === 'mouseleave') {
this.hide();
return;
}
if (!this.paused) {
this.show();
this.hideWithDelay();
return;
}
this.show();
}
getPosition() {
if (this.isAudioView)
return {};
if (this.pin === 'center') {
return {
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
};
}
// topLeft => { top: 0, left: 0 }
const pos = this.pin.split(/(?=[L|R])/).map(s => s.toLowerCase());
return { [pos[0]]: 0, [pos[1]]: 0 };
}
onStartInteraction() {
this.isInteracting = true;
}
onEndInteraction() {
this.isInteracting = false;
}
render() {
return (index.h(index.Host, { video: !this.isAudioView }, index.h("div", { style: Object.assign(Object.assign({}, this.getPosition()), { flexDirection: this.direction, alignItems: this.align === 'center' ? 'center' : `flex-${this.align}`, justifyContent: this.justify }), class: {
controls: true,
audio: this.isAudioView,
hidden: this.hidden,
active: this.playbackReady && this.isControlsActive,
fullWidth: this.isAudioView || this.fullWidth,
fullHeight: !this.isAudioView && this.fullHeight,
}, onMouseEnter: this.onStartInteraction.bind(this), onMouseLeave: this.onEndInteraction.bind(this), onTouchStart: this.onStartInteraction.bind(this), onTouchEnd: this.onEndInteraction.bind(this) }, index.h("slot", null))));
}
static get watchers() { return {
"paused": ["onControlsChange"],
"hidden": ["onControlsChange"],
"isAudioView": ["onControlsChange"],
"isInteracting": ["onControlsChange"],
"isSettingsActive": ["onControlsChange"],
"hideWhenPaused": ["onControlsChange"],
"hideOnMouseLeave": ["onControlsChange"],
"playbackStarted": ["onControlsChange"],
"waitForPlaybackStart": ["onControlsChange"],
"playbackReady": ["onControlsChange"]
}; }
};
Controls.style = controlsCss;
const currentTimeCss = ":host{display:flex;align-items:center;justify-content:center}";
const CurrentTime = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/** @internal */
this.currentTime = 0;
/** @internal */
this.i18n = {};
/**
* Whether the time should always show the hours unit, even if the time is less than
* 1 hour (eg: `20:35` -> `00:20:35`).
*/
this.alwaysShowHours = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['currentTime', 'i18n']);
}
render() {
return (index.h("vm-time", { label: this.i18n.currentTime, seconds: this.currentTime, alwaysShowHours: this.alwaysShowHours }));
}
};
CurrentTime.style = currentTimeCss;
const endTimeCss = ":host{display:flex;align-items:center;justify-content:center}";
const EndTime = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/** @internal */
this.duration = -1;
/** @internal */
this.i18n = {};
/**
* Whether the time should always show the hours unit, even if the time is less than
* 1 hour (eg: `20:35` -> `00:20:35`).
*/
this.alwaysShowHours = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['duration', 'i18n']);
}
render() {
return (index.h("vm-time", { label: this.i18n.duration, seconds: Math.max(0, this.duration), alwaysShowHours: this.alwaysShowHours }));
}
};
EndTime.style = endTimeCss;
const fullscreenControlCss = ":host([hidden]){display:none}";
var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const FullscreenControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.canSetFullscreen = false;
/**
* The name of the enter fullscreen icon to resolve from the icon library.
*/
this.enterIcon = 'fullscreen-enter';
/**
* The name of the exit fullscreen icon to resolve from the icon library.
*/
this.exitIcon = 'fullscreen-exit';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @inheritdoc */
this.keys = 'f';
/** @internal */
this.isFullscreenActive = false;
/** @internal */
this.i18n = {};
/** @internal */
this.playbackReady = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['isFullscreenActive', 'playbackReady', 'i18n']);
}
onPlaybackReadyChange() {
var _a;
return __awaiter$4(this, void 0, void 0, function* () {
const player = withComponentRegistry.getPlayerFromRegistry(this);
this.canSetFullscreen = (_a = (yield (player === null || player === void 0 ? void 0 : player.canSetFullscreen()))) !== null && _a !== void 0 ? _a : false;
});
}
componentDidLoad() {
this.onPlaybackReadyChange();
}
onClick() {
const player = withComponentRegistry.getPlayerFromRegistry(this);
!this.isFullscreenActive
? player === null || player === void 0 ? void 0 : player.enterFullscreen()
: player === null || player === void 0 ? void 0 : player.exitFullscreen();
}
render() {
const tooltip = this.isFullscreenActive
? this.i18n.exitFullscreen
: this.i18n.enterFullscreen;
const tooltipWithHint = !withComponentRegistry.isUndefined(this.keys)
? `${tooltip} (${this.keys})`
: tooltip;
return (index.h(index.Host, { hidden: !this.canSetFullscreen }, index.h("vm-control", { label: this.i18n.fullscreen, keys: this.keys, pressed: this.isFullscreenActive, hidden: !this.canSetFullscreen, onClick: this.onClick.bind(this) }, index.h("vm-icon", { name: this.isFullscreenActive ? this.exitIcon : this.enterIcon, library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip, position: this.tooltipPosition, direction: this.tooltipDirection }, tooltipWithHint))));
}
static get watchers() { return {
"playbackReady": ["onPlaybackReadyChange"]
}; }
};
FullscreenControl.style = fullscreenControlCss;
const liveIndicatorCss = ".liveIndicator{display:flex;align-items:center;font-size:13px;font-weight:bold;letter-spacing:0.6px;color:var(--vm-control-color)}.liveIndicator.hidden{display:none}.indicator{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px;background-color:var(--vm-live-indicator-color, red)}";
const LiveIndicator = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/** @internal */
this.isLive = false;
/** @internal */
this.i18n = {};
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['isLive', 'i18n']);
}
render() {
return (index.h("div", { class: {
liveIndicator: true,
hidden: !this.isLive,
} }, index.h("div", { class: "indicator" }), this.i18n.live));
}
};
LiveIndicator.style = liveIndicatorCss;
const MuteControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.vmFocus = index.createEvent(this, "vmFocus", 7);
this.vmBlur = index.createEvent(this, "vmBlur", 7);
/**
* The name of the low volume icon to resolve from the icon library.
*/
this.lowVolumeIcon = 'volume-low';
/**
* The name of the high volume icon to resolve from the icon library.
*/
this.highVolumeIcon = 'volume-high';
/**
* The name of the muted volume icon to resolve from the icon library.
*/
this.mutedIcon = 'volume-mute';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @inheritdoc */
this.keys = 'm';
/** @internal */
this.volume = 50;
/** @internal */
this.muted = false;
/** @internal */
this.i18n = {};
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['muted', 'volume', 'i18n']);
}
connectedCallback() {
this.dispatch = PlayerDispatcher.createDispatcher(this);
}
getIcon() {
const volumeIcon = this.volume < 50 ? this.lowVolumeIcon : this.highVolumeIcon;
return this.muted || this.volume === 0 ? this.mutedIcon : volumeIcon;
}
onClick() {
this.dispatch('muted', !this.muted);
}
render() {
const tooltip = this.muted ? this.i18n.unmute : this.i18n.mute;
const tooltipWithHint = !withComponentRegistry.isUndefined(this.keys)
? `${tooltip} (${this.keys})`
: tooltip;
return (index.h("vm-control", { label: this.i18n.mute, pressed: this.muted, keys: this.keys, onClick: this.onClick.bind(this) }, index.h("vm-icon", { name: this.getIcon(), library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip, position: this.tooltipPosition, direction: this.tooltipDirection }, tooltipWithHint)));
}
};
const pipControlCss = ":host([hidden]){display:none}";
var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const PiPControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.canSetPiP = false;
/**
* The name of the enter pip icon to resolve from the icon library.
*/
this.enterIcon = 'pip-enter';
/**
* The name of the exit pip icon to resolve from the icon library.
*/
this.exitIcon = 'pip-exit';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @inheritdoc */
this.keys = 'p';
/** @internal */
this.isPiPActive = false;
/** @internal */
this.i18n = {};
/** @internal */
this.playbackReady = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['isPiPActive', 'playbackReady', 'i18n']);
}
onPlaybackReadyChange() {
var _a;
return __awaiter$3(this, void 0, void 0, function* () {
const player = withComponentRegistry.getPlayerFromRegistry(this);
this.canSetPiP = (_a = (yield (player === null || player === void 0 ? void 0 : player.canSetPiP()))) !== null && _a !== void 0 ? _a : false;
});
}
componentDidLoad() {
this.onPlaybackReadyChange();
}
onClick() {
const player = withComponentRegistry.getPlayerFromRegistry(this);
!this.isPiPActive ? player === null || player === void 0 ? void 0 : player.enterPiP() : player === null || player === void 0 ? void 0 : player.exitPiP();
}
render() {
const tooltip = this.isPiPActive ? this.i18n.exitPiP : this.i18n.enterPiP;
const tooltipWithHint = !withComponentRegistry.isUndefined(this.keys)
? `${tooltip} (${this.keys})`
: tooltip;
return (index.h(index.Host, { hidden: !this.canSetPiP }, index.h("vm-control", { label: this.i18n.pip, keys: this.keys, pressed: this.isPiPActive, hidden: !this.canSetPiP, onClick: this.onClick.bind(this) }, index.h("vm-icon", { name: this.isPiPActive ? this.exitIcon : this.enterIcon, library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip, position: this.tooltipPosition, direction: this.tooltipDirection }, tooltipWithHint))));
}
static get watchers() { return {
"playbackReady": ["onPlaybackReadyChange"]
}; }
};
PiPControl.style = pipControlCss;
const PlaybackControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/**
* The name of the play icon to resolve from the icon library.
*/
this.playIcon = 'play';
/**
* The name of the pause icon to resolve from the icon library.
*/
this.pauseIcon = 'pause';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @inheritdoc */
this.keys = 'k';
/** @internal */
this.paused = true;
/** @internal */
this.i18n = {};
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['paused', 'i18n']);
}
connectedCallback() {
this.dispatch = PlayerDispatcher.createDispatcher(this);
}
onClick() {
this.dispatch('paused', !this.paused);
}
render() {
const tooltip = this.paused ? this.i18n.play : this.i18n.pause;
const tooltipWithHint = !withComponentRegistry.isUndefined(this.keys)
? `${tooltip} (${this.keys})`
: tooltip;
return (index.h("vm-control", { label: this.i18n.playback, keys: this.keys, pressed: !this.paused, onClick: this.onClick.bind(this) }, index.h("vm-icon", { name: this.paused ? this.playIcon : this.pauseIcon, library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip, position: this.tooltipPosition, direction: this.tooltipDirection }, tooltipWithHint)));
}
};
const scrimCss = ":host{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:var(--vm-scrim-z-index)}.scrim{position:absolute;width:100%;background:var(--vm-scrim-bg);display:inline-block;opacity:0;visibility:hidden;transition:var(--vm-fade-transition)}.scrim.gradient{height:258px;background:none;background-position:bottom;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAECCAYAAAA/9r2TAAABKklEQVQ4T2XI50cFABiF8dvee++67b33uM17b1MkkSSSSBJJJIkkkkQSSSKJ9Efmeb8cr86HH88JBP4thkfEkiKOFPGkSCCNRE8SKZJJkUIaqZ40UqSTIoMUmaSR5ckmRQ4pckkjz5NPigJSFJKiiDSKPSWkKCVFGWmUeypIUUmKKlJUk0aNJ0iKWlLUkUa9p4EUjaRoIkUzabR4WknRRop20ujwdJKiixTdpOghjV5PHyn6STFAGoOeIVIMk2KEFKOkMeYZJ8UEKUKkMemZIsU0KWZIMUsac54wKSKkiJLGvGeBFIukWCLFMrkCq7AG67ABm7AF27ADu7AH+3AAh3AEx3ACp3AG53ABl3AF13ADt3AH9/AAj/AEz/ACr/AG7/ABn/AF3/ADv39LujSyJPVJ0QAAAABJRU5ErkJggg==')}.scrim.gradientUp{top:unset;bottom:0}.scrim.gradientDown{transform:rotate(180deg)}.scrim.hidden{display:none}.scrim.active{opacity:1;visibility:visible}";
const Scrim = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/** @internal */
this.isVideoView = false;
/** @internal */
this.isControlsActive = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['isVideoView', 'isControlsActive']);
}
render() {
return (index.h("div", { class: {
scrim: true,
gradient: !withComponentRegistry.isUndefined(this.gradient),
gradientUp: this.gradient === 'up',
gradientDown: this.gradient === 'down',
hidden: !this.isVideoView,
active: this.isControlsActive,
} }));
}
};
Scrim.style = scrimCss;
const scrubberControlCss = ":host{--vm-tooltip-spacing:var(--vm-scrubber-tooltip-spacing);flex:1;position:relative;cursor:pointer;pointer-events:auto;box-sizing:border-box;left:calc(var(--vm-slider-thumb-width) / 2);margin-right:var(--vm-slider-thumb-width);margin-bottom:var(--vm-slider-track-height)}@keyframes progress{to{background-position:var(--vm-scrubber-loading-stripe-size) 0}}.scrubber{position:relative;width:100%}vm-slider,progress{margin-left:calc(calc(var(--vm-slider-thumb-width) / 2) * -1);margin-right:calc(calc(var(--vm-slider-thumb-width) / 2) * -1);width:calc(100% + var(--vm-slider-thumb-width));height:var(--vm-slider-track-height)}vm-slider:hover,progress:hover{cursor:pointer}vm-slider{position:absolute;top:0;left:0;z-index:3}progress{-webkit-appearance:none;background:transparent;border:0;border-radius:100px;position:absolute;left:0;top:50%;padding:0;color:var(--vm-scrubber-buffered-bg);height:var(--vm-slider-track-height)}progress::-webkit-progress-bar{background:transparent}progress::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:var(--vm-slider-track-height);transition:width 0.2s ease}progress::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:var(--vm-slider-track-height);transition:width 0.2s ease}progress::-ms-fill{border-radius:100px;transition:width 0.2s ease}progress.loading{animation:progress 1s linear infinite;background-image:linear-gradient(\n -45deg,\n var(--vm-scrubber-loading-stripe-color) 25%,\n transparent 25%,\n transparent 50%,\n var(--vm-scrubber-loading-stripe-color) 50%,\n var(--vm-scrubber-loading-stripe-color) 75%,\n transparent 75%,\n transparent\n );background-repeat:repeat-x;background-size:var(--vm-scrubber-loading-stripe-size)\n var(--vm-scrubber-loading-stripe-size);color:transparent;background-color:transparent}";
var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const ScrubberControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.keyboardDisposal = new withComponentRegistry.Disposal();
this.timestamp = '';
this.endTime = 0;
/**
* Whether the timestamp in the tooltip should show the hours unit, even if the time is less than
* 1 hour (eg: `20:35` -> `00:20:35`).
*/
this.alwaysShowHours = false;
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
/** @internal */
this.currentTime = 0;
/** @internal */
this.duration = -1;
/**
* Prevents seeking forward/backward by using the Left/Right arrow keys.
*/
this.noKeyboard = false;
/** @internal */
this.buffering = false;
/** @internal */
this.buffered = 0;
/** @internal */
this.i18n = {};
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, [
'i18n',
'currentTime',
'duration',
'buffering',
'buffered',
]);
}
onNoKeyboardChange() {
return __awaiter$2(this, void 0, void 0, function* () {
this.keyboardDisposal.empty();
if (this.noKeyboard)
return;
const player = yield withComponentRegistry.findPlayer(this);
if (withComponentRegistry.isUndefined(player))
return;
const onKeyDown = (event) => {
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight')
return;
event.preventDefault();
const isLeftArrow = event.key === 'ArrowLeft';
const seekTo = isLeftArrow
? Math.max(0, this.currentTime - 5)
: Math.min(this.duration, this.currentTime + 5);
this.dispatch('currentTime', seekTo);
};
this.keyboardDisposal.add(withComponentRegistry.listen(player, 'keydown', onKeyDown));
});
}
onDurationChange() {
// Avoid -1.
this.endTime = Math.max(0, this.duration);
}
connectedCallback() {
this.dispatch = PlayerDispatcher.createDispatcher(this);
this.timestamp = formatters.formatTime(this.currentTime, this.alwaysShowHours);
this.onNoKeyboardChange();
}
disconnectedCallback() {
this.keyboardDisposal.empty();
}
setTooltipPosition(value) {
var _a, _b;
const tooltipRect = (_b = (_a = this.tooltip.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.tooltip')) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
const bounds = this.slider.getBoundingClientRect();
const thumbWidth = parseFloat(window
.getComputedStyle(this.slider)
.getPropertyValue('--vm-slider-thumb-width'));
const leftLimit = tooltipRect.width / 2 - thumbWidth / 2;
const rightLimit = bounds.width - tooltipRect.width / 2 - thumbWidth / 2;
const xPos = Math.max(leftLimit, Math.min(value, rightLimit));
this.tooltip.style = `--vm-tooltip-left: ${xPos}px`;
}
onSeek(event) {
this.dispatch('currentTime', event.detail);
}
onSeeking(event) {
if (this.duration < 0 || this.tooltip.hidden)
return;
if (event.type === 'mouseleave') {
this.getSliderInput().blur();
this.tooltip.active = false;
return;
}
const rect = this.host.getBoundingClientRect();
const percent = Math.max(0, Math.min(100, (100 / rect.width) * (event.pageX - rect.left)));
this.timestamp = formatters.formatTime((this.duration / 100) * percent, this.alwaysShowHours);
this.setTooltipPosition((percent / 100) * rect.width);
if (!this.tooltip.active) {
this.getSliderInput().focus();
this.tooltip.active = true;
}
}
getSliderInput() {
var _a;
return (_a = this.slider.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('input');
}
render() {
const sliderValueText = this.i18n.scrubberLabel
.replace(/{currentTime}/, formatters.formatTime(this.currentTime))
.replace(/{duration}/, formatters.formatTime(this.endTime));
return (index.h("div", { class: "scrubber", onMouseEnter: this.onSeeking.bind(this), onMouseLeave: this.onSeeking.bind(this), onMouseMove: this.onSeeking.bind(this), onTouchMove: () => {
this.getSliderInput().focus();
}, onTouchEnd: () => {
this.getSliderInput().blur();
} }, index.h("vm-slider", { step: 0.01, max: this.endTime, value: this.currentTime, label: this.i18n.scrubber, valueText: sliderValueText, onVmValueChange: this.onSeek.bind(this), ref: (el) => {
this.slider = el;
} }), index.h("progress", { class: {
loading: this.buffering,
},
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
min: 0, max: this.endTime, value: this.buffered, "aria-label": this.i18n.buffered, "aria-valuemin": "0", "aria-valuemax": this.endTime, "aria-valuenow": this.buffered, "aria-valuetext": `${(this.endTime > 0
? this.buffered / this.endTime
: 0).toFixed(0)}%` }, "% buffered"), index.h("vm-tooltip", { hidden: this.hideTooltip, ref: (el) => {
this.tooltip = el;
} }, this.timestamp)));
}
get host() { return index.getElement(this); }
static get watchers() { return {
"noKeyboard": ["onNoKeyboardChange"],
"duration": ["onDurationChange"]
}; }
};
ScrubberControl.style = scrubberControlCss;
const settingsControlCss = ".settingsControl.hidden{display:none}.settingsControl{--vm-icon-transition:transform 0.3s ease}.settingsControl.active{--vm-icon-transform:rotate(90deg)}";
var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
let idCount = 0;
const SettingsControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/**
* The name of the settings icon to resolve from the icon library.
*/
this.icon = 'settings';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the settings menu this control manages is open.
*/
this.expanded = false;
/** @internal */
this.i18n = {};
/**
* Whether the tooltip should not be displayed.
*/
this.hideTooltip = false;
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['i18n']);
}
onComponentsChange() {
if (!withComponentRegistry.isUndefined(this.vmSettings)) {
this.vmSettings.setController(this.host);
}
}
connectedCallback() {
idCount += 1;
this.id = `vm-settings-control-${idCount}`;
withComponentRegistry.watchComponentRegistry(this, 'vm-settings', regs => {
[this.vmSettings] = regs;
});
}
/**
* Focuses the control.
*/
focusControl() {
var _a;
return __awaiter$1(this, void 0, void 0, function* () {
(_a = this.control) === null || _a === void 0 ? void 0 : _a.focusControl();
});
}
/**
* Removes focus from the control.
*/
blurControl() {
var _a;
return __awaiter$1(this, void 0, void 0, function* () {
(_a = this.control) === null || _a === void 0 ? void 0 : _a.blurControl();
});
}
render() {
const hasSettings = !withComponentRegistry.isUndefined(this.menu);
return (index.h("div", { class: {
settingsControl: true,
hidden: !hasSettings,
active: hasSettings && this.expanded,
} }, index.h("vm-control", { identifier: this.id, menu: this.menu, hidden: !hasSettings, expanded: this.expanded, label: this.i18n.settings, ref: control => {
this.control = control;
} }, index.h("vm-icon", { name: this.icon, library: this.icons }), index.h("vm-tooltip", { hidden: this.hideTooltip || this.expanded, position: this.tooltipPosition, direction: this.tooltipDirection }, this.i18n.settings))));
}
get host() { return index.getElement(this); }
static get watchers() { return {
"vmSettings": ["onComponentsChange"]
}; }
};
SettingsControl.style = settingsControlCss;
const timeProgressCss = ".timeProgress{display:flex;width:100%;height:100%;align-items:center;color:var(--vm-time-color)}.separator{margin:0 4px}";
const TimeProgress = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
/**
* The string used to separate the current time and end time.
*/
this.separator = '/';
/**
* Whether the times should always show the hours unit, even if the time is less than
* 1 hour (eg: `20:35` -> `00:20:35`).
*/
this.alwaysShowHours = false;
withComponentRegistry.withComponentRegistry(this);
}
render() {
return (index.h("div", { class: "timeProgress" }, index.h("vm-current-time", { alwaysShowHours: this.alwaysShowHours }), index.h("span", { class: "separator" }, this.separator), index.h("vm-end-time", { alwaysShowHours: this.alwaysShowHours })));
}
};
TimeProgress.style = timeProgressCss;
const volumeControlCss = ".volumeControl{align-items:center;display:flex;position:relative;pointer-events:auto;box-sizing:border-box}vm-slider{width:75px;height:100%;margin:0;max-width:0;position:relative;z-index:3;transition:margin 0.2s cubic-bezier(0.4, 0, 1, 1),\n max-width 0.2s cubic-bezier(0.4, 0, 1, 1);margin-left:calc(var(--vm-control-spacing) / 2) !important;visibility:hidden}vm-slider:hover{cursor:pointer}vm-slider.hidden{display:none}vm-slider.active{max-width:75px;visibility:visible;margin:0 calc(var(--vm-control-spacing) / 2)}";
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const VolumeControl = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.keyboardDisposal = new withComponentRegistry.Disposal();
this.prevMuted = false;
this.currentVolume = 50;
this.isSliderActive = false;
/**
* The name of the low volume icon to resolve from the icon library.
*/
this.lowVolumeIcon = 'volume-low';
/**
* The name of the high volume icon to resolve from the icon library.
*/
this.highVolumeIcon = 'volume-high';
/**
* The name of the muted volume icon to resolve from the icon library.
*/
this.mutedIcon = 'volume-mute';
/**
* Whether the tooltip is positioned above/below the control.
*/
this.tooltipPosition = 'top';
/**
* Whether the tooltip should be hidden.
*/
this.hideTooltip = false;
/**
* A pipe (`/`) separated string of JS keyboard keys, that when caught in a `keydown` event, will
* toggle the muted state of the player.
*/
this.muteKeys = 'm';
/**
* Prevents the volume being changed using the Up/Down arrow keys.
*/
this.noKeyboard = false;
/** @internal */
this.muted = false;
/** @internal */
this.volume = 50;
/** @internal */
this.isMobile = false;
/** @internal */
this.i18n = {};
withComponentRegistry.withComponentRegistry(this);
withPlayerContext.withPlayerContext(this, ['volume', 'muted', 'isMobile', 'i18n']);
}
onNoKeyboardChange() {
return __awaiter(this, void 0, void 0, function* () {
this.keyboardDisposal.empty();
if (this.noKeyboard)
return;
const player = yield withComponentRegistry.findPlayer(this);
if (withComponentRegistry.isUndefined(player))
return;
this.keyboardDisposal.add(withComponentRegistry.listen(player, 'keydown', (event) => {
if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')
return;
const isUpArrow = event.key === 'ArrowUp';
const newVolume = isUpArrow
? Math.min(100, this.volume + 5)
: Math.max(0, this.volume - 5);
this.dispatch('volume', parseInt(`${newVolume}`, 10));
}));
});
}
onPlayerVolumeChange() {
this.currentVolume = this.muted ? 0 : this.volume;
if (!this.muted && this.prevMuted && this.volume === 0) {
this.dispatch('volume', 30);
}
this.prevMuted = this.muted;
}
connectedCallback() {
this.prevMuted = this.muted;
this.dispatch = PlayerDispatcher.createDispatcher(this);
this.onNoKeyboardChange();
}
disconnectedCallback() {
this.keyboardDisposal.empty();
}
onShowSlider() {
clearTimeout(this.hideSliderTimeout);
this.isSliderActive = true;
}
onHideSlider() {
this.hideSliderTimeout = setTimeout(() => {
this.isSliderActive = false;
}, 100);
}
onVolumeChange(event) {
const newVolume = event.detail;
this.currentVolume = newVolume;
this.dispatch('volume', newVolume);
this.dispatch('muted', newVolume === 0);
}
onKeyDown(event) {
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight')
return;
event.stopPropagation();
}
render() {
return (index.h("div", { class: "volumeControl", onMouseEnter: this.onShowSlider.bind(this), onMouseLeave: this.onHideSlider.bind(this) }, index.h("vm-mute-control", { keys: this.muteKeys, lowVolumeIcon: this.lowVolumeIcon, highVolumeIcon: this.highVolumeIcon, mutedIcon: this.mutedIcon, icons: this.icons, tooltipPosition: this.tooltipPosition, tooltipDirection: this.tooltipDirection, hideTooltip: this.hideTooltip, onVmFocus: this.onShowSlider.bind(this), onVmBlur: this.onHideSlider.bind(this) }), index.h("vm-slider", { class: {
hidden: this.isMobile,
active: this.isSliderActive,
}, step: 5, max: 100, value: this.currentVolume, label: this.i18n.volume, onKeyDown: this.onKeyDown.bind(this), onVmFocus: this.onShowSlider.bind(this), onVmBlur: this.onHideSlider.bind(this), onVmValueChange: this.onVolumeChange.bind(this) })));
}
static get watchers() { return {
"noKeyboard": ["onNoKeyboardChange"],
"muted": ["onPlayerVolumeChange"],
"volume": ["onPlayerVolumeChange"]
}; }
};
VolumeControl.style = volumeControlCss;
exports.vm_caption_control = CaptionControl;
exports.vm_control_group = ControlNewLine;
exports.vm_control_spacer = ControlSpacer;
exports.vm_controls = Controls;
exports.vm_current_time = CurrentTime;
exports.vm_end_time = EndTime;
exports.vm_fullscreen_control = FullscreenControl;
exports.vm_live_indicator = LiveIndicator;
exports.vm_mute_control = MuteControl;
exports.vm_pip_control = PiPControl;
exports.vm_playback_control = PlaybackControl;
exports.vm_scrim = Scrim;
exports.vm_scrubber_control = ScrubberControl;
exports.vm_settings_control = SettingsControl;
exports.vm_time_progress = TimeProgress;
exports.vm_volume_control = VolumeControl;