From 9c6eaef2aa61771ae1407d0a594b3f790e0ff665 Mon Sep 17 00:00:00 2001 From: Wesley Luyten Date: Thu, 9 Oct 2025 13:05:56 -0500 Subject: [PATCH] feat: rename range to slider (#46) --- .../src/components/{range.ts => slider.ts} | 12 +- .../{time-range.ts => time-slider.ts} | 18 +- .../{volume-range.ts => volume-slider.ts} | 18 +- packages/core/core/src/index.ts | 4 +- .../{time-range.ts => time-slider.ts} | 14 +- .../{volume-range.ts => volume-slider.ts} | 14 +- packages/core/media-store/src/index.ts | 4 +- ...dia-time-range.ts => media-time-slider.ts} | 255 +++++++++--------- ...volume-range.ts => media-volume-slider.ts} | 250 +++++++++-------- packages/html/html/src/index.ts | 2 +- .../html/html/src/skins/media-skin-default.ts | 68 ++--- .../{TimeRange.tsx => TimeSlider.tsx} | 129 ++++----- .../{VolumeRange.tsx => VolumeSlider.tsx} | 111 ++++---- packages/react/react/src/index.ts | 2 +- .../src/skins/default/MediaSkinDefault.tsx | 30 +-- .../react/src/skins/default/styles.module.css | 22 +- .../src/skins/toasted/MediaSkinToasted.tsx | 16 +- 17 files changed, 470 insertions(+), 499 deletions(-) rename packages/core/core/src/components/{range.ts => slider.ts} (94%) rename packages/core/core/src/components/{time-range.ts => time-slider.ts} (87%) rename packages/core/core/src/components/{volume-range.ts => volume-slider.ts} (82%) rename packages/core/media-store/src/component-state-definitions/{time-range.ts => time-slider.ts} (64%) rename packages/core/media-store/src/component-state-definitions/{volume-range.ts => volume-slider.ts} (78%) rename packages/html/html/src/components/{media-time-range.ts => media-time-slider.ts} (62%) rename packages/html/html/src/components/{media-volume-range.ts => media-volume-slider.ts} (57%) rename packages/react/react/src/components/{TimeRange.tsx => TimeSlider.tsx} (54%) rename packages/react/react/src/components/{VolumeRange.tsx => VolumeSlider.tsx} (54%) diff --git a/packages/core/core/src/components/range.ts b/packages/core/core/src/components/slider.ts similarity index 94% rename from packages/core/core/src/components/range.ts rename to packages/core/core/src/components/slider.ts index 4f577615..fb797323 100644 --- a/packages/core/core/src/components/range.ts +++ b/packages/core/core/src/components/slider.ts @@ -2,7 +2,7 @@ import { map } from 'nanostores'; import { shallowEqual } from '../utils/state'; -export interface RangeState { +export interface SliderState { _trackElement: HTMLElement | null; _pointerRatio: number; _hovering: boolean; @@ -11,10 +11,10 @@ export interface RangeState { _pointerWidth: number; } -export class Range { +export class Slider { #element: HTMLElement | null = null; #abortController: AbortController | null = null; - #state = map({ + #state = map({ _trackElement: null, _pointerRatio: 0, _hovering: false, @@ -42,16 +42,16 @@ export class Range { this.#abortController = null; } - subscribe(callback: (state: RangeState) => void): () => void { + subscribe(callback: (state: SliderState) => void): () => void { return this.#state.subscribe(callback); } - setState(state: Partial): void { + setState(state: Partial): void { if (shallowEqual(state, this.#state.get())) return; this.#state.set({ ...this.#state.get(), ...state }); } - getState(): RangeState { + getState(): SliderState { const state = this.#state.get(); let _pointerWidth = 0; diff --git a/packages/core/core/src/components/time-range.ts b/packages/core/core/src/components/time-slider.ts similarity index 87% rename from packages/core/core/src/components/time-range.ts rename to packages/core/core/src/components/time-slider.ts index 30e9af5f..a814ce26 100644 --- a/packages/core/core/src/components/time-range.ts +++ b/packages/core/core/src/components/time-slider.ts @@ -1,8 +1,8 @@ -import type { RangeState } from './range'; +import type { SliderState } from './slider'; -import { Range } from './range'; +import { Slider } from './slider'; -export interface TimeRangeState extends RangeState { +export interface TimeSliderState extends SliderState { currentTime: number; duration: number; requestSeek: (time: number) => void; @@ -10,12 +10,12 @@ export interface TimeRangeState extends RangeState { _durationText: string; } -export class TimeRange extends Range { +export class TimeSlider extends Slider { #seekingTime: number | null = null; #oldCurrentTime: number | null = null; - getState(): TimeRangeState { - const state = super.getState() as TimeRangeState; + getState(): TimeSliderState { + const state = super.getState() as TimeSliderState; // When dragging, use pointer position for immediate feedback; // While seeking, use seeking time so it doesn't jump back to the current time; @@ -61,7 +61,7 @@ export class TimeRange extends Range { #handlePointerDown(event: PointerEvent) { super.handleEvent(event); - const { _pointerRatio, duration, requestSeek } = super.getState() as TimeRangeState; + const { _pointerRatio, duration, requestSeek } = super.getState() as TimeSliderState; this.#seekingTime = _pointerRatio * duration; requestSeek(this.#seekingTime); @@ -70,7 +70,7 @@ export class TimeRange extends Range { #handlePointerMove(event: PointerEvent) { super.handleEvent(event); - const { _dragging, _pointerRatio, duration, requestSeek } = super.getState() as TimeRangeState; + const { _dragging, _pointerRatio, duration, requestSeek } = super.getState() as TimeSliderState; if (_dragging) { this.#seekingTime = _pointerRatio * duration; @@ -79,7 +79,7 @@ export class TimeRange extends Range { } #handlePointerUp(event: PointerEvent) { - const { _dragging, _pointerRatio, duration, requestSeek } = super.getState() as TimeRangeState; + const { _dragging, _pointerRatio, duration, requestSeek } = super.getState() as TimeSliderState; if (_dragging) { this.#seekingTime = _pointerRatio * duration; diff --git a/packages/core/core/src/components/volume-range.ts b/packages/core/core/src/components/volume-slider.ts similarity index 82% rename from packages/core/core/src/components/volume-range.ts rename to packages/core/core/src/components/volume-slider.ts index 8dcaed4f..aadac969 100644 --- a/packages/core/core/src/components/volume-range.ts +++ b/packages/core/core/src/components/volume-slider.ts @@ -1,8 +1,8 @@ -import type { RangeState } from './range'; +import type { SliderState } from './slider'; -import { Range } from './range'; +import { Slider } from './slider'; -export interface VolumeRangeState extends RangeState { +export interface VolumeSliderState extends SliderState { volume: number; muted: boolean; volumeLevel: string; @@ -10,9 +10,9 @@ export interface VolumeRangeState extends RangeState { _volumeText: string; } -export class VolumeRange extends Range { - getState(): VolumeRangeState { - const state = super.getState() as VolumeRangeState; +export class VolumeSlider extends Slider { + getState(): VolumeSliderState { + const state = super.getState() as VolumeSliderState; // When dragging, use pointer position for immediate feedback; // Otherwise, use current volume; @@ -49,14 +49,14 @@ export class VolumeRange extends Range { #handlePointerDown(event: PointerEvent) { super.handleEvent(event); - const { _pointerRatio, requestVolumeChange } = super.getState() as VolumeRangeState; + const { _pointerRatio, requestVolumeChange } = super.getState() as VolumeSliderState; requestVolumeChange(_pointerRatio); } #handlePointerMove(event: PointerEvent) { super.handleEvent(event); - const { _dragging, _pointerRatio, requestVolumeChange } = super.getState() as VolumeRangeState; + const { _dragging, _pointerRatio, requestVolumeChange } = super.getState() as VolumeSliderState; if (_dragging) { requestVolumeChange(_pointerRatio); @@ -64,7 +64,7 @@ export class VolumeRange extends Range { } #handlePointerUp(event: PointerEvent) { - const { _dragging, _pointerRatio, requestVolumeChange } = super.getState() as VolumeRangeState; + const { _dragging, _pointerRatio, requestVolumeChange } = super.getState() as VolumeSliderState; if (_dragging) { requestVolumeChange(_pointerRatio); diff --git a/packages/core/core/src/index.ts b/packages/core/core/src/index.ts index ba04faa4..96974210 100644 --- a/packages/core/core/src/index.ts +++ b/packages/core/core/src/index.ts @@ -1,2 +1,2 @@ -export { TimeRange, type TimeRangeState } from './components/time-range.js'; -export { VolumeRange, type VolumeRangeState } from './components/volume-range.js'; +export { TimeSlider, type TimeSliderState } from './components/time-slider.js'; +export { VolumeSlider, type VolumeSliderState } from './components/volume-slider.js'; diff --git a/packages/core/media-store/src/component-state-definitions/time-range.ts b/packages/core/media-store/src/component-state-definitions/time-slider.ts similarity index 64% rename from packages/core/media-store/src/component-state-definitions/time-range.ts rename to packages/core/media-store/src/component-state-definitions/time-slider.ts index 92d90246..7a538b39 100644 --- a/packages/core/media-store/src/component-state-definitions/time-range.ts +++ b/packages/core/media-store/src/component-state-definitions/time-slider.ts @@ -1,23 +1,23 @@ -export interface TimeRangeState { +export interface TimeSliderState { currentTime: number; duration: number; } -export interface TimeRangeMethods { +export interface TimeSliderMethods { requestSeek: (time: number) => void; } -export interface TimeRangeStateDefinition { +export interface TimeSliderStateDefinition { keys: string[]; - stateTransform: (rawState: any) => TimeRangeState; - createRequestMethods: (dispatch: (action: { type: string; detail?: any }) => void) => TimeRangeMethods; + stateTransform: (rawState: any) => TimeSliderState; + createRequestMethods: (dispatch: (action: { type: string; detail?: any }) => void) => TimeSliderMethods; } /** - * TimeRange state definition + * TimeSlider state definition * Defines the core state logic that can be shared between implementations */ -export const timeRangeStateDefinition: TimeRangeStateDefinition = { +export const timeSliderStateDefinition: TimeSliderStateDefinition = { keys: ['currentTime', 'duration'], stateTransform: (rawState: any) => ({ currentTime: rawState.currentTime ?? 0, diff --git a/packages/core/media-store/src/component-state-definitions/volume-range.ts b/packages/core/media-store/src/component-state-definitions/volume-slider.ts similarity index 78% rename from packages/core/media-store/src/component-state-definitions/volume-range.ts rename to packages/core/media-store/src/component-state-definitions/volume-slider.ts index 74859307..64e4df5e 100644 --- a/packages/core/media-store/src/component-state-definitions/volume-range.ts +++ b/packages/core/media-store/src/component-state-definitions/volume-slider.ts @@ -1,24 +1,24 @@ -export interface VolumeRangeState { +export interface VolumeSliderState { volume: number; muted: boolean; volumeLevel: 'high' | 'medium' | 'low' | 'off'; } -export interface VolumeRangeMethods { +export interface VolumeSliderMethods { requestVolumeChange: (volume: number) => void; } -export interface VolumeRangeStateDefinition { +export interface VolumeSliderStateDefinition { keys: string[]; - stateTransform: (rawState: any) => VolumeRangeState; - createRequestMethods: (dispatch: (action: { type: string; detail?: any }) => void) => VolumeRangeMethods; + stateTransform: (rawState: any) => VolumeSliderState; + createRequestMethods: (dispatch: (action: { type: string; detail?: any }) => void) => VolumeSliderMethods; } /** - * VolumeRange state definition + * VolumeSlider state definition * Defines the core state logic that can be shared between implementations */ -export const volumeRangeStateDefinition: VolumeRangeStateDefinition = { +export const volumeSliderStateDefinition: VolumeSliderStateDefinition = { keys: ['volume', 'muted', 'volumeLevel'], stateTransform: (rawState: any) => ({ volume: rawState.volume ?? 1, diff --git a/packages/core/media-store/src/index.ts b/packages/core/media-store/src/index.ts index bb9b3847..786b8075 100644 --- a/packages/core/media-store/src/index.ts +++ b/packages/core/media-store/src/index.ts @@ -3,8 +3,8 @@ export * from './component-state-definitions/duration-display'; export * from './component-state-definitions/fullscreen-button'; export * from './component-state-definitions/mute-button'; export * from './component-state-definitions/play-button'; -export * from './component-state-definitions/time-range'; -export * from './component-state-definitions/volume-range'; +export * from './component-state-definitions/time-slider'; +export * from './component-state-definitions/volume-slider'; export * from './factory'; export { createMediaStore } from './media-store'; export * from './state-mediators/audible'; diff --git a/packages/html/html/src/components/media-time-range.ts b/packages/html/html/src/components/media-time-slider.ts similarity index 62% rename from packages/html/html/src/components/media-time-range.ts rename to packages/html/html/src/components/media-time-slider.ts index 4a792f13..ee7f3e2b 100644 --- a/packages/html/html/src/components/media-time-range.ts +++ b/packages/html/html/src/components/media-time-slider.ts @@ -1,22 +1,55 @@ import type { ConnectedComponentConstructor, PropsHook, StateHook } from '../utils/component-factory'; -import { TimeRange as CoreTimeRange } from '@vjs-10/core'; -import { timeRangeStateDefinition } from '@vjs-10/media-store'; +import { TimeSlider as CoreTimeSlider } from '@vjs-10/core'; +import { timeSliderStateDefinition } from '@vjs-10/media-store'; import { toConnectedHTMLComponent } from '../utils/component-factory'; -interface TimeRangeRootState { +interface TimeSliderRootState { currentTime: number; duration: number; requestSeek: (time: number) => void; - core: CoreTimeRange | null; + core: CoreTimeSlider | null; } -export class TimeRangeRootBase extends HTMLElement { +/** + * TimeSlider Root props hook - equivalent to React's useTimeSliderRootProps + * Handles element attributes and properties based on state + */ +export const getTimeSliderRootProps: PropsHook<{ + currentTime: number; + duration: number; + requestSeek: (time: number) => void; + core: CoreTimeSlider | null; +}> = (state, element) => { + const formatTime = (time: number) => { + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60); + return `${minutes}:${seconds.toString().padStart(2, '0')}`; + }; + + const currentTimeText = formatTime(state.currentTime); + const durationText = formatTime(state.duration); + + const baseProps: Record = { + /** data attributes/props */ + 'data-current-time': state.currentTime.toString(), + 'data-duration': state.duration.toString(), + 'data-orientation': (element as any).orientation || 'horizontal', + /** aria attributes/props */ + 'aria-label': 'Seek', + 'aria-valuetext': `${currentTimeText} of ${durationText}`, + 'aria-orientation': (element as any).orientation || 'horizontal', + }; + + return baseProps; +}; + +export class TimeSliderRootBase extends HTMLElement { static readonly observedAttributes: readonly string[] = ['orientation']; - _state: TimeRangeRootState | undefined; - _core: CoreTimeRange | null = null; + _state: TimeSliderRootState | undefined; + _core: CoreTimeSlider | null = null; get currentTime(): number { return this._state?.currentTime ?? 0; @@ -32,7 +65,7 @@ export class TimeRangeRootBase extends HTMLElement { attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void { if (name === 'orientation' && this._state) { - this._render(useTimeRangeRootProps(this._state, this), this._state); + this._render(getTimeSliderRootProps(this._state, this), this._state); } } @@ -40,8 +73,8 @@ export class TimeRangeRootBase extends HTMLElement { this._state = state; if (state && !this._core) { - this._core = new CoreTimeRange(); - this._core.subscribe(() => this._render(useTimeRangeRootProps(state, this), state)); + this._core = new CoreTimeSlider(); + this._core.subscribe(() => this._render(getTimeSliderRootProps(state, this), state)); this._core.attach(this); state.core = this._core; } @@ -70,14 +103,14 @@ export class TimeRangeRootBase extends HTMLElement { } } -export class TimeRangeTrackBase extends HTMLElement { +export class TimeSliderTrackBase extends HTMLElement { constructor() { super(); } connectedCallback(): void { - // Set this element as the track element in the core TimeRange - const rootElement = this.closest('media-time-range-root') as any; + // Set this element as the track element in the core TimeSlider + const rootElement = this.closest('media-time-slider-root') as any; if (rootElement?._state?.core) { rootElement._state.core.setState({ _trackElement: this }); } @@ -98,7 +131,7 @@ export class TimeRangeTrackBase extends HTMLElement { } } -export class TimeRangeProgressBase extends HTMLElement { +export class TimeSliderProgressBase extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -125,7 +158,7 @@ export class TimeRangeProgressBase extends HTMLElement { } } -export class TimeRangePointerBase extends HTMLElement { +export class TimeSliderPointerBase extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -152,7 +185,7 @@ export class TimeRangePointerBase extends HTMLElement { } } -export class TimeRangeThumbBase extends HTMLElement { +export class TimeSliderThumbBase extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -175,157 +208,123 @@ export class TimeRangeThumbBase extends HTMLElement { } } -export const useTimeRangeRootState: StateHook<{ +export const useTimeSliderRootState: StateHook<{ currentTime: number; duration: number; requestSeek: (time: number) => void; - core: CoreTimeRange | null; + core: CoreTimeSlider | null; }> = { - keys: timeRangeStateDefinition.keys, + keys: timeSliderStateDefinition.keys, transform: (rawState, mediaStore) => ({ - ...timeRangeStateDefinition.stateTransform(rawState), - ...timeRangeStateDefinition.createRequestMethods(mediaStore.dispatch), + ...timeSliderStateDefinition.stateTransform(rawState), + ...timeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), core: null, }), }; -export const useTimeRangeRootProps: PropsHook<{ +export const getTimeSliderTrackProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-time-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +export const getTimeSliderProgressProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-time-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +export const getTimeSliderPointerProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-time-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +export const getTimeSliderThumbProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-time-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +export const TimeSliderRoot: ConnectedComponentConstructor<{ currentTime: number; duration: number; requestSeek: (time: number) => void; - core: CoreTimeRange | null; -}> = (state, element) => { - const formatTime = (time: number) => { - const minutes = Math.floor(time / 60); - const seconds = Math.floor(time % 60); - return `${minutes}:${seconds.toString().padStart(2, '0')}`; - }; + core: CoreTimeSlider | null; +}> = toConnectedHTMLComponent(TimeSliderRootBase, useTimeSliderRootState, getTimeSliderRootProps, 'TimeSliderRoot'); - const currentTimeText = formatTime(state.currentTime); - const durationText = formatTime(state.duration); - - const baseProps: Record = { - /** data attributes/props */ - 'data-current-time': state.currentTime.toString(), - 'data-duration': state.duration.toString(), - 'data-orientation': (element as any).orientation || 'horizontal', - /** aria attributes/props */ - 'aria-label': 'Seek', - 'aria-valuetext': `${currentTimeText} of ${durationText}`, - 'aria-orientation': (element as any).orientation || 'horizontal', - }; - - return baseProps; -}; - -export const useTimeRangeTrackProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-time-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -export const useTimeRangeProgressProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-time-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -export const useTimeRangePointerProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-time-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -export const useTimeRangeThumbProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-time-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -export const TimeRangeRoot: ConnectedComponentConstructor<{ - currentTime: number; - duration: number; - requestSeek: (time: number) => void; - core: CoreTimeRange | null; -}> = toConnectedHTMLComponent(TimeRangeRootBase, useTimeRangeRootState, useTimeRangeRootProps, 'TimeRangeRoot'); - -export const TimeRangeTrack: ConnectedComponentConstructor = toConnectedHTMLComponent( - TimeRangeTrackBase, +export const TimeSliderTrack: ConnectedComponentConstructor = toConnectedHTMLComponent( + TimeSliderTrackBase, { keys: [], transform: () => ({}) }, - useTimeRangeTrackProps, - 'TimeRangeTrack', + getTimeSliderTrackProps, + 'TimeSliderTrack', ); -export const TimeRangeProgress: ConnectedComponentConstructor = toConnectedHTMLComponent( - TimeRangeProgressBase, +export const TimeSliderProgress: ConnectedComponentConstructor = toConnectedHTMLComponent( + TimeSliderProgressBase, { keys: [], transform: () => ({}) }, - useTimeRangeProgressProps, - 'TimeRangeProgress', + getTimeSliderProgressProps, + 'TimeSliderProgress', ); -export const TimeRangePointer: ConnectedComponentConstructor = toConnectedHTMLComponent( - TimeRangePointerBase, +export const TimeSliderPointer: ConnectedComponentConstructor = toConnectedHTMLComponent( + TimeSliderPointerBase, { keys: [], transform: () => ({}) }, - useTimeRangePointerProps, - 'TimeRangePointer', + getTimeSliderPointerProps, + 'TimeSliderPointer', ); -export const TimeRangeThumb: ConnectedComponentConstructor = toConnectedHTMLComponent( - TimeRangeThumbBase, +export const TimeSliderThumb: ConnectedComponentConstructor = toConnectedHTMLComponent( + TimeSliderThumbBase, { keys: [], transform: () => ({}) }, - useTimeRangeThumbProps, - 'TimeRangeThumb', + getTimeSliderThumbProps, + 'TimeSliderThumb', ); -export const TimeRange = Object.assign( +export const TimeSlider = Object.assign( {}, { - Root: TimeRangeRoot, - Track: TimeRangeTrack, - Progress: TimeRangeProgress, - Pointer: TimeRangePointer, - Thumb: TimeRangeThumb, + Root: TimeSliderRoot, + Track: TimeSliderTrack, + Progress: TimeSliderProgress, + Pointer: TimeSliderPointer, + Thumb: TimeSliderThumb, }, ) as { - Root: typeof TimeRangeRoot; - Track: typeof TimeRangeTrack; - Progress: typeof TimeRangeProgress; - Pointer: typeof TimeRangePointer; - Thumb: typeof TimeRangeThumb; + Root: typeof TimeSliderRoot; + Track: typeof TimeSliderTrack; + Progress: typeof TimeSliderProgress; + Pointer: typeof TimeSliderPointer; + Thumb: typeof TimeSliderThumb; }; // Register custom elements -if (!globalThis.customElements.get('media-time-range-root')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-time-range-root', TimeRangeRoot); +if (!globalThis.customElements.get('media-time-slider-root')) { + globalThis.customElements.define('media-time-slider-root', TimeSliderRoot); } -if (!globalThis.customElements.get('media-time-range-track')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-time-range-track', TimeRangeTrack); +if (!globalThis.customElements.get('media-time-slider-track')) { + globalThis.customElements.define('media-time-slider-track', TimeSliderTrack); } -if (!globalThis.customElements.get('media-time-range-progress')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-time-range-progress', TimeRangeProgress); +if (!globalThis.customElements.get('media-time-slider-progress')) { + globalThis.customElements.define('media-time-slider-progress', TimeSliderProgress); } -if (!globalThis.customElements.get('media-time-range-pointer')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-time-range-pointer', TimeRangePointer); +if (!globalThis.customElements.get('media-time-slider-pointer')) { + globalThis.customElements.define('media-time-slider-pointer', TimeSliderPointer); } -if (!globalThis.customElements.get('media-time-range-thumb')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-time-range-thumb', TimeRangeThumb); +if (!globalThis.customElements.get('media-time-slider-thumb')) { + globalThis.customElements.define('media-time-slider-thumb', TimeSliderThumb); } -export default TimeRange; +export default TimeSlider; diff --git a/packages/html/html/src/components/media-volume-range.ts b/packages/html/html/src/components/media-volume-slider.ts similarity index 57% rename from packages/html/html/src/components/media-volume-range.ts rename to packages/html/html/src/components/media-volume-slider.ts index 45efb6eb..9fd4364a 100644 --- a/packages/html/html/src/components/media-volume-range.ts +++ b/packages/html/html/src/components/media-volume-slider.ts @@ -1,26 +1,53 @@ import type { ConnectedComponentConstructor, PropsHook, StateHook } from '../utils/component-factory'; -import { VolumeRange as CoreVolumeRange } from '@vjs-10/core'; -import { volumeRangeStateDefinition } from '@vjs-10/media-store'; +import { VolumeSlider as CoreVolumeSlider } from '@vjs-10/core'; +import { volumeSliderStateDefinition } from '@vjs-10/media-store'; import { toConnectedHTMLComponent } from '../utils/component-factory'; /** - * VolumeRange Root component - Main container with pointer event handling + * VolumeSlider Root props hook - equivalent to React's useVolumeSliderRootProps + * Handles element attributes and properties based on state */ -interface VolumeRangeRootState { +export const getVolumeSliderRootProps: PropsHook<{ volume: number; muted: boolean; volumeLevel: string; requestVolumeChange: (volume: number) => void; - core: CoreVolumeRange | null; + core: CoreVolumeSlider | null; +}> = (state, element) => { + const volumeText = `${Math.round(state.muted ? 0 : state.volume * 100)}%`; + + const baseProps: Record = { + /** data attributes/props */ + 'data-muted': state.muted.toString(), + 'data-volume-level': state.volumeLevel, + 'data-orientation': (element as any).orientation || 'horizontal', + /** aria attributes/props */ + 'aria-label': 'Volume', + 'aria-valuetext': volumeText, + 'aria-orientation': (element as any).orientation || 'horizontal', + }; + + return baseProps; +}; + +/** + * VolumeSlider Root component - Main container with pointer event handling + */ +interface VolumeSliderRootState { + volume: number; + muted: boolean; + volumeLevel: string; + requestVolumeChange: (volume: number) => void; + core: CoreVolumeSlider | null; } -export class VolumeRangeRootBase extends HTMLElement { +export class VolumeSliderRootBase extends HTMLElement { static readonly observedAttributes: readonly string[] = ['orientation']; - _state: VolumeRangeRootState | undefined; - _core: CoreVolumeRange | null = null; + _state: VolumeSliderRootState | undefined; + _core: CoreVolumeSlider | null = null; get volume(): number | undefined { return this._state?.volume; @@ -40,7 +67,7 @@ export class VolumeRangeRootBase extends HTMLElement { attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void { if (name === 'orientation' && this._state) { - this._render(useVolumeRangeRootProps(this._state, this), this._state); + this._render(getVolumeSliderRootProps(this._state, this), this._state); } } @@ -48,8 +75,8 @@ export class VolumeRangeRootBase extends HTMLElement { this._state = state; if (state && !this._core) { - this._core = new CoreVolumeRange(); - this._core.subscribe(() => this._render(useVolumeRangeRootProps(state, this), state)); + this._core = new CoreVolumeSlider(); + this._core.subscribe(() => this._render(getVolumeSliderRootProps(state, this), state)); this._core.attach(this); state.core = this._core; } @@ -79,16 +106,16 @@ export class VolumeRangeRootBase extends HTMLElement { } /** - * VolumeRange Track component - Track element that captures pointer events + * VolumeSlider Track component - Track element that captures pointer events */ -export class VolumeRangeTrackBase extends HTMLElement { +export class VolumeSliderTrackBase extends HTMLElement { constructor() { super(); } connectedCallback(): void { - // Set this element as the track element in the core VolumeRange - const rootElement = this.closest('media-volume-range-root') as any; + // Set this element as the track element in the core VolumeSlider + const rootElement = this.closest('media-volume-slider-root') as any; if (rootElement?._state?.core) { rootElement._state.core.setState({ _trackElement: this }); } @@ -110,9 +137,9 @@ export class VolumeRangeTrackBase extends HTMLElement { } /** - * VolumeRange Progress component - Shows current progress + * VolumeSlider Progress component - Shows current progress */ -export class VolumeRangeProgressBase extends HTMLElement { +export class VolumeSliderProgressBase extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -140,9 +167,9 @@ export class VolumeRangeProgressBase extends HTMLElement { } /** - * VolumeRange Thumb component - Draggable thumb element + * VolumeSlider Thumb component - Draggable thumb element */ -export class VolumeRangeThumbBase extends HTMLElement { +export class VolumeSliderThumbBase extends HTMLElement { constructor() { super(); this.style.position = 'absolute'; @@ -166,162 +193,131 @@ export class VolumeRangeThumbBase extends HTMLElement { } /** - * VolumeRange Root state hook - equivalent to React's useVolumeRangeRootState + * VolumeSlider Root state hook - equivalent to React's useVolumeSliderRootState * Handles media store state subscription and transformation */ -export const useVolumeRangeRootState: StateHook<{ +export const useVolumeSliderRootState: StateHook<{ volume: number; muted: boolean; volumeLevel: string; requestVolumeChange: (volume: number) => void; - core: CoreVolumeRange | null; + core: CoreVolumeSlider | null; }> = { - keys: volumeRangeStateDefinition.keys, + keys: volumeSliderStateDefinition.keys, transform: (rawState, mediaStore) => ({ - ...volumeRangeStateDefinition.stateTransform(rawState), - ...volumeRangeStateDefinition.createRequestMethods(mediaStore.dispatch), + ...volumeSliderStateDefinition.stateTransform(rawState), + ...volumeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), core: null, }), }; /** - * VolumeRange Root props hook - equivalent to React's useVolumeRangeRootProps - * Handles element attributes and properties based on state + * VolumeSlider Track props hook */ -export const useVolumeRangeRootProps: PropsHook<{ +export const getVolumeSliderTrackProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-volume-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +/** + * VolumeSlider Progress props hook + */ +export const getVolumeSliderProgressProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-volume-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +/** + * VolumeSlider Thumb props hook + */ +export const getVolumeSliderThumbProps: PropsHook> = (_state, element) => { + // Get orientation from parent root element if not provided in state + const rootElement = element.closest('media-volume-slider-root') as any; + return { + 'data-orientation': rootElement?.orientation || 'horizontal', + }; +}; + +/** + * Connected VolumeSlider Root component using hook-style architecture + */ +export const VolumeSliderRoot: ConnectedComponentConstructor<{ volume: number; muted: boolean; volumeLevel: string; requestVolumeChange: (volume: number) => void; - core: CoreVolumeRange | null; -}> = (state, element) => { - const volumeText = `${Math.round(state.muted ? 0 : state.volume * 100)}%`; - - const baseProps: Record = { - /** data attributes/props */ - 'data-muted': state.muted.toString(), - 'data-volume-level': state.volumeLevel, - 'data-orientation': (element as any).orientation || 'horizontal', - /** aria attributes/props */ - 'aria-label': 'Volume', - 'aria-valuetext': volumeText, - 'aria-orientation': (element as any).orientation || 'horizontal', - }; - - return baseProps; -}; + core: CoreVolumeSlider | null; +}> = toConnectedHTMLComponent(VolumeSliderRootBase, useVolumeSliderRootState, getVolumeSliderRootProps, 'VolumeSliderRoot'); /** - * VolumeRange Track props hook + * Connected VolumeSlider Track component */ -export const useVolumeRangeTrackProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-volume-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -/** - * VolumeRange Progress props hook - */ -export const useVolumeRangeProgressProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-volume-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -/** - * VolumeRange Thumb props hook - */ -export const useVolumeRangeThumbProps: PropsHook<{}> = (_state, element) => { - // Get orientation from parent root element if not provided in state - const rootElement = element.closest('media-volume-range-root') as any; - return { - 'data-orientation': rootElement?.orientation || 'horizontal', - }; -}; - -/** - * Connected VolumeRange Root component using hook-style architecture - */ -export const VolumeRangeRoot: ConnectedComponentConstructor<{ - volume: number; - muted: boolean; - volumeLevel: string; - requestVolumeChange: (volume: number) => void; - core: CoreVolumeRange | null; -}> = toConnectedHTMLComponent(VolumeRangeRootBase, useVolumeRangeRootState, useVolumeRangeRootProps, 'VolumeRangeRoot'); - -/** - * Connected VolumeRange Track component - */ -export const VolumeRangeTrack: ConnectedComponentConstructor = toConnectedHTMLComponent( - VolumeRangeTrackBase, +export const VolumeSliderTrack: ConnectedComponentConstructor = toConnectedHTMLComponent( + VolumeSliderTrackBase, { keys: [], transform: () => ({}) }, - useVolumeRangeTrackProps, - 'VolumeRangeTrack', + getVolumeSliderTrackProps, + 'VolumeSliderTrack', ); /** - * Connected VolumeRange Progress component + * Connected VolumeSlider Progress component */ -export const VolumeRangeProgress: ConnectedComponentConstructor = toConnectedHTMLComponent( - VolumeRangeProgressBase, +export const VolumeSliderProgress: ConnectedComponentConstructor = toConnectedHTMLComponent( + VolumeSliderProgressBase, { keys: [], transform: () => ({}) }, - useVolumeRangeProgressProps, - 'VolumeRangeProgress', + getVolumeSliderProgressProps, + 'VolumeSliderProgress', ); /** - * Connected VolumeRange Thumb component + * Connected VolumeSlider Thumb component */ -export const VolumeRangeThumb: ConnectedComponentConstructor = toConnectedHTMLComponent( - VolumeRangeThumbBase, +export const VolumeSliderThumb: ConnectedComponentConstructor = toConnectedHTMLComponent( + VolumeSliderThumbBase, { keys: [], transform: () => ({}) }, - useVolumeRangeThumbProps, - 'VolumeRangeThumb', + getVolumeSliderThumbProps, + 'VolumeSliderThumb', ); /** - * Compound VolumeRange component object + * Compound VolumeSlider component object */ -export const VolumeRange = Object.assign( +export const VolumeSlider = Object.assign( {}, { - Root: VolumeRangeRoot, - Track: VolumeRangeTrack, - Progress: VolumeRangeProgress, - Thumb: VolumeRangeThumb, + Root: VolumeSliderRoot, + Track: VolumeSliderTrack, + Progress: VolumeSliderProgress, + Thumb: VolumeSliderThumb, }, ) as { - Root: typeof VolumeRangeRoot; - Track: typeof VolumeRangeTrack; - Progress: typeof VolumeRangeProgress; - Thumb: typeof VolumeRangeThumb; + Root: typeof VolumeSliderRoot; + Track: typeof VolumeSliderTrack; + Progress: typeof VolumeSliderProgress; + Thumb: typeof VolumeSliderThumb; }; // Register custom elements -if (!globalThis.customElements.get('media-volume-range-root')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-volume-range-root', VolumeRangeRoot); +if (!globalThis.customElements.get('media-volume-slider-root')) { + globalThis.customElements.define('media-volume-slider-root', VolumeSliderRoot); } -if (!globalThis.customElements.get('media-volume-range-track')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-volume-range-track', VolumeRangeTrack); +if (!globalThis.customElements.get('media-volume-slider-track')) { + globalThis.customElements.define('media-volume-slider-track', VolumeSliderTrack); } -if (!globalThis.customElements.get('media-volume-range-progress')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-volume-range-progress', VolumeRangeProgress); +if (!globalThis.customElements.get('media-volume-slider-progress')) { + globalThis.customElements.define('media-volume-slider-progress', VolumeSliderProgress); } -if (!globalThis.customElements.get('media-volume-range-thumb')) { - // @ts-ignore - Custom element constructor compatibility - globalThis.customElements.define('media-volume-range-thumb', VolumeRangeThumb); +if (!globalThis.customElements.get('media-volume-slider-thumb')) { + globalThis.customElements.define('media-volume-slider-thumb', VolumeSliderThumb); } -export default VolumeRange; +export default VolumeSlider; diff --git a/packages/html/html/src/index.ts b/packages/html/html/src/index.ts index bc14b968..291d3cde 100644 --- a/packages/html/html/src/index.ts +++ b/packages/html/html/src/index.ts @@ -5,7 +5,7 @@ export { FullscreenButton } from './components/media-fullscreen-button.js'; export { MuteButton } from './components/media-mute-button.js'; // New hook-style components export { PlayButton } from './components/media-play-button.js'; -export { VolumeRange } from './components/media-volume-range.js'; +export { VolumeSlider } from './components/media-volume-slider.js'; export * as MediaProvider from './media-provider.js'; export * as MediaThemeDefault from './skins/media-skin-default.js'; diff --git a/packages/html/html/src/skins/media-skin-default.ts b/packages/html/html/src/skins/media-skin-default.ts index 93b0ffb7..e3c9c844 100644 --- a/packages/html/html/src/skins/media-skin-default.ts +++ b/packages/html/html/src/skins/media-skin-default.ts @@ -4,8 +4,8 @@ import { uniqueId } from '../utils/element-utils'; import '../media-container'; import '../components/media-play-button'; import '../components/media-mute-button'; -import '../components/media-volume-range'; -import '../components/media-time-range'; +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'; @@ -114,8 +114,8 @@ export function getTemplateHTML() { flex-grow: 1; } - /* TimeRange Component Styles */ - media-time-range-root { + /* TimeSlider Component Styles */ + media-time-slider-root { display: flex; align-items: center; justify-content: center; @@ -126,21 +126,21 @@ export function getTemplateHTML() { } /* Horizontal orientation styles */ - media-time-range-root[data-orientation="horizontal"] { + media-time-slider-root[data-orientation="horizontal"] { min-width: 100px; width: 100%; height: 20px; } /* Vertical orientation styles */ - media-time-range-root[data-orientation="vertical"] { + media-time-slider-root[data-orientation="vertical"] { min-width: 20px; width: 20px; height: 100px; flex-direction: column; } - media-time-range-track { + media-time-slider-track { position: relative; width: 100%; height: .375rem; @@ -151,18 +151,18 @@ export function getTemplateHTML() { } /* Horizontal track styles */ - media-time-range-track[data-orientation="horizontal"] { + media-time-slider-track[data-orientation="horizontal"] { width: 100%; height: .375rem; } /* Vertical track styles */ - media-time-range-track[data-orientation="vertical"] { + media-time-slider-track[data-orientation="vertical"] { width: .375rem; height: 100%; } - media-time-range-thumb { + media-time-slider-thumb { width: .75rem; height: .75rem; background-color: #fff; @@ -170,12 +170,12 @@ export function getTemplateHTML() { pointer-events: none; } - media-time-range-pointer { + media-time-slider-pointer { background-color: rgba(255, 255, 255, .5); pointer-events: none; } - media-time-range-progress { + media-time-slider-progress { background-color: #007bff; border-radius: inherit; } @@ -185,8 +185,8 @@ export function getTemplateHTML() { padding: 14px 0; } - /* VolumeRange Component Styles */ - media-volume-range-root { + /* VolumeSlider Component Styles */ + media-volume-slider-root { display: flex; align-items: center; justify-content: center; @@ -197,21 +197,21 @@ export function getTemplateHTML() { } /* Horizontal orientation styles */ - media-volume-range-root[data-orientation="horizontal"] { + media-volume-slider-root[data-orientation="horizontal"] { min-width: 80px; width: 80px; height: 20px; } /* Vertical orientation styles */ - media-volume-range-root[data-orientation="vertical"] { + media-volume-slider-root[data-orientation="vertical"] { min-width: 20px; width: 20px; height: 80px; flex-direction: column; } - media-volume-range-track { + media-volume-slider-track { position: relative; width: 100%; height: .375rem; @@ -222,18 +222,18 @@ export function getTemplateHTML() { } /* Horizontal track styles */ - media-volume-range-track[data-orientation="horizontal"] { + media-volume-slider-track[data-orientation="horizontal"] { width: 100%; height: .375rem; } /* Vertical track styles */ - media-volume-range-track[data-orientation="vertical"] { + media-volume-slider-track[data-orientation="vertical"] { width: .375rem; height: 100%; } - media-volume-range-thumb { + media-volume-slider-thumb { width: .75rem; height: .75rem; background-color: #fff; @@ -241,7 +241,7 @@ export function getTemplateHTML() { pointer-events: none; } - media-volume-range-progress { + media-volume-slider-progress { background-color: #007bff; border-radius: inherit; } @@ -302,13 +302,13 @@ export function getTemplateHTML() { - - - - - - - + + + + + + + @@ -321,12 +321,12 @@ export function getTemplateHTML() { - - - - - - + + + + + + diff --git a/packages/react/react/src/components/TimeRange.tsx b/packages/react/react/src/components/TimeSlider.tsx similarity index 54% rename from packages/react/react/src/components/TimeRange.tsx rename to packages/react/react/src/components/TimeSlider.tsx index 46c7bfc4..1eaacb61 100644 --- a/packages/react/react/src/components/TimeRange.tsx +++ b/packages/react/react/src/components/TimeSlider.tsx @@ -1,28 +1,26 @@ import type { ConnectedComponent } from '../utils/component-factory'; -import { TimeRange as CoreTimeRange } from '@vjs-10/core'; +import { TimeSlider as CoreTimeSlider } from '@vjs-10/core'; -import { timeRangeStateDefinition } from '@vjs-10/media-store'; +import { timeSliderStateDefinition } from '@vjs-10/media-store'; import { shallowEqual, useMediaSelector, useMediaStore } from '@vjs-10/react-media-store'; import { useCallback, useMemo } from 'react'; import { toConnectedComponent, toContextComponent, useCore } from '../utils/component-factory'; -export namespace TimeRange { - export interface State { - currentTime: number; - duration: number; - requestSeek: (time: number) => void; - core: CoreTimeRange; - orientation: 'horizontal' | 'vertical'; - } - - export interface Props extends React.ComponentProps<'div'> { - orientation?: 'horizontal' | 'vertical'; - } +export interface TimeSliderState { + currentTime: number; + duration: number; + requestSeek: (time: number) => void; + core: CoreTimeSlider; + orientation: 'horizontal' | 'vertical'; } -interface TimeRangeRenderProps extends React.ComponentProps<'div'> { +export interface TimeSliderProps extends React.ComponentProps<'div'> { + orientation?: 'horizontal' | 'vertical'; +} + +interface TimeSliderRenderProps extends React.ComponentProps<'div'> { 'data-orientation'?: 'horizontal' | 'vertical'; 'data-current-time'?: number; 'data-duration'?: number; @@ -32,12 +30,12 @@ interface TimeRangeRenderProps extends React.ComponentProps<'div'> { // ROOT COMPONENT // ============================================================================ -export function useTimeRangeRootState(props: TimeRange.Props): TimeRange.State { +export function useTimeSliderRootState(props: TimeSliderProps): TimeSliderState { const { orientation = 'horizontal' } = props; const mediaStore = useMediaStore(); - const mediaState = useMediaSelector(timeRangeStateDefinition.stateTransform, shallowEqual); - const mediaMethods = useMemo(() => timeRangeStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]); - const core = useCore(CoreTimeRange, { ...mediaState, ...mediaMethods }); + const mediaState = useMediaSelector(timeSliderStateDefinition.stateTransform, shallowEqual); + const mediaMethods = useMemo(() => timeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore]); + const core = useCore(CoreTimeSlider, { ...mediaState, ...mediaMethods }); return { ...mediaState, @@ -47,7 +45,7 @@ export function useTimeRangeRootState(props: TimeRange.Props): TimeRange.State { }; } -export function useTimeRangeRootProps(props: TimeRange.Props, state: TimeRange.State): TimeRangeRenderProps { +export function useTimeSliderRootProps(props: TimeSliderProps, state: TimeSliderState): TimeSliderRenderProps { const { _fillWidth, _pointerWidth, _currentTimeText, _durationText } = state.core.getState(); const { children, className, id, style, orientation = 'horizontal' } = props; @@ -78,25 +76,22 @@ export function useTimeRangeRootProps(props: TimeRange.Props, state: TimeRange.S }; } -type useTimeRangeRootState = typeof useTimeRangeRootState; -type useTimeRangeRootProps = typeof useTimeRangeRootProps; - -export function renderTimeRangeRoot(props: TimeRangeRenderProps): JSX.Element { +export function renderTimeSliderRoot(props: TimeSliderRenderProps): JSX.Element { return
; } -const TimeRangeRoot: ConnectedComponent = toConnectedComponent( - useTimeRangeRootState, - useTimeRangeRootProps, - renderTimeRangeRoot, - 'TimeRange.Root', +const TimeSliderRoot: ConnectedComponent = toConnectedComponent( + useTimeSliderRootState, + useTimeSliderRootProps, + renderTimeSliderRoot, + 'TimeSlider.Root', ); // ============================================================================ // TRACK COMPONENT // ============================================================================ -export function useTimeRangeTrackProps(props: React.ComponentProps<'div'>, context: TimeRange.State): TimeRangeRenderProps { +export function useTimeSliderTrackProps(props: React.ComponentProps<'div'>, context: TimeSliderState): TimeSliderRenderProps { return { ref: useCallback((el: HTMLDivElement) => { context.core?.setState({ _trackElement: el }); @@ -110,23 +105,21 @@ export function useTimeRangeTrackProps(props: React.ComponentProps<'div'>, conte }; } -type useTimeRangeTrackProps = typeof useTimeRangeTrackProps; - -export function renderTimeRangeTrack(props: TimeRangeRenderProps): JSX.Element { +export function renderTimeSliderTrack(props: TimeSliderRenderProps): JSX.Element { return
; } -const TimeRangeTrack: ConnectedComponent, typeof renderTimeRangeTrack> = toContextComponent( - useTimeRangeTrackProps, - renderTimeRangeTrack, - 'TimeRange.Track', +const TimeSliderTrack: ConnectedComponent, typeof renderTimeSliderTrack> = toContextComponent( + useTimeSliderTrackProps, + renderTimeSliderTrack, + 'TimeSlider.Track', ); // ============================================================================ // THUMB COMPONENT // ============================================================================ -export function useTimeRangeThumbProps(props: React.ComponentProps<'div'>, context: TimeRange.State): TimeRangeRenderProps { +export function getTimeSliderThumbProps(props: React.ComponentProps<'div'>, context: TimeSliderState): TimeSliderRenderProps { return { 'data-orientation': context.orientation, ...props, @@ -140,23 +133,21 @@ export function useTimeRangeThumbProps(props: React.ComponentProps<'div'>, conte }; } -type useTimeRangeThumbProps = typeof useTimeRangeThumbProps; - -export function renderTimeRangeThumb(props: TimeRangeRenderProps): JSX.Element { +export function renderTimeSliderThumb(props: TimeSliderRenderProps): JSX.Element { return
; } -const TimeRangeThumb: ConnectedComponent, typeof renderTimeRangeThumb> = toContextComponent( - useTimeRangeThumbProps, - renderTimeRangeThumb, - 'TimeRange.Thumb', +const TimeSliderThumb: ConnectedComponent, typeof renderTimeSliderThumb> = toContextComponent( + getTimeSliderThumbProps, + renderTimeSliderThumb, + 'TimeSlider.Thumb', ); // ============================================================================ // POINTER COMPONENT // ============================================================================ -export function useTimeRangePointerProps(props: React.ComponentProps<'div'>, context: TimeRange.State): TimeRangeRenderProps { +export function getTimeSliderPointerProps(props: React.ComponentProps<'div'>, context: TimeSliderState): TimeSliderRenderProps { return { 'data-orientation': context.orientation, ...props, @@ -169,22 +160,20 @@ export function useTimeRangePointerProps(props: React.ComponentProps<'div'>, con }; } -type useTimeRangePointerProps = typeof useTimeRangePointerProps; - -export function renderTimeRangePointer(props: TimeRangeRenderProps): JSX.Element { +export function renderTimeSliderPointer(props: TimeSliderRenderProps): JSX.Element { return
; } -const TimeRangePointer: ConnectedComponent< +const TimeSliderPointer: ConnectedComponent< React.ComponentProps<'div'>, - typeof renderTimeRangePointer -> = toContextComponent(useTimeRangePointerProps, renderTimeRangePointer, 'TimeRange.Pointer'); + typeof renderTimeSliderPointer +> = toContextComponent(getTimeSliderPointerProps, renderTimeSliderPointer, 'TimeSlider.Pointer'); // ============================================================================ // PROGRESS COMPONENT // ============================================================================ -export function useTimeRangeProgressProps(props: React.ComponentProps<'div'>, context: TimeRange.State): TimeRangeRenderProps { +export function getTimeSliderProgressProps(props: React.ComponentProps<'div'>, context: TimeSliderState): TimeSliderRenderProps { return { 'data-orientation': context.orientation, ...props, @@ -198,36 +187,34 @@ export function useTimeRangeProgressProps(props: React.ComponentProps<'div'>, co }; } -type useTimeRangeProgressProps = typeof useTimeRangeProgressProps; - -export function renderTimeRangeProgress(props: TimeRangeRenderProps): JSX.Element { +export function renderTimeSliderProgress(props: TimeSliderRenderProps): JSX.Element { return
; } -const TimeRangeProgress: ConnectedComponent< +const TimeSliderProgress: ConnectedComponent< React.ComponentProps<'div'>, - typeof renderTimeRangeProgress -> = toContextComponent(useTimeRangeProgressProps, renderTimeRangeProgress, 'TimeRange.Progress'); + typeof renderTimeSliderProgress +> = toContextComponent(getTimeSliderProgressProps, renderTimeSliderProgress, 'TimeSlider.Progress'); // ============================================================================ // EXPORTS // ============================================================================ -export const TimeRange = Object.assign( +export const TimeSlider = Object.assign( {}, { - Root: TimeRangeRoot, - Track: TimeRangeTrack, - Thumb: TimeRangeThumb, - Pointer: TimeRangePointer, - Progress: TimeRangeProgress, + Root: TimeSliderRoot, + Track: TimeSliderTrack, + Thumb: TimeSliderThumb, + Pointer: TimeSliderPointer, + Progress: TimeSliderProgress, }, ) as { - Root: typeof TimeRangeRoot; - Track: typeof TimeRangeTrack; - Thumb: typeof TimeRangeThumb; - Pointer: typeof TimeRangePointer; - Progress: typeof TimeRangeProgress; + Root: typeof TimeSliderRoot; + Track: typeof TimeSliderTrack; + Thumb: typeof TimeSliderThumb; + Pointer: typeof TimeSliderPointer; + Progress: typeof TimeSliderProgress; }; -export default TimeRange; +export default TimeSlider; diff --git a/packages/react/react/src/components/VolumeRange.tsx b/packages/react/react/src/components/VolumeSlider.tsx similarity index 54% rename from packages/react/react/src/components/VolumeRange.tsx rename to packages/react/react/src/components/VolumeSlider.tsx index 913a496a..29778c80 100644 --- a/packages/react/react/src/components/VolumeRange.tsx +++ b/packages/react/react/src/components/VolumeSlider.tsx @@ -1,29 +1,27 @@ import type { ConnectedComponent } from '../utils/component-factory'; -import { VolumeRange as CoreVolumeRange } from '@vjs-10/core'; +import { VolumeSlider as CoreVolumeSlider } from '@vjs-10/core'; -import { volumeRangeStateDefinition } from '@vjs-10/media-store'; +import { volumeSliderStateDefinition } from '@vjs-10/media-store'; import { shallowEqual, useMediaSelector, useMediaStore } from '@vjs-10/react-media-store'; import { useCallback, useMemo } from 'react'; import { toConnectedComponent, toContextComponent, useCore } from '../utils/component-factory'; -export namespace VolumeRange { - export interface State { - volume: number; - muted: boolean; - volumeLevel: string; - requestVolumeChange: (volume: number) => void; - core: CoreVolumeRange; - orientation: 'horizontal' | 'vertical'; - } - - export interface Props extends React.ComponentProps<'div'> { - orientation?: 'horizontal' | 'vertical'; - } +export interface VolumeSliderState { + volume: number; + muted: boolean; + volumeLevel: string; + requestVolumeChange: (volume: number) => void; + core: CoreVolumeSlider; + orientation: 'horizontal' | 'vertical'; } -interface VolumeRangeRenderProps extends React.ComponentProps<'div'> { +export interface VolumeSliderProps extends React.ComponentProps<'div'> { + orientation?: 'horizontal' | 'vertical'; +} + +interface VolumeSliderRenderProps extends React.ComponentProps<'div'> { 'data-orientation'?: 'horizontal' | 'vertical'; 'data-muted'?: boolean; 'data-volume-level'?: string; @@ -33,15 +31,15 @@ interface VolumeRangeRenderProps extends React.ComponentProps<'div'> { // ROOT COMPONENT // ============================================================================ -export function useVolumeRangeRootState(props: VolumeRange.Props): VolumeRange.State { +export function useVolumeSliderRootState(props: VolumeSliderProps): VolumeSliderState { const { orientation = 'horizontal' } = props; const mediaStore = useMediaStore(); - const mediaState = useMediaSelector(volumeRangeStateDefinition.stateTransform, shallowEqual); + const mediaState = useMediaSelector(volumeSliderStateDefinition.stateTransform, shallowEqual); const mediaMethods = useMemo( - () => volumeRangeStateDefinition.createRequestMethods(mediaStore.dispatch), + () => volumeSliderStateDefinition.createRequestMethods(mediaStore.dispatch), [mediaStore], ); - const core = useCore(CoreVolumeRange, { ...mediaState, ...mediaMethods }); + const core = useCore(CoreVolumeSlider, { ...mediaState, ...mediaMethods }); return { ...mediaState, @@ -51,7 +49,7 @@ export function useVolumeRangeRootState(props: VolumeRange.Props): VolumeRange.S }; } -export function useVolumeRangeRootProps(props: VolumeRange.Props, state: VolumeRange.State): VolumeRangeRenderProps { +export function useVolumeSliderRootProps(props: VolumeSliderProps, state: VolumeSliderState): VolumeSliderRenderProps { const { _fillWidth, _pointerWidth, _volumeText } = state.core.getState(); const { children, className, id, style, orientation = 'horizontal' } = props; @@ -82,25 +80,22 @@ export function useVolumeRangeRootProps(props: VolumeRange.Props, state: VolumeR }; } -type useVolumeRangeRootState = typeof useVolumeRangeRootState; -type useVolumeRangeRootProps = typeof useVolumeRangeRootProps; - -export function renderVolumeRangeRoot(props: VolumeRangeRenderProps): JSX.Element { +export function renderVolumeSliderRoot(props: VolumeSliderRenderProps): JSX.Element { return
; } -const VolumeRangeRoot: ConnectedComponent = toConnectedComponent( - useVolumeRangeRootState, - useVolumeRangeRootProps, - renderVolumeRangeRoot, - 'VolumeRange.Root', +const VolumeSliderRoot: ConnectedComponent = toConnectedComponent( + useVolumeSliderRootState, + useVolumeSliderRootProps, + renderVolumeSliderRoot, + 'VolumeSlider.Root', ); // ============================================================================ // TRACK COMPONENT // ============================================================================ -export function useVolumeRangeTrackProps(props: React.ComponentProps<'div'>, context: VolumeRange.State): VolumeRangeRenderProps { +export function useVolumeSliderTrackProps(props: React.ComponentProps<'div'>, context: VolumeSliderState): VolumeSliderRenderProps { return { ref: useCallback((el: HTMLDivElement) => { context.core?.setState({ _trackElement: el }); @@ -114,22 +109,20 @@ export function useVolumeRangeTrackProps(props: React.ComponentProps<'div'>, con }; } -type useVolumeRangeTrackProps = typeof useVolumeRangeTrackProps; - -export function renderVolumeRangeTrack(props: VolumeRangeRenderProps): JSX.Element { +export function renderVolumeSliderTrack(props: VolumeSliderRenderProps): JSX.Element { return
; } -const VolumeRangeTrack: ConnectedComponent< +const VolumeSliderTrack: ConnectedComponent< React.ComponentProps<'div'>, - typeof renderVolumeRangeTrack -> = toContextComponent(useVolumeRangeTrackProps, renderVolumeRangeTrack, 'VolumeRange.Track'); + typeof renderVolumeSliderTrack +> = toContextComponent(useVolumeSliderTrackProps, renderVolumeSliderTrack, 'VolumeSlider.Track'); // ============================================================================ // THUMB COMPONENT // ============================================================================ -export function useVolumeRangeThumbProps(props: React.ComponentProps<'div'>, context: VolumeRange.State): VolumeRangeRenderProps { +export function getVolumeSliderThumbProps(props: React.ComponentProps<'div'>, context: VolumeSliderState): VolumeSliderRenderProps { return { 'data-orientation': context.orientation, ...props, @@ -143,22 +136,20 @@ export function useVolumeRangeThumbProps(props: React.ComponentProps<'div'>, con }; } -type useVolumeRangeThumbProps = typeof useVolumeRangeThumbProps; - -export function renderVolumeRangeThumb(props: VolumeRangeRenderProps): JSX.Element { +export function renderVolumeSliderThumb(props: VolumeSliderRenderProps): JSX.Element { return
; } -const VolumeRangeThumb: ConnectedComponent< +const VolumeSliderThumb: ConnectedComponent< React.ComponentProps<'div'>, - typeof renderVolumeRangeThumb -> = toContextComponent(useVolumeRangeThumbProps, renderVolumeRangeThumb, 'VolumeRange.Thumb'); + typeof renderVolumeSliderThumb +> = toContextComponent(getVolumeSliderThumbProps, renderVolumeSliderThumb, 'VolumeSlider.Thumb'); // ============================================================================ // PROGRESS COMPONENT // ============================================================================ -export function useVolumeRangeProgressProps(props: React.ComponentProps<'div'>, context: VolumeRange.State): VolumeRangeRenderProps { +export function getVolumeSliderProgressProps(props: React.ComponentProps<'div'>, context: VolumeSliderState): VolumeSliderRenderProps { return { 'data-orientation': context.orientation, ...props, @@ -172,34 +163,32 @@ export function useVolumeRangeProgressProps(props: React.ComponentProps<'div'>, }; } -type useVolumeRangeProgressProps = typeof useVolumeRangeProgressProps; - -export function renderVolumeRangeProgress(props: VolumeRangeRenderProps): JSX.Element { +export function renderVolumeSliderProgress(props: VolumeSliderRenderProps): JSX.Element { return
; } -const VolumeRangeProgress: ConnectedComponent< +const VolumeSliderProgress: ConnectedComponent< React.ComponentProps<'div'>, - typeof renderVolumeRangeProgress -> = toContextComponent(useVolumeRangeProgressProps, renderVolumeRangeProgress, 'VolumeRange.Progress'); + typeof renderVolumeSliderProgress +> = toContextComponent(getVolumeSliderProgressProps, renderVolumeSliderProgress, 'VolumeSlider.Progress'); // ============================================================================ // EXPORTS // ============================================================================ -export const VolumeRange = Object.assign( +export const VolumeSlider = Object.assign( {}, { - Root: VolumeRangeRoot, - Track: VolumeRangeTrack, - Thumb: VolumeRangeThumb, - Progress: VolumeRangeProgress, + Root: VolumeSliderRoot, + Track: VolumeSliderTrack, + Thumb: VolumeSliderThumb, + Progress: VolumeSliderProgress, }, ) as { - Root: typeof VolumeRangeRoot; - Track: typeof VolumeRangeTrack; - Thumb: typeof VolumeRangeThumb; - Progress: typeof VolumeRangeProgress; + Root: typeof VolumeSliderRoot; + Track: typeof VolumeSliderTrack; + Thumb: typeof VolumeSliderThumb; + Progress: typeof VolumeSliderProgress; }; -export default VolumeRange; +export default VolumeSlider; diff --git a/packages/react/react/src/index.ts b/packages/react/react/src/index.ts index bb8c4071..14493cb2 100644 --- a/packages/react/react/src/index.ts +++ b/packages/react/react/src/index.ts @@ -7,6 +7,6 @@ export { MuteButton } from './components/MuteButton'; export { PlayButton } from './components/PlayButton'; export { Popover } from './components/Popover'; export { MediaElementVideo, Video } from './components/Video'; -export { VolumeRange } from './components/VolumeRange'; +export { VolumeSlider } from './components/VolumeSlider'; export * from './skins'; export * from '@vjs-10/react-media-store'; diff --git a/packages/react/react/src/skins/default/MediaSkinDefault.tsx b/packages/react/react/src/skins/default/MediaSkinDefault.tsx index 507d8897..f19923dc 100644 --- a/packages/react/react/src/skins/default/MediaSkinDefault.tsx +++ b/packages/react/react/src/skins/default/MediaSkinDefault.tsx @@ -19,9 +19,9 @@ import { MediaContainer } from '../../components/MediaContainer'; import MuteButton from '../../components/MuteButton'; import PlayButton from '../../components/PlayButton'; import { Popover } from '../../components/Popover'; -import { TimeRange } from '../../components/TimeRange'; +import { TimeSlider } from '../../components/TimeSlider'; import { Tooltip } from '../../components/Tooltip'; -import { VolumeRange } from '../../components/VolumeRange'; +import { VolumeSlider } from '../../components/VolumeSlider'; import styles from './styles'; type SkinProps = PropsWithChildren<{ @@ -62,13 +62,13 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps className={styles.TimeDisplay} /> - - - - - - - + + + + + + +
@@ -84,12 +84,12 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps - - - - - - + + + + + + diff --git a/packages/react/react/src/skins/default/styles.module.css b/packages/react/react/src/skins/default/styles.module.css index 1d3255c0..46b2424d 100644 --- a/packages/react/react/src/skins/default/styles.module.css +++ b/packages/react/react/src/skins/default/styles.module.css @@ -108,8 +108,8 @@ } } -/* TimeRange Component Styles */ -.TimeRangeRoot { +/* TimeSlider Component Styles */ +.TimeSliderRoot { display: flex; align-items: center; position: relative; @@ -119,7 +119,7 @@ margin: 0 0.5rem; } -.TimeRangeTrack { +.TimeSliderTrack { position: relative; width: 100%; height: 0.375rem; @@ -128,7 +128,7 @@ overflow: hidden; } -.TimeRangeThumb { +.TimeSliderThumb { width: 0.75rem; height: 0.75rem; background-color: #fff; @@ -136,18 +136,18 @@ pointer-events: none; } -.TimeRangePointer { +.TimeSliderPointer { background-color: rgba(255, 255, 255, 0.5); pointer-events: none; } -.TimeRangeProgress { +.TimeSliderProgress { background-color: #007bff; border-radius: inherit; } -/* VolumeRange Component Styles */ -.VolumeRangeRoot { +/* VolumeSlider Component Styles */ +.VolumeSliderRoot { display: flex; align-items: center; position: relative; @@ -157,7 +157,7 @@ margin: 0 0.5rem; } -.VolumeRangeTrack { +.VolumeSliderTrack { position: relative; width: 100%; height: 0.375rem; @@ -166,7 +166,7 @@ overflow: hidden; } -.VolumeRangeThumb { +.VolumeSliderThumb { width: 0.75rem; height: 0.75rem; background-color: #fff; @@ -174,7 +174,7 @@ pointer-events: none; } -.VolumeRangeProgress { +.VolumeSliderProgress { background-color: #007bff; border-radius: inherit; } diff --git a/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx b/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx index 4cb702cc..659c2fa7 100644 --- a/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx +++ b/packages/react/react/src/skins/toasted/MediaSkinToasted.tsx @@ -16,7 +16,7 @@ import { FullscreenButton } from '../../components/FullscreenButton'; import { MediaContainer } from '../../components/MediaContainer'; import MuteButton from '../../components/MuteButton'; import PlayButton from '../../components/PlayButton'; -import { TimeRange } from '../../components/TimeRange'; +import { TimeSlider } from '../../components/TimeSlider'; import styles from './styles'; type SkinProps = PropsWithChildren<{ @@ -46,13 +46,13 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
- - - - - - - + + + + + + +