@xhub-short/ui 0.1.0-beta.1 → 0.1.0-beta.10

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.
Files changed (45) hide show
  1. package/dist/CommentSheet.css-BeCrEaUG.d.ts +221 -0
  2. package/dist/{chunk-2PTMP65P.js → chunk-2FSDVYER.js} +8 -9
  3. package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
  4. package/dist/{chunk-ANGBSV7L.js → chunk-AC2IFAJR.js} +10 -5
  5. package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
  6. package/dist/chunk-AQHD6LPS.js +430 -0
  7. package/dist/{chunk-HW4LXTFT.js → chunk-CL6BS7GB.js} +7 -5
  8. package/dist/{chunk-YW23IBKF.js → chunk-ECR42RKK.js} +46 -5
  9. package/dist/chunk-EDWS2IPH.js +1 -0
  10. package/dist/chunk-FNXTPQ6L.js +2573 -0
  11. package/dist/{chunk-DHQJBXQW.js → chunk-KWHMZ6H5.js} +1 -1
  12. package/dist/{chunk-UXMA4KJZ.js → chunk-RMLTPW5S.js} +3 -2
  13. package/dist/{chunk-SSJDO24Q.js → chunk-SZXFH334.js} +1 -1
  14. package/dist/{chunk-4MN72OZH.js → chunk-UNV3NWN6.js} +4 -4
  15. package/dist/{chunk-ZZDQKP4R.js → chunk-WCRDTBCZ.js} +94 -155
  16. package/dist/{chunk-XAOEHLOX.js → chunk-XDIH66C4.js} +245 -52
  17. package/dist/components/ActionBar/index.js +1 -1
  18. package/dist/components/AuthorInfo/index.d.ts +5 -1
  19. package/dist/components/AuthorInfo/index.js +1 -1
  20. package/dist/components/BlurhashPlaceholder/index.d.ts +67 -0
  21. package/dist/components/BlurhashPlaceholder/index.js +150 -0
  22. package/dist/components/CommentSheet/index.d.ts +164 -0
  23. package/dist/components/CommentSheet/index.js +1 -0
  24. package/dist/components/ErrorBoundary/index.js +1 -1
  25. package/dist/components/OfflineIndicator/index.d.ts +56 -0
  26. package/dist/components/OfflineIndicator/index.js +151 -0
  27. package/dist/components/ProgressBar/index.d.ts +30 -2
  28. package/dist/components/ProgressBar/index.js +1 -1
  29. package/dist/components/Skeleton/index.js +1 -1
  30. package/dist/components/SubtitleDisplay/index.d.ts +94 -0
  31. package/dist/components/SubtitleDisplay/index.js +165 -0
  32. package/dist/components/VideoFeed/index.d.ts +11 -0
  33. package/dist/components/VideoFeed/index.js +1 -1
  34. package/dist/components/VideoInfo/index.js +1 -1
  35. package/dist/components/VideoPlayer/index.d.ts +14 -41
  36. package/dist/components/VideoPlayer/index.js +1 -1
  37. package/dist/components/VideoSlot/index.d.ts +124 -64
  38. package/dist/components/VideoSlot/index.js +1 -1
  39. package/dist/components/VirtualSlider/index.d.ts +339 -0
  40. package/dist/components/VirtualSlider/index.js +1 -0
  41. package/dist/components/icons/index.js +1 -1
  42. package/dist/index.d.ts +76 -93
  43. package/dist/index.js +75 -27
  44. package/package.json +53 -8
  45. package/dist/use-gesture-react.esm-3SV4QLEJ.js +0 -1893
@@ -1,3 +1,4 @@
1
+ import * as react from 'react';
1
2
  import { ProgressBarHeadlessProps } from '@xhub-short/contracts';
2
3
 
