fix: mobile controls issues (#896)

This commit is contained in:
Wesley Luyten
2026-03-11 16:52:04 -05:00
committed by GitHub
parent 0de0c28123
commit b892cfc261
10 changed files with 19 additions and 16 deletions
@@ -62,9 +62,10 @@ export const controlsFeature = definePlayerFeature({
function onPointerUp(event: PointerEvent) {
if (event.pointerType === 'touch' && Date.now() - pointerDownTime < TAP_THRESHOLD) {
if (get().controlsVisible) {
clearIdle();
set({ userActive: false, controlsVisible: computeVisible(false) });
// If the event target is in the controls don't set inactive because that sets pointer-events: none in CSS.
const isMediaOrContainer = [media, container].includes(event.target as HTMLElement);
if (get().controlsVisible && isMediaOrContainer) {
setInactive();
} else {
setActive();
}
@@ -90,7 +91,9 @@ export const controlsFeature = definePlayerFeature({
listen(container, 'pointerup', onPointerUp, { signal });
listen(container, 'keyup', setActive, { signal });
listen(container, 'focusin', setActive, { signal });
listen(container, 'pointerleave', setInactive, { signal });
// On touch devices pointerleave would fire after a pointerup event which hides the controls.
// https://w3c.github.io/pointerevents/#dfn-pointerup
listen(container, 'mouseleave', setInactive, { signal });
// Media event listeners for playback state changes.
listen(media, 'play', onPlaybackChange, { signal });
@@ -123,22 +123,22 @@ describe('controlsFeature', () => {
expect(store.state.userActive).toBe(true);
});
it('sets inactive immediately on pointerleave', () => {
it('sets inactive immediately on mouseleave', () => {
const video = createMockVideo({ paused: false });
const { store, container } = createPlayerStore(video);
container!.dispatchEvent(new Event('pointerleave'));
container!.dispatchEvent(new Event('mouseleave'));
flush();
expect(store.state.userActive).toBe(false);
expect(store.state.controlsVisible).toBe(false);
});
it('keeps controlsVisible true on pointerleave when paused', () => {
it('keeps controlsVisible true on mouseleave when paused', () => {
const video = createMockVideo({ paused: true });
const { store, container } = createPlayerStore(video);
container!.dispatchEvent(new Event('pointerleave'));
container!.dispatchEvent(new Event('mouseleave'));
flush();
expect(store.state.userActive).toBe(false);