refactor(packages): dry up core, html, and react UI architecture (#699)

This commit is contained in:
rahim
2026-03-03 23:27:53 -08:00
committed by GitHub
parent 8bdd4ce7fa
commit 1edeadefed
110 changed files with 1349 additions and 1359 deletions
@@ -1,10 +1,12 @@
import type { SliderState } from '@videojs/core';
import type { SliderState, StateAttrMap } from '@videojs/core';
import type { SliderThumbProps } from '@videojs/core/dom';
import { createContext } from '@videojs/element/context';
export interface SliderContextValue {
/** Base slider state — children use this for data attributes and value display. */
state: SliderState;
/** Maps state keys to `data-*` attribute names for part elements. */
stateAttrMap: StateAttrMap<SliderState>;
/** Domain value at the current pointer position (e.g., seconds for time, percent for volume). */
pointerValue: number;
/** ARIA attributes for the thumb element (role, tabindex, aria-value*, etc.). */
@@ -1,22 +1,11 @@
import { SliderDataAttrs } from '@videojs/core';
import { applyStateDataAttrs } from '@videojs/core/dom';
import type { PropertyValues } from '@videojs/element';
import type { SliderState } from '@videojs/core';
import { ContextConsumer } from '@videojs/element/context';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { ContextPartElement } from '../context-part-element';
import { sliderContext } from './context';
export class SliderBufferElement extends MediaElement {
export class SliderBufferElement extends ContextPartElement<SliderState> {
static readonly tagName = 'media-slider-buffer';
readonly #ctx = new ContextConsumer(this, {
context: sliderContext,
subscribe: true,
});
protected override update(_changed: PropertyValues): void {
super.update(_changed);
const ctx = this.#ctx.value;
if (ctx) applyStateDataAttrs(this, ctx.state, SliderDataAttrs);
}
protected readonly consumer = new ContextConsumer(this, { context: sliderContext, subscribe: true });
}
+9 -16
View File
@@ -1,11 +1,11 @@
import { SliderCore, SliderDataAttrs } from '@videojs/core';
import { applyStateDataAttrs, createSlider, getSliderCSSVars, type SliderHandle } from '@videojs/core/dom';
import { applyStateDataAttrs, createSlider, getSliderCSSVars, type SliderApi } from '@videojs/core/dom';
import type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';
import { ContextProvider } from '@videojs/element/context';
import { applyStyles, isRTL } from '@videojs/utils/dom';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { sliderContext } from './context';
export class SliderElement extends MediaElement {
static readonly tagName = 'media-slider';
@@ -35,7 +35,7 @@ export class SliderElement extends MediaElement {
readonly #core = new SliderCore();
readonly #provider = new ContextProvider(this, { context: sliderContext });
#slider: SliderHandle | null = null;
#slider: SliderApi | null = null;
#disconnect: AbortController | null = null;
override connectedCallback(): void {
@@ -51,16 +51,8 @@ export class SliderElement extends MediaElement {
isRTL: () => isRTL(this),
isDisabled: () => this.disabled,
getPercent: () => this.#core.percentFromValue(this.value),
getStepPercent: () => {
const { step, min, max } = this.#core.props;
const range = max - min;
return range > 0 ? (step / range) * 100 : 0;
},
getLargeStepPercent: () => {
const { largeStep, min, max } = this.#core.props;
const range = max - min;
return range > 0 ? (largeStep / range) * 100 : 0;
},
getStepPercent: () => this.#core.getStepPercent(),
getLargeStepPercent: () => this.#core.getLargeStepPercent(),
onValueChange: (percent) => {
this.value = this.#core.valueFromPercent(percent);
this.dispatchEvent(new CustomEvent('value-change', { detail: { value: this.value }, bubbles: true }));
@@ -77,7 +69,7 @@ export class SliderElement extends MediaElement {
},
});
this.#slider.interaction.subscribe(() => this.requestUpdate(), { signal });
this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
// Prevent default touch gestures and text selection during interaction.
this.style.touchAction = 'none';
@@ -101,8 +93,8 @@ export class SliderElement extends MediaElement {
super.update(_changed);
if (!this.#slider) return;
const interaction = this.#slider.interaction.current;
const state = this.#core.getState(interaction, this.value);
this.#core.setInput(this.#slider.input.current);
const state = this.#core.getSliderState(this.value);
const cssVars = getSliderCSSVars(state);
applyStyles(this, cssVars);
@@ -113,6 +105,7 @@ export class SliderElement extends MediaElement {
// Provide context to child elements (thumb, value, track, etc.).
this.#provider.setValue({
state,
stateAttrMap: SliderDataAttrs,
pointerValue: this.#core.valueFromPercent(state.pointerPercent),
thumbAttrs: this.#core.getAttrs(state),
thumbProps: this.#slider.thumbProps,
@@ -1,22 +1,11 @@
import { SliderDataAttrs } from '@videojs/core';
import { applyStateDataAttrs } from '@videojs/core/dom';
import type { PropertyValues } from '@videojs/element';
import type { SliderState } from '@videojs/core';
import { ContextConsumer } from '@videojs/element/context';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { ContextPartElement } from '../context-part-element';
import { sliderContext } from './context';
export class SliderFillElement extends MediaElement {
export class SliderFillElement extends ContextPartElement<SliderState> {
static readonly tagName = 'media-slider-fill';
readonly #ctx = new ContextConsumer(this, {
context: sliderContext,
subscribe: true,
});
protected override update(_changed: PropertyValues): void {
super.update(_changed);
const ctx = this.#ctx.value;
if (ctx) applyStateDataAttrs(this, ctx.state, SliderDataAttrs);
}
protected readonly consumer = new ContextConsumer(this, { context: sliderContext, subscribe: true });
}
@@ -1,10 +1,9 @@
import { SliderDataAttrs } from '@videojs/core';
import { applyElementProps, applyStateDataAttrs } from '@videojs/core/dom';
import type { PropertyValues } from '@videojs/element';
import { ContextConsumer } from '@videojs/element/context';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { sliderContext } from './context';
export class SliderThumbElement extends MediaElement {
static readonly tagName = 'media-slider-thumb';
@@ -38,7 +37,7 @@ export class SliderThumbElement extends MediaElement {
// Apply keyboard and focus handlers once — they don't change per slider instance.
if (!this.#thumbPropsApplied && this.#disconnect) {
applyElementProps(this, ctx.thumbProps, this.#disconnect.signal);
applyElementProps(this, ctx.thumbProps, { signal: this.#disconnect.signal });
this.#thumbPropsApplied = true;
}
@@ -46,6 +45,6 @@ export class SliderThumbElement extends MediaElement {
applyElementProps(this, ctx.thumbAttrs);
// Apply state data attributes.
applyStateDataAttrs(this, ctx.state, SliderDataAttrs);
applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
}
}
@@ -1,22 +1,11 @@
import { SliderDataAttrs } from '@videojs/core';
import { applyStateDataAttrs } from '@videojs/core/dom';
import type { PropertyValues } from '@videojs/element';
import type { SliderState } from '@videojs/core';
import { ContextConsumer } from '@videojs/element/context';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { ContextPartElement } from '../context-part-element';
import { sliderContext } from './context';
export class SliderTrackElement extends MediaElement {
export class SliderTrackElement extends ContextPartElement<SliderState> {
static readonly tagName = 'media-slider-track';
readonly #ctx = new ContextConsumer(this, {
context: sliderContext,
subscribe: true,
});
protected override update(_changed: PropertyValues): void {
super.update(_changed);
const ctx = this.#ctx.value;
if (ctx) applyStateDataAttrs(this, ctx.state, SliderDataAttrs);
}
protected readonly consumer = new ContextConsumer(this, { context: sliderContext, subscribe: true });
}
@@ -1,10 +1,9 @@
import { SliderDataAttrs } from '@videojs/core';
import { applyStateDataAttrs } from '@videojs/core/dom';
import type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';
import { ContextConsumer } from '@videojs/element/context';
import { MediaElement } from '../media-element';
import { sliderContext } from './slider-context';
import { sliderContext } from './context';
export class SliderValueElement extends MediaElement {
static readonly tagName = 'media-slider-value';
@@ -35,6 +34,6 @@ export class SliderValueElement extends MediaElement {
this.textContent = ctx.formatValue ? ctx.formatValue(value, this.type) : String(Math.round(value));
applyStateDataAttrs(this, ctx.state, SliderDataAttrs);
applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
}
}