@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.
- package/dist/CommentSheet.css-BeCrEaUG.d.ts +221 -0
- package/dist/{chunk-2PTMP65P.js → chunk-2FSDVYER.js} +8 -9
- package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
- package/dist/{chunk-ANGBSV7L.js → chunk-AC2IFAJR.js} +10 -5
- package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
- package/dist/chunk-AQHD6LPS.js +430 -0
- package/dist/{chunk-HW4LXTFT.js → chunk-CL6BS7GB.js} +7 -5
- package/dist/{chunk-YW23IBKF.js → chunk-ECR42RKK.js} +46 -5
- package/dist/chunk-EDWS2IPH.js +1 -0
- package/dist/chunk-FNXTPQ6L.js +2573 -0
- package/dist/{chunk-DHQJBXQW.js → chunk-KWHMZ6H5.js} +1 -1
- package/dist/{chunk-UXMA4KJZ.js → chunk-RMLTPW5S.js} +3 -2
- package/dist/{chunk-SSJDO24Q.js → chunk-SZXFH334.js} +1 -1
- package/dist/{chunk-4MN72OZH.js → chunk-UNV3NWN6.js} +4 -4
- package/dist/{chunk-ZZDQKP4R.js → chunk-WCRDTBCZ.js} +94 -155
- package/dist/{chunk-XAOEHLOX.js → chunk-XDIH66C4.js} +245 -52
- package/dist/components/ActionBar/index.js +1 -1
- package/dist/components/AuthorInfo/index.d.ts +5 -1
- package/dist/components/AuthorInfo/index.js +1 -1
- package/dist/components/BlurhashPlaceholder/index.d.ts +67 -0
- package/dist/components/BlurhashPlaceholder/index.js +150 -0
- package/dist/components/CommentSheet/index.d.ts +164 -0
- package/dist/components/CommentSheet/index.js +1 -0
- package/dist/components/ErrorBoundary/index.js +1 -1
- package/dist/components/OfflineIndicator/index.d.ts +56 -0
- package/dist/components/OfflineIndicator/index.js +151 -0
- package/dist/components/ProgressBar/index.d.ts +30 -2
- package/dist/components/ProgressBar/index.js +1 -1
- package/dist/components/Skeleton/index.js +1 -1
- package/dist/components/SubtitleDisplay/index.d.ts +94 -0
- package/dist/components/SubtitleDisplay/index.js +165 -0
- package/dist/components/VideoFeed/index.d.ts +11 -0
- package/dist/components/VideoFeed/index.js +1 -1
- package/dist/components/VideoInfo/index.js +1 -1
- package/dist/components/VideoPlayer/index.d.ts +14 -41
- package/dist/components/VideoPlayer/index.js +1 -1
- package/dist/components/VideoSlot/index.d.ts +124 -64
- package/dist/components/VideoSlot/index.js +1 -1
- package/dist/components/VirtualSlider/index.d.ts +339 -0
- package/dist/components/VirtualSlider/index.js +1 -0
- package/dist/components/icons/index.js +1 -1
- package/dist/index.d.ts +76 -93
- package/dist/index.js +75 -27
- package/package.json +53 -8
- 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
|
|
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-
|
|
1
|
+
export { PROGRESS_BAR_CSS, ProgressBarHeadless, calculateProgress, formatTime } from '../../chunk-ECR42RKK.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Skeleton, SkeletonAvatar, SkeletonText, SkeletonVideo } from '../../chunk-
|
|
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-
|
|
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-
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
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-
|
|
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';
|