feat(html): add element registrations

This commit is contained in:
Rahim
2025-10-30 04:51:51 +00:00
parent 9e4af60361
commit eaaa03c284
54 changed files with 374 additions and 409 deletions
+12
View File
@@ -0,0 +1,12 @@
import './media-container';
import './media-provider';
import './media-play-button';
import './media-mute-button';
import './media-volume-slider';
import './media-time-slider';
import './media-fullscreen-button';
import './media-duration-display';
import './media-current-time-display';
import './media-preview-time-display';
import './media-popover';
import './media-tooltip';
@@ -0,0 +1,4 @@
import { MediaContainerElement } from '@/media/media-container';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-container', MediaContainerElement);
@@ -0,0 +1,4 @@
import { CurrentTimeDisplayElement } from '@/elements/current-time-display';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-current-time-display', CurrentTimeDisplayElement);
@@ -0,0 +1,4 @@
import { DurationDisplayElement } from '@/elements/duration-display';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-duration-display', DurationDisplayElement);
@@ -0,0 +1,4 @@
import { FullscreenButtonElement } from '@/elements/fullscreen-button';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-fullscreen-button', FullscreenButtonElement);
@@ -0,0 +1,4 @@
import { MuteButtonElement } from '@/elements/mute-button';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-mute-button', MuteButtonElement);
@@ -0,0 +1,4 @@
import { PlayButtonElement } from '@/elements/play-button';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-play-button', PlayButtonElement);
@@ -0,0 +1,4 @@
import { PopoverElement } from '@/elements/popover';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-popover', PopoverElement);
@@ -0,0 +1,4 @@
import { PreviewTimeDisplayElement } from '@/elements/preview-time-display';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-preview-time-display', PreviewTimeDisplayElement);
@@ -0,0 +1,4 @@
import { MediaProviderElement } from '@/media/media-provider';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-provider', MediaProviderElement);
@@ -0,0 +1,8 @@
import { TimeSliderPointerElement, TimeSliderProgressElement, TimeSliderRootElement, TimeSliderThumbElement, TimeSliderTrackElement } from '@/elements/time-slider';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-time-slider', TimeSliderRootElement);
defineCustomElement('media-time-slider-track', TimeSliderTrackElement);
defineCustomElement('media-time-slider-progress', TimeSliderProgressElement);
defineCustomElement('media-time-slider-pointer', TimeSliderPointerElement);
defineCustomElement('media-time-slider-thumb', TimeSliderThumbElement);
+10
View File
@@ -0,0 +1,10 @@
import { TooltipArrowElement, TooltipPopupElement, TooltipPortalElement, TooltipPositionerElement, TooltipRootElement, TooltipTriggerElement } from '@/elements/tooltip';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-tooltip', TooltipRootElement);
defineCustomElement('media-tooltip-trigger', TooltipTriggerElement);
defineCustomElement('media-tooltip-portal', TooltipPortalElement);
defineCustomElement('media-tooltip-positioner', TooltipPositionerElement);
defineCustomElement('media-tooltip-portal', TooltipPortalElement);
defineCustomElement('media-tooltip-popup', TooltipPopupElement);
defineCustomElement('media-tooltip-arrow', TooltipArrowElement);
@@ -0,0 +1,7 @@
import { VolumeSliderIndicatorElement, VolumeSliderRootElement, VolumeSliderThumbElement, VolumeSliderTrackElement } from '@/elements/volume-slider';
import { defineCustomElement } from '@/utils/custom-element';
defineCustomElement('media-volume-slider', VolumeSliderRootElement);
defineCustomElement('media-volume-slider-track', VolumeSliderTrackElement);
defineCustomElement('media-volume-slider-indicator', VolumeSliderIndicatorElement);
defineCustomElement('media-volume-slider-thumb', VolumeSliderThumbElement);
@@ -1,7 +1,7 @@
import { namedNodeMapToObject } from '@videojs/utils/dom';
export function getTemplateHTML(
this: typeof MediaChromeButton,
this: typeof ButtonElement,
_attrs: Record<string, string>,
_props: Record<string, any> = {},
): string {
@@ -20,7 +20,7 @@ export function getTemplateHTML(
`;
}
export class MediaChromeButton extends HTMLElement {
export class ButtonElement extends HTMLElement {
static shadowRootOptions = {
mode: 'open' as ShadowRootMode,
};
@@ -32,10 +32,10 @@ export class MediaChromeButton extends HTMLElement {
if (!this.shadowRoot) {
// Set up the Shadow DOM if not using Declarative Shadow DOM.
this.attachShadow((this.constructor as typeof MediaChromeButton).shadowRootOptions);
this.attachShadow((this.constructor as typeof ButtonElement).shadowRootOptions);
const attrs = namedNodeMapToObject(this.attributes);
const html = (this.constructor as typeof MediaChromeButton).getTemplateHTML(attrs);
const html = (this.constructor as typeof ButtonElement).getTemplateHTML(attrs);
// From MDN: setHTMLUnsafe should be used instead of ShadowRoot.innerHTML
// when a string of HTML may contain declarative shadow roots.
const shadowRoot = this.shadowRoot as unknown as ShadowRoot;
@@ -6,7 +6,7 @@ import { currentTimeDisplayStateDefinition } from '@videojs/core/store';
import { formatDisplayTime } from '@videojs/utils';
import { toConnectedHTMLComponent } from '../utils/component-factory';
export class CurrentTimeDisplayBase extends HTMLElement {
export class CurrentTimeDisplay extends HTMLElement {
static shadowRootOptions = {
mode: 'open' as ShadowRootMode,
};
@@ -24,7 +24,7 @@ export class CurrentTimeDisplayBase extends HTMLElement {
super();
if (!this.shadowRoot) {
this.attachShadow((this.constructor as typeof CurrentTimeDisplayBase).shadowRootOptions);
this.attachShadow((this.constructor as typeof CurrentTimeDisplay).shadowRootOptions);
}
}
@@ -81,16 +81,9 @@ export const getCurrentTimeDisplayProps: PropsHook<{
return baseProps;
};
export const CurrentTimeDisplay: ConnectedComponentConstructor<CurrentTimeDisplayState> = toConnectedHTMLComponent(
CurrentTimeDisplayBase,
export const CurrentTimeDisplayElement: ConnectedComponentConstructor<CurrentTimeDisplayState> = toConnectedHTMLComponent(
CurrentTimeDisplay,
useCurrentTimeDisplayState,
getCurrentTimeDisplayProps,
'CurrentTimeDisplay',
);
// Register the custom element
if (!globalThis.customElements.get('media-current-time-display')) {
globalThis.customElements.define('media-current-time-display', CurrentTimeDisplay);
}
export default CurrentTimeDisplay;
@@ -8,7 +8,7 @@ import { namedNodeMapToObject } from '@videojs/utils/dom';
import { toConnectedHTMLComponent } from '../utils/component-factory';
export function getTemplateHTML(
this: typeof DurationDisplayBase,
this: typeof DurationDisplay,
_attrs: Record<string, string>,
_props: Record<string, any> = {},
) {
@@ -17,7 +17,7 @@ export function getTemplateHTML(
`;
}
export class DurationDisplayBase extends HTMLElement {
export class DurationDisplay extends HTMLElement {
static shadowRootOptions = {
mode: 'open' as ShadowRootMode,
};
@@ -34,10 +34,10 @@ export class DurationDisplayBase extends HTMLElement {
super();
if (!this.shadowRoot) {
this.attachShadow((this.constructor as typeof DurationDisplayBase).shadowRootOptions);
this.attachShadow((this.constructor as typeof DurationDisplay).shadowRootOptions);
const attrs = namedNodeMapToObject(this.attributes);
const html = (this.constructor as typeof DurationDisplayBase).getTemplateHTML(attrs);
const html = (this.constructor as typeof DurationDisplay).getTemplateHTML(attrs);
const shadowRoot = this.shadowRoot as unknown as ShadowRoot;
shadowRoot.setHTMLUnsafe ? shadowRoot.setHTMLUnsafe(html) : (shadowRoot.innerHTML = html);
}
@@ -75,16 +75,9 @@ export const getDurationDisplayProps: PropsHook<{
return baseProps;
};
export const DurationDisplay: ConnectedComponentConstructor<DurationDisplayState> = toConnectedHTMLComponent(
DurationDisplayBase,
export const DurationDisplayElement: ConnectedComponentConstructor<DurationDisplayState> = toConnectedHTMLComponent(
DurationDisplay,
useDurationDisplayState,
getDurationDisplayProps,
'DurationDisplay',
);
// Register the custom element
if (!globalThis.customElements.get('media-duration-display')) {
globalThis.customElements.define('media-duration-display', DurationDisplay);
}
export default DurationDisplay;
@@ -5,9 +5,9 @@ import { fullscreenButtonStateDefinition } from '@videojs/core/store';
import { setAttributes } from '@videojs/utils/dom';
import { toConnectedHTMLComponent } from '../utils/component-factory';
import { MediaChromeButton } from './media-chrome-button';
import { ButtonElement } from './button';
export class FullscreenButtonBase extends MediaChromeButton {
export class FullscreenButton extends ButtonElement {
_state:
| {
fullscreen: boolean;
@@ -72,16 +72,9 @@ export const getFullscreenButtonProps: PropsHook<{ fullscreen: boolean }> = (sta
return baseProps;
};
export const FullscreenButton: ConnectedComponentConstructor<FullscreenButtonState> = toConnectedHTMLComponent(
FullscreenButtonBase,
export const FullscreenButtonElement: ConnectedComponentConstructor<FullscreenButtonState> = toConnectedHTMLComponent(
FullscreenButton,
getFullscreenButtonState,
getFullscreenButtonProps,
'FullscreenButton',
);
// NOTE: In this architecture it will be important to decouple component class definitions from their registration in the CustomElementsRegistry. (CJP)
if (!globalThis.customElements.get('media-fullscreen-button')) {
globalThis.customElements.define('media-fullscreen-button', FullscreenButton);
}
export default FullscreenButton;
@@ -5,9 +5,9 @@ import { muteButtonStateDefinition } from '@videojs/core/store';
import { setAttributes } from '@videojs/utils/dom';
import { toConnectedHTMLComponent } from '../utils/component-factory';
import { MediaChromeButton } from './media-chrome-button';
import { ButtonElement } from './button';
export class MuteButtonBase extends MediaChromeButton {
export class MuteButton extends ButtonElement {
_state:
| {
muted: boolean;
@@ -83,16 +83,9 @@ export const getMuteButtonProps: PropsHook<{
return baseProps;
};
export const MuteButton: ConnectedComponentConstructor<MuteButtonState> = toConnectedHTMLComponent(
MuteButtonBase,
export const MuteButtonElement: ConnectedComponentConstructor<MuteButtonState> = toConnectedHTMLComponent(
MuteButton,
getMuteButtonState,
getMuteButtonProps,
'MuteButton',
);
// NOTE: In this architecture it will be important to decouple component class definitions from their registration in the CustomElementsRegistry. (CJP)
if (!globalThis.customElements.get('media-mute-button')) {
globalThis.customElements.define('media-mute-button', MuteButton);
}
export default MuteButton;
@@ -5,9 +5,9 @@ import { playButtonStateDefinition } from '@videojs/core/store';
import { setAttributes } from '@videojs/utils/dom';
import { toConnectedHTMLComponent } from '../utils/component-factory';
import { MediaChromeButton } from './media-chrome-button';
import { ButtonElement } from './button';
export class PlayButtonBase extends MediaChromeButton {
export class PlayButton extends ButtonElement {
_state: { paused: boolean; requestPlay: () => void; requestPause: () => void } | undefined;
handleEvent(event: Event): void {
@@ -62,16 +62,9 @@ export const getPlayButtonProps: PropsHook<{ paused: boolean }> = (state, _eleme
return baseProps;
};
export const PlayButton: ConnectedComponentConstructor<PlayButtonState> = toConnectedHTMLComponent(
PlayButtonBase,
export const PlayButtonElement: ConnectedComponentConstructor<PlayButtonState> = toConnectedHTMLComponent(
PlayButton,
getPlayButtonState,
getPlayButtonProps,
'PlayButton',
);
// NOTE: In this architecture it will be important to decouple component class definitions from their registration in the CustomElementsRegistry. (CJP)
if (!globalThis.customElements.get('media-play-button')) {
globalThis.customElements.define('media-play-button', PlayButton);
}
export default PlayButton;
@@ -14,7 +14,7 @@ type FloatingContext = Prettify<ComputePositionReturn> & {
};
};
class Popover extends HTMLElement {
export class PopoverElement extends HTMLElement {
#open = false;
#transitionStatus: 'initial' | 'open' | 'close' | 'unmounted' = 'initial';
#hoverTimeout: ReturnType<typeof setTimeout> | null = null;
@@ -236,11 +236,3 @@ class Popover extends HTMLElement {
this.#setOpen(false);
};
}
if (!globalThis.customElements.get('media-popover')) {
globalThis.customElements.define('media-popover', Popover);
}
export { Popover };
export default Popover;
@@ -6,7 +6,7 @@ import { previewTimeDisplayStateDefinition } from '@videojs/core/store';
import { formatDisplayTime } from '@videojs/utils';
import { toConnectedHTMLComponent } from '../utils/component-factory';
export class PreviewTimeDisplayBase extends HTMLElement {
export class PreviewTimeDisplay extends HTMLElement {
static shadowRootOptions = {
mode: 'open' as ShadowRootMode,
};
@@ -23,7 +23,7 @@ export class PreviewTimeDisplayBase extends HTMLElement {
super();
if (!this.shadowRoot) {
this.attachShadow((this.constructor as typeof PreviewTimeDisplayBase).shadowRootOptions);
this.attachShadow((this.constructor as typeof PreviewTimeDisplay).shadowRootOptions);
}
}
@@ -71,16 +71,9 @@ export const getPreviewTimeDisplayProps: PropsHook<{
return baseProps;
};
export const PreviewTimeDisplay: ConnectedComponentConstructor<PreviewTimeDisplayState> = toConnectedHTMLComponent(
PreviewTimeDisplayBase,
export const PreviewTimeDisplayElement: ConnectedComponentConstructor<PreviewTimeDisplayState> = toConnectedHTMLComponent(
PreviewTimeDisplay,
usePreviewTimeDisplayState,
getPreviewTimeDisplayProps,
'PreviewTimeDisplay',
);
// Register the custom element
if (!globalThis.customElements.get('preview-time-display')) {
globalThis.customElements.define('preview-time-display', PreviewTimeDisplay);
}
export default PreviewTimeDisplay;
@@ -49,7 +49,7 @@ export const getTimeSliderRootProps: PropsHook<{
return baseProps;
};
export class TimeSliderRootBase extends HTMLElement {
export class TimeSliderRoot extends HTMLElement {
static readonly observedAttributes: readonly string[] = ['orientation'];
_state: TimeSliderRootState | undefined;
@@ -97,14 +97,14 @@ export class TimeSliderRootBase extends HTMLElement {
}
}
export class TimeSliderTrackBase extends HTMLElement {
export class TimeSliderTrack extends HTMLElement {
constructor() {
super();
}
connectedCallback(): void {
// Set this element as the track element in the core TimeSlider
const rootElement = this.closest('media-time-slider-root') as any;
const rootElement = this.closest('media-time-slider') as any;
if (rootElement?._state?.core) {
rootElement._state.core.setState({ _trackElement: this });
}
@@ -123,7 +123,7 @@ export class TimeSliderTrackBase extends HTMLElement {
}
}
export class TimeSliderProgressBase extends HTMLElement {
export class TimeSliderProgress extends HTMLElement {
constructor() {
super();
this.style.position = 'absolute';
@@ -148,7 +148,7 @@ export class TimeSliderProgressBase extends HTMLElement {
}
}
export class TimeSliderPointerBase extends HTMLElement {
export class TimeSliderPointer extends HTMLElement {
constructor() {
super();
this.style.position = 'absolute';
@@ -173,7 +173,7 @@ export class TimeSliderPointerBase extends HTMLElement {
}
}
export class TimeSliderThumbBase extends HTMLElement {
export class TimeSliderThumb extends HTMLElement {
constructor() {
super();
this.style.position = 'absolute';
@@ -210,103 +210,81 @@ export const useTimeSliderRootState: StateHook<{
};
export const getTimeSliderTrackProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-time-slider-root') as any;
const rootElement = element.closest('media-time-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
};
export const getTimeSliderProgressProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-time-slider-root') as any;
const rootElement = element.closest('media-time-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
};
export const getTimeSliderPointerProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-time-slider-root') as any;
const rootElement = element.closest('media-time-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
};
export const getTimeSliderThumbProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-time-slider-root') as any;
const rootElement = element.closest('media-time-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
};
export const TimeSliderRoot: ConnectedComponentConstructor<{
export const TimeSliderRootElement: ConnectedComponentConstructor<{
currentTime: number;
duration: number;
requestSeek: (time: number) => void;
core: CoreTimeSlider | null;
}> = toConnectedHTMLComponent(TimeSliderRootBase, useTimeSliderRootState, getTimeSliderRootProps, 'TimeSliderRoot');
}> = toConnectedHTMLComponent(TimeSliderRoot, useTimeSliderRootState, getTimeSliderRootProps, 'TimeSliderRoot');
export const TimeSliderTrack: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderTrackBase,
export const TimeSliderTrackElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderTrack,
{ keys: [], transform: () => ({}) },
getTimeSliderTrackProps,
'TimeSliderTrack',
);
export const TimeSliderProgress: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderProgressBase,
export const TimeSliderProgressElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderProgress,
{ keys: [], transform: () => ({}) },
getTimeSliderProgressProps,
'TimeSliderProgress',
);
export const TimeSliderPointer: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderPointerBase,
export const TimeSliderPointerElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderPointer,
{ keys: [], transform: () => ({}) },
getTimeSliderPointerProps,
'TimeSliderPointer',
);
export const TimeSliderThumb: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderThumbBase,
export const TimeSliderThumbElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
TimeSliderThumb,
{ keys: [], transform: () => ({}) },
getTimeSliderThumbProps,
'TimeSliderThumb',
);
export const TimeSlider = Object.assign(
export const TimeSliderElement = Object.assign(
{},
{
Root: TimeSliderRoot,
Track: TimeSliderTrack,
Progress: TimeSliderProgress,
Pointer: TimeSliderPointer,
Thumb: TimeSliderThumb,
Root: TimeSliderRootElement,
Track: TimeSliderTrackElement,
Progress: TimeSliderProgressElement,
Pointer: TimeSliderPointerElement,
Thumb: TimeSliderThumbElement,
},
) as {
Root: typeof TimeSliderRoot;
Track: typeof TimeSliderTrack;
Progress: typeof TimeSliderProgress;
Pointer: typeof TimeSliderPointer;
Thumb: typeof TimeSliderThumb;
Root: typeof TimeSliderRootElement;
Track: typeof TimeSliderTrackElement;
Progress: typeof TimeSliderProgressElement;
Pointer: typeof TimeSliderPointerElement;
Thumb: typeof TimeSliderThumbElement;
};
if (!globalThis.customElements.get('media-time-slider-root')) {
globalThis.customElements.define('media-time-slider-root', TimeSliderRoot);
}
if (!globalThis.customElements.get('media-time-slider-track')) {
globalThis.customElements.define('media-time-slider-track', TimeSliderTrack);
}
if (!globalThis.customElements.get('media-time-slider-progress')) {
globalThis.customElements.define('media-time-slider-progress', TimeSliderProgress);
}
if (!globalThis.customElements.get('media-time-slider-pointer')) {
globalThis.customElements.define('media-time-slider-pointer', TimeSliderPointer);
}
if (!globalThis.customElements.get('media-time-slider-thumb')) {
globalThis.customElements.define('media-time-slider-thumb', TimeSliderThumb);
}
export default TimeSlider;
@@ -1,10 +1,10 @@
import type { Placement } from '@floating-ui/dom';
import type { MediaContainer } from '@/media/media-container';
import type { MediaContainerElement } from '@/media/media-container';
import { arrow, autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom';
import { uniqueId } from '@videojs/utils';
export class MediaTooltipRoot extends HTMLElement {
export class TooltipRootElement extends HTMLElement {
#open = false;
#hoverTimeout: ReturnType<typeof setTimeout> | null = null;
#cleanup: (() => void) | null = null;
@@ -61,20 +61,20 @@ export class MediaTooltipRoot extends HTMLElement {
return value === 'x' || value === 'y' || value === 'both' ? value : undefined;
}
get #triggerElement(): MediaTooltipTrigger | null {
return this.querySelector('media-tooltip-trigger') as MediaTooltipTrigger | null;
get #triggerElement(): TooltipTriggerElement | null {
return this.querySelector('media-tooltip-trigger') as TooltipTriggerElement | null;
}
get #portalElement(): MediaTooltipPortal | null {
return this.querySelector('media-tooltip-portal') as MediaTooltipPortal | null;
get #portalElement(): TooltipPortalElement | null {
return this.querySelector('media-tooltip-portal') as TooltipPortalElement | null;
}
get #positionerElement(): MediaTooltipPositioner | null {
return this.#portalElement?.querySelector('media-tooltip-positioner') as MediaTooltipPositioner | null;
get #positionerElement(): TooltipPositionerElement | null {
return this.#portalElement?.querySelector('media-tooltip-positioner') as TooltipPositionerElement | null;
}
get #popupElement(): MediaTooltipPopup | null {
return this.#portalElement?.querySelector('media-tooltip-popup') as MediaTooltipPopup | null;
get #popupElement(): TooltipPopupElement | null {
return this.#portalElement?.querySelector('media-tooltip-popup') as TooltipPopupElement | null;
}
#setOpen(open: boolean): void {
@@ -132,7 +132,7 @@ export class MediaTooltipRoot extends HTMLElement {
const placement = this.#positionerElement?.side ?? 'top';
const sideOffset = this.#positionerElement?.sideOffset ?? 0;
const collisionPadding = this.#positionerElement?.collisionPadding ?? 0;
const mediaContainer = this.closest('media-container') as MediaContainer;
const mediaContainer = this.closest('media-container') as MediaContainerElement;
this.#arrowElement = popup.querySelector('media-tooltip-arrow') as HTMLElement;
@@ -260,7 +260,7 @@ export class MediaTooltipRoot extends HTMLElement {
}
}
export class MediaTooltipTrigger extends HTMLElement {
export class TooltipTriggerElement extends HTMLElement {
connectedCallback(): void {
this.style.display = 'contents';
@@ -269,16 +269,16 @@ export class MediaTooltipTrigger extends HTMLElement {
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
const rootElement = this.closest('media-tooltip-root') as MediaTooltipRoot;
let popupElement = rootElement.querySelector('media-tooltip-popup') as MediaTooltipPopup;
const rootElement = this.closest('media-tooltip') as TooltipRootElement;
let popupElement = rootElement.querySelector('media-tooltip-popup') as TooltipPopupElement;
if (!popupElement) {
const portalElement = rootElement.querySelector('media-tooltip-portal') as MediaTooltipPortal;
const portalElement = rootElement.querySelector('media-tooltip-portal') as TooltipPortalElement;
if (!portalElement) {
return;
}
popupElement = portalElement.querySelector('media-tooltip-popup') as MediaTooltipPopup;
popupElement = portalElement.querySelector('media-tooltip-popup') as TooltipPopupElement;
if (!popupElement) {
return;
}
@@ -306,7 +306,7 @@ export class MediaTooltipTrigger extends HTMLElement {
}
}
export class MediaTooltipPortal extends HTMLElement {
export class TooltipPortalElement extends HTMLElement {
#portal: HTMLElement | null = null;
connectedCallback(): void {
@@ -356,7 +356,7 @@ export class MediaTooltipPortal extends HTMLElement {
}
}
export class MediaTooltipPositioner extends HTMLElement {
export class TooltipPositionerElement extends HTMLElement {
connectedCallback(): void {
this.style.display = 'contents';
@@ -383,56 +383,30 @@ export class MediaTooltipPositioner extends HTMLElement {
}
}
export class MediaTooltipPopup extends HTMLElement {
export class TooltipPopupElement extends HTMLElement {
connectedCallback(): void {
this.setAttribute('role', 'tooltip');
}
}
export class MediaTooltipArrow extends HTMLElement {
export class TooltipArrowElement extends HTMLElement {
connectedCallback(): void {
this.setAttribute('aria-hidden', 'true');
}
}
if (!globalThis.customElements.get('media-tooltip-root')) {
globalThis.customElements.define('media-tooltip-root', MediaTooltipRoot);
}
if (!globalThis.customElements.get('media-tooltip-trigger')) {
globalThis.customElements.define('media-tooltip-trigger', MediaTooltipTrigger);
}
if (!globalThis.customElements.get('media-tooltip-portal')) {
globalThis.customElements.define('media-tooltip-portal', MediaTooltipPortal);
}
if (!globalThis.customElements.get('media-tooltip-positioner')) {
globalThis.customElements.define('media-tooltip-positioner', MediaTooltipPositioner);
}
if (!globalThis.customElements.get('media-tooltip-popup')) {
globalThis.customElements.define('media-tooltip-popup', MediaTooltipPopup);
}
if (!globalThis.customElements.get('media-tooltip-arrow')) {
globalThis.customElements.define('media-tooltip-arrow', MediaTooltipArrow);
}
export const Tooltip: {
Root: typeof MediaTooltipRoot;
Trigger: typeof MediaTooltipTrigger;
Portal: typeof MediaTooltipPortal;
Positioner: typeof MediaTooltipPositioner;
Popup: typeof MediaTooltipPopup;
Arrow: typeof MediaTooltipArrow;
export const TooltipElement: {
Root: typeof TooltipRootElement;
Trigger: typeof TooltipTriggerElement;
Portal: typeof TooltipPortalElement;
Positioner: typeof TooltipPositionerElement;
Popup: typeof TooltipPopupElement;
Arrow: typeof TooltipArrowElement;
} = {
Root: MediaTooltipRoot,
Trigger: MediaTooltipTrigger,
Portal: MediaTooltipPortal,
Positioner: MediaTooltipPositioner,
Popup: MediaTooltipPopup,
Arrow: MediaTooltipArrow,
Root: TooltipRootElement,
Trigger: TooltipTriggerElement,
Portal: TooltipPortalElement,
Positioner: TooltipPositionerElement,
Popup: TooltipPopupElement,
Arrow: TooltipArrowElement,
};
export default Tooltip;
@@ -46,7 +46,7 @@ interface VolumeSliderRootState {
core: CoreVolumeSlider | null;
}
export class VolumeSliderRootBase extends HTMLElement {
export class VolumeSliderRoot extends HTMLElement {
static readonly observedAttributes: readonly string[] = ['orientation'];
_state: VolumeSliderRootState | undefined;
@@ -103,14 +103,14 @@ export class VolumeSliderRootBase extends HTMLElement {
/**
* VolumeSlider Track component - Track element that captures pointer events
*/
export class VolumeSliderTrackBase extends HTMLElement {
export class VolumeSliderTrack extends HTMLElement {
constructor() {
super();
}
connectedCallback(): void {
// Set this element as the track element in the core VolumeSlider
const rootElement = this.closest('media-volume-slider-root') as any;
const rootElement = this.closest('media-volume-slider') as any;
if (rootElement?._state?.core) {
rootElement._state.core.setState({ _trackElement: this });
}
@@ -132,7 +132,7 @@ export class VolumeSliderTrackBase extends HTMLElement {
/**
* VolumeSlider Progress component - Shows current progress
*/
export class VolumeSliderProgressBase extends HTMLElement {
export class VolumeSliderIndicatorElement extends HTMLElement {
constructor() {
super();
this.style.position = 'absolute';
@@ -160,7 +160,7 @@ export class VolumeSliderProgressBase extends HTMLElement {
/**
* VolumeSlider Thumb component - Draggable thumb element
*/
export class VolumeSliderThumbBase extends HTMLElement {
export class VolumeSliderThumb extends HTMLElement {
constructor() {
super();
this.style.position = 'absolute';
@@ -205,7 +205,7 @@ export const useVolumeSliderRootState: StateHook<{
* VolumeSlider Track props hook
*/
export const getVolumeSliderTrackProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-volume-slider-root') as any;
const rootElement = element.closest('media-volume-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
@@ -215,7 +215,7 @@ export const getVolumeSliderTrackProps: PropsHook<Record<string, never>> = (_sta
* VolumeSlider Progress props hook
*/
export const getVolumeSliderProgressProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-volume-slider-root') as any;
const rootElement = element.closest('media-volume-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
@@ -225,7 +225,7 @@ export const getVolumeSliderProgressProps: PropsHook<Record<string, never>> = (_
* VolumeSlider Thumb props hook
*/
export const getVolumeSliderThumbProps: PropsHook<Record<string, never>> = (_state, element) => {
const rootElement = element.closest('media-volume-slider-root') as any;
const rootElement = element.closest('media-volume-slider') as any;
return {
'data-orientation': rootElement?.orientation || 'horizontal',
};
@@ -234,19 +234,19 @@ export const getVolumeSliderThumbProps: PropsHook<Record<string, never>> = (_sta
/**
* Connected VolumeSlider Root component using hook-style architecture
*/
export const VolumeSliderRoot: ConnectedComponentConstructor<{
export const VolumeSliderRootElement: ConnectedComponentConstructor<{
volume: number;
muted: boolean;
volumeLevel: string;
requestVolumeChange: (volume: number) => void;
core: CoreVolumeSlider | null;
}> = toConnectedHTMLComponent(VolumeSliderRootBase, useVolumeSliderRootState, getVolumeSliderRootProps, 'VolumeSliderRoot');
}> = toConnectedHTMLComponent(VolumeSliderRoot, useVolumeSliderRootState, getVolumeSliderRootProps, 'VolumeSliderRoot');
/**
* Connected VolumeSlider Track component
*/
export const VolumeSliderTrack: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderTrackBase,
export const VolumeSliderTrackElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderTrack,
{ keys: [], transform: () => ({}) },
getVolumeSliderTrackProps,
'VolumeSliderTrack',
@@ -255,8 +255,8 @@ export const VolumeSliderTrack: ConnectedComponentConstructor<any> = toConnected
/**
* Connected VolumeSlider Progress component
*/
export const VolumeSliderProgress: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderProgressBase,
export const VolumeSliderProgressElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderIndicatorElement,
{ keys: [], transform: () => ({}) },
getVolumeSliderProgressProps,
'VolumeSliderProgress',
@@ -265,8 +265,8 @@ export const VolumeSliderProgress: ConnectedComponentConstructor<any> = toConnec
/**
* Connected VolumeSlider Thumb component
*/
export const VolumeSliderThumb: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderThumbBase,
export const VolumeSliderThumbElement: ConnectedComponentConstructor<any> = toConnectedHTMLComponent(
VolumeSliderThumb,
{ keys: [], transform: () => ({}) },
getVolumeSliderThumbProps,
'VolumeSliderThumb',
@@ -275,35 +275,17 @@ export const VolumeSliderThumb: ConnectedComponentConstructor<any> = toConnected
/**
* Compound VolumeSlider component object
*/
export const VolumeSlider = Object.assign(
export const VolumeSliderElement = Object.assign(
{},
{
Root: VolumeSliderRoot,
Track: VolumeSliderTrack,
Progress: VolumeSliderProgress,
Thumb: VolumeSliderThumb,
Root: VolumeSliderRootElement,
Track: VolumeSliderTrackElement,
Progress: VolumeSliderProgressElement,
Thumb: VolumeSliderThumbElement,
},
) as {
Root: typeof VolumeSliderRoot;
Track: typeof VolumeSliderTrack;
Progress: typeof VolumeSliderProgress;
Thumb: typeof VolumeSliderThumb;
Root: typeof VolumeSliderRootElement;
Track: typeof VolumeSliderTrackElement;
Progress: typeof VolumeSliderProgressElement;
Thumb: typeof VolumeSliderThumbElement;
};
if (!globalThis.customElements.get('media-volume-slider-root')) {
globalThis.customElements.define('media-volume-slider-root', VolumeSliderRoot);
}
if (!globalThis.customElements.get('media-volume-slider-track')) {
globalThis.customElements.define('media-volume-slider-track', VolumeSliderTrack);
}
if (!globalThis.customElements.get('media-volume-slider-progress')) {
globalThis.customElements.define('media-volume-slider-progress', VolumeSliderProgress);
}
if (!globalThis.customElements.get('media-volume-slider-thumb')) {
globalThis.customElements.define('media-volume-slider-thumb', VolumeSliderThumb);
}
export default VolumeSlider;
+9 -9
View File
@@ -1,9 +1,9 @@
export * as MediaFullscreenEnterAltIcon from './media-fullscreen-enter-alt-icon';
export * as MediaFullscreenEnterIcon from './media-fullscreen-enter-icon';
export * as MediaFullscreenExitAltIcon from './media-fullscreen-exit-alt-icon';
export * as MediaFullscreenExitIcon from './media-fullscreen-exit-icon';
export * as MediaPauseIcon from './media-pause-icon';
export * as MediaPlayIcon from './media-play-icon';
export * as MediaVolumeHighIcon from './media-volume-high-icon';
export * as MediaVolumeLowIcon from './media-volume-low-icon';
export * as MediaVolumeOffIcon from './media-volume-off-icon';
import './media-fullscreen-enter-alt-icon';
import './media-fullscreen-enter-icon';
import './media-fullscreen-exit-alt-icon';
import './media-fullscreen-exit-icon';
import './media-pause-icon';
import './media-play-icon';
import './media-volume-high-icon';
import './media-volume-low-icon';
import './media-volume-off-icon';
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaFullscreenEnterAltIcon extends MediaChromeIcon {
export class MediaFullscreenEnterAltIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-fullscreen-enter-alt-icon', MediaFullscreenEnterAltIcon);
defineCustomElement('media-fullscreen-enter-alt-icon', MediaFullscreenEnterAltIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaFullscreenEnterIcon extends MediaChromeIcon {
export class MediaFullscreenEnterIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-fullscreen-enter-icon', MediaFullscreenEnterIcon);
defineCustomElement('media-fullscreen-enter-icon', MediaFullscreenEnterIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaFullscreenExitAltIcon extends MediaChromeIcon {
export class MediaFullscreenExitAltIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-fullscreen-exit-alt-icon', MediaFullscreenExitAltIcon);
defineCustomElement('media-fullscreen-exit-alt-icon', MediaFullscreenExitAltIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaFullscreenExitIcon extends MediaChromeIcon {
export class MediaFullscreenExitIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-fullscreen-exit-icon', MediaFullscreenExitIcon);
defineCustomElement('media-fullscreen-exit-icon', MediaFullscreenExitIconElement);
+3 -2
View File
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -9,8 +10,8 @@ export function getTemplateHTML() {
`;
}
export class MediaPauseIcon extends MediaChromeIcon {
export class MediaPauseIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-pause-icon', MediaPauseIcon);
defineCustomElement('media-pause-icon', MediaPauseIconElement);
+3 -2
View File
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaPlayIcon extends MediaChromeIcon {
export class MediaPlayIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-play-icon', MediaPlayIcon);
defineCustomElement('media-play-icon', MediaPlayIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaVolumeHighIcon extends MediaChromeIcon {
export class MediaVolumeHighIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-volume-high-icon', MediaVolumeHighIcon);
defineCustomElement('media-volume-high-icon', MediaVolumeHighIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaVolumeLowIcon extends MediaChromeIcon {
export class MediaVolumeLowIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-volume-low-icon', MediaVolumeLowIcon);
defineCustomElement('media-volume-low-icon', MediaVolumeLowIconElement);
@@ -1,5 +1,6 @@
import { SVG_ICONS } from '@videojs/icons';
import { defineCustomElement } from '@/utils/custom-element';
import { MediaChromeIcon } from './media-chrome-icon';
export function getTemplateHTML() {
@@ -14,8 +15,8 @@ export function getTemplateHTML() {
`;
}
export class MediaVolumeOffIcon extends MediaChromeIcon {
export class MediaVolumeOffIconElement extends MediaChromeIcon {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-volume-off-icon', MediaVolumeOffIcon);
defineCustomElement('media-volume-off-icon', MediaVolumeOffIconElement);
+13 -19
View File
@@ -1,19 +1,13 @@
export { CurrentTimeDisplay } from './components/media-current-time-display';
export { DurationDisplay } from './components/media-duration-display';
export { FullscreenButton } from './components/media-fullscreen-button';
export { MuteButton } from './components/media-mute-button';
export { PlayButton } from './components/media-play-button';
export { Popover } from './components/media-popover';
export { TimeSlider } from './components/media-time-slider';
export { Tooltip } from './components/media-tooltip';
export { VolumeSlider } from './components/media-volume-slider';
export { MediaContainer } from './media/media-container';
export { MediaProvider } from './media/media-provider';
export { MediaSkin } from './media/media-skin';
export function defineVjsPlayer(): void {
/** @TODO - Reimplement me (at least as a POC) (CJP) */
// defineVideoProvider();
// defineVideoDefaultSkin();
// <video> is native, no need to define
}
export { CurrentTimeDisplayElement } from './elements/current-time-display';
export { DurationDisplayElement } from './elements/duration-display';
export { FullscreenButtonElement } from './elements/fullscreen-button';
export { MuteButtonElement } from './elements/mute-button';
export { PlayButtonElement } from './elements/play-button';
export { PopoverElement } from './elements/popover';
export { PreviewTimeDisplayElement } from './elements/preview-time-display';
export { TimeSliderElement } from './elements/time-slider';
export { TooltipElement } from './elements/tooltip';
export { VolumeSliderElement } from './elements/volume-slider';
export { MediaContainerElement } from './media/media-container';
export { MediaProviderElement } from './media/media-provider';
export { MediaSkinElement } from './media/media-skin';
+4 -9
View File
@@ -13,9 +13,9 @@ export function getTemplateHTML() {
`;
}
const CustomElementConsumer: Constructor<CustomElement> = ConsumerMixin(HTMLElement);
const CustomElementConsumer: Constructor<CustomElement & HTMLElement> = ConsumerMixin(HTMLElement);
export class MediaContainer extends CustomElementConsumer {
export class MediaContainerElement extends CustomElementConsumer {
static shadowRootOptions = { mode: 'open' as ShadowRootMode };
static getTemplateHTML: () => string = getTemplateHTML;
@@ -35,8 +35,8 @@ export class MediaContainer extends CustomElementConsumer {
super();
if (!this.shadowRoot) {
this.attachShadow((this.constructor as typeof MediaContainer).shadowRootOptions);
this.shadowRoot!.innerHTML = (this.constructor as typeof MediaContainer).getTemplateHTML();
this.attachShadow((this.constructor as typeof MediaContainerElement).shadowRootOptions);
this.shadowRoot!.innerHTML = (this.constructor as typeof MediaContainerElement).getTemplateHTML();
}
this._mediaSlot = this.shadowRoot!.querySelector('slot[name=media]') as HTMLSlotElement;
@@ -92,8 +92,3 @@ export class MediaContainer extends CustomElementConsumer {
});
};
}
if (!globalThis.customElements.get('media-container')) {
// @ts-expect-error ts(2345)
globalThis.customElements.define('media-container', MediaContainer);
}
+2 -5
View File
@@ -4,15 +4,12 @@ import type { MediaStore } from '@videojs/core/store';
import { ProviderMixin } from '@open-wc/context-protocol';
import { createMediaStore } from '@videojs/core/store';
const ProviderHTMLElement: Constructor<CustomElement> = ProviderMixin(HTMLElement);
const ProviderHTMLElement: Constructor<CustomElement & HTMLElement> = ProviderMixin(HTMLElement);
export class MediaProvider extends ProviderHTMLElement {
export class MediaProviderElement extends ProviderHTMLElement {
contexts = {
mediaStore: (): MediaStore => {
return createMediaStore();
},
};
}
// @ts-expect-error - fix types after (Rahim)
customElements.define('media-provider', MediaProvider);
+3 -7
View File
@@ -15,7 +15,7 @@ export function getTemplateHTML() {
`;
}
export class MediaSkin extends HTMLElement {
export class MediaSkinElement extends HTMLElement {
static shadowRootOptions = { mode: 'open' as ShadowRootMode };
static getTemplateHTML: () => string = getTemplateHTML;
@@ -23,12 +23,8 @@ export class MediaSkin extends HTMLElement {
super();
if (!this.shadowRoot) {
this.attachShadow((this.constructor as typeof MediaSkin).shadowRootOptions);
this.shadowRoot!.innerHTML = (this.constructor as typeof MediaSkin).getTemplateHTML();
this.attachShadow((this.constructor as typeof MediaSkinElement).shadowRootOptions);
this.shadowRoot!.innerHTML = (this.constructor as typeof MediaSkinElement).getTemplateHTML();
}
}
}
if (!customElements.get('media-skin')) {
customElements.define('media-skin', MediaSkin);
}
+29 -29
View File
@@ -1,23 +1,23 @@
import { MediaSkin } from '@/media/media-skin';
import { MediaSkinElement } from '@/media/media-skin';
import { defineCustomElement } from '@/utils/custom-element';
import styles from './styles.css';
import '@/media/media-container';
import '@/media/media-provider';
import '@/components/media-play-button';
import '@/components/media-mute-button';
import '@/components/media-volume-slider';
import '@/components/media-time-slider';
import '@/components/media-fullscreen-button';
import '@/components/media-duration-display';
import '@/components/media-current-time-display';
import '@/components/media-preview-time-display';
import '@/components/media-popover';
import '@/components/media-tooltip';
import '@/define/media-container';
import '@/define/media-provider';
import '@/define/media-play-button';
import '@/define/media-mute-button';
import '@/define/media-volume-slider';
import '@/define/media-time-slider';
import '@/define/media-fullscreen-button';
import '@/define/media-duration-display';
import '@/define/media-current-time-display';
import '@/define/media-preview-time-display';
import '@/define/media-popover';
import '@/define/media-tooltip';
import '@/icons';
export function getTemplateHTML() {
return /* html */`
${MediaSkin.getTemplateHTML()}
${MediaSkinElement.getTemplateHTML()}
<style>${styles}</style>
<media-container>
@@ -27,7 +27,7 @@ export function getTemplateHTML() {
<div class="control-bar surface">
<!-- NOTE: We can decide if we further want to provide a further, "themed" media-play-button that comes with baked in default styles and icons. (CJP) -->
<media-tooltip-root delay="500" close-delay="0">
<media-tooltip delay="500" close-delay="0">
<media-tooltip-trigger>
<media-play-button class="button">
<media-play-icon class="icon play-icon"></media-play-icon>
@@ -42,30 +42,30 @@ export function getTemplateHTML() {
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
<div class="time-controls">
<!-- Use the show-remaining attribute to show count down/remaining time -->
<media-current-time-display></media-current-time-display>
<media-tooltip-root track-cursor-axis="x">
<media-tooltip track-cursor-axis="x">
<media-tooltip-trigger>
<media-time-slider-root class="slider-root">
<media-time-slider class="slider">
<media-time-slider-track class="slider-track">
<media-time-slider-progress class="slider-progress"></media-time-slider-progress>
<media-time-slider-pointer class="slider-pointer"></media-time-slider-pointer>
</media-time-slider-track>
<media-time-slider-thumb class="slider-thumb"></media-time-slider-thumb>
</media-time-slider-root>
</media-time-slider>
</media-tooltip-trigger>
<media-tooltip-portal>
<media-tooltip-positioner side="top" side-offset="18" collision-padding="12">
<media-tooltip-popup class="surface popup-animation">
<preview-time-display></preview-time-display>
<media-preview-time-display></media-preview-time-display>
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
<media-duration-display></media-duration-display>
</div>
@@ -86,15 +86,15 @@ export function getTemplateHTML() {
side-offset="12"
collision-padding="12"
>
<media-volume-slider-root class="slider-root" orientation="vertical">
<media-volume-slider class="slider" orientation="vertical">
<media-volume-slider-track class="slider-track">
<media-volume-slider-progress class="slider-progress"></media-volume-slider-progress>
<media-volume-slider-indicator class="slider-progress"></media-volume-slider-indicator>
</media-volume-slider-track>
<media-volume-slider-thumb class="slider-thumb"></media-volume-slider-thumb>
</media-volume-slider-root>
</media-volume-slider>
</media-popover>
<media-tooltip-root delay="500" close-delay="0">
<media-tooltip delay="500" close-delay="0">
<media-tooltip-trigger>
<media-fullscreen-button class="button">
<media-fullscreen-enter-icon class="icon fullscreen-enter-icon"></media-fullscreen-enter-icon>
@@ -109,14 +109,14 @@ export function getTemplateHTML() {
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
</div>
</media-container>
`;
}
export class MediaSkinFrosted extends MediaSkin {
export class MediaSkinFrostedElement extends MediaSkinElement {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-skin-frosted', MediaSkinFrosted);
defineCustomElement('media-skin-frosted', MediaSkinFrostedElement);
+7 -7
View File
@@ -209,7 +209,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
}
/* TimeSlider Component Styles */
.slider-root {
.slider {
flex: 1;
display: flex;
align-items: center;
@@ -220,14 +220,14 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
}
/* Horizontal orientation styles */
.slider-root[data-orientation='horizontal'] {
.slider[data-orientation='horizontal'] {
min-width: 5rem;
width: 100%;
height: 1.25rem;
}
/* Vertical orientation styles */
.slider-root[data-orientation='vertical'] {
.slider[data-orientation='vertical'] {
height: 5rem;
width: 1.25rem;
}
@@ -257,7 +257,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
height: 100%;
}
.slider-root:focus-visible .slider-track {
.slider:focus-visible .slider-track {
outline-color: oklch(62.3% 0.214 259.815);
outline-offset: 6px;
}
@@ -282,8 +282,8 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
width: 0.75rem;
height: 0.75rem;
}
.slider-root:hover .slider-thumb,
.slider-root:focus-within .slider-thumb {
.slider:hover .slider-thumb,
.slider:focus-within .slider-thumb {
opacity: 1;
}
.slider-track[data-orientation='horizontal'] .slider-thumb {
@@ -303,7 +303,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
border-radius: inherit;
}
preview-time-display {
media-preview-time-display {
font-variant-numeric: tabular-nums;
}
+29 -28
View File
@@ -1,23 +1,24 @@
import { MediaSkin } from '@/media/media-skin';
import { MediaSkinElement } from '@/media/media-skin';
import { defineCustomElement } from '@/utils/custom-element';
import styles from './styles.css';
import '@/media/media-container';
import '@/media/media-provider';
import '@/components/media-play-button';
import '@/components/media-mute-button';
import '@/components/media-volume-slider';
import '@/components/media-time-slider';
import '@/components/media-fullscreen-button';
import '@/components/media-duration-display';
import '@/components/media-current-time-display';
import '@/components/media-preview-time-display';
import '@/components/media-popover';
import '@/components/media-tooltip';
import '@/define/media-container';
import '@/define/media-provider';
import '@/define/media-play-button';
import '@/define/media-mute-button';
import '@/define/media-volume-slider';
import '@/define/media-time-slider';
import '@/define/media-fullscreen-button';
import '@/define/media-duration-display';
import '@/define/media-current-time-display';
import '@/define/media-preview-time-display';
import '@/define/media-popover';
import '@/define/media-tooltip';
import '@/icons';
export function getTemplateHTML() {
return /* html */`
${MediaSkin.getTemplateHTML()}
${MediaSkinElement.getTemplateHTML()}
<style>${styles}</style>
<media-container>
@@ -27,7 +28,7 @@ export function getTemplateHTML() {
<div class="control-bar">
<!-- NOTE: We can decide if we further want to provide a further, "themed" media-play-button that comes with baked in default styles and icons. (CJP) -->
<media-tooltip-root delay="500" close-delay="0">
<media-tooltip delay="500" close-delay="0">
<media-tooltip-trigger>
<media-play-button class="button">
<media-play-icon class="icon play-icon"></media-play-icon>
@@ -42,7 +43,7 @@ export function getTemplateHTML() {
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
<div class="time-display-group">
<!-- Use the show-remaining attribute to show count down/remaining time -->
@@ -54,24 +55,24 @@ export function getTemplateHTML() {
</span>
</div>
<media-tooltip-root track-cursor-axis="x">
<media-tooltip track-cursor-axis="x">
<media-tooltip-trigger>
<media-time-slider-root class="slider-root">
<media-time-slider class="slider">
<media-time-slider-track class="slider-track">
<media-time-slider-progress class="slider-progress"></media-time-slider-progress>
<media-time-slider-pointer class="slider-pointer"></media-time-slider-pointer>
</media-time-slider-track>
<media-time-slider-thumb class="slider-thumb"></media-time-slider-thumb>
</media-time-slider-root>
</media-time-slider>
</media-tooltip-trigger>
<media-tooltip-portal>
<media-tooltip-positioner side="top" side-offset="12" collision-padding="12">
<media-tooltip-popup class="popup-animation">
<preview-time-display></preview-time-display>
<media-preview-time-display></media-preview-time-display>
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
<div class="button-group">
<media-mute-button popovertarget="volume-slider-popover" class="button">
@@ -90,15 +91,15 @@ export function getTemplateHTML() {
side-offset="2"
collision-padding="12"
>
<media-volume-slider-root class="slider-root" orientation="vertical">
<media-volume-slider class="slider" orientation="vertical">
<media-volume-slider-track class="slider-track">
<media-volume-slider-progress class="slider-progress"></media-volume-slider-progress>
<media-volume-slider-indicator class="slider-progress"></media-volume-slider-indicator>
</media-volume-slider-track>
<media-volume-slider-thumb class="slider-thumb"></media-volume-slider-thumb>
</media-volume-slider-root>
</media-volume-slider>
</media-popover>
<media-tooltip-root delay="500" close-delay="0">
<media-tooltip delay="500" close-delay="0">
<media-tooltip-trigger>
<media-fullscreen-button class="button">
<media-fullscreen-enter-alt-icon class="icon fullscreen-enter-icon"></media-fullscreen-enter-alt-icon>
@@ -113,15 +114,15 @@ export function getTemplateHTML() {
</media-tooltip-popup>
</media-tooltip-positioner>
</media-tooltip-portal>
</media-tooltip-root>
</media-tooltip>
</div>
</div>
</media-container>
`;
}
export class MediaSkinMinimal extends MediaSkin {
export class MediaSkinMinimalElement extends MediaSkinElement {
static getTemplateHTML: () => string = getTemplateHTML;
}
customElements.define('media-skin-minimal', MediaSkinMinimal);
defineCustomElement('media-skin-minimal', MediaSkinMinimalElement);
+7 -7
View File
@@ -188,7 +188,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
}
/* TimeSlider Component Styles */
.slider-root {
.slider {
flex: 1;
display: flex;
align-items: center;
@@ -199,14 +199,14 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
}
/* Horizontal orientation styles */
.slider-root[data-orientation='horizontal'] {
.slider[data-orientation='horizontal'] {
min-width: 5rem;
width: 100%;
height: 1.25rem;
}
/* Vertical orientation styles */
.slider-root[data-orientation='vertical'] {
.slider[data-orientation='vertical'] {
height: 4.5rem;
width: 1.25rem;
}
@@ -236,7 +236,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
height: 100%;
}
.slider-root:focus-visible .slider-track {
.slider:focus-visible .slider-track {
outline-color: oklab(1 0 0);
outline-offset: 6px;
}
@@ -259,8 +259,8 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
transition-duration: 150ms;
transition-timing-function: ease-out;
}
.slider-root:hover .slider-thumb,
.slider-root:focus-within .slider-thumb {
.slider:hover .slider-thumb,
.slider:focus-within .slider-thumb {
opacity: 1;
scale: 1;
}
@@ -280,7 +280,7 @@ media-mute-button[data-volume-level='off'] .volume-off-icon {
border-radius: inherit;
}
preview-time-display {
media-preview-time-display {
font-variant-numeric: tabular-nums;
}
@@ -0,0 +1,7 @@
export function defineCustomElement(tagName: string, ctor: CustomElementConstructor): void {
if (typeof window === 'undefined') return;
if (window.customElements.get(tagName)) return;
window.customElements.define(tagName, ctor);
}