@xhub-short/ui 0.1.0-beta.9 → 1.0.0-beta.18

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 (74) hide show
  1. package/dist/CommentSheet.css-DuBy01rU.d.ts +219 -0
  2. package/dist/VideoSlotPlayIndicator-DPs8Xt5C.d.ts +51 -0
  3. package/dist/chunk-3OB3OVYR.js +349 -0
  4. package/dist/chunk-4RIMQOBR.js +58 -0
  5. package/dist/chunk-5MKYDI4X.js +1 -0
  6. package/dist/chunk-5Y43HNRG.js +296 -0
  7. package/dist/chunk-7WXAQHJI.js +350 -0
  8. package/dist/chunk-BADA7OLG.js +564 -0
  9. package/dist/chunk-BEJAJFV6.js +191 -0
  10. package/dist/chunk-BNI7CYRI.js +334 -0
  11. package/dist/{chunk-RMLTPW5S.js → chunk-CAWE42LH.js} +4 -3
  12. package/dist/chunk-DGKMO3AE.js +717 -0
  13. package/dist/chunk-DR7KR7OT.js +103 -0
  14. package/dist/chunk-GSNIZ6DF.js +605 -0
  15. package/dist/chunk-HXQPEZRG.js +105 -0
  16. package/dist/{chunk-FNXTPQ6L.js → chunk-IC2KUU4V.js} +31 -1340
  17. package/dist/chunk-IWSBYOSS.js +91 -0
  18. package/dist/chunk-MFJS65C5.js +368 -0
  19. package/dist/{chunk-AC2IFAJR.js → chunk-NJXIYSDZ.js} +12 -1
  20. package/dist/{chunk-CL6BS7GB.js → chunk-OM4L7RE5.js} +12 -2
  21. package/dist/chunk-QCRRF76W.js +75 -0
  22. package/dist/chunk-QUEJHA24.js +508 -0
  23. package/dist/chunk-UYBQTE4M.js +337 -0
  24. package/dist/chunk-VJ744W5N.js +603 -0
  25. package/dist/chunk-VXW7AOGM.js +285 -0
  26. package/dist/{chunk-AQHD6LPS.js → chunk-YB7AXTX7.js} +1 -1
  27. package/dist/components/ActionBar/index.d.ts +7 -2
  28. package/dist/components/ActionBar/index.js +1 -1
  29. package/dist/components/AdvanceMenu/index.d.ts +80 -0
  30. package/dist/components/AdvanceMenu/index.js +1 -0
  31. package/dist/components/ArticleSlot/index.d.ts +213 -0
  32. package/dist/components/ArticleSlot/index.js +1 -0
  33. package/dist/components/AuthorInfo/index.js +1 -1
  34. package/dist/components/BottomSheet/index.d.ts +87 -0
  35. package/dist/components/BottomSheet/index.js +1 -0
  36. package/dist/components/CleanModeOverlay/index.d.ts +60 -0
  37. package/dist/components/CleanModeOverlay/index.js +1 -0
  38. package/dist/components/CommentSheet/index.d.ts +1 -1
  39. package/dist/components/CommentSheet/index.js +1 -1
  40. package/dist/components/DetailView/index.d.ts +314 -0
  41. package/dist/components/DetailView/index.js +1 -0
  42. package/dist/components/ErrorBoundary/index.js +1 -1
  43. package/dist/components/{VideoFeed → Feed}/index.d.ts +64 -45
  44. package/dist/components/Feed/index.js +1 -0
  45. package/dist/components/ImageCarousel/index.d.ts +50 -0
  46. package/dist/components/ImageCarousel/index.js +1 -0
  47. package/dist/components/Playlist/index.d.ts +117 -0
  48. package/dist/components/Playlist/index.js +1 -0
  49. package/dist/components/ProgressBar/index.js +1 -1
  50. package/dist/components/QualityPicker/index.d.ts +35 -0
  51. package/dist/components/QualityPicker/index.js +1 -0
  52. package/dist/components/ReportSheet/index.d.ts +74 -0
  53. package/dist/components/ReportSheet/index.js +1 -0
  54. package/dist/components/Skeleton/index.js +1 -1
  55. package/dist/components/SpeedPicker/index.d.ts +32 -0
  56. package/dist/components/SpeedPicker/index.js +1 -0
  57. package/dist/components/VideoInfo/index.d.ts +7 -3
  58. package/dist/components/VideoInfo/index.js +1 -1
  59. package/dist/components/VideoPlayer/index.js +1 -1
  60. package/dist/components/VideoSlot/index.d.ts +31 -68
  61. package/dist/components/VideoSlot/index.js +2 -1
  62. package/dist/components/VirtualSlider/index.js +1 -1
  63. package/dist/index.d.ts +40 -10
  64. package/dist/index.js +23 -13
  65. package/package.json +8 -4
  66. package/dist/CommentSheet.css-BeCrEaUG.d.ts +0 -221
  67. package/dist/chunk-2FSDVYER.js +0 -737
  68. package/dist/chunk-ECR42RKK.js +0 -571
  69. package/dist/chunk-KWHMZ6H5.js +0 -562
  70. package/dist/chunk-SZXFH334.js +0 -204
  71. package/dist/chunk-UNV3NWN6.js +0 -148
  72. package/dist/chunk-WCRDTBCZ.js +0 -357
  73. package/dist/chunk-XDIH66C4.js +0 -1519
  74. package/dist/components/VideoFeed/index.js +0 -1
