@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.
@@ -1,6 +1,6 @@
1
1
  import React, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
2
2
  import gsap from 'gsap';
3
- import { Pause, Play, VolumeX, Volume2, Captions as Captions$1, Settings, Minimize, Maximize } from 'lucide-react';
3
+ import { Pause, Play, Captions as Captions$1, Settings, Minimize, Maximize, VolumeX, Volume2 } from 'lucide-react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  var AUTO_QUALITY = {
@@ -104,6 +104,8 @@ function Video({
104
104
  const [audioTracks, setAudioTracks] = useState([]);
105
105
  const [selectedAudio, setSelectedAudio] = useState(0);
106
106
  const [settingsOpen, setSettingsOpen] = useState(false);
107
+ const [settingsVisible, setSettingsVisible] = useState(false);
108
+ const settingsCloseTimerRef = useRef(null);
107
109
  const [settingsTab, setSettingsTab] = useState("root");
108
110
  const [playbackRate, setPlaybackRate] = useState(1);
109
111
  const [subtitleStyle, setSubtitleStyle] = useState({
@@ -114,6 +116,8 @@ function Video({
114
116
  });
115
117
  const [subtitleMode, setSubtitleMode] = useState(initialSubtitleMode);
116
118
  const [activeCue, setActiveCue] = useState(null);
119
+ const [storyboardSheetSize, setStoryboardSheetSize] = useState(null);
120
+ const storyboardSheetUrlRef = useRef("");
117
121
  const [storyboardCues, setStoryboardCues] = useState(
118
122
  []
119
123
  );
@@ -122,6 +126,7 @@ function Video({
122
126
  const [currentTime, setCurrentTime] = useState(0);
123
127
  const [bufferedTime, setBufferedTime] = useState(0);
124
128
  const [isDragging, setIsDragging] = useState(false);
129
+ const [isHoveringProgress, setIsHoveringProgress] = useState(false);
125
130
  const dragPointerIdRef = useRef(null);
126
131
  const [isPlaying, setIsPlaying] = useState(false);
127
132
  const [hasPlayed, setHasPlayed] = useState(false);
@@ -150,11 +155,20 @@ function Video({
150
155
  const applySubtitleMode = useCallback((mode) => {
151
156
  const video = videoRef.current;
152
157
  if (!video) return;
158
+ let activeTrack = null;
153
159
  Array.from(video.textTracks).forEach((track) => {
154
160
  if (track.kind === "metadata") return;
155
- track.mode = mode !== "off" && track.language === mode ? "hidden" : "disabled";
161
+ const enabled = mode !== "off" && track.language === mode;
162
+ track.mode = enabled ? "hidden" : "disabled";
163
+ if (enabled) activeTrack = track;
156
164
  });
157
- if (mode === "off") setActiveCue(null);
165
+ if (!activeTrack) {
166
+ setActiveCue(null);
167
+ return;
168
+ }
169
+ const cues = activeTrack.activeCues;
170
+ const cue = cues && cues.length > 0 ? cues[0] : null;
171
+ setActiveCue(cue ? cue.text.replace(/<[^>]*>/g, "") : null);
158
172
  }, []);
159
173
  const showControlsTemporarily = useCallback(() => {
160
174
  setControlsVisible(true);
@@ -188,6 +202,16 @@ function Video({
188
202
  }
189
203
  );
190
204
  }, []);
205
+ const openSettings = useCallback(() => {
206
+ setSettingsOpen(true);
207
+ setSettingsTab("root");
208
+ window.setTimeout(() => setSettingsVisible(true), 10);
209
+ }, []);
210
+ const closeSettings = useCallback(() => {
211
+ setSettingsVisible(false);
212
+ if (settingsCloseTimerRef.current) window.clearTimeout(settingsCloseTimerRef.current);
213
+ settingsCloseTimerRef.current = window.setTimeout(() => setSettingsOpen(false), 200);
214
+ }, []);
191
215
  useEffect(() => {
192
216
  if (sourceIndex >= parsed.sources.length) {
193
217
  setSourceIndex(initialSourceIndex);
@@ -413,7 +437,7 @@ function Video({
413
437
  setQualities([AUTO_QUALITY]);
414
438
  setAudioTracks([]);
415
439
  setSelectedAudio(0);
416
- setSettingsOpen(false);
440
+ closeSettings();
417
441
  video.pause();
418
442
  video.removeAttribute("src");
419
443
  video.load();
@@ -640,17 +664,17 @@ function Video({
640
664
  }, []);
641
665
  const changeAudio = useCallback((trackId) => {
642
666
  setSelectedAudio(trackId);
643
- setSettingsOpen(false);
667
+ closeSettings();
644
668
  if (hlsRef.current) {
645
669
  hlsRef.current.audioTrack = trackId;
646
670
  }
647
- }, []);
671
+ }, [closeSettings]);
648
672
  const changeQuality = useCallback(
649
673
  (qualityId) => {
650
674
  const option = qualities.find((quality) => quality.id === qualityId);
651
675
  if (!option) return;
652
676
  setSelectedQuality(qualityId);
653
- setSettingsOpen(false);
677
+ closeSettings();
654
678
  if (option.type === "auto") {
655
679
  if (hlsRef.current) {
656
680
  hlsRef.current.currentLevel = -1;
@@ -685,7 +709,7 @@ function Video({
685
709
  dashRef.current.setQualityFor("video", option.index);
686
710
  }
687
711
  },
688
- [qualities]
712
+ [qualities, closeSettings]
689
713
  );
690
714
  const seekFromPointer = useCallback(
691
715
  (clientX) => {
@@ -730,7 +754,11 @@ function Video({
730
754
  },
731
755
  [isDragging, seekFromPointer, updatePreview]
732
756
  );
757
+ const handleProgressPointerEnter = useCallback(() => {
758
+ setIsHoveringProgress(true);
759
+ }, []);
733
760
  const handleProgressPointerLeave = useCallback(() => {
761
+ setIsHoveringProgress(false);
734
762
  if (!isDragging) setPreview(null);
735
763
  }, [isDragging]);
736
764
  const handleProgressPointerDown = useCallback(
@@ -801,10 +829,18 @@ function Video({
801
829
  onKeyDown: handleKeyDown,
802
830
  onMouseMove: showControlsTemporarily,
803
831
  onMouseLeave: () => {
832
+ closeSettings();
804
833
  if (isPlaying && autoHideControls) {
805
834
  setControlsVisible(false);
806
835
  }
807
836
  },
837
+ onBlur: (e) => {
838
+ if (!e.currentTarget.contains(e.relatedTarget)) {
839
+ closeSettings();
840
+ }
841
+ },
842
+ onTouchStart: showControlsTemporarily,
843
+ onTouchMove: showControlsTemporarily,
808
844
  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",
809
845
  style: fixedHeight ? {
810
846
  height: typeof fixedHeight === "number" ? `${fixedHeight}px` : fixedHeight
@@ -817,7 +853,7 @@ function Video({
817
853
  "video",
818
854
  {
819
855
  ref: videoRef,
820
- className: "h-full w-full object-contain",
856
+ className: `h-full w-full ${isFullscreen ? "object-contain" : "object-cover"}`,
821
857
  playsInline: true,
822
858
  preload: "metadata",
823
859
  crossOrigin: "anonymous",
@@ -908,7 +944,7 @@ function Video({
908
944
  "div",
909
945
  {
910
946
  className: "fixed inset-0 z-70",
911
- onClick: () => setSettingsOpen(false)
947
+ onClick: closeSettings
912
948
  }
913
949
  ),
914
950
  /* @__PURE__ */ jsxs(
@@ -920,7 +956,9 @@ function Video({
920
956
  224,
921
957
  Math.max(180, (playerWidth || 640) * 0.22)
922
958
  ) + "px",
923
- animation: "spFadeIn 0.15s ease"
959
+ opacity: settingsVisible ? 1 : 0,
960
+ transform: settingsVisible ? "translateY(0) scale(1)" : "translateY(8px) scale(0.97)",
961
+ transition: "opacity 0.18s ease, transform 0.18s ease"
924
962
  },
925
963
  children: [
926
964
  settingsTab === "root" && /* @__PURE__ */ jsx("div", { children: [
@@ -1354,8 +1392,7 @@ function Video({
1354
1392
  type: "button",
1355
1393
  onClick: () => {
1356
1394
  setPlaybackRate(speed);
1357
- setSettingsOpen(false);
1358
- setSettingsTab("root");
1395
+ closeSettings();
1359
1396
  },
1360
1397
  className: "flex w-full items-center gap-3 px-4 py-2.5 text-sm transition hover:bg-white/8",
1361
1398
  children: [
@@ -1391,37 +1428,40 @@ function Video({
1391
1428
  ] })
1392
1429
  ]
1393
1430
  }
1394
- ),
1395
- /* @__PURE__ */ jsx("style", { children: `@keyframes spFadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}` })
1431
+ )
1396
1432
  ] }),
1397
1433
  /* @__PURE__ */ jsxs(
1398
1434
  "div",
1399
1435
  {
1400
1436
  ref: progressRef,
1401
1437
  onPointerMove: handleProgressPointerMove,
1438
+ onPointerEnter: handleProgressPointerEnter,
1402
1439
  onPointerLeave: handleProgressPointerLeave,
1403
1440
  onPointerDown: handleProgressPointerDown,
1404
1441
  onPointerUp: handleProgressPointerUp,
1405
- className: "group relative mb-3 h-7 cursor-pointer",
1442
+ className: "relative mb-2 h-8 cursor-pointer overflow-visible",
1406
1443
  children: [
1407
1444
  /* @__PURE__ */ jsxs(
1408
1445
  "div",
1409
1446
  {
1410
- className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/22 transition-[height] duration-150",
1411
- style: { height: isDragging ? "6px" : "3px" },
1447
+ className: "absolute left-0 right-0 top-1/2 -translate-y-1/2 overflow-hidden rounded-full bg-white/18",
1448
+ style: {
1449
+ height: isDragging ? "7px" : isHoveringProgress ? "5px" : "3px",
1450
+ transition: "height 0.15s ease"
1451
+ },
1412
1452
  children: [
1413
1453
  /* @__PURE__ */ jsx(
1414
1454
  "div",
1415
1455
  {
1416
- className: "absolute inset-y-0 left-0 rounded-full bg-white/30",
1456
+ className: "absolute inset-y-0 left-0 rounded-full bg-white/28",
1417
1457
  style: { width: `${bufferedPercent}%` }
1418
1458
  }
1419
1459
  ),
1420
1460
  /* @__PURE__ */ jsx(
1421
1461
  "div",
1422
1462
  {
1423
- className: "absolute inset-y-0 left-0 rounded-full bg-white/90",
1424
- style: { width: `${progressPercent}%` }
1463
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
1464
+ style: { width: `${progressPercent}%`, transition: "width 0.05s linear" }
1425
1465
  }
1426
1466
  )
1427
1467
  ]
@@ -1430,14 +1470,90 @@ function Video({
1430
1470
  /* @__PURE__ */ jsx(
1431
1471
  "div",
1432
1472
  {
1433
- 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",
1473
+ className: "pointer-events-none absolute rounded-full bg-white shadow-[0_1px_6px_rgba(0,0,0,0.5)]",
1434
1474
  style: {
1475
+ top: "50%",
1435
1476
  left: `${progressPercent}%`,
1436
- width: isDragging ? "16px" : "10px",
1437
- height: isDragging ? "16px" : "10px"
1477
+ transform: "translate(-50%, -50%)",
1478
+ width: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
1479
+ height: isDragging ? "18px" : isHoveringProgress ? "14px" : "10px",
1480
+ 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)"
1438
1481
  }
1439
1482
  }
1440
- )
1483
+ ),
1484
+ preview && (() => {
1485
+ const frameW = preview.cue.w ?? 160;
1486
+ const frameH = preview.cue.h ?? 90;
1487
+ const thumbW = 200;
1488
+ const thumbH = Math.round(thumbW * (frameH / frameW));
1489
+ const scale = thumbW / frameW;
1490
+ const isSprite = preview.cue.x != null && preview.cue.y != null;
1491
+ return /* @__PURE__ */ jsxs(
1492
+ "div",
1493
+ {
1494
+ className: "pointer-events-none absolute flex flex-col items-center gap-1",
1495
+ style: {
1496
+ bottom: "calc(100% + 6px)",
1497
+ left: preview.left,
1498
+ transform: "translateX(-50%)",
1499
+ zIndex: 80
1500
+ },
1501
+ children: [
1502
+ /* @__PURE__ */ jsx(
1503
+ "div",
1504
+ {
1505
+ className: "overflow-hidden rounded-lg shadow-2xl ring-1 ring-white/20",
1506
+ style: { width: thumbW, height: thumbH, flexShrink: 0 },
1507
+ children: isSprite ? (
1508
+ // Sprite: need full sheet dimensions to compute backgroundSize correctly.
1509
+ // Load them once from the image's natural size.
1510
+ (() => {
1511
+ const imgUrl = preview.cue.image;
1512
+ if (storyboardSheetUrlRef.current !== imgUrl) {
1513
+ storyboardSheetUrlRef.current = imgUrl;
1514
+ const img = new window.Image();
1515
+ img.onload = () => setStoryboardSheetSize({ w: img.naturalWidth, h: img.naturalHeight });
1516
+ img.src = imgUrl;
1517
+ }
1518
+ if (!storyboardSheetSize) return null;
1519
+ const bsW = storyboardSheetSize.w * scale;
1520
+ const bsH = storyboardSheetSize.h * scale;
1521
+ return /* @__PURE__ */ jsx(
1522
+ "div",
1523
+ {
1524
+ style: {
1525
+ width: thumbW,
1526
+ height: thumbH,
1527
+ backgroundImage: `url(${imgUrl})`,
1528
+ backgroundRepeat: "no-repeat",
1529
+ backgroundPosition: `-${(preview.cue.x ?? 0) * scale}px -${(preview.cue.y ?? 0) * scale}px`,
1530
+ backgroundSize: `${bsW}px ${bsH}px`
1531
+ }
1532
+ }
1533
+ );
1534
+ })()
1535
+ ) : /* @__PURE__ */ jsx(
1536
+ "img",
1537
+ {
1538
+ src: preview.cue.image,
1539
+ alt: "",
1540
+ style: { width: thumbW, height: thumbH, objectFit: "cover", objectPosition: "center", display: "block" }
1541
+ }
1542
+ )
1543
+ }
1544
+ ),
1545
+ /* @__PURE__ */ jsx(
1546
+ "span",
1547
+ {
1548
+ className: "rounded-md px-2 py-0.5 text-[11px] font-semibold tabular-nums text-white/90",
1549
+ style: { background: "rgba(0,0,0,0.55)", backdropFilter: "blur(6px)" },
1550
+ children: formatTime(preview.time)
1551
+ }
1552
+ )
1553
+ ]
1554
+ }
1555
+ );
1556
+ })()
1441
1557
  ]
1442
1558
  }
1443
1559
  ),
@@ -1460,44 +1576,29 @@ function Video({
1460
1576
  ] })
1461
1577
  ] }),
1462
1578
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 @sm:gap-1", children: [
1463
- /* @__PURE__ */ jsxs("div", { className: "group flex items-center", children: [
1464
- /* @__PURE__ */ jsx(
1465
- "button",
1466
- {
1467
- type: "button",
1468
- onClick: () => setIsMuted((value) => !value),
1469
- className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
1470
- "aria-label": isMuted ? "Unmute" : "Mute",
1471
- children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
1472
- }
1473
- ),
1474
- /* @__PURE__ */ jsx("div", { className: "w-0 overflow-hidden transition-all duration-200 group-hover:w-16 @md:group-hover:w-20", children: /* @__PURE__ */ jsx(
1475
- "input",
1476
- {
1477
- type: "range",
1478
- min: "0",
1479
- max: "1",
1480
- step: "0.01",
1481
- value: isMuted ? 0 : volume,
1482
- onChange: (event) => {
1483
- const nextVolume = Number(event.target.value);
1484
- setVolume(nextVolume);
1485
- setIsMuted(nextVolume === 0);
1486
- },
1487
- className: "h-1 w-14 accent-white @md:w-20",
1488
- "aria-label": "Audio level"
1489
- }
1490
- ) })
1491
- ] }),
1579
+ /* @__PURE__ */ jsx(
1580
+ VolumeSlider,
1581
+ {
1582
+ volume: isMuted ? 0 : volume,
1583
+ onMuteToggle: () => setIsMuted((v) => !v),
1584
+ onVolumeChange: (v) => {
1585
+ setVolume(v);
1586
+ setIsMuted(v === 0);
1587
+ },
1588
+ isMuted
1589
+ }
1590
+ ),
1492
1591
  /* @__PURE__ */ jsx("div", { className: "mx-0.5 h-4 w-px bg-white/20 @md:mx-1" }),
1493
1592
  captions.length > 0 && /* @__PURE__ */ jsx(
1494
1593
  "button",
1495
1594
  {
1496
1595
  type: "button",
1497
- onClick: () => setSubtitleMode(
1498
- (m) => m === "off" ? captions[0]?.srclang ?? "off" : "off"
1499
- ),
1500
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
1596
+ onClick: () => {
1597
+ const next = subtitleMode === "off" ? captions[0]?.srclang ?? "off" : "off";
1598
+ setSubtitleMode(next);
1599
+ setSubtitleStyle((st) => ({ ...st, track: next }));
1600
+ },
1601
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${subtitleMode !== "off" ? "text-white" : "text-white/60"}`,
1501
1602
  "aria-label": "Captions",
1502
1603
  children: /* @__PURE__ */ jsx(Captions$1, { className: "size-4 @sm:size-5" })
1503
1604
  }
@@ -1506,11 +1607,8 @@ function Video({
1506
1607
  "button",
1507
1608
  {
1508
1609
  type: "button",
1509
- onClick: () => {
1510
- setSettingsOpen((v) => !v);
1511
- setSettingsTab("root");
1512
- },
1513
- className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10${settingsOpen ? "text-white" : "text-white/60"}`,
1610
+ onClick: () => settingsOpen ? closeSettings() : openSettings(),
1611
+ className: `grid size-8 place-items-center rounded transition hover:text-white/80 @sm:size-10 ${settingsOpen ? "text-white" : "text-white/60"}`,
1514
1612
  "aria-label": "Settings",
1515
1613
  children: /* @__PURE__ */ jsx(Settings, { className: "size-4 @sm:size-5" })
1516
1614
  }
@@ -1533,65 +1631,6 @@ function Video({
1533
1631
  ]
1534
1632
  }
1535
1633
  ),
1536
- preview && (() => {
1537
- const srcW = preview.cue.w ?? 160;
1538
- const srcH = preview.cue.h ?? 90;
1539
- const thumbW = Math.max(
1540
- 140,
1541
- Math.round((playerWidth || 640) * 0.13)
1542
- );
1543
- const thumbH = Math.round(thumbW * (srcH / srcW));
1544
- const scale = thumbW / srcW;
1545
- const isSprite = preview.cue.x != null && preview.cue.y != null;
1546
- return /* @__PURE__ */ jsx(
1547
- "div",
1548
- {
1549
- 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",
1550
- style: {
1551
- bottom: controlsVisible ? "80px" : "20px",
1552
- left: preview.left,
1553
- transition: "bottom 0.2s"
1554
- },
1555
- children: isSprite ? /* @__PURE__ */ jsx(
1556
- "div",
1557
- {
1558
- style: {
1559
- width: thumbW,
1560
- height: thumbH,
1561
- overflow: "hidden"
1562
- },
1563
- children: /* @__PURE__ */ jsx(
1564
- "div",
1565
- {
1566
- style: {
1567
- width: srcW,
1568
- height: srcH,
1569
- backgroundImage: `url(${preview.cue.image})`,
1570
- backgroundPosition: `-${preview.cue.x ?? 0}px -${preview.cue.y ?? 0}px`,
1571
- backgroundSize: "auto",
1572
- backgroundRepeat: "no-repeat",
1573
- transform: `scale(${scale})`,
1574
- transformOrigin: "top left"
1575
- }
1576
- }
1577
- )
1578
- }
1579
- ) : /* @__PURE__ */ jsx(
1580
- "div",
1581
- {
1582
- style: {
1583
- width: thumbW,
1584
- height: thumbH,
1585
- backgroundImage: `url(${preview.cue.image})`,
1586
- backgroundSize: "cover",
1587
- backgroundPosition: "center",
1588
- backgroundRepeat: "no-repeat"
1589
- }
1590
- }
1591
- )
1592
- }
1593
- );
1594
- })(),
1595
1634
  activeCue && /* @__PURE__ */ jsx(
1596
1635
  "div",
1597
1636
  {
@@ -1625,6 +1664,109 @@ function Video({
1625
1664
  );
1626
1665
  }
1627
1666
  var VideoPlayer = Video;
1667
+ function VolumeSlider({
1668
+ volume,
1669
+ isMuted,
1670
+ onMuteToggle,
1671
+ onVolumeChange
1672
+ }) {
1673
+ const [hovered, setHovered] = useState(false);
1674
+ const [dragging, setDragging] = useState(false);
1675
+ const trackRef = useRef(null);
1676
+ const expanded = hovered || dragging;
1677
+ const seek = useCallback((clientX) => {
1678
+ const track = trackRef.current;
1679
+ if (!track) return;
1680
+ const rect = track.getBoundingClientRect();
1681
+ const v = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
1682
+ onVolumeChange(v);
1683
+ }, [onVolumeChange]);
1684
+ const onPointerDown = useCallback((e) => {
1685
+ e.currentTarget.setPointerCapture(e.pointerId);
1686
+ setDragging(true);
1687
+ seek(e.clientX);
1688
+ }, [seek]);
1689
+ const onPointerMove = useCallback((e) => {
1690
+ if (dragging) seek(e.clientX);
1691
+ }, [dragging, seek]);
1692
+ const onPointerUp = useCallback(() => setDragging(false), []);
1693
+ const fillPercent = volume * 100;
1694
+ return /* @__PURE__ */ jsxs(
1695
+ "div",
1696
+ {
1697
+ className: "flex items-center",
1698
+ onMouseEnter: () => setHovered(true),
1699
+ onMouseLeave: () => {
1700
+ if (!dragging) setHovered(false);
1701
+ },
1702
+ children: [
1703
+ /* @__PURE__ */ jsx(
1704
+ "button",
1705
+ {
1706
+ type: "button",
1707
+ onClick: onMuteToggle,
1708
+ className: "grid size-8 place-items-center text-white/70 transition hover:text-white @sm:size-9",
1709
+ "aria-label": isMuted ? "Unmute" : "Mute",
1710
+ children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "size-4 @sm:size-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "size-4 @sm:size-5" })
1711
+ }
1712
+ ),
1713
+ /* @__PURE__ */ jsx(
1714
+ "div",
1715
+ {
1716
+ style: {
1717
+ width: expanded ? "64px" : "0px",
1718
+ opacity: expanded ? 1 : 0,
1719
+ transition: "width 0.2s ease, opacity 0.2s ease",
1720
+ overflow: "hidden"
1721
+ },
1722
+ children: /* @__PURE__ */ jsxs(
1723
+ "div",
1724
+ {
1725
+ ref: trackRef,
1726
+ onPointerDown,
1727
+ onPointerMove,
1728
+ onPointerUp,
1729
+ className: "relative mx-1 flex h-7 cursor-pointer items-center",
1730
+ style: { width: "52px" },
1731
+ children: [
1732
+ /* @__PURE__ */ jsx(
1733
+ "div",
1734
+ {
1735
+ className: "absolute inset-x-0 rounded-full bg-white/20",
1736
+ style: {
1737
+ height: dragging ? "5px" : hovered ? "4px" : "3px",
1738
+ transition: "height 0.15s ease"
1739
+ },
1740
+ children: /* @__PURE__ */ jsx(
1741
+ "div",
1742
+ {
1743
+ className: "absolute inset-y-0 left-0 rounded-full bg-white",
1744
+ style: { width: `${fillPercent}%` }
1745
+ }
1746
+ )
1747
+ }
1748
+ ),
1749
+ /* @__PURE__ */ jsx(
1750
+ "div",
1751
+ {
1752
+ className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-white shadow-md",
1753
+ style: {
1754
+ left: `${fillPercent}%`,
1755
+ width: dragging ? "14px" : hovered ? "11px" : "0px",
1756
+ height: dragging ? "14px" : hovered ? "11px" : "0px",
1757
+ transition: "width 0.15s ease, height 0.15s ease"
1758
+ }
1759
+ }
1760
+ )
1761
+ ]
1762
+ }
1763
+ )
1764
+ }
1765
+ )
1766
+ ]
1767
+ }
1768
+ );
1769
+ }
1628
1770
  function parseVideoChildren(children) {
1629
1771
  const parsed = {
1630
1772
  sources: []