mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
fix(packages): prevent controls click triggering interactions (#1885)
This commit is contained in:
@@ -53,6 +53,13 @@ test.describe('Mouse Gestures', () => {
|
||||
await expect(player.playButton).not.toHaveAttribute(DATA_ATTRS.paused, { timeout: 5_000 });
|
||||
});
|
||||
|
||||
test('click on controls container does not trigger container gesture', async () => {
|
||||
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
||||
await player.controls.dispatchEvent('pointerdown', { button: 0, pointerType: 'mouse' });
|
||||
await player.controls.dispatchEvent('pointerup', { button: 0, pointerType: 'mouse' });
|
||||
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
||||
});
|
||||
|
||||
test('click on slider does not trigger container gesture', async ({ page }) => {
|
||||
// Start playback so the slider has a seekable range
|
||||
await player.play();
|
||||
@@ -91,6 +98,13 @@ test.describe('React Mouse Gestures', () => {
|
||||
await expect(player.playButton).not.toHaveAttribute(DATA_ATTRS.paused, { timeout: 5_000 });
|
||||
});
|
||||
|
||||
test('click on controls container does not trigger container gesture', async () => {
|
||||
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
||||
await player.controls.dispatchEvent('pointerdown', { button: 0, pointerType: 'mouse' });
|
||||
await player.controls.dispatchEvent('pointerup', { button: 0, pointerType: 'mouse' });
|
||||
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
||||
});
|
||||
|
||||
test('click on slider does not trigger container gesture', async ({ page }) => {
|
||||
await player.play();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
@@ -464,6 +464,24 @@ describe('interactive child filtering', () => {
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not fire from any child inside a marked controls surface', () => {
|
||||
const container = setup();
|
||||
const controls = document.createElement('div');
|
||||
const label = document.createElement('span');
|
||||
controls.setAttribute('data-interactive', '');
|
||||
controls.appendChild(label);
|
||||
container.appendChild(controls);
|
||||
|
||||
const handler = vi.fn();
|
||||
createTapGesture(container, handler);
|
||||
|
||||
pointerDown(label);
|
||||
vi.advanceTimersByTime(50);
|
||||
pointerUp(label, { pointerType: 'mouse', clientX: 150 });
|
||||
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fires when event originates from a non-interactive child', () => {
|
||||
const container = setup();
|
||||
const overlay = document.createElement('div');
|
||||
|
||||
@@ -20,6 +20,8 @@ export class ControlsElement extends MediaElement {
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
this.setAttribute('data-interactive', '');
|
||||
|
||||
if (__DEV__ && !this.#mediaState.value && this.#mediaState.displayName) {
|
||||
logMissingFeature(this.localName, this.#mediaState.displayName);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,18 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe('ControlsElement', () => {
|
||||
it('marks the controls surface as interactive', async () => {
|
||||
const provider = document.createElement('test-controls-player-provider') as TestPlayerProviderElement;
|
||||
const controls = createDefinedElement(ControlsElement);
|
||||
|
||||
document.body.append(provider);
|
||||
provider.append(controls);
|
||||
|
||||
await controls.updateComplete;
|
||||
|
||||
expect(controls.hasAttribute('data-interactive')).toBe(true);
|
||||
});
|
||||
|
||||
it('closes owned popovers, menus, and tooltips when controls hide', async () => {
|
||||
const provider = document.createElement('test-controls-player-provider') as TestPlayerProviderElement;
|
||||
const controls = createDefinedElement(ControlsElement);
|
||||
|
||||
@@ -42,7 +42,7 @@ export const ControlsRoot = forwardRef(function ControlsRoot(
|
||||
state,
|
||||
stateAttrMap: ControlsDataAttrs,
|
||||
ref: [forwardedRef],
|
||||
props: [{ children }, elementProps],
|
||||
props: [{ children }, elementProps, { 'data-interactive': '' }],
|
||||
}
|
||||
)}
|
||||
</ControlsContextProvider>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { createPlayerWrapper } from '../../../testing/mocks';
|
||||
import { ControlsRoot } from '../controls-root';
|
||||
|
||||
describe('ControlsRoot', () => {
|
||||
it('marks the controls surface as interactive', () => {
|
||||
const { Wrapper } = createPlayerWrapper({
|
||||
controlsVisible: true,
|
||||
userActive: true,
|
||||
});
|
||||
const { getByTestId } = render(<ControlsRoot data-testid="controls" />, { wrapper: Wrapper });
|
||||
|
||||
expect(getByTestId('controls').hasAttribute('data-interactive')).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user