@@ -0,0 +1,508 @@
1
+ import { injectComponentCSS } from './chunk-CAWE42LH.js';
2
+ import { clsx } from 'clsx';
3
+ import { memo, useState, useRef, useEffect, useCallback } from 'react';
4
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/CleanModeOverlay/CleanModeOverlay.css.ts
7
+ var CLEAN_MODE_OVERLAY_CSS = (
8
+ /* css */
9
+ `
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
11
+ CSS VARIABLES
12
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
13
+
14
+ .sv-clean-mode-container {
15
+ /* Colors */
16
+ --sv-clean-mode-bg: rgba(40, 40, 40, 0.85);
17
+ --sv-clean-mode-text: rgba(255, 255, 255, 0.95);
18
+ --sv-clean-mode-divider: rgba(255, 255, 255, 0.2);
19
+ --sv-clean-mode-progress-bg: rgba(255, 255, 255, 0.3);
20
+ --sv-clean-mode-progress-fill: rgba(255, 255, 255, 0.9);
21
+ --sv-clean-mode-progress-thumb: #ffffff;
22
+
23
+ /* Layout */
24
+ --sv-clean-mode-radius: 50px;
25
+ --sv-clean-mode-button-size: 48px;
26
+ --sv-clean-mode-progress-height: 4px;
27
+
28
+ /* Animation */
29
+ --sv-clean-mode-duration: 200ms;
30
+ --sv-clean-mode-easing: cubic-bezier(0.4, 0, 0.2, 1);
31
+ }
32
+
33
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
34
+ MAIN CONTAINER - Full width bar at bottom
35
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
36
+
37
+ .sv-clean-mode-container {
38
+ position: absolute;
39
+ bottom: 24px;
40
+ left: 16px;
41
+ right: 16px;
42
+ z-index: 80;
43
+
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 12px;
47
+ margin: 0;
48
+ padding: 0;
49
+
50
+ /* Animation */
51
+ opacity: 1;
52
+ transition: opacity var(--sv-clean-mode-duration) var(--sv-clean-mode-easing);
53
+
54
+ /* Prevent text selection */
55
+ user-select: none;
56
+ -webkit-user-select: none;
57
+ pointer-events: none;
58
+ }
59
+
60
+ .sv-clean-mode-container[data-hidden="true"] {
61
+ opacity: 0;
62
+ }
63
+
64
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
65
+ LEFT PILL - Exit button
66
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
67
+
68
+ .sv-clean-mode-left {
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ flex-shrink: 0;
73
+
74
+ width: var(--sv-clean-mode-button-size);
75
+ height: var(--sv-clean-mode-button-size);
76
+ margin: 0;
77
+ padding: 0;
78
+
79
+ background: var(--sv-clean-mode-bg);
80
+ border-radius: var(--sv-clean-mode-radius);
81
+ backdrop-filter: blur(12px);
82
+ -webkit-backdrop-filter: blur(12px);
83
+
84
+ pointer-events: auto;
85
+ }
86
+
87
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
88
+ CENTER - Progress Bar
89
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
90
+
91
+ .sv-clean-mode-center {
92
+ flex: 1;
93
+ min-width: 0;
94
+ display: flex;
95
+ align-items: center;
96
+ margin: 0;
97
+ padding: 0;
98
+
99
+ pointer-events: auto;
100
+ }
101
+
102
+ .sv-clean-mode-progress {
103
+ position: relative;
104
+ width: 100%;
105
+ height: 24px;
106
+ margin: 0;
107
+ padding: 0;
108
+ display: flex;
109
+ align-items: center;
110
+ cursor: pointer;
111
+ touch-action: none;
112
+ }
113
+
114
+ .sv-clean-mode-progress-track {
115
+ position: absolute;
116
+ left: 0;
117
+ right: 0;
118
+ height: var(--sv-clean-mode-progress-height);
119
+ margin: 0;
120
+ padding: 0;
121
+ background: var(--sv-clean-mode-progress-bg);
122
+ border-radius: calc(var(--sv-clean-mode-progress-height) / 2);
123
+ overflow: hidden;
124
+ }
125
+
126
+ .sv-clean-mode-progress-fill {
127
+ height: 100%;
128
+ margin: 0;
129
+ padding: 0;
130
+ background: var(--sv-clean-mode-progress-fill);
131
+ border-radius: inherit;
132
+ transition: width 100ms linear;
133
+ }
134
+
135
+ .sv-clean-mode-progress-thumb {
136
+ position: absolute;
137
+ width: 14px;
138
+ height: 14px;
139
+ margin: 0;
140
+ padding: 0;
141
+ background: var(--sv-clean-mode-progress-thumb);
142
+ border-radius: 50%;
143
+ transform: translateX(-50%);
144
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
145
+ opacity: 0;
146
+ transition: opacity 150ms ease;
147
+ }
148
+
149
+ .sv-clean-mode-progress:hover .sv-clean-mode-progress-thumb,
150
+ .sv-clean-mode-progress[data-dragging="true"] .sv-clean-mode-progress-thumb {
151
+ opacity: 1;
152
+ }
153
+
154
+ .sv-clean-mode-progress[data-dragging="true"] .sv-clean-mode-progress-track {
155
+ height: 6px;
156
+ }
157
+
158
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
159
+ RIGHT PILL - Play/Pause + Speed
160
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
161
+
162
+ .sv-clean-mode-right {
163
+ display: flex;
164
+ align-items: center;
165
+ flex-shrink: 0;
166
+
167
+ height: var(--sv-clean-mode-button-size);
168
+ margin: 0;
169
+ padding: 0 4px;
170
+
171
+ background: var(--sv-clean-mode-bg);
172
+ border-radius: var(--sv-clean-mode-radius);
173
+ backdrop-filter: blur(12px);
174
+ -webkit-backdrop-filter: blur(12px);
175
+
176
+ pointer-events: auto;
177
+ }
178
+
179
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
180
+ BUTTONS
181
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
182
+
183
+ .sv-clean-mode-button {
184
+ display: flex;
185
+ align-items: center;
186
+ justify-content: center;
187
+ gap: 6px;
188
+
189
+ height: 40px;
190
+ margin: 0;
191
+ padding: 0 14px;
192
+
193
+ background: transparent;
194
+ border: none;
195
+
196
+ color: var(--sv-clean-mode-text);
197
+ font-size: 15px;
198
+ font-weight: 600;
199
+ white-space: nowrap;
200
+
201
+ cursor: pointer;
202
+ transition: opacity 150ms ease;
203
+ }
204
+
205
+ .sv-clean-mode-button:active {
206
+ opacity: 0.7;
207
+ }
208
+
209
+ .sv-clean-mode-button svg {
210
+ width: 22px;
211
+ height: 22px;
212
+ margin: 0;
213
+ padding: 0;
214
+ flex-shrink: 0;
215
+ }
216
+
217
+ /* Exit button - icon only */
218
+ .sv-clean-mode-exit {
219
+ width: 40px;
220
+ height: 40px;
221
+ padding: 0;
222
+ }
223
+
224
+ .sv-clean-mode-exit svg {
225
+ width: 20px;
226
+ height: 20px;
227
+ }
228
+
229
+ /* Play/Pause button - icon only */
230
+ .sv-clean-mode-play {
231
+ width: 40px;
232
+ padding: 0;
233
+ }
234
+
235
+ /* Speed button */
236
+ .sv-clean-mode-speed {
237
+ padding: 0 16px 0 8px;
238
+ }
239
+
240
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
241
+ DIVIDER
242
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
243
+
244
+ .sv-clean-mode-divider {
245
+ width: 1px;
246
+ height: 24px;
247
+ margin: 0;
248
+ padding: 0;
249
+ background: var(--sv-clean-mode-divider);
250
+ flex-shrink: 0;
251
+ }
252
+
253
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
254
+ TAP AREA (for showing hidden bar)
255
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
256
+
257
+ .sv-clean-mode-tap-area {
258
+ position: absolute;
259
+ inset: 0;
260
+ z-index: 70;
261
+ margin: 0;
262
+ padding: 0;
263
+ cursor: pointer;
264
+ }
265
+
266
+ /* Hide tap area when bar is visible */
267
+ .sv-clean-mode-tap-area[data-visible="true"] {
268
+ pointer-events: none;
269
+ }
270
+ `
271
+ );
272
+ function injectCleanModeOverlayCSS() {
273
+ injectComponentCSS("clean-mode-overlay", CLEAN_MODE_OVERLAY_CSS, {
274
+ layered: false
275
+ // Critical component - resist global resets
276
+ });
277
+ }
278
+ var DEFAULT_HIDE_DELAY = 3e3;
279
+ var DEFAULT_SPEEDS = [0.5, 0.75, 1, 1.25, 1.5, 2];
280
+ function CloseIcon() {
281
+ return /* @__PURE__ */ jsxs(
282
+ "svg",
283
+ {
284
+ "aria-hidden": "true",
285
+ width: "20",
286
+ height: "20",
287
+ viewBox: "0 0 24 24",
288
+ fill: "none",
289
+ stroke: "currentColor",
290
+ strokeWidth: "2.5",
291
+ strokeLinecap: "round",
292
+ strokeLinejoin: "round",
293
+ children: [
294
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
295
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
296
+ ]
297
+ }
298
+ );
299
+ }
300
+ function PlayIcon() {
301
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) });
302
+ }
303
+ function PauseIcon() {
304
+ return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", children: [
305
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "4", width: "4", height: "16", rx: "1" }),
306
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "4", width: "4", height: "16", rx: "1" })
307
+ ] });
308
+ }
309
+ function formatSpeed(speed) {
310
+ return `${speed}x`;
311
+ }
312
+ function getNextSpeed(currentSpeed, speeds) {
313
+ const currentIndex = speeds.indexOf(currentSpeed);
314
+ if (currentIndex === -1) {
315
+ const closest = speeds.reduce(
316
+ (prev, curr) => Math.abs(curr - currentSpeed) < Math.abs(prev - currentSpeed) ? curr : prev
317
+ );
318
+ const closestIndex = speeds.indexOf(closest);
319
+ return speeds[(closestIndex + 1) % speeds.length] ?? speeds[0] ?? 1;
320
+ }
321
+ return speeds[(currentIndex + 1) % speeds.length] ?? speeds[0] ?? 1;
322
+ }
323
+ function CleanModeOverlayHeadlessComponent({
324
+ isActive,
325
+ isPlaying,
326
+ speed,
327
+ currentTime,
328
+ duration,
329
+ onTogglePlay,
330
+ onSpeedChange,
331
+ onSeek,
332
+ onExit,
333
+ speeds = DEFAULT_SPEEDS,
334
+ hideDelay = DEFAULT_HIDE_DELAY,
335
+ exitIcon,
336
+ playIcon,
337
+ pauseIcon,
338
+ className,
339
+ ariaLabel = "Clean mode controls"
340
+ }) {
341
+ const [isHidden, setIsHidden] = useState(false);
342
+ const [isDragging, setIsDragging] = useState(false);
343
+ const hideTimerRef = useRef(null);
344
+ const progressRef = useRef(null);
345
+ useEffect(() => {
346
+ injectCleanModeOverlayCSS();
347
+ }, []);
348
+ useEffect(() => {
349
+ if (isActive) {
350
+ setIsHidden(false);
351
+ }
352
+ }, [isActive]);
353
+ const resetHideTimer = useCallback(() => {
354
+ if (hideTimerRef.current) {
355
+ clearTimeout(hideTimerRef.current);
356
+ }
357
+ if (hideDelay > 0 && !isDragging) {
358
+ hideTimerRef.current = setTimeout(() => {
359
+ setIsHidden(true);
360
+ }, hideDelay);
361
+ }
362
+ }, [hideDelay, isDragging]);
363
+ useEffect(() => {
364
+ if (isActive && hideDelay > 0) {
365
+ resetHideTimer();
366
+ }
367
+ return () => {
368
+ if (hideTimerRef.current) {
369
+ clearTimeout(hideTimerRef.current);
370
+ }
371
+ };
372
+ }, [isActive, hideDelay, resetHideTimer]);
373
+ const handleTapArea = useCallback(() => {
374
+ if (isHidden) {
375
+ setIsHidden(false);
376
+ resetHideTimer();
377
+ }
378
+ }, [isHidden, resetHideTimer]);
379
+ const handlePlayPause = useCallback(() => {
380
+ onTogglePlay();
381
+ resetHideTimer();
382
+ }, [onTogglePlay, resetHideTimer]);
383
+ const handleSpeedClick = useCallback(() => {
384
+ const nextSpeed = getNextSpeed(speed, speeds);
385
+ onSpeedChange(nextSpeed);
386
+ resetHideTimer();
387
+ }, [speed, speeds, onSpeedChange, resetHideTimer]);
388
+ const handleExit = useCallback(() => {
389
+ if (hideTimerRef.current) {
390
+ clearTimeout(hideTimerRef.current);
391
+ }
392
+ onExit();
393
+ }, [onExit]);
394
+ const progress = duration > 0 ? currentTime / duration * 100 : 0;
395
+ const getTimeFromEvent = useCallback(
396
+ (clientX) => {
397
+ if (!progressRef.current || duration <= 0) return 0;
398
+ const rect = progressRef.current.getBoundingClientRect();
399
+ const x = clientX - rect.left;
400
+ const percent = Math.max(0, Math.min(1, x / rect.width));
401
+ return percent * duration;
402
+ },
403
+ [duration]
404
+ );
405
+ const handleProgressPointerDown = useCallback(
406
+ (e) => {
407
+ e.preventDefault();
408
+ setIsDragging(true);
409
+ const time = getTimeFromEvent(e.clientX);
410
+ onSeek(time);
411
+ if (hideTimerRef.current) {
412
+ clearTimeout(hideTimerRef.current);
413
+ }
414
+ const handlePointerMove = (moveEvent) => {
415
+ const newTime = getTimeFromEvent(moveEvent.clientX);
416
+ onSeek(newTime);
417
+ };
418
+ const handlePointerUp = () => {
419
+ setIsDragging(false);
420
+ resetHideTimer();
421
+ document.removeEventListener("pointermove", handlePointerMove);
422
+ document.removeEventListener("pointerup", handlePointerUp);
423
+ };
424
+ document.addEventListener("pointermove", handlePointerMove);
425
+ document.addEventListener("pointerup", handlePointerUp);
426
+ },
427
+ [getTimeFromEvent, onSeek, resetHideTimer]
428
+ );
429
+ if (!isActive) return null;
430
+ const isVisible = !isHidden;
431
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
432
+ isHidden && // biome-ignore lint/a11y/useKeyWithClickEvents: tap area for touch
433
+ /* @__PURE__ */ jsx(
434
+ "div",
435
+ {
436
+ className: "sv-clean-mode-tap-area",
437
+ "data-visible": isVisible,
438
+ onClick: handleTapArea,
439
+ "aria-label": "Tap to show controls"
440
+ }
441
+ ),
442
+ /* @__PURE__ */ jsxs(
443
+ "div",
444
+ {
445
+ className: clsx("sv-clean-mode-container", className),
446
+ "data-hidden": isHidden,
447
+ role: "toolbar",
448
+ "aria-label": ariaLabel,
449
+ children: [
450
+ /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-left", children: /* @__PURE__ */ jsx(
451
+ "button",
452
+ {
453
+ type: "button",
454
+ className: "sv-clean-mode-button sv-clean-mode-exit",
455
+ onClick: handleExit,
456
+ "aria-label": "Exit clean mode",
457
+ children: exitIcon ?? /* @__PURE__ */ jsx(CloseIcon, {})
458
+ }
459
+ ) }),
460
+ /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-center", children: /* @__PURE__ */ jsxs(
461
+ "div",
462
+ {
463
+ ref: progressRef,
464
+ className: "sv-clean-mode-progress",
465
+ "data-dragging": isDragging,
466
+ onPointerDown: handleProgressPointerDown,
467
+ "aria-label": "Video progress",
468
+ "aria-valuemin": 0,
469
+ "aria-valuemax": duration,
470
+ "aria-valuenow": currentTime,
471
+ children: [
472
+ /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-progress-track", children: /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-progress-fill", style: { width: `${progress}%` } }) }),
473
+ /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-progress-thumb", style: { left: `${progress}%` } })
474
+ ]
475
+ }
476
+ ) }),
477
+ /* @__PURE__ */ jsxs("div", { className: "sv-clean-mode-right", children: [
478
+ /* @__PURE__ */ jsx(
479
+ "button",
480
+ {
481
+ type: "button",
482
+ className: "sv-clean-mode-button sv-clean-mode-play",
483
+ onClick: handlePlayPause,
484
+ "aria-label": isPlaying ? "Pause" : "Play",
485
+ children: isPlaying ? pauseIcon ?? /* @__PURE__ */ jsx(PauseIcon, {}) : playIcon ?? /* @__PURE__ */ jsx(PlayIcon, {})
486
+ }
487
+ ),
488
+ /* @__PURE__ */ jsx("div", { className: "sv-clean-mode-divider", "aria-hidden": "true" }),
489
+ /* @__PURE__ */ jsx(
490
+ "button",
491
+ {
492
+ type: "button",
493
+ className: "sv-clean-mode-button sv-clean-mode-speed",
494
+ onClick: handleSpeedClick,
495
+ "aria-label": `Playback speed: ${formatSpeed(speed)}. Click to change.`,
496
+ children: /* @__PURE__ */ jsx("span", { children: formatSpeed(speed) })
497
+ }
498
+ )
499
+ ] })
500
+ ]
501
+ }
502
+ )
503
+ ] });
504
+ }
505
+ var CleanModeOverlayHeadless = memo(CleanModeOverlayHeadlessComponent);
506
+ CleanModeOverlayHeadless.displayName = "CleanModeOverlayHeadless";
507
+
508
+ export { CLEAN_MODE_OVERLAY_CSS, CleanModeOverlayHeadless, injectCleanModeOverlayCSS };