Skip to content

feat: PlayGesture & HotKeys#805

Closed
luwes wants to merge 16 commits intomainfrom
gesture
Closed

feat: PlayGesture & HotKeys#805
luwes wants to merge 16 commits intomainfrom
gesture

Conversation

@luwes
Copy link
Copy Markdown
Collaborator

@luwes luwes commented Mar 10, 2026

Summary

Adds PlayGesture and Hotkeys interaction components.

PlayGesture

Click/tap the video surface to toggle play/pause — modeled as a declarative gesture component. Built on a GestureCorePlayGestureCore abstraction in @videojs/core that keeps the logic runtime-agnostic, with DOM binding (bindGesture) in @videojs/core/dom. Touch events are excluded by default (type="mouse").

Hotkeys

YouTube-style keyboard shortcuts bound to the media container. HotkeysCore maps keys to actions (space/k = play/pause, f = fullscreen, m = mute, arrows = seek/volume, j/l = ±10s seek, </> = playback rate). Modifier keys (Ctrl/Meta/Alt) are ignored, and space only fires when the container itself is focused.

Usage

HTML — drop the custom elements inside a skin template:

<media-container>
  <slot name="media"></slot>

  <media-play-gesture></media-play-gesture>
  <media-hotkeys></media-hotkeys>

  <!-- ...controls... -->
</media-container>

React — render the components inside a <Container>:

import { Container } from '@videojs/react';
import { PlayGesture } from '@videojs/react/ui/play-gesture';
import { Hotkeys } from '@videojs/react/ui/hotkeys';

function VideoSkin({ children }) {
  return (
    <Container className="my-skin">
      {children}

      <PlayGesture />
      <Hotkeys />

      {/* ...controls... */}
    </Container>
  );
}

References

