vidply 1.0.2 → 1.0.3

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.
@@ -1212,6 +1212,42 @@ var ControlBar = class {
1212
1212
  document.addEventListener("keydown", handleEscape);
1213
1213
  }, 100);
1214
1214
  }
1215
+ // Helper method to add keyboard navigation to menus (arrow keys)
1216
+ attachMenuKeyboardNavigation(menu) {
1217
+ const menuItems = Array.from(menu.querySelectorAll(`.${this.player.options.classPrefix}-menu-item`));
1218
+ if (menuItems.length === 0) return;
1219
+ const handleKeyDown = (e) => {
1220
+ const currentIndex = menuItems.indexOf(document.activeElement);
1221
+ switch (e.key) {
1222
+ case "ArrowDown":
1223
+ e.preventDefault();
1224
+ const nextIndex = (currentIndex + 1) % menuItems.length;
1225
+ menuItems[nextIndex].focus();
1226
+ break;
1227
+ case "ArrowUp":
1228
+ e.preventDefault();
1229
+ const prevIndex = (currentIndex - 1 + menuItems.length) % menuItems.length;
1230
+ menuItems[prevIndex].focus();
1231
+ break;
1232
+ case "Home":
1233
+ e.preventDefault();
1234
+ menuItems[0].focus();
1235
+ break;
1236
+ case "End":
1237
+ e.preventDefault();
1238
+ menuItems[menuItems.length - 1].focus();
1239
+ break;
1240
+ case "Enter":
1241
+ case " ":
1242
+ e.preventDefault();
1243
+ if (document.activeElement && menuItems.includes(document.activeElement)) {
1244
+ document.activeElement.click();
1245
+ }
1246
+ break;
1247
+ }
1248
+ };
1249
+ menu.addEventListener("keydown", handleKeyDown);
1250
+ }
1215
1251
  createElement() {
1216
1252
  this.element = DOMUtils.createElement("div", {
1217
1253
  className: `${this.player.options.classPrefix}-controls`,
@@ -1706,7 +1742,8 @@ var ControlBar = class {
1706
1742
  className: `${this.player.options.classPrefix}-menu-item`,
1707
1743
  attributes: {
1708
1744
  "type": "button",
1709
- "role": "menuitem"
1745
+ "role": "menuitem",
1746
+ "tabindex": "-1"
1710
1747
  }
1711
1748
  });
1712
1749
  const timeLabel = DOMUtils.createElement("span", {
@@ -1726,6 +1763,13 @@ var ControlBar = class {
1726
1763
  });
1727
1764
  menu.appendChild(item);
1728
1765
  }
1766
+ this.attachMenuKeyboardNavigation(menu);
1767
+ setTimeout(() => {
1768
+ const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
1769
+ if (firstItem) {
1770
+ firstItem.focus();
1771
+ }
1772
+ }, 0);
1729
1773
  }
1730
1774
  }
1731
1775
  button.appendChild(menu);
@@ -1779,19 +1823,22 @@ var ControlBar = class {
1779
1823
  });
1780
1824
  menu.appendChild(noQualityItem);
