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

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 (76) hide show
  1. package/dist/CommentSheet.css-DyEc3Sro.d.ts +217 -0
  2. package/dist/VideoSlotPlayIndicator-DPs8Xt5C.d.ts +51 -0
  3. package/dist/chunk-3OB3OVYR.js +349 -0
  4. package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
  5. package/dist/chunk-4RIMQOBR.js +58 -0
  6. package/dist/chunk-4TUBNA2X.js +180 -0
  7. package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
  8. package/dist/{chunk-UXMA4KJZ.js → chunk-CAWE42LH.js} +5 -3
  9. package/dist/{chunk-ANGBSV7L.js → chunk-CIIZ3IHV.js} +10 -5
  10. package/dist/chunk-DR7KR7OT.js +103 -0
  11. package/dist/chunk-DXLCQ4FH.js +102 -0
  12. package/dist/chunk-EDWS2IPH.js +1 -0
  13. package/dist/chunk-FR7UQSZP.js +570 -0
  14. package/dist/chunk-IWSBYOSS.js +91 -0
  15. package/dist/chunk-JEY6R4KJ.js +334 -0
  16. package/dist/chunk-KMJ3PQ7M.js +1262 -0
  17. package/dist/chunk-MFJS65C5.js +368 -0
  18. package/dist/{chunk-HW4LXTFT.js → chunk-OM4L7RE5.js} +18 -6
  19. package/dist/chunk-PBIH2F2Q.js +344 -0
  20. package/dist/chunk-PJ4NMVMY.js +326 -0
  21. package/dist/chunk-Q6MG7AVG.js +531 -0
  22. package/dist/chunk-QCKVF2DR.js +713 -0
  23. package/dist/chunk-QCRRF76W.js +75 -0
  24. package/dist/chunk-QUEJHA24.js +508 -0
  25. package/dist/chunk-VXW7AOGM.js +285 -0
  26. package/dist/chunk-YB7AXTX7.js +430 -0
  27. package/dist/chunk-ZGWSJ6Z5.js +601 -0
  28. package/dist/components/ActionBar/index.js +1 -1
  29. package/dist/components/AdvanceMenu/index.d.ts +78 -0
  30. package/dist/components/AdvanceMenu/index.js +1 -0
  31. package/dist/components/AuthorInfo/index.d.ts +5 -1
  32. package/dist/components/AuthorInfo/index.js +1 -1
  33. package/dist/components/BottomSheet/index.d.ts +82 -0
  34. package/dist/components/BottomSheet/index.js +1 -0
  35. package/dist/components/CleanModeOverlay/index.d.ts +60 -0
  36. package/dist/components/CleanModeOverlay/index.js +1 -0
  37. package/dist/components/CommentSheet/index.d.ts +164 -0
  38. package/dist/components/CommentSheet/index.js +1 -0
  39. package/dist/components/DetailView/index.d.ts +311 -0
  40. package/dist/components/DetailView/index.js +1 -0
  41. package/dist/components/ErrorBoundary/index.js +1 -1
  42. package/dist/components/ImageCarousel/index.d.ts +50 -0
  43. package/dist/components/ImageCarousel/index.js +1 -0
  44. package/dist/components/ImagePostSlot/index.d.ts +207 -0
  45. package/dist/components/ImagePostSlot/index.js +1 -0
  46. package/dist/components/ProgressBar/index.d.ts +30 -2
  47. package/dist/components/ProgressBar/index.js +1 -1
  48. package/dist/components/QualityPicker/index.d.ts +35 -0
  49. package/dist/components/QualityPicker/index.js +1 -0
  50. package/dist/components/ReportSheet/index.d.ts +68 -0
  51. package/dist/components/ReportSheet/index.js +1 -0
  52. package/dist/components/Skeleton/index.js +1 -1
  53. package/dist/components/SpeedPicker/index.d.ts +32 -0
  54. package/dist/components/SpeedPicker/index.js +1 -0
  55. package/dist/components/VideoFeed/index.d.ts +12 -1
  56. package/dist/components/VideoFeed/index.js +1 -1
  57. package/dist/components/VideoInfo/index.d.ts +4 -2
  58. package/dist/components/VideoInfo/index.js +1 -1
  59. package/dist/components/VideoPlayer/index.d.ts +14 -41
  60. package/dist/components/VideoPlayer/index.js +1 -1
  61. package/dist/components/VideoSlot/index.d.ts +84 -65
  62. package/dist/components/VideoSlot/index.js +2 -1
  63. package/dist/components/VirtualSlider/index.d.ts +339 -0
  64. package/dist/components/VirtualSlider/index.js +1 -0
  65. package/dist/components/icons/index.js +1 -1
  66. package/dist/index.d.ts +107 -95
  67. package/dist/index.js +84 -27
  68. package/package.json +51 -7
  69. package/dist/chunk-2PTMP65P.js +0 -738
  70. package/dist/chunk-4MN72OZH.js +0 -148
  71. package/dist/chunk-DHQJBXQW.js +0 -562
  72. package/dist/chunk-SSJDO24Q.js +0 -204
  73. package/dist/chunk-XAOEHLOX.js +0 -1326
  74. package/dist/chunk-YW23IBKF.js +0 -530
  75. package/dist/chunk-ZZDQKP4R.js +0 -418
  76. package/dist/use-gesture-react.esm-3SV4QLEJ.js +0 -1893
@@ -0,0 +1,1262 @@
1
+ import { useBottomSheetContext, BottomSheetHeadless } from './chunk-PJ4NMVMY.js';
2
+ import { clsx } from 'clsx';
3
+ import { createContext, memo, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ var CommentSheetContext = createContext(void 0);
7
+ function useCommentSheetContext() {
8
+ const context = useContext(CommentSheetContext);
9
+ if (!context) {
10
+ throw new Error("useCommentSheetContext must be used within <CommentSheetHeadless>");
11
+ }
12
+ return context;
13
+ }
14
+ function useOptionalCommentSheetContext() {
15
+ return useContext(CommentSheetContext);
16
+ }
17
+ function ImageIcon({ className }) {
18
+ return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", className, viewBox: "0 0 20 20", fill: "none", children: [
19
+ /* @__PURE__ */ jsx(
20
+ "rect",
21
+ {
22
+ x: "2",
23
+ y: "4",
24
+ width: "16",
25
+ height: "12",
26
+ rx: "2",
27
+ stroke: "#164d8e",
28
+ strokeWidth: "1.5",
29
+ fill: "none"
30
+ }
31
+ ),
32
+ /* @__PURE__ */ jsx(
33
+ "path",
34
+ {
35
+ d: "M2 13l4-4 3 3 5-5 4 4",
36
+ stroke: "#164d8e",
37
+ strokeWidth: "1.5",
38
+ strokeLinecap: "round",
39
+ strokeLinejoin: "round",
40
+ fill: "none"
41
+ }
42
+ ),
43
+ /* @__PURE__ */ jsx("circle", { cx: "14", cy: "8", r: "1.5", fill: "#9fc6e9" })
44
+ ] });
45
+ }
46
+ function EmojiIcon({ className }) {
47
+ return /* @__PURE__ */ jsxs(
48
+ "svg",
49
+ {
50
+ "aria-hidden": "true",
51
+ className,
52
+ viewBox: "0 0 24 24",
53
+ fill: "none",
54
+ stroke: "currentColor",
55
+ strokeWidth: "1.5",
56
+ children: [
57
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
58
+ /* @__PURE__ */ jsx("path", { d: "M8 14s1.5 2 4 2 4-2 4-2", strokeLinecap: "round" }),
59
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "9.01", y2: "9", strokeWidth: "2", strokeLinecap: "round" }),
60
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "15.01", y2: "9", strokeWidth: "2", strokeLinecap: "round" })
61
+ ]
62
+ }
63
+ );
64
+ }
65
+ function CloseIcon({ className }) {
66
+ return /* @__PURE__ */ jsxs(
67
+ "svg",
68
+ {
69
+ className,
70
+ viewBox: "0 0 24 24",
71
+ fill: "none",
72
+ stroke: "currentColor",
73
+ strokeWidth: "2",
74
+ "aria-hidden": "true",
75
+ focusable: "false",
76
+ children: [
77
+ /* @__PURE__ */ jsx("title", { children: "Close" }),
78
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
79
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
80
+ ]
81
+ }
82
+ );
83
+ }
84
+ var DEFAULT_EMOJIS = ["\u{1F600}", "\u{1F602}", "\u{1F60D}", "\u{1F525}", "\u{1F44D}", "\u{1F4AF}", "\u2764\uFE0F", "\u{1F622}"];
85
+ var CommentInput = memo(function CommentInput2({
86
+ placeholder = "Add a comment...",
87
+ emojis = DEFAULT_EMOJIS,
88
+ maxLength = 500,
89
+ className,
90
+ onSubmitSuccess,
91
+ onMediaClick,
92
+ replyingToText = "Replying to",
93
+ replyPlaceholderTemplate = "Reply to @{name}...",
94
+ cancelReplyAriaLabel = "Cancel reply",
95
+ addMediaAriaLabel = "Add media",
96
+ submitAriaLabel = "Submit comment",
97
+ emojiAriaLabel = "Open emoji",
98
+ addEmojiAriaLabel = "Add {emoji}"
99
+ }) {
100
+ const { actions, state, replyTarget, setReplyTarget } = useCommentSheetContext();
101
+ const [text, setText] = useState("");
102
+ const [showEmojis, setShowEmojis] = useState(false);
103
+ const inputRef = useRef(null);
104
+ useEffect(() => {
105
+ if (replyTarget && inputRef.current) {
106
+ inputRef.current.focus();
107
+ }
108
+ }, [replyTarget]);
109
+ const handleTextChange = useCallback(
110
+ (e) => {
111
+ const value = e.target.value;
112
+ if (value.length <= maxLength) {
113
+ setText(value);
114
+ }
115
+ },
116
+ [maxLength]
117
+ );
118
+ const handleSubmit = useCallback(async () => {
119
+ const trimmed = text.trim();
120
+ if (!trimmed || state.isPosting) return;
121
+ try {
122
+ if (replyTarget) {
123
+ await actions.postReply(replyTarget.commentId, trimmed, {
124
+ id: replyTarget.authorId,
125
+ name: replyTarget.authorName
126
+ });
127
+ setReplyTarget(null);
128
+ } else {
129
+ await actions.postComment(trimmed);
130
+ }
131
+ setText("");
132
+ setShowEmojis(false);
133
+ onSubmitSuccess?.();
134
+ } catch {
135
+ }
136
+ }, [text, state.isPosting, replyTarget, actions, setReplyTarget, onSubmitSuccess]);
137
+ const handleKeyDown = useCallback(
138
+ (e) => {
139
+ if (e.key === "Enter") {
140
+ e.preventDefault();
141
+ handleSubmit();
142
+ }
143
+ },
144
+ [handleSubmit]
145
+ );
146
+ const handleEmojiClick = useCallback((emoji) => {
147
+ setText((prev) => prev + emoji);
148
+ inputRef.current?.focus();
149
+ }, []);
150
+ const handleClearReply = useCallback(() => {
151
+ setReplyTarget(null);
152
+ inputRef.current?.focus();
153
+ }, [setReplyTarget]);
154
+ const toggleEmojis = useCallback(() => {
155
+ setShowEmojis((prev) => !prev);
156
+ }, []);
157
+ const canSubmit = text.trim().length > 0 && !state.isPosting;
158
+ return /* @__PURE__ */ jsxs("div", { className: clsx("sv-comment-sheet__input-area", className), children: [
159
+ replyTarget && /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__reply-to", children: [
160
+ /* @__PURE__ */ jsxs("span", { children: [
161
+ replyingToText,
162
+ " \u2022 ",
163
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-sheet__reply-to-author-name", children: replyTarget.authorName })
164
+ ] }),
165
+ /* @__PURE__ */ jsx(
166
+ "button",
167
+ {
168
+ type: "button",
169
+ className: "sv-comment-sheet__reply-to-clear",
170
+ onClick: handleClearReply,
171
+ "aria-label": cancelReplyAriaLabel,
172
+ children: /* @__PURE__ */ jsx(CloseIcon, { className: "sv-comment-item__action-icon" })
173
+ }
174
+ )
175
+ ] }),
176
+ /* @__PURE__ */ jsx(
177
+ "div",
178
+ {
179
+ className: clsx(
180
+ "sv-comment-sheet__emoji-bar",
181
+ showEmojis && "sv-comment-sheet__emoji-bar--visible"
182
+ ),
183
+ children: emojis.map((emoji) => /* @__PURE__ */ jsx(
184
+ "button",
185
+ {
186
+ type: "button",
187
+ className: "sv-comment-sheet__emoji-bar-btn",
188
+ onClick: () => handleEmojiClick(emoji),
189
+ "aria-label": addEmojiAriaLabel.replace("{emoji}", emoji),
190
+ children: emoji
191
+ },
192
+ emoji
193
+ ))
194
+ }
195
+ ),
196
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__input-wrapper", children: [
197
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__input-left", children: [
198
+ /* @__PURE__ */ jsx(
199
+ "button",
200
+ {
201
+ type: "button",
202
+ className: "sv-comment-sheet__media-btn",
203
+ onClick: onMediaClick,
204
+ "aria-label": addMediaAriaLabel,
205
+ children: /* @__PURE__ */ jsx(ImageIcon, {})
206
+ }
207
+ ),
208
+ /* @__PURE__ */ jsx(
209
+ "input",
210
+ {
211
+ ref: inputRef,
212
+ type: "text",
213
+ className: "sv-comment-sheet__input",
214
+ value: text,
215
+ onChange: handleTextChange,
216
+ onKeyDown: handleKeyDown,
217
+ placeholder: replyTarget ? replyPlaceholderTemplate.replace("{name}", replyTarget.authorName) : placeholder,
218
+ disabled: state.isPosting,
219
+ maxLength
220
+ }
221
+ )
222
+ ] }),
223
+ canSubmit ? /* @__PURE__ */ jsx(
224
+ "button",
225
+ {
226
+ type: "button",
227
+ className: "sv-comment-sheet__emoji-btn",
228
+ onClick: handleSubmit,
229
+ "aria-label": submitAriaLabel,
230
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) })
231
+ }
232
+ ) : /* @__PURE__ */ jsx(
233
+ "button",
234
+ {
235
+ type: "button",
236
+ className: "sv-comment-sheet__emoji-btn",
237
+ onClick: toggleEmojis,
238
+ "aria-label": emojiAriaLabel,
239
+ children: /* @__PURE__ */ jsx(EmojiIcon, {})
240
+ }
241
+ )
242
+ ] })
243
+ ] });
244
+ });
245
+ CommentInput.displayName = "CommentInput";
246
+ function MoreIcon({ className }) {
247
+ return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", className, viewBox: "0 0 24 24", fill: "currentColor", children: [
248
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.5" }),
249
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "6", r: "1.5" }),
250
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "18", r: "1.5" })
251
+ ] });
252
+ }
253
+ function TrashIcon({ className }) {
254
+ return /* @__PURE__ */ jsx(
255
+ "svg",
256
+ {
257
+ "aria-hidden": "true",
258
+ className,
259
+ viewBox: "0 0 24 24",
260
+ fill: "none",
261
+ stroke: "currentColor",
262
+ strokeWidth: "1.5",
263
+ children: /* @__PURE__ */ jsx(
264
+ "path",
265
+ {
266
+ strokeLinecap: "round",
267
+ strokeLinejoin: "round",
268
+ d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
269
+ }
270
+ )
271
+ }
272
+ );
273
+ }
274
+ function EditIcon({ className }) {
275
+ return /* @__PURE__ */ jsx(
276
+ "svg",
277
+ {
278
+ "aria-hidden": "true",
279
+ className,
280
+ viewBox: "0 0 24 24",
281
+ fill: "none",
282
+ stroke: "currentColor",
283
+ strokeWidth: "1.5",
284
+ children: /* @__PURE__ */ jsx(
285
+ "path",
286
+ {
287
+ strokeLinecap: "round",
288
+ strokeLinejoin: "round",
289
+ d: "M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
290
+ }
291
+ )
292
+ }
293
+ );
294
+ }
295
+ function FlagIcon({ className }) {
296
+ return /* @__PURE__ */ jsx(
297
+ "svg",
298
+ {
299
+ "aria-hidden": "true",
300
+ className,
301
+ viewBox: "0 0 24 24",
302
+ fill: "none",
303
+ stroke: "currentColor",
304
+ strokeWidth: "1.5",
305
+ children: /* @__PURE__ */ jsx(
306
+ "path",
307
+ {
308
+ strokeLinecap: "round",
309
+ strokeLinejoin: "round",
310
+ d: "M3 3v1.5M3 21v-6m0 0l2.77-.693a9 9 0 016.208.682l.108.054a9 9 0 006.086.71l3.114-.732a48.524 48.524 0 01-.005-10.499l-3.11.732a9 9 0 01-6.085-.711l-.108-.054a9 9 0 00-6.208-.682L3 4.5M3 15V4.5"
311
+ }
312
+ )
313
+ }
314
+ );
315
+ }
316
+ var CommentMenuContext = createContext(null);
317
+ function useCommentMenuContext() {
318
+ const context = useContext(CommentMenuContext);
319
+ if (!context) {
320
+ throw new Error("CommentMenu compound components must be used within <CommentMenu>");
321
+ }
322
+ return context;
323
+ }
324
+ var DeleteConfirmDialog = memo(function DeleteConfirmDialog2({
325
+ isOpen,
326
+ onClose,
327
+ onConfirm,
328
+ isDeleting = false,
329
+ title = "Delete comment?",
330
+ message = "This action cannot be undone.",
331
+ confirmText = "Delete",
332
+ cancelText = "Cancel",
333
+ danger = true
334
+ }) {
335
+ const dialogRef = useRef(null);
336
+ useEffect(() => {
337
+ if (!isOpen) return;
338
+ const handleEscape = (e) => {
339
+ if (e.key === "Escape") onClose();
340
+ };
341
+ document.addEventListener("keydown", handleEscape);
342
+ return () => document.removeEventListener("keydown", handleEscape);
343
+ }, [isOpen, onClose]);
344
+ useEffect(() => {
345
+ if (!isOpen || !dialogRef.current) return;
346
+ const firstButton = dialogRef.current.querySelector("button");
347
+ firstButton?.focus();
348
+ }, [isOpen]);
349
+ if (!isOpen) return null;
350
+ return /* @__PURE__ */ jsx(
351
+ "div",
352
+ {
353
+ onKeyDown: (e) => e.stopPropagation(),
354
+ className: "sv-comment-dialog-overlay",
355
+ onClick: onClose,
356
+ children: /* @__PURE__ */ jsxs(
357
+ "div",
358
+ {
359
+ onKeyDown: (e) => e.stopPropagation(),
360
+ ref: dialogRef,
361
+ className: "sv-comment-dialog",
362
+ onClick: (e) => e.stopPropagation(),
363
+ role: "alertdialog",
364
+ "aria-modal": "true",
365
+ "aria-labelledby": "delete-dialog-title",
366
+ "aria-describedby": "delete-dialog-message",
367
+ children: [
368
+ /* @__PURE__ */ jsx("h3", { id: "delete-dialog-title", className: "sv-comment-dialog__title", children: title }),
369
+ /* @__PURE__ */ jsx("p", { id: "delete-dialog-message", className: "sv-comment-dialog__message", children: message }),
370
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-dialog__actions", children: [
371
+ /* @__PURE__ */ jsx(
372
+ "button",
373
+ {
374
+ type: "button",
375
+ className: "sv-comment-dialog__btn sv-comment-dialog__btn--cancel",
376
+ onClick: onClose,
377
+ disabled: isDeleting,
378
+ children: cancelText
379
+ }
380
+ ),
381
+ /* @__PURE__ */ jsx(
382
+ "button",
383
+ {
384
+ type: "button",
385
+ className: clsx(
386
+ "sv-comment-dialog__btn",
387
+ danger ? "sv-comment-dialog__btn--danger" : "sv-comment-dialog__btn--primary"
388
+ ),
389
+ onClick: onConfirm,
390
+ disabled: isDeleting,
391
+ children: isDeleting ? "..." : confirmText
392
+ }
393
+ )
394
+ ] })
395
+ ]
396
+ }
397
+ )
398
+ }
399
+ );
400
+ });
401
+ function CommentMenuRoot({
402
+ comment,
403
+ isReply = false,
404
+ parentId,
405
+ className,
406
+ children
407
+ }) {
408
+ const { i18n: sheetI18n } = useCommentSheetContext();
409
+ const [isOpen, setIsOpen] = useState(false);
410
+ const [confirmDialog, setConfirmDialog] = useState({
411
+ isOpen: false,
412
+ isLoading: false,
413
+ title: "",
414
+ message: "",
415
+ confirmText: "",
416
+ cancelText: "",
417
+ onConfirm: async () => {
418
+ }
419
+ });
420
+ const triggerRef = useRef(null);
421
+ const menuRef = useRef(null);
422
+ const i18n = useMemo(
423
+ () => ({
424
+ deleteText: sheetI18n.deleteText ?? "Delete",
425
+ editText: sheetI18n.editText ?? "Edit",
426
+ reportText: sheetI18n.reportText ?? "Report",
427
+ deleteConfirmTitle: sheetI18n.deleteConfirmTitle ?? "Delete comment?",
428
+ deleteConfirmMessage: sheetI18n.deleteConfirmMessage ?? "This action cannot be undone.",
429
+ deleteConfirmButton: sheetI18n.deleteConfirmButton ?? "Delete",
430
+ cancelButton: sheetI18n.cancelButton ?? "Cancel"
431
+ }),
432
+ [sheetI18n]
433
+ );
434
+ useEffect(() => {
435
+ if (!isOpen) return;
436
+ const handleClickOutside = (e) => {
437
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
438
+ setIsOpen(false);
439
+ }
440
+ };
441
+ document.addEventListener("mousedown", handleClickOutside);
442
+ return () => document.removeEventListener("mousedown", handleClickOutside);
443
+ }, [isOpen]);
444
+ useEffect(() => {
445
+ if (!isOpen) return;
446
+ const handleEscape = (e) => {
447
+ if (e.key === "Escape") {
448
+ setIsOpen(false);
449
+ triggerRef.current?.focus();
450
+ }
451
+ };
452
+ document.addEventListener("keydown", handleEscape);
453
+ return () => document.removeEventListener("keydown", handleEscape);
454
+ }, [isOpen]);
455
+ const open = useCallback(() => setIsOpen(true), []);
456
+ const close = useCallback(() => setIsOpen(false), []);
457
+ const toggle = useCallback(() => setIsOpen((prev) => !prev), []);
458
+ const showConfirm = useCallback((config) => {
459
+ setConfirmDialog({
460
+ ...config,
461
+ isOpen: true,
462
+ isLoading: false
463
+ });
464
+ }, []);
465
+ const handleConfirm = useCallback(async () => {
466
+ setConfirmDialog((prev) => ({ ...prev, isLoading: true }));
467
+ try {
468
+ await confirmDialog.onConfirm();
469
+ setConfirmDialog((prev) => ({ ...prev, isOpen: false, isLoading: false }));
470
+ } catch {
471
+ setConfirmDialog((prev) => ({ ...prev, isLoading: false }));
472
+ }
473
+ }, [confirmDialog.onConfirm]);
474
+ const handleCloseConfirm = useCallback(() => {
475
+ setConfirmDialog((prev) => ({ ...prev, isOpen: false }));
476
+ }, []);
477
+ const contextValue = useMemo(
478
+ () => ({
479
+ comment,
480
+ isReply,
481
+ parentId,
482
+ isOpen,
483
+ open,
484
+ close,
485
+ toggle,
486
+ triggerRef,
487
+ menuRef,
488
+ showConfirm,
489
+ i18n
490
+ }),
491
+ [comment, isReply, parentId, isOpen, open, close, toggle, showConfirm, i18n]
492
+ );
493
+ return /* @__PURE__ */ jsxs(CommentMenuContext.Provider, { value: contextValue, children: [
494
+ /* @__PURE__ */ jsx("div", { ref: menuRef, className: clsx("sv-comment-menu", className), children }),
495
+ /* @__PURE__ */ jsx(
496
+ DeleteConfirmDialog,
497
+ {
498
+ isOpen: confirmDialog.isOpen,
499
+ onClose: handleCloseConfirm,
500
+ onConfirm: handleConfirm,
501
+ isDeleting: confirmDialog.isLoading,
502
+ title: confirmDialog.title,
503
+ message: confirmDialog.message,
504
+ confirmText: confirmDialog.confirmText,
505
+ cancelText: confirmDialog.cancelText,
506
+ danger: confirmDialog.danger
507
+ }
508
+ )
509
+ ] });
510
+ }
511
+ function Trigger({
512
+ className,
513
+ icon,
514
+ "aria-label": ariaLabel = "More options"
515
+ }) {
516
+ const { isOpen, toggle, triggerRef } = useCommentMenuContext();
517
+ return /* @__PURE__ */ jsx(
518
+ "button",
519
+ {
520
+ ref: triggerRef,
521
+ type: "button",
522
+ className: clsx("sv-comment-menu__trigger", className),
523
+ onClick: toggle,
524
+ "aria-label": ariaLabel,
525
+ "aria-expanded": isOpen,
526
+ "aria-haspopup": "menu",
527
+ children: icon ?? /* @__PURE__ */ jsx(MoreIcon, { className: "sv-comment-menu__icon" })
528
+ }
529
+ );
530
+ }
531
+ function Dropdown({ className, children }) {
532
+ const { isOpen } = useCommentMenuContext();
533
+ if (!isOpen) return null;
534
+ return /* @__PURE__ */ jsx("div", { className: clsx("sv-comment-menu__dropdown", className), role: "menu", children });
535
+ }
536
+ function Item({
537
+ icon,
538
+ danger = false,
539
+ disabled = false,
540
+ className,
541
+ onClick,
542
+ children
543
+ }) {
544
+ const { close } = useCommentMenuContext();
545
+ const handleClick = useCallback(() => {
546
+ if (disabled) return;
547
+ onClick?.();
548
+ close();
549
+ }, [disabled, onClick, close]);
550
+ return /* @__PURE__ */ jsxs(
551
+ "button",
552
+ {
553
+ type: "button",
554
+ className: clsx(
555
+ "sv-comment-menu__item",
556
+ danger && "sv-comment-menu__item--danger",
557
+ disabled && "sv-comment-menu__item--disabled",
558
+ className
559
+ ),
560
+ onClick: handleClick,
561
+ disabled,
562
+ role: "menuitem",
563
+ children: [
564
+ icon && /* @__PURE__ */ jsx("span", { className: "sv-comment-menu__item-icon", children: icon }),
565
+ /* @__PURE__ */ jsx("span", { children })
566
+ ]
567
+ }
568
+ );
569
+ }
570
+ function DeleteItem({ requireConfirm, onDelete, label, className }) {
571
+ const { comment, isReply, parentId, close, showConfirm, i18n } = useCommentMenuContext();
572
+ const { actions, config } = useCommentSheetContext();
573
+ const shouldConfirm = requireConfirm ?? config.requireDeleteConfirm;
574
+ const displayLabel = label ?? i18n.deleteText;
575
+ const performDelete = useCallback(async () => {
576
+ if (onDelete) {
577
+ await onDelete(comment.id, isReply, parentId);
578
+ } else {
579
+ await actions.deleteComment(comment.id, isReply, parentId);
580
+ }
581
+ }, [onDelete, actions, comment.id, isReply, parentId]);
582
+ const handleClick = useCallback(() => {
583
+ close();
584
+ if (shouldConfirm) {
585
+ showConfirm({
586
+ title: i18n.deleteConfirmTitle,
587
+ message: i18n.deleteConfirmMessage,
588
+ confirmText: i18n.deleteConfirmButton,
589
+ cancelText: i18n.cancelButton,
590
+ danger: true,
591
+ onConfirm: performDelete
592
+ });
593
+ } else {
594
+ performDelete();
595
+ }
596
+ }, [shouldConfirm, showConfirm, performDelete, i18n, close]);
597
+ return /* @__PURE__ */ jsxs(
598
+ "button",
599
+ {
600
+ type: "button",
601
+ className: clsx("sv-comment-menu__item sv-comment-menu__item--danger", className),
602
+ onClick: handleClick,
603
+ role: "menuitem",
604
+ children: [
605
+ /* @__PURE__ */ jsx(TrashIcon, { className: "sv-comment-menu__item-icon" }),
606
+ /* @__PURE__ */ jsx("span", { children: displayLabel })
607
+ ]
608
+ }
609
+ );
610
+ }
611
+ function EditItem({ onEdit, label, className }) {
612
+ const { comment, close, i18n } = useCommentMenuContext();
613
+ const displayLabel = label ?? i18n.editText;
614
+ const isDisabled = !onEdit;
615
+ const handleClick = useCallback(() => {
616
+ if (!onEdit) return;
617
+ close();
618
+ onEdit(comment.id, comment.content);
619
+ }, [close, onEdit, comment.id, comment.content]);
620
+ return /* @__PURE__ */ jsxs(
621
+ "button",
622
+ {
623
+ type: "button",
624
+ className: clsx(
625
+ "sv-comment-menu__item",
626
+ isDisabled && "sv-comment-menu__item--disabled",
627
+ className
628
+ ),
629
+ onClick: handleClick,
630
+ disabled: isDisabled,
631
+ role: "menuitem",
632
+ children: [
633
+ /* @__PURE__ */ jsx(EditIcon, { className: "sv-comment-menu__item-icon" }),
634
+ /* @__PURE__ */ jsx("span", { children: displayLabel })
635
+ ]
636
+ }
637
+ );
638
+ }
639
+ function ReportItem({
640
+ onReport,
641
+ reason = "inappropriate",
642
+ label,
643
+ className
644
+ }) {
645
+ const { comment, close, i18n } = useCommentMenuContext();
646
+ const { actions } = useCommentSheetContext();
647
+ const displayLabel = label ?? i18n.reportText;
648
+ const handleClick = useCallback(() => {
649
+ close();
650
+ if (onReport) {
651
+ onReport(comment.id);
652
+ } else {
653
+ actions.reportComment(comment.id, reason);
654
+ }
655
+ }, [close, onReport, comment.id, actions, reason]);
656
+ return /* @__PURE__ */ jsxs(
657
+ "button",
658
+ {
659
+ type: "button",
660
+ className: clsx("sv-comment-menu__item", className),
661
+ onClick: handleClick,
662
+ role: "menuitem",
663
+ children: [
664
+ /* @__PURE__ */ jsx(FlagIcon, { className: "sv-comment-menu__item-icon" }),
665
+ /* @__PURE__ */ jsx("span", { children: displayLabel })
666
+ ]
667
+ }
668
+ );
669
+ }
670
+ var CommentMenu = Object.assign(memo(CommentMenuRoot), {
671
+ Trigger: memo(Trigger),
672
+ Dropdown: memo(Dropdown),
673
+ Item: memo(Item),
674
+ DeleteItem: memo(DeleteItem),
675
+ EditItem: memo(EditItem),
676
+ ReportItem: memo(ReportItem)
677
+ });
678
+ CommentMenu.displayName = "CommentMenu";
679
+ function PinIcon({ className }) {
680
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className, viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a5.927 5.927 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707-.195-.195.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a5.922 5.922 0 0 1 1.013.16l3.134-3.133a2.772 2.772 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146z" }) });
681
+ }
682
+ function ReplyIcon({ className }) {
683
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className, viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx(
684
+ "path",
685
+ {
686
+ fillRule: "evenodd",
687
+ d: "M7.793 2.232a.75.75 0 01-.025 1.06L3.622 7.25h10.003a5.375 5.375 0 010 10.75H10.75a.75.75 0 010-1.5h2.875a3.875 3.875 0 000-7.75H3.622l4.146 3.957a.75.75 0 01-1.036 1.085l-5.5-5.25a.75.75 0 010-1.085l5.5-5.25a.75.75 0 011.06.025z",
688
+ clipRule: "evenodd"
689
+ }
690
+ ) });
691
+ }
692
+ function VerifiedIcon({ className }) {
693
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) });
694
+ }
695
+ function ChevronIcon({ direction, className }) {
696
+ return /* @__PURE__ */ jsx(
697
+ "svg",
698
+ {
699
+ "aria-hidden": "true",
700
+ className,
701
+ viewBox: "0 0 20 20",
702
+ fill: "currentColor",
703
+ style: { transform: direction === "up" ? "rotate(180deg)" : void 0 },
704
+ children: /* @__PURE__ */ jsx(
705
+ "path",
706
+ {
707
+ fillRule: "evenodd",
708
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
709
+ clipRule: "evenodd"
710
+ }
711
+ )
712
+ }
713
+ );
714
+ }
715
+ function CommentAvatar({
716
+ src,
717
+ name,
718
+ size = "normal",
719
+ className
720
+ }) {
721
+ const [error, setError] = useState(false);
722
+ const sizeClass = size === "small" ? "sv-comment-reply__avatar" : "sv-comment-item__avatar";
723
+ const initial = name.charAt(0).toUpperCase();
724
+ if (!src || error) {
725
+ return /* @__PURE__ */ jsx(
726
+ "div",
727
+ {
728
+ className: clsx(sizeClass, className),
729
+ style: {
730
+ display: "flex",
731
+ alignItems: "center",
732
+ justifyContent: "center",
733
+ fontSize: size === "small" ? 10 : 14,
734
+ fontWeight: 600,
735
+ color: "#6b7271"
736
+ },
737
+ children: initial
738
+ }
739
+ );
740
+ }
741
+ return /* @__PURE__ */ jsx(
742
+ "img",
743
+ {
744
+ src,
745
+ alt: name,
746
+ className: clsx(sizeClass, className),
747
+ onError: () => setError(true)
748
+ }
749
+ );
750
+ }
751
+ function CommentText({
752
+ text,
753
+ maxLines,
754
+ className,
755
+ expandText = "See more",
756
+ collapseText = "See less"
757
+ }) {
758
+ const [expanded, setExpanded] = useState(false);
759
+ const needsCollapse = text.length > maxLines * 60 || text.split("\n").length > maxLines;
760
+ return /* @__PURE__ */ jsxs("div", { className, children: [
761
+ /* @__PURE__ */ jsx(
762
+ "p",
763
+ {
764
+ className: clsx(
765
+ "sv-comment-item__text",
766
+ !expanded && needsCollapse && "sv-comment-item__text--collapsed"
767
+ ),
768
+ style: { "--sv-comment-max-lines": maxLines },
769
+ children: text
770
+ }
771
+ ),
772
+ needsCollapse && /* @__PURE__ */ jsx(
773
+ "button",
774
+ {
775
+ type: "button",
776
+ className: "sv-comment-item__expand-btn",
777
+ onClick: () => setExpanded(!expanded),
778
+ children: expanded ? collapseText : expandText
779
+ }
780
+ )
781
+ ] });
782
+ }
783
+ function defaultFormatTimeAgo(dateStr) {
784
+ const date = new Date(dateStr);
785
+ const now = /* @__PURE__ */ new Date();
786
+ const diff = Math.floor((now.getTime() - date.getTime()) / 1e3);
787
+ if (diff < 60) return "just now";
788
+ if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
789
+ if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
790
+ if (diff < 604800) return `${Math.floor(diff / 86400)}d ago`;
791
+ if (diff < 2592e3) return `${Math.floor(diff / 604800)}w ago`;
792
+ return `${Math.floor(diff / 2592e3)}mo ago`;
793
+ }
794
+ function formatCount(count) {
795
+ if (count >= 1e6) {
796
+ return `${(count / 1e6).toFixed(1)}M`;
797
+ }
798
+ if (count >= 1e3) {
799
+ return `${(count / 1e3).toFixed(1)}K`;
800
+ }
801
+ return String(count);
802
+ }
803
+ var ReplyItemComponent = memo(function ReplyItemComponent2({
804
+ reply,
805
+ parentComment
806
+ }) {
807
+ const { setReplyTarget, i18n } = useCommentSheetContext();
808
+ const formatTimeAgo = i18n.formatRelativeTime ?? defaultFormatTimeAgo;
809
+ const handleReply = useCallback(() => {
810
+ setReplyTarget({
811
+ commentId: parentComment.id,
812
+ authorName: reply.author.name,
813
+ authorId: reply.author.id
814
+ });
815
+ }, [setReplyTarget, parentComment.id, reply.author]);
816
+ return /* @__PURE__ */ jsxs("div", { className: clsx("sv-comment-reply", reply.isPending && "sv-comment-item--pending"), children: [
817
+ /* @__PURE__ */ jsx(CommentAvatar, { src: reply.author.avatar, name: reply.author.name, size: "small" }),
818
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__content", children: [
819
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__header", children: [
820
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__header-left", children: [
821
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-item__author", children: reply.author.name }),
822
+ reply.author.isVerified && /* @__PURE__ */ jsx(VerifiedIcon, { className: "sv-comment-item__verified" })
823
+ ] }),
824
+ reply.isOwner && /* @__PURE__ */ jsxs(CommentMenu, { comment: reply, isReply: true, parentId: parentComment.id, children: [
825
+ /* @__PURE__ */ jsx(CommentMenu.Trigger, {}),
826
+ /* @__PURE__ */ jsx(CommentMenu.Dropdown, { children: /* @__PURE__ */ jsx(CommentMenu.DeleteItem, {}) })
827
+ ] })
828
+ ] }),
829
+ /* @__PURE__ */ jsxs("p", { className: "sv-comment-item__text", children: [
830
+ reply.replyTo && reply.replyTo.id !== parentComment.author.id && /* @__PURE__ */ jsxs("span", { className: "sv-comment-reply__mention", children: [
831
+ "@",
832
+ reply.replyTo.name,
833
+ " "
834
+ ] }),
835
+ reply.content
836
+ ] }),
837
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__actions", children: [
838
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-item__time", children: formatTimeAgo(reply.createdAt) }),
839
+ /* @__PURE__ */ jsx("button", { type: "button", className: "sv-comment-item__action-btn", onClick: handleReply, children: /* @__PURE__ */ jsx(ReplyIcon, { className: "sv-comment-item__action-icon" }) })
840
+ ] })
841
+ ] })
842
+ ] });
843
+ });
844
+ function RepliesList({ comment }) {
845
+ const { actions, config, i18n } = useCommentSheetContext();
846
+ const [expanded, setExpanded] = useState(false);
847
+ const { replyCount, replies = [], repliesLoaded } = comment;
848
+ const shouldAutoExpand = replyCount <= config.repliesAutoExpandThreshold;
849
+ const showReplies = shouldAutoExpand || expanded;
850
+ const visibleReplies = showReplies ? replies : [];
851
+ const hasMoreReplies = !repliesLoaded && replyCount > replies.length;
852
+ const remainingReplies = replyCount - visibleReplies.length;
853
+ const hideRepliesText = i18n.hideRepliesText ?? "Hide replies";
854
+ const viewRepliesText = (i18n.viewRepliesText ?? "View {count} more replies").replace(
855
+ "{count}",
856
+ String(remainingReplies)
857
+ );
858
+ const viewMoreRepliesText = i18n.viewMoreRepliesText ?? "View more replies";
859
+ const loadRepliesText = i18n.loadRepliesText ?? "Load replies";
860
+ const handleToggle = useCallback(() => {
861
+ if (!expanded && replies.length === 0) {
862
+ actions.loadReplies(comment.id);
863
+ }
864
+ setExpanded(!expanded);
865
+ }, [expanded, replies.length, actions, comment.id]);
866
+ const handleLoadMore = useCallback(() => {
867
+ actions.loadReplies(comment.id);
868
+ }, [actions, comment.id]);
869
+ if (replyCount === 0) return null;
870
+ return /* @__PURE__ */ jsxs("div", { className: "sv-comment-replies", children: [
871
+ showReplies && visibleReplies.length > 0 && /* @__PURE__ */ jsx("div", { className: "sv-comment-replies__list", children: visibleReplies.map((reply) => /* @__PURE__ */ jsx(ReplyItemComponent, { reply, parentComment: comment }, reply.id)) }),
872
+ !shouldAutoExpand && /* @__PURE__ */ jsxs("button", { type: "button", className: "sv-comment-replies__toggle", onClick: handleToggle, children: [
873
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-line" }),
874
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-text", children: expanded ? hideRepliesText : viewRepliesText }),
875
+ /* @__PURE__ */ jsx(
876
+ ChevronIcon,
877
+ {
878
+ direction: expanded ? "up" : "down",
879
+ className: "sv-comment-replies__toggle-icon"
880
+ }
881
+ )
882
+ ] }),
883
+ expanded && hasMoreReplies && /* @__PURE__ */ jsxs("button", { type: "button", className: "sv-comment-replies__toggle", onClick: handleLoadMore, children: [
884
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-line" }),
885
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-text", children: viewMoreRepliesText }),
886
+ /* @__PURE__ */ jsx(ChevronIcon, { direction: "down", className: "sv-comment-replies__toggle-icon" })
887
+ ] }),
888
+ shouldAutoExpand && replies.length === 0 && replyCount > 0 && /* @__PURE__ */ jsxs(
889
+ "button",
890
+ {
891
+ type: "button",
892
+ className: "sv-comment-replies__toggle",
893
+ onClick: () => actions.loadReplies(comment.id),
894
+ children: [
895
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-line" }),
896
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-replies__toggle-text", children: loadRepliesText }),
897
+ /* @__PURE__ */ jsx(ChevronIcon, { direction: "down", className: "sv-comment-replies__toggle-icon" })
898
+ ]
899
+ }
900
+ )
901
+ ] });
902
+ }
903
+ var CommentItemComponent = memo(function CommentItemComponent2({
904
+ comment,
905
+ className
906
+ }) {
907
+ const { config, setReplyTarget, i18n } = useCommentSheetContext();
908
+ const expandText = i18n.expandText ?? "See more";
909
+ const collapseText = i18n.collapseText ?? "See less";
910
+ const formatTimeAgo = i18n.formatRelativeTime ?? defaultFormatTimeAgo;
911
+ const handleReply = useCallback(() => {
912
+ setReplyTarget({
913
+ commentId: comment.id,
914
+ authorName: comment.author.name,
915
+ authorId: comment.author.id
916
+ });
917
+ }, [setReplyTarget, comment.id, comment.author]);
918
+ const hasReplies = comment.replyCount > 0;
919
+ return /* @__PURE__ */ jsxs(
920
+ "div",
921
+ {
922
+ className: clsx(
923
+ "sv-comment-item",
924
+ comment.isPending && "sv-comment-item--pending",
925
+ comment.isPinned && "sv-comment-item--pinned",
926
+ hasReplies && "sv-comment-item--has-replies",
927
+ className
928
+ ),
929
+ children: [
930
+ /* @__PURE__ */ jsx(CommentAvatar, { src: comment.author.avatar, name: comment.author.name }),
931
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__content", children: [
932
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__header", children: [
933
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__header-left", children: [
934
+ comment.isPinned && /* @__PURE__ */ jsx(PinIcon, { className: "sv-comment-item__pin-icon" }),
935
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-item__author", children: comment.author.name }),
936
+ comment.author.isVerified && /* @__PURE__ */ jsx(VerifiedIcon, { className: "sv-comment-item__verified" }),
937
+ comment.author.badge && /* @__PURE__ */ jsx("span", { className: "sv-comment-item__badge", children: comment.author.badge })
938
+ ] }),
939
+ comment.isOwner && /* @__PURE__ */ jsxs(CommentMenu, { comment, children: [
940
+ /* @__PURE__ */ jsx(CommentMenu.Trigger, {}),
941
+ /* @__PURE__ */ jsx(CommentMenu.Dropdown, { children: /* @__PURE__ */ jsx(CommentMenu.DeleteItem, {}) })
942
+ ] })
943
+ ] }),
944
+ /* @__PURE__ */ jsx(
945
+ CommentText,
946
+ {
947
+ text: comment.content,
948
+ maxLines: config.textMaxLines,
949
+ expandText,
950
+ collapseText
951
+ }
952
+ ),
953
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__actions", children: [
954
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-item__time", children: formatTimeAgo(comment.createdAt) }),
955
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "sv-comment-item__action-btn", onClick: handleReply, children: [
956
+ /* @__PURE__ */ jsx(ReplyIcon, { className: "sv-comment-item__action-icon" }),
957
+ comment.replyCount > 0 && /* @__PURE__ */ jsx("span", { children: formatCount(comment.replyCount) })
958
+ ] })
959
+ ] }),
960
+ /* @__PURE__ */ jsx(RepliesList, { comment })
961
+ ] })
962
+ ]
963
+ }
964
+ );
965
+ });
966
+ CommentItemComponent.displayName = "CommentItem";
967
+ var CommentItemSkeleton = memo(function CommentItemSkeleton2() {
968
+ return /* @__PURE__ */ jsxs("div", { className: "sv-comment-item sv-comment-skeleton", children: [
969
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__avatar" }),
970
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-skeleton__content", children: [
971
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-skeleton__header", children: [
972
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__author" }),
973
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__time" })
974
+ ] }),
975
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-skeleton__text", children: [
976
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__line sv-comment-skeleton__line--full" }),
977
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__line sv-comment-skeleton__line--medium" })
978
+ ] }),
979
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-skeleton__actions", children: [
980
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__action" }),
981
+ /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton__action" })
982
+ ] })
983
+ ] })
984
+ ] });
985
+ });
986
+ CommentItemSkeleton.displayName = "CommentItemSkeleton";
987
+ var CommentListSkeleton = memo(function CommentListSkeleton2({
988
+ count = 5
989
+ }) {
990
+ return /* @__PURE__ */ jsx("div", { className: "sv-comment-skeleton-list", children: Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx(
991
+ CommentItemSkeleton,
992
+ {},
993
+ `skeleton-${// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
994
+ index}`
995
+ )) });
996
+ });
997
+ CommentListSkeleton.displayName = "CommentListSkeleton";
998
+ var CommentList = memo(function CommentList2({
999
+ emptyState,
1000
+ loadingState,
1001
+ errorState,
1002
+ className,
1003
+ errorText = "Failed to load comments",
1004
+ retryText = "Try again",
1005
+ emptyText = "No comments yet. Be the first!",
1006
+ loadMoreText = "Load more comments"
1007
+ }) {
1008
+ const { state, actions, videoId } = useCommentSheetContext();
1009
+ const listRef = useRef(null);
1010
+ const loadMoreRef = useRef(null);
1011
+ const { comments, isLoading, error, hasMore, isLoadingMore } = state;
1012
+ useEffect(() => {
1013
+ if (!hasMore || isLoadingMore) return;
1014
+ const observer = new IntersectionObserver(
1015
+ (entries) => {
1016
+ if (entries[0]?.isIntersecting) {
1017
+ actions.loadMore();
1018
+ }
1019
+ },
1020
+ { threshold: 0.1 }
1021
+ );
1022
+ const target = loadMoreRef.current;
1023
+ if (target) {
1024
+ observer.observe(target);
1025
+ }
1026
+ return () => {
1027
+ if (target) {
1028
+ observer.unobserve(target);
1029
+ }
1030
+ };
1031
+ }, [hasMore, isLoadingMore, actions]);
1032
+ const handleRetry = useCallback(() => {
1033
+ if (videoId) {
1034
+ actions.loadComments(videoId);
1035
+ }
1036
+ }, [actions, videoId]);
1037
+ if (isLoading && comments.length === 0) {
1038
+ return /* @__PURE__ */ jsx("div", { className: clsx("sv-comment-sheet__list", className), children: loadingState ?? /* @__PURE__ */ jsx(CommentListSkeleton, { count: 5 }) });
1039
+ }
1040
+ if (error && comments.length === 0) {
1041
+ return /* @__PURE__ */ jsx("div", { className: clsx("sv-comment-sheet__list", className), children: errorState?.(error, handleRetry) ?? /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__error", children: [
1042
+ /* @__PURE__ */ jsx("span", { children: errorText }),
1043
+ /* @__PURE__ */ jsx("button", { type: "button", className: "sv-comment-sheet__error-btn", onClick: handleRetry, children: retryText })
1044
+ ] }) });
1045
+ }
1046
+ if (comments.length === 0) {
1047
+ return /* @__PURE__ */ jsx("div", { className: clsx("sv-comment-sheet__list", className), children: emptyState ?? /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__empty", children: [
1048
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-sheet__empty-icon", children: "\u{1F4AC}" }),
1049
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-sheet__empty-text", children: emptyText })
1050
+ ] }) });
1051
+ }
1052
+ return /* @__PURE__ */ jsxs("div", { ref: listRef, className: clsx("sv-comment-sheet__list", className), children: [
1053
+ comments.map((comment) => /* @__PURE__ */ jsx(CommentItemComponent, { comment }, comment.id)),
1054
+ hasMore && /* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "sv-comment-sheet__load-more", children: isLoadingMore ? /* @__PURE__ */ jsx(CommentItemSkeleton, {}) : /* @__PURE__ */ jsx(
1055
+ "button",
1056
+ {
1057
+ type: "button",
1058
+ className: "sv-comment-sheet__load-more-btn",
1059
+ onClick: () => actions.loadMore(),
1060
+ children: loadMoreText
1061
+ }
1062
+ ) })
1063
+ ] });
1064
+ });
1065
+ CommentList.displayName = "CommentList";
1066
+
1067
+ // src/components/CommentSheet/CommentSheet.css.ts
1068
+ var COMMENT_SHEET_CSS = `:root{--sv-comment-primary:#164d8e;--sv-comment-primary-light:#1354ae;--sv-comment-primary-dark:#003477;--sv-comment-bg:#fff;--sv-comment-text:#121212;--sv-comment-text-secondary:#6b7271;--sv-comment-border:rgba(18,18,18,.08);--sv-comment-like-color:#ff434e;--sv-comment-verified-color:#1ea031;--sv-comment-mention-color:#164d8e;--sv-comment-avatar-bg:#e5e6e6;--sv-comment-input-border:#a3a3a3;--sv-comment-reply-line:#e5e6e6}.sv-comment-sheet{--sv-sheet-bg:var(--sv-comment-bg,#fff);--sv-sheet-border-radius:var(--sv-comment-sheet-radius,24px);--sv-sheet-animation-duration:var(--sv-comment-animation-duration,400ms);--sv-sheet-animation-easing:var(--sv-comment-animation-easing,cubic-bezier(.32,.72,0,1));margin:16px;border-radius:var(--sv-comment-sheet-radius,24px)}.sv-comment-sheet-backdrop{--sv-sheet-backdrop-bg:var(--sv-comment-backdrop-bg,rgba(0,0,0,.5))}.sv-comment-sheet__inner{display:flex;flex-direction:column;height:100%}.sv-comment-sheet .sv-bottom-sheet__content{overflow:visible;display:flex;flex-direction:column;flex:1}.sv-comment-sheet__header{display:flex;align-items:center;justify-content:space-between;padding:16px;border-bottom:1px solid var(--sv-comment-border);flex-shrink:0;position:relative;cursor:grab;touch-action:none}.sv-comment-sheet__header:active{cursor:grabbing}.sv-comment-sheet__header-handle{position:absolute;top:8px;left:50%;transform:translateX(-50%);width:36px;height:4px;background:var(--sv-comment-text-secondary);border-radius:2px;opacity:.3}.sv-comment-sheet__header-left{display:flex;align-items:center;gap:2px}.sv-comment-sheet__title{font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:18px;font-weight:600;line-height:1.4;color:var(--sv-comment-text);opacity:.9;margin:0}.sv-comment-sheet__sort-btn{display:flex;align-items:center;justify-content:center;background:0 0;border:0;padding:0;cursor:pointer;color:var(--sv-comment-text)}.sv-comment-sheet__sort-btn svg{width:20px;height:20px}.sv-comment-sheet__close-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:0;border-radius:100px;background:linear-gradient(180deg,var(--sv-comment-primary-light)0%,var(--sv-comment-primary-dark)100%);cursor:pointer;transition:opacity .15s ease}.sv-comment-sheet__close-btn:hover{opacity:.9}.sv-comment-sheet__close-btn svg{width:20px;height:20px;color:#fff}.sv-comment-sheet__list{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 16px 28px 16px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:pan-y}.sv-comment-sheet__list::-webkit-scrollbar{width:0}.sv-comment-sheet__list::-webkit-scrollbar-thumb{background:rgba(0,0,0,.0);border-radius:0}.sv-comment-item{display:flex;gap:6px;padding:16px 0;position:relative}.sv-comment-item--pending{opacity:.6}.sv-comment-item--pinned{background:var(--sv-comment-bg)}.sv-comment-item__avatar{width:40px;height:40px;border-radius:120px;flex-shrink:0;object-fit:cover;background:var(--sv-comment-avatar-bg)}.sv-comment-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}.sv-comment-item__header{display:flex;align-items:center;justify-content:space-between;gap:4px}.sv-comment-item__header-left{display:flex;align-items:center;gap:4px;min-width:0}.sv-comment-item__pin-icon{width:16px;height:16px;flex-shrink:0;color:var(--sv-comment-primary)}.sv-comment-item__author{font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:600;line-height:1.4;color:var(--sv-comment-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sv-comment-item__verified{width:12px;height:12px;flex-shrink:0;color:var(--sv-comment-verified-color)}.sv-comment-item__badge{font-size:10px;padding:2px 6px;background:var(--sv-comment-primary);color:#fff;border-radius:4px;flex-shrink:0}.sv-comment-item__menu-btn{display:flex;align-items:center;justify-content:center;background:0 0;border:0;padding:0;cursor:pointer;color:var(--sv-comment-text-secondary)}.sv-comment-item__menu-btn svg{width:20px;height:20px}.sv-comment-item__text{font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-weight:normal;line-height:1.4;color:var(--sv-comment-text);word-break:break-word;margin:0;padding-right:16px}.sv-comment-item__text--collapsed{display:-webkit-box;-webkit-line-clamp:var(--sv-comment-max-lines,3);-webkit-box-orient:vertical;overflow:hidden}.sv-comment-item__expand-btn{background:0 0;border:0;padding:0;font-size:12px;color:var(--sv-comment-text-secondary);cursor:pointer;margin-top:4px}.sv-comment-item__expand-btn:hover{color:var(--sv-comment-text)}.sv-comment-item__actions{display:flex;align-items:center;gap:16px}.sv-comment-item__time{font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-weight:500;line-height:1.2;color:var(--sv-comment-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sv-comment-item__action-btn{display:flex;align-items:center;gap:4px;background:0 0;border:0;padding:0;font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-weight:500;line-height:1.2;color:var(--sv-comment-text-secondary);cursor:pointer;transition:color .15s ease}.sv-comment-item__action-btn:hover{color:var(--sv-comment-text)}.sv-comment-item__action-btn--active{color:var(--sv-comment-like-color)}.sv-comment-item__action-btn--active:hover{color:var(--sv-comment-like-color)}.sv-comment-item__action-icon{width:20px;height:20px}.sv-comment-replies{margin-top:12px;position:relative}.sv-comment-item--has-replies::before{content:'';position:absolute;left:20px;top:56px;bottom:0;width:1px;background:var(--sv-comment-reply-line)}.sv-comment-replies__toggle{display:flex;align-items:center;gap:0;background:0 0;border:0;padding:4px 0;cursor:pointer}.sv-comment-replies__toggle-line{width:24px;height:1px;background:#a3a3a3;margin-right:0}.sv-comment-replies__toggle-text{font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:13px;font-weight:600;line-height:1.4;color:var(--sv-comment-text-secondary);white-space:nowrap}.sv-comment-replies__toggle-icon{width:20px;height:20px;color:var(--sv-comment-text-secondary)}.sv-comment-replies__list{margin-top:12px}.sv-comment-reply{display:flex;gap:6px;padding:0 0 12px 0;position:relative}.sv-comment-reply__avatar{width:24px;height:24px;border-radius:100px;flex-shrink:0;object-fit:cover;background:var(--sv-comment-avatar-bg)}.sv-comment-reply__mention{color:var(--sv-comment-mention-color);font-weight:500}.sv-comment-sheet__input-area{padding:0 16px 36px 16px;flex-shrink:0}.sv-comment-input-guest{padding:16px;border-top:1px solid var(--sv-comment-border);display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--sv-comment-bg);color:var(--sv-comment-primary);font-weight:600;font-size:14px;width:100%;transition:background .15s ease}.sv-comment-input-guest:hover{background:rgba(22,77,142,.05)}.sv-comment-input-guest:active{background:rgba(22,77,142,.1)}.sv-comment-sheet__reply-to{display:flex;align-items:center;justify-content:space-between;padding:4px 0;margin-bottom:8px;font-size:12px;color:var(--sv-comment-text-secondary)}.sv-comment-sheet__reply-to-author-name{font-size:12px;color:var(--sv-comment-text);font-weight:500}.sv-comment-sheet__reply-to-clear{background:0 0;border:0;padding:4px;color:var(--sv-comment-text-secondary);cursor:pointer;font-size:12px}.sv-comment-sheet__input-wrapper{display:flex;align-items:center;gap:8px;height:44px;padding:16px;background:var(--sv-comment-bg);border:1px solid var(--sv-comment-input-border);border-radius:12px;backdrop-filter:blur(50px)}.sv-comment-sheet__input-left{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.sv-comment-sheet__media-btn{display:flex;align-items:center;justify-content:center;background:0 0;border:0;padding:0;cursor:pointer;flex-shrink:0}.sv-comment-sheet__media-btn svg{width:20px;height:20px}.sv-comment-sheet__input{flex:1;background:0 0;border:0;outline:none;resize:none;font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-style:italic;font-weight:normal;line-height:1.4;color:var(--sv-comment-text);padding:0;min-width:0}.sv-comment-sheet__input::placeholder{color:var(--sv-comment-text-secondary)}.sv-comment-sheet__input:not(:placeholder-shown){font-style:normal}.sv-comment-sheet__emoji-btn{display:flex;align-items:center;justify-content:center;background:0 0;border:0;padding:0;cursor:pointer;flex-shrink:0}.sv-comment-sheet__emoji-btn svg{width:20px;height:20px;color:var(--sv-comment-primary)}.sv-comment-sheet__emoji-bar{display:none;gap:8px;padding:8px 0;overflow-x:auto;-webkit-overflow-scrolling:touch}.sv-comment-sheet__emoji-bar--visible{display:flex}.sv-comment-sheet__emoji-bar::-webkit-scrollbar{display:none}.sv-comment-sheet__emoji-bar-btn{background:0 0;border:0;padding:4px;font-size:20px;cursor:pointer;border-radius:4px;transition:background .15s ease}.sv-comment-sheet__emoji-bar-btn:hover{background:rgba(0,0,0,.05)}.sv-comment-sheet__loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;color:var(--sv-comment-text-secondary)}.sv-comment-sheet__loading-spinner{width:24px;height:24px;border:2px solid rgba(0,0,0,.1);border-top-color:var(--sv-comment-primary);border-radius:50%;animation:sv-comment-spin .8s linear infinite}@keyframes sv-comment-spin{to{transform:rotate(360deg)}}.sv-comment-sheet__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;text-align:center}.sv-comment-sheet__empty-icon{font-size:48px;margin-bottom:12px}.sv-comment-sheet__empty-text{color:var(--sv-comment-text-secondary);font-size:14px}.sv-comment-sheet__error{display:flex;flex-direction:column;align-items:center;padding:32px;text-align:center;color:var(--sv-comment-like-color)}.sv-comment-sheet__error-btn{margin-top:12px;padding:8px 16px;background:rgba(0,0,0,.05);border:0;border-radius:8px;color:var(--sv-comment-text);cursor:pointer}.sv-comment-sheet__load-more{display:flex;justify-content:center;padding:12px}.sv-comment-sheet__load-more-btn{background:0 0;border:0;padding:8px 16px;color:var(--sv-comment-text-secondary);cursor:pointer;font-size:13px}.sv-comment-sheet__load-more-btn:hover{color:var(--sv-comment-text)}.sv-comment-menu{position:relative}.sv-comment-menu__trigger{display:flex;align-items:center;justify-content:center;background:0 0;border:0;padding:4px;cursor:pointer;color:var(--sv-comment-text-secondary);border-radius:4px;transition:background .15s ease}.sv-comment-menu__trigger:hover{background:rgba(0,0,0,.05)}.sv-comment-menu__icon{width:20px;height:20px}.sv-comment-menu__dropdown{position:absolute;top:100%;right:0;margin-top:4px;min-width:140px;background:var(--sv-comment-bg);border:1px solid var(--sv-comment-border);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);z-index:10;overflow:hidden;animation:sv-menu-fade-in .15s ease}@keyframes sv-menu-fade-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sv-comment-menu__item{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;background:0 0;border:0;cursor:pointer;font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:500;color:var(--sv-comment-text);text-align:left;transition:background .15s ease}.sv-comment-menu__item:hover{background:rgba(0,0,0,.05)}.sv-comment-menu__item--danger{color:var(--sv-comment-like-color)}.sv-comment-menu__item--danger:hover{background:rgba(255,67,78,.08)}.sv-comment-menu__item-icon{width:18px;height:18px;flex-shrink:0}.sv-comment-dialog-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5);z-index:var(--sv-comment-modal-z-index,1100);animation:sv-dialog-overlay-fade-in .2s ease}@keyframes sv-dialog-overlay-fade-in{from{opacity:0}to{opacity:1}}.sv-comment-dialog{background:var(--sv-comment-bg);border-radius:16px;padding:24px;max-width:300px;width:calc(100% - 48px);text-align:center;animation:sv-dialog-scale-in .2s ease}@keyframes sv-dialog-scale-in{from{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.sv-comment-dialog__title{font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:17px;font-weight:600;color:var(--sv-comment-text);margin:0 0 8px 0}.sv-comment-dialog__message{font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;color:var(--sv-comment-text-secondary);margin:0 0 20px 0;line-height:1.4}.sv-comment-dialog__actions{display:flex;gap:12px}.sv-comment-dialog__btn{flex:1;padding:12px 16px;border:0;border-radius:10px;font-family:'SF Pro Display',-apple-system,BlinkMacSystemFont,sans-serif;font-size:15px;font-weight:600;cursor:pointer;transition:opacity .15s ease}.sv-comment-dialog__btn:disabled{opacity:.6;cursor:not-allowed}.sv-comment-dialog__btn--cancel{background:rgba(0,0,0,.06);color:var(--sv-comment-text)}.sv-comment-dialog__btn--cancel:hover:not(:disabled){background:rgba(0,0,0,.1)}.sv-comment-dialog__btn--danger{background:var(--sv-comment-like-color);color:#fff}.sv-comment-dialog__btn--danger:hover:not(:disabled){opacity:.9}.sv-comment-delete-confirm{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5);z-index:var(--sv-comment-modal-z-index,1100)}.sv-comment-delete-confirm__dialog{background:var(--sv-comment-bg);border-radius:12px;padding:16px;max-width:280px;text-align:center}.sv-comment-delete-confirm__title{font-size:16px;font-weight:600;color:var(--sv-comment-text);margin-bottom:8px}.sv-comment-delete-confirm__text{font-size:14px;color:var(--sv-comment-text-secondary);margin-bottom:16px}.sv-comment-delete-confirm__actions{display:flex;gap:8px}.sv-comment-delete-confirm__btn{flex:1;padding:8px 12px;border:0;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer}.sv-comment-delete-confirm__btn--cancel{background:rgba(0,0,0,.05);color:var(--sv-comment-text)}.sv-comment-delete-confirm__btn--delete{background:var(--sv-comment-like-color);color:#fff}@keyframes sv-skeleton-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}.sv-comment-skeleton-list{display:flex;flex-direction:column}.sv-comment-skeleton{animation:sv-skeleton-fade-in .3s ease}@keyframes sv-skeleton-fade-in{from{opacity:0}to{opacity:1}}.sv-comment-skeleton__avatar{width:40px;height:40px;border-radius:50%;background:linear-gradient(90deg,rgba(0,0,0,.04)25%,rgba(0,0,0,.08)50%,rgba(0,0,0,.04)75%);background-size:200% 100%;animation:sv-skeleton-shimmer 1.5s ease-in-out infinite}.sv-comment-skeleton__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:8px}.sv-comment-skeleton__header{display:flex;align-items:center;gap:12px}.sv-comment-skeleton__author{width:80px;height:14px;border-radius:4px;background:linear-gradient(90deg,rgba(0,0,0,.04)25%,rgba(0,0,0,.08)50%,rgba(0,0,0,.04)75%);background-size:200% 100%;animation:sv-skeleton-shimmer 1.5s ease-in-out infinite;animation-delay:.1s}.sv-comment-skeleton__time{width:40px;height:12px;border-radius:4px;background:linear-gradient(90deg,rgba(0,0,0,.04)25%,rgba(0,0,0,.08)50%,rgba(0,0,0,.04)75%);background-size:200% 100%;animation:sv-skeleton-shimmer 1.5s ease-in-out infinite;animation-delay:.15s}.sv-comment-skeleton__text{display:flex;flex-direction:column;gap:4px}.sv-comment-skeleton__line{height:14px;border-radius:4px;background:linear-gradient(90deg,rgba(0,0,0,.04)25%,rgba(0,0,0,.08)50%,rgba(0,0,0,.04)75%);background-size:200% 100%;animation:sv-skeleton-shimmer 1.5s ease-in-out infinite}.sv-comment-skeleton__line--full{width:100%;animation-delay:.2s}.sv-comment-skeleton__line--medium{width:65%;animation-delay:.25s}.sv-comment-skeleton__actions{display:flex;align-items:center;gap:16px;margin-top:4px}.sv-comment-skeleton__action{width:50px;height:12px;border-radius:4px;background:linear-gradient(90deg,rgba(0,0,0,.04)25%,rgba(0,0,0,.08)50%,rgba(0,0,0,.04)75%);background-size:200% 100%;animation:sv-skeleton-shimmer 1.5s ease-in-out infinite;animation-delay:.3s}`;
1069
+ function AngleDownIcon({ className }) {
1070
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className, viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx(
1071
+ "path",
1072
+ {
1073
+ fillRule: "evenodd",
1074
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
1075
+ clipRule: "evenodd"
1076
+ }
1077
+ ) });
1078
+ }
1079
+ function CloseIcon2({ className, style }) {
1080
+ return /* @__PURE__ */ jsxs(
1081
+ "svg",
1082
+ {
1083
+ "aria-hidden": "true",
1084
+ className,
1085
+ style,
1086
+ viewBox: "0 0 24 24",
1087
+ fill: "none",
1088
+ stroke: "currentColor",
1089
+ strokeWidth: "2",
1090
+ strokeLinecap: "round",
1091
+ strokeLinejoin: "round",
1092
+ children: [
1093
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1094
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1095
+ ]
1096
+ }
1097
+ );
1098
+ }
1099
+ function formatCount2(count) {
1100
+ if (count >= 1e6) {
1101
+ return `${(count / 1e6).toFixed(1)}M`;
1102
+ }
1103
+ if (count >= 1e3) {
1104
+ return `${(count / 1e3).toFixed(1)}K`;
1105
+ }
1106
+ return String(count);
1107
+ }
1108
+ var SheetHeader = memo(function SheetHeader2({
1109
+ titleLabel = "Comments",
1110
+ showHandle = false,
1111
+ showSort = true,
1112
+ onSortClick,
1113
+ closeIcon,
1114
+ className,
1115
+ sortAriaLabel = "Sort comments",
1116
+ closeAriaLabel = "Close comments"
1117
+ }) {
1118
+ const { state, initialCount } = useCommentSheetContext();
1119
+ const { onClose } = useBottomSheetContext();
1120
+ const totalCount = state.totalCount > 0 ? state.totalCount : initialCount ?? 0;
1121
+ return /* @__PURE__ */ jsxs("div", { className: clsx("sv-comment-sheet__header", className), children: [
1122
+ showHandle && /* @__PURE__ */ jsx("div", { className: "sv-comment-sheet__header-handle" }),
1123
+ /* @__PURE__ */ jsxs("div", { className: "sv-comment-sheet__header-left", children: [
1124
+ /* @__PURE__ */ jsxs("h2", { className: "sv-comment-sheet__title", children: [
1125
+ formatCount2(totalCount),
1126
+ " ",
1127
+ titleLabel
1128
+ ] }),
1129
+ showSort && /* @__PURE__ */ jsx(
1130
+ "button",
1131
+ {
1132
+ type: "button",
1133
+ className: "sv-comment-sheet__sort-btn",
1134
+ onClick: onSortClick,
1135
+ "aria-label": sortAriaLabel,
1136
+ children: /* @__PURE__ */ jsx(AngleDownIcon, {})
1137
+ }
1138
+ )
1139
+ ] }),
1140
+ /* @__PURE__ */ jsx(
1141
+ "button",
1142
+ {
1143
+ type: "button",
1144
+ className: "sv-comment-sheet__close-btn",
1145
+ onClick: onClose,
1146
+ "aria-label": closeAriaLabel,
1147
+ children: closeIcon ?? /* @__PURE__ */ jsx(CloseIcon2, {})
1148
+ }
1149
+ )
1150
+ ] });
1151
+ });
1152
+ SheetHeader.displayName = "SheetHeader";
1153
+ var cssInjected = false;
1154
+ function injectCSS() {
1155
+ if (cssInjected || typeof document === "undefined") return;
1156
+ const styleId = "sv-comment-sheet-styles";
1157
+ if (!document.getElementById(styleId)) {
1158
+ const style = document.createElement("style");
1159
+ style.id = styleId;
1160
+ style.textContent = COMMENT_SHEET_CSS;
1161
+ document.head.appendChild(style);
1162
+ }
1163
+ cssInjected = true;
1164
+ }
1165
+ var DEFAULT_CONFIG = {
1166
+ pageSize: 20,
1167
+ replyPageSize: 10,
1168
+ cacheTTL: 5 * 60 * 1e3,
1169
+ repliesAutoExpandThreshold: 1,
1170
+ repliesCollapseLimit: 3,
1171
+ textMaxLines: 3,
1172
+ inputMaxLength: 500,
1173
+ enableOptimisticUI: true,
1174
+ requireDeleteConfirm: true
1175
+ };
1176
+ var DEFAULT_I18N = {
1177
+ expandText: "See more",
1178
+ collapseText: "See less",
1179
+ viewRepliesText: "View {count} more replies",
1180
+ hideRepliesText: "Hide replies",
1181
+ loadRepliesText: "Load replies",
1182
+ viewMoreRepliesText: "View more replies"
1183
+ };
1184
+ var CommentSheetHeadless = memo(function CommentSheetHeadless2({
1185
+ isOpen,
1186
+ onClose,
1187
+ videoId,
1188
+ state,
1189
+ actions,
1190
+ config: configOverride,
1191
+ initialCount,
1192
+ children,
1193
+ className,
1194
+ backdropClassName,
1195
+ closeOnBackdropClick = true,
1196
+ closeOnEscape = true,
1197
+ enableDragToDismiss = true,
1198
+ dragCloseThreshold = 150,
1199
+ i18n: i18nOverride
1200
+ }) {
1201
+ useEffect(() => {
1202
+ injectCSS();
1203
+ }, []);
1204
+ const [replyTarget, setReplyTarget] = useState(null);
1205
+ const config = useMemo(() => ({ ...DEFAULT_CONFIG, ...configOverride }), [configOverride]);
1206
+ const i18n = useMemo(() => ({ ...DEFAULT_I18N, ...i18nOverride }), [i18nOverride]);
1207
+ useEffect(() => {
1208
+ if (!isOpen) {
1209
+ setReplyTarget(null);
1210
+ }
1211
+ }, [isOpen]);
1212
+ const contextValue = useMemo(
1213
+ () => ({
1214
+ state,
1215
+ actions,
1216
+ videoId,
1217
+ config,
1218
+ isOpen,
1219
+ onClose,
1220
+ replyTarget,
1221
+ setReplyTarget,
1222
+ initialCount,
1223
+ i18n
1224
+ }),
1225
+ [state, actions, videoId, config, isOpen, onClose, replyTarget, initialCount, i18n]
1226
+ );
1227
+ const defaultChildren = /* @__PURE__ */ jsxs(Fragment, { children: [
1228
+ /* @__PURE__ */ jsx(SheetHeader, {}),
1229
+ /* @__PURE__ */ jsx(CommentList, {}),
1230
+ /* @__PURE__ */ jsx(CommentInput, {})
1231
+ ] });
1232
+ return /* @__PURE__ */ jsx(CommentSheetContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
1233
+ BottomSheetHeadless,
1234
+ {
1235
+ isOpen,
1236
+ onClose,
1237
+ height: "var(--sv-comment-sheet-height, 55vh)",
1238
+ className: clsx("sv-comment-sheet", className),
1239
+ backdropClassName: clsx("sv-comment-sheet-backdrop", backdropClassName),
1240
+ contentClassName: "sv-comment-sheet__content",
1241
+ closeOnBackdropClick,
1242
+ closeOnEscape,
1243
+ showDragHandle: false,
1244
+ enableDragToDismiss,
1245
+ dragCloseThreshold,
1246
+ ariaLabel: "Comments",
1247
+ dragHandleSelector: ".sv-comment-sheet__header",
1248
+ scrollContainerSelector: ".sv-comment-sheet__list",
1249
+ dragExcludeSelector: ".sv-comment-sheet__input-container",
1250
+ children: children ?? defaultChildren
1251
+ }
1252
+ ) });
1253
+ });
1254
+ CommentSheetHeadless.displayName = "CommentSheetHeadless";
1255
+ var CommentSheet = Object.assign(CommentSheetHeadless, {
1256
+ Header: SheetHeader,
1257
+ List: CommentList,
1258
+ Input: CommentInput,
1259
+ Item: CommentItemComponent
1260
+ });
1261
+
1262
+ export { COMMENT_SHEET_CSS, CommentInput, CommentItemComponent, CommentItemSkeleton, CommentList, CommentListSkeleton, CommentMenu, CommentSheet, CommentSheetContext, CommentSheetHeadless, DeleteConfirmDialog, SheetHeader, useCommentMenuContext, useCommentSheetContext, useOptionalCommentSheetContext };