Skip to content

feat(core): add vimeo media host and html/react components#1667

Merged
luwes merged 3 commits into
mainfrom
feat/vimeo-media-host
Jun 17, 2026
Merged

feat(core): add vimeo media host and html/react components#1667
luwes merged 3 commits into
mainfrom
feat/vimeo-media-host

Conversation

@luwes

@luwes luwes commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Ported from #1620

Refs #1435
Refs #1538

Summary

Adds Vimeo as a first-class media source on the current media stack. A VimeoMedia host wraps @vimeo/player behind the standard Video surface, with HTML (vimeo-video) and React (VimeoVideo) components and sandbox demos.

This re-ports #1620 onto the current HTMLMediaElementHost + attach/detach architecture (the original PR targeted the MediaLayer/extension design).

Changes

  • VimeoMedia core host: wraps @vimeo/player, maps player events to the standard media API (play/pause, time, volume, fullscreen, PiP, text tracks), and parses ids/URLs including unlisted h hashes and live events. Driven via attach(iframe) / detach() to match how hosts are wired here.
  • Played-range tracking reimplemented as a class mixin (MediaPlayedRangesMixin) rather than a layer/extension, so iframe-based hosts expose a TimeRanges-like played.
  • CustomMediaElement gains minimal iframe-embed support: keep host-bound attrs (e.g. src) in the template, and skip mirroring attributes / track / source syncing onto the iframe.
  • escapeHtml util to secure the iframe src in templates.
  • Sandbox vimeo-video preset with HTML/React templates and shell wiring (no Tailwind skin variant, source picker disabled).
Architecture notes
  • VimeoMedia extends MediaPlayedRangesMixin(EventTarget) implements Video. It's a leaf host with no native <video> target — the target is the <iframe> the player binds to.
  • Did not port the original PR's lazy host-recreation / upgradeProperty reconnect rewrite of CustomMediaElement, since that lifecycle is shared by all media hosts; Vimeo follows the same construct-on-create / destroy-on-disconnect lifecycle as the others.
  • Settles the loadComplete gate on player error so play() / fullscreen / PiP do not hang on load failure.

Testing

  • pnpm -F @videojs/core test src/dom/media/vimeo src/dom/media/media-played-ranges
  • Full core / utils / html / react suites pass; pnpm typecheck and pnpm check:workspace clean for touched files.
  • Sandbox: open the HTML and React Vimeo Video demos.

Note

Medium Risk
Touches shared CustomMediaElement behavior for all iframe-based embeds and adds a new third-party dependency; playback and load-failure handling are security- and UX-sensitive but covered by tests.

Overview
Adds Vimeo as a first-class embed source: a VimeoMedia host wraps @vimeo/player and exposes the standard media API via attach(iframe) / detach(), with URL parsing (unlisted h, live events) and iframe embed URL building.

MediaPlayedRangesMixin supplies a TimeRanges-like played for hosts without native HTMLMediaElement.played. CustomMediaElement is extended for iframe embeds: keep src (and similar) in the shadow template, skip attribute mirroring and track/source sync, and set data-cross-origin-frame on connect.

Ships vimeo-video / VimeoVideo (HTML + React), useAttachIframe, escapeHtml for safe iframe src, sandbox vimeo-video preset (fixed Vimeo URL, no Tailwind, source picker off), and unit tests for Vimeo, played ranges, and iframe custom elements.

Reviewed by Cursor Bugbot for commit bf93da5. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify

netlify Bot commented Jun 5, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit bf93da5
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a32f04f1f87de000817a04b
😎 Deploy Preview https://deploy-preview-1667--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Jun 17, 2026 7:07pm

Request Review

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html

