@scarlett-player/embed 0.5.1 → 0.5.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.
@@ -1007,6 +1007,8 @@ var styles = `
1007
1007
  border-radius: 4px;
1008
1008
  transition: color 0.15s ease, transform 0.15s ease, background 0.15s ease;
1009
1009
  flex-shrink: 0;
1010
+ min-width: 44px;
1011
+ min-height: 44px;
1010
1012
  }
1011
1013
 
1012
1014
  @media (hover: hover) {
@@ -1945,6 +1947,9 @@ var ProgressBar = class {
1945
1947
  this.el.setAttribute("role", "slider");
1946
1948
  this.el.setAttribute("aria-label", "Seek");
1947
1949
  this.el.setAttribute("aria-valuemin", "0");
1950
+ this.el.setAttribute("aria-valuemax", "0");
1951
+ this.el.setAttribute("aria-valuenow", "0");
1952
+ this.el.setAttribute("aria-valuetext", "0:00");
1948
1953
  this.el.setAttribute("tabindex", "0");
1949
1954
  this.wrapper.addEventListener("mousedown", this.onMouseDown);
1950
1955
  this.wrapper.addEventListener("mousemove", this.onMouseMove);
@@ -2203,7 +2208,9 @@ var VolumeControl = class {
2203
2208
  this.btn.setAttribute("aria-label", label);
2204
2209
  const displayVolume = muted ? 0 : volume;
2205
2210
  this.level.style.width = `${displayVolume * 100}%`;
2206
- this.slider.setAttribute("aria-valuenow", String(Math.round(displayVolume * 100)));
2211
+ const volumePercent = Math.round(displayVolume * 100);
2212
+ this.slider.setAttribute("aria-valuenow", String(volumePercent));
2213
+ this.slider.setAttribute("aria-valuetext", `${volumePercent}%`);
2207
2214
  }
2208
2215
  toggleMute() {
2209
2216
  const video = getVideo(this.api.container);
@@ -2254,7 +2261,7 @@ var LiveIndicator = class {
2254
2261
  this.el.appendChild(this.dot);
2255
2262
  this.el.appendChild(this.label);
2256
2263
  this.el.setAttribute("role", "button");
2257
- this.el.setAttribute("aria-label", "Seek to live");
2264
+ this.el.setAttribute("aria-label", "Live broadcast - currently at live edge");
2258
2265
  this.el.setAttribute("tabindex", "0");
2259
2266
  this.el.addEventListener("click", this.handleClick);
2260
2267
  this.el.addEventListener("keydown", this.handleKeyDown);
@@ -2269,11 +2276,13 @@ var LiveIndicator = class {
2269
2276
  if (liveEdge) {
2270
2277
  this.el.classList.remove("sp-live--behind");
2271
2278
  this.label.textContent = "LIVE";
2272
- this.el.setAttribute("aria-label", "At live edge");
2279
+ this.dot.setAttribute("aria-hidden", "true");
2280
+ this.el.setAttribute("aria-label", "Live broadcast - currently at live edge");
2273
2281
  } else {
2274
2282
  this.el.classList.add("sp-live--behind");
2275
2283
  this.label.textContent = "GO LIVE";
2276
- this.el.setAttribute("aria-label", "Seek to live");
2284
+ this.dot.setAttribute("aria-hidden", "true");
2285
+ this.el.setAttribute("aria-label", "Live broadcast - behind live edge, click to seek to live");
2277
2286
  }
2278
2287
  }
2279
2288
  seekToLive() {
@@ -2751,6 +2760,18 @@ var SettingsMenu = class {
2751
2760
  this.close();
2752
2761
  this.btn.focus();
2753
2762
  }
2763
+ return;
2764
+ }
2765
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
2766
+ e.preventDefault();
2767
+ e.stopPropagation();
2768
+ this.navigateItems(e.key === "ArrowDown" ? 1 : -1);
2769
+ return;
2770
+ }
2771
+ if (e.key === "Tab") {
2772
+ e.preventDefault();
2773
+ e.stopPropagation();
2774
+ this.navigateItems(e.shiftKey ? -1 : 1);
2754
2775
  }
2755
2776
  };
2756
2777
  document.addEventListener("keydown", this.keyHandler);
@@ -2786,6 +2807,7 @@ var SettingsMenu = class {
2786
2807
  this.renderMainPanel();
2787
2808
  this.panel.classList.add("sp-settings-panel--open");
2788
2809
  this.btn.setAttribute("aria-expanded", "true");
2810
+ this.focusFirstItem();
2789
2811
  }
2790
2812
  close() {
2791
2813
  this.isOpen = false;
@@ -2809,6 +2831,7 @@ var SettingsMenu = class {
2809
2831
  this.renderCaptionsPanel();
2810
2832
  break;
2811
2833
  }
2834
+ this.focusFirstItem();
2812
2835
  }
2813
2836
  renderMainPanel() {
2814
2837
  this.panel.innerHTML = "";
@@ -3027,6 +3050,32 @@ var SettingsMenu = class {
3027
3050
  );
3028
3051
  });
3029
3052
  }
3053
+ getFocusableItems() {
3054
+ return Array.from(
3055
+ this.panel.querySelectorAll('[role="menuitem"]')
3056
+ );
3057
+ }
3058
+ focusFirstItem() {
3059
+ requestAnimationFrame(() => {
3060
+ const items = this.getFocusableItems();
3061
+ if (items.length > 0) {
3062
+ items[0].focus();
3063
+ }
3064
+ });
3065
+ }
3066
+ navigateItems(direction) {
3067
+ const items = this.getFocusableItems();
3068
+ if (items.length === 0) return;
3069
+ const active = document.activeElement;
3070
+ const currentIndex = items.indexOf(active);
3071
+ let nextIndex;
3072
+ if (currentIndex === -1) {
3073
+ nextIndex = direction === 1 ? 0 : items.length - 1;
3074
+ } else {
3075
+ nextIndex = (currentIndex + direction + items.length) % items.length;
3076
+ }
3077
+ items[nextIndex].focus();
3078
+ }
3030
3079
  getPanel() {
3031
3080
  return this.currentPanel;
3032
3081
  }
@@ -4949,6 +4998,7 @@ class ScarlettPlayer {
4949
4998
  this.destroyed = false;
4950
4999
  this.seekingWhilePlaying = false;
4951
5000
  this.seekResumeTimeout = null;
5001
+ this.loadGeneration = 0;
4952
5002
  if (typeof options.container === "string") {
4953
5003
  const el = document.querySelector(options.container);
4954
5004
  if (!el || !(el instanceof HTMLElement)) {
@@ -5022,6 +5072,7 @@ class ScarlettPlayer {
5022
5072
  */
5023
5073
  async load(source) {
5024
5074
  this.checkDestroyed();
5075
+ const generation = ++this.loadGeneration;
5025
5076
  try {
5026
5077
  this.logger.info("Loading source", { source });
5027
5078
  this.stateManager.update({
@@ -5040,6 +5091,10 @@ class ScarlettPlayer {
5040
5091
  await this.pluginManager.destroyPlugin(previousProviderId);
5041
5092
  this._currentProvider = null;
5042
5093
  }
5094
+ if (generation !== this.loadGeneration) {
5095
+ this.logger.info("Load superseded by newer load call", { source });
5096
+ return;
5097
+ }
5043
5098
  const provider = this.pluginManager.selectProvider(source);
5044
5099
  if (!provider) {
5045
5100
  this.errorHandler.throw(
@@ -5055,18 +5110,28 @@ class ScarlettPlayer {
5055
5110
  this._currentProvider = provider;
5056
5111
  this.logger.info("Provider selected", { provider: provider.id });
5057
5112
  await this.pluginManager.initPlugin(provider.id);
5113
+ if (generation !== this.loadGeneration) {
5114
+ this.logger.info("Load superseded by newer load call", { source });
5115
+ return;
5116
+ }
5058
5117
  this.stateManager.set("source", { src: source, type: this.detectMimeType(source) });
5059
5118
  if (typeof provider.loadSource === "function") {
5060
5119
  await provider.loadSource(source);
5061
5120
  }
5121
+ if (generation !== this.loadGeneration) {
5122
+ this.logger.info("Load superseded by newer load call", { source });
5123
+ return;
5124
+ }
5062
5125
  if (this.stateManager.getValue("autoplay")) {
5063
5126
  await this.play();
5064
5127
  }
5065
5128
  } catch (error) {
5066
- this.errorHandler.handle(error, {
5067
- operation: "load",
5068
- source
5069
- });
5129
+ if (generation === this.loadGeneration) {
5130
+ this.errorHandler.handle(error, {
5131
+ operation: "load",
5132
+ source
5133
+ });
5134
+ }
5070
5135
  }
5071
5136
  }
5072
5137
  /**