avbridge 2.8.1 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +14 -2
- package/dist/player.cjs +32 -1
- package/dist/player.cjs.map +1 -1
- package/dist/player.d.cts +2 -1
- package/dist/player.d.ts +2 -1
- package/dist/player.js +32 -1
- package/dist/player.js.map +1 -1
- package/package.json +1 -1
- package/src/element/avbridge-player.ts +43 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to **avbridge.js** are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.8.2]
|
|
8
|
+
|
|
9
|
+
Small ergonomics release driven by downstream `<avbridge-player>`
|
|
10
|
+
consumer feedback.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Opt-in "Fit" entry in the `<avbridge-player>` settings menu.** Set
|
|
15
|
+
the new `show-fit` attribute on `<avbridge-player>` and the settings
|
|
16
|
+
menu gains a Fit section with Contain / Cover / Fill choices; picking
|
|
17
|
+
one writes the `fit` attribute (which proxies through to the inner
|
|
18
|
+
`<avbridge-video>`). Off by default — chromeless consumers don't get
|
|
19
|
+
a surprise entry.
|
|
20
|
+
- **`data-visible="true|false"` on `part="toolbar-top"`.** Mirrors the
|
|
21
|
+
controls auto-hide state so slotted toolbar buttons can drive JS
|
|
22
|
+
behavior (focus management, screen-reader announcements, disabling
|
|
23
|
+
clicks) without listening to the host's `data-controls-hidden`. The
|
|
24
|
+
existing CSS fade on opacity is unchanged.
|
|
25
|
+
|
|
7
26
|
## [2.8.1]
|
|
8
27
|
|
|
9
28
|
Cross-browser playback validation — second slice of the v2.7.0 Playwright
|
package/README.md
CHANGED
|
@@ -343,15 +343,21 @@ Both support:
|
|
|
343
343
|
|
|
344
344
|
`<avbridge-player>` also exposes `top-left` and `top-right` slots
|
|
345
345
|
inside its auto-hiding top chrome for consumer buttons (back, title,
|
|
346
|
-
translate, etc.)
|
|
346
|
+
translate, etc.), and an opt-in `show-fit` attribute that adds a
|
|
347
|
+
Contain / Cover / Fill entry to the settings menu:
|
|
347
348
|
|
|
348
349
|
```html
|
|
349
|
-
<avbridge-player src="/video.mkv" fit="cover">
|
|
350
|
+
<avbridge-player src="/video.mkv" fit="cover" show-fit>
|
|
350
351
|
<button slot="top-left">← Back</button>
|
|
351
352
|
<button slot="top-right">Translate</button>
|
|
352
353
|
</avbridge-player>
|
|
353
354
|
```
|
|
354
355
|
|
|
356
|
+
The toolbar-top `part` exposes a `data-visible="true|false"`
|
|
357
|
+
attribute mirroring the controls auto-hide state — useful if slotted
|
|
358
|
+
buttons need to drive JS behavior (focus, announcements) in sync with
|
|
359
|
+
the fade, not just CSS opacity.
|
|
360
|
+
|
|
355
361
|
This is a second tsup entry (`dist/element-browser.js`) that inlines
|
|
356
362
|
mediabunny + libavjs-webcodecs-bridge into a single ~1.3 MB file with
|
|
357
363
|
zero bare specifiers at runtime. Perfect for self-hosted tools or static
|
|
@@ -401,6 +407,12 @@ LGPL compliance — see [`NOTICE.md`](./NOTICE.md) and
|
|
|
401
407
|
|
|
402
408
|
## Demos
|
|
403
409
|
|
|
410
|
+
Try it live: **https://keishi.github.io/avbridge/** — player + converter
|
|
411
|
+
running against the latest release, served from GitHub Pages with the
|
|
412
|
+
COOP/COEP headers needed for SharedArrayBuffer.
|
|
413
|
+
|
|
414
|
+
Or run locally:
|
|
415
|
+
|
|
404
416
|
```bash
|
|
405
417
|
npm install
|
|
406
418
|
npm run demo
|
package/dist/player.cjs
CHANGED
|
@@ -5144,8 +5144,10 @@ var PROXY_ATTRIBUTES = [
|
|
|
5144
5144
|
"preferstrategy",
|
|
5145
5145
|
"fit"
|
|
5146
5146
|
];
|
|
5147
|
+
var PLAYER_ATTRIBUTES = ["show-fit"];
|
|
5148
|
+
var FIT_MODES = ["contain", "cover", "fill"];
|
|
5147
5149
|
var AvbridgePlayerElement = class extends HTMLElement {
|
|
5148
|
-
static observedAttributes = [...PROXY_ATTRIBUTES];
|
|
5150
|
+
static observedAttributes = [...PROXY_ATTRIBUTES, ...PLAYER_ATTRIBUTES];
|
|
5149
5151
|
// ── Internal DOM refs ──────────────────────────────────────────────────
|
|
5150
5152
|
_video;
|
|
5151
5153
|
_playBtn;
|
|
@@ -5182,6 +5184,7 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5182
5184
|
_eventCleanup = [];
|
|
5183
5185
|
_updateToolbarEmpty = () => {
|
|
5184
5186
|
};
|
|
5187
|
+
_toolbarTop;
|
|
5185
5188
|
// ── Constructor ────────────────────────────────────────────────────────
|
|
5186
5189
|
constructor() {
|
|
5187
5190
|
super();
|
|
@@ -5205,6 +5208,8 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5205
5208
|
this._statsEl = shadow.querySelector(".avp-stats");
|
|
5206
5209
|
this._rippleLeft = shadow.querySelector(".avp-ripple-left");
|
|
5207
5210
|
this._rippleRight = shadow.querySelector(".avp-ripple-right");
|
|
5211
|
+
this._toolbarTop = shadow.querySelector('[part="toolbar-top"]');
|
|
5212
|
+
this._toolbarTop.setAttribute("data-visible", "true");
|
|
5208
5213
|
const slots = shadow.querySelectorAll('slot[name="top-left"], slot[name="top-right"]');
|
|
5209
5214
|
this._updateToolbarEmpty = () => {
|
|
5210
5215
|
const hasContent = Array.from(slots).some((s) => s.assignedNodes({ flatten: true }).length > 0);
|
|
@@ -5388,6 +5393,12 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5388
5393
|
}
|
|
5389
5394
|
attributeChangedCallback(name, _old, value) {
|
|
5390
5395
|
if (!this._video) return;
|
|
5396
|
+
if (PLAYER_ATTRIBUTES.includes(name)) {
|
|
5397
|
+
if (name === "show-fit" && this._settingsOpen) {
|
|
5398
|
+
this._buildSettingsMenu();
|
|
5399
|
+
}
|
|
5400
|
+
return;
|
|
5401
|
+
}
|
|
5391
5402
|
if (value == null) this._video.removeAttribute(name);
|
|
5392
5403
|
else this._video.setAttribute(name, value);
|
|
5393
5404
|
}
|
|
@@ -5510,6 +5521,16 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5510
5521
|
}
|
|
5511
5522
|
_buildSettingsMenu() {
|
|
5512
5523
|
const sections = [];
|
|
5524
|
+
if (this.hasAttribute("show-fit")) {
|
|
5525
|
+
const currentFit = this._video.fit ?? "contain";
|
|
5526
|
+
let fitItems = "";
|
|
5527
|
+
for (const mode of FIT_MODES) {
|
|
5528
|
+
const active = mode === currentFit;
|
|
5529
|
+
const label = mode[0].toUpperCase() + mode.slice(1);
|
|
5530
|
+
fitItems += `<div class="avp-settings-item${active ? " active" : ""}" data-fit="${mode}">${label}</div>`;
|
|
5531
|
+
}
|
|
5532
|
+
sections.push(`<div class="avp-settings-section"><div class="avp-settings-label">Fit</div>${fitItems}</div>`);
|
|
5533
|
+
}
|
|
5513
5534
|
const currentRate = this._video.playbackRate ?? 1;
|
|
5514
5535
|
let speedItems = "";
|
|
5515
5536
|
for (const spd of PLAYBACK_SPEEDS) {
|
|
@@ -5536,6 +5557,14 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5536
5557
|
}
|
|
5537
5558
|
sections.push(`<div class="avp-settings-section"><div class="avp-settings-item" data-stats>Stats for nerds</div></div>`);
|
|
5538
5559
|
this._settingsMenu.innerHTML = sections.join("");
|
|
5560
|
+
for (const item of this._settingsMenu.querySelectorAll("[data-fit]")) {
|
|
5561
|
+
item.addEventListener("click", (e) => {
|
|
5562
|
+
e.stopPropagation();
|
|
5563
|
+
const mode = item.dataset.fit;
|
|
5564
|
+
this.setAttribute("fit", mode);
|
|
5565
|
+
this._buildSettingsMenu();
|
|
5566
|
+
});
|
|
5567
|
+
}
|
|
5539
5568
|
for (const item of this._settingsMenu.querySelectorAll("[data-speed]")) {
|
|
5540
5569
|
item.addEventListener("click", (e) => {
|
|
5541
5570
|
e.stopPropagation();
|
|
@@ -5621,6 +5650,7 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5621
5650
|
// ── Controls: auto-hide ────────────────────────────────────────────────
|
|
5622
5651
|
_showControls() {
|
|
5623
5652
|
this.removeAttribute("data-controls-hidden");
|
|
5653
|
+
this._toolbarTop.setAttribute("data-visible", "true");
|
|
5624
5654
|
this._scheduleHide();
|
|
5625
5655
|
}
|
|
5626
5656
|
_scheduleHide() {
|
|
@@ -5630,6 +5660,7 @@ var AvbridgePlayerElement = class extends HTMLElement {
|
|
|
5630
5660
|
this._controlsTimer = setTimeout(() => {
|
|
5631
5661
|
if (this._state === "playing") {
|
|
5632
5662
|
this.setAttribute("data-controls-hidden", "");
|
|
5663
|
+
this._toolbarTop.setAttribute("data-visible", "false");
|
|
5633
5664
|
}
|
|
5634
5665
|
}, CONTROLS_HIDE_MS);
|
|
5635
5666
|
}
|