mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add a solution for React preview time display (#50)
This commit is contained in:
@@ -6,6 +6,7 @@ export interface TimeSliderState extends SliderState {
|
||||
currentTime: number;
|
||||
duration: number;
|
||||
requestSeek: (time: number) => void;
|
||||
requestPreview: (time: number) => void;
|
||||
_currentTimeText: string;
|
||||
_durationText: string;
|
||||
}
|
||||
@@ -70,10 +71,13 @@ export class TimeSlider extends Slider {
|
||||
#handlePointerMove(event: PointerEvent) {
|
||||
super.handleEvent(event);
|
||||
|
||||
const { _dragging, _pointerRatio, duration, requestSeek } = super.getState() as TimeSliderState;
|
||||
const { _dragging, _pointerRatio, duration, requestSeek, requestPreview } = super.getState() as TimeSliderState;
|
||||
|
||||
const previewTime = _pointerRatio * duration;
|
||||
requestPreview(previewTime);
|
||||
|
||||
if (_dragging) {
|
||||
this.#seekingTime = _pointerRatio * duration;
|
||||
this.#seekingTime = previewTime;
|
||||
requestSeek(this.#seekingTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @fileoverview Preview time display component state definition
|
||||
*
|
||||
* This module provides the component state definition for preview time display
|
||||
* components across HTML, React, and React Native platforms. The preview time
|
||||
* display is a read-only component that shows the preview time when hovering
|
||||
* over the time slider.
|
||||
*/
|
||||
|
||||
/**
|
||||
* State interface for preview time display components
|
||||
*/
|
||||
export interface PreviewTimeDisplayState {
|
||||
/** The preview time value in seconds */
|
||||
previewTime: number | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview time display component state definition following VJS-10 patterns.
|
||||
* This provides a read-only display component that shows the preview time.
|
||||
*/
|
||||
export interface PreviewTimeDisplayStateDefinition {
|
||||
keys: (keyof PreviewTimeDisplayState)[];
|
||||
stateTransform: (rawState: any) => PreviewTimeDisplayState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview time display state definition
|
||||
* Defines the core state logic that can be shared between implementations
|
||||
*/
|
||||
export const previewTimeDisplayStateDefinition: PreviewTimeDisplayStateDefinition = {
|
||||
keys: ['previewTime'],
|
||||
stateTransform: (rawState: any) => ({
|
||||
previewTime: rawState.previewTime ?? 0,
|
||||
}),
|
||||
};
|
||||
@@ -1,10 +1,12 @@
|
||||
export interface TimeSliderState {
|
||||
currentTime: number;
|
||||
duration: number;
|
||||
previewTime: number;
|
||||
}
|
||||
|
||||
export interface TimeSliderMethods {
|
||||
requestSeek: (time: number) => void;
|
||||
requestPreview: (time: number) => void;
|
||||
}
|
||||
|
||||
export interface TimeSliderStateDefinition {
|
||||
@@ -18,14 +20,18 @@ export interface TimeSliderStateDefinition {
|
||||
* Defines the core state logic that can be shared between implementations
|
||||
*/
|
||||
export const timeSliderStateDefinition: TimeSliderStateDefinition = {
|
||||
keys: ['currentTime', 'duration'],
|
||||
keys: ['currentTime', 'duration', 'previewTime'],
|
||||
stateTransform: (rawState: any) => ({
|
||||
currentTime: rawState.currentTime ?? 0,
|
||||
duration: rawState.duration ?? 0,
|
||||
previewTime: rawState.previewTime ?? 0,
|
||||
}),
|
||||
createRequestMethods: dispatch => ({
|
||||
requestSeek: (time: number) => {
|
||||
dispatch({ type: 'seekrequest', detail: time });
|
||||
},
|
||||
requestPreview: (time: number) => {
|
||||
dispatch({ type: 'previewrequest', detail: time });
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -41,6 +41,7 @@ export interface StateMediator {
|
||||
currentTime: FacadeProp<HTMLMediaElement['currentTime']>;
|
||||
duration: ReadonlyFacadeProp<HTMLMediaElement['duration']>;
|
||||
seekable: ReadonlyFacadeProp<[number, number] | undefined>;
|
||||
previewTime: FacadeProp<number>;
|
||||
fullscreen: FacadeProp<boolean>;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ export function createMediaStore({
|
||||
}: {
|
||||
media?: any;
|
||||
container?: any;
|
||||
stateMediator: Partial<StateMediator> & Pick<StateMediator, 'paused'>;
|
||||
stateMediator: Partial<StateMediator>;
|
||||
}): MediaStore {
|
||||
const stateOwners: StateOwners = {};
|
||||
const store = map<any>({});
|
||||
@@ -117,16 +118,21 @@ export function createMediaStore({
|
||||
} else if (type === 'containerstateownerchangerequest') {
|
||||
updateStateOwners({ container: detail });
|
||||
} else {
|
||||
for (const stateObject of Object.values(stateMediator).filter(
|
||||
(stateMediatorEntry): stateMediatorEntry is FacadeProp<any, any, any> => 'set' in stateMediatorEntry,
|
||||
)) {
|
||||
const { set, actions } = stateObject;
|
||||
if (actions[type]) {
|
||||
Object.entries(stateMediator).forEach(([stateName, stateObject]) => {
|
||||
const { set, actions } = stateObject as FacadeProp<any, any, any>;
|
||||
|
||||
if (actions?.[type]) {
|
||||
const actionFn = actions[type];
|
||||
const actionValue = actionFn(action);
|
||||
(set as FacadeSetter<any>)(actionValue, stateOwners);
|
||||
if (set) {
|
||||
(set as FacadeSetter<any>)(actionValue, stateOwners);
|
||||
} else {
|
||||
// If there is no setter, store the action value in the store.
|
||||
// Might need revisiting.
|
||||
store.setKey(stateName, actionValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -155,9 +161,10 @@ export function createMediaStore({
|
||||
};
|
||||
}
|
||||
|
||||
function getInitialState(stateMediator: Partial<StateMediator> & Pick<StateMediator, 'paused'>, stateOwners: any) {
|
||||
function getInitialState(stateMediator: Partial<StateMediator>, stateOwners: any) {
|
||||
const initialState: any = {};
|
||||
for (const [stateName, { get }] of Object.entries(stateMediator)) {
|
||||
if (!get) continue;
|
||||
initialState[stateName] = get(stateOwners);
|
||||
}
|
||||
return initialState;
|
||||
|
||||
@@ -3,6 +3,7 @@ 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/preview-time-display';
|
||||
export * from './component-state-definitions/time-slider';
|
||||
export * from './component-state-definitions/volume-slider';
|
||||
export * from './factory';
|
||||
|
||||
@@ -4,11 +4,12 @@ import { createMediaStore as factory } from './factory';
|
||||
import { audible } from './state-mediators/audible';
|
||||
import { fullscreenable } from './state-mediators/fullscreenable';
|
||||
import { playable } from './state-mediators/playable';
|
||||
import { preview } from './state-mediators/preview';
|
||||
import { temporal } from './state-mediators/temporal';
|
||||
|
||||
// Example of default media store with default state mediator definitions. (CJP)
|
||||
// NOTE: We can also change the API to take an array of stateMediators (or either/both) (CJP)
|
||||
const stateMediator = { ...playable, ...audible, ...temporal, ...fullscreenable };
|
||||
const stateMediator = { ...playable, ...audible, ...temporal, ...fullscreenable, ...preview };
|
||||
|
||||
type Params = Partial<Parameters<typeof factory>[0]>;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export { audible } from './audible';
|
||||
export { fullscreenable } from './fullscreenable';
|
||||
export { playable } from './playable';
|
||||
export { preview } from './preview';
|
||||
export { temporal } from './temporal';
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export const preview = {
|
||||
previewTime: {
|
||||
actions: {
|
||||
previewrequest: ({ detail }: Pick<CustomEvent<any>, 'detail'> = { detail: 0 }): number => +detail,
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user