Path Base PR Diff %
/media/vimeo-video 12.32 kB 🆕
Presets (7)
Entry Size
/video (default) 41.80 kB
/video (default + hls) 181.33 kB
/video (minimal) 41.46 kB
/video (minimal + hls) 181.04 kB
/audio (default) 35.62 kB
/audio (minimal) 32.88 kB
/background 4.22 kB
Media (10)
Entry Size
/media/background-video 1.07 kB
/media/container 1.72 kB
/media/dash-video 242.77 kB
/media/hls-video 141.13 kB
/media/mux-audio 163.62 kB
/media/mux-video 163.67 kB
/media/native-hls-video 9.00 kB
/media/simple-hls-audio-only 16.94 kB
/media/simple-hls-video 18.80 kB
/media/vimeo-video 12.32 kB
Players (5)
Entry Size
/video/player 7.61 kB
/audio/player 5.39 kB
/background/player 3.92 kB
/live-video/player 7.63 kB
/live-audio/player 5.40 kB
Skins (30)
Entry Type Size
/video/minimal-skin.css css 5.23 kB
/video/skin.css css 5.19 kB
/video/minimal-skin js 41.46 kB
/video/minimal-skin.tailwind js 41.95 kB
/video/skin js 41.78 kB
/video/skin.tailwind js 42.21 kB
/audio/minimal-skin.css css 3.45 kB
/audio/skin.css css 3.36 kB
/audio/minimal-skin js 32.92 kB
/audio/minimal-skin.tailwind js 33.22 kB
/audio/skin js 35.70 kB
/audio/skin.tailwind js 36.02 kB
/background/skin.css css 133 B
/background/skin js 1.16 kB
/live-video/minimal-skin.css css 5.23 kB
/live-video/skin.css css 5.19 kB
/live-video/minimal-skin js 40.88 kB
/live-video/minimal-skin.tailwind js 41.25 kB
/live-video/skin js 40.86 kB
/live-video/skin.tailwind js 41.13 kB
/live-audio/minimal-skin.css css 3.45 kB
/live-audio/skin.css css 3.36 kB
/live-audio/minimal-skin js 27.17 kB
/live-audio/minimal-skin.tailwind js 26.64 kB
/live-audio/skin js 29.61 kB
/live-audio/skin.tailwind js 29.19 kB
/global.css css 176 B
/shared.css css 88 B
/tailwind.css css 228 B
/skin-element js 1.37 kB
UI Components (37)
Entry Size
/ui/airplay-button 2.92 kB
/ui/alert-dialog 1.27 kB
/ui/alert-dialog-close 558 B
/ui/alert-dialog-description 448 B
/ui/alert-dialog-title 450 B
/ui/buffering-indicator 2.79 kB
/ui/captions-button 2.96 kB
/ui/captions-radio-group 2.21 kB
/ui/cast-button 2.87 kB
/ui/compounds 8.22 kB
/ui/controls 2.19 kB
/ui/error-dialog 3.25 kB
/ui/fullscreen-button 2.91 kB
/ui/hotkey 2.04 kB
/ui/menu 5.38 kB
/ui/mute-button 2.96 kB
/ui/pip-button 2.88 kB
/ui/play-button 2.88 kB
/ui/playback-rate-button 2.93 kB
/ui/playback-rate-radio-group 2.18 kB
/ui/popover 2.10 kB
/ui/poster 2.59 kB
/ui/seek-button 2.87 kB
/ui/seek-indicator 3.76 kB
/ui/seek-indicator-value 241 B
/ui/slider 1.50 kB
/ui/status-announcer 3.39 kB
/ui/status-indicator 3.48 kB
/ui/status-indicator-value 272 B
/ui/thumbnail 3.16 kB
/ui/time 1.99 kB
/ui/time-slider 2.90 kB
/ui/tooltip 2.23 kB
/ui/volume-indicator 3.67 kB
/ui/volume-indicator-fill 222 B
/ui/volume-indicator-value 222 B
/ui/volume-slider 3.67 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react