3
4
  interface ProgressBarHeadlessExtendedProps extends ProgressBarHeadlessProps {
@@ -16,6 +17,23 @@ interface ProgressBarHeadlessExtendedProps extends ProgressBarHeadlessProps {
16
17
  * @default false
17
18
  */
18
19
  minimal?: boolean;
20
+ /**
21
+ * Auto-hide progress bar when video is playing
22
+ *
23
+ * When enabled:
24
+ * - Hidden when video is playing
25
+ * - Visible when video is paused
26
+ * - Visible when user hovers (if seekable)
27
+ *
28
+ * @default true
29
+ */
30
+ autoHide?: boolean;
31
+ /**
32
+ * Whether progress bar should be visible (controlled by parent)
33
+ * Used by wired component to control visibility based on player state.
34
+ * Takes precedence over autoHide behavior.
35
+ */
36
+ visible?: boolean;
19
37
  /**
20
38
  * Ref to the fill element for direct DOM manipulation (ADR 005)
21
39
  * Used by wired component for 60fps smooth updates
@@ -64,8 +82,18 @@ declare function calculateProgress(currentTime: number, duration: number): numbe
64
82
  * - Headless version updates via React state (acceptable for demos)
65
83
  * - Wired version (P11) will use Direct DOM Update for 60fps smooth
66
84
  * - Fill element uses will-change: transform for GPU compositing
85
+ *
86
+ * Wrapped with React.memo to prevent unnecessary re-renders from parent.
87
+ * Re-render is expected during seek (local state changes).
88
+ */
89
+ declare function ProgressBarHeadlessBase({ currentTime, duration, buffered, seekable, className, onSeek, onSeekStart, onSeekEnd, showTime, showTooltip, minimal, autoHide, visible, fillRef: externalFillRef, bufferedRef: externalBufferedRef, handleRef: externalHandleRef, currentTimeRef: externalCurrentTimeRef, durationRef: externalDurationRef, }: ProgressBarHeadlessExtendedProps): React.ReactElement;
90
+ /**
91
+ * ProgressBarHeadless - Memoized for performance
92
+ *
93
+ * Custom compare function excludes frequently-changing time values since
94
+ * the wired component uses Direct DOM Update for those.
67
95
  */
68
- declare function ProgressBarHeadless({ currentTime, duration, buffered, seekable, className, onSeek, onSeekStart, onSeekEnd, showTime, showTooltip, minimal, fillRef: externalFillRef, bufferedRef: externalBufferedRef, handleRef: externalHandleRef, currentTimeRef: externalCurrentTimeRef, durationRef: externalDurationRef, }: ProgressBarHeadlessExtendedProps): React.ReactElement;
96
+ declare const ProgressBarHeadless: react.MemoExoticComponent<typeof ProgressBarHeadlessBase>;
69
97
 
70
98
  /**
71
99
  * CSS for ProgressBar Component
@@ -79,6 +107,6 @@ declare function ProgressBarHeadless({ currentTime, duration, buffered, seekable
79
107
  * - Avoid width changes (causes layout thrashing)
80
108
  * 5. Support touch/click seek interaction
81
109
  */
82
- declare const PROGRESS_BAR_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * ProgressBar Container\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-progress-bar {\n /* Layout */\n position: relative;\n width: 100%;\n \n /* Interactive area - larger than visual for easier touch */\n height: var(--sv-progress-bar-touch-height, 24px);\n display: flex;\n align-items: center;\n \n /* Cursor */\n cursor: pointer;\n \n /* Prevent text selection during seek */\n user-select: none;\n -webkit-user-select: none;\n touch-action: none;\n}\n\n.sv-progress-bar--disabled {\n cursor: default;\n pointer-events: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Track Wrapper (contains track + tooltip)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__track-wrapper {\n position: relative;\n flex: 1;\n display: flex;\n align-items: center;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Track (background bar)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__track {\n position: relative;\n width: 100%;\n height: var(--sv-progress-bar-height, 3px);\n \n /* Visual */\n background: var(--sv-progress-bar-track-bg, rgba(255, 255, 255, 0.2));\n border-radius: var(--sv-progress-bar-radius, 1.5px);\n overflow: hidden;\n}\n\n/* Expand track on hover/active for better visibility */\n.sv-progress-bar:hover .sv-progress-bar__track,\n.sv-progress-bar--seeking .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-active, 5px);\n}\n\n/* Disable transition during seeking for immediate feedback */\n.sv-progress-bar--seeking .sv-progress-bar__fill,\n.sv-progress-bar--seeking .sv-progress-bar__handle {\n transition: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Buffered Fill (shows buffered progress)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n \n /* Visual */\n background: var(--sv-progress-bar-buffered-bg, rgba(255, 255, 255, 0.3));\n border-radius: inherit;\n \n /* Performance: Use scaleX for GPU acceleration */\n transform-origin: left center;\n transform: scaleX(0);\n \n /* Smooth transition for buffered updates */\n transition: transform 0.3s ease-out;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Progress Fill (shows playback progress)\n * IMPORTANT: Designed for Direct DOM Update (ADR 005)\n * - Uses scaleX() for 60fps smooth animation\n * - Wired component will update transform directly via DOM manipulation\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__fill {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n width: 100%;\n \n /* Visual */\n background: var(--sv-progress-bar-fill-bg, var(--sv-color-accent, #fe2c55));\n border-radius: inherit;\n \n /* Performance: Use scaleX for GPU acceleration */\n transform-origin: left center;\n transform: scaleX(0);\n \n /* Smooth transition for headless mode (timeupdate ~250ms intervals)\n * For RAF-based Direct DOM Update (wired mode), this has minimal impact\n * because transform updates every 16ms anyway */\n transition: var(--sv-progress-bar-fill-transition, transform 0.25s linear);\n will-change: transform;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Seek Handle (thumb indicator)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__handle {\n position: absolute;\n top: 50%;\n \n /* Size */\n width: var(--sv-progress-bar-handle-size, 12px);\n height: var(--sv-progress-bar-handle-size, 12px);\n \n /* Positioning - will be set via left % */\n left: 0;\n transform: translate(-50%, -50%) scale(0);\n \n /* Visual */\n background: var(--sv-progress-bar-handle-bg, #fff);\n border-radius: 50%;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n \n /* Animation - smooth position + show/hide */\n transition: left 0.25s linear, transform 0.15s ease-out;\n}\n\n/* Show handle on hover/seeking */\n.sv-progress-bar:hover .sv-progress-bar__handle,\n.sv-progress-bar--seeking .sv-progress-bar__handle {\n transform: translate(-50%, -50%) scale(1);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Time Display (optional, shows current/duration)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__time {\n display: flex;\n justify-content: space-between;\n padding: var(--sv-spacing-xs, 4px) 0;\n \n font-family: var(--sv-font-family, 'Urbanist', sans-serif);\n font-size: var(--sv-font-size-xs, 11px);\n font-variant-numeric: tabular-nums;\n color: var(--sv-text-secondary, rgba(255, 255, 255, 0.7));\n}\n\n.sv-progress-bar__time-current,\n.sv-progress-bar__time-duration {\n /* Ensure consistent width for changing numbers */\n min-width: 2.5em;\n}\n\n.sv-progress-bar__time-current {\n text-align: left;\n}\n\n.sv-progress-bar__time-duration {\n text-align: right;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Seek Tooltip (shows time at cursor position during hover)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__tooltip {\n position: absolute;\n /* Position above the container (not inside track to avoid overflow:hidden) */\n top: 0;\n left: 0;\n transform: translate(-50%, -100%);\n margin-top: -8px;\n \n /* Visual */\n padding: 4px 8px;\n background: var(--sv-bg-overlay, rgba(0, 0, 0, 0.8));\n border-radius: var(--sv-border-radius-sm, 4px);\n \n /* Typography */\n font-family: var(--sv-font-family, 'Urbanist', sans-serif);\n font-size: var(--sv-font-size-xs, 11px);\n font-variant-numeric: tabular-nums;\n color: var(--sv-text-primary, #fff);\n white-space: nowrap;\n \n /* Hidden by default */\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s ease, visibility 0.15s ease;\n \n /* Prevent tooltip from capturing pointer events */\n pointer-events: none;\n \n /* Ensure tooltip is above other elements */\n z-index: 10;\n}\n\n.sv-progress-bar:hover .sv-progress-bar__tooltip,\n.sv-progress-bar--seeking .sv-progress-bar__tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Minimal Variant (for use inside VideoSlot overlay)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar--minimal {\n height: auto;\n}\n\n.sv-progress-bar--minimal .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-minimal, 2px);\n}\n\n.sv-progress-bar--minimal:hover .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-minimal, 2px);\n}\n\n.sv-progress-bar--minimal .sv-progress-bar__handle {\n display: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Reduced Motion (Accessibility)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n@media (prefers-reduced-motion: reduce) {\n .sv-progress-bar__fill,\n .sv-progress-bar__buffered,\n .sv-progress-bar__handle,\n .sv-progress-bar__tooltip {\n transition: none;\n }\n}\n";
110
+ declare const PROGRESS_BAR_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * ProgressBar Container\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-progress-bar {\n /* Layout */\n position: relative;\n width: 100%;\n \n /* Interactive area - larger than visual for easier touch */\n height: var(--sv-progress-bar-touch-height, 24px);\n display: flex;\n align-items: center;\n \n /* Cursor */\n cursor: pointer;\n \n /* Prevent text selection during seek */\n user-select: none;\n -webkit-user-select: none;\n touch-action: none;\n}\n\n.sv-progress-bar--disabled {\n cursor: default;\n pointer-events: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Track Wrapper (contains track + tooltip)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__track-wrapper {\n position: relative;\n flex: 1;\n display: flex;\n align-items: center;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Track (background bar)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__track {\n position: relative;\n width: 100%;\n height: var(--sv-progress-bar-height, 3px);\n \n /* Visual */\n background: var(--sv-progress-bar-track-bg, rgba(255, 255, 255, 0.2));\n border-radius: var(--sv-progress-bar-radius, 1.5px);\n overflow: hidden;\n}\n\n/* Expand track on hover/active for better visibility */\n.sv-progress-bar:hover .sv-progress-bar__track,\n.sv-progress-bar--seeking .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-active, 5px);\n}\n\n/* Disable transition during seeking for immediate feedback */\n.sv-progress-bar--seeking .sv-progress-bar__fill,\n.sv-progress-bar--seeking .sv-progress-bar__handle {\n transition: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Buffered Fill (shows buffered progress)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n \n /* Visual */\n background: var(--sv-progress-bar-buffered-bg, rgba(255, 255, 255, 0.3));\n border-radius: inherit;\n \n /* Performance: Use scaleX for GPU acceleration */\n transform-origin: left center;\n transform: scaleX(0);\n \n /* Smooth transition for buffered updates */\n transition: transform 0.3s ease-out;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Progress Fill (shows playback progress)\n * IMPORTANT: Designed for Direct DOM Update (ADR 005)\n * - Uses scaleX() for 60fps smooth animation\n * - Wired component will update transform directly via DOM manipulation\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__fill {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n width: 100%;\n \n /* Visual */\n background: var(--sv-progress-bar-fill-bg, var(--sv-color-accent, #fe2c55));\n border-radius: inherit;\n \n /* Performance: Use scaleX for GPU acceleration */\n transform-origin: left center;\n transform: scaleX(0);\n \n /* Smooth transition for headless mode (timeupdate ~250ms intervals)\n * For RAF-based Direct DOM Update (wired mode), this has minimal impact\n * because transform updates every 16ms anyway */\n transition: var(--sv-progress-bar-fill-transition, transform 0.25s linear);\n will-change: transform;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Seek Handle (thumb indicator)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__handle {\n position: absolute;\n top: 50%;\n \n /* Size */\n width: var(--sv-progress-bar-handle-size, 12px);\n height: var(--sv-progress-bar-handle-size, 12px);\n \n /* Positioning - will be set via left % */\n left: 0;\n transform: translate(-50%, -50%) scale(0);\n \n /* Visual */\n background: var(--sv-progress-bar-handle-bg, #fff);\n border-radius: 50%;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n \n /* Animation - smooth position + show/hide */\n transition: left 0.25s linear, transform 0.15s ease-out;\n}\n\n/* Show handle on hover/seeking */\n.sv-progress-bar:hover .sv-progress-bar__handle,\n.sv-progress-bar--seeking .sv-progress-bar__handle {\n transform: translate(-50%, -50%) scale(1);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Time Display (optional, shows current/duration)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__time {\n display: flex;\n justify-content: space-between;\n padding: var(--sv-spacing-xs, 4px) 0;\n \n font-family: var(--sv-font-family, 'Urbanist', sans-serif);\n font-size: var(--sv-font-size-xs, 11px);\n font-variant-numeric: tabular-nums;\n color: var(--sv-text-secondary, rgba(255, 255, 255, 0.7));\n}\n\n.sv-progress-bar__time-current,\n.sv-progress-bar__time-duration {\n /* Ensure consistent width for changing numbers */\n min-width: 2.5em;\n}\n\n.sv-progress-bar__time-current {\n text-align: left;\n}\n\n.sv-progress-bar__time-duration {\n text-align: right;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Seek Tooltip (shows time at cursor position during hover)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar__tooltip {\n position: absolute;\n /* Position above the container (not inside track to avoid overflow:hidden) */\n top: 0;\n left: 0;\n transform: translate(-50%, -100%);\n margin-top: -8px;\n \n /* Visual */\n padding: 4px 8px;\n background: var(--sv-bg-overlay, rgba(0, 0, 0, 0.8));\n border-radius: var(--sv-border-radius-sm, 4px);\n \n /* Typography */\n font-family: var(--sv-font-family, 'Urbanist', sans-serif);\n font-size: var(--sv-font-size-xs, 11px);\n font-variant-numeric: tabular-nums;\n color: var(--sv-text-primary, #fff);\n white-space: nowrap;\n \n /* Hidden by default */\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s ease, visibility 0.15s ease;\n \n /* Prevent tooltip from capturing pointer events */\n pointer-events: none;\n \n /* Ensure tooltip is above other elements */\n z-index: 10;\n}\n\n.sv-progress-bar:hover .sv-progress-bar__tooltip,\n.sv-progress-bar--seeking .sv-progress-bar__tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Minimal Variant (for use inside VideoSlot overlay)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar--minimal {\n height: auto;\n}\n\n.sv-progress-bar--minimal .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-minimal, 2px);\n}\n\n.sv-progress-bar--minimal:hover .sv-progress-bar__track {\n height: var(--sv-progress-bar-height-minimal, 2px);\n}\n\n.sv-progress-bar--minimal .sv-progress-bar__handle {\n display: none;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Auto-hide Variant\n * Shows progress bar only when video is paused or user is seeking/hovering\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sv-progress-bar--auto-hide {\n /* Smooth transition for show/hide */\n transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease;\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n}\n\n.sv-progress-bar--auto-hide.sv-progress-bar--hidden {\n opacity: 0;\n visibility: hidden;\n transform: translateY(8px);\n pointer-events: none;\n}\n\n/* Show on hover even when auto-hide is enabled */\n.sv-progress-bar--auto-hide:hover {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n}\n\n/* Always show when seeking */\n.sv-progress-bar--auto-hide.sv-progress-bar--seeking {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Reduced Motion (Accessibility)\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n@media (prefers-reduced-motion: reduce) {\n .sv-progress-bar__fill,\n .sv-progress-bar__buffered,\n .sv-progress-bar__handle,\n .sv-progress-bar__tooltip {\n transition: none;\n }\n}\n";
83
111
 
84
112
  export { PROGRESS_BAR_CSS, ProgressBarHeadless, type ProgressBarHeadlessExtendedProps, calculateProgress, formatTime };
@@ -1 +1 @@
1
- export { PROGRESS_BAR_CSS, ProgressBarHeadless, calculateProgress, formatTime } from '../../chunk-YW23IBKF.js';
1
+ export { PROGRESS_BAR_CSS, ProgressBarHeadless, calculateProgress, formatTime } from '../../chunk-ECR42RKK.js';
@@ -1 +1 @@
1
- export { Skeleton, SkeletonAvatar, SkeletonText, SkeletonVideo } from '../../chunk-4MN72OZH.js';
1
+ export { Skeleton, SkeletonAvatar, SkeletonText, SkeletonVideo } from '../../chunk-UNV3NWN6.js';
@@ -0,0 +1,94 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ /**
4
+ * SubtitleDisplayHeadless - Headless subtitle display component
5
+ *
6
+ * Displays subtitle text on video with customizable styling.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+
11
+ /**
12
+ * Subtitle position
13
+ */
14
+ type SubtitlePosition = 'bottom' | 'top' | 'middle';
15
+ /**
16
+ * Subtitle size
17
+ */
18
+ type SubtitleSize = 'small' | 'medium' | 'large';
19
+ /**
20
+ * Subtitle style variant
21
+ */
22
+ type SubtitleStyle = 'background' | 'outline' | 'drop-shadow';
23
+ /**
24
+ * Props for SubtitleDisplayHeadless
25
+ */
26
+ interface SubtitleDisplayHeadlessProps {
27
+ /** Subtitle text to display */
28
+ text?: string | null;
29
+ /** Whether subtitles are enabled */
30
+ isEnabled?: boolean;
31
+ /** Position of subtitles */
32
+ position?: SubtitlePosition;
33
+ /** Size variant */
34
+ size?: SubtitleSize;
35
+ /** Style variant */
36
+ styleVariant?: SubtitleStyle;
37
+ /** Additional CSS class */
38
+ className?: string;
39
+ /** Custom render */
40
+ renderSubtitle?: (text: string) => ReactNode;
41
+ /** Test ID */
42
+ testId?: string;
43
+ }
44
+ /**
45
+ * SubtitleDisplayHeadless - Display subtitles on video
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * <SubtitleDisplayHeadless
50
+ * text={currentSubtitle}
51
+ * isEnabled={isSubtitleEnabled}
52
+ * position="bottom"
53
+ * size="medium"
54
+ * />
55
+ * ```
56
+ */
57
+ declare function SubtitleDisplayHeadless({ text, isEnabled, position, size, styleVariant, className, renderSubtitle, testId, }: SubtitleDisplayHeadlessProps): React.ReactElement | null;
58
+ /**
59
+ * Props for SubtitleIndicator
60
+ */
61
+ interface SubtitleIndicatorProps {
62
+ /** Whether video has subtitles */
63
+ hasSubtitle: boolean;
64
+ /** Whether subtitles are enabled */
65
+ isEnabled?: boolean;
66
+ /** Custom icon */
67
+ icon?: ReactNode;
68
+ /** Additional CSS class */
69
+ className?: string;
70
+ /** Click handler */
71
+ onClick?: () => void;
72
+ }
73
+ /**
74
+ * SubtitleIndicator - CC icon showing subtitle availability
75
+ *
76
+ * @example
77
+ * ```tsx
78
+ * <SubtitleIndicator
79
+ * hasSubtitle={video.hasSubtitle}
80
+ * isEnabled={isSubtitleEnabled}
81
+ * onClick={toggleSubtitle}
82
+ * />
83
+ * ```
84
+ */
85
+ declare function SubtitleIndicator({ hasSubtitle, isEnabled, icon, className, onClick, }: SubtitleIndicatorProps): React.ReactElement | null;
86
+
87
+ /**
88
+ * SubtitleDisplay CSS
89
+ *
90
+ * Styles for subtitle text overlay on video.
91
+ */
92
+ declare const SUBTITLE_DISPLAY_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * SUBTITLE DISPLAY\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-subtitle-display {\n position: absolute;\n bottom: var(--sv-subtitle-bottom, 80px);\n left: 50%;\n transform: translateX(-50%);\n max-width: 90%;\n padding: var(--sv-subtitle-padding, 8px 16px);\n background: var(--sv-subtitle-bg, rgba(0, 0, 0, 0.75));\n border-radius: var(--sv-subtitle-radius, 4px);\n color: var(--sv-subtitle-color, #fff);\n font-size: var(--sv-subtitle-font-size, 16px);\n font-family: var(--sv-subtitle-font-family, inherit);\n line-height: var(--sv-subtitle-line-height, 1.4);\n text-align: center;\n z-index: var(--sv-z-subtitle, 10);\n pointer-events: none;\n transition: opacity 150ms ease-out;\n}\n\n/* Hidden state */\n.sv-subtitle-display--hidden {\n opacity: 0;\n}\n\n/* Position variants */\n.sv-subtitle-display--top {\n bottom: auto;\n top: var(--sv-subtitle-top, 60px);\n}\n\n.sv-subtitle-display--middle {\n bottom: auto;\n top: 50%;\n transform: translate(-50%, -50%);\n}\n\n/* Size variants */\n.sv-subtitle-display--small {\n font-size: 14px;\n padding: 6px 12px;\n}\n\n.sv-subtitle-display--large {\n font-size: 20px;\n padding: 10px 20px;\n}\n\n/* Style variants */\n.sv-subtitle-display--outline {\n background: transparent;\n text-shadow: \n -1px -1px 0 #000,\n 1px -1px 0 #000,\n -1px 1px 0 #000,\n 1px 1px 0 #000;\n}\n\n.sv-subtitle-display--drop-shadow {\n background: transparent;\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * SUBTITLE INDICATOR (CC icon)\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-subtitle-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: var(--sv-subtitle-indicator-color, rgba(255, 255, 255, 0.7));\n}\n\n.sv-subtitle-indicator[data-enabled=\"true\"] {\n color: var(--sv-subtitle-indicator-active, #fff);\n}\n\n.sv-subtitle-indicator[data-available=\"false\"] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * REDUCE MOTION\n * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (prefers-reduced-motion: reduce) {\n .sv-subtitle-display {\n transition: none;\n }\n}\n";
93
+
94
+ export { SUBTITLE_DISPLAY_CSS, SubtitleDisplayHeadless, type SubtitleDisplayHeadlessProps, SubtitleIndicator, type SubtitleIndicatorProps, type SubtitlePosition, type SubtitleSize, type SubtitleStyle };
@@ -0,0 +1,165 @@
1
+ import { injectComponentCSS } from '../../chunk-RMLTPW5S.js';
2
+ import { clsx } from 'clsx';
3
+ import { useInsertionEffect } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/SubtitleDisplay/SubtitleDisplay.css.ts
7
+ var SUBTITLE_DISPLAY_CSS = `
8
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
9
+ * SUBTITLE DISPLAY
10
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
11
+
12
+ .sv-subtitle-display {
13
+ position: absolute;
14
+ bottom: var(--sv-subtitle-bottom, 80px);
15
+ left: 50%;
16
+ transform: translateX(-50%);
17
+ max-width: 90%;
18
+ padding: var(--sv-subtitle-padding, 8px 16px);
19
+ background: var(--sv-subtitle-bg, rgba(0, 0, 0, 0.75));
20
+ border-radius: var(--sv-subtitle-radius, 4px);
21
+ color: var(--sv-subtitle-color, #fff);
22
+ font-size: var(--sv-subtitle-font-size, 16px);
23
+ font-family: var(--sv-subtitle-font-family, inherit);
24
+ line-height: var(--sv-subtitle-line-height, 1.4);
25
+ text-align: center;
26
+ z-index: var(--sv-z-subtitle, 10);
27
+ pointer-events: none;
28
+ transition: opacity 150ms ease-out;
29
+ }
30
+
31
+ /* Hidden state */
32
+ .sv-subtitle-display--hidden {
33
+ opacity: 0;
34
+ }
35
+
36
+ /* Position variants */
37
+ .sv-subtitle-display--top {
38
+ bottom: auto;
39
+ top: var(--sv-subtitle-top, 60px);
40
+ }
41
+
42
+ .sv-subtitle-display--middle {
43
+ bottom: auto;
44
+ top: 50%;
45
+ transform: translate(-50%, -50%);
46
+ }
47
+
48
+ /* Size variants */
49
+ .sv-subtitle-display--small {
50
+ font-size: 14px;
51
+ padding: 6px 12px;
52
+ }
53
+
54
+ .sv-subtitle-display--large {
55
+ font-size: 20px;
56
+ padding: 10px 20px;
57
+ }
58
+
59
+ /* Style variants */
60
+ .sv-subtitle-display--outline {
61
+ background: transparent;
62
+ text-shadow:
63
+ -1px -1px 0 #000,
64
+ 1px -1px 0 #000,
65
+ -1px 1px 0 #000,
66
+ 1px 1px 0 #000;
67
+ }
68
+
69
+ .sv-subtitle-display--drop-shadow {
70
+ background: transparent;
71
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
72
+ }
73
+
74
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
75
+ * SUBTITLE INDICATOR (CC icon)
76
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
77
+
78
+ .sv-subtitle-indicator {
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ width: 24px;
83
+ height: 24px;
84
+ color: var(--sv-subtitle-indicator-color, rgba(255, 255, 255, 0.7));
85
+ }
86
+
87
+ .sv-subtitle-indicator[data-enabled="true"] {
88
+ color: var(--sv-subtitle-indicator-active, #fff);
89
+ }
90
+
91
+ .sv-subtitle-indicator[data-available="false"] {
92
+ opacity: 0.3;
93
+ pointer-events: none;
94
+ }
95
+
96
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
97
+ * REDUCE MOTION
98
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
99
+
100
+ @media (prefers-reduced-motion: reduce) {
101
+ .sv-subtitle-display {
102
+ transition: none;
103
+ }
104
+ }
105
+ `;
106
+ function SubtitleDisplayHeadless({
107
+ text,
108
+ isEnabled = true,
109
+ position = "bottom",
110
+ size = "medium",
111
+ styleVariant = "background",
112
+ className,
113
+ renderSubtitle,
114
+ testId
115
+ }) {
116
+ useInsertionEffect(() => {
117
+ return injectComponentCSS("subtitle-display", SUBTITLE_DISPLAY_CSS);
118
+ }, []);
119
+ if (!isEnabled || !text) {
120
+ return null;
121
+ }
122
+ const positionClass = position !== "bottom" ? `sv-subtitle-display--${position}` : "";
123
+ const sizeClass = size !== "medium" ? `sv-subtitle-display--${size}` : "";
124
+ const styleClass = styleVariant !== "background" ? `sv-subtitle-display--${styleVariant}` : "";
125
+ return /* @__PURE__ */ jsx(
126
+ "div",
127
+ {
128
+ className: clsx("sv-subtitle-display", positionClass, sizeClass, styleClass, className),
129
+ "aria-live": "polite",
130
+ "aria-atomic": "true",
131
+ "data-testid": testId,
132
+ children: renderSubtitle ? renderSubtitle(text) : text
133
+ }
134
+ );
135
+ }
136
+ function CCIcon() {
137
+ return /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M19 4H5a2 2 0 00-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 01-1 1h-3a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1z" }) });
138
+ }
139
+ function SubtitleIndicator({
140
+ hasSubtitle,
141
+ isEnabled = false,
142
+ icon,
143
+ className,
144
+ onClick
145
+ }) {
146
+ useInsertionEffect(() => {
147
+ return injectComponentCSS("subtitle-display", SUBTITLE_DISPLAY_CSS);
148
+ }, []);
149
+ if (!hasSubtitle) return null;
150
+ return /* @__PURE__ */ jsx(
151
+ "button",
152
+ {
153
+ type: "button",
154
+ className: clsx("sv-subtitle-indicator", className),
155
+ "data-enabled": isEnabled,
156
+ "data-available": hasSubtitle,
157
+ onClick,
158
+ "aria-label": isEnabled ? "Turn off subtitles" : "Turn on subtitles",
159
+ "aria-pressed": isEnabled,
160
+ children: icon ?? /* @__PURE__ */ jsx(CCIcon, {})
161
+ }
162
+ );
163
+ }
164
+
165
+ export { SUBTITLE_DISPLAY_CSS, SubtitleDisplayHeadless, SubtitleIndicator };
@@ -8,6 +8,11 @@ import { ReactNode } from 'react';
8
8
  * Position-based virtual scroller for video feed (TikTok-style).
9
9
  * Receives state via props (headless pattern).
10
10
  *
11
+ * This component wraps VirtualSlider<VideoItem> and adds:
12
+ * - Video-specific context (VideoFeedContext)
13
+ * - Video-specific CSS classes (sv-video-feed prefix)
14
+ * - Backwards-compatible API
15
+ *
11
16
  * Features:
12
17
  * - Virtual scrolling (only renders visible + buffer slots)
13
18
  * - CSS transform-based scrolling (60fps)
@@ -72,8 +77,14 @@ interface VideoFeedHeadlessProps {
72
77
  *
73
78
  * Renders a vertical video feed with virtual scrolling.
74
79
  * Position-based: each video takes full viewport height.
80
+ *
81
+ * Internally uses VirtualSlider<VideoItem> for the core slider logic,
82
+ * adding video-specific context and styling.
75
83
  */
76
84
  declare function VideoFeedHeadless({ feedState, swipeState, height, className, renderSlot, onIndexChange, onEndReached, endReachedThreshold, bufferSize, loadingText, emptyText, endText, disableInlineTransforms, }: VideoFeedHeadlessProps): React.ReactElement;
85
+ declare namespace VideoFeedHeadless {
86
+ var displayName: string;
87
+ }
77
88
 
78
89
  /**
79
90
  * VideoFeed context value
@@ -1 +1 @@
1
- export { SLOT_ACTIVE_ATTR, SLOT_ACTIVE_DATASET_KEY, SLOT_INDEX_ATTR, SLOT_INDEX_DATASET_KEY, VIDEO_FEED_CLASS_PREFIX, VIDEO_FEED_CSS, VideoFeedContext, VideoFeedHeadless, getSlotIndexFromPosition, useOptionalVideoFeedContext, useVideoFeedContext, useVideoFeedPosition } from '../../chunk-ZZDQKP4R.js';
1
+ export { SLOT_ACTIVE_ATTR, SLOT_ACTIVE_DATASET_KEY, SLOT_INDEX_ATTR, SLOT_INDEX_DATASET_KEY, VIDEO_FEED_CLASS_PREFIX, VIDEO_FEED_CSS, VideoFeedContext, VideoFeedHeadless, getSlotIndexFromPosition, useOptionalVideoFeedContext, useVideoFeedContext, useVideoFeedPosition } from '../../chunk-WCRDTBCZ.js';
@@ -1 +1 @@
1
- export { VIDEO_INFO_CSS, VideoAuthorName, VideoCaption, VideoHashtags, VideoInfoContext, VideoInfoHeadless, VideoLocation, VideoMusic, useOptionalVideoInfoContext, useVideoInfoContext } from '../../chunk-DHQJBXQW.js';
1
+ export { VIDEO_INFO_CSS, VideoAuthorName, VideoCaption, VideoHashtags, VideoInfoContext, VideoInfoHeadless, VideoLocation, VideoMusic, useOptionalVideoInfoContext, useVideoInfoContext } from '../../chunk-KWHMZ6H5.js';
@@ -1,41 +1,6 @@
1
+ import * as react from 'react';
1
2
  import { VideoPlayerHeadlessProps } from '@xhub-short/contracts';
2
3
 
3
- /**
4
- * VideoPlayerHeadless Component
5
- *
6
- * Headless video player component that receives all data via props.
7
- * Handles video playback for both MP4 and HLS sources.
8
- *
9
- * Features:
10
- * - MP4 and HLS support (with lazy hls.js loading)
11
- * - First frame capture
12
- * - Loading and error states
13
- * - Poster image support
14
- * - Accessibility support
15
- *
16
- * @example
17
- * ```tsx
18
- * // Basic usage
19
- * <VideoPlayerHeadless
20
- * src="https://example.com/video.mp4"
21
- * type="mp4"
22
- * poster="https://example.com/poster.jpg"
23
- * autoPlay
24
- * muted
25
- * />
26
- *
27
- * // With all callbacks
28
- * <VideoPlayerHeadless
29
- * src={video.url}
30
- * type={video.type}
31
- * onPlay={() => console.log('Playing')}
32
- * onPause={() => console.log('Paused')}
33
- * onTimeUpdate={(time) => setCurrentTime(time)}
34
- * onError={(error) => console.error(error)}
35
- * />
36
- * ```
37
- */
38
-
39
4
  interface VideoPlayerHeadlessExtendedProps extends VideoPlayerHeadlessProps {
40
5
  /** Unique video ID for first frame caching */
41
6
  videoId?: string;
@@ -72,11 +37,19 @@ interface VideoPlayerHeadlessExtendedProps extends VideoPlayerHeadlessProps {
72
37
  *
73
38
  * Headless video player component.
74
39
  * All state is managed via props - no SDK dependencies.
40
+ *
41
+ * Wrapped with React.memo to prevent unnecessary re-renders.
42
+ * The component only re-renders when props actually change.
75
43
  */
76
- declare function VideoPlayerHeadless({ src, type, poster, autoPlay, loop, muted, volume, startTime, className, videoRef: externalVideoRef, videoId, objectFit, showErrorUI, showLoadingUI, showPoster, loadingComponent, errorComponent, onCanPlay, onPlay, onPlaying, onPause, onEnded, onTimeUpdate, onDurationChange, onWaiting, onError, onFirstFrameCapture, }: VideoPlayerHeadlessExtendedProps): React.ReactElement;
77
- declare namespace VideoPlayerHeadless {
78
- var displayName: string;
79
- }
44
+ declare function VideoPlayerHeadlessBase({ src, type, poster, autoPlay, loop, muted, volume, startTime, className, videoRef: externalVideoRef, videoId, objectFit, showErrorUI, showLoadingUI, showPoster, loadingComponent, errorComponent, onCanPlay, onPlay, onPlaying, onPause, onEnded, onTimeUpdate, onDurationChange, onWaiting, onError, onFirstFrameCapture, }: VideoPlayerHeadlessExtendedProps): React.ReactElement;
45
+ /**
46
+ * VideoPlayerHeadless - Memoized for performance
47
+ *
48
+ * Prevents re-renders when parent components update with same props.
49
+ * Particularly important when used inside VideoSlot which may receive
50
+ * frequent state updates from PlayerEngine.
51
+ */
52
+ declare const VideoPlayerHeadless: react.MemoExoticComponent<typeof VideoPlayerHeadlessBase>;
80
53
 
81
54
  /**
82
55
  * useVideoElement Hook
@@ -473,6 +446,6 @@ declare const FIRST_FRAME_MAX_WIDTH = 360;
473
446
  * CSS-in-JS styles injected per component.
474
447
  * Uses CSS variables for theming and customization.
475
448
  */
476
- declare const VIDEO_PLAYER_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VideoPlayer Container\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--sv-bg-primary, #000);\n /* CSS variable z-index defaults */\n --sv-player-video-z: 1;\n --sv-player-poster-z: 2;\n --sv-player-loading-z: 3;\n --sv-player-error-z: 4;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Video Element Wrapper\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__video-wrapper {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--sv-player-video-z);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Video Element\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__video {\n width: 100%;\n height: 100%;\n object-fit: var(--sv-player-object-fit, contain);\n background: transparent;\n /* Prevent iOS controls */\n -webkit-playsinline: true;\n}\n\n/* Hide video when loading/error for smooth poster display */\n.sv-video-player--loading .sv-video-player__video,\n.sv-video-player--error .sv-video-player__video {\n opacity: 0;\n}\n\n/* Smooth transition for video visibility */\n.sv-video-player__video {\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Poster Overlay\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__poster {\n position: absolute;\n inset: 0;\n z-index: var(--sv-player-poster-z);\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n/**\n * Hide poster when video is ready OR playing.\n *\n * Poster visibility rules:\n * - SHOW: During initial loading (--loading)\n * - HIDE: Once video is ready (--ready) - even if paused\n * - HIDE: When playing (--playing)\n * - STAY HIDDEN: During buffering (--buffering) - video already visible\n *\n * pointer-events: none ensures poster doesn't block clicks on video.\n */\n.sv-video-player--ready .sv-video-player__poster,\n.sv-video-player--playing .sv-video-player__poster {\n opacity: 0;\n pointer-events: none;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Loading Spinner\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__loading {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--sv-player-loading-z);\n background: var(--sv-loading-bg, rgba(0, 0, 0, 0.3));\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n.sv-video-player--loading .sv-video-player__loading {\n opacity: 1;\n pointer-events: auto;\n}\n\n/* Default spinner animation */\n.sv-video-player__spinner {\n width: var(--sv-spinner-size, 40px);\n height: var(--sv-spinner-size, 40px);\n border: 3px solid var(--sv-spinner-color, rgba(255, 255, 255, 0.3));\n border-top-color: var(--sv-spinner-active-color, #fff);\n border-radius: 50%;\n animation: sv-player-spin 0.8s linear infinite;\n}\n\n@keyframes sv-player-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Error State\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__error {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--sv-spacing-md, 12px);\n z-index: var(--sv-player-error-z);\n background: var(--sv-error-bg, rgba(0, 0, 0, 0.8));\n color: var(--sv-error-color, #fff);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n.sv-video-player--error .sv-video-player__error {\n opacity: 1;\n pointer-events: auto;\n}\n\n.sv-video-player__error-icon {\n width: var(--sv-error-icon-size, 48px);\n height: var(--sv-error-icon-size, 48px);\n color: var(--sv-error-icon-color, rgba(255, 255, 255, 0.7));\n}\n\n.sv-video-player__error-message {\n font-size: var(--sv-error-font-size, 14px);\n color: var(--sv-error-text-color, rgba(255, 255, 255, 0.8));\n text-align: center;\n max-width: 80%;\n}\n\n.sv-video-player__retry-btn {\n padding: var(--sv-spacing-sm, 8px) var(--sv-spacing-lg, 16px);\n background: var(--sv-btn-bg, rgba(255, 255, 255, 0.2));\n border: 1px solid var(--sv-btn-border, rgba(255, 255, 255, 0.3));\n border-radius: var(--sv-btn-radius, 6px);\n color: var(--sv-btn-color, #fff);\n font-size: var(--sv-btn-font-size, 14px);\n cursor: pointer;\n transition: background var(--sv-transition-duration, 200ms) ease;\n}\n\n.sv-video-player__retry-btn:hover {\n background: var(--sv-btn-hover-bg, rgba(255, 255, 255, 0.3));\n}\n\n.sv-video-player__retry-btn:active {\n transform: scale(0.98);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Accessibility - Reduced Motion\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (prefers-reduced-motion: reduce) {\n .sv-video-player__video,\n .sv-video-player__poster,\n .sv-video-player__loading,\n .sv-video-player__error {\n transition: none;\n }\n\n .sv-video-player__spinner {\n animation: none;\n border-top-color: var(--sv-spinner-active-color, #fff);\n }\n}\n";
449
+ declare const VIDEO_PLAYER_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VideoPlayer Container\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--sv-bg-primary, #000);\n /* CSS variable z-index defaults */\n --sv-player-video-z: 1;\n --sv-player-poster-z: 2;\n --sv-player-loading-z: 3;\n --sv-player-error-z: 4;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Video Element Wrapper\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__video-wrapper {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--sv-player-video-z);\n background: var(--sv-bg-primary, #000);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Video Element\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__video {\n width: 100%;\n height: 100%;\n object-fit: var(--sv-player-object-fit, contain);\n background: transparent;\n /* Prevent iOS controls */\n -webkit-playsinline: true;\n}\n\n/* Hide video when loading/error for smooth poster display */\n.sv-video-player--loading .sv-video-player__video,\n.sv-video-player--error .sv-video-player__video {\n opacity: 0;\n}\n\n/* Smooth transition for video visibility */\n.sv-video-player__video {\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Poster Overlay\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__poster {\n position: absolute;\n inset: 0;\n z-index: var(--sv-player-poster-z);\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n/**\n * Hide poster when video is ready OR playing.\n *\n * Poster visibility rules:\n * - SHOW: During initial loading (--loading)\n * - HIDE: Once video is ready (--ready) - even if paused\n * - HIDE: When playing (--playing)\n * - STAY HIDDEN: During buffering (--buffering) - video already visible\n *\n * pointer-events: none ensures poster doesn't block clicks on video.\n */\n.sv-video-player--ready .sv-video-player__poster,\n.sv-video-player--playing .sv-video-player__poster {\n opacity: 0;\n pointer-events: none;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Loading Spinner\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__loading {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: var(--sv-player-loading-z);\n background: var(--sv-loading-bg, rgba(0, 0, 0, 0.3));\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n.sv-video-player--loading .sv-video-player__loading {\n opacity: 1;\n pointer-events: auto;\n}\n\n/* Default spinner animation */\n.sv-video-player__spinner {\n width: var(--sv-spinner-size, 40px);\n height: var(--sv-spinner-size, 40px);\n border: 3px solid var(--sv-spinner-color, rgba(255, 255, 255, 0.3));\n border-top-color: var(--sv-spinner-active-color, #fff);\n border-radius: 50%;\n animation: sv-player-spin 0.8s linear infinite;\n}\n\n@keyframes sv-player-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Error State\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-video-player__error {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--sv-spacing-md, 12px);\n z-index: var(--sv-player-error-z);\n background: var(--sv-error-bg, rgba(0, 0, 0, 0.8));\n color: var(--sv-error-color, #fff);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--sv-transition-duration, 200ms) ease-out;\n}\n\n.sv-video-player--error .sv-video-player__error {\n opacity: 1;\n pointer-events: auto;\n}\n\n.sv-video-player__error-icon {\n width: var(--sv-error-icon-size, 48px);\n height: var(--sv-error-icon-size, 48px);\n color: var(--sv-error-icon-color, rgba(255, 255, 255, 0.7));\n}\n\n.sv-video-player__error-message {\n font-size: var(--sv-error-font-size, 14px);\n color: var(--sv-error-text-color, rgba(255, 255, 255, 0.8));\n text-align: center;\n max-width: 80%;\n}\n\n.sv-video-player__retry-btn {\n padding: var(--sv-spacing-sm, 8px) var(--sv-spacing-lg, 16px);\n background: var(--sv-btn-bg, rgba(255, 255, 255, 0.2));\n border: 1px solid var(--sv-btn-border, rgba(255, 255, 255, 0.3));\n border-radius: var(--sv-btn-radius, 6px);\n color: var(--sv-btn-color, #fff);\n font-size: var(--sv-btn-font-size, 14px);\n cursor: pointer;\n transition: background var(--sv-transition-duration, 200ms) ease;\n}\n\n.sv-video-player__retry-btn:hover {\n background: var(--sv-btn-hover-bg, rgba(255, 255, 255, 0.3));\n}\n\n.sv-video-player__retry-btn:active {\n transform: scale(0.98);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Accessibility - Reduced Motion\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (prefers-reduced-motion: reduce) {\n .sv-video-player__video,\n .sv-video-player__poster,\n .sv-video-player__loading,\n .sv-video-player__error {\n transition: none;\n }\n\n .sv-video-player__spinner {\n animation: none;\n border-top-color: var(--sv-spinner-active-color, #fff);\n }\n}\n";
477
450
 
478
451
  export { BUFFERING_STATE_CLASS, DEFAULT_OBJECT_FIT, DEFAULT_PRELOAD, ENDED_CLASS, ERROR_CLASS, ERROR_STATE_CLASS, FIRST_FRAME_MAX_WIDTH, FIRST_FRAME_QUALITY, LOADING_CLASS, LOADING_STATE_ATTR, LOADING_STATE_CLASS, PAUSED_CLASS, PLAYBACK_STATE_ATTR, PLAYER_CLASS, PLAYING_CLASS, POSTER_CLASS, READY_CLASS, type UseAutoFirstFrameCaptureConfig, type UseFirstFrameCaptureConfig, type UseFirstFrameCaptureReturn, type UseVideoElementConfig, type UseVideoElementReturn, VIDEO_CLASS, VIDEO_PLAYER_CSS, VIDEO_TYPE_ATTR, VIDEO_WRAPPER_CLASS, VideoElementError, type VideoErrorOrigin, VideoPlayerHeadless, type VideoPlayerHeadlessExtendedProps, type VideoSourceType, Z_INDEX, Z_INDEX_CSS_VARS, useAutoFirstFrameCapture, useFirstFrameCapture, useVideoElement };
@@ -1 +1 @@
1
- export { BUFFERING_STATE_CLASS, DEFAULT_OBJECT_FIT, DEFAULT_PRELOAD, ENDED_CLASS, ERROR_CLASS, ERROR_STATE_CLASS, FIRST_FRAME_MAX_WIDTH, FIRST_FRAME_QUALITY, LOADING_CLASS, LOADING_STATE_ATTR, LOADING_STATE_CLASS, PAUSED_CLASS, PLAYBACK_STATE_ATTR, PLAYER_CLASS, PLAYING_CLASS, POSTER_CLASS, READY_CLASS, VIDEO_CLASS, VIDEO_PLAYER_CSS, VIDEO_TYPE_ATTR, VIDEO_WRAPPER_CLASS, VideoElementError, VideoPlayerHeadless, Z_INDEX, Z_INDEX_CSS_VARS, useAutoFirstFrameCapture, useFirstFrameCapture, useVideoElement } from '../../chunk-HW4LXTFT.js';
1
+ export { BUFFERING_STATE_CLASS, DEFAULT_OBJECT_FIT, DEFAULT_PRELOAD, ENDED_CLASS, ERROR_CLASS, ERROR_STATE_CLASS, FIRST_FRAME_MAX_WIDTH, FIRST_FRAME_QUALITY, LOADING_CLASS, LOADING_STATE_ATTR, LOADING_STATE_CLASS, PAUSED_CLASS, PLAYBACK_STATE_ATTR, PLAYER_CLASS, PLAYING_CLASS, POSTER_CLASS, READY_CLASS, VIDEO_CLASS, VIDEO_PLAYER_CSS, VIDEO_TYPE_ATTR, VIDEO_WRAPPER_CLASS, VideoElementError, VideoPlayerHeadless, Z_INDEX, Z_INDEX_CSS_VARS, useAutoFirstFrameCapture, useFirstFrameCapture, useVideoElement } from '../../chunk-CL6BS7GB.js';