UNPKG

@vime/core

Version:

Customizable, extensible, accessible and framework agnostic media player.

347 lines (338 loc) 12.9 kB
import { r as registerInstance, c as createEvent, h, g as getElement } from './index-f5fd0f81.js'; import { D as Disposal, c as withComponentRegistry, e as isUndefined, f as findPlayer, l as listen, x as isNull, h as isString } from './withComponentRegistry-28311671.js'; import { w as withPlayerContext } from './withPlayerContext-4c52f564.js'; import { w as withIconRegistry, g as getIconLibraryResolver } from './IconRegistry-75cb81e3.js'; import './PlayerEvents-5c5704d6.js'; const controlCss = "button{display:flex;align-items:center;flex-direction:row;border:var(--vm-control-border);cursor:pointer;flex-shrink:0;font-size:var(--vm-control-icon-size);color:var(--vm-control-color);background:var(--vm-control-bg, transparent);border-radius:var(--vm-control-border-radius);padding:var(--vm-control-padding);position:relative;pointer-events:auto;transition:all 0.3s ease;transform:scale(var(--vm-control-scale, 1));touch-action:manipulation;box-sizing:border-box}button.hidden{display:none}button:focus{outline:0}button.tapHighlight{background:var(--vm-control-tap-highlight)}button.notTouch:focus,button.notTouch:hover,button.notTouch[aria-expanded='true']{background:var(--vm-control-focus-bg);color:var(--vm-control-focus-color);transform:scale(calc(var(--vm-control-scale, 1) + 0.06))}"; 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 Control = class { constructor(hostRef) { registerInstance(this, hostRef); this.vmInteractionChange = createEvent(this, "vmInteractionChange", 7); this.vmFocus = createEvent(this, "vmFocus", 7); this.vmBlur = createEvent(this, "vmBlur", 7); this.keyboardDisposal = new Disposal(); this.showTapHighlight = false; /** * Whether the control should be displayed or not. */ this.hidden = false; /** @internal */ this.isTouch = false; withComponentRegistry(this); withPlayerContext(this, ['isTouch']); } onKeysChange() { return __awaiter$2(this, void 0, void 0, function* () { this.keyboardDisposal.empty(); if (isUndefined(this.keys)) return; const player = yield findPlayer(this); const codes = this.keys.split('/'); if (isUndefined(player)) return; this.keyboardDisposal.add(listen(player, 'keydown', (event) => { if (codes.includes(event.key)) { this.button.click(); } })); }); } connectedCallback() { this.findTooltip(); this.onKeysChange(); } componentWillLoad() { this.findTooltip(); } disconnectedCallback() { this.keyboardDisposal.empty(); } /** * Focuses the control. */ focusControl() { var _a; return __awaiter$2(this, void 0, void 0, function* () { (_a = this.button) === null || _a === void 0 ? void 0 : _a.focus(); }); } /** * Removes focus from the control. */ blurControl() { var _a; return __awaiter$2(this, void 0, void 0, function* () { (_a = this.button) === null || _a === void 0 ? void 0 : _a.blur(); }); } onTouchStart() { this.showTapHighlight = true; } onTouchEnd() { setTimeout(() => { this.showTapHighlight = false; }, 100); } findTooltip() { const tooltip = this.host.querySelector('vm-tooltip'); if (!isNull(tooltip)) this.describedBy = tooltip.id; return tooltip; } onShowTooltip() { const tooltip = this.findTooltip(); if (!isNull(tooltip)) tooltip.active = true; this.vmInteractionChange.emit(true); } onHideTooltip() { const tooltip = this.findTooltip(); if (!isNull(tooltip)) tooltip.active = false; this.button.blur(); this.vmInteractionChange.emit(false); } onFocus() { this.vmFocus.emit(); this.onShowTooltip(); } onBlur() { this.vmBlur.emit(); this.onHideTooltip(); } onMouseEnter() { this.onShowTooltip(); } onMouseLeave() { this.onHideTooltip(); } render() { const isMenuExpanded = this.expanded ? 'true' : 'false'; const isPressed = this.pressed ? 'true' : 'false'; return (h("button", { class: { hidden: this.hidden, notTouch: !this.isTouch, tapHighlight: this.showTapHighlight, }, id: this.identifier, type: "button", "aria-label": this.label, "aria-haspopup": !isUndefined(this.menu) ? 'true' : undefined, "aria-controls": this.menu, "aria-expanded": !isUndefined(this.menu) ? isMenuExpanded : undefined, "aria-pressed": !isUndefined(this.pressed) ? isPressed : undefined, "aria-hidden": this.hidden ? 'true' : 'false', "aria-describedby": this.describedBy, onTouchStart: this.onTouchStart.bind(this), onTouchEnd: this.onTouchEnd.bind(this), onFocus: this.onFocus.bind(this), onBlur: this.onBlur.bind(this), onMouseEnter: this.onMouseEnter.bind(this), onMouseLeave: this.onMouseLeave.bind(this), ref: (el) => { this.button = el; } }, h("slot", null))); } get host() { return getElement(this); } static get watchers() { return { "keys": ["onKeysChange"] }; } }; Control.style = controlCss; /** * INSPIRED BY: https://github.com/shoelace-style/shoelace/blob/next/src/components/icon/request.ts */ 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()); }); }; const iconFiles = new Map(); const requestIcon = (url) => { if (iconFiles.has(url)) return iconFiles.get(url); const request = fetch(url).then((response) => __awaiter$1(void 0, void 0, void 0, function* () { if (response.ok) { const div = document.createElement('div'); div.innerHTML = yield response.text(); const svg = div.firstElementChild; return { ok: response.ok, status: response.status, svg: svg && svg.tagName.toLowerCase() === 'svg' ? svg.outerHTML : '', }; } return { ok: response.ok, status: response.status, }; })); iconFiles.set(url, request); return request; }; const iconCss = ":host{display:inline-block;width:1em;height:1em;contain:strict;box-sizing:content-box !important}.icon,svg{display:block;height:100%;width:100%;transition:var(--vm-icon-transition);transform:var(--vm-icon-transform);fill:var(--vm-icon-fill, currentColor);stroke:var(--vm-icon-stroke)}"; /** * INSPIRED BY: https://github.com/shoelace-style/shoelace/blob/next/src/components/icon/icon.tsx */ 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 parser = new DOMParser(); const Icon = class { constructor(hostRef) { registerInstance(this, hostRef); this.vmLoad = createEvent(this, "vmLoad", 7); this.vmError = createEvent(this, "vmError", 7); /** @internal */ this.icons = 'material'; withComponentRegistry(this); withIconRegistry(this); } handleChange() { this.setIcon(); } connectedCallback() { withPlayerContext(this, ['icons']); } componentDidLoad() { this.setIcon(); } /** * @internal Fetches the icon and redraws it. Used to handle library registrations. */ redraw() { return __awaiter(this, void 0, void 0, function* () { this.setIcon(); }); } getLabel() { let label = ''; if (this.label) { label = this.label; } else if (this.name) { label = this.name.replace(/-/g, ' '); } else if (this.src) { label = this.src .replace(/.*\//, '') .replace(/-/g, ' ') .replace(/\.svg/i, ''); } return label; } setIcon() { var _a; return __awaiter(this, void 0, void 0, function* () { const resolver = getIconLibraryResolver((_a = this.library) !== null && _a !== void 0 ? _a : this.icons); let url = this.src; if (this.name && resolver) { url = resolver(this.name); } if (url) { try { const file = yield requestIcon(url); if (file.ok) { const doc = parser.parseFromString(file.svg, 'text/html'); const svg = doc.body.querySelector('svg'); if (svg) { this.svg = svg.outerHTML; this.vmLoad.emit(); } else { this.svg = ''; this.vmError.emit({ status: file.status }); } } } catch (_b) { this.vmError.emit(); } } }); } render() { return (h("div", { class: "icon", role: "img", "aria-label": this.getLabel(), innerHTML: this.svg })); } static get watchers() { return { "name": ["handleChange"], "src": ["handleChange"], "library": ["handleChange"], "icons": ["handleChange"] }; } }; Icon.style = iconCss; const tooltipCss = ":host{display:contents;z-index:var(--vm-tooltip-z-index)}.tooltip{left:var(--vm-tooltip-left, 50%);transform:translateX(-50%);line-height:1.3;pointer-events:none;position:absolute;opacity:0;white-space:nowrap;visibility:hidden;background:var(--vm-tooltip-bg);border-radius:var(--vm-tooltip-border-radius);box-sizing:border-box;box-shadow:var(--vm-tooltip-box-shadow);color:var(--vm-tooltip-color);font-size:var(--vm-tooltip-font-size);padding:var(--vm-tooltip-padding);transition:opacity var(--vm-tooltip-fade-duration)\n var(--vm-tooltip-fade-timing-func)}.tooltip[aria-hidden='false']{opacity:1;visibility:visible}.tooltip.hidden{display:none}.tooltip.onTop{bottom:100%;margin-bottom:var(--vm-tooltip-spacing)}.tooltip.onBottom{top:100%;margin-top:var(--vm-tooltip-spacing)}.tooltip.growLeft{left:auto;right:0;transform:none}.tooltip.growRight{left:0;transform:none}"; let tooltipIdCount = 0; const Tooltip = class { constructor(hostRef) { registerInstance(this, hostRef); // Avoid tooltips flashing when player initializing. this.hasLoaded = false; /** * Whether the tooltip is displayed or not. */ this.hidden = false; /** * Whether the tooltip is visible or not. */ this.active = false; /** * Determines if the tooltip appears on top/bottom of it's parent. */ this.position = 'top'; /** @internal */ this.isTouch = false; /** @internal */ this.isMobile = false; withComponentRegistry(this); withPlayerContext(this, ['isTouch', 'isMobile']); } componentDidLoad() { this.hasLoaded = true; } getId() { // eslint-disable-next-line prefer-destructuring const id = this.host.id; if (isString(id) && id.length > 0) return id; tooltipIdCount += 1; return `vm-tooltip-${tooltipIdCount}`; } render() { return (h("div", { id: this.getId(), role: "tooltip", "aria-hidden": !this.active || this.isTouch || this.isMobile ? 'true' : 'false', class: { tooltip: true, hidden: !this.hasLoaded || this.hidden, onTop: this.position === 'top', onBottom: this.position === 'bottom', growLeft: this.direction === 'left', growRight: this.direction === 'right', } }, h("slot", null))); } get host() { return getElement(this); } }; Tooltip.style = tooltipCss; export { Control as vm_control, Icon as vm_icon, Tooltip as vm_tooltip };