@xhub-short/ui 0.1.0-beta.8 → 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 (75) 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-UPCVSGWH.js → chunk-CAWE42LH.js} +5 -2
  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-IC2KUU4V.js +1264 -0
  17. package/dist/chunk-IWSBYOSS.js +91 -0
  18. package/dist/chunk-MFJS65C5.js +368 -0
  19. package/dist/{chunk-CXPNPSF7.js → chunk-NJXIYSDZ.js} +12 -1
  20. package/dist/{chunk-NRQXKZO3.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-OQ7P5XC7.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 +155 -3
  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 +74 -11
  64. package/dist/index.js +39 -15
  65. package/package.json +8 -4
  66. package/dist/CommentSheet.css-BD6XbpU2.d.ts +0 -207
  67. package/dist/chunk-EBAMBI3O.js +0 -571
  68. package/dist/chunk-K3CETRCY.js +0 -737
  69. package/dist/chunk-PGHLVKXS.js +0 -148
  70. package/dist/chunk-QF7O26KZ.js +0 -357
  71. package/dist/chunk-RKS7YA7Z.js +0 -562
  72. package/dist/chunk-T4RQWGRY.js +0 -1519
  73. package/dist/chunk-UXNIXHII.js +0 -2040
  74. package/dist/chunk-YWAPI7JO.js +0 -204
  75. package/dist/components/VideoFeed/index.js +0 -1
@@ -1,737 +0,0 @@
1
- import { PlusIcon } from './chunk-ANCP53F3.js';
2
- import { injectComponentCSS } from './chunk-UPCVSGWH.js';
3
- import { clsx } from 'clsx';
4
- import { createContext, useInsertionEffect, useMemo, useState, useEffect, useContext } from 'react';
5
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
-
7
- var AuthorInfoContext = createContext(null);
8
- AuthorInfoContext.displayName = "AuthorInfoContext";
9
- function useAuthorInfoContext() {
10
- const context = useContext(AuthorInfoContext);
11
- if (!context) {
12
- throw new Error(
13
- "[AuthorInfo] useAuthorInfoContext must be used within <AuthorInfoHeadless>. Make sure you wrap your component with <AuthorInfoHeadless>."
14
- );
15
- }
16
- return context;
17
- }
18
- function useOptionalAuthorInfoContext() {
19
- return useContext(AuthorInfoContext);
20
- }
21
- function DefaultCheckIcon() {
22
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", 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.41z" }) });
23
- }
24
- function DefaultUserIcon() {
25
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" }) });
26
- }
27
- var SIZE_CLASS_MAP = {
28
- small: "sv-author-info__avatar--small",
29
- large: "sv-author-info__avatar--large",
30
- default: ""
31
- };
32
- function AuthorAvatar({
33
- src,
34
- alt,
35
- size = "default",
36
- showVerified = false,
37
- verifiedIcon,
38
- onClick,
39
- className,
40
- children
41
- }) {
42
- const [imgError, setImgError] = useState(false);
43
- const context = useOptionalAuthorInfoContext();
44
- const avatarSrc = src ?? context?.author.avatar;
45
- const avatarAlt = alt ?? context?.author.name ?? "Author avatar";
46
- const isVerified = context?.author.isVerified ?? false;
47
- const handleClick = onClick ?? context?.openProfile;
48
- useEffect(() => {
49
- setImgError(false);
50
- }, [avatarSrc]);
51
- const handleImgError = () => setImgError(true);
52
- const sizeClass = SIZE_CLASS_MAP[size];
53
- const showImage = avatarSrc && !imgError;
54
- const handleKeyDown = (e) => {
55
- if ((e.key === "Enter" || e.key === " ") && handleClick) {
56
- e.preventDefault();
57
- e.stopPropagation();
58
- handleClick();
59
- }
60
- };
61
- return /* @__PURE__ */ jsxs(
62
- "div",
63
- {
64
- className: clsx("sv-author-info__avatar", sizeClass, className),
65
- onClick: (e) => {
66
- e.stopPropagation();
67
- handleClick?.();
68
- },
69
- onKeyDown: handleKeyDown,
70
- role: handleClick ? "button" : void 0,
71
- tabIndex: handleClick ? 0 : void 0,
72
- "aria-label": handleClick ? `View ${avatarAlt}'s profile` : void 0,
73
- children: [
74
- children ?? (showImage && avatarSrc ? /* @__PURE__ */ jsx(
75
- "img",
76
- {
77
- src: avatarSrc,
78
- alt: avatarAlt,
79
- className: "sv-author-info__avatar-img",
80
- loading: "lazy",
81
- onError: handleImgError
82
- }
83
- ) : /* @__PURE__ */ jsx("div", { className: "sv-author-info__avatar-placeholder", children: /* @__PURE__ */ jsx(DefaultUserIcon, {}) })),
84
- showVerified && isVerified && /* @__PURE__ */ jsx("div", { className: "sv-author-info__verified-badge", "aria-label": "Verified", children: verifiedIcon ?? /* @__PURE__ */ jsx(DefaultCheckIcon, {}) })
85
- ]
86
- }
87
- );
88
- }
89
- function AuthorDescription({
90
- description,
91
- singleLine = false,
92
- className,
93
- children
94
- }) {
95
- const context = useOptionalAuthorInfoContext();
96
- const displayDescription = description ?? context?.author.description;
97
- if (!children && !displayDescription) {
98
- return null;
99
- }
100
- return /* @__PURE__ */ jsx(
101
- "p",
102
- {
103
- className: clsx(
104
- "sv-author-info__description",
105
- singleLine && "sv-author-info__description--single-line",
106
- className
107
- ),
108
- children: children ?? displayDescription
109
- }
110
- );
111
- }
112
-
113
- // src/components/AuthorInfo/AuthorInfo.css.ts
114
- var AUTHOR_INFO_CSS = `
115
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
116
- AUTHOR INFO - Container
117
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
118
-
119
- .sv-author-info {
120
- display: flex;
121
- align-items: center;
122
- gap: var(--sv-author-gap, 12px);
123
- width: 100%;
124
- }
125
-
126
- .sv-author-info--vertical {
127
- flex-direction: column;
128
- align-items: flex-start;
129
- }
130
-
131
- .sv-author-info--horizontal {
132
- flex-direction: row;
133
- align-items: center;
134
- }
135
-
136
- .sv-author-info--compact {
137
- gap: var(--sv-author-gap-compact, 8px);
138
- }
139
-
140
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
141
- AVATAR
142
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
143
-
144
- .sv-author-info__avatar {
145
- position: relative;
146
- flex-shrink: 0;
147
- width: var(--sv-author-avatar-size, 48px);
148
- height: var(--sv-author-avatar-size, 48px);
149
- border-radius: 50%;
150
- overflow: hidden;
151
- background: var(--sv-author-avatar-bg, rgba(255, 255, 255, 0.1));
152
- cursor: pointer;
153
- transition: transform 0.15s ease;
154
- }
155
-
156
- .sv-author-info__avatar:hover {
157
- transform: scale(1.05);
158
- }
159
-
160
- .sv-author-info__avatar:active {
161
- transform: scale(0.98);
162
- }
163
-
164
- .sv-author-info__avatar-img {
165
- width: 100%;
166
- height: 100%;
167
- object-fit: cover;
168
- border-radius: 50%;
169
- }
170
-
171
- .sv-author-info__avatar-placeholder {
172
- width: 100%;
173
- height: 100%;
174
- display: flex;
175
- align-items: center;
176
- justify-content: center;
177
- background: var(--sv-author-avatar-placeholder-bg, linear-gradient(135deg, #667eea 0%, #764ba2 100%));
178
- color: var(--sv-author-avatar-placeholder-color, #fff);
179
- font-size: calc(var(--sv-author-avatar-size, 48px) * 0.4);
180
- font-weight: 600;
181
- text-transform: uppercase;
182
- }
183
-
184
- .sv-author-info__avatar-placeholder svg {
185
- width: 60%;
186
- height: 60%;
187
- opacity: 0.9;
188
- }
189
-
190
- /* Avatar sizes */
191
- .sv-author-info__avatar--small {
192
- width: var(--sv-author-avatar-size-small, 32px);
193
- height: var(--sv-author-avatar-size-small, 32px);
194
- }
195
-
196
- .sv-author-info__avatar--large {
197
- width: var(--sv-author-avatar-size-large, 64px);
198
- height: var(--sv-author-avatar-size-large, 64px);
199
- }
200
-
201
- /* Verified badge */
202
- .sv-author-info__verified-badge {
203
- position: absolute;
204
- bottom: -2px;
205
- right: -2px;
206
- width: calc(var(--sv-author-avatar-size, 48px) * 0.35);
207
- height: calc(var(--sv-author-avatar-size, 48px) * 0.35);
208
- min-width: 14px;
209
- min-height: 14px;
210
- border-radius: 50%;
211
- background: var(--sv-verified-badge-bg, #1DA1F2);
212
- display: flex;
213
- align-items: center;
214
- justify-content: center;
215
- border: 2px solid var(--sv-verified-badge-border, #000);
216
- }
217
-
218
- .sv-author-info__verified-badge svg {
219
- width: 60%;
220
- height: 60%;
221
- color: var(--sv-verified-badge-color, #fff);
222
- }
223
-
224
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
225
- INFO (Name + Description container)
226
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
227
-
228
- .sv-author-info__content {
229
- display: flex;
230
- flex-direction: column;
231
- gap: var(--sv-author-content-gap, 2px);
232
- flex: 1;
233
- min-width: 0; /* Allow text truncation */
234
- }
235
-
236
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
237
- NAME
238
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
239
-
240
- .sv-author-info__name {
241
- display: flex;
242
- align-items: center;
243
- gap: var(--sv-author-name-gap, 4px);
244
- font-size: var(--sv-author-name-size, 16px);
245
- font-weight: var(--sv-author-name-weight, 600);
246
- color: var(--sv-author-name-color, #fff);
247
- cursor: pointer;
248
- transition: opacity 0.15s ease;
249
- }
250
-
251
- .sv-author-info__name:hover {
252
- opacity: 0.8;
253
- }
254
-
255
- .sv-author-info__name-text {
256
- overflow: hidden;
257
- text-overflow: ellipsis;
258
- white-space: nowrap;
259
- }
260
-
261
- .sv-author-info__name--with-at::before {
262
- content: '@';
263
- opacity: 0.8;
264
- }
265
-
266
- .sv-author-info__name-verified {
267
- flex-shrink: 0;
268
- width: var(--sv-author-name-verified-size, 14px);
269
- height: var(--sv-author-name-verified-size, 14px);
270
- color: var(--sv-verified-badge-bg, #1DA1F2);
271
- }
272
-
273
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
274
- DESCRIPTION / BIO
275
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
276
-
277
- .sv-author-info__description {
278
- font-size: var(--sv-author-desc-size, 13px);
279
- color: var(--sv-author-desc-color, rgba(255, 255, 255, 0.7));
280
- line-height: var(--sv-author-desc-line-height, 1.4);
281
- overflow: hidden;
282
- text-overflow: ellipsis;
283
- display: -webkit-box;
284
- -webkit-line-clamp: var(--sv-author-desc-lines, 2);
285
- -webkit-box-orient: vertical;
286
- }
287
-
288
- .sv-author-info__description--single-line {
289
- -webkit-line-clamp: 1;
290
- white-space: nowrap;
291
- display: block;
292
- }
293
-
294
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
295
- FOLLOW BUTTON
296
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
297
-
298
- .sv-author-info__follow-btn {
299
- display: inline-flex;
300
- align-items: center;
301
- justify-content: center;
302
- gap: var(--sv-follow-btn-gap, 6px);
303
- padding: var(--sv-follow-btn-padding, 8px 16px);
304
- min-width: var(--sv-follow-btn-min-width, 88px);
305
- border: none;
306
- border-radius: var(--sv-follow-btn-radius, 4px);
307
- font-size: var(--sv-follow-btn-size, 14px);
308
- font-weight: var(--sv-follow-btn-weight, 600);
309
- cursor: pointer;
310
- transition: all 0.2s ease;
311
- outline: none;
312
- user-select: none;
313
- -webkit-tap-highlight-color: transparent;
314
- }
315
-
316
- /* Not following state (primary CTA) */
317
- .sv-author-info__follow-btn--default {
318
- background: var(--sv-follow-btn-bg, #fe2c55);
319
- color: var(--sv-follow-btn-color, #fff);
320
- }
321
-
322
- .sv-author-info__follow-btn--default:hover:not(:disabled) {
323
- background: var(--sv-follow-btn-bg-hover, #ff4466);
324
- transform: scale(1.02);
325
- }
326
-
327
- .sv-author-info__follow-btn--default:active:not(:disabled) {
328
- transform: scale(0.98);
329
- }
330
-
331
- /* Following state (outline) */
332
- .sv-author-info__follow-btn--following {
333
- background: var(--sv-follow-btn-following-bg, transparent);
334
- color: var(--sv-follow-btn-following-color, rgba(255, 255, 255, 0.9));
335
- border: 1px solid var(--sv-follow-btn-following-border, rgba(255, 255, 255, 0.3));
336
- }
337
-
338
- .sv-author-info__follow-btn--following:hover:not(:disabled) {
339
- background: var(--sv-follow-btn-following-bg-hover, rgba(255, 255, 255, 0.1));
340
- border-color: var(--sv-follow-btn-following-border-hover, rgba(255, 255, 255, 0.5));
341
- }
342
-
343
- /* Pending state */
344
- .sv-author-info__follow-btn--pending {
345
- opacity: 0.6;
346
- pointer-events: none;
347
- cursor: wait;
348
- }
349
-
350
- .sv-author-info__follow-btn:disabled {
351
- opacity: 0.5;
352
- cursor: not-allowed;
353
- }
354
-
355
- /* Icon in button */
356
- .sv-author-info__follow-btn-icon {
357
- width: var(--sv-follow-btn-icon-size, 16px);
358
- height: var(--sv-follow-btn-icon-size, 16px);
359
- flex-shrink: 0;
360
- }
361
-
362
- /* Loading spinner */
363
- .sv-author-info__follow-btn-spinner {
364
- width: var(--sv-follow-btn-icon-size, 16px);
365
- height: var(--sv-follow-btn-icon-size, 16px);
366
- border: 2px solid currentColor;
367
- border-top-color: transparent;
368
- border-radius: 50%;
369
- animation: sv-author-info-spin 0.6s linear infinite;
370
- }
371
-
372
- @keyframes sv-author-info-spin {
373
- from {
374
- transform: rotate(0deg);
375
- }
376
- to {
377
- transform: rotate(360deg);
378
- }
379
- }
380
-
381
- /* Button sizes */
382
- .sv-author-info__follow-btn--small {
383
- padding: var(--sv-follow-btn-padding-small, 6px 12px);
384
- font-size: var(--sv-follow-btn-size-small, 12px);
385
- min-width: var(--sv-follow-btn-min-width-small, 72px);
386
- }
387
-
388
- .sv-author-info__follow-btn--large {
389
- padding: var(--sv-follow-btn-padding-large, 10px 20px);
390
- font-size: var(--sv-follow-btn-size-large, 16px);
391
- min-width: var(--sv-follow-btn-min-width-large, 100px);
392
- }
393
-
394
- /* Icon-only button */
395
- .sv-author-info__follow-btn--icon-only {
396
- min-width: unset;
397
- padding: var(--sv-follow-btn-icon-padding, 8px);
398
- border-radius: 50%;
399
- }
400
-
401
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
402
- LAYOUT VARIANTS
403
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
404
-
405
- /* Inline variant (avatar + name inline, follow button on right) */
406
- .sv-author-info--inline {
407
- justify-content: space-between;
408
- }
409
-
410
- .sv-author-info--inline .sv-author-info__content {
411
- flex: 1;
412
- }
413
-
414
- /* Stacked variant (avatar above name) */
415
- .sv-author-info--stacked {
416
- flex-direction: column;
417
- align-items: center;
418
- text-align: center;
419
- }
420
-
421
- .sv-author-info--stacked .sv-author-info__content {
422
- align-items: center;
423
- }
424
-
425
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
426
- OVERLAY MODE (for use on video)
427
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
428
-
429
- .sv-author-info--overlay {
430
- /* Text shadow for readability on video */
431
- text-shadow: var(--sv-author-overlay-shadow, 0 1px 2px rgba(0, 0, 0, 0.5));
432
- }
433
-
434
- .sv-author-info--overlay .sv-author-info__avatar {
435
- border: 2px solid var(--sv-author-overlay-avatar-border, rgba(255, 255, 255, 0.5));
436
- }
437
-
438
- /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
439
- AVATAR-BADGE VARIANT (TikTok-style avatar with follow badge)
440
- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
441
-
442
- .sv-author-info--avatar-badge {
443
- position: relative;
444
- display: flex;
445
- flex-direction: column;
446
- align-items: center;
447
- width: auto;
448
- gap: 0;
449
- }
450
-
451
- /* Avatar in badge variant */
452
- .sv-author-info--avatar-badge .sv-author-info__avatar {
453
- width: var(--sv-avatar-badge-size, 48px);
454
- height: var(--sv-avatar-badge-size, 48px);
455
- border: 2px solid var(--sv-avatar-badge-border, #fff);
456
- }
457
-
458
- /* Follow button as overlay badge */
459
- .sv-author-info--avatar-badge .sv-author-info__follow-btn {
460
- position: absolute;
461
- bottom: var(--sv-avatar-badge-btn-bottom, -10px);
462
- left: 50%;
463
- transform: translateX(-50%);
464
- min-width: unset;
465
- width: var(--sv-avatar-badge-btn-size, 24px);
466
- height: var(--sv-avatar-badge-btn-size, 24px);
467
- padding: 0;
468
- border-radius: 50%;
469
- background: var(--sv-color-primary, #fe2c55);
470
- border: 2px solid var(--sv-bg-primary, #000);
471
- z-index: 1;
472
- }
473
-
474
- .sv-author-info--avatar-badge .sv-author-info__follow-btn:hover:not(:disabled) {
475
- transform: translateX(-50%) scale(1.1);
476
- }
477
-
478
- .sv-author-info--avatar-badge .sv-author-info__follow-btn:active:not(:disabled) {
479
- transform: translateX(-50%) scale(0.95);
480
- }
481
-
482
- /* Icon size in badge button */
483
- .sv-author-info--avatar-badge .sv-author-info__follow-btn-icon {
484
- width: var(--sv-avatar-badge-icon-size, 14px);
485
- height: var(--sv-avatar-badge-icon-size, 14px);
486
- }
487
-
488
- /* Hide button when following (TikTok behavior) */
489
- .sv-author-info--avatar-badge .sv-author-info__follow-btn--following {
490
- display: none;
491
- }
492
-
493
- /* Hide content section in badge variant */
494
- .sv-author-info--avatar-badge .sv-author-info__content {
495
- display: none;
496
- }
497
-
498
- /* Add margin bottom for action bar spacing */
499
- .sv-author-info--avatar-badge {
500
- margin-bottom: var(--sv-avatar-badge-margin, 16px);
501
- }
502
- `;
503
- function DefaultVerifiedIcon() {
504
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M22.5 12.5c0-1.58-.875-2.95-2.148-3.6.154-.435.238-.905.238-1.4 0-2.21-1.71-3.998-3.818-3.998-.47 0-.92.084-1.336.25C14.818 2.415 13.51 1.5 12 1.5s-2.816.917-3.437 2.25c-.415-.165-.866-.25-1.336-.25-2.11 0-3.818 1.79-3.818 4 0 .494.083.964.237 1.4-1.272.65-2.147 2.018-2.147 3.6 0 1.495.782 2.798 1.942 3.486-.02.17-.032.34-.032.514 0 2.21 1.708 4 3.818 4 .47 0 .92-.086 1.335-.25.62 1.334 1.926 2.25 3.437 2.25 1.512 0 2.818-.916 3.437-2.25.415.163.865.248 1.336.248 2.11 0 3.818-1.79 3.818-4 0-.174-.012-.344-.033-.513 1.158-.687 1.943-1.99 1.943-3.484zm-6.616-3.334l-4.334 6.5c-.145.217-.382.334-.625.334-.143 0-.288-.04-.416-.126l-.115-.094-2.415-2.415c-.293-.293-.293-.768 0-1.06s.768-.294 1.06 0l1.77 1.767 3.825-5.74c.23-.345.696-.436 1.04-.207.346.23.44.696.21 1.04z" }) });
505
- }
506
- function AuthorName({
507
- name,
508
- showAtPrefix = false,
509
- showVerified = false,
510
- verifiedIcon,
511
- onClick,
512
- className,
513
- children
514
- }) {
515
- const context = useOptionalAuthorInfoContext();
516
- const displayName = name ?? context?.author.name ?? "Unknown";
517
- const isVerified = context?.author.isVerified ?? false;
518
- const handleClick = onClick ?? context?.openProfile;
519
- const handleKeyDown = (e) => {
520
- if ((e.key === "Enter" || e.key === " ") && handleClick) {
521
- e.preventDefault();
522
- e.stopPropagation();
523
- handleClick();
524
- }
525
- };
526
- return /* @__PURE__ */ jsxs(
527
- "div",
528
- {
529
- className: clsx(
530
- "sv-author-info__name",
531
- showAtPrefix && "sv-author-info__name--with-at",
532
- className
533
- ),
534
- onClick: (e) => {
535
- e.stopPropagation();
536
- handleClick?.();
537
- },
538
- onKeyDown: handleKeyDown,
539
- role: handleClick ? "button" : void 0,
540
- tabIndex: handleClick ? 0 : void 0,
541
- "aria-label": handleClick ? `View ${displayName}'s profile` : void 0,
542
- children: [
543
- children ?? /* @__PURE__ */ jsx("span", { className: "sv-author-info__name-text", children: displayName }),
544
- showVerified && isVerified && /* @__PURE__ */ jsx("span", { className: "sv-author-info__name-verified", "aria-label": "Verified", children: verifiedIcon ?? /* @__PURE__ */ jsx(DefaultVerifiedIcon, {}) })
545
- ]
546
- }
547
- );
548
- }
549
- function DefaultFollowIcon() {
550
- return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
551
- /* @__PURE__ */ jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
552
- /* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "7", r: "4" }),
553
- /* @__PURE__ */ jsx("line", { x1: "20", y1: "8", x2: "20", y2: "14" }),
554
- /* @__PURE__ */ jsx("line", { x1: "23", y1: "11", x2: "17", y2: "11" })
555
- ] });
556
- }
557
- function DefaultFollowingIcon() {
558
- return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
559
- /* @__PURE__ */ jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
560
- /* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "7", r: "4" }),
561
- /* @__PURE__ */ jsx("polyline", { points: "17 11 19 13 23 9" })
562
- ] });
563
- }
564
- var SIZE_CLASS_MAP2 = {
565
- small: "sv-author-info__follow-btn--small",
566
- default: "",
567
- large: "sv-author-info__follow-btn--large"
568
- };
569
- function ButtonIcon({
570
- isPending,
571
- isFollowing,
572
- followIcon,
573
- followingIcon
574
- }) {
575
- if (isPending) {
576
- return /* @__PURE__ */ jsx("span", { className: "sv-author-info__follow-btn-spinner" });
577
- }
578
- const icon = isFollowing ? followingIcon ?? /* @__PURE__ */ jsx(DefaultFollowingIcon, {}) : followIcon ?? /* @__PURE__ */ jsx(DefaultFollowIcon, {});
579
- return /* @__PURE__ */ jsx("span", { className: "sv-author-info__follow-btn-icon", children: icon });
580
- }
581
- function FollowButton({
582
- isFollowing: isFollowingProp,
583
- isPending: isPendingProp,
584
- onClick,
585
- size = "default",
586
- iconOnly = false,
587
- followIcon,
588
- followingIcon,
589
- followText = "Follow",
590
- followingText = "Following",
591
- disabled = false,
592
- className,
593
- children,
594
- followAriaLabel = "Follow",
595
- unfollowAriaLabel = "Unfollow"
596
- }) {
597
- const context = useOptionalAuthorInfoContext();
598
- const isFollowing = isFollowingProp ?? context?.isFollowing ?? false;
599
- const isPending = isPendingProp ?? context?.isFollowPending ?? false;
600
- const handleClick = onClick ?? context?.toggleFollow;
601
- const isDisabled = disabled || isPending;
602
- const stateClass = isFollowing ? "sv-author-info__follow-btn--following" : "sv-author-info__follow-btn--default";
603
- const buttonText = isFollowing ? followingText : followText;
604
- const handleButtonClick = (e) => {
605
- e.stopPropagation();
606
- e.preventDefault();
607
- if (!isDisabled) {
608
- handleClick?.();
609
- }
610
- };
611
- const handleKeyDown = (e) => {
612
- if ((e.key === "Enter" || e.key === " ") && !isDisabled) {
613
- e.preventDefault();
614
- e.stopPropagation();
615
- handleClick?.();
616
- }
617
- };
618
- const stopPropagation = (e) => e.stopPropagation();
619
- return /* @__PURE__ */ jsx(
620
- "button",
621
- {
622
- type: "button",
623
- className: clsx(
624
- "sv-author-info__follow-btn",
625
- stateClass,
626
- isPending && "sv-author-info__follow-btn--pending",
627
- iconOnly && "sv-author-info__follow-btn--icon-only",
628
- SIZE_CLASS_MAP2[size],
629
- className
630
- ),
631
- onClick: handleButtonClick,
632
- onKeyDown: handleKeyDown,
633
- onPointerDown: stopPropagation,
634
- onPointerUp: stopPropagation,
635
- onTouchStart: stopPropagation,
636
- onTouchEnd: stopPropagation,
637
- disabled: isDisabled,
638
- "aria-pressed": isFollowing,
639
- "aria-label": isFollowing ? unfollowAriaLabel : followAriaLabel,
640
- "aria-busy": isPending,
641
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
642
- /* @__PURE__ */ jsx(
643
- ButtonIcon,
644
- {
645
- isPending,
646
- isFollowing,
647
- followIcon: followIcon ?? /* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
648
- followingIcon
649
- }
650
- ),
651
- !iconOnly && /* @__PURE__ */ jsx("span", { children: buttonText })
652
- ] })
653
- }
654
- );
655
- }
656
- var CSS_COMPONENT_ID = "author-info";
657
- function AuthorInfoContent({
658
- className,
659
- children
660
- }) {
661
- return /* @__PURE__ */ jsx("div", { className: clsx("sv-author-info__content", className), children });
662
- }
663
- function AuthorInfoHeadlessRoot({
664
- authorState,
665
- authorActions,
666
- showFollowButton = true,
667
- variant = "horizontal",
668
- overlay = false,
669
- className,
670
- children
671
- }) {
672
- useInsertionEffect(() => {
673
- return injectComponentCSS(CSS_COMPONENT_ID, AUTHOR_INFO_CSS);
674
- }, []);
675
- const contextValue = useMemo(
676
- () => ({
677
- author: authorState.author,
678
- isFollowing: authorState.isFollowing,
679
- isFollowPending: authorState.isFollowPending,
680
- toggleFollow: () => {
681
- authorActions.toggleFollow();
682
- },
683
- openProfile: () => {
684
- authorActions.openProfile();
685
- }
686
- }),
687
- [authorState, authorActions]
688
- );
689
- const variantClass = `sv-author-info--${variant}`;
690
- const stopPropagation = (e) => {
691
- e.stopPropagation();
692
- };
693
- return /* @__PURE__ */ jsx(AuthorInfoContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
694
- "div",
695
- {
696
- className: clsx(
697
- "sv-author-info",
698
- variantClass,
699
- overlay && "sv-author-info--overlay",
700
- className
701
- ),
702
- onClick: stopPropagation,
703
- onPointerDown: stopPropagation,
704
- onPointerUp: stopPropagation,
705
- onTouchStart: stopPropagation,
706
- onTouchEnd: stopPropagation,
707
- children: children ? children : variant === "avatar-badge" ? (
708
- // Default layout for avatar-badge variant
709
- /* @__PURE__ */ jsxs(Fragment, { children: [
710
- /* @__PURE__ */ jsx(AuthorAvatar, {}),
711
- showFollowButton && /* @__PURE__ */ jsx(FollowButton, { iconOnly: true })
712
- ] })
713
- ) : (
714
- // Default layout when no children provided
715
- /* @__PURE__ */ jsxs(Fragment, { children: [
716
- /* @__PURE__ */ jsx(AuthorAvatar, { showVerified: true }),
717
- /* @__PURE__ */ jsx(AuthorInfoContent, { children: /* @__PURE__ */ jsx(AuthorName, { showAtPrefix: true, showVerified: true }) }),
718
- showFollowButton && /* @__PURE__ */ jsx(FollowButton, {})
719
- ] })
720
- )
721
- }
722
- ) });
723
- }
724
- var AuthorInfoHeadless = Object.assign(AuthorInfoHeadlessRoot, {
725
- /** Avatar sub-component */
726
- Avatar: AuthorAvatar,
727
- /** Name sub-component */
728
- Name: AuthorName,
729
- /** Description/bio sub-component */
730
- Description: AuthorDescription,
731
- /** Follow button sub-component */
732
- FollowButton,
733
- /** Content wrapper for name + description */
734
- Content: AuthorInfoContent
735
- });
736
-
737
- export { AUTHOR_INFO_CSS, AuthorAvatar, AuthorDescription, AuthorInfoContext, AuthorInfoHeadless, AuthorName, FollowButton, useAuthorInfoContext, useOptionalAuthorInfoContext };