From 271a8c850216bd1654baaa26f8bb2f5eda56be37 Mon Sep 17 00:00:00 2001 From: Wesley Luyten Date: Tue, 24 Mar 2026 18:19:50 -0500 Subject: [PATCH] feat: add Mux video component (#1036) --- commitlint.config.js | 1 + internal/design/media-api.md | 103 ++++---- package.json | 1 + packages/core/package.json | 5 +- packages/core/src/core/media/delegate.ts | 15 ++ packages/core/src/dom/media/dash/index.ts | 13 +- packages/core/src/dom/media/hls/index.ts | 147 ++++++++++-- packages/core/src/dom/media/mux/env.ts | 11 + packages/core/src/dom/media/mux/index.ts | 224 ++++++++++++++++++ .../src/dom/media/mux/tests/index.test.ts | 76 ++++++ packages/core/src/dom/media/mux/types.ts | 2 + packages/core/src/dom/media/proxy.ts | 2 +- .../core/src/dom/media/simple-hls/index.ts | 11 +- packages/core/tsdown.config.ts | 3 + packages/element/package.json | 2 +- packages/html/package.json | 2 +- packages/html/src/cdn/media/mux-video.ts | 1 + packages/html/src/define/media/mux-video.ts | 14 ++ packages/html/src/media/dash-video/index.ts | 21 +- packages/html/src/media/hls-video/index.ts | 21 +- packages/html/src/media/mux-video/index.ts | 18 ++ .../html/src/media/simple-hls-video/index.ts | 24 +- packages/html/src/utils/media-props-mixin.ts | 61 +++++ packages/html/tsdown.cdn.config.ts | 2 +- packages/icons/package.json | 2 +- packages/react/package.json | 2 +- packages/react/src/media/dash-video/index.tsx | 8 +- packages/react/src/media/hls-video/index.tsx | 8 +- packages/react/src/media/mux-video/index.tsx | 25 ++ .../src/media/simple-hls-video/index.tsx | 3 +- packages/react/src/utils/media-props.ts | 36 ++- packages/sandbox/app/constants.ts | 10 +- packages/sandbox/app/shared/sources.ts | 9 + packages/sandbox/app/shell/app.tsx | 19 +- packages/sandbox/app/shell/navbar.tsx | 17 +- .../templates/html-mux-video/index.html | 14 ++ .../sandbox/templates/html-mux-video/main.ts | 49 ++++ .../templates/react-mux-video/index.html | 14 ++ .../templates/react-mux-video/main.tsx | 45 ++++ packages/skins/package.json | 2 +- packages/spf/package.json | 2 +- packages/store/package.json | 2 +- packages/utils/package.json | 2 +- pnpm-lock.yaml | 72 +++++- turbo.json | 2 +- 45 files changed, 941 insertions(+), 182 deletions(-) create mode 100644 packages/core/src/dom/media/mux/env.ts create mode 100644 packages/core/src/dom/media/mux/index.ts create mode 100644 packages/core/src/dom/media/mux/tests/index.test.ts create mode 100644 packages/core/src/dom/media/mux/types.ts create mode 100644 packages/html/src/cdn/media/mux-video.ts create mode 100644 packages/html/src/define/media/mux-video.ts create mode 100644 packages/html/src/media/mux-video/index.ts create mode 100644 packages/html/src/utils/media-props-mixin.ts create mode 100644 packages/react/src/media/mux-video/index.tsx create mode 100644 packages/sandbox/templates/html-mux-video/index.html create mode 100644 packages/sandbox/templates/html-mux-video/main.ts create mode 100644 packages/sandbox/templates/react-mux-video/index.html create mode 100644 packages/sandbox/templates/react-mux-video/main.tsx diff --git a/commitlint.config.js b/commitlint.config.js index 85b5ba75..c2f85b9f 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -13,6 +13,7 @@ export default { 2, 'always', [ + 'build', 'cd', 'ci', 'claude', diff --git a/internal/design/media-api.md b/internal/design/media-api.md index ac14a2bc..3bb9b929 100644 --- a/internal/design/media-api.md +++ b/internal/design/media-api.md @@ -158,66 +158,69 @@ interface MediaApi extends MediaBaseApi, // ... } -export interface MediaApiProxyTarget extends EventTarget {} - -// Proxy mixin that creates a MediaApi from the passed classes and proxies the methods and properties to the attached target. -export const MediaProxyMixin = ( - ...MediaApiTargetClasses: AnyConstructor[] -) => class MediaApiProxy { - // Logic that proxies media API to the media target - // ... - - // Attach media target to the media instance - target: MediaApiProxyTarget; - attach(target: MediaApiProxyTarget): void; - detach(): void; - - // Proxy handlers - get(prop: keyof MediaApiProxyTarget): any; - set(prop: keyof MediaApiProxyTarget, val: any): void; - call(prop: keyof MediaApiProxyTarget, ...args: any[]): any; +export interface Delegate { + attach?(target: EventTarget): void; + detach?(): void; } -// Size optimized for the most common use case of proxying HTMLMediaElement. -export class MediaApiProxy extends MediaProxyMixin(HTMLMediaElement, EventTarget) {} -export class VideoApiProxy extends MediaProxyMixin(HTMLVideoElement, HTMLMediaElement, EventTarget) {} -export class AudioApiProxy extends MediaProxyMixin(HTMLAudioElement, HTMLMediaElement, EventTarget) {} +// DelegateMixin intercepts get/set/call to route through a Delegate before falling through to the base class. +export function DelegateMixin>( + BaseClass: Base, + DelegateClass: D +): Constructor & InstanceType>; + + +// ProxyMixin creates a class that proxies methods and properties to the attached target. +export const ProxyMixin = ( + PrimaryClass: AnyConstructor, + ...AdditionalClasses: AnyConstructor[] +) => class MediaProxy { + target: EventTarget | null; + attach(target: EventTarget): void; + detach(): void; + + get(prop: keyof EventTarget): any; + set(prop: keyof EventTarget, val: any): void; + call(prop: keyof EventTarget, ...args: any[]): any; +} + +// Pre-built proxy for video elements. +export const VideoProxy = ProxyMixin(HTMLVideoElement, HTMLMediaElement, EventTarget); + +// CustomVideoElement wraps a native