1781
1825
  } else {
1826
+ let activeItem = null;
1782
1827
  if (isHLS) {
1783
1828
  const autoItem = DOMUtils.createElement("button", {
1784
1829
  className: `${this.player.options.classPrefix}-menu-item`,
1785
1830
  textContent: i18n.t("player.auto"),
1786
1831
  attributes: {
1787
1832
  "type": "button",
1788
- "role": "menuitem"
1833
+ "role": "menuitem",
1834
+ "tabindex": "-1"
1789
1835
  }
1790
1836
  });
1791
1837
  const isAuto = this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1;
1792
1838
  if (isAuto) {
1793
1839
  autoItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
1794
1840
  autoItem.appendChild(createIconElement("check"));
1841
+ activeItem = autoItem;
1795
1842
  }
1796
1843
  autoItem.addEventListener("click", () => {
1797
1844
  if (this.player.renderer.switchQuality) {
@@ -1807,12 +1854,14 @@ var ControlBar = class {
1807
1854
  textContent: quality.name || `${quality.height}p`,
1808
1855
  attributes: {
1809
1856
  "type": "button",
1810
- "role": "menuitem"
1857
+ "role": "menuitem",
1858
+ "tabindex": "-1"
1811
1859
  }
1812
1860
  });
1813
1861
  if (quality.index === currentQuality) {
1814
1862
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
1815
1863
  item.appendChild(createIconElement("check"));
1864
+ activeItem = item;
1816
1865
  }
1817
1866
  item.addEventListener("click", () => {
1818
1867
  if (this.player.renderer.switchQuality) {
@@ -1822,6 +1871,13 @@ var ControlBar = class {
1822
1871
  });
1823
1872
  menu.appendChild(item);
1824
1873
  });
1874
+ this.attachMenuKeyboardNavigation(menu);
1875
+ setTimeout(() => {
1876
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
1877
+ if (focusTarget) {
1878
+ focusTarget.focus();
1879
+ }
1880
+ }, 0);
1825
1881
  }
1826
1882
  } else {
1827
1883
  const noSupportItem = DOMUtils.createElement("div", {
@@ -1915,6 +1971,12 @@ var ControlBar = class {
1915
1971
  menu.style.minWidth = "220px";
1916
1972
  button.appendChild(menu);
1917
1973
  this.attachMenuCloseHandler(menu, button, true);
1974
+ setTimeout(() => {
1975
+ const firstSelect = menu.querySelector("select");
1976
+ if (firstSelect) {
1977
+ firstSelect.focus();
1978
+ }
1979
+ }, 0);
1918
1980
  }
1919
1981
  createStyleControl(label, property, options) {
1920
1982
  const group = DOMUtils.createElement("div", {
@@ -2127,18 +2189,21 @@ var ControlBar = class {
2127
2189
  }
2128
2190
  });
2129
2191
  const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
2192
+ let activeItem = null;
2130
2193
  speeds.forEach((speed) => {
2131
2194
  const item = DOMUtils.createElement("button", {
2132
2195
  className: `${this.player.options.classPrefix}-menu-item`,
2133
2196
  textContent: this.formatSpeedLabel(speed),
2134
2197
  attributes: {
2135
2198
  "type": "button",
2136
- "role": "menuitem"
2199
+ "role": "menuitem",
2200
+ "tabindex": "-1"
2137
2201
  }
2138
2202
  });
2139
2203
  if (speed === this.player.state.playbackSpeed) {
2140
2204
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2141
2205
  item.appendChild(createIconElement("check"));
2206
+ activeItem = item;
2142
2207
  }
2143
2208
  item.addEventListener("click", () => {
2144
2209
  this.player.setPlaybackSpeed(speed);
@@ -2147,7 +2212,14 @@ var ControlBar = class {
2147
2212
  menu.appendChild(item);
2148
2213
  });
2149
2214
  button.appendChild(menu);
2215
+ this.attachMenuKeyboardNavigation(menu);
2150
2216
  this.attachMenuCloseHandler(menu, button);
2217
+ setTimeout(() => {
2218
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
2219
+ if (focusTarget) {
2220
+ focusTarget.focus();
2221
+ }
2222
+ }, 0);
2151
2223
  }
2152
2224
  createCaptionsButton() {
2153
2225
  const button = DOMUtils.createElement("button", {
@@ -2190,17 +2262,20 @@ var ControlBar = class {
2190
2262
  this.attachMenuCloseHandler(menu, button);
2191
2263
  return;
2192
2264
  }
2265
+ let activeItem = null;
2193
2266
  const offItem = DOMUtils.createElement("button", {
2194
2267
  className: `${this.player.options.classPrefix}-menu-item`,
2195
2268
  textContent: i18n.t("captions.off"),
2196
2269
  attributes: {
2197
2270
  "type": "button",
2198
- "role": "menuitem"
2271
+ "role": "menuitem",
2272
+ "tabindex": "-1"
2199
2273
  }
2200
2274
  });
2201
2275
  if (!this.player.state.captionsEnabled) {
2202
2276
  offItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2203
2277
  offItem.appendChild(createIconElement("check"));
2278
+ activeItem = offItem;
2204
2279
  }
2205
2280
  offItem.addEventListener("click", () => {
2206
2281
  this.player.disableCaptions();
@@ -2216,12 +2291,14 @@ var ControlBar = class {
2216
2291
  attributes: {
2217
2292
  "type": "button",
2218
2293
  "role": "menuitem",
2219
- "lang": track.language
2294
+ "lang": track.language,
2295
+ "tabindex": "-1"
2220
2296
  }
2221
2297
  });
2222
2298
  if (this.player.state.captionsEnabled && this.player.captionManager.currentTrack === this.player.captionManager.tracks[track.index]) {
2223
2299
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2224
2300
  item.appendChild(createIconElement("check"));
2301
+ activeItem = item;
2225
2302
  }
2226
2303
  item.addEventListener("click", () => {
2227
2304
  this.player.captionManager.switchTrack(track.index);
@@ -2231,7 +2308,14 @@ var ControlBar = class {
2231
2308
  menu.appendChild(item);
2232
2309
  });
2233
2310
  button.appendChild(menu);
2311
+ this.attachMenuKeyboardNavigation(menu);
2234
2312
  this.attachMenuCloseHandler(menu, button);
2313
+ setTimeout(() => {
2314
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
2315
+ if (focusTarget) {
2316
+ focusTarget.focus();
2317
+ }
2318
+ }, 0);
2235
2319
  }
2236
2320
  updateCaptionsButton() {
2237
2321
  if (!this.controls.captions) return;
@@ -2416,26 +2500,29 @@ var ControlBar = class {
2416
2500
  }
2417
2501
  }
2418
2502
  updateVolumeDisplay() {
2419
- if (!this.controls.volumeFill) return;
2420
2503
  const percent = this.player.state.volume * 100;
2421
- this.controls.volumeFill.style.height = `${percent}%`;
2504
+ if (this.controls.volumeFill) {
2505
+ this.controls.volumeFill.style.height = `${percent}%`;
2506
+ }
2422
2507
  if (this.controls.mute) {
2423
2508
  const icon = this.controls.mute.querySelector(".vidply-icon");
2424
- let iconName;
2425
- if (this.player.state.muted || this.player.state.volume === 0) {
2426
- iconName = "volumeMuted";
2427
- } else if (this.player.state.volume < 0.3) {
2428
- iconName = "volumeLow";
2429
- } else if (this.player.state.volume < 0.7) {
2430
- iconName = "volumeMedium";
2431
- } else {
2432
- iconName = "volumeHigh";
2509
+ if (icon) {
2510
+ let iconName;
2511
+ if (this.player.state.muted || this.player.state.volume === 0) {
2512
+ iconName = "volumeMuted";
2513
+ } else if (this.player.state.volume < 0.3) {
2514
+ iconName = "volumeLow";
2515
+ } else if (this.player.state.volume < 0.7) {
2516
+ iconName = "volumeMedium";
2517
+ } else {
2518
+ iconName = "volumeHigh";
2519
+ }
2520
+ icon.innerHTML = createIconElement(iconName).innerHTML;
2521
+ this.controls.mute.setAttribute(
2522
+ "aria-label",
2523
+ this.player.state.muted ? i18n.t("player.unmute") : i18n.t("player.mute")
2524
+ );
2433
2525
  }
2434
- icon.innerHTML = createIconElement(iconName).innerHTML;
2435
- this.controls.mute.setAttribute(
2436
- "aria-label",
2437
- this.player.state.muted ? i18n.t("player.unmute") : i18n.t("player.mute")
2438
- );
2439
2526
  }
2440
2527
  if (this.controls.volumeSlider) {
2441
2528
  this.controls.volumeSlider.setAttribute("aria-valuenow", String(Math.round(percent)));
@@ -2620,7 +2707,6 @@ var CaptionManager = class {
2620
2707
  this.updateCaptions();
2621
2708
  };
2622
2709
  selectedTrack.track.addEventListener("cuechange", this.cueChangeHandler);
2623
- this.element.style.display = "block";
2624
2710
  this.player.emit("captionsenabled", selectedTrack);
2625
2711
  }
2626
2712
  }
@@ -2763,6 +2849,9 @@ var KeyboardManager = class {
2763
2849
  }
2764
2850
  }
2765
2851
  }
2852
+ if (!handled && this.player.options.debug) {
2853
+ console.log("[VidPly] Unhandled key:", e.key, "code:", e.code, "shiftKey:", e.shiftKey);
2854
+ }
2766
2855
  }
2767
2856
  executeAction(action, event) {
2768
2857
  switch (action) {
@@ -2781,12 +2870,6 @@ var KeyboardManager = class {
2781
2870
  case "seek-backward":
2782
2871
  this.player.seekBackward();
2783
2872
  return true;
2784
- case "seek-forward-large":
2785
- this.player.seekForward(this.player.options.seekIntervalLarge);
2786
- return true;
2787
- case "seek-backward-large":
2788
- this.player.seekBackward(this.player.options.seekIntervalLarge);
2789
- return true;
2790
2873
  case "mute":
2791
2874
  this.player.toggleMute();
2792
2875
  return true;
@@ -2795,14 +2878,22 @@ var KeyboardManager = class {
2795
2878
  return true;
2796
2879
  case "captions":
2797
2880
  if (this.player.captionManager && this.player.captionManager.tracks.length > 1) {
2798
- const captionsButton = document.querySelector(".vidply-captions");
2799
- if (captionsButton && this.player.controlBar) {
2881
+ const captionsButton = this.player.controlBar && this.player.controlBar.controls.captions;
2882
+ if (captionsButton) {
2800
2883
  this.player.controlBar.showCaptionsMenu(captionsButton);
2884
+ } else {
2885
+ this.player.toggleCaptions();
2801
2886
  }
2802
2887
  } else {
2803
2888
  this.player.toggleCaptions();
2804
2889
  }
2805
2890
  return true;
2891
+ case "caption-style-menu":
2892
+ if (this.player.controlBar && this.player.controlBar.controls.captionStyle) {
2893
+ this.player.controlBar.showCaptionStyleMenu(this.player.controlBar.controls.captionStyle);
2894
+ return true;
2895
+ }
2896
+ return false;
2806
2897
  case "speed-up":
2807
2898
  this.player.setPlaybackSpeed(
2808
2899
  Math.min(2, this.player.state.playbackSpeed + 0.25)
@@ -2813,9 +2904,30 @@ var KeyboardManager = class {
2813
2904
  Math.max(0.25, this.player.state.playbackSpeed - 0.25)
2814
2905
  );
2815
2906
  return true;
2816
- case "settings":
2817
- this.player.showSettings();
2818
- return true;
2907
+ case "speed-menu":
2908
+ if (this.player.controlBar && this.player.controlBar.controls.speed) {
2909
+ this.player.controlBar.showSpeedMenu(this.player.controlBar.controls.speed);
2910
+ return true;
2911
+ }
2912
+ return false;
2913
+ case "quality-menu":
2914
+ if (this.player.controlBar && this.player.controlBar.controls.quality) {
2915
+ this.player.controlBar.showQualityMenu(this.player.controlBar.controls.quality);
2916
+ return true;
2917
+ }
2918
+ return false;
2919
+ case "chapters-menu":
2920
+ if (this.player.controlBar && this.player.controlBar.controls.chapters) {
2921
+ this.player.controlBar.showChaptersMenu(this.player.controlBar.controls.chapters);
2922
+ return true;
2923
+ }
2924
+ return false;
2925
+ case "transcript-toggle":
2926
+ if (this.player.transcriptManager) {
2927
+ this.player.transcriptManager.toggleTranscript();
2928
+ return true;
2929
+ }
2930
+ return false;
2819
2931
  default:
2820
2932
  return false;
2821
2933
  }
@@ -2882,317 +2994,6 @@ var KeyboardManager = class {
2882
2994
  }
2883
2995
  };
2884
2996
 
2885
- // src/controls/SettingsDialog.js
2886
- var SettingsDialog = class {
2887
- constructor(player) {
2888
- this.player = player;
2889
- this.element = null;
2890
- this.isOpen = false;
2891
- this.init();
2892
- }
2893
- init() {
2894
- this.createElement();
2895
- }
2896
- createElement() {
2897
- this.overlay = DOMUtils.createElement("div", {
2898
- className: `${this.player.options.classPrefix}-settings-overlay`,
2899
- attributes: {
2900
- "role": "dialog",
2901
- "aria-modal": "true",
2902
- "aria-label": i18n.t("settings.title")
2903
- }
2904
- });
2905
- this.overlay.style.display = "none";
2906
- this.element = DOMUtils.createElement("div", {
2907
- className: `${this.player.options.classPrefix}-settings-dialog`
2908
- });
2909
- const header = DOMUtils.createElement("div", {
2910
- className: `${this.player.options.classPrefix}-settings-header`
2911
- });
2912
- const title = DOMUtils.createElement("h2", {
2913
- textContent: i18n.t("settings.title"),
2914
- attributes: {
2915
- "id": `${this.player.options.classPrefix}-settings-title`
2916
- }
2917
- });
2918
- const closeButton = DOMUtils.createElement("button", {
2919
- className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-settings-close`,
2920
- attributes: {
2921
- "type": "button",
2922
- "aria-label": i18n.t("settings.close")
2923
- }
2924
- });
2925
- closeButton.appendChild(createIconElement("close"));
2926
- closeButton.addEventListener("click", () => this.hide());
2927
- header.appendChild(title);
2928
- header.appendChild(closeButton);
2929
- const content = DOMUtils.createElement("div", {
2930
- className: `${this.player.options.classPrefix}-settings-content`
2931
- });
2932
- content.appendChild(this.createSpeedSettings());
2933
- if (this.player.captionManager && this.player.captionManager.tracks.length > 0) {
2934
- content.appendChild(this.createCaptionSettings());
2935
- }
2936
- const footer = DOMUtils.createElement("div", {
2937
- className: `${this.player.options.classPrefix}-settings-footer`
2938
- });
2939
- const resetButton = DOMUtils.createElement("button", {
2940
- className: `${this.player.options.classPrefix}-button`,
2941
- textContent: i18n.t("settings.reset"),
2942
- attributes: {
2943
- "type": "button"
2944
- }
2945
- });
2946
- resetButton.addEventListener("click", () => this.resetSettings());
2947
- footer.appendChild(resetButton);
2948
- this.element.appendChild(header);
2949
- this.element.appendChild(content);
2950
- this.element.appendChild(footer);
2951
- this.overlay.appendChild(this.element);
2952
- this.player.container.appendChild(this.overlay);
2953
- this.overlay.addEventListener("click", (e) => {
2954
- if (e.target === this.overlay) {
2955
- this.hide();
2956
- }
2957
- });
2958
- document.addEventListener("keydown", (e) => {
2959
- if (e.key === "Escape" && this.isOpen) {
2960
- this.hide();
2961
- }
2962
- });
2963
- }
2964
- formatSpeedLabel(speed) {
2965
- if (speed === 1) {
2966
- return i18n.t("speeds.normal");
2967
- }
2968
- const speedStr = speed.toLocaleString(i18n.getLanguage(), {
2969
- minimumFractionDigits: 0,
2970
- maximumFractionDigits: 2
2971
- });
2972
- return `${speedStr}\xD7`;
2973
- }
2974
- createSpeedSettings() {
2975
- const section = DOMUtils.createElement("div", {
2976
- className: `${this.player.options.classPrefix}-settings-section`
2977
- });
2978
- const label = DOMUtils.createElement("label", {
2979
- textContent: i18n.t("settings.speed"),
2980
- attributes: {
2981
- "for": `${this.player.options.classPrefix}-speed-select`
2982
- }
2983
- });
2984
- const select = DOMUtils.createElement("select", {
2985
- className: `${this.player.options.classPrefix}-settings-select`,
2986
- attributes: {
2987
- "id": `${this.player.options.classPrefix}-speed-select`
2988
- }
2989
- });
2990
- const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
2991
- speeds.forEach((speed) => {
2992
- const option = DOMUtils.createElement("option", {
2993
- textContent: this.formatSpeedLabel(speed),
2994
- attributes: {
2995
- "value": String(speed)
2996
- }
2997
- });
2998
- if (speed === this.player.state.playbackSpeed) {
2999
- option.selected = true;
3000
- }
3001
- select.appendChild(option);
3002
- });
3003
- select.addEventListener("change", (e) => {
3004
- this.player.setPlaybackSpeed(parseFloat(e.target.value));
3005
- });
3006
- section.appendChild(label);
3007
- section.appendChild(select);
3008
- return section;
3009
- }
3010
- createCaptionSettings() {
3011
- const section = DOMUtils.createElement("div", {
3012
- className: `${this.player.options.classPrefix}-settings-section`
3013
- });
3014
- const heading = DOMUtils.createElement("h3", {
3015
- textContent: i18n.t("settings.captions")
3016
- });
3017
- section.appendChild(heading);
3018
- const trackLabel = DOMUtils.createElement("label", {
3019
- textContent: i18n.t("captions.select"),
3020
- attributes: {
3021
- "for": `${this.player.options.classPrefix}-caption-track-select`
3022
- }
3023
- });
3024
- const trackSelect = DOMUtils.createElement("select", {
3025
- className: `${this.player.options.classPrefix}-settings-select`,
3026
- attributes: {
3027
- "id": `${this.player.options.classPrefix}-caption-track-select`
3028
- }
3029
- });
3030
- const offOption = DOMUtils.createElement("option", {
3031
- textContent: i18n.t("captions.off"),
3032
- attributes: { "value": "-1" }
3033
- });
3034
- trackSelect.appendChild(offOption);
3035
- const tracks = this.player.captionManager.getAvailableTracks();
3036
- tracks.forEach((track) => {
3037
- const option = DOMUtils.createElement("option", {
3038
- textContent: track.label,
3039
- attributes: { "value": String(track.index) }
3040
- });
3041
- trackSelect.appendChild(option);
3042
- });
3043
- trackSelect.addEventListener("change", (e) => {
3044
- const index = parseInt(e.target.value);
3045
- if (index === -1) {
3046
- this.player.disableCaptions();
3047
- } else {
3048
- this.player.captionManager.switchTrack(index);
3049
- }
3050
- });
3051
- section.appendChild(trackLabel);
3052
- section.appendChild(trackSelect);
3053
- section.appendChild(this.createCaptionStyleControl("fontSize", i18n.t("captions.fontSize"), [
3054
- { label: i18n.t("fontSizes.small"), value: "80%" },
3055
- { label: i18n.t("fontSizes.medium"), value: "100%" },
3056
- { label: i18n.t("fontSizes.large"), value: "120%" },
3057
- { label: i18n.t("fontSizes.xlarge"), value: "150%" }
3058
- ]));
3059
- section.appendChild(this.createCaptionStyleControl("fontFamily", i18n.t("captions.fontFamily"), [
3060
- { label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
3061
- { label: i18n.t("fontFamilies.serif"), value: "serif" },
3062
- { label: i18n.t("fontFamilies.monospace"), value: "monospace" }
3063
- ]));
3064
- section.appendChild(this.createColorControl("color", i18n.t("captions.color")));
3065
- section.appendChild(this.createColorControl("backgroundColor", i18n.t("captions.backgroundColor")));
3066
- section.appendChild(this.createRangeControl("opacity", i18n.t("captions.opacity"), 0, 1, 0.1));
3067
- return section;
3068
- }
3069
- createCaptionStyleControl(property, label, options) {
3070
- const wrapper = DOMUtils.createElement("div", {
3071
- className: `${this.player.options.classPrefix}-settings-control`
3072
- });
3073
- const labelEl = DOMUtils.createElement("label", {
3074
- textContent: label,
3075
- attributes: {
3076
- "for": `${this.player.options.classPrefix}-caption-${property}`
3077
- }
3078
- });
3079
- const select = DOMUtils.createElement("select", {
3080
- className: `${this.player.options.classPrefix}-settings-select`,
3081
- attributes: {
3082
- "id": `${this.player.options.classPrefix}-caption-${property}`
3083
- }
3084
- });
3085
- options.forEach((opt) => {
3086
- const option = DOMUtils.createElement("option", {
3087
- textContent: opt.label,
3088
- attributes: { "value": opt.value }
3089
- });
3090
- if (opt.value === this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`]) {
3091
- option.selected = true;
3092
- }
3093
- select.appendChild(option);
3094
- });
3095
- select.addEventListener("change", (e) => {
3096
- this.player.captionManager.setCaptionStyle(property, e.target.value);
3097
- });
3098
- wrapper.appendChild(labelEl);
3099
- wrapper.appendChild(select);
3100
- return wrapper;
3101
- }
3102
- createColorControl(property, label) {
3103
- const wrapper = DOMUtils.createElement("div", {
3104
- className: `${this.player.options.classPrefix}-settings-control`
3105
- });
3106
- const labelEl = DOMUtils.createElement("label", {
3107
- textContent: label,
3108
- attributes: {
3109
- "for": `${this.player.options.classPrefix}-caption-${property}`
3110
- }
3111
- });
3112
- const input = DOMUtils.createElement("input", {
3113
- className: `${this.player.options.classPrefix}-settings-color`,
3114
- attributes: {
3115
- "type": "color",
3116
- "id": `${this.player.options.classPrefix}-caption-${property}`,
3117
- "value": this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`]
3118
- }
3119
- });
3120
- input.addEventListener("change", (e) => {
3121
- this.player.captionManager.setCaptionStyle(property, e.target.value);
3122
- });
3123
- wrapper.appendChild(labelEl);
3124
- wrapper.appendChild(input);
3125
- return wrapper;
3126
- }
3127
- createRangeControl(property, label, min, max, step) {
3128
- const wrapper = DOMUtils.createElement("div", {
3129
- className: `${this.player.options.classPrefix}-settings-control`
3130
- });
3131
- const labelEl = DOMUtils.createElement("label", {
3132
- textContent: label,
3133
- attributes: {
3134
- "for": `${this.player.options.classPrefix}-caption-${property}`
3135
- }
3136
- });
3137
- const input = DOMUtils.createElement("input", {
3138
- className: `${this.player.options.classPrefix}-settings-range`,
3139
- attributes: {
3140
- "type": "range",
3141
- "id": `${this.player.options.classPrefix}-caption-${property}`,
3142
- "min": String(min),
3143
- "max": String(max),
3144
- "step": String(step),
3145
- "value": String(this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`])
3146
- }
3147
- });
3148
- const valueDisplay = DOMUtils.createElement("span", {
3149
- className: `${this.player.options.classPrefix}-settings-value`,
3150
- textContent: String(this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`])
3151
- });
3152
- input.addEventListener("input", (e) => {
3153
- const value = parseFloat(e.target.value);
3154
- valueDisplay.textContent = value.toFixed(1);
3155
- this.player.captionManager.setCaptionStyle(property, value);
3156
- });
3157
- wrapper.appendChild(labelEl);
3158
- wrapper.appendChild(input);
3159
- wrapper.appendChild(valueDisplay);
3160
- return wrapper;
3161
- }
3162
- resetSettings() {
3163
- this.player.setPlaybackSpeed(1);
3164
- if (this.player.captionManager) {
3165
- this.player.captionManager.setCaptionStyle("fontSize", "100%");
3166
- this.player.captionManager.setCaptionStyle("fontFamily", "sans-serif");
3167
- this.player.captionManager.setCaptionStyle("color", "#FFFFFF");
3168
- this.player.captionManager.setCaptionStyle("backgroundColor", "#000000");
3169
- this.player.captionManager.setCaptionStyle("opacity", 0.8);
3170
- }
3171
- this.hide();
3172
- setTimeout(() => this.show(), 100);
3173
- }
3174
- show() {
3175
- this.overlay.style.display = "flex";
3176
- this.isOpen = true;
3177
- const closeButton = this.element.querySelector(`.${this.player.options.classPrefix}-settings-close`);
3178
- if (closeButton) {
3179
- closeButton.focus();
3180
- }
3181
- this.player.emit("settingsopen");
3182
- }
3183
- hide() {
3184
- this.overlay.style.display = "none";
3185
- this.isOpen = false;
3186
- this.player.container.focus();
3187
- this.player.emit("settingsclose");
3188
- }
3189
- destroy() {
3190
- if (this.overlay && this.overlay.parentNode) {
3191
- this.overlay.parentNode.removeChild(this.overlay);
3192
- }
3193
- }
3194
- };
3195
-
3196
2997
  // src/controls/TranscriptManager.js
3197
2998
  var TranscriptManager = class {
3198
2999
  constructor(player) {
@@ -4480,16 +4281,18 @@ var Player = class extends EventEmitter {
4480
4281
  "play-pause": [" ", "p", "k"],
4481
4282
  "volume-up": ["ArrowUp"],
4482
4283
  "volume-down": ["ArrowDown"],
4483
- "seek-forward": ["ArrowRight", "f"],
4484
- "seek-backward": ["ArrowLeft", "r"],
4485
- "seek-forward-large": ["l"],
4486
- "seek-backward-large": ["j"],
4284
+ "seek-forward": ["ArrowRight"],
4285
+ "seek-backward": ["ArrowLeft"],
4487
4286
  "mute": ["m"],
4488
4287
  "fullscreen": ["f"],
4489
4288
  "captions": ["c"],
4289
+ "caption-style-menu": ["a"],
4490
4290
  "speed-up": [">"],
4491
4291
  "speed-down": ["<"],
4492
- "settings": ["s"]
4292
+ "speed-menu": ["s"],
4293
+ "quality-menu": ["q"],
4294
+ "chapters-menu": ["j"],
4295
+ "transcript-toggle": ["t"]
4493
4296
  },
4494
4297
  // Accessibility
4495
4298
  ariaLabels: {},
@@ -4578,9 +4381,6 @@ var Player = class extends EventEmitter {
4578
4381
  if (this.options.keyboard) {
4579
4382
  this.keyboardManager = new KeyboardManager(this);
4580
4383
  }
4581
- if (this.options.settingsButton) {
4582
- this.settingsDialog = new SettingsDialog(this);
4583
- }
4584
4384
  this.setupResponsiveHandlers();
4585
4385
  if (this.options.startTime > 0) {
4586
4386
  this.seek(this.options.startTime);
@@ -4833,12 +4633,14 @@ var Player = class extends EventEmitter {
4833
4633
  this.renderer.setMuted(true);
4834
4634
  }
4835
4635
  this.state.muted = true;
4636
+ this.emit("volumechange");
4836
4637
  }
4837
4638
  unmute() {
4838
4639
  if (this.renderer) {
4839
4640
  this.renderer.setMuted(false);
4840
4641
  }
4841
4642
  this.state.muted = false;
4643
+ this.emit("volumechange");
4842
4644
  }
4843
4645
  toggleMute() {
4844
4646
  if (this.state.muted) {
@@ -5072,15 +4874,11 @@ var Player = class extends EventEmitter {
5072
4874
  }
5073
4875
  }
5074
4876
  // Settings
4877
+ // Settings dialog removed - using individual control buttons instead
5075
4878
  showSettings() {
5076
- if (this.settingsDialog) {
5077
- this.settingsDialog.show();
5078
- }
4879
+ console.warn("[VidPly] Settings dialog has been removed. Use individual control buttons (speed, captions, etc.)");
5079
4880
  }
5080
4881
  hideSettings() {
5081
- if (this.settingsDialog) {
5082
- this.settingsDialog.hide();
5083
- }
5084
4882
  }
5085
4883
  // Utility methods
5086
4884
  getCurrentTime() {
@@ -5177,9 +4975,6 @@ var Player = class extends EventEmitter {
5177
4975
  if (this.keyboardManager) {
5178
4976
  this.keyboardManager.destroy();
5179
4977
  }
5180
- if (this.settingsDialog) {
5181
- this.settingsDialog.destroy();
5182
- }
5183
4978
  if (this.transcriptManager) {
5184
4979
  this.transcriptManager.destroy();
5185
4980
  }