mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
refactor(packages): dry up core, html, and react UI architecture (#699)
This commit is contained in:
@@ -12,9 +12,9 @@ import { TimeSliderRoot } from '../time-slider-root';
|
||||
|
||||
// --- Hoisted mock data (available inside vi.mock factories) ---
|
||||
|
||||
const { mockSliderHandle, mockTimeState, mockBufferState } = vi.hoisted(() => ({
|
||||
mockSliderHandle: () => ({
|
||||
interaction: {
|
||||
const { mockSliderApi, mockTimeState, mockBufferState } = vi.hoisted(() => ({
|
||||
mockSliderApi: () => ({
|
||||
input: {
|
||||
current: {
|
||||
pointerPercent: 0,
|
||||
dragPercent: 0,
|
||||
@@ -52,7 +52,7 @@ const { mockSliderHandle, mockTimeState, mockBufferState } = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@videojs/core/dom', async (importOriginal) => {
|
||||
const orig: Record<string, unknown> = await importOriginal();
|
||||
return { ...orig, createSlider: vi.fn(mockSliderHandle) };
|
||||
return { ...orig, createSlider: vi.fn(mockSliderApi) };
|
||||
});
|
||||
|
||||
vi.mock('@videojs/store/react', () => ({
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
import { TimeSliderCore, TimeSliderDataAttrs } from '@videojs/core';
|
||||
import { getTimeSliderCSSVars, logMissingFeature, selectBuffer, selectTime } from '@videojs/core/dom';
|
||||
import { formatTime } from '@videojs/utils/time';
|
||||
import { forwardRef, useRef, useState } from 'react';
|
||||
import { forwardRef, useState } from 'react';
|
||||
|
||||
import { usePlayer } from '../../player/context';
|
||||
import type { UIComponentProps } from '../../utils/types';
|
||||
import { useLatestRef } from '../../utils/use-latest-ref';
|
||||
import { renderElement } from '../../utils/use-render';
|
||||
import { useSlider } from '../hooks/use-slider';
|
||||
import { SliderProvider } from '../slider/slider-context';
|
||||
import { SliderProvider } from '../slider/context';
|
||||
|
||||
const noopSeek = (): Promise<number> => Promise.resolve(0);
|
||||
|
||||
@@ -46,65 +46,38 @@ export const TimeSliderRoot = forwardRef<HTMLDivElement, TimeSliderRootProps>(
|
||||
// Keep a ref to the latest media state for callbacks that fire outside the render cycle.
|
||||
const mediaRef = useLatestRef(time && buffer ? { ...time, ...buffer } : null);
|
||||
|
||||
// Holds the target time (seconds) between commit and seek completion, preventing the slider
|
||||
// from snapping back to the stale `currentTime` while the async seek settles.
|
||||
const pendingSeekRef = useRef<number | null>(null);
|
||||
|
||||
const duration = time?.duration ?? 0;
|
||||
const range = duration || 1;
|
||||
|
||||
const { state, cssVars, rootRef, thumbRef, rootProps, thumbProps } = useSlider<TimeSliderCore.State>({
|
||||
computeState: (interaction) => {
|
||||
computeState: (input) => {
|
||||
core.setInput(input);
|
||||
if (!time || !buffer) {
|
||||
return core.getTimeState(
|
||||
{ currentTime: 0, duration: 0, seeking: false, seek: noopSeek, buffered: [], seekable: [] },
|
||||
interaction
|
||||
);
|
||||
core.setMedia({
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
seeking: false,
|
||||
seek: noopSeek,
|
||||
buffered: [],
|
||||
seekable: [],
|
||||
});
|
||||
} else {
|
||||
core.setMedia({ ...time, ...buffer });
|
||||
}
|
||||
|
||||
const baseState = core.getTimeState({ ...time, ...buffer }, interaction);
|
||||
|
||||
// After drag release, `dragging` resets before the async seek completes. Hold the
|
||||
// slider at the committed position until `currentTime` catches up.
|
||||
const pending = pendingSeekRef.current;
|
||||
if (!interaction.dragging && pending !== null) {
|
||||
if (Math.abs(time.currentTime - pending) < 0.5) {
|
||||
// Seek landed — clear pending.
|
||||
pendingSeekRef.current = null;
|
||||
} else {
|
||||
const dur = time.duration || 1;
|
||||
const fillPercent = (pending / dur) * 100;
|
||||
return { ...baseState, value: pending, fillPercent };
|
||||
}
|
||||
}
|
||||
|
||||
return baseState;
|
||||
return core.getState();
|
||||
},
|
||||
getPercent: () => (duration > 0 ? ((time?.currentTime ?? 0) / duration) * 100 : 0),
|
||||
getStepPercent: () => (step / range) * 100,
|
||||
getLargeStepPercent: () => (largeStep / range) * 100,
|
||||
getStepPercent: () => core.getStepPercent(),
|
||||
getLargeStepPercent: () => core.getLargeStepPercent(),
|
||||
orientation,
|
||||
disabled,
|
||||
commitThrottle,
|
||||
adjustPercent: (rawPercent, thumbSize, trackSize) =>
|
||||
core.adjustPercentForAlignment(rawPercent, thumbSize, trackSize),
|
||||
getCSSVars: getTimeSliderCSSVars,
|
||||
onValueChange: (percent) => {
|
||||
// Track the target position for visual hold during pointer interaction.
|
||||
const media = mediaRef.current;
|
||||
if (media) {
|
||||
pendingSeekRef.current = (percent / 100) * (media.duration || 0);
|
||||
}
|
||||
},
|
||||
onValueCommit: (percent) => {
|
||||
const media = mediaRef.current;
|
||||
if (!media) return;
|
||||
const seconds = (percent / 100) * (media.duration || 0);
|
||||
pendingSeekRef.current = seconds;
|
||||
// seek() is async — catch rejection if the media target isn't attached yet.
|
||||
media.seek(seconds).catch(() => {
|
||||
pendingSeekRef.current = null;
|
||||
});
|
||||
if (media) media.seek(core.valueFromPercent(percent));
|
||||
},
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
|
||||
Reference in New Issue
Block a user