@xhub-short/ui 0.1.0-beta.8 → 0.1.0-beta.9

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 (28) hide show
  1. package/dist/{CommentSheet.css-BD6XbpU2.d.ts → CommentSheet.css-BeCrEaUG.d.ts} +15 -1
  2. package/dist/{chunk-K3CETRCY.js → chunk-2FSDVYER.js} +1 -1
  3. package/dist/{chunk-CXPNPSF7.js → chunk-AC2IFAJR.js} +1 -1
  4. package/dist/{chunk-OQ7P5XC7.js → chunk-AQHD6LPS.js} +1 -1
  5. package/dist/{chunk-NRQXKZO3.js → chunk-CL6BS7GB.js} +1 -1
  6. package/dist/{chunk-EBAMBI3O.js → chunk-ECR42RKK.js} +1 -1
  7. package/dist/{chunk-UXNIXHII.js → chunk-FNXTPQ6L.js} +610 -77
  8. package/dist/{chunk-RKS7YA7Z.js → chunk-KWHMZ6H5.js} +1 -1
  9. package/dist/{chunk-UPCVSGWH.js → chunk-RMLTPW5S.js} +3 -1
  10. package/dist/{chunk-YWAPI7JO.js → chunk-SZXFH334.js} +1 -1
  11. package/dist/{chunk-PGHLVKXS.js → chunk-UNV3NWN6.js} +1 -1
  12. package/dist/{chunk-QF7O26KZ.js → chunk-WCRDTBCZ.js} +2 -2
  13. package/dist/{chunk-T4RQWGRY.js → chunk-XDIH66C4.js} +1 -1
  14. package/dist/components/ActionBar/index.js +1 -1
  15. package/dist/components/AuthorInfo/index.js +1 -1
  16. package/dist/components/CommentSheet/index.d.ts +155 -3
  17. package/dist/components/CommentSheet/index.js +1 -1
  18. package/dist/components/ErrorBoundary/index.js +1 -1
  19. package/dist/components/ProgressBar/index.js +1 -1
  20. package/dist/components/Skeleton/index.js +1 -1
  21. package/dist/components/VideoFeed/index.js +1 -1
  22. package/dist/components/VideoInfo/index.js +1 -1
  23. package/dist/components/VideoPlayer/index.js +1 -1
  24. package/dist/components/VideoSlot/index.js +1 -1
  25. package/dist/components/VirtualSlider/index.js +1 -1
  26. package/dist/index.d.ts +35 -2
  27. package/dist/index.js +29 -15
  28. package/package.json +4 -4
@@ -243,39 +243,442 @@ var CommentInput = memo(function CommentInput2({
243
243
  ] });
244
244
  });
245
245
  CommentInput.displayName = "CommentInput";
246
- function PinIcon({ className }) {
247
- 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" }) });
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
+ ] });
248
252
  }
249
- function HeartIcon({ filled, className }) {
250
- if (filled) {
251
- return /* @__PURE__ */ jsx(
252
- "svg",
253
- {
254
- xmlns: "http://www.w3.org/2000/svg",
255
- "aria-label": "Heart icon",
256
- "aria-hidden": "true",
257
- className,
258
- viewBox: "0 0 24 24",
259
- fill: "currentColor",
260
- children: /* @__PURE__ */ jsx("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })
261
- }
262
- );
263
- }
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 }) {
264
296
  return /* @__PURE__ */ jsx(
265
297
  "svg",
266
298
  {
267
- xmlns: "http://www.w3.org/2000/svg",
268
- "aria-label": "Heart icon",
269
299
  "aria-hidden": "true",
270
300
  className,
271
301
  viewBox: "0 0 24 24",
272
302
  fill: "none",
273
303
  stroke: "currentColor",
274
304
  strokeWidth: "1.5",
275
- children: /* @__PURE__ */ jsx("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })
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
+ ]
276
636
  }
277
637
  );
278
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
+ }
279
682
  function ReplyIcon({ className }) {
280
683
  return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", className, viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx(
281
684
  "path",
@@ -289,13 +692,6 @@ function ReplyIcon({ className }) {
289
692
  function VerifiedIcon({ className }) {
290
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" }) });
291
694
  }
292
- function MoreIcon({ className }) {
293
- return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", className, viewBox: "0 0 24 24", fill: "currentColor", children: [
294
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.5" }),
295
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "6", r: "1.5" }),
296
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "18", r: "1.5" })
297
- ] });
298
- }
299
695
  function ChevronIcon({ direction, className }) {
300
696
  return /* @__PURE__ */ jsx(
301
697
  "svg",
@@ -408,14 +804,8 @@ var ReplyItemComponent = memo(function ReplyItemComponent2({
408
804
  reply,
409
805
  parentComment
410
806
  }) {
411
- const { actions, setReplyTarget } = useCommentSheetContext();
412
- const handleLike = useCallback(() => {
413
- if (reply.isLiked) {
414
- actions.unlikeComment(reply.id);
415
- } else {
416
- actions.likeComment(reply.id);
417
- }
418
- }, [actions, reply.id, reply.isLiked]);
807
+ const { setReplyTarget, i18n } = useCommentSheetContext();
808
+ const formatTimeAgo = i18n.formatRelativeTime ?? defaultFormatTimeAgo;
419
809
  const handleReply = useCallback(() => {
420
810
  setReplyTarget({
421
811
  commentId: parentComment.id,
@@ -431,7 +821,10 @@ var ReplyItemComponent = memo(function ReplyItemComponent2({
431
821
  /* @__PURE__ */ jsx("span", { className: "sv-comment-item__author", children: reply.author.name }),
432
822
  reply.author.isVerified && /* @__PURE__ */ jsx(VerifiedIcon, { className: "sv-comment-item__verified" })
433
823
  ] }),
434
- /* @__PURE__ */ jsx("button", { type: "button", className: "sv-comment-item__menu-btn", "aria-label": "More options", children: /* @__PURE__ */ jsx(MoreIcon, {}) })
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
+ ] })
435
828
  ] }),
436
829
  /* @__PURE__ */ jsxs("p", { className: "sv-comment-item__text", children: [
437
830
  reply.replyTo && reply.replyTo.id !== parentComment.author.id && /* @__PURE__ */ jsxs("span", { className: "sv-comment-reply__mention", children: [
@@ -442,21 +835,7 @@ var ReplyItemComponent = memo(function ReplyItemComponent2({
442
835
  reply.content
443
836
  ] }),
444
837
  /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__actions", children: [
445
- /* @__PURE__ */ jsxs(
446
- "button",
447
- {
448
- type: "button",
449
- className: clsx(
450
- "sv-comment-item__action-btn",
451
- reply.isLiked && "sv-comment-item__action-btn--active"
452
- ),
453
- onClick: handleLike,
454
- children: [
455
- /* @__PURE__ */ jsx(HeartIcon, { filled: reply.isLiked, className: "sv-comment-item__action-icon" }),
456
- reply.likeCount > 0 && /* @__PURE__ */ jsx("span", { children: formatCount(reply.likeCount) })
457
- ]
458
- }
459
- ),
838
+ /* @__PURE__ */ jsx("span", { className: "sv-comment-item__time", children: formatTimeAgo(reply.createdAt) }),
460
839
  /* @__PURE__ */ jsx("button", { type: "button", className: "sv-comment-item__action-btn", onClick: handleReply, children: /* @__PURE__ */ jsx(ReplyIcon, { className: "sv-comment-item__action-icon" }) })
461
840
  ] })
462
841
  ] })
@@ -525,17 +904,10 @@ var CommentItemComponent = memo(function CommentItemComponent2({
525
904
  comment,
526
905
  className
527
906
  }) {
528
- const { actions, config, setReplyTarget, i18n } = useCommentSheetContext();
907
+ const { config, setReplyTarget, i18n } = useCommentSheetContext();
529
908
  const expandText = i18n.expandText ?? "See more";
530
909
  const collapseText = i18n.collapseText ?? "See less";
531
910
  const formatTimeAgo = i18n.formatRelativeTime ?? defaultFormatTimeAgo;
532
- const handleLike = useCallback(() => {
533
- if (comment.isLiked) {
534
- actions.unlikeComment(comment.id);
535
- } else {
536
- actions.likeComment(comment.id);
537
- }
538
- }, [actions, comment.id, comment.isLiked]);
539
911
  const handleReply = useCallback(() => {
540
912
  setReplyTarget({
541
913
  commentId: comment.id,
@@ -564,7 +936,10 @@ var CommentItemComponent = memo(function CommentItemComponent2({
564
936
  comment.author.isVerified && /* @__PURE__ */ jsx(VerifiedIcon, { className: "sv-comment-item__verified" }),
565
937
  comment.author.badge && /* @__PURE__ */ jsx("span", { className: "sv-comment-item__badge", children: comment.author.badge })
566
938
  ] }),
567
- /* @__PURE__ */ jsx("button", { type: "button", className: "sv-comment-item__menu-btn", "aria-label": "More options", children: /* @__PURE__ */ jsx(MoreIcon, {}) })
939
+ comment.isOwner && /* @__PURE__ */ jsxs(CommentMenu, { comment, children: [
940
+ /* @__PURE__ */ jsx(CommentMenu.Trigger, {}),
941
+ /* @__PURE__ */ jsx(CommentMenu.Dropdown, { children: /* @__PURE__ */ jsx(CommentMenu.DeleteItem, {}) })
942
+ ] })
568
943
  ] }),
569
944
  /* @__PURE__ */ jsx(
570
945
  CommentText,
@@ -577,21 +952,6 @@ var CommentItemComponent = memo(function CommentItemComponent2({
577
952
  ),
578
953
  /* @__PURE__ */ jsxs("div", { className: "sv-comment-item__actions", children: [
579
954
  /* @__PURE__ */ jsx("span", { className: "sv-comment-item__time", children: formatTimeAgo(comment.createdAt) }),
580
- /* @__PURE__ */ jsxs(
581
- "button",
582
- {
583
- type: "button",
584
- className: clsx(
585
- "sv-comment-item__action-btn",
586
- comment.isLiked && "sv-comment-item__action-btn--active"
587
- ),
588
- onClick: handleLike,
589
- children: [
590
- /* @__PURE__ */ jsx(HeartIcon, { filled: comment.isLiked, className: "sv-comment-item__action-icon" }),
591
- comment.likeCount > 0 && /* @__PURE__ */ jsx("span", { children: formatCount(comment.likeCount) })
592
- ]
593
- }
594
- ),
595
955
  /* @__PURE__ */ jsxs("button", { type: "button", className: "sv-comment-item__action-btn", onClick: handleReply, children: [
596
956
  /* @__PURE__ */ jsx(ReplyIcon, { className: "sv-comment-item__action-icon" }),
597
957
  comment.replyCount > 0 && /* @__PURE__ */ jsx("span", { children: formatCount(comment.replyCount) })
@@ -1435,9 +1795,182 @@ body.sv-comment-sheet-open .sv-comment-sheet-backdrop {
1435
1795
  }
1436
1796
 
1437
1797
  /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1438
- DELETE CONFIRMATION
1798
+ COMMENT MENU (Dropdown)
1439
1799
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
1440
1800
 
1801
+ .sv-comment-menu {
1802
+ position: relative;
1803
+ }
1804
+
1805
+ .sv-comment-menu__trigger {
1806
+ display: flex;
1807
+ align-items: center;
1808
+ justify-content: center;
1809
+ background: none;
1810
+ border: none;
1811
+ padding: 4px;
1812
+ cursor: pointer;
1813
+ color: var(--sv-comment-text-secondary);
1814
+ border-radius: 4px;
1815
+ transition: background 0.15s ease;
1816
+ }
1817
+
1818
+ .sv-comment-menu__trigger:hover {
1819
+ background: rgba(0, 0, 0, 0.05);
1820
+ }
1821
+
1822
+ .sv-comment-menu__icon {
1823
+ width: 20px;
1824
+ height: 20px;
1825
+ }
1826
+
1827
+ .sv-comment-menu__dropdown {
1828
+ position: absolute;
1829
+ top: 100%;
1830
+ right: 0;
1831
+ margin-top: 4px;
1832
+ min-width: 140px;
1833
+ background: var(--sv-comment-bg);
1834
+ border: 1px solid var(--sv-comment-border);
1835
+ border-radius: 8px;
1836
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1837
+ z-index: 10;
1838
+ overflow: hidden;
1839
+ animation: sv-menu-fade-in 0.15s ease;
1840
+ }
1841
+
1842
+ @keyframes sv-menu-fade-in {
1843
+ from { opacity: 0; transform: translateY(-4px); }
1844
+ to { opacity: 1; transform: translateY(0); }
1845
+ }
1846
+
1847
+ .sv-comment-menu__item {
1848
+ display: flex;
1849
+ align-items: center;
1850
+ gap: 8px;
1851
+ width: 100%;
1852
+ padding: 10px 12px;
1853
+ background: none;
1854
+ border: none;
1855
+ cursor: pointer;
1856
+ font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
1857
+ font-size: 14px;
1858
+ font-weight: 500;
1859
+ color: var(--sv-comment-text);
1860
+ text-align: left;
1861
+ transition: background 0.15s ease;
1862
+ }
1863
+
1864
+ .sv-comment-menu__item:hover {
1865
+ background: rgba(0, 0, 0, 0.05);
1866
+ }
1867
+
1868
+ .sv-comment-menu__item--danger {
1869
+ color: var(--sv-comment-like-color);
1870
+ }
1871
+
1872
+ .sv-comment-menu__item--danger:hover {
1873
+ background: rgba(255, 67, 78, 0.08);
1874
+ }
1875
+
1876
+ .sv-comment-menu__item-icon {
1877
+ width: 18px;
1878
+ height: 18px;
1879
+ flex-shrink: 0;
1880
+ }
1881
+
1882
+ /* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1883
+ DELETE CONFIRMATION DIALOG
1884
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
1885
+
1886
+ .sv-comment-dialog-overlay {
1887
+ position: fixed;
1888
+ inset: 0;
1889
+ display: flex;
1890
+ align-items: center;
1891
+ justify-content: center;
1892
+ background: rgba(0, 0, 0, 0.5);
1893
+ z-index: var(--sv-comment-modal-z-index, 1100);
1894
+ animation: sv-dialog-overlay-fade-in 0.2s ease;
1895
+ }
1896
+
1897
+ @keyframes sv-dialog-overlay-fade-in {
1898
+ from { opacity: 0; }
1899
+ to { opacity: 1; }
1900
+ }
1901
+
1902
+ .sv-comment-dialog {
1903
+ background: var(--sv-comment-bg);
1904
+ border-radius: 16px;
1905
+ padding: 24px;
1906
+ max-width: 300px;
1907
+ width: calc(100% - 48px);
1908
+ text-align: center;
1909
+ animation: sv-dialog-scale-in 0.2s ease;
1910
+ }
1911
+
1912
+ @keyframes sv-dialog-scale-in {
1913
+ from { opacity: 0; transform: scale(0.95); }
1914
+ to { opacity: 1; transform: scale(1); }
1915
+ }
1916
+
1917
+ .sv-comment-dialog__title {
1918
+ font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
1919
+ font-size: 17px;
1920
+ font-weight: 600;
1921
+ color: var(--sv-comment-text);
1922
+ margin: 0 0 8px 0;
1923
+ }
1924
+
1925
+ .sv-comment-dialog__message {
1926
+ font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
1927
+ font-size: 14px;
1928
+ color: var(--sv-comment-text-secondary);
1929
+ margin: 0 0 20px 0;
1930
+ line-height: 1.4;
1931
+ }
1932
+
1933
+ .sv-comment-dialog__actions {
1934
+ display: flex;
1935
+ gap: 12px;
1936
+ }
1937
+
1938
+ .sv-comment-dialog__btn {
1939
+ flex: 1;
1940
+ padding: 12px 16px;
1941
+ border: none;
1942
+ border-radius: 10px;
1943
+ font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
1944
+ font-size: 15px;
1945
+ font-weight: 600;
1946
+ cursor: pointer;
1947
+ transition: opacity 0.15s ease;
1948
+ }
1949
+
1950
+ .sv-comment-dialog__btn:disabled {
1951
+ opacity: 0.6;
1952
+ cursor: not-allowed;
1953
+ }
1954
+
1955
+ .sv-comment-dialog__btn--cancel {
1956
+ background: rgba(0, 0, 0, 0.06);
1957
+ color: var(--sv-comment-text);
1958
+ }
1959
+
1960
+ .sv-comment-dialog__btn--cancel:hover:not(:disabled) {
1961
+ background: rgba(0, 0, 0, 0.1);
1962
+ }
1963
+
1964
+ .sv-comment-dialog__btn--danger {
1965
+ background: var(--sv-comment-like-color);
1966
+ color: #ffffff;
1967
+ }
1968
+
1969
+ .sv-comment-dialog__btn--danger:hover:not(:disabled) {
1970
+ opacity: 0.9;
1971
+ }
1972
+
1973
+ /* Legacy classes (keep for backwards compatibility) */
1441
1974
  .sv-comment-delete-confirm {
1442
1975
  position: fixed;
1443
1976
  inset: 0;
@@ -2037,4 +2570,4 @@ var CommentSheet = Object.assign(CommentSheetHeadless, {
2037
2570
  Item: CommentItemComponent
2038
2571
  });
2039
2572
 
2040
- export { COMMENT_SHEET_CSS, CommentInput, CommentItemComponent, CommentItemSkeleton, CommentList, CommentListSkeleton, CommentSheet, CommentSheetContext, CommentSheetHeadless, SheetHeader, useCommentSheetContext, useOptionalCommentSheetContext };
2573
+ export { COMMENT_SHEET_CSS, CommentInput, CommentItemComponent, CommentItemSkeleton, CommentList, CommentListSkeleton, CommentMenu, CommentSheet, CommentSheetContext, CommentSheetHeadless, DeleteConfirmDialog, SheetHeader, useCommentMenuContext, useCommentSheetContext, useOptionalCommentSheetContext };