fix(embedded-mpv): stop native-view video jump by moving menus into the dock

Opening any control popover in the native-view embedded MPV dock used to
shrink the MPV view by a 300 px bottom cutout so the popover DOM stayed
clickable, which made mpv re-letterbox the video on every menu open/close.

All five menus now render horizontally inside the fixed-height controls
strip, so menu state never changes the native view bounds:

- volume expands as an inline horizontal slider next to the mute button
- audio/subtitle/speed/aspect morph the dock row into a back button, a
  panel title, and a scrollable chip ribbon (app-embedded-mpv-dock-panel)
  with wheel-to-horizontal-scroll mapping, edge fades, active-chip
  reveal/focus, roving arrow-key navigation, ellipsis + tooltips, and
  RTL-aware scrolling
- boundsProvider loses the menus.anyOpen() cutout branch and the
  MENU_OPEN_BOTTOM_CUTOUT_PX constant is removed; HIDDEN_BOUNDS for modal
  overlays is unchanged
- global arrow shortcuts (seek/volume) are suspended while a chip panel
  is open so arrows walk the chips; Esc, click-outside, and close-on-select
  semantics are preserved
- new EMBEDDED_MPV.PLAYER.BACK i18n key in all 18 languages

Regression coverage: the new dock-panels spec asserts the bounds provider
returns full host bounds while every menu is open (fails against the old
cutout behavior), plus panel morph/a11y/selection specs and a dedicated
dock-panel component spec (keyboard, wheel, tabindex, emits).

Frame-copy shared controls (app-player-controls) are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5 committed 2026-07-19 07:55:55 +02:00
1 parent 2f8aee72df
commit 4bc6f7e919
35 files changed
+1627 -622

No files matched your search

+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "رجوع",
"RETRY": "إعادة المحاولة",
"STALLED": "يستغرق بدء هذا البث وقتًا أطول من المتوقع.",
"PLAYBACK_FAILED": "فشل التشغيل عبر MPV المضمّن.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "رجوع",
"RETRY": "حاول مرة أخرى",
"STALLED": "هاد البث كياخد وقت كثر من المتوقع باش يبدا.",
"PLAYBACK_FAILED": "فشل التشغيل بـ MPV المدمج.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Назад",
"RETRY": "Паўтарыць",
"STALLED": "Гэты паток запускаецца даўжэй, чым чакалася.",
"PLAYBACK_FAILED": "Не ўдалося прайграць праз убудаваны MPV.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Zurück",
"RETRY": "Erneut versuchen",
"STALLED": "Der Start dieses Streams dauert länger als erwartet.",
"PLAYBACK_FAILED": "Die Wiedergabe mit eingebettetem MPV ist fehlgeschlagen.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Πίσω",
"RETRY": "Επανάληψη",
"STALLED": "Η έναρξη αυτής της ροής καθυστερεί περισσότερο από το αναμενόμενο.",
"PLAYBACK_FAILED": "Η αναπαραγωγή με το ενσωματωμένο MPV απέτυχε.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Back",
"RETRY": "Retry",
"STALLED": "This stream is taking longer than expected to start.",
"PLAYBACK_FAILED": "Embedded MPV playback failed.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Atrás",
"RETRY": "Reintentar",
"STALLED": "Este stream está tardando más de lo esperado en iniciarse.",
"PLAYBACK_FAILED": "Falló la reproducción de MPV integrado.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Retour",
"RETRY": "Réessayer",
"STALLED": "Ce flux met plus de temps que prévu à démarrer.",
"PLAYBACK_FAILED": "Échec de la lecture avec MPV intégré.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Indietro",
"RETRY": "Riprova",
"STALLED": "L'avvio di questo stream sta richiedendo più tempo del previsto.",
"PLAYBACK_FAILED": "Riproduzione con MPV integrato non riuscita.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "戻る",
"RETRY": "再試行",
"STALLED": "このストリームの開始に予想より時間がかかっています。",
"PLAYBACK_FAILED": "組み込みMPVでの再生に失敗しました。",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "뒤로",
"RETRY": "다시 시도",
"STALLED": "이 스트림의 시작이 예상보다 오래 걸리고 있습니다.",
"PLAYBACK_FAILED": "내장 MPV 재생에 실패했습니다.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Terug",
"RETRY": "Opnieuw proberen",
"STALLED": "Deze stream doet er langer over dan verwacht om te starten.",
"PLAYBACK_FAILED": "Afspelen via Embedded MPV is mislukt.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Wstecz",
"RETRY": "Spróbuj ponownie",
"STALLED": "Uruchamianie tego strumienia trwa dłużej niż zwykle.",
"PLAYBACK_FAILED": "Odtwarzanie we wbudowanym MPV nie powiodło się.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Voltar",
"RETRY": "Tentar novamente",
"STALLED": "Este stream está demorando mais do que o esperado para iniciar.",
"PLAYBACK_FAILED": "Falha na reprodução do MPV integrado.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Назад",
"RETRY": "Повторить",
"STALLED": "Запуск этого потока занимает больше времени, чем ожидалось.",
"PLAYBACK_FAILED": "Не удалось воспроизвести через встроенный MPV.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "Geri",
"RETRY": "Tekrar dene",
"STALLED": "Bu yayının başlaması beklenenden uzun sürüyor.",
"PLAYBACK_FAILED": "Gömülü MPV oynatması başarısız oldu.",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "返回",
"RETRY": "重试",
"STALLED": "该流的启动时间超出预期。",
"PLAYBACK_FAILED": "嵌入式 MPV 播放失败。",
+1
View File
@@ -453,6 +453,7 @@
},
"EMBEDDED_MPV": {
"PLAYER": {
"BACK": "返回",
"RETRY": "重試",
"STALLED": "此串流的啟動時間比預期長。",
"PLAYBACK_FAILED": "內嵌 MPV 播放失敗。",