mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
fix(html): slider interaction and edge alignment broken (#721)
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
import { SliderCore, SliderDataAttrs } from '@videojs/core';
|
||||
import { applyStateDataAttrs, createSlider, getSliderCSSVars, type SliderApi } from '@videojs/core/dom';
|
||||
import {
|
||||
applyElementProps,
|
||||
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';
|
||||
@@ -67,8 +73,10 @@ export class SliderElement extends MediaElement {
|
||||
onDragEnd: () => {
|
||||
this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));
|
||||
},
|
||||
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
||||
});
|
||||
|
||||
applyElementProps(this, this.#slider.rootProps, { signal });
|
||||
this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
|
||||
|
||||
// Prevent default touch gestures and text selection during interaction.
|
||||
@@ -95,7 +103,8 @@ export class SliderElement extends MediaElement {
|
||||
|
||||
this.#core.setInput(this.#slider.input.current);
|
||||
const state = this.#core.getSliderState(this.value);
|
||||
const cssVars = getSliderCSSVars(state);
|
||||
|
||||
const cssVars = getSliderCSSVars(this.#slider.adjustForAlignment(state));
|
||||
|
||||
applyStyles(this, cssVars);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { SliderBufferElement } from '../slider-buffer-element';
|
||||
import { SliderElement } from '../slider-element';
|
||||
import { SliderFillElement } from '../slider-fill-element';
|
||||
@@ -107,6 +107,27 @@ describe('SliderElement', () => {
|
||||
expect(slider.style.getPropertyValue('--media-slider-fill')).toBe('75.000%');
|
||||
});
|
||||
|
||||
it('binds rootProps pointer events on connect', async () => {
|
||||
const slider = createElement(SliderElement);
|
||||
slider.value = 0;
|
||||
|
||||
document.body.appendChild(slider);
|
||||
await slider.updateComplete;
|
||||
|
||||
// Stub setPointerCapture/releasePointerCapture (not available in happy-dom).
|
||||
slider.setPointerCapture = vi.fn();
|
||||
slider.releasePointerCapture = vi.fn();
|
||||
|
||||
const spy = vi.fn();
|
||||
slider.addEventListener('value-change', spy);
|
||||
|
||||
// Simulate pointerdown on the slider element.
|
||||
slider.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, pointerId: 1, clientX: 50, clientY: 0 }));
|
||||
|
||||
// pointerdown triggers onValueChange via rootProps.
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('supports vertical orientation', async () => {
|
||||
const slider = createElement(SliderElement);
|
||||
slider.orientation = 'vertical';
|
||||
|
||||
@@ -36,6 +36,20 @@ describe('TimeSliderElement', () => {
|
||||
expect(slider.thumbAlignment).toBe('center');
|
||||
});
|
||||
|
||||
it('binds rootProps pointer events on connect', async () => {
|
||||
const slider = createElement(TimeSliderElement);
|
||||
|
||||
document.body.appendChild(slider);
|
||||
await slider.updateComplete;
|
||||
|
||||
// Without store, slider is disabled — but rootProps should still be bound.
|
||||
// Verify by dispatching pointermove (which does not guard on disabled).
|
||||
slider.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, clientX: 50, clientY: 0 }));
|
||||
|
||||
// No errors thrown means rootProps were bound correctly.
|
||||
expect(slider.isConnected).toBe(true);
|
||||
});
|
||||
|
||||
it('sets touch-action and user-select styles on connect', async () => {
|
||||
const slider = createElement(TimeSliderElement);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { TimeSliderCore, TimeSliderDataAttrs } from '@videojs/core';
|
||||
import {
|
||||
applyElementProps,
|
||||
applyStateDataAttrs,
|
||||
createSlider,
|
||||
getTimeSliderCSSVars,
|
||||
@@ -77,8 +78,10 @@ export class TimeSliderElement extends MediaElement {
|
||||
onDragEnd: () => {
|
||||
this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));
|
||||
},
|
||||
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
||||
});
|
||||
|
||||
applyElementProps(this, this.#slider.rootProps, { signal });
|
||||
this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
|
||||
|
||||
// Prevent default touch gestures and text selection during interaction.
|
||||
@@ -115,7 +118,8 @@ export class TimeSliderElement extends MediaElement {
|
||||
const media = { ...time, ...(buffer ?? { buffered: [], seekable: [] }) };
|
||||
this.#core.setMedia(media);
|
||||
const state = this.#core.getState();
|
||||
const cssVars = getTimeSliderCSSVars(state);
|
||||
|
||||
const cssVars = getTimeSliderCSSVars(this.#slider.adjustForAlignment(state));
|
||||
|
||||
applyStyles(this, cssVars);
|
||||
|
||||
|
||||
@@ -34,6 +34,19 @@ describe('VolumeSliderElement', () => {
|
||||
expect(slider.thumbAlignment).toBe('center');
|
||||
});
|
||||
|
||||
it('binds rootProps pointer events on connect', async () => {
|
||||
const slider = createElement(VolumeSliderElement);
|
||||
|
||||
document.body.appendChild(slider);
|
||||
await slider.updateComplete;
|
||||
|
||||
// Without store, slider is disabled — but rootProps should still be bound.
|
||||
slider.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, clientX: 50, clientY: 0 }));
|
||||
|
||||
// No errors thrown means rootProps were bound correctly.
|
||||
expect(slider.isConnected).toBe(true);
|
||||
});
|
||||
|
||||
it('sets touch-action and user-select styles on connect', async () => {
|
||||
const slider = createElement(VolumeSliderElement);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SliderDataAttrs, VolumeSliderCore } from '@videojs/core';
|
||||
import {
|
||||
applyElementProps,
|
||||
applyStateDataAttrs,
|
||||
createSlider,
|
||||
getSliderCSSVars,
|
||||
@@ -73,8 +74,10 @@ export class VolumeSliderElement extends MediaElement {
|
||||
onDragEnd: () => {
|
||||
this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));
|
||||
},
|
||||
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
||||
});
|
||||
|
||||
applyElementProps(this, this.#slider.rootProps, { signal });
|
||||
this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
|
||||
|
||||
// Prevent default touch gestures and text selection during interaction.
|
||||
@@ -109,7 +112,8 @@ export class VolumeSliderElement extends MediaElement {
|
||||
this.#core.setInput(this.#slider.input.current);
|
||||
this.#core.setMedia(media);
|
||||
const state = this.#core.getState();
|
||||
const cssVars = getSliderCSSVars(state);
|
||||
|
||||
const cssVars = getSliderCSSVars(this.#slider.adjustForAlignment(state));
|
||||
|
||||
applyStyles(this, cssVars);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user