mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add Mux video component (#1036)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
import '../../define/media/mux-video';
|
||||
@@ -0,0 +1,14 @@
|
||||
import { MuxVideo } from '../../media/mux-video';
|
||||
import { safeDefine } from '../safe-define';
|
||||
|
||||
export class MuxVideoElement extends MuxVideo {
|
||||
static readonly tagName = 'mux-video';
|
||||
}
|
||||
|
||||
safeDefine(MuxVideoElement);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
[MuxVideoElement.tagName]: MuxVideoElement;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,13 @@
|
||||
import { DashCustomMedia } from '@videojs/core/dom/media/dash';
|
||||
import { DashCustomMedia, DashMediaDelegate } from '@videojs/core/dom/media/dash';
|
||||
import { MediaAttachMixin } from '../../store/media-attach-mixin';
|
||||
import { MediaPropsMixin } from '../../utils/media-props-mixin';
|
||||
|
||||
export class DashVideo extends MediaAttachMixin(DashCustomMedia) {
|
||||
static getTemplateHTML(attrs: Record<string, string>): string {
|
||||
const { src, ...rest } = attrs;
|
||||
// biome-ignore lint/complexity/noThisInStatic: intentional use of super
|
||||
return super.getTemplateHTML(rest);
|
||||
}
|
||||
|
||||
export class DashVideo extends MediaPropsMixin(MediaAttachMixin(DashCustomMedia), DashMediaDelegate) {
|
||||
constructor() {
|
||||
super();
|
||||
this.attach(this.target);
|
||||
}
|
||||
|
||||
attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void {
|
||||
if (attrName !== 'src') {
|
||||
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||
}
|
||||
|
||||
if (attrName === 'src' && oldValue !== newValue) {
|
||||
this.src = newValue ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback?.();
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { HlsCustomMedia } from '@videojs/core/dom/media/hls';
|
||||
import { HlsCustomMedia, HlsMediaDelegate } from '@videojs/core/dom/media/hls';
|
||||
import { MediaAttachMixin } from '../../store/media-attach-mixin';
|
||||
import { MediaPropsMixin } from '../../utils/media-props-mixin';
|
||||
|
||||
export class HlsVideo extends MediaAttachMixin(HlsCustomMedia) {
|
||||
static getTemplateHTML(attrs: Record<string, string>): string {
|
||||
const { src, ...rest } = attrs;
|
||||
// biome-ignore lint/complexity/noThisInStatic: intentional use of super
|
||||
return super.getTemplateHTML(rest);
|
||||
}
|
||||
|
||||
export class HlsVideo extends MediaPropsMixin(MediaAttachMixin(HlsCustomMedia), HlsMediaDelegate) {
|
||||
constructor() {
|
||||
super();
|
||||
// TODO: If we like to support native media elements that
|
||||
@@ -17,16 +12,6 @@ export class HlsVideo extends MediaAttachMixin(HlsCustomMedia) {
|
||||
this.attach(this.target);
|
||||
}
|
||||
|
||||
attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void {
|
||||
if (attrName !== 'src') {
|
||||
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||
}
|
||||
|
||||
if (attrName === 'src' && oldValue !== newValue) {
|
||||
this.src = newValue ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback?.();
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { MuxCustomVideo, MuxMediaDelegate } from '@videojs/core/dom/media/mux';
|
||||
import { MediaAttachMixin } from '../../store/media-attach-mixin';
|
||||
import { MediaPropsMixin } from '../../utils/media-props-mixin';
|
||||
|
||||
export class MuxVideo extends MediaPropsMixin(MediaAttachMixin(MuxCustomVideo), MuxMediaDelegate) {
|
||||
constructor() {
|
||||
super();
|
||||
this.attach(this.target);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback?.();
|
||||
|
||||
if (!this.hasAttribute('keep-alive')) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,11 @@
|
||||
import { SimpleHlsCustomMedia } from '@videojs/core/dom/media/simple-hls';
|
||||
import { SpfMedia } from '@videojs/spf/dom';
|
||||
import { MediaAttachMixin } from '../../store/media-attach-mixin';
|
||||
import { MediaPropsMixin } from '../../utils/media-props-mixin';
|
||||
|
||||
export class SimpleHlsVideo extends MediaAttachMixin(SimpleHlsCustomMedia) {
|
||||
static getTemplateHTML(attrs: Record<string, string>): string {
|
||||
const { src, ...rest } = attrs;
|
||||
// biome-ignore lint/complexity/noThisInStatic: intentional use of super
|
||||
return super.getTemplateHTML(rest);
|
||||
}
|
||||
|
||||
export class SimpleHlsVideo extends MediaPropsMixin(MediaAttachMixin(SimpleHlsCustomMedia), SpfMedia) {
|
||||
constructor() {
|
||||
super();
|
||||
this.attach(this.target);
|
||||
}
|
||||
|
||||
attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void {
|
||||
if (attrName !== 'src') {
|
||||
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||
}
|
||||
|
||||
if (attrName === 'src' && oldValue !== newValue) {
|
||||
this.src = newValue ?? '';
|
||||
}
|
||||
|
||||
if (attrName === 'preload' && oldValue !== newValue) {
|
||||
this.preload = (newValue ?? '') as '' | 'none' | 'metadata' | 'auto';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import type { AnyConstructor } from '@videojs/utils/types';
|
||||
|
||||
type AnyClass = abstract new (...args: any[]) => any;
|
||||
|
||||
function camelToKebab(str: string): string {
|
||||
return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
||||
}
|
||||
|
||||
function buildAttrPropMap(DelegateClass: AnyClass): Map<string, string> {
|
||||
const map = new Map<string, string>();
|
||||
for (let proto = DelegateClass.prototype; proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
||||
for (const key of Object.getOwnPropertyNames(proto)) {
|
||||
const desc = Object.getOwnPropertyDescriptor(proto, key);
|
||||
if (desc?.set) map.set(camelToKebab(key), key);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin that intercepts `getTemplateHTML` and `attributeChangedCallback` to
|
||||
* handle delegate-owned properties. Delegate props are stripped from template
|
||||
* HTML attrs and routed through the property setter in `attributeChangedCallback`
|
||||
* instead of being forwarded to the inner native element.
|
||||
*/
|
||||
export function MediaPropsMixin<Base extends AnyConstructor<HTMLElement>>(
|
||||
BaseClass: Base,
|
||||
DelegateClass: AnyClass
|
||||
): Base {
|
||||
const attrToProp = buildAttrPropMap(DelegateClass);
|
||||
|
||||
class MediaPropsElement extends (BaseClass as any) {
|
||||
static get observedAttributes(): string[] {
|
||||
// biome-ignore lint/complexity/noThisInStatic: intentional use of super
|
||||
return [...new Set([...(super.observedAttributes ?? []), ...attrToProp.keys()])];
|
||||
}
|
||||
|
||||
static getTemplateHTML(attrs: Record<string, string>): string {
|
||||
const filtered = { ...attrs };
|
||||
for (const attr of attrToProp.keys()) {
|
||||
delete filtered[attr];
|
||||
}
|
||||
// biome-ignore lint/complexity/noThisInStatic: intentional use of super
|
||||
return super.getTemplateHTML(filtered);
|
||||
}
|
||||
|
||||
attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string | null): void {
|
||||
const prop = attrToProp.get(attrName);
|
||||
if (prop) {
|
||||
if (oldValue !== newValue) {
|
||||
(this as any)[prop] = typeof (this as any)[prop] === 'boolean' ? newValue !== null : (newValue ?? '');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
super.attributeChangedCallback?.(attrName, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
return MediaPropsElement as unknown as Base;
|
||||
}
|
||||
Reference in New Issue
Block a user