@geekapps/silo-elements-nextjs 0.2.51 → 0.2.53

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/index.js CHANGED
@@ -3,7 +3,7 @@ import { useMultipartUpload, useBatchUpload, useSignedUrl, useFileStatus } from
3
3
  export { SiloProvider, useBatchUpload, useFileStatus, useMultipartUpload, useSignedUrl } from '@geekapps/silo-nextjs';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import gsap from 'gsap';
6
- import { Pause, Play, VolumeX, Volume2, Captions as Captions$1, Settings, Minimize, Maximize } from 'lucide-react';
6
+ import { Pause, Play, Captions as Captions$1, Settings, Minimize, Maximize, VolumeX, Volume2 } from 'lucide-react';
7
7
 
8
8
  // src/ImageUploader.tsx
9
9
 
@@ -1231,6 +1231,8 @@ function Video({
1231
1231
  const [audioTracks, setAudioTracks] = useState([]);
1232
1232
  const [selectedAudio, setSelectedAudio] = useState(0);
1233
1233
  const [settingsOpen, setSettingsOpen] = useState(false);
1234
+ const [settingsVisible, setSettingsVisible] = useState(false);
1235
+ const settingsCloseTimerRef = useRef(null);
1234
1236
  const [settingsTab, setSettingsTab] = useState("root");
1235
1237
  const [playbackRate, setPlaybackRate] = useState(1);
1236
1238
  const [subtitleStyle, setSubtitleStyle] = useState({
@@ -1241,6 +1243,8 @@ function Video({
1241
1243
  });
1242
1244
  const [subtitleMode, setSubtitleMode] = useState(initialSubtitleMode);
1243
1245
  const [activeCue, setActiveCue] = useState(null);
1246
+ const [storyboardSheetSize, setStoryboardSheetSize] = useState(null);
1247
+ const storyboardSheetUrlRef = useRef("");
1244
1248
  const [storyboardCues, setStoryboardCues] = useState(
1245
1249
  []
1246
1250
  );
@@ -1249,6 +1253,7 @@ function Video({
1249
1253
  const [currentTime, setCurrentTime] = useState(0);
1250
1254
  const [bufferedTime, setBufferedTime] = useState(0);
1251
1255
  const [isDragging, setIsDragging] = useState(false);
1256
+ const [isHoveringProgress, setIsHoveringProgress] = useState(false);
1252
1257
  const dragPointerIdRef = useRef(null);
1253
1258
  const [isPlaying, setIsPlaying] = useState(false);
1254
1259
  const [hasPlayed, setHasPlayed] = useState(false);
@@ -1277,11 +1282,20 @@ function Video({
1277
1282
  const applySubtitleMode = useCallback((mode) => {
1278
1283
  const video = videoRef.current;
1279
1284
  if (!video) return;
1285
+ let activeTrack = null;
1280
1286
  Array.from(video.textTracks).forEach((track) => {
1281
1287
  if (track.kind === "metadata") return;
1282
- track.mode = mode !== "off" && track.language === mode ? "hidden" : "disabled";
1288
+ const enabled = mode !== "off" && track.language === mode;
1289
+ track.mode = enabled ? "hidden" : "disabled";
1290
+ if (enabled) activeTrack = track;
1283
1291
  });
1284
- if (mode === "off") setActiveCue(null);
1292
+ if (!activeTrack) {
1293
+ setActiveCue(null);
1294
+ return;
1295
+ }
1296
+ const cues = activeTrack.activeCues;
1297
+ const cue = cues && cues.length > 0 ? cues[0] : null;
1298
+ setActiveCue(cue ? cue.text.replace(/<[^>]*>/g, "") : null);
1285
1299
  }, []);
1286
1300
  const showControlsTemporarily = useCallback(() => {
1287
1301
  setControlsVisible(true);
@@ -1315,6 +1329,16 @@ function Video({
1315
1329
  }
1316
1330
  );
1317
1331
  }, []);
1332
+ const openSettings = useCallback(() => {
1333
+ setSettingsOpen(true);
1334
+ setSettingsTab("root");
1335
+ window.setTimeout(() => setSettingsVisible(true), 10);
1336
+ }, []);
1337
+ const closeSettings = useCallback(() => {
1338
+ setSettingsVisible(false);
1339
+ if (settingsCloseTimerRef.current) window.clearTimeout(settingsCloseTimerRef.current);
1340
+ settingsCloseTimerRef.current = window.setTimeout(() => setSettingsOpen(false), 200);
1341
+ }, []);
1318
1342
  useEffect(() => {
1319
1343
  if (sourceIndex >= parsed.sources.length) {
1320
1344
  setSourceIndex(initialSourceIndex);
@@ -1540,7 +1564,7 @@ function Video({
1540
1564
  setQualities([AUTO_QUALITY]);
1541
1565
  setAudioTracks([]);
1542
1566
  setSelectedAudio(0);
1543
- setSettingsOpen(false);
1567
+ closeSettings();
1544
1568
  video.pause();
1545
1569
  video.removeAttribute("src");
1546
1570
  video.load();
@@ -1767,17 +1791,17 @@ function Video({
1767
1791
  }, []);
1768
1792
  const changeAudio = useCallback((trackId) => {
1769
1793
  setSelectedAudio(trackId);
1770
- setSettingsOpen(false);
1794
+ closeSettings();
1771
1795
  if (hlsRef.current) {
1772
1796
  hlsRef.current.audioTrack = trackId;
1773
1797
  }
1774
- }, []);
1798
+ }, [closeSettings]);
1775
1799
  const changeQuality = useCallback(
1776
1800
  (qualityId) => {
1777
1801
  const option = qualities.find((quality) => quality.id === qualityId);
1778
1802
  if (!option) return;
1779
1803
  setSelectedQuality(qualityId);
1780
- setSettingsOpen(false);
1804
+ closeSettings();
1781
1805
  if (option.type === "auto") {
1782
1806
  if (hlsRef.current) {
1783
1807
  hlsRef.current.currentLevel = -1;
@@ -1812,7 +1836,7 @@ function Video({
1812
1836
  dashRef.current.setQualityFor("video", option.index);
1813
1837
  }
1814
1838
  },
1815
- [qualities]
1839
+ [qualities, closeSettings]
1816
1840
  );
1817
1841
  const seekFromPointer = useCallback(
1818
1842
  (clientX) => {
@@ -1857,7 +1881,11 @@ function Video({
1857
1881
  },
1858
1882
  [isDragging, seekFromPointer, updatePreview]
1859
1883
  );
1884
+ const handleProgressPointerEnter = useCallback(() => {
1885
+ setIsHoveringProgress(true);
1886
+ }, []);
1860
1887
  const handleProgressPointerLeave = useCallback(() => {
1888
+ setIsHoveringProgress(false);
1861
1889
  if (!isDragging) setPreview(null);
1862
1890
  }, [isDragging]);
1863
1891
  const handleProgressPointerDown = useCallback(
@@ -1928,10 +1956,18 @@ function Video({
1928
1956
  onKeyDown: handleKeyDown,
1929
1957
  onMouseMove: showControlsTemporarily,
1930
1958
  onMouseLeave: () => {
1959
+ closeSettings();
1931
1960
  if (isPlaying && autoHideControls) {
1932
1961
  setControlsVisible(false);
1933
1962
  }
1934
1963
  },
1964
+ onBlur: (e) => {
1965
+ if (!e.currentTarget.contains(e.relatedTarget)) {
1966
+ closeSettings();
1967
+ }
1968
+ },
1969
+ onTouchStart: showControlsTemporarily,
1970
+ onTouchMove: showControlsTemporarily,
1935
1971
  className: "relative w-full overflow-hidden rounded-[14px] bg-black shadow-[0_30px_90px_rgba(15,15,15,0.22)] outline-none ring-1 ring-black/5",
1936
1972
  style: fixedHeight ? {
1937
1973
  height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
@@ -1944,7 +1980,7 @@ function Video({
1944
1980
  "video",
1945
1981
  {
1946
1982
  ref: videoRef,
1947
- className: "h-full w-full object-contain",
1983
+ className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
1948
1984
  playsInline: true,
1949
1985
  preload: "metadata",
1950
1986
  crossOrigin: "anonymous",
@@ -2035,7 +2071,7 @@ function Video({
2035
2071
  "div",
2036
2072
  {
2037
2073
  className: "fixed inset-0 z-70",
2038
- onClick: () => setSettingsOpen(false)
2074
+ onClick: closeSettings
2039
2075
  }
2040
2076
  ),
2041
2077
  /* @__PURE__ */ jsxs(
@@ -2047,7 +2083,9 @@ function Video({
2047
2083
  224,
2048
2084
  Math.max(180, (playerWidth || 640) * 0.22)
2049
2085
  ) + "px",
2050
- animation: "spFadeIn 0.15s ease"
2086
+ opacity: settingsVisible ? 1 : 0,
2087
+ transform: settingsVisible ? "translateY(0) scale(1)" : "translateY(8px) scale(0.97)",
2088
+ transition: "opacity 0.18s ease, transform 0.18s ease"
2051
2089
  },
2052
2090
  children: [
2053
2091
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
@@ -2481,8 +2519,7 @@ function Video({
2481
2519
  type: "button",
2482
2520
  onClick: () => {
2483
2521
  setPlaybackRate(speed);
2484
- setSettingsOpen(false);
2485
- setSettingsTab("root");
2522
+ closeSettings();
2486
2523
  },
2487
2524
  className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2488
2525
  children: [
@@ -2518,37 +2555,40 @@ function Video({
2518
2555
  ] })
2519
2556
  ]
2520
2557
  }
2521
- ),
2522
- /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
2558
+ )
2523
2559
  ] }),
2524
2560
  /* @__PURE__ */ jsxs(
2525
2561
  "div",
2526
2562
  {
2527
2563
  ref: progressRef,
2528
2564
  onPointerMove: handleProgressPointerMove,
2565
+ onPointerEnter: handleProgressPointerEnter,
2529
2566
  onPointerLeave: handleProgressPointerLeave,
2530
2567
  onPointerDown: handleProgressPointerDown,
2531
2568
  onPointerUp: handleProgressPointerUp,
2532
- className: "group relative mb-3 h-7 cursor-pointer",
2569
+ className: "relative mb-2 h-8 cursor-pointer overflow-visible",
2533
2570
  children: [
2534
2571
  /* @__PURE__ */ jsxs(
2535
2572
  "div",
2536
2573
  {
2537
- className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 transition-[height] duration-150",
2538
- style: { height: isDragging ? "6px" : "3px" },
2574
+ className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/18",
2575
+ style: {
2576
+ height: isDragging ? "7px" : isHoveringProgress ? "5px" : "3px",
2577
+ transition: "height 0.15s ease"
2578
+ },
2539
2579
  children: [
2540
2580
  /* @__PURE__ */ jsx(
2541
2581
  "div",
2542
2582
  {
2543
- className: "absolute inset-y-0 left-0 rounded-full bg-white/30",
2583
+ className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
2544
2584
  style: { width: `${bufferedPercent}%` }
2545
2585
  }
2546
2586
  ),
2547
2587
  /* @__PURE__ */ jsx(
2548
2588
  "div",
2549
2589
  {
2550
- className: "absolute inset-y-0 left-0 rounded-full bg-white/90",
2551
- style: { width: `${progressPercent}%` }
2590
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
2591
+ style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
2552
2592
  }
2553
2593
  )
2554
2594
  ]
@@ -2557,14 +2597,90 @@ function Video({
2557
2597
  /* @__PURE__ */ jsx(
2558
2598
  "div",
2559
2599
  {
2560
- className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md transition-[width,height] duration-100 group-hover:size-4",
2600
+ className: "pointer-events-none absolute rounded-full bg-white shadow-[0_1px_6px_rgba(0,0,0,0.5)]",
2561
2601
  style: {
2602
+ top: "50%",
2562
2603
  left: `${progressPercent}%`,
2563
- width: isDragging ? "16px" : "10px",
2564
- height: isDragging ? "16px" : "10px"
2604
+ transform: "translate(-50%, -50%)",
2605
+ width: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
2606
+ height: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
2607
+ transition: "width 0.2s cubic-bezier(0.34,1.56,0.64,1), height 0.2s cubic-bezier(0.34,1.56,0.64,1)"
2565
2608
  }
2566
2609
  }
2567
- )
2610
+ ),
2611
+ preview && (() => {
2612
+ const frameW = preview.cue.w ?? 160;
2613
+ const frameH = preview.cue.h ?? 90;
2614
+ const thumbW = 200;
2615
+ const thumbH = Math.round(thumbW * (frameH / frameW));
2616
+ const scale = thumbW / frameW;
2617
+ const isSprite = preview.cue.x != null && preview.cue.y != null;
2618
+ return /* @__PURE__ */ jsxs(
2619
+ "div",
2620
+ {
2621
+ className: "pointer-events-none absolute flex flex-col items-center gap-1",
2622
+ style: {
2623
+ bottom: "calc(100% + 6px)",
2624
+ left: preview.left,
2625
+ transform: "translateX(-50%)",
2626
+ zIndex: 80
2627
+ },
2628
+ children: [
2629
+ /* @__PURE__ */ jsx(
2630
+ "div",
2631
+ {
2632
+ className: "overflow-hidden rounded-lg shadow-2xl ring-1 ring-white/20",
2633
+ style: { width: thumbW, height: thumbH, flexShrink: 0 },
2634
+ children: isSprite ? (
2635
+ // Sprite: need full sheet dimensions to compute backgroundSize correctly.
2636
+ // Load them once from the image's natural size.
2637
+ (() => {
2638
+ const imgUrl = preview.cue.image;
2639
+ if (storyboardSheetUrlRef.current !== imgUrl) {
2640
+ storyboardSheetUrlRef.current = imgUrl;
2641
+ const img = new window.Image();
2642
+ img.onload = () => setStoryboardSheetSize({ w: img.naturalWidth, h: img.naturalHeight });
2643
+ img.src = imgUrl;
2644
+ }
2645
+ if (!storyboardSheetSize) return null;
2646
+ const bsW = storyboardSheetSize.w * scale;
2647
+ const bsH = storyboardSheetSize.h * scale;
2648
+ return /* @__PURE__ */ jsx(
2649
+ "div",
2650
+ {
2651
+ style: {
2652
+ width: thumbW,
2653
+ height: thumbH,
2654
+ backgroundImage: `url(${imgUrl})`,
2655
+ backgroundRepeat: "no-repeat",
2656
+ backgroundPosition: `-${(preview.cue.x ?? 0) * scale}px -${(preview.cue.y ?? 0) * scale}px`,
2657
+ backgroundSize: `${bsW}px ${bsH}px`
2658
+ }
2659
+ }
2660
+ );
2661
+ })()
2662
+ ) : /* @__PURE__ */ jsx(
2663
+ "img",
2664
+ {
2665
+ src: preview.cue.image,
2666
+ alt: "",
2667
+ style: { width: thumbW, height: thumbH, objectFit: "cover", objectPosition: "center", display: "block" }
2668
+ }
2669
+ )
2670
+ }
2671
+ ),
2672
+ /* @__PURE__ */ jsx(
2673
+ "span",
2674
+ {
2675
+ className: "rounded-md px-2 py-0.5 text-[11px] font-semibold tabular-nums text-white/90",
2676
+ style: { background: "rgba(0,0,0,0.55)", backdropFilter: "blur(6px)" },
2677
+ children: formatTime(preview.time)
2678
+ }
2679
+ )
2680
+ ]
2681
+ }
2682
+ );
2683
+ })()
2568
2684
  ]
2569
2685
  }
2570
2686
  ),
@@ -2587,44 +2703,29 @@ function Video({
2587
2703
  ] })
2588
2704
  ] }),
2589
2705
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
2590
- /* @__PURE__ */ jsxs("div", { className: "group flex items-center", children: [
2591
- /* @__PURE__ */ jsx(
2592
- "button",
2593
- {
2594
- type: "button",
2595
- onClick: () => setIsMuted((value) => !value),
2596
- className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
2597
- "aria-label": isMuted ? "Unmute" : "Mute",
2598
- children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2599
- }
2600
- ),
2601
- /* @__PURE__ */ jsx("div", { className: "w-0 overflow-hidden transition-all duration-200 group-hover:w-16 @md:group-hover:w-20", children: /* @__PURE__ */ jsx(
2602
- "input",
2603
- {
2604
- type: "range",
2605
- min: "0",
2606
- max: "1",
2607
- step: "0.01",
2608
- value: isMuted ? 0 : volume,
2609
- onChange: (event) => {
2610
- const nextVolume = Number(event.target.value);
2611
- setVolume(nextVolume);
2612
- setIsMuted(nextVolume === 0);
2613
- },
2614
- className: "h-1 w-14 accent-white @md:w-20",
2615
- "aria-label": "Audio level"
2616
- }
2617
- ) })
2618
- ] }),
2706
+ /* @__PURE__ */ jsx(
2707
+ VolumeSlider,
2708
+ {
2709
+ volume: isMuted ? 0 : volume,
2710
+ onMuteToggle: () => setIsMuted((v) => !v),
2711
+ onVolumeChange: (v) => {
2712
+ setVolume(v);
2713
+ setIsMuted(v === 0);
2714
+ },
2715
+ isMuted
2716
+ }
2717
+ ),
2619
2718
  /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
2620
2719
  captions.length > 0 && /* @__PURE__ */ jsx(
2621
2720
  "button",
2622
2721
  {
2623
2722
  type: "button",
2624
- onClick: () => setSubtitleMode(
2625
- (m) => m === "off" ? captions[0]?.srclang ?? "off" : "off"
2626
- ),
2627
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
2723
+ onClick: () => {
2724
+ const next = subtitleMode === "off" ? captions[0]?.srclang ?? "off" : "off";
2725
+ setSubtitleMode(next);
2726
+ setSubtitleStyle((st) => ({ ...st, track: next }));
2727
+ },
2728
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
2628
2729
  "aria-label": "Captions",
2629
2730
  children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
2630
2731
  }
@@ -2633,11 +2734,8 @@ function Video({
2633
2734
  "button",
2634
2735
  {
2635
2736
  type: "button",
2636
- onClick: () => {
2637
- setSettingsOpen((v) => !v);
2638
- setSettingsTab("root");
2639
- },
2640
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${settingsOpen ? "text-white" : "text-white/60"}`,
2737
+ onClick: () => settingsOpen ? closeSettings() : openSettings(),
2738
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
2641
2739
  "aria-label": "Settings",
2642
2740
  children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
2643
2741
  }
@@ -2660,65 +2758,6 @@ function Video({
2660
2758
  ]
2661
2759
  }
2662
2760
  ),
2663
- preview && (() => {
2664
- const srcW = preview.cue.w ?? 160;
2665
- const srcH = preview.cue.h ?? 90;
2666
- const thumbW = Math.max(
2667
- 140,
2668
- Math.round((playerWidth || 640) * 0.13)
2669
- );
2670
- const thumbH = Math.round(thumbW * (srcH / srcW));
2671
- const scale = thumbW / srcW;
2672
- const isSprite = preview.cue.x != null && preview.cue.y != null;
2673
- return /* @__PURE__ */ jsx(
2674
- "div",
2675
- {
2676
- className: "pointer-events-none absolute z-60 -translate-x-1/2 -translate-y-2 overflow-hidden rounded-xl shadow-2xl ring-1 ring-white/15",
2677
- style: {
2678
- bottom: controlsVisible ? "80px" : "20px",
2679
- left: preview.left,
2680
- transition: "bottom 0.2s"
2681
- },
2682
- children: isSprite ? /* @__PURE__ */ jsx(
2683
- "div",
2684
- {
2685
- style: {
2686
- width: thumbW,
2687
- height: thumbH,
2688
- overflow: "hidden"
2689
- },
2690
- children: /* @__PURE__ */ jsx(
2691
- "div",
2692
- {
2693
- style: {
2694
- width: srcW,
2695
- height: srcH,
2696
- backgroundImage: `url(${preview.cue.image})`,
2697
- backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
2698
- backgroundSize: "auto",
2699
- backgroundRepeat: "no-repeat",
2700
- transform: `scale(${scale})`,
2701
- transformOrigin: "top left"
2702
- }
2703
- }
2704
- )
2705
- }
2706
- ) : /* @__PURE__ */ jsx(
2707
- "div",
2708
- {
2709
- style: {
2710
- width: thumbW,
2711
- height: thumbH,
2712
- backgroundImage: `url(${preview.cue.image})`,
2713
- backgroundSize: "cover",
2714
- backgroundPosition: "center",
2715
- backgroundRepeat: "no-repeat"
2716
- }
2717
- }
2718
- )
2719
- }
2720
- );
2721
- })(),
2722
2761
  activeCue && /* @__PURE__ */ jsx(
2723
2762
  "div",
2724
2763
  {
@@ -2752,6 +2791,109 @@ function Video({
2752
2791
  );
2753
2792
  }
2754
2793
  var VideoPlayer = Video;
2794
+ function VolumeSlider({
2795
+ volume,
2796
+ isMuted,
2797
+ onMuteToggle,
2798
+ onVolumeChange
2799
+ }) {
2800
+ const [hovered, setHovered] = useState(false);
2801
+ const [dragging, setDragging] = useState(false);
2802
+ const trackRef = useRef(null);
2803
+ const expanded = hovered || dragging;
2804
+ const seek = useCallback((clientX) => {
2805
+ const track = trackRef.current;
2806
+ if (!track) return;
2807
+ const rect = track.getBoundingClientRect();
2808
+ const v = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
2809
+ onVolumeChange(v);
2810
+ }, [onVolumeChange]);
2811
+ const onPointerDown = useCallback((e) => {
2812
+ e.currentTarget.setPointerCapture(e.pointerId);
2813
+ setDragging(true);
2814
+ seek(e.clientX);
2815
+ }, [seek]);
2816
+ const onPointerMove = useCallback((e) => {
2817
+ if (dragging) seek(e.clientX);
2818
+ }, [dragging, seek]);
2819
+ const onPointerUp = useCallback(() => setDragging(false), []);
2820
+ const fillPercent = volume * 100;
2821
+ return /* @__PURE__ */ jsxs(
2822
+ "div",
2823
+ {
2824
+ className: "flex items-center",
2825
+ onMouseEnter: () => setHovered(true),
2826
+ onMouseLeave: () => {
2827
+ if (!dragging) setHovered(false);
2828
+ },
2829
+ children: [
2830
+ /* @__PURE__ */ jsx(
2831
+ "button",
2832
+ {
2833
+ type: "button",
2834
+ onClick: onMuteToggle,
2835
+ className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
2836
+ "aria-label": isMuted ? "Unmute" : "Mute",
2837
+ children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2838
+ }
2839
+ ),
2840
+ /* @__PURE__ */ jsx(
2841
+ "div",
2842
+ {
2843
+ style: {
2844
+ width: expanded ? "64px" : "0px",
2845
+ opacity: expanded ? 1 : 0,
2846
+ transition: "width 0.2s ease, opacity 0.2s ease",
2847
+ overflow: "hidden"
2848
+ },
2849
+ children: /* @__PURE__ */ jsxs(
2850
+ "div",
2851
+ {
2852
+ ref: trackRef,
2853
+ onPointerDown,
2854
+ onPointerMove,
2855
+ onPointerUp,
2856
+ className: "relative mx-1 flex h-7 cursor-pointer items-center",
2857
+ style: { width: "52px" },
2858
+ children: [
2859
+ /* @__PURE__ */ jsx(
2860
+ "div",
2861
+ {
2862
+ className: "absolute inset-x-0 rounded-full bg-white/20",
2863
+ style: {
2864
+ height: dragging ? "5px" : hovered ? "4px" : "3px",
2865
+ transition: "height 0.15s ease"
2866
+ },
2867
+ children: /* @__PURE__ */ jsx(
2868
+ "div",
2869
+ {
2870
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
2871
+ style: { width: `${fillPercent}%` }
2872
+ }
2873
+ )
2874
+ }
2875
+ ),
2876
+ /* @__PURE__ */ jsx(
2877
+ "div",
2878
+ {
2879
+ className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md",
2880
+ style: {
2881
+ left: `${fillPercent}%`,
2882
+ width: dragging ? "14px" : hovered ? "11px" : "0px",
2883
+ height: dragging ? "14px" : hovered ? "11px" : "0px",
2884
+ transition: "width 0.15s ease, height 0.15s ease"
2885
+ }
2886
+ }
2887
+ )
2888
+ ]
2889
+ }
2890
+ )
2891
+ }
2892
+ )
2893
+ ]
2894
+ }
2895
+ );
2896
+ }
2755
2897
  function parseVideoChildren(children) {
2756
2898
  const parsed = {
2757
2899
  sources: []