@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
@@ -1,562 +0,0 @@
1
- import { injectComponentCSS } from './chunk-RMLTPW5S.js';
2
- import { clsx } from 'clsx';
3
- import { createContext, useInsertionEffect, useMemo, useState, useContext } from 'react';
4
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
-
6
- var VideoInfoContext = createContext(void 0);
7
- function useVideoInfoContext() {
8
- const context = useContext(VideoInfoContext);
9
- if (context === void 0) {
10
- throw new Error("useVideoInfoContext must be used within a VideoInfoHeadless component");
11
- }
12
- return context;
13
- }
14
- function useOptionalVideoInfoContext() {
15
- return useContext(VideoInfoContext);
16
- }
17
- function DefaultVerifiedIcon() {
18
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "10", height: "10", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" }) });
19
- }
20
- function VideoAuthorName({
21
- name,
22
- showAtPrefix = true,
23
- showVerified = true,
24
- isVerified,
25
- verifiedIcon,
26
- onClick,
27
- className,
28
- children
29
- }) {
30
- const context = useOptionalVideoInfoContext();
31
- const authorName = name ?? context?.state.authorName;
32
- const verified = isVerified ?? context?.state.isVerified ?? false;
33
- const handleClick = onClick ?? context?.actions.openProfile;
34
- if (!authorName) {
35
- return null;
36
- }
37
- const handleKeyDown = (e) => {
38
- if ((e.key === "Enter" || e.key === " ") && handleClick) {
39
- e.preventDefault();
40
- e.stopPropagation();
41
- handleClick();
42
- }
43
- };
44
- return /* @__PURE__ */ jsx(
45
- "div",
46
- {
47
- className: clsx("sv-video-info__author", className),
48
- onClick: (e) => {
49
- e.stopPropagation();
50
- handleClick?.();
51
- },
52
- onKeyDown: handleKeyDown,
53
- role: handleClick ? "button" : void 0,
54
- tabIndex: handleClick ? 0 : void 0,
55
- "aria-label": handleClick ? `View ${authorName}'s profile` : void 0,
56
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
57
- /* @__PURE__ */ jsxs("span", { className: "sv-video-info__author-name", children: [
58
- showAtPrefix && /* @__PURE__ */ jsx("span", { className: "sv-video-info__author-prefix", children: "@" }),
59
- authorName
60
- ] }),
61
- showVerified && verified && /* @__PURE__ */ jsx("span", { className: "sv-video-info__verified-badge", "aria-label": "Verified", children: verifiedIcon ?? /* @__PURE__ */ jsx(DefaultVerifiedIcon, {}) })
62
- ] })
63
- }
64
- );
65
- }
66
- function VideoCaption({
67
- caption,
68
- maxLines = 2,
69
- expandable = false,
70
- moreText = "more",
71
- lessText = "less",
72
- className,
73
- children
74
- }) {
75
- const context = useOptionalVideoInfoContext();
76
- const [isExpanded, setIsExpanded] = useState(false);
77
- const captionText = caption ?? context?.state.caption;
78
- if (!captionText) {
79
- return null;
80
- }
81
- const lineClampClass = isExpanded ? "sv-video-info__caption--expanded" : `sv-video-info__caption--lines-${maxLines}`;
82
- const handleToggleExpand = (e) => {
83
- e.stopPropagation();
84
- setIsExpanded(!isExpanded);
85
- };
86
- return /* @__PURE__ */ jsx("div", { className: clsx("sv-video-info__caption", lineClampClass, className), children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
87
- captionText,
88
- expandable && /* @__PURE__ */ jsx(
89
- "button",
90
- {
91
- type: "button",
92
- className: "sv-video-info__caption-more",
93
- onClick: handleToggleExpand,
94
- children: isExpanded ? lessText : moreText
95
- }
96
- )
97
- ] }) });
98
- }
99
- function VideoHashtags({
100
- hashtags,
101
- clickable = true,
102
- onHashtagClick,
103
- display = "block",
104
- className,
105
- children
106
- }) {
107
- const context = useOptionalVideoInfoContext();
108
- const hashtagsArray = hashtags ?? context?.state.hashtags ?? [];
109
- const handleClick = onHashtagClick ?? context?.actions.onHashtagClick;
110
- if (hashtagsArray.length === 0) {
111
- return null;
112
- }
113
- const handleHashtagClick = (tag) => (e) => {
114
- e.stopPropagation();
115
- if (clickable && handleClick) {
116
- handleClick(tag);
117
- }
118
- };
119
- const handleKeyDown = (tag) => (e) => {
120
- if ((e.key === "Enter" || e.key === " ") && clickable && handleClick) {
121
- e.preventDefault();
122
- handleClick(tag);
123
- }
124
- };
125
- const formatTag = (tag) => tag.startsWith("#") ? tag : `#${tag}`;
126
- if (children) {
127
- return /* @__PURE__ */ jsx(Fragment, { children });
128
- }
129
- return /* @__PURE__ */ jsx(
130
- "div",
131
- {
132
- className: clsx(
133
- "sv-video-info__hashtags",
134
- display === "inline" && "sv-video-info__hashtags--inline",
135
- className
136
- ),
137
- children: hashtagsArray.map((tag) => /* @__PURE__ */ jsx(
138
- "button",
139
- {
140
- type: "button",
141
- className: clsx(
142
- "sv-video-info__hashtag",
143
- !clickable && "sv-video-info__hashtag--not-clickable"
144
- ),
145
- onClick: handleHashtagClick(tag),
146
- onKeyDown: handleKeyDown(tag),
147
- tabIndex: clickable ? 0 : -1,
148
- "aria-label": clickable ? `View hashtag ${tag}` : void 0,
149
- children: formatTag(tag)
150
- },
151
- tag
152
- ))
153
- }
154
- );
155
- }
156
-
157
- // src/components/VideoInfo/VideoInfo.css.ts
158
- var VIDEO_INFO_CSS = `
159
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
160
- * VideoInfo Container
161
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
162
-
163
- .sv-video-info {
164
- display: flex;
165
- flex-direction: column;
166
- gap: var(--sv-video-info-gap, 6px);
167
- color: var(--sv-video-info-color, #fff);
168
- font-family: var(--sv-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
169
- text-shadow: var(--sv-video-info-text-shadow, 0 1px 2px rgba(0, 0, 0, 0.5));
170
- max-width: 100%;
171
- overflow: hidden;
172
- }
173
-
174
- /* Overlay variant (on top of video) */
175
- .sv-video-info--overlay {
176
- pointer-events: none;
177
- }
178
-
179
- .sv-video-info--overlay > * {
180
- pointer-events: auto;
181
- }
182
-
183
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
184
- * Author Name
185
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
186
-
187
- .sv-video-info__author {
188
- display: flex;
189
- align-items: center;
190
- gap: var(--sv-video-info-author-gap, 6px);
191
- cursor: pointer;
192
- transition: opacity 0.15s ease;
193
- }
194
-
195
- .sv-video-info__author:hover {
196
- opacity: 0.85;
197
- }
198
-
199
- .sv-video-info__author:active {
200
- opacity: 0.7;
201
- }
202
-
203
- .sv-video-info__author-name {
204
- font-size: var(--sv-video-info-author-font-size, 16px);
205
- font-weight: var(--sv-video-info-author-font-weight, 700);
206
- line-height: 1.3;
207
- white-space: nowrap;
208
- overflow: hidden;
209
- text-overflow: ellipsis;
210
- max-width: 200px;
211
- }
212
-
213
- .sv-video-info__author-prefix {
214
- opacity: 0.95;
215
- }
216
-
217
- .sv-video-info__verified-badge {
218
- display: inline-flex;
219
- align-items: center;
220
- justify-content: center;
221
- width: var(--sv-video-info-verified-size, 14px);
222
- height: var(--sv-video-info-verified-size, 14px);
223
- background: var(--sv-video-info-verified-bg, #20d5ec);
224
- border-radius: 50%;
225
- flex-shrink: 0;
226
- }
227
-
228
- .sv-video-info__verified-badge svg,
229
- .sv-video-info__verified-badge span {
230
- font-size: 10px;
231
- color: #fff;
232
- font-weight: 700;
233
- }
234
-
235
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
236
- * Caption
237
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
238
-
239
- .sv-video-info__caption {
240
- font-size: var(--sv-video-info-caption-font-size, 14px);
241
- line-height: var(--sv-video-info-caption-line-height, 1.4);
242
- color: var(--sv-video-info-caption-color, #fff);
243
- display: -webkit-box;
244
- -webkit-box-orient: vertical;
245
- overflow: hidden;
246
- word-break: break-word;
247
- }
248
-
249
- .sv-video-info__caption--lines-1 {
250
- -webkit-line-clamp: 1;
251
- }
252
-
253
- .sv-video-info__caption--lines-2 {
254
- -webkit-line-clamp: 2;
255
- }
256
-
257
- .sv-video-info__caption--lines-3 {
258
- -webkit-line-clamp: 3;
259
- }
260
-
261
- .sv-video-info__caption--expanded {
262
- -webkit-line-clamp: unset;
263
- }
264
-
265
- /* "more" button for expandable caption */
266
- .sv-video-info__caption-more {
267
- background: none;
268
- border: none;
269
- color: var(--sv-video-info-caption-more-color, rgba(255, 255, 255, 0.7));
270
- font-size: var(--sv-video-info-caption-font-size, 14px);
271
- padding: 0;
272
- margin-left: 4px;
273
- cursor: pointer;
274
- }
275
-
276
- .sv-video-info__caption-more:hover {
277
- color: var(--sv-video-info-caption-color, #fff);
278
- }
279
-
280
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
281
- * Hashtags
282
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
283
-
284
- .sv-video-info__hashtags {
285
- display: inline-flex;
286
- flex-direction: row;
287
- flex-wrap: wrap;
288
- align-items: center;
289
- gap: var(--sv-video-info-hashtag-gap, 6px);
290
- font-size: var(--sv-video-info-hashtag-font-size, 14px);
291
- }
292
-
293
- /* Inline variant - more compact */
294
- .sv-video-info__hashtags--inline {
295
- gap: var(--sv-video-info-hashtag-gap-inline, 4px);
296
- }
297
-
298
- .sv-video-info__hashtag {
299
- display: inline-flex;
300
- color: var(--sv-video-info-hashtag-color, #fff);
301
- font-weight: var(--sv-video-info-hashtag-font-weight, 500);
302
- background: none;
303
- border: none;
304
- padding: 0;
305
- cursor: pointer;
306
- transition: opacity 0.15s ease;
307
- white-space: nowrap;
308
- }
309
-
310
- .sv-video-info__hashtag:hover {
311
- opacity: 0.8;
312
- text-decoration: underline;
313
- }
314
-
315
- .sv-video-info__hashtag--not-clickable {
316
- cursor: default;
317
- }
318
-
319
- .sv-video-info__hashtag--not-clickable:hover {
320
- opacity: 1;
321
- text-decoration: none;
322
- }
323
-
324
- /* Inline hashtags (inside caption) */
325
- .sv-video-info__caption .sv-video-info__hashtag {
326
- display: inline;
327
- }
328
-
329
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
330
- * Location
331
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
332
-
333
- .sv-video-info__location {
334
- display: flex;
335
- align-items: center;
336
- gap: var(--sv-video-info-location-gap, 4px);
337
- font-size: var(--sv-video-info-location-font-size, 13px);
338
- color: var(--sv-video-info-location-color, rgba(255, 255, 255, 0.9));
339
- cursor: pointer;
340
- transition: opacity 0.15s ease;
341
- }
342
-
343
- .sv-video-info__location:hover {
344
- opacity: 0.8;
345
- }
346
-
347
- .sv-video-info__location-icon {
348
- font-size: 14px;
349
- flex-shrink: 0;
350
- }
351
-
352
- .sv-video-info__location-text {
353
- white-space: nowrap;
354
- overflow: hidden;
355
- text-overflow: ellipsis;
356
- }
357
-
358
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
359
- * Music
360
- * \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
361
-
362
- .sv-video-info__music {
363
- display: flex;
364
- align-items: center;
365
- gap: var(--sv-video-info-music-gap, 8px);
366
- font-size: var(--sv-video-info-music-font-size, 13px);
367
- color: var(--sv-video-info-music-color, #fff);
368
- cursor: pointer;
369
- transition: opacity 0.15s ease;
370
- overflow: hidden;
371
- }
372
-
373
- .sv-video-info__music:hover {
374
- opacity: 0.8;
375
- }
376
-
377
- .sv-video-info__music-icon {
378
- font-size: 14px;
379
- flex-shrink: 0;
380
- }
381
-
382
- .sv-video-info__music-text {
383
- white-space: nowrap;
384
- overflow: hidden;
385
- text-overflow: ellipsis;
386
- /* Marquee animation for long text */
387
- }
388
-
389
- /* Marquee animation for music text */
390
- .sv-video-info__music-text--marquee {
391
- animation: sv-video-info-marquee 8s linear infinite;
392
- }
393
-
394
- @keyframes sv-video-info-marquee {
395
- 0% {
396
- transform: translateX(0);
397
- }
398
- 100% {
399
- transform: translateX(-50%);
400
- }
401
- }
402
- `;
403
- function DefaultLocationIcon() {
404
- return /* @__PURE__ */ jsx("span", { className: "sv-video-info__location-icon", children: "\u{1F4CD}" });
405
- }
406
- function VideoLocation({
407
- location,
408
- icon,
409
- onClick,
410
- className,
411
- children
412
- }) {
413
- const context = useOptionalVideoInfoContext();
414
- const locationText = location ?? context?.state.location;
415
- const handleClick = onClick ?? context?.actions.onLocationClick;
416
- if (!locationText) {
417
- return null;
418
- }
419
- const handleKeyDown = (e) => {
420
- if ((e.key === "Enter" || e.key === " ") && handleClick) {
421
- e.preventDefault();
422
- e.stopPropagation();
423
- handleClick();
424
- }
425
- };
426
- return /* @__PURE__ */ jsx(
427
- "div",
428
- {
429
- className: clsx("sv-video-info__location", className),
430
- onClick: (e) => {
431
- e.stopPropagation();
432
- handleClick?.();
433
- },
434
- onKeyDown: handleKeyDown,
435
- role: handleClick ? "button" : void 0,
436
- tabIndex: handleClick ? 0 : void 0,
437
- "aria-label": handleClick ? `View location: ${locationText}` : void 0,
438
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
439
- icon ?? /* @__PURE__ */ jsx(DefaultLocationIcon, {}),
440
- /* @__PURE__ */ jsx("span", { className: "sv-video-info__location-text", children: locationText })
441
- ] })
442
- }
443
- );
444
- }
445
- function DefaultMusicIcon() {
446
- return /* @__PURE__ */ jsx("span", { className: "sv-video-info__music-icon", children: "\u{1F3B5}" });
447
- }
448
- function VideoMusic({
449
- title,
450
- artist,
451
- icon,
452
- marquee = false,
453
- onClick,
454
- className,
455
- children
456
- }) {
457
- const context = useOptionalVideoInfoContext();
458
- const musicTitle = title ?? context?.state.music?.title;
459
- const musicArtist = artist ?? context?.state.music?.artist;
460
- const handleClick = onClick ?? context?.actions.onMusicClick;
461
- if (!musicTitle && !musicArtist) {
462
- return null;
463
- }
464
- const displayText = musicArtist ? `${musicTitle} - ${musicArtist}` : musicTitle;
465
- const handleKeyDown = (e) => {
466
- if ((e.key === "Enter" || e.key === " ") && handleClick) {
467
- e.preventDefault();
468
- e.stopPropagation();
469
- handleClick();
470
- }
471
- };
472
- return /* @__PURE__ */ jsx(
473
- "div",
474
- {
475
- className: clsx("sv-video-info__music", className),
476
- onClick: (e) => {
477
- e.stopPropagation();
478
- handleClick?.();
479
- },
480
- onKeyDown: handleKeyDown,
481
- role: handleClick ? "button" : void 0,
482
- tabIndex: handleClick ? 0 : void 0,
483
- "aria-label": handleClick ? `View sound: ${displayText}` : void 0,
484
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
485
- icon ?? /* @__PURE__ */ jsx(DefaultMusicIcon, {}),
486
- /* @__PURE__ */ jsx(
487
- "span",
488
- {
489
- className: clsx(
490
- "sv-video-info__music-text",
491
- marquee && "sv-video-info__music-text--marquee"
492
- ),
493
- children: displayText
494
- }
495
- )
496
- ] })
497
- }
498
- );
499
- }
500
- function VideoInfoHeadlessRoot({
501
- videoInfoState,
502
- videoInfoActions,
503
- overlay = false,
504
- className,
505
- children,
506
- testId
507
- }) {
508
- useInsertionEffect(() => {
509
- return injectComponentCSS("video-info", VIDEO_INFO_CSS);
510
- }, []);
511
- const contextValue = useMemo(
512
- () => ({
513
- state: videoInfoState,
514
- actions: videoInfoActions
515
- }),
516
- [videoInfoState, videoInfoActions]
517
- );
518
- const stopPropagation = (e) => {
519
- e.stopPropagation();
520
- };
521
- return /* @__PURE__ */ jsx(VideoInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
522
- "div",
523
- {
524
- className: clsx("sv-video-info", overlay && "sv-video-info--overlay", className),
525
- onClick: stopPropagation,
526
- onKeyDown: stopPropagation,
527
- onPointerDown: stopPropagation,
528
- onPointerUp: stopPropagation,
529
- onTouchStart: stopPropagation,
530
- onTouchEnd: stopPropagation,
531
- "data-testid": testId,
532
- children: children ?? // Default layout
533
- /* @__PURE__ */ jsxs(Fragment, { children: [
534
- /* @__PURE__ */ jsx(VideoAuthorName, { showAtPrefix: true, showVerified: true }),
535
- /* @__PURE__ */ jsx(VideoCaption, { maxLines: 2 }),
536
- /* @__PURE__ */ jsx(VideoHashtags, { clickable: true })
537
- ] })
538
- }
539
- ) });
540
- }
541
- function VideoInfoContent({
542
- children,
543
- className
544
- }) {
545
- return /* @__PURE__ */ jsx("div", { className: clsx("sv-video-info__content", className), children });
546
- }
547
- var VideoInfoHeadless = Object.assign(VideoInfoHeadlessRoot, {
548
- /** Author name with @ prefix and verified badge */
549
- AuthorName: VideoAuthorName,
550
- /** Video caption/title with line clamping */
551
- Caption: VideoCaption,
552
- /** Hashtags (inline or block) */
553
- Hashtags: VideoHashtags,
554
- /** Location info */
555
- Location: VideoLocation,
556
- /** Music/sound info */
557
- Music: VideoMusic,
558
- /** Content wrapper */
559
- Content: VideoInfoContent
560
- });
561
-
562
- export { VIDEO_INFO_CSS, VideoAuthorName, VideoCaption, VideoHashtags, VideoInfoContext, VideoInfoHeadless, VideoLocation, VideoMusic, useOptionalVideoInfoContext, useVideoInfoContext };