This PR makes progress towards two sub-issues under the gestures epic (#504)

Test plan

  • HotkeysCore unit tests cover all key bindings, modifier exclusion, and edge cases (no media, missing methods)
  • PlayGestureCore unit tests cover play/pause toggling and ended→play restart
  • Manual: click video surface to toggle playback in HTML and React sandboxes
  • Manual: verify keyboard shortcuts (space, k, f, m, arrows, j, l, <, >) in both sandboxes
  • Manual: confirm touch events do not trigger PlayGesture (mouse-only by default)

@luwes luwes self-assigned this Mar 10, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Mar 19, 2026 7:56am

Request Review

@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 10, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 66de82a
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/69bbac27a2060a000830364f
😎 Deploy Preview https://deploy-preview-805--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 10, 2026

📦 Bundle Size Report

🎨 @videojs/html

Path Base PR Diff %
/video/minimal-skin 22.24 kB 22.98 kB +757 B +3.3% 🔺
/video/minimal-skin.tailwind 22.45 kB 23.17 kB +739 B +3.2% 🔺
/video/skin 22.36 kB 23.11 kB +768 B +3.4% 🔺
/video/skin.tailwind 22.71 kB 23.41 kB +714 B +3.1% 🔺
/ui/hotkeys 1.56 kB 🆕
/ui/play-gesture 1.76 kB 🆕
/video (default) 23.17 kB 23.88 kB +729 B +3.1% 🔺
/video (default + hls) 153.69 kB 154.26 kB +588 B +0.4% 🔺
/video (minimal) 23.03 kB 23.75 kB +737 B +3.1% 🔺
/video (minimal + hls) 153.51 kB 154.16 kB +661 B +0.4% 🔺
Presets (7)
Entry Size
/video (default) 23.88 kB
/video (default + hls) 154.26 kB
/video (minimal) 23.75 kB
/video (minimal + hls) 154.16 kB
/audio (default) 21.43 kB
/audio (minimal) 21.40 kB
/background 6.37 kB
Media (5)
Entry Size
/media/background-video 1.03 kB
/media/container 1.59 kB
/media/dash-video 236.04 kB
/media/hls-video 131.57 kB
/media/simple-hls-video 12.33 kB
Players (3)
Entry Size
/video/player 6.23 kB
/audio/player 6.23 kB
/background/player 6.23 kB
Skins (16)
Entry Type Size
/video/minimal-skin.css css 3.11 kB
/video/skin.css css 3.14 kB
/video/minimal-skin js 22.98 kB
/video/minimal-skin.tailwind js 23.17 kB
/video/skin js 23.11 kB
/video/skin.tailwind js 23.41 kB
/audio/minimal-skin.css css 2.25 kB
/audio/skin.css css 2.29 kB
/audio/minimal-skin js 20.61 kB
/audio/minimal-skin.tailwind js 20.64 kB
/audio/skin js 20.63 kB
/audio/skin.tailwind js 20.89 kB
/background/skin.css css 117 B
/background/skin js 1003 B
/base.css css 157 B
/shared.css css 43 B
UI Components (23)
Entry Size
/ui/alert-dialog 2.10 kB
/ui/alert-dialog-close 1.61 kB
/ui/alert-dialog-description 1.50 kB
/ui/alert-dialog-title 1.55 kB
/ui/buffering-indicator 1.81 kB
/ui/captions-button 1.86 kB
/ui/controls 1.62 kB
/ui/fullscreen-button 1.82 kB
/ui/hotkeys 1.56 kB
/ui/mute-button 1.82 kB
/ui/pip-button 1.84 kB
/ui/play-button 1.81 kB
/ui/play-gesture 1.76 kB
/ui/playback-rate-button 1.83 kB
/ui/popover 3.33 kB
/ui/poster 1.71 kB
/ui/seek-button 1.86 kB
/ui/slider 2.01 kB
/ui/thumbnail 2.12 kB
/ui/time 1.65 kB
/ui/time-slider 2.09 kB
/ui/tooltip 2.37 kB
/ui/volume-slider 2.23 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react

Path Base PR Diff %
/video/minimal-skin 18.90 kB 19.60 kB +721 B +3.7% 🔺
/video/skin 18.89 kB 19.57 kB +695 B +3.6% 🔺
/ui/hotkeys 1016 B 🆕
/ui/play-gesture 1.32 kB 🆕
/video (default) 18.94 kB 19.62 kB +690 B +3.6% 🔺
/video (default + hls) 149.81 kB 150.46 kB +674 B +0.4% 🔺
/video (minimal) 18.98 kB 19.67 kB +703 B +3.6% 🔺
/video (minimal + hls) 149.69 kB 150.41 kB +742 B +0.5% 🔺
Presets (7)
Entry Size
/video (default) 19.62 kB
/video (default + hls) 150.46 kB
/video (minimal) 19.67 kB
/video (minimal + hls) 150.41 kB
/audio (default) 14.92 kB
/audio (minimal) 14.98 kB
/background 3.13 kB
Media (4)
Entry Size
/media/background-video 476 B
/media/dash-video 236.19 kB
/media/hls-video 131.59 kB
/media/simple-hls-video 12.34 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 3.11 kB
/video/skin.css css 3.14 kB
/video/minimal-skin js 19.60 kB
/video/minimal-skin.tailwind js 22.03 kB
/video/skin js 19.57 kB
/video/skin.tailwind js 22.11 kB
/audio/minimal-skin.css css 2.25 kB
/audio/skin.css css 2.29 kB
/audio/minimal-skin js 14.93 kB
/audio/minimal-skin.tailwind js 16.98 kB
/audio/skin js 14.89 kB
/audio/skin.tailwind js 17.24 kB
/background/skin.css css 90 B
/background/skin js 272 B
UI Components (20)
Entry Size
/ui/alert-dialog 1.46 kB
/ui/buffering-indicator 1.61 kB
/ui/captions-button 1.70 kB
/ui/controls 1.61 kB
/ui/fullscreen-button 1.69 kB
/ui/hotkeys 1016 B
/ui/mute-button 1.69 kB
/ui/pip-button 1.68 kB
/ui/play-button 1.67 kB
/ui/play-gesture 1.32 kB
/ui/playback-rate-button 1.67 kB
/ui/popover 2.09 kB
/ui/poster 1.49 kB
/ui/seek-button 1.68 kB
/ui/slider 2.28 kB
/ui/thumbnail 1.35 kB
/ui/time 1.22 kB
/ui/time-slider 2.01 kB
/ui/tooltip 1.85 kB
/ui/volume-slider 1.80 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core

Path Base PR Diff %
. 4.80 kB 5.19 kB +401 B +8.2% 🔺
Entries (6)
Entry Size
. 5.19 kB
/dom 8.65 kB
/dom/media/custom-media-element 1.81 kB
/dom/media/dash 235.62 kB
/dom/media/hls 131.27 kB
/dom/media/simple-hls 11.85 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 999 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.32 kB
/html 700 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 1.25 kB
/events 227 B
/function 261 B
/object 119 B
/predicate 265 B
/string 148 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (3)
Entry Size
. 40 B
/dom 10.04 kB
/playback-engine 9.94 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 10, 2026

CI Failure Diagnosis

File Type What failed
packages/react/src/player/create-player.tsx typecheck MediaContainer is imported but never used (TS6196).

Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/html/src/media/container-element.ts Outdated
Comment thread packages/html/src/store/container-mixin.ts
Comment thread packages/react/src/ui/gesture/gesture.tsx Outdated
Comment thread package.json
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new cross-platform “gesture” abstraction (core + React + HTML) and wires it into the default/minimal video skins to toggle playback on pointer interactions, supported by a new useMediaContainer hook in React for container-level event binding.

Changes:

  • Introduces GestureCore in @videojs/core plus initial unit tests.
  • Adds React Gesture component and HTML media-gesture custom element, and includes them in video skin templates/presets.
  • Extends React player context to track the media container (useMediaContainer, container registration in Container).

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/react/src/ui/gesture/index.ts Adds a barrel export for the React Gesture component.
packages/react/src/ui/gesture/gesture.tsx Implements React headless Gesture component that binds pointer events to the media container.
packages/react/src/testing/mocks.tsx Updates test helpers to include container/setContainer in PlayerContextValue.
packages/react/src/presets/video/skin.tsx Installs default gesture behavior into the default React video skin.
packages/react/src/presets/video/minimal-skin.tsx Installs default gesture behavior into the minimal React video skin.
packages/react/src/player/tests/context.test.tsx Updates context tests for extended PlayerContextValue shape.
packages/react/src/player/create-player.tsx Provider now tracks container state and exposes it via context.
packages/react/src/player/context.tsx Adds useMediaContainer and container registration lifecycle in Container.
packages/react/src/media/tests/video.test.tsx Updates PlayerContextValue usage to include container fields.
packages/react/src/media/tests/audio.test.tsx Updates PlayerContextValue usage to include container fields.
packages/react/src/index.ts Exports useMediaContainer and React Gesture from the package entrypoint.
packages/html/src/ui/gesture/gesture-element.ts Adds media-gesture custom element that binds to the player container and forwards events to GestureCore.
packages/html/src/index.ts Exports GestureElement from the HTML package entrypoint.
packages/html/src/define/video/skin.ts Registers gesture element and adds <media-gesture> to the default video skin template.
packages/html/src/define/video/minimal-skin.ts Registers gesture element and adds <media-gesture> to the minimal video skin template.
packages/html/src/define/ui/gesture.ts Adds safeDefine(GestureElement) module for side-effect registration.
packages/html/src/define/background/skin.ts Adjusts background skin slot markup (removes redundant slot="media" attribute).
packages/core/src/core/ui/gesture/tests/gesture-core.test.ts Adds initial unit tests for GestureCore behavior.
packages/core/src/core/ui/gesture/gesture-core.ts Introduces GestureCore, allowed gesture types/commands, and pointer-type handling.
packages/core/src/core/index.ts Re-exports GestureCore from the core package entrypoint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/core/src/core/ui/gesture/tests/gesture-core.test.ts Outdated
Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/core/src/core/ui/gesture/gesture-core.ts Outdated
Comment thread packages/html/src/ui/gesture/gesture-element.ts Outdated
Comment thread packages/react/src/ui/gesture/gesture.tsx Outdated
Comment thread packages/react/src/player/context.tsx
@luwes luwes changed the title feat: add Gesture component / add useMediaContainer feat: PlayGesture & HotKeys & container context Mar 18, 2026
mihar-22 added a commit that referenced this pull request Mar 19, 2026
Refactors the HTML custom element context system from simple setter
callbacks (`mediaAttachContext`, `containerAttachContext`) to richer
context objects that carry both the current value and its setter
(`mediaContext`, `containerContext`). This enables descendant elements
to read the current media/container reference without needing a
separate context.

On the React side, adds `container` to `PlayerContextValue` and
exposes a `useContainer()` hook for accessing the container element.

Extracted from #805.

Co-authored-by: Wesley Luyten <luwes@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mihar-22 added a commit that referenced this pull request Mar 19, 2026
Refactors the HTML custom element context system from simple setter
callbacks (`mediaAttachContext`, `containerAttachContext`) to richer
context objects that carry both the current value and its setter
(`mediaContext`, `containerContext`). This enables descendant elements
to read the current media/container reference without needing a
separate context.

On the React side, adds `container` to `PlayerContextValue` and
exposes a `useContainer()` hook for accessing the container element.

Extracted from #805.

Co-authored-by: Wesley Luyten <luwes@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mihar-22 added a commit that referenced this pull request Mar 19, 2026
Refactors the HTML custom element context system from simple setter
callbacks (`mediaAttachContext`, `containerAttachContext`) to richer
context objects that carry both the current value and its setter
(`mediaContext`, `containerContext`). This enables descendant elements
to read the current media/container reference without needing a
separate context.

On the React side, adds `container` to `PlayerContextValue` and
exposes a `useContainer()` hook for accessing the container element.

Extracted from #805.

Co-authored-by: Wesley Luyten <luwes@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mihar-22 mihar-22 changed the title feat: PlayGesture & HotKeys & container context feat: PlayGesture & HotKeys Mar 19, 2026
@mihar-22
Copy link
Copy Markdown
Member

Closing this PR as we explore the new designs in #1044 and further chunk this work.

@mihar-22 mihar-22 closed this Mar 30, 2026
@mihar-22 mihar-22 deleted the gesture branch April 6, 2026 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants