@geekapps/silo-elements-nextjs 0.2.52 → 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);
@@ -1324,6 +1329,16 @@ function Video({
1324
1329
  }
1325
1330
  );
1326
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
+ }, []);
1327
1342
  useEffect(() => {
1328
1343
  if (sourceIndex >= parsed.sources.length) {
1329
1344
  setSourceIndex(initialSourceIndex);
@@ -1549,7 +1564,7 @@ function Video({
1549
1564
  setQualities([AUTO_QUALITY]);
1550
1565
  setAudioTracks([]);
1551
1566
  setSelectedAudio(0);
1552
- setSettingsOpen(false);
1567
+ closeSettings();
1553
1568
  video.pause();
1554
1569
  video.removeAttribute("src");
1555
1570
  video.load();
@@ -1776,17 +1791,17 @@ function Video({
1776
1791
  }, []);
1777
1792
  const changeAudio = useCallback((trackId) => {
1778
1793
  setSelectedAudio(trackId);
1779
- setSettingsOpen(false);
1794
+ closeSettings();
1780
1795
  if (hlsRef.current) {
1781
1796
  hlsRef.current.audioTrack = trackId;
1782
1797
  }
1783
- }, []);
1798
+ }, [closeSettings]);
1784
1799
  const changeQuality = useCallback(
1785
1800
  (qualityId) => {
1786
1801
  const option = qualities.find((quality) => quality.id === qualityId);
1787
1802
  if (!option) return;
1788
1803
  setSelectedQuality(qualityId);
1789
- setSettingsOpen(false);
1804
+ closeSettings();
1790
1805
  if (option.type === "auto") {
1791
1806
  if (hlsRef.current) {
1792
1807
  hlsRef.current.currentLevel = -1;
@@ -1821,7 +1836,7 @@ function Video({
1821
1836
  dashRef.current.setQualityFor("video", option.index);
1822
1837
  }
1823
1838
  },
1824
- [qualities]
1839
+ [qualities, closeSettings]
1825
1840
  );
1826
1841
  const seekFromPointer = useCallback(
1827
1842
  (clientX) => {
@@ -1866,7 +1881,11 @@ function Video({
1866
1881
  },
1867
1882
  [isDragging, seekFromPointer, updatePreview]
1868
1883
  );
1884
+ const handleProgressPointerEnter = useCallback(() => {
1885
+ setIsHoveringProgress(true);
1886
+ }, []);
1869
1887
  const handleProgressPointerLeave = useCallback(() => {
1888
+ setIsHoveringProgress(false);
1870
1889
  if (!isDragging) setPreview(null);
1871
1890
  }, [isDragging]);
1872
1891
  const handleProgressPointerDown = useCallback(
@@ -1937,10 +1956,18 @@ function Video({
1937
1956
  onKeyDown: handleKeyDown,
1938
1957
  onMouseMove: showControlsTemporarily,
1939
1958
  onMouseLeave: () => {
1959
+ closeSettings();
1940
1960
  if (isPlaying && autoHideControls) {
1941
1961
  setControlsVisible(false);
1942
1962
  }
1943
1963
  },
1964
+ onBlur: (e) => {
1965
+ if (!e.currentTarget.contains(e.relatedTarget)) {
1966
+ closeSettings();
1967
+ }
1968
+ },
1969
+ onTouchStart: showControlsTemporarily,
1970
+ onTouchMove: showControlsTemporarily,
1944
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",
1945
1972
  style: fixedHeight ? {
1946
1973
  height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
@@ -1953,7 +1980,7 @@ function Video({
1953
1980
  "video",
1954
1981
  {
1955
1982
  ref: videoRef,
1956
- className: "h-full w-full object-contain",
1983
+ className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
1957
1984
  playsInline: true,
1958
1985
  preload: "metadata",
1959
1986
  crossOrigin: "anonymous",
@@ -2044,7 +2071,7 @@ function Video({
2044
2071
  "div",
2045
2072
  {
2046
2073
  className: "fixed inset-0 z-70",
2047
- onClick: () => setSettingsOpen(false)
2074
+ onClick: closeSettings
2048
2075
  }
2049
2076
  ),
2050
2077
  /* @__PURE__ */ jsxs(
@@ -2056,7 +2083,9 @@ function Video({
2056
2083
  224,
2057
2084
  Math.max(180, (playerWidth || 640) * 0.22)
2058
2085
  ) + "px",
2059
- 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"
2060
2089
  },
2061
2090
  children: [
2062
2091
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
@@ -2490,8 +2519,7 @@ function Video({
2490
2519
  type: "button",
2491
2520
  onClick: () => {
2492
2521
  setPlaybackRate(speed);
2493
- setSettingsOpen(false);
2494
- setSettingsTab("root");
2522
+ closeSettings();
2495
2523
  },
2496
2524
  className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
2497
2525
  children: [
@@ -2527,37 +2555,40 @@ function Video({
2527
2555
  ] })
2528
2556
  ]
2529
2557
  }
2530
- ),
2531
- /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
2558
+ )
2532
2559
  ] }),
2533
2560
  /* @__PURE__ */ jsxs(
2534
2561
  "div",
2535
2562
  {
2536
2563
  ref: progressRef,
2537
2564
  onPointerMove: handleProgressPointerMove,
2565
+ onPointerEnter: handleProgressPointerEnter,
2538
2566
  onPointerLeave: handleProgressPointerLeave,
2539
2567
  onPointerDown: handleProgressPointerDown,
2540
2568
  onPointerUp: handleProgressPointerUp,
2541
- className: "group relative mb-3 h-7 cursor-pointer",
2569
+ className: "relative mb-2 h-8 cursor-pointer overflow-visible",
2542
2570
  children: [
2543
2571
  /* @__PURE__ */ jsxs(
2544
2572
  "div",
2545
2573
  {
2546
- className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 transition-[height] duration-150",
2547
- 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
+ },
2548
2579
  children: [
2549
2580
  /* @__PURE__ */ jsx(
2550
2581
  "div",
2551
2582
  {
2552
- 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",
2553
2584
  style: { width: `${bufferedPercent}%` }
2554
2585
  }
2555
2586
  ),
2556
2587
  /* @__PURE__ */ jsx(
2557
2588
  "div",
2558
2589
  {
2559
- className: "absolute inset-y-0 left-0 rounded-full bg-white/90",
2560
- style: { width: `${progressPercent}%` }
2590
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
2591
+ style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
2561
2592
  }
2562
2593
  )
2563
2594
  ]
@@ -2566,14 +2597,90 @@ function Video({
2566
2597
  /* @__PURE__ */ jsx(
2567
2598
  "div",
2568
2599
  {
2569
- 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)]",
2570
2601
  style: {
2602
+ top: "50%",
2571
2603
  left: `${progressPercent}%`,
2572
- width: isDragging ? "16px" : "10px",
2573
- 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)"
2574
2608
  }
2575
2609
  }
2576
- )
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
+ })()
2577
2684
  ]
2578
2685
  }
2579
2686
  ),
@@ -2596,44 +2703,29 @@ function Video({
2596
2703
  ] })
2597
2704
  ] }),
2598
2705
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
2599
- /* @__PURE__ */ jsxs("div", { className: "group flex items-center", children: [
2600
- /* @__PURE__ */ jsx(
2601
- "button",
2602
- {
2603
- type: "button",
2604
- onClick: () => setIsMuted((value) => !value),
2605
- className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
2606
- "aria-label": isMuted ? "Unmute" : "Mute",
2607
- children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
2608
- }
2609
- ),
2610
- /* @__PURE__ */ jsx("div", { className: "w-0 overflow-hidden transition-all duration-200 group-hover:w-16 @md:group-hover:w-20", children: /* @__PURE__ */ jsx(
2611
- "input",
2612
- {
2613
- type: "range",
2614
- min: "0",
2615
- max: "1",
2616
- step: "0.01",
2617
- value: isMuted ? 0 : volume,
2618
- onChange: (event) => {
2619
- const nextVolume = Number(event.target.value);
2620
- setVolume(nextVolume);
2621
- setIsMuted(nextVolume === 0);
2622
- },
2623
- className: "h-1 w-14 accent-white @md:w-20",
2624
- "aria-label": "Audio level"
2625
- }
2626
- ) })
2627
- ] }),
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
+ ),
2628
2718
  /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
2629
2719
  captions.length > 0 && /* @__PURE__ */ jsx(
2630
2720
  "button",
2631
2721
  {
2632
2722
  type: "button",
2633
- onClick: () => setSubtitleMode(
2634
- (m) => m === "off" ? captions[0]?.srclang ?? "off" : "off"
2635
- ),
2636
- 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"}`,
2637
2729
  "aria-label": "Captions",
2638
2730
  children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
2639
2731
  }
@@ -2642,11 +2734,8 @@ function Video({
2642
2734
  "button",
2643
2735
  {
2644
2736
  type: "button",
2645
- onClick: () => {
2646
- setSettingsOpen((v) => !v);
2647
- setSettingsTab("root");
2648
- },
2649
- 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"}`,
2650
2739
  "aria-label": "Settings",
2651
2740
  children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
2652
2741
  }
@@ -2669,65 +2758,6 @@ function Video({
2669
2758
  ]
2670
2759
  }
2671
2760
  ),
2672
- preview && (() => {
2673
- const srcW = preview.cue.w ?? 160;
2674
- const srcH = preview.cue.h ?? 90;
2675
- const thumbW = Math.max(
2676
- 140,
2677
- Math.round((playerWidth || 640) * 0.13)
2678
- );
2679
- const thumbH = Math.round(thumbW * (srcH / srcW));
2680
- const scale = thumbW / srcW;
2681
- const isSprite = preview.cue.x != null && preview.cue.y != null;
2682
- return /* @__PURE__ */ jsx(
2683
- "div",
2684
- {
2685
- 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",
2686
- style: {
2687
- bottom: controlsVisible ? "80px" : "20px",
2688
- left: preview.left,
2689
- transition: "bottom 0.2s"
2690
- },
2691
- children: isSprite ? /* @__PURE__ */ jsx(
2692
- "div",
2693
- {
2694
- style: {
2695
- width: thumbW,
2696
- height: thumbH,
2697
- overflow: "hidden"
2698
- },
2699
- children: /* @__PURE__ */ jsx(
2700
- "div",
2701
- {
2702
- style: {
2703
- width: srcW,
2704
- height: srcH,
2705
- backgroundImage: `url(${preview.cue.image})`,
2706
- backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
2707
- backgroundSize: "auto",
2708
- backgroundRepeat: "no-repeat",
2709
- transform: `scale(${scale})`,
2710
- transformOrigin: "top left"
2711
- }
2712
- }
2713
- )
2714
- }
2715
- ) : /* @__PURE__ */ jsx(
2716
- "div",
2717
- {
2718
- style: {
2719
- width: thumbW,
2720
- height: thumbH,
2721
- backgroundImage: `url(${preview.cue.image})`,
2722
- backgroundSize: "cover",
2723
- backgroundPosition: "center",
2724
- backgroundRepeat: "no-repeat"
2725
- }
2726
- }
2727
- )
2728
- }
2729
- );
2730
- })(),
2731
2761
  activeCue && /* @__PURE__ */ jsx(
2732
2762
  "div",
2733
2763
  {
@@ -2761,6 +2791,109 @@ function Video({
2761
2791
  );
2762
2792
  }
2763
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
+ }
2764
2897
  function parseVideoChildren(children) {
2765
2898
  const parsed = {
2766
2899
  sources: []