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.
package/dist/vidply.js CHANGED
@@ -1232,6 +1232,42 @@ var VidPly = (() => {
1232
1232
  document.addEventListener("keydown", handleEscape);
1233
1233
  }, 100);
1234
1234
  }
1235
+ // Helper method to add keyboard navigation to menus (arrow keys)
1236
+ attachMenuKeyboardNavigation(menu) {
1237
+ const menuItems = Array.from(menu.querySelectorAll(`.${this.player.options.classPrefix}-menu-item`));
1238
+ if (menuItems.length === 0) return;
1239
+ const handleKeyDown = (e) => {
1240
+ const currentIndex = menuItems.indexOf(document.activeElement);
1241
+ switch (e.key) {
1242
+ case "ArrowDown":
1243
+ e.preventDefault();
1244
+ const nextIndex = (currentIndex + 1) % menuItems.length;
1245
+ menuItems[nextIndex].focus();
1246
+ break;
1247
+ case "ArrowUp":
1248
+ e.preventDefault();
1249
+ const prevIndex = (currentIndex - 1 + menuItems.length) % menuItems.length;
1250
+ menuItems[prevIndex].focus();
1251
+ break;
1252
+ case "Home":
1253
+ e.preventDefault();
1254
+ menuItems[0].focus();
1255
+ break;
1256
+ case "End":
1257
+ e.preventDefault();
1258
+ menuItems[menuItems.length - 1].focus();
1259
+ break;
1260
+ case "Enter":
1261
+ case " ":
1262
+ e.preventDefault();
1263
+ if (document.activeElement && menuItems.includes(document.activeElement)) {
1264
+ document.activeElement.click();
1265
+ }
1266
+ break;
1267
+ }
1268
+ };
1269
+ menu.addEventListener("keydown", handleKeyDown);
1270
+ }
1235
1271
  createElement() {
1236
1272
  this.element = DOMUtils.createElement("div", {
1237
1273
  className: `${this.player.options.classPrefix}-controls`,
@@ -1726,7 +1762,8 @@ var VidPly = (() => {
1726
1762
  className: `${this.player.options.classPrefix}-menu-item`,
1727
1763
  attributes: {
1728
1764
  "type": "button",
1729
- "role": "menuitem"
1765
+ "role": "menuitem",
1766
+ "tabindex": "-1"
1730
1767
  }
1731
1768
  });
1732
1769
  const timeLabel = DOMUtils.createElement("span", {
@@ -1746,6 +1783,13 @@ var VidPly = (() => {
1746
1783
  });
1747
1784
  menu.appendChild(item);
1748
1785
  }
1786
+ this.attachMenuKeyboardNavigation(menu);
1787
+ setTimeout(() => {
1788
+ const firstItem = menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
1789
+ if (firstItem) {
1790
+ firstItem.focus();
1791
+ }
1792
+ }, 0);
1749
1793
  }
1750
1794
  }
1751
1795
  button.appendChild(menu);
@@ -1799,19 +1843,22 @@ var VidPly = (() => {
1799
1843
  });
1800
1844
  menu.appendChild(noQualityItem);
1801
1845
  } else {
1846
+ let activeItem = null;
1802
1847
  if (isHLS) {
1803
1848
  const autoItem = DOMUtils.createElement("button", {
1804
1849
  className: `${this.player.options.classPrefix}-menu-item`,
1805
1850
  textContent: i18n.t("player.auto"),
1806
1851
  attributes: {
1807
1852
  "type": "button",
1808
- "role": "menuitem"
1853
+ "role": "menuitem",
1854
+ "tabindex": "-1"
1809
1855
  }
1810
1856
  });
1811
1857
  const isAuto = this.player.renderer.hls && this.player.renderer.hls.currentLevel === -1;
1812
1858
  if (isAuto) {
1813
1859
  autoItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
1814
1860
  autoItem.appendChild(createIconElement("check"));
1861
+ activeItem = autoItem;
1815
1862
  }
1816
1863
  autoItem.addEventListener("click", () => {
1817
1864
  if (this.player.renderer.switchQuality) {
@@ -1827,12 +1874,14 @@ var VidPly = (() => {
1827
1874
  textContent: quality.name || `${quality.height}p`,
1828
1875
  attributes: {
1829
1876
  "type": "button",
1830
- "role": "menuitem"
1877
+ "role": "menuitem",
1878
+ "tabindex": "-1"
1831
1879
  }
1832
1880
  });
1833
1881
  if (quality.index === currentQuality) {
1834
1882
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
1835
1883
  item.appendChild(createIconElement("check"));
1884
+ activeItem = item;
1836
1885
  }
1837
1886
  item.addEventListener("click", () => {
1838
1887
  if (this.player.renderer.switchQuality) {
@@ -1842,6 +1891,13 @@ var VidPly = (() => {
1842
1891
  });
1843
1892
  menu.appendChild(item);
1844
1893
  });
1894
+ this.attachMenuKeyboardNavigation(menu);
1895
+ setTimeout(() => {
1896
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
1897
+ if (focusTarget) {
1898
+ focusTarget.focus();
1899
+ }
1900
+ }, 0);
1845
1901
  }
1846
1902
  } else {
1847
1903
  const noSupportItem = DOMUtils.createElement("div", {
@@ -1935,6 +1991,12 @@ var VidPly = (() => {
1935
1991
  menu.style.minWidth = "220px";
1936
1992
  button.appendChild(menu);
1937
1993
  this.attachMenuCloseHandler(menu, button, true);
1994
+ setTimeout(() => {
1995
+ const firstSelect = menu.querySelector("select");
1996
+ if (firstSelect) {
1997
+ firstSelect.focus();
1998
+ }
1999
+ }, 0);
1938
2000
  }
1939
2001
  createStyleControl(label, property, options) {
1940
2002
  const group = DOMUtils.createElement("div", {
@@ -2147,18 +2209,21 @@ var VidPly = (() => {
2147
2209
  }
2148
2210
  });
2149
2211
  const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
2212
+ let activeItem = null;
2150
2213
  speeds.forEach((speed) => {
2151
2214
  const item = DOMUtils.createElement("button", {
2152
2215
  className: `${this.player.options.classPrefix}-menu-item`,
2153
2216
  textContent: this.formatSpeedLabel(speed),
2154
2217
  attributes: {
2155
2218
  "type": "button",
2156
- "role": "menuitem"
2219
+ "role": "menuitem",
2220
+ "tabindex": "-1"
2157
2221
  }
2158
2222
  });
2159
2223
  if (speed === this.player.state.playbackSpeed) {
2160
2224
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2161
2225
  item.appendChild(createIconElement("check"));
2226
+ activeItem = item;
2162
2227
  }
2163
2228
  item.addEventListener("click", () => {
2164
2229
  this.player.setPlaybackSpeed(speed);
@@ -2167,7 +2232,14 @@ var VidPly = (() => {
2167
2232
  menu.appendChild(item);
2168
2233
  });
2169
2234
  button.appendChild(menu);
2235
+ this.attachMenuKeyboardNavigation(menu);
2170
2236
  this.attachMenuCloseHandler(menu, button);
2237
+ setTimeout(() => {
2238
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
2239
+ if (focusTarget) {
2240
+ focusTarget.focus();
2241
+ }
2242
+ }, 0);
2171
2243
  }
2172
2244
  createCaptionsButton() {
2173
2245
  const button = DOMUtils.createElement("button", {
@@ -2210,17 +2282,20 @@ var VidPly = (() => {
2210
2282
  this.attachMenuCloseHandler(menu, button);
2211
2283
  return;
2212
2284
  }
2285
+ let activeItem = null;
2213
2286
  const offItem = DOMUtils.createElement("button", {
2214
2287
  className: `${this.player.options.classPrefix}-menu-item`,
2215
2288
  textContent: i18n.t("captions.off"),
2216
2289
  attributes: {
2217
2290
  "type": "button",
2218
- "role": "menuitem"
2291
+ "role": "menuitem",
2292
+ "tabindex": "-1"
2219
2293
  }
2220
2294
  });
2221
2295
  if (!this.player.state.captionsEnabled) {
2222
2296
  offItem.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2223
2297
  offItem.appendChild(createIconElement("check"));
2298
+ activeItem = offItem;
2224
2299
  }
2225
2300
  offItem.addEventListener("click", () => {
2226
2301
  this.player.disableCaptions();
@@ -2236,12 +2311,14 @@ var VidPly = (() => {
2236
2311
  attributes: {
2237
2312
  "type": "button",
2238
2313
  "role": "menuitem",
2239
- "lang": track.language
2314
+ "lang": track.language,
2315
+ "tabindex": "-1"
2240
2316
  }
2241
2317
  });
2242
2318
  if (this.player.state.captionsEnabled && this.player.captionManager.currentTrack === this.player.captionManager.tracks[track.index]) {
2243
2319
  item.classList.add(`${this.player.options.classPrefix}-menu-item-active`);
2244
2320
  item.appendChild(createIconElement("check"));
2321
+ activeItem = item;
2245
2322
  }
2246
2323
  item.addEventListener("click", () => {
2247
2324
  this.player.captionManager.switchTrack(track.index);
@@ -2251,7 +2328,14 @@ var VidPly = (() => {
2251
2328
  menu.appendChild(item);
2252
2329
  });
2253
2330
  button.appendChild(menu);
2331
+ this.attachMenuKeyboardNavigation(menu);
2254
2332
  this.attachMenuCloseHandler(menu, button);
2333
+ setTimeout(() => {
2334
+ const focusTarget = activeItem || menu.querySelector(`.${this.player.options.classPrefix}-menu-item`);
2335
+ if (focusTarget) {
2336
+ focusTarget.focus();
2337
+ }
2338
+ }, 0);
2255
2339
  }
2256
2340
  updateCaptionsButton() {
2257
2341
  if (!this.controls.captions) return;
@@ -2436,26 +2520,29 @@ var VidPly = (() => {
2436
2520
  }
2437
2521
  }
2438
2522
  updateVolumeDisplay() {
2439
- if (!this.controls.volumeFill) return;
2440
2523
  const percent = this.player.state.volume * 100;
2441
- this.controls.volumeFill.style.height = `${percent}%`;
2524
+ if (this.controls.volumeFill) {
2525
+ this.controls.volumeFill.style.height = `${percent}%`;
2526
+ }
2442
2527
  if (this.controls.mute) {
2443
2528
  const icon = this.controls.mute.querySelector(".vidply-icon");
2444
- let iconName;
2445
- if (this.player.state.muted || this.player.state.volume === 0) {
2446
- iconName = "volumeMuted";
2447
- } else if (this.player.state.volume < 0.3) {
2448
- iconName = "volumeLow";
2449
- } else if (this.player.state.volume < 0.7) {
2450
- iconName = "volumeMedium";
2451
- } else {
2452
- iconName = "volumeHigh";
2529
+ if (icon) {
2530
+ let iconName;
2531
+ if (this.player.state.muted || this.player.state.volume === 0) {
2532
+ iconName = "volumeMuted";
2533
+ } else if (this.player.state.volume < 0.3) {
2534
+ iconName = "volumeLow";
2535
+ } else if (this.player.state.volume < 0.7) {
2536
+ iconName = "volumeMedium";
2537
+ } else {
2538
+ iconName = "volumeHigh";
2539
+ }
2540
+ icon.innerHTML = createIconElement(iconName).innerHTML;
2541
+ this.controls.mute.setAttribute(
2542
+ "aria-label",
2543
+ this.player.state.muted ? i18n.t("player.unmute") : i18n.t("player.mute")
2544
+ );
2453
2545
  }
2454
- icon.innerHTML = createIconElement(iconName).innerHTML;
2455
- this.controls.mute.setAttribute(
2456
- "aria-label",
2457
- this.player.state.muted ? i18n.t("player.unmute") : i18n.t("player.mute")
2458
- );
2459
2546
  }
2460
2547
  if (this.controls.volumeSlider) {
2461
2548
  this.controls.volumeSlider.setAttribute("aria-valuenow", String(Math.round(percent)));
@@ -2640,7 +2727,6 @@ var VidPly = (() => {
2640
2727
  this.updateCaptions();
2641
2728
  };
2642
2729
  selectedTrack.track.addEventListener("cuechange", this.cueChangeHandler);
2643
- this.element.style.display = "block";
2644
2730
  this.player.emit("captionsenabled", selectedTrack);
2645
2731
  }
2646
2732
  }
@@ -2783,6 +2869,9 @@ var VidPly = (() => {
2783
2869
  }
2784
2870
  }
2785
2871
  }
2872
+ if (!handled && this.player.options.debug) {
2873
+ console.log("[VidPly] Unhandled key:", e.key, "code:", e.code, "shiftKey:", e.shiftKey);
2874
+ }
2786
2875
  }
2787
2876
  executeAction(action, event) {
2788
2877
  switch (action) {
@@ -2801,12 +2890,6 @@ var VidPly = (() => {
2801
2890
  case "seek-backward":
2802
2891
  this.player.seekBackward();
2803
2892
  return true;
2804
- case "seek-forward-large":
2805
- this.player.seekForward(this.player.options.seekIntervalLarge);
2806
- return true;
2807
- case "seek-backward-large":
2808
- this.player.seekBackward(this.player.options.seekIntervalLarge);
2809
- return true;
2810
2893
  case "mute":
2811
2894
  this.player.toggleMute();
2812
2895
  return true;
@@ -2815,14 +2898,22 @@ var VidPly = (() => {
2815
2898
  return true;
2816
2899
  case "captions":
2817
2900
  if (this.player.captionManager && this.player.captionManager.tracks.length > 1) {
2818
- const captionsButton = document.querySelector(".vidply-captions");
2819
- if (captionsButton && this.player.controlBar) {
2901
+ const captionsButton = this.player.controlBar && this.player.controlBar.controls.captions;
2902
+ if (captionsButton) {
2820
2903
  this.player.controlBar.showCaptionsMenu(captionsButton);
2904
+ } else {
2905
+ this.player.toggleCaptions();
2821
2906
  }
2822
2907
  } else {
2823
2908
  this.player.toggleCaptions();
2824
2909
  }
2825
2910
  return true;
2911
+ case "caption-style-menu":
2912
+ if (this.player.controlBar && this.player.controlBar.controls.captionStyle) {
2913
+ this.player.controlBar.showCaptionStyleMenu(this.player.controlBar.controls.captionStyle);
2914
+ return true;
2915
+ }
2916
+ return false;
2826
2917
  case "speed-up":
2827
2918
  this.player.setPlaybackSpeed(
2828
2919
  Math.min(2, this.player.state.playbackSpeed + 0.25)
@@ -2833,9 +2924,30 @@ var VidPly = (() => {
2833
2924
  Math.max(0.25, this.player.state.playbackSpeed - 0.25)
2834
2925
  );
2835
2926
  return true;
2836
- case "settings":
2837
- this.player.showSettings();
2838
- return true;
2927
+ case "speed-menu":
2928
+ if (this.player.controlBar && this.player.controlBar.controls.speed) {
2929
+ this.player.controlBar.showSpeedMenu(this.player.controlBar.controls.speed);
2930
+ return true;
2931
+ }
2932
+ return false;
2933
+ case "quality-menu":
2934
+ if (this.player.controlBar && this.player.controlBar.controls.quality) {
2935
+ this.player.controlBar.showQualityMenu(this.player.controlBar.controls.quality);
2936
+ return true;
2937
+ }
2938
+ return false;
2939
+ case "chapters-menu":
2940
+ if (this.player.controlBar && this.player.controlBar.controls.chapters) {
2941
+ this.player.controlBar.showChaptersMenu(this.player.controlBar.controls.chapters);
2942
+ return true;
2943
+ }
2944
+ return false;
2945
+ case "transcript-toggle":
2946
+ if (this.player.transcriptManager) {
2947
+ this.player.transcriptManager.toggleTranscript();
2948
+ return true;
2949
+ }
2950
+ return false;
2839
2951
  default:
2840
2952
  return false;
2841
2953
  }
@@ -2902,317 +3014,6 @@ var VidPly = (() => {
2902
3014
  }
2903
3015
  };
2904
3016
 
2905
- // src/controls/SettingsDialog.js
2906
- var SettingsDialog = class {
2907
- constructor(player) {
2908
- this.player = player;
2909
- this.element = null;
2910
- this.isOpen = false;
2911
- this.init();
2912
- }
2913
- init() {
2914
- this.createElement();
2915
- }
2916
- createElement() {
2917
- this.overlay = DOMUtils.createElement("div", {
2918
- className: `${this.player.options.classPrefix}-settings-overlay`,
2919
- attributes: {
2920
- "role": "dialog",
2921
- "aria-modal": "true",
2922
- "aria-label": i18n.t("settings.title")
2923
- }
2924
- });
2925
- this.overlay.style.display = "none";
2926
- this.element = DOMUtils.createElement("div", {
2927
- className: `${this.player.options.classPrefix}-settings-dialog`
2928
- });
2929
- const header = DOMUtils.createElement("div", {
2930
- className: `${this.player.options.classPrefix}-settings-header`
2931
- });
2932
- const title = DOMUtils.createElement("h2", {
2933
- textContent: i18n.t("settings.title"),
2934
- attributes: {
2935
- "id": `${this.player.options.classPrefix}-settings-title`
2936
- }
2937
- });
2938
- const closeButton = DOMUtils.createElement("button", {
2939
- className: `${this.player.options.classPrefix}-button ${this.player.options.classPrefix}-settings-close`,
2940
- attributes: {
2941
- "type": "button",
2942
- "aria-label": i18n.t("settings.close")
2943
- }
2944
- });
2945
- closeButton.appendChild(createIconElement("close"));
2946
- closeButton.addEventListener("click", () => this.hide());
2947
- header.appendChild(title);
2948
- header.appendChild(closeButton);
2949
- const content = DOMUtils.createElement("div", {
2950
- className: `${this.player.options.classPrefix}-settings-content`
2951
- });
2952
- content.appendChild(this.createSpeedSettings());
2953
- if (this.player.captionManager && this.player.captionManager.tracks.length > 0) {
2954
- content.appendChild(this.createCaptionSettings());
2955
- }
2956
- const footer = DOMUtils.createElement("div", {
2957
- className: `${this.player.options.classPrefix}-settings-footer`
2958
- });
2959
- const resetButton = DOMUtils.createElement("button", {
2960
- className: `${this.player.options.classPrefix}-button`,
2961
- textContent: i18n.t("settings.reset"),
2962
- attributes: {
2963
- "type": "button"
2964
- }
2965
- });
2966
- resetButton.addEventListener("click", () => this.resetSettings());
2967
- footer.appendChild(resetButton);
2968
- this.element.appendChild(header);
2969
- this.element.appendChild(content);
2970
- this.element.appendChild(footer);
2971
- this.overlay.appendChild(this.element);
2972
- this.player.container.appendChild(this.overlay);
2973
- this.overlay.addEventListener("click", (e) => {
2974
- if (e.target === this.overlay) {
2975
- this.hide();
2976
- }
2977
- });
2978
- document.addEventListener("keydown", (e) => {
2979
- if (e.key === "Escape" && this.isOpen) {
2980
- this.hide();
2981
- }
2982
- });
2983
- }
2984
- formatSpeedLabel(speed) {
2985
- if (speed === 1) {
2986
- return i18n.t("speeds.normal");
2987
- }
2988
- const speedStr = speed.toLocaleString(i18n.getLanguage(), {
2989
- minimumFractionDigits: 0,
2990
- maximumFractionDigits: 2
2991
- });
2992
- return `${speedStr}\xD7`;
2993
- }
2994
- createSpeedSettings() {
2995
- const section = DOMUtils.createElement("div", {
2996
- className: `${this.player.options.classPrefix}-settings-section`
2997
- });
2998
- const label = DOMUtils.createElement("label", {
2999
- textContent: i18n.t("settings.speed"),
3000
- attributes: {
3001
- "for": `${this.player.options.classPrefix}-speed-select`
3002
- }
3003
- });
3004
- const select = DOMUtils.createElement("select", {
3005
- className: `${this.player.options.classPrefix}-settings-select`,
3006
- attributes: {
3007
- "id": `${this.player.options.classPrefix}-speed-select`
3008
- }
3009
- });
3010
- const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
3011
- speeds.forEach((speed) => {
3012
- const option = DOMUtils.createElement("option", {
3013
- textContent: this.formatSpeedLabel(speed),
3014
- attributes: {
3015
- "value": String(speed)
3016
- }
3017
- });
3018
- if (speed === this.player.state.playbackSpeed) {
3019
- option.selected = true;
3020
- }
3021
- select.appendChild(option);
3022
- });
3023
- select.addEventListener("change", (e) => {
3024
- this.player.setPlaybackSpeed(parseFloat(e.target.value));
3025
- });
3026
- section.appendChild(label);
3027
- section.appendChild(select);
3028
- return section;
3029
- }
3030
- createCaptionSettings() {
3031
- const section = DOMUtils.createElement("div", {
3032
- className: `${this.player.options.classPrefix}-settings-section`
3033
- });
3034
- const heading = DOMUtils.createElement("h3", {
3035
- textContent: i18n.t("settings.captions")
3036
- });
3037
- section.appendChild(heading);
3038
- const trackLabel = DOMUtils.createElement("label", {
3039
- textContent: i18n.t("captions.select"),
3040
- attributes: {
3041
- "for": `${this.player.options.classPrefix}-caption-track-select`
3042
- }
3043
- });
3044
- const trackSelect = DOMUtils.createElement("select", {
3045
- className: `${this.player.options.classPrefix}-settings-select`,
3046
- attributes: {
3047
- "id": `${this.player.options.classPrefix}-caption-track-select`
3048
- }
3049
- });
3050
- const offOption = DOMUtils.createElement("option", {
3051
- textContent: i18n.t("captions.off"),
3052
- attributes: { "value": "-1" }
3053
- });
3054
- trackSelect.appendChild(offOption);
3055
- const tracks = this.player.captionManager.getAvailableTracks();
3056
- tracks.forEach((track) => {
3057
- const option = DOMUtils.createElement("option", {
3058
- textContent: track.label,
3059
- attributes: { "value": String(track.index) }
3060
- });
3061
- trackSelect.appendChild(option);
3062
- });
3063
- trackSelect.addEventListener("change", (e) => {
3064
- const index = parseInt(e.target.value);
3065
- if (index === -1) {
3066
- this.player.disableCaptions();
3067
- } else {
3068
- this.player.captionManager.switchTrack(index);
3069
- }
3070
- });
3071
- section.appendChild(trackLabel);
3072
- section.appendChild(trackSelect);
3073
- section.appendChild(this.createCaptionStyleControl("fontSize", i18n.t("captions.fontSize"), [
3074
- { label: i18n.t("fontSizes.small"), value: "80%" },
3075
- { label: i18n.t("fontSizes.medium"), value: "100%" },
3076
- { label: i18n.t("fontSizes.large"), value: "120%" },
3077
- { label: i18n.t("fontSizes.xlarge"), value: "150%" }
3078
- ]));
3079
- section.appendChild(this.createCaptionStyleControl("fontFamily", i18n.t("captions.fontFamily"), [
3080
- { label: i18n.t("fontFamilies.sansSerif"), value: "sans-serif" },
3081
- { label: i18n.t("fontFamilies.serif"), value: "serif" },
3082
- { label: i18n.t("fontFamilies.monospace"), value: "monospace" }
3083
- ]));
3084
- section.appendChild(this.createColorControl("color", i18n.t("captions.color")));
3085
- section.appendChild(this.createColorControl("backgroundColor", i18n.t("captions.backgroundColor")));
3086
- section.appendChild(this.createRangeControl("opacity", i18n.t("captions.opacity"), 0, 1, 0.1));
3087
- return section;
3088
- }
3089
- createCaptionStyleControl(property, label, options) {
3090
- const wrapper = DOMUtils.createElement("div", {
3091
- className: `${this.player.options.classPrefix}-settings-control`
3092
- });
3093
- const labelEl = DOMUtils.createElement("label", {
3094
- textContent: label,
3095
- attributes: {
3096
- "for": `${this.player.options.classPrefix}-caption-${property}`
3097
- }
3098
- });
3099
- const select = DOMUtils.createElement("select", {
3100
- className: `${this.player.options.classPrefix}-settings-select`,
3101
- attributes: {
3102
- "id": `${this.player.options.classPrefix}-caption-${property}`
3103
- }
3104
- });
3105
- options.forEach((opt) => {
3106
- const option = DOMUtils.createElement("option", {
3107
- textContent: opt.label,
3108
- attributes: { "value": opt.value }
3109
- });
3110
- if (opt.value === this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`]) {
3111
- option.selected = true;
3112
- }
3113
- select.appendChild(option);
3114
- });
3115
- select.addEventListener("change", (e) => {
3116
- this.player.captionManager.setCaptionStyle(property, e.target.value);
3117
- });
3118
- wrapper.appendChild(labelEl);
3119
- wrapper.appendChild(select);
3120
- return wrapper;
3121
- }
3122
- createColorControl(property, label) {
3123
- const wrapper = DOMUtils.createElement("div", {
3124
- className: `${this.player.options.classPrefix}-settings-control`
3125
- });
3126
- const labelEl = DOMUtils.createElement("label", {
3127
- textContent: label,
3128
- attributes: {
3129
- "for": `${this.player.options.classPrefix}-caption-${property}`
3130
- }
3131
- });
3132
- const input = DOMUtils.createElement("input", {
3133
- className: `${this.player.options.classPrefix}-settings-color`,
3134
- attributes: {
3135
- "type": "color",
3136
- "id": `${this.player.options.classPrefix}-caption-${property}`,
3137
- "value": this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`]
3138
- }
3139
- });
3140
- input.addEventListener("change", (e) => {
3141
- this.player.captionManager.setCaptionStyle(property, e.target.value);
3142
- });
3143
- wrapper.appendChild(labelEl);
3144
- wrapper.appendChild(input);
3145
- return wrapper;
3146
- }
3147
- createRangeControl(property, label, min, max, step) {
3148
- const wrapper = DOMUtils.createElement("div", {
3149
- className: `${this.player.options.classPrefix}-settings-control`
3150
- });
3151
- const labelEl = DOMUtils.createElement("label", {
3152
- textContent: label,
3153
- attributes: {
3154
- "for": `${this.player.options.classPrefix}-caption-${property}`
3155
- }
3156
- });
3157
- const input = DOMUtils.createElement("input", {
3158
- className: `${this.player.options.classPrefix}-settings-range`,
3159
- attributes: {
3160
- "type": "range",
3161
- "id": `${this.player.options.classPrefix}-caption-${property}`,
3162
- "min": String(min),
3163
- "max": String(max),
3164
- "step": String(step),
3165
- "value": String(this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`])
3166
- }
3167
- });
3168
- const valueDisplay = DOMUtils.createElement("span", {
3169
- className: `${this.player.options.classPrefix}-settings-value`,
3170
- textContent: String(this.player.options[`captions${property.charAt(0).toUpperCase() + property.slice(1)}`])
3171
- });
3172
- input.addEventListener("input", (e) => {
3173
- const value = parseFloat(e.target.value);
3174
- valueDisplay.textContent = value.toFixed(1);
3175
- this.player.captionManager.setCaptionStyle(property, value);
3176
- });
3177
- wrapper.appendChild(labelEl);
3178
- wrapper.appendChild(input);
3179
- wrapper.appendChild(valueDisplay);
3180
- return wrapper;
3181
- }
3182
- resetSettings() {
3183
- this.player.setPlaybackSpeed(1);
3184
- if (this.player.captionManager) {
3185
- this.player.captionManager.setCaptionStyle("fontSize", "100%");
3186
- this.player.captionManager.setCaptionStyle("fontFamily", "sans-serif");
3187
- this.player.captionManager.setCaptionStyle("color", "#FFFFFF");
3188
- this.player.captionManager.setCaptionStyle("backgroundColor", "#000000");
3189
- this.player.captionManager.setCaptionStyle("opacity", 0.8);
3190
- }
3191
- this.hide();
3192
- setTimeout(() => this.show(), 100);
3193
- }
3194
- show() {
3195
- this.overlay.style.display = "flex";
3196
- this.isOpen = true;
3197
- const closeButton = this.element.querySelector(`.${this.player.options.classPrefix}-settings-close`);
3198
- if (closeButton) {
3199
- closeButton.focus();
3200
- }
3201
- this.player.emit("settingsopen");
3202
- }
3203
- hide() {
3204
- this.overlay.style.display = "none";
3205
- this.isOpen = false;
3206
- this.player.container.focus();
3207
- this.player.emit("settingsclose");
3208
- }
3209
- destroy() {
3210
- if (this.overlay && this.overlay.parentNode) {
3211
- this.overlay.parentNode.removeChild(this.overlay);
3212
- }
3213
- }
3214
- };
3215
-
3216
3017
  // src/controls/TranscriptManager.js
3217
3018
  var TranscriptManager = class {
3218
3019
  constructor(player) {
@@ -4500,16 +4301,18 @@ var VidPly = (() => {
4500
4301
  "play-pause": [" ", "p", "k"],
4501
4302
  "volume-up": ["ArrowUp"],
4502
4303
  "volume-down": ["ArrowDown"],
4503
- "seek-forward": ["ArrowRight", "f"],
4504
- "seek-backward": ["ArrowLeft", "r"],
4505
- "seek-forward-large": ["l"],
4506
- "seek-backward-large": ["j"],
4304
+ "seek-forward": ["ArrowRight"],
4305
+ "seek-backward": ["ArrowLeft"],
4507
4306
  "mute": ["m"],
4508
4307
  "fullscreen": ["f"],
4509
4308
  "captions": ["c"],
4309
+ "caption-style-menu": ["a"],
4510
4310
  "speed-up": [">"],
4511
4311
  "speed-down": ["<"],
4512
- "settings": ["s"]
4312
+ "speed-menu": ["s"],
4313
+ "quality-menu": ["q"],
4314
+ "chapters-menu": ["j"],
4315
+ "transcript-toggle": ["t"]
4513
4316
  },
4514
4317
  // Accessibility
4515
4318
  ariaLabels: {},
@@ -4598,9 +4401,6 @@ var VidPly = (() => {
4598
4401
  if (this.options.keyboard) {
4599
4402
  this.keyboardManager = new KeyboardManager(this);
4600
4403
  }
4601
- if (this.options.settingsButton) {
4602
- this.settingsDialog = new SettingsDialog(this);
4603
- }
4604
4404
  this.setupResponsiveHandlers();
4605
4405
  if (this.options.startTime > 0) {
4606
4406
  this.seek(this.options.startTime);
@@ -4853,12 +4653,14 @@ var VidPly = (() => {
4853
4653
  this.renderer.setMuted(true);
4854
4654
  }
4855
4655
  this.state.muted = true;
4656
+ this.emit("volumechange");
4856
4657
  }
4857
4658
  unmute() {
4858
4659
  if (this.renderer) {
4859
4660
  this.renderer.setMuted(false);
4860
4661
  }
4861
4662
  this.state.muted = false;
4663
+ this.emit("volumechange");
4862
4664
  }
4863
4665
  toggleMute() {
4864
4666
  if (this.state.muted) {
@@ -5092,15 +4894,11 @@ var VidPly = (() => {
5092
4894
  }
5093
4895
  }
5094
4896
  // Settings
4897
+ // Settings dialog removed - using individual control buttons instead
5095
4898
  showSettings() {
5096
- if (this.settingsDialog) {
5097
- this.settingsDialog.show();
5098
- }
4899
+ console.warn("[VidPly] Settings dialog has been removed. Use individual control buttons (speed, captions, etc.)");
5099
4900
  }
5100
4901
  hideSettings() {
5101
- if (this.settingsDialog) {
5102
- this.settingsDialog.hide();
5103
- }
5104
4902
  }
5105
4903
  // Utility methods
5106
4904
  getCurrentTime() {
@@ -5197,9 +4995,6 @@ var VidPly = (() => {
5197
4995
  if (this.keyboardManager) {
5198
4996
  this.keyboardManager.destroy();
5199
4997
  }
5200
- if (this.settingsDialog) {
5201
- this.settingsDialog.destroy();
5202
- }
5203
4998
  if (this.transcriptManager) {
5204
4999
  this.transcriptManager.destroy();
5205
5000
  }