Path Base PR Diff %
/media/vimeo-video 10.58 kB 🆕
Presets (7)
Entry Size
/video (default) 34.72 kB
/video (default + hls) 172.88 kB
/video (minimal) 34.77 kB
/video (minimal + hls) 173.08 kB
/audio (default) 28.43 kB
/audio (minimal) 28.51 kB
/background 754 B
Media (9)
Entry Size
/media/background-video 575 B
/media/dash-video 241.20 kB
/media/hls-video 139.64 kB
/media/mux-audio 162.30 kB
/media/mux-video 162.33 kB
/media/native-hls-video 7.41 kB
/media/simple-hls-audio-only 15.40 kB
/media/simple-hls-video 17.20 kB
/media/vimeo-video 10.58 kB
Skins (27)
Entry Type Size
/tailwind.css css 228 B
/video/minimal-skin.css css 5.14 kB
/video/skin.css css 5.10 kB
/video/minimal-skin js 34.69 kB
/video/minimal-skin.tailwind js 40.13 kB
/video/skin js 34.63 kB
/video/skin.tailwind js 39.99 kB
/audio/minimal-skin.css css 3.32 kB
/audio/skin.css css 3.23 kB
/audio/minimal-skin js 28.45 kB
/audio/minimal-skin.tailwind js 28.91 kB
/audio/skin js 28.36 kB
/audio/skin.tailwind js 31.97 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 5.14 kB
/live-video/skin.css css 5.10 kB
/live-video/minimal-skin js 30.93 kB
/live-video/minimal-skin.tailwind js 36.15 kB
/live-video/skin js 30.88 kB
/live-video/skin.tailwind js 36.14 kB
/live-audio/minimal-skin.css css 3.32 kB
/live-audio/skin.css css 3.23 kB
/live-audio/minimal-skin js 20.94 kB
/live-audio/minimal-skin.tailwind js 23.71 kB
/live-audio/skin js 20.96 kB
/live-audio/skin.tailwind js 23.77 kB
UI Components (31)
Entry Size
/ui/airplay-button 2.87 kB
/ui/alert-dialog 1.21 kB
/ui/buffering-indicator 2.60 kB
/ui/captions-button 2.86 kB
/ui/captions-radio-group 2.58 kB
/ui/cast-button 2.88 kB
/ui/controls 2.52 kB
/ui/error-dialog 2.49 kB
/ui/fullscreen-button 2.83 kB
/ui/gesture 2.05 kB
/ui/hotkey 2.65 kB
/ui/live-button 2.78 kB
/ui/menu 5.53 kB
/ui/mute-button 2.94 kB
/ui/pip-button 2.88 kB
/ui/play-button 2.89 kB
/ui/playback-rate 2.54 kB
/ui/playback-rate-button 2.83 kB
/ui/popover 2.42 kB
/ui/poster 2.43 kB
/ui/seek-button 2.91 kB
/ui/seek-indicator 2.06 kB
/ui/slider 4.38 kB
/ui/status-announcer 1.85 kB
/ui/status-indicator 1.96 kB
/ui/thumbnail 2.76 kB
/ui/time 2.66 kB
/ui/time-slider 3.98 kB
/ui/tooltip 2.63 kB
/ui/volume-indicator 2.05 kB
/ui/volume-slider 3.40 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core

Path Base PR Diff %
/dom/media/media-played-ranges 576 B 🆕
/dom/media/vimeo 9.86 kB 🆕
Entries (13)
Entry Size
. 7.94 kB
/dom 16.40 kB
/dom/media/custom-media-element 2.05 kB
/dom/media/dash 236.79 kB
/dom/media/google-cast 4.04 kB
/dom/media/hls 135.58 kB
/dom/media/media-host 1.31 kB
/dom/media/media-played-ranges 576 B
/dom/media/mux 151.26 kB
/dom/media/native-hls 3.02 kB
/dom/media/simple-hls 16.56 kB
/dom/media/simple-hls-audio-only 14.74 kB
/dom/media/vimeo 9.86 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 996 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.39 kB
/html 696 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 2.22 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/string 232 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (4)
Entry Size
. 4.45 kB
/dom 6.33 kB
/hls 15.44 kB
/background-looping-video 12.95 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.

Comment thread packages/core/src/dom/media/vimeo/index.ts
Comment thread packages/core/src/dom/media/vimeo/index.ts
Comment thread packages/html/src/media/vimeo-video/index.ts
Comment thread packages/core/src/dom/media/vimeo/index.ts
luwes added 3 commits June 13, 2026 09:30
Add referrerPolicy support to Vimeo embeds, extract a shared

useAttachIframe hook for React, and trim the public surface of VimeoMedia.
Standardizes the attribute name (was the misspelled data-cross-origin-iframe)

so skins can disable backdrop-filter over cross-origin embeds.
Comment thread packages/html/src/define/global.css Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bf93da5. Configure here.

Comment thread packages/core/src/dom/media/vimeo/index.ts
@luwes luwes requested a review from sampotts June 17, 2026 19:29
@luwes luwes merged commit 1b31f3e into main Jun 17, 2026
26 checks passed
@luwes luwes deleted the feat/vimeo-media-host branch June 17, 2026 23:36
@luwes luwes mentioned this pull request Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants