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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/CommentSheet.css-BeCrEaUG.d.ts +221 -0
  2. package/dist/{chunk-2PTMP65P.js → chunk-2FSDVYER.js} +8 -9
  3. package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
  4. package/dist/{chunk-ANGBSV7L.js → chunk-AC2IFAJR.js} +10 -5
  5. package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
  6. package/dist/chunk-AQHD6LPS.js +430 -0
  7. package/dist/{chunk-HW4LXTFT.js → chunk-CL6BS7GB.js} +7 -5
  8. package/dist/{chunk-YW23IBKF.js → chunk-ECR42RKK.js} +46 -5
  9. package/dist/chunk-EDWS2IPH.js +1 -0
  10. package/dist/chunk-FNXTPQ6L.js +2573 -0
  11. package/dist/{chunk-DHQJBXQW.js → chunk-KWHMZ6H5.js} +1 -1
  12. package/dist/{chunk-UXMA4KJZ.js → chunk-RMLTPW5S.js} +3 -2
  13. package/dist/{chunk-SSJDO24Q.js → chunk-SZXFH334.js} +1 -1
  14. package/dist/{chunk-4MN72OZH.js → chunk-UNV3NWN6.js} +4 -4
  15. package/dist/{chunk-ZZDQKP4R.js → chunk-WCRDTBCZ.js} +94 -155
  16. package/dist/{chunk-XAOEHLOX.js → chunk-XDIH66C4.js} +245 -52
  17. package/dist/components/ActionBar/index.js +1 -1
  18. package/dist/components/AuthorInfo/index.d.ts +5 -1
  19. package/dist/components/AuthorInfo/index.js +1 -1
  20. package/dist/components/BlurhashPlaceholder/index.d.ts +67 -0
  21. package/dist/components/BlurhashPlaceholder/index.js +150 -0
  22. package/dist/components/CommentSheet/index.d.ts +164 -0
  23. package/dist/components/CommentSheet/index.js +1 -0
  24. package/dist/components/ErrorBoundary/index.js +1 -1
  25. package/dist/components/OfflineIndicator/index.d.ts +56 -0
  26. package/dist/components/OfflineIndicator/index.js +151 -0
  27. package/dist/components/ProgressBar/index.d.ts +30 -2
  28. package/dist/components/ProgressBar/index.js +1 -1
  29. package/dist/components/Skeleton/index.js +1 -1
  30. package/dist/components/SubtitleDisplay/index.d.ts +94 -0
  31. package/dist/components/SubtitleDisplay/index.js +165 -0
  32. package/dist/components/VideoFeed/index.d.ts +11 -0
  33. package/dist/components/VideoFeed/index.js +1 -1
  34. package/dist/components/VideoInfo/index.js +1 -1
  35. package/dist/components/VideoPlayer/index.d.ts +14 -41
  36. package/dist/components/VideoPlayer/index.js +1 -1
  37. package/dist/components/VideoSlot/index.d.ts +124 -64
  38. package/dist/components/VideoSlot/index.js +1 -1
  39. package/dist/components/VirtualSlider/index.d.ts +339 -0
  40. package/dist/components/VirtualSlider/index.js +1 -0
  41. package/dist/components/icons/index.js +1 -1
  42. package/dist/index.d.ts +76 -93
  43. package/dist/index.js +75 -27
  44. package/package.json +53 -8
  45. package/dist/use-gesture-react.esm-3SV4QLEJ.js +0 -1893
@@ -0,0 +1,430 @@
1
+ import { injectComponentCSS } from './chunk-RMLTPW5S.js';
2
+ import { createContext, useContext, useMemo, useInsertionEffect, useRef, useState, useEffect, useCallback } from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/components/VirtualSlider/VirtualSlider.css.ts
6
+ var VIRTUAL_SLIDER_CSS = (
7
+ /* css */
8
+ `
9
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
10
+ * Container
11
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
12
+
13
+ .sv-slider {
14
+ position: relative;
15
+ width: 100%;
16
+ height: 100vh;
17
+ overflow: hidden;
18
+ background-color: var(--sv-slider-bg, #000);
19
+ touch-action: none;
20
+ -webkit-user-select: none;
21
+ user-select: none;
22
+ }
23
+
24
+ .sv-slider__container {
25
+ position: relative;
26
+ width: 100%;
27
+ height: 100%;
28
+ }
29
+
30
+ /* Transition during snap (not swiping) */
31
+ .sv-slider__container--snapping {
32
+ /* Transitions handled by individual slots */
33
+ }
34
+
35
+ /* During swipe - no transitions for immediate response */
36
+ .sv-slider__container--swiping {
37
+ /* Slots handle their own transitions */
38
+ }
39
+
40
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
41
+ * Slots
42
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
43
+
44
+ .sv-slider__slot {
45
+ position: absolute;
46
+ top: 0;
47
+ left: 0;
48
+ width: 100%;
49
+ height: 100%;
50
+ will-change: transform, opacity;
51
+ contain: layout style;
52
+ }
53
+
54
+ /* Active slot */
55
+ .sv-slider__slot--active {
56
+ z-index: 2;
57
+ }
58
+
59
+ /* Adjacent slots (before/after active) */
60
+ .sv-slider__slot--adjacent {
61
+ z-index: 1;
62
+ }
63
+
64
+ /* Smooth transition when snapping */
65
+ .sv-slider__slot--transitioning {
66
+ transition:
67
+ transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),
68
+ opacity 0.3s ease;
69
+ }
70
+
71
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
72
+ * Loading State
73
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
74
+
75
+ .sv-slider__loading {
76
+ position: absolute;
77
+ top: 0;
78
+ left: 0;
79
+ right: 0;
80
+ bottom: 0;
81
+ display: flex;
82
+ flex-direction: column;
83
+ align-items: center;
84
+ justify-content: center;
85
+ gap: 16px;
86
+ background-color: var(--sv-slider-bg, #000);
87
+ color: var(--sv-slider-text, #fff);
88
+ }
89
+
90
+ .sv-slider__loading-spinner {
91
+ width: 40px;
92
+ height: 40px;
93
+ border: 3px solid rgba(255, 255, 255, 0.2);
94
+ border-top-color: var(--sv-color-primary, #fe2c55);
95
+ border-radius: 50%;
96
+ animation: sv-slider-spin 0.8s linear infinite;
97
+ }
98
+
99
+ @keyframes sv-slider-spin {
100
+ to {
101
+ transform: rotate(360deg);
102
+ }
103
+ }
104
+
105
+ .sv-slider__loading-text {
106
+ font-size: 14px;
107
+ color: var(--sv-slider-text-muted, rgba(255, 255, 255, 0.7));
108
+ }
109
+
110
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
111
+ * Empty State
112
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
113
+
114
+ .sv-slider__empty {
115
+ position: absolute;
116
+ top: 0;
117
+ left: 0;
118
+ right: 0;
119
+ bottom: 0;
120
+ display: flex;
121
+ flex-direction: column;
122
+ align-items: center;
123
+ justify-content: center;
124
+ gap: 12px;
125
+ background-color: var(--sv-slider-bg, #000);
126
+ color: var(--sv-slider-text, #fff);
127
+ }
128
+
129
+ .sv-slider__empty-icon {
130
+ font-size: 48px;
131
+ opacity: 0.5;
132
+ }
133
+
134
+ .sv-slider__empty-text {
135
+ font-size: 16px;
136
+ color: var(--sv-slider-text-muted, rgba(255, 255, 255, 0.7));
137
+ }
138
+
139
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
140
+ * End of List
141
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
142
+
143
+ .sv-slider__end {
144
+ position: absolute;
145
+ bottom: var(--sv-safe-area-bottom, 20px);
146
+ left: 0;
147
+ right: 0;
148
+ text-align: center;
149
+ padding: 12px 16px;
150
+ font-size: 14px;
151
+ color: var(--sv-slider-text-muted, rgba(255, 255, 255, 0.6));
152
+ pointer-events: none;
153
+ z-index: 10;
154
+ }
155
+
156
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
157
+ * CSS Variables Reference
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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
159
+ *
160
+ * --sv-slider-bg: Background color (default: #000)
161
+ * --sv-slider-text: Text color (default: #fff)
162
+ * --sv-slider-text-muted: Muted text color (default: rgba(255,255,255,0.7))
163
+ * --sv-color-primary: Primary accent color (default: #fe2c55)
164
+ * --sv-safe-area-bottom: Bottom safe area for notched devices
165
+ *
166
+ * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
167
+ `
168
+ );
169
+ var VirtualSliderContext = createContext(null);
170
+ VirtualSliderContext.displayName = "VirtualSliderContext";
171
+ function useVirtualSliderContext() {
172
+ const context = useContext(VirtualSliderContext);
173
+ if (!context) {
174
+ throw new Error("useVirtualSliderContext must be used within a VirtualSlider");
175
+ }
176
+ return context;
177
+ }
178
+ function useOptionalVirtualSliderContext() {
179
+ return useContext(VirtualSliderContext);
180
+ }
181
+ function useSliderActiveIndex() {
182
+ const context = useVirtualSliderContext();
183
+ return context.activeIndex;
184
+ }
185
+ function useSliderIsSwiping() {
186
+ const context = useVirtualSliderContext();
187
+ return context.isSwiping;
188
+ }
189
+
190
+ // src/components/VirtualSlider/constants.ts
191
+ var SLIDER_CLASS = "sv-slider";
192
+ var SLIDER_CONTAINER_CLASS = "sv-slider__container";
193
+ var SLIDER_SLOT_CLASS = "sv-slider__slot";
194
+ var SLIDER_SLOT_ACTIVE_CLASS = "sv-slider__slot--active";
195
+ var SLIDER_SLOT_ADJACENT_CLASS = "sv-slider__slot--adjacent";
196
+ var SLIDER_SLOT_TRANSITIONING_CLASS = "sv-slider__slot--transitioning";
197
+ var SLIDER_CONTAINER_SWIPING_CLASS = "sv-slider__container--swiping";
198
+ var SLIDER_CONTAINER_SNAPPING_CLASS = "sv-slider__container--snapping";
199
+ var SLOT_INDEX_ATTR = "data-slot-index";
200
+ var SLOT_INDEX_DATASET_KEY = "slotIndex";
201
+ var SLOT_ACTIVE_ATTR = "data-slot-active";
202
+ var SLOT_ACTIVE_DATASET_KEY = "slotActive";
203
+ var DEFAULT_BUFFER_SIZE = 1;
204
+ var DEFAULT_END_REACHED_THRESHOLD = 2;
205
+ var DEFAULT_LOADING_TEXT = "Loading...";
206
+ var DEFAULT_EMPTY_TEXT = "No items";
207
+ var DEFAULT_END_TEXT = "You've reached the end";
208
+ function useSliderPosition(options) {
209
+ const {
210
+ totalCount,
211
+ activeIndex,
212
+ containerHeight,
213
+ dragOffset,
214
+ isSwiping,
215
+ isResizing = false,
216
+ bufferSize = 1
217
+ } = options;
218
+ return useMemo(() => {
219
+ if (totalCount === 0) {
220
+ return {
221
+ slots: [],
222
+ scrollOffset: 0,
223
+ isAtStart: true,
224
+ isAtLastIndex: true,
225
+ clampedActiveIndex: 0
226
+ };
227
+ }
228
+ const clampedActiveIndex = Math.max(0, Math.min(totalCount - 1, activeIndex));
229
+ const slots = [];
230
+ const startIndex = Math.max(0, clampedActiveIndex - bufferSize);
231
+ const endIndex = Math.min(totalCount - 1, clampedActiveIndex + bufferSize);
232
+ const baseOffset = -clampedActiveIndex * containerHeight;
233
+ const scrollOffset = baseOffset + dragOffset;
234
+ for (let i = startIndex; i <= endIndex; i++) {
235
+ const signedDistance = i - clampedActiveIndex;
236
+ const distance = Math.abs(signedDistance);
237
+ const isActive = i === clampedActiveIndex;
238
+ const top = i * containerHeight;
239
+ const transform = `translateY(${top + scrollOffset}px)`;
240
+ let opacity = 1;
241
+ if (!isActive && !isResizing) {
242
+ opacity = isSwiping ? 0.7 : 0.3;
243
+ }
244
+ slots.push({
245
+ index: i,
246
+ top,
247
+ isActive,
248
+ distance,
249
+ signedDistance,
250
+ transform,
251
+ opacity
252
+ });
253
+ }
254
+ return {
255
+ slots,
256
+ scrollOffset,
257
+ isAtStart: clampedActiveIndex === 0,
258
+ isAtLastIndex: clampedActiveIndex >= totalCount - 1,
259
+ clampedActiveIndex
260
+ };
261
+ }, [totalCount, activeIndex, containerHeight, dragOffset, isSwiping, isResizing, bufferSize]);
262
+ }
263
+ function getSlotIndexFromPosition(yPosition, containerHeight, totalCount) {
264
+ if (totalCount === 0 || containerHeight === 0) {
265
+ return 0;
266
+ }
267
+ const rawIndex = Math.round(-yPosition / containerHeight);
268
+ return Math.max(0, Math.min(totalCount - 1, rawIndex));
269
+ }
270
+ function DefaultLoading({ text = DEFAULT_LOADING_TEXT }) {
271
+ return /* @__PURE__ */ jsxs("div", { className: "sv-slider__loading", children: [
272
+ /* @__PURE__ */ jsx("div", { className: "sv-slider__loading-spinner" }),
273
+ /* @__PURE__ */ jsx("span", { className: "sv-slider__loading-text", children: text })
274
+ ] });
275
+ }
276
+ function DefaultEmpty({ text = DEFAULT_EMPTY_TEXT }) {
277
+ return /* @__PURE__ */ jsxs("div", { className: "sv-slider__empty", children: [
278
+ /* @__PURE__ */ jsx("span", { className: "sv-slider__empty-icon", children: "\u{1F4ED}" }),
279
+ /* @__PURE__ */ jsx("span", { className: "sv-slider__empty-text", children: text })
280
+ ] });
281
+ }
282
+ function DefaultEnd({ text = DEFAULT_END_TEXT }) {
283
+ return /* @__PURE__ */ jsx("div", { className: "sv-slider__end", children: text });
284
+ }
285
+ function VirtualSlider({
286
+ // Required
287
+ items,
288
+ keyExtractor,
289
+ renderItem,
290
+ // Swipe state
291
+ activeIndex,
292
+ isSwiping,
293
+ dragOffset,
294
+ goToIndex,
295
+ // Callbacks
296
+ onIndexChange,
297
+ onEndReached,
298
+ endReachedThreshold = DEFAULT_END_REACHED_THRESHOLD,
299
+ bufferSize = DEFAULT_BUFFER_SIZE,
300
+ // Loading states
301
+ isLoading = false,
302
+ hasMore = true,
303
+ // Custom UI
304
+ loadingComponent,
305
+ emptyComponent,
306
+ endComponent,
307
+ loadingText,
308
+ emptyText,
309
+ endText,
310
+ // Styling
311
+ height,
312
+ className,
313
+ disableInlineTransforms = false,
314
+ testId
315
+ }) {
316
+ useInsertionEffect(() => {
317
+ return injectComponentCSS("virtual-slider", VIRTUAL_SLIDER_CSS);
318
+ }, []);
319
+ const containerRef = useRef(null);
320
+ const prevActiveIndexRef = useRef(activeIndex);
321
+ const [containerHeight, setContainerHeight] = useState(
322
+ typeof window !== "undefined" ? window.innerHeight : 800
323
+ );
324
+ useEffect(() => {
325
+ const container = containerRef.current;
326
+ if (!container) return;
327
+ const updateHeight = () => {
328
+ const rect = container.getBoundingClientRect();
329
+ if (rect.height > 0) {
330
+ setContainerHeight(rect.height);
331
+ }
332
+ };
333
+ updateHeight();
334
+ const resizeObserver = new ResizeObserver(updateHeight);
335
+ resizeObserver.observe(container);
336
+ return () => resizeObserver.disconnect();
337
+ }, []);
338
+ const { slots, isAtLastIndex } = useSliderPosition({
339
+ totalCount: items.length,
340
+ activeIndex,
341
+ containerHeight,
342
+ dragOffset,
343
+ isSwiping,
344
+ bufferSize
345
+ });
346
+ useEffect(() => {
347
+ if (activeIndex !== prevActiveIndexRef.current) {
348
+ prevActiveIndexRef.current = activeIndex;
349
+ onIndexChange?.(activeIndex);
350
+ }
351
+ }, [activeIndex, onIndexChange]);
352
+ useEffect(() => {
353
+ if (items.length === 0) return;
354
+ const remainingItems = items.length - 1 - activeIndex;
355
+ if (remainingItems <= endReachedThreshold && hasMore && !isLoading) {
356
+ onEndReached?.();
357
+ }
358
+ }, [activeIndex, items.length, endReachedThreshold, hasMore, isLoading, onEndReached]);
359
+ const contextValue = useMemo(
360
+ () => ({
361
+ items,
362
+ activeIndex,
363
+ isSwiping,
364
+ dragOffset,
365
+ containerHeight,
366
+ goToIndex,
367
+ totalCount: items.length
368
+ }),
369
+ [items, activeIndex, isSwiping, dragOffset, containerHeight, goToIndex]
370
+ );
371
+ const buildSlotClassName = useCallback(
372
+ (isActive) => {
373
+ const classes = [SLIDER_SLOT_CLASS];
374
+ if (isActive) {
375
+ classes.push(SLIDER_SLOT_ACTIVE_CLASS);
376
+ } else {
377
+ classes.push(SLIDER_SLOT_ADJACENT_CLASS);
378
+ }
379
+ if (!isSwiping) {
380
+ classes.push(SLIDER_SLOT_TRANSITIONING_CLASS);
381
+ }
382
+ return classes.join(" ");
383
+ },
384
+ [isSwiping]
385
+ );
386
+ const buildContainerClassName = useCallback(() => {
387
+ const classes = [SLIDER_CONTAINER_CLASS];
388
+ if (isSwiping) {
389
+ classes.push(SLIDER_CONTAINER_SWIPING_CLASS);
390
+ } else {
391
+ classes.push(SLIDER_CONTAINER_SNAPPING_CLASS);
392
+ }
393
+ return classes.join(" ");
394
+ }, [isSwiping]);
395
+ const rootClassName = [SLIDER_CLASS, className].filter(Boolean).join(" ");
396
+ const rootStyle = height ? { height: typeof height === "number" ? `${height}px` : height } : void 0;
397
+ if (isLoading && items.length === 0) {
398
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: rootClassName, style: rootStyle, "data-testid": testId, children: loadingComponent ?? /* @__PURE__ */ jsx(DefaultLoading, { text: loadingText }) });
399
+ }
400
+ if (!isLoading && items.length === 0) {
401
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: rootClassName, style: rootStyle, "data-testid": testId, children: emptyComponent ?? /* @__PURE__ */ jsx(DefaultEmpty, { text: emptyText }) });
402
+ }
403
+ const showEndIndicator = isAtLastIndex && !hasMore && !isLoading;
404
+ return /* @__PURE__ */ jsx(VirtualSliderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs("div", { ref: containerRef, className: rootClassName, style: rootStyle, "data-testid": testId, children: [
405
+ /* @__PURE__ */ jsx("div", { className: buildContainerClassName(), children: slots.map((slot) => {
406
+ const item = items[slot.index];
407
+ if (item === void 0) return null;
408
+ const key = keyExtractor(item, slot.index);
409
+ const slotStyle = disableInlineTransforms ? void 0 : {
410
+ transform: slot.transform,
411
+ opacity: slot.opacity
412
+ };
413
+ return /* @__PURE__ */ jsx(
414
+ "div",
415
+ {
416
+ className: buildSlotClassName(slot.isActive),
417
+ style: slotStyle,
418
+ ...{ [SLOT_INDEX_ATTR]: slot.index },
419
+ ...{ [SLOT_ACTIVE_ATTR]: slot.isActive ? "true" : "false" },
420
+ children: renderItem(item, slot.index, slot.isActive)
421
+ },
422
+ key
423
+ );
424
+ }) }),
425
+ showEndIndicator && (endComponent ?? /* @__PURE__ */ jsx(DefaultEnd, { text: endText }))
426
+ ] }) });
427
+ }
428
+ VirtualSlider.displayName = "VirtualSlider";
429
+
430
+ export { DEFAULT_BUFFER_SIZE, DEFAULT_EMPTY_TEXT, DEFAULT_END_REACHED_THRESHOLD, DEFAULT_END_TEXT, DEFAULT_LOADING_TEXT, SLIDER_CLASS, SLIDER_CONTAINER_CLASS, SLIDER_CONTAINER_SNAPPING_CLASS, SLIDER_CONTAINER_SWIPING_CLASS, SLIDER_SLOT_ACTIVE_CLASS, SLIDER_SLOT_ADJACENT_CLASS, SLIDER_SLOT_CLASS, SLIDER_SLOT_TRANSITIONING_CLASS, SLOT_ACTIVE_ATTR, SLOT_ACTIVE_DATASET_KEY, SLOT_INDEX_ATTR, SLOT_INDEX_DATASET_KEY, VIRTUAL_SLIDER_CSS, VirtualSlider, VirtualSliderContext, getSlotIndexFromPosition, useOptionalVirtualSliderContext, useSliderActiveIndex, useSliderIsSwiping, useSliderPosition, useVirtualSliderContext };
@@ -1,6 +1,6 @@
1
- import { cn } from './chunk-WKX2WBVO.js';
2
- import { injectComponentCSS } from './chunk-UXMA4KJZ.js';
3
- import { useRef, useCallback, useEffect, useState, useInsertionEffect, useMemo } from 'react';
1
+ import { clsx2 } from './chunk-EDWS2IPH.js';
2
+ import { injectComponentCSS } from './chunk-RMLTPW5S.js';
3
+ import { memo, useInsertionEffect, useCallback, useMemo, useRef, useState, useEffect } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  // src/components/VideoPlayer/VideoPlayer.css.ts
@@ -35,6 +35,7 @@ var VIDEO_PLAYER_CSS = (
35
35
  align-items: center;
36
36
  justify-content: center;
37
37
  z-index: var(--sv-player-video-z);
38
+ background: var(--sv-bg-primary, #000);
38
39
  }
39
40
 
40
41
  /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
@@ -920,7 +921,7 @@ function getMediaErrorMessage(code) {
920
921
  return "Unknown video error";
921
922
  }
922
923
  }
923
- function VideoPlayerHeadless({
924
+ function VideoPlayerHeadlessBase({
924
925
  src,
925
926
  type,
926
927
  poster,
@@ -1021,7 +1022,7 @@ function VideoPlayerHeadless({
1021
1022
  return /* @__PURE__ */ jsxs(
1022
1023
  "div",
1023
1024
  {
1024
- className: cn(PLAYER_CLASS, stateClasses, className),
1025
+ className: clsx2(PLAYER_CLASS, stateClasses, className),
1025
1026
  ...{ [VIDEO_TYPE_ATTR]: type },
1026
1027
  ...{ [PLAYBACK_STATE_ATTR]: playbackState },
1027
1028
  style: {
@@ -1118,6 +1119,7 @@ function getUserFriendlyErrorMessage(message) {
1118
1119
  }
1119
1120
  return "Failed to load video. Please try again.";
1120
1121
  }
1122
+ var VideoPlayerHeadless = memo(VideoPlayerHeadlessBase);
1121
1123
  VideoPlayerHeadless.displayName = "VideoPlayerHeadless";
1122
1124
 
1123
1125
  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, createFirstFrameCache, firstFrameCache, useAutoFirstFrameCapture, useFirstFrameCapture, useVideoElement };
@@ -1,6 +1,6 @@
1
- import { cn } from './chunk-WKX2WBVO.js';
2
- import { injectComponentCSS } from './chunk-UXMA4KJZ.js';
3
- import { useInsertionEffect, useMemo, useEffect, useCallback, useRef, useState } from 'react';
1
+ import { clsx2 } from './chunk-EDWS2IPH.js';
2
+ import { injectComponentCSS } from './chunk-RMLTPW5S.js';
3
+ import { memo, useInsertionEffect, useMemo, useEffect, useCallback, useRef, useState } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  // src/components/ProgressBar/ProgressBar.css.ts
@@ -244,6 +244,40 @@ var PROGRESS_BAR_CSS = `
244
244
  display: none;
245
245
  }
246
246
 
247
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
248
+ * Auto-hide Variant
249
+ * Shows progress bar only when video is paused or user is seeking/hovering
250
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
251
+
252
+ .sv-progress-bar--auto-hide {
253
+ /* Smooth transition for show/hide */
254
+ transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease;
255
+ opacity: 1;
256
+ visibility: visible;
257
+ transform: translateY(0);
258
+ }
259
+
260
+ .sv-progress-bar--auto-hide.sv-progress-bar--hidden {
261
+ opacity: 0;
262
+ visibility: hidden;
263
+ transform: translateY(8px);
264
+ pointer-events: none;
265
+ }
266
+
267
+ /* Show on hover even when auto-hide is enabled */
268
+ .sv-progress-bar--auto-hide:hover {
269
+ opacity: 1;
270
+ visibility: visible;
271
+ transform: translateY(0);
272
+ }
273
+
274
+ /* Always show when seeking */
275
+ .sv-progress-bar--auto-hide.sv-progress-bar--seeking {
276
+ opacity: 1;
277
+ visibility: visible;
278
+ transform: translateY(0);
279
+ }
280
+
247
281
  /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
248
282
  * Reduced Motion (Accessibility)
249
283
  * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
@@ -379,7 +413,7 @@ function useSeekHandlers({
379
413
  handlePointerLeave
380
414
  };
381
415
  }
382
- function ProgressBarHeadless({
416
+ function ProgressBarHeadlessBase({
383
417
  currentTime,
384
418
  duration,
385
419
  buffered = 0,
@@ -391,6 +425,8 @@ function ProgressBarHeadless({
391
425
  showTime = false,
392
426
  showTooltip,
393
427
  minimal = false,
428
+ autoHide = true,
429
+ visible,
394
430
  fillRef: externalFillRef,
395
431
  bufferedRef: externalBufferedRef,
396
432
  handleRef: externalHandleRef,
@@ -440,14 +476,17 @@ function ProgressBarHeadless({
440
476
  const stopBubble = useCallback((e) => {
441
477
  e.stopPropagation();
442
478
  }, []);
479
+ const isHidden = visible !== void 0 ? !visible : autoHide && !isSeeking && hoverTime === null;
443
480
  return /* @__PURE__ */ jsxs(
444
481
  "div",
445
482
  {
446
- className: cn(
483
+ className: clsx2(
447
484
  CSS_PREFIX,
448
485
  !isSeekable && `${CSS_PREFIX}--disabled`,
449
486
  isSeeking && `${CSS_PREFIX}--seeking`,
450
487
  minimal && `${CSS_PREFIX}--minimal`,
488
+ autoHide && `${CSS_PREFIX}--auto-hide`,
489
+ isHidden && `${CSS_PREFIX}--hidden`,
451
490
  className
452
491
  ),
453
492
  onClick: stopBubble,
@@ -526,5 +565,7 @@ function ProgressBarHeadless({
526
565
  }
527
566
  );
528
567
  }
568
+ var ProgressBarHeadless = memo(ProgressBarHeadlessBase);
569
+ ProgressBarHeadless.displayName = "ProgressBarHeadless";
529
570
 
530
571
  export { PROGRESS_BAR_CSS, ProgressBarHeadless, calculateProgress, formatTime };
@@ -0,0 +1 @@
1
+ export { clsx, clsx as clsx2 } from 'clsx';