@mieweb/ui 0.8.0-dev.0 → 0.8.0-dev.1

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 (110) hide show
  1. package/dist/{chunk-IILJGFI5.js → chunk-2AB4PQYL.js} +3 -3
  2. package/dist/{chunk-IILJGFI5.js.map → chunk-2AB4PQYL.js.map} +1 -1
  3. package/dist/{chunk-SK7H3Z67.cjs → chunk-2PEVRI26.cjs} +8 -8
  4. package/dist/{chunk-SK7H3Z67.cjs.map → chunk-2PEVRI26.cjs.map} +1 -1
  5. package/dist/{chunk-JHGMZX4I.cjs → chunk-2SSAAE3I.cjs} +4 -4
  6. package/dist/{chunk-JHGMZX4I.cjs.map → chunk-2SSAAE3I.cjs.map} +1 -1
  7. package/dist/{chunk-LQHI44OZ.cjs → chunk-3RADKLLD.cjs} +5 -5
  8. package/dist/{chunk-LQHI44OZ.cjs.map → chunk-3RADKLLD.cjs.map} +1 -1
  9. package/dist/{chunk-L6D4CKLV.cjs → chunk-5BPUZK2B.cjs} +15 -2
  10. package/dist/chunk-5BPUZK2B.cjs.map +1 -0
  11. package/dist/{chunk-XWYKLEKG.js → chunk-6GKX36JX.js} +3 -3
  12. package/dist/{chunk-XWYKLEKG.js.map → chunk-6GKX36JX.js.map} +1 -1
  13. package/dist/{chunk-ELYGV32O.cjs → chunk-AHHFFXJR.cjs} +4 -4
  14. package/dist/{chunk-ELYGV32O.cjs.map → chunk-AHHFFXJR.cjs.map} +1 -1
  15. package/dist/{chunk-LZU7YBXG.js → chunk-AHUYW673.js} +167 -8
  16. package/dist/chunk-AHUYW673.js.map +1 -0
  17. package/dist/{chunk-MYFZYUPR.cjs → chunk-AOHJILLU.cjs} +38 -3
  18. package/dist/chunk-AOHJILLU.cjs.map +1 -0
  19. package/dist/{chunk-XBKOZRDO.js → chunk-ATOWMVZH.js} +3 -3
  20. package/dist/{chunk-XBKOZRDO.js.map → chunk-ATOWMVZH.js.map} +1 -1
  21. package/dist/{chunk-4PIW3Y5M.js → chunk-DJ4JPFWI.js} +3 -3
  22. package/dist/{chunk-4PIW3Y5M.js.map → chunk-DJ4JPFWI.js.map} +1 -1
  23. package/dist/{chunk-FDV7EQWH.js → chunk-EK6DYGFG.js} +3 -3
  24. package/dist/{chunk-FDV7EQWH.js.map → chunk-EK6DYGFG.js.map} +1 -1
  25. package/dist/{chunk-IYXCFIMP.js → chunk-F2S6NV5N.js} +4 -4
  26. package/dist/{chunk-IYXCFIMP.js.map → chunk-F2S6NV5N.js.map} +1 -1
  27. package/dist/{chunk-26DPQUSB.cjs → chunk-G52YRAJC.cjs} +4 -4
  28. package/dist/{chunk-26DPQUSB.cjs.map → chunk-G52YRAJC.cjs.map} +1 -1
  29. package/dist/{chunk-QHTDWIED.js → chunk-JQQABHDN.js} +3 -3
  30. package/dist/{chunk-QHTDWIED.js.map → chunk-JQQABHDN.js.map} +1 -1
  31. package/dist/{chunk-7L7OPISJ.cjs → chunk-JR4QIU54.cjs} +4 -4
  32. package/dist/{chunk-7L7OPISJ.cjs.map → chunk-JR4QIU54.cjs.map} +1 -1
  33. package/dist/{chunk-56QJHQ5C.cjs → chunk-K5GQPTTA.cjs} +4 -4
  34. package/dist/{chunk-56QJHQ5C.cjs.map → chunk-K5GQPTTA.cjs.map} +1 -1
  35. package/dist/{chunk-XMECP2MD.js → chunk-KFEN2SRZ.js} +3 -3
  36. package/dist/{chunk-XMECP2MD.js.map → chunk-KFEN2SRZ.js.map} +1 -1
  37. package/dist/{chunk-RYQ3S3KO.cjs → chunk-LDCFNWJC.cjs} +5 -5
  38. package/dist/{chunk-RYQ3S3KO.cjs.map → chunk-LDCFNWJC.cjs.map} +1 -1
  39. package/dist/{chunk-A5YOIJKL.js → chunk-LDQ2T27A.js} +3 -3
  40. package/dist/{chunk-A5YOIJKL.js.map → chunk-LDQ2T27A.js.map} +1 -1
  41. package/dist/{chunk-SPWVKDGC.cjs → chunk-QMKYJ4AT.cjs} +4 -4
  42. package/dist/{chunk-SPWVKDGC.cjs.map → chunk-QMKYJ4AT.cjs.map} +1 -1
  43. package/dist/{chunk-BOW7ZGI2.cjs → chunk-QOJ4V7YX.cjs} +168 -8
  44. package/dist/chunk-QOJ4V7YX.cjs.map +1 -0
  45. package/dist/{chunk-QGZC43L7.js → chunk-SVZ4MQVQ.js} +3 -3
  46. package/dist/{chunk-QGZC43L7.js.map → chunk-SVZ4MQVQ.js.map} +1 -1
  47. package/dist/{chunk-KVE7PQ5P.cjs → chunk-TQZPYDUL.cjs} +7 -7
  48. package/dist/{chunk-KVE7PQ5P.cjs.map → chunk-TQZPYDUL.cjs.map} +1 -1
  49. package/dist/{chunk-EKRT7K2K.js → chunk-UJS3JTVT.js} +3 -3
  50. package/dist/{chunk-EKRT7K2K.js.map → chunk-UJS3JTVT.js.map} +1 -1
  51. package/dist/{chunk-AESFOMSH.js → chunk-VQ5HJCTP.js} +15 -2
  52. package/dist/chunk-VQ5HJCTP.js.map +1 -0
  53. package/dist/{chunk-BOOJDRJO.js → chunk-WSNMQQ4P.js} +38 -3
  54. package/dist/chunk-WSNMQQ4P.js.map +1 -0
  55. package/dist/{chunk-U5TTXN45.cjs → chunk-YRLCR76L.cjs} +4 -4
  56. package/dist/{chunk-U5TTXN45.cjs.map → chunk-YRLCR76L.cjs.map} +1 -1
  57. package/dist/components/Autocomplete/index.cjs +3 -3
  58. package/dist/components/Autocomplete/index.js +2 -2
  59. package/dist/components/CountryCodeDropdown/index.cjs +5 -5
  60. package/dist/components/CountryCodeDropdown/index.js +2 -2
  61. package/dist/components/DateInput/index.cjs +3 -3
  62. package/dist/components/DateInput/index.js +2 -2
  63. package/dist/components/Dropdown/index.cjs +12 -8
  64. package/dist/components/Dropdown/index.d.cts +38 -2
  65. package/dist/components/Dropdown/index.d.ts +38 -2
  66. package/dist/components/Dropdown/index.js +2 -2
  67. package/dist/components/GlossaryTooltip/index.cjs +3 -3
  68. package/dist/components/GlossaryTooltip/index.js +2 -2
  69. package/dist/components/MediaEditor/index.cjs +8 -8
  70. package/dist/components/MediaEditor/index.js +3 -3
  71. package/dist/components/RichTextEditor/index.cjs +6 -6
  72. package/dist/components/RichTextEditor/index.js +3 -3
  73. package/dist/components/Select/index.cjs +4 -4
  74. package/dist/components/Select/index.js +2 -2
  75. package/dist/components/SourceTip/index.cjs +3 -3
  76. package/dist/components/SourceTip/index.js +2 -2
  77. package/dist/components/SuperChat/index.cjs +249 -91
  78. package/dist/components/SuperChat/index.cjs.map +1 -1
  79. package/dist/components/SuperChat/index.d.cts +13 -5
  80. package/dist/components/SuperChat/index.d.ts +13 -5
  81. package/dist/components/SuperChat/index.js +246 -88
  82. package/dist/components/SuperChat/index.js.map +1 -1
  83. package/dist/components/SuperChat/plugins/index.cjs +4 -4
  84. package/dist/components/SuperChat/plugins/index.d.cts +2 -2
  85. package/dist/components/SuperChat/plugins/index.d.ts +2 -2
  86. package/dist/components/SuperChat/plugins/index.js +3 -3
  87. package/dist/esheet.cjs +7 -7
  88. package/dist/esheet.js +4 -4
  89. package/dist/hooks/index.cjs +2 -2
  90. package/dist/hooks/index.d.cts +1 -1
  91. package/dist/hooks/index.d.ts +1 -1
  92. package/dist/hooks/index.js +1 -1
  93. package/dist/index.cjs +178 -174
  94. package/dist/index.d.cts +2 -2
  95. package/dist/index.d.ts +2 -2
  96. package/dist/index.js +22 -22
  97. package/dist/styles.css +1 -1
  98. package/dist/tailwind-preset.cjs +4 -4
  99. package/dist/tailwind-preset.js +1 -1
  100. package/dist/{types-BoTeTPdH.d.ts → types-9vK_YdEb.d.ts} +12 -1
  101. package/dist/{types-DyIB9HYT.d.cts → types-DZDroUW8.d.cts} +12 -1
  102. package/dist/{useAnchoredPosition-C7PNglzD.d.cts → useAnchoredPosition-CKwLSQW8.d.cts} +10 -3
  103. package/dist/{useAnchoredPosition-C7PNglzD.d.ts → useAnchoredPosition-CKwLSQW8.d.ts} +10 -3
  104. package/package.json +1 -1
  105. package/dist/chunk-AESFOMSH.js.map +0 -1
  106. package/dist/chunk-BOOJDRJO.js.map +0 -1
  107. package/dist/chunk-BOW7ZGI2.cjs.map +0 -1
  108. package/dist/chunk-L6D4CKLV.cjs.map +0 -1
  109. package/dist/chunk-LZU7YBXG.js.map +0 -1
  110. package/dist/chunk-MYFZYUPR.cjs.map +0 -1
@@ -2,8 +2,8 @@
2
2
 
3
3
  var chunkJFLC7SHM_cjs = require('../../chunk-JFLC7SHM.cjs');
4
4
  var chunkXS35KPBZ_cjs = require('../../chunk-XS35KPBZ.cjs');
5
- var chunk26DPQUSB_cjs = require('../../chunk-26DPQUSB.cjs');
6
- var chunkBOW7ZGI2_cjs = require('../../chunk-BOW7ZGI2.cjs');
5
+ var chunkG52YRAJC_cjs = require('../../chunk-G52YRAJC.cjs');
6
+ var chunkQOJ4V7YX_cjs = require('../../chunk-QOJ4V7YX.cjs');
7
7
  require('../../chunk-VBWRH4UW.cjs');
8
8
  require('../../chunk-ZZJ4ZVYR.cjs');
9
9
  var chunkU3JU6BI5_cjs = require('../../chunk-U3JU6BI5.cjs');
@@ -12,9 +12,9 @@ require('../../chunk-Z5S5JEJD.cjs');
12
12
  var chunkYVL3XATO_cjs = require('../../chunk-YVL3XATO.cjs');
13
13
  require('../../chunk-FHY3K6PL.cjs');
14
14
  require('../../chunk-FSGEDDF2.cjs');
15
- require('../../chunk-MYFZYUPR.cjs');
15
+ require('../../chunk-AOHJILLU.cjs');
16
16
  var chunkS5RVSXDV_cjs = require('../../chunk-S5RVSXDV.cjs');
17
- var React4 = require('react');
17
+ var React2 = require('react');
18
18
  var Markdown = require('react-markdown');
19
19
  var remarkGfm = require('remark-gfm');
20
20
  var rehypeSanitize = require('rehype-sanitize');
@@ -43,7 +43,7 @@ function _interopNamespace(e) {
43
43
  return Object.freeze(n);
44
44
  }
45
45
 
46
- var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
46
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
47
47
  var Markdown__default = /*#__PURE__*/_interopDefault(Markdown);
48
48
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
49
49
  var rehypeSanitize__default = /*#__PURE__*/_interopDefault(rehypeSanitize);
@@ -292,7 +292,7 @@ var transformUrl = (url, key, node) => {
292
292
  }
293
293
  return Markdown.defaultUrlTransform(url);
294
294
  };
295
- var MarkdownContent = React4__namespace.memo(function MarkdownContent2({
295
+ var MarkdownContent = React2__namespace.memo(function MarkdownContent2({
296
296
  text,
297
297
  messageId,
298
298
  streaming,
@@ -487,13 +487,19 @@ function filesToComposerAttachments(files) {
487
487
  )
488
488
  );
489
489
  }
490
- function CopyMenu({ isSelf, markdown, getHtml, getText }) {
491
- const [open, setOpen] = React4__namespace.useState(false);
492
- const [copied, setCopied] = React4__namespace.useState(false);
493
- const copiedTimer = React4__namespace.useRef(
490
+ var actionRevealClass = "opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100 focus-visible:opacity-100 [@media(pointer:coarse)]:opacity-100";
491
+ var actionButtonClass = "rounded p-1 text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-200";
492
+ function useMessageCopy({
493
+ markdown,
494
+ getHtml,
495
+ getText,
496
+ defaultFormat
497
+ }) {
498
+ const [copied, setCopied] = React2__namespace.useState(false);
499
+ const copiedTimer = React2__namespace.useRef(
494
500
  void 0
495
501
  );
496
- React4__namespace.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
502
+ React2__namespace.useEffect(() => () => window.clearTimeout(copiedTimer.current), []);
497
503
  const flash = () => {
498
504
  setCopied(true);
499
505
  window.clearTimeout(copiedTimer.current);
@@ -524,21 +530,111 @@ function CopyMenu({ isSelf, markdown, getHtml, getText }) {
524
530
  }
525
531
  };
526
532
  const run = (fn) => {
527
- setOpen(false);
528
533
  void fn().then(flash, () => {
529
534
  });
530
535
  };
536
+ const copyRich = () => run(writeBoth);
537
+ const copyMarkdown = () => run(() => writeText(markdown || getText()));
538
+ const copyPlain = () => run(() => writeText(getText()));
539
+ const copyDefault = defaultFormat === "markdown" ? copyMarkdown : defaultFormat === "plain" ? copyPlain : copyRich;
540
+ return { copied, copyDefault, copyRich, copyMarkdown, copyPlain };
541
+ }
542
+ function ActionMenuItem({
543
+ item,
544
+ onSelect
545
+ }) {
546
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkQOJ4V7YX_cjs.DropdownItem, { onClick: () => onSelect(item.onSelect), children: item.description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col items-start", children: [
547
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: item.label }),
548
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-normal text-neutral-400", children: item.description })
549
+ ] }) : item.label });
550
+ }
551
+ function FooterActionButton({
552
+ action,
553
+ isSelf
554
+ }) {
555
+ const [open, setOpen] = React2__namespace.useState(false);
556
+ const onClickCapture = action.submenu ? (e) => {
557
+ if (e.metaKey || e.ctrlKey) {
558
+ e.preventDefault();
559
+ e.stopPropagation();
560
+ action.onSelect();
561
+ }
562
+ } : void 0;
563
+ const button = /* @__PURE__ */ jsxRuntime.jsx(
564
+ "button",
565
+ {
566
+ type: "button",
567
+ "data-slot": `superchat-action-${action.id}`,
568
+ "aria-label": action.label,
569
+ title: action.title ?? action.label,
570
+ onClick: action.submenu ? void 0 : action.onSelect,
571
+ onClickCapture,
572
+ className: actionButtonClass,
573
+ children: action.icon
574
+ }
575
+ );
576
+ if (!action.submenu) return button;
577
+ return /* @__PURE__ */ jsxRuntime.jsx(
578
+ chunkQOJ4V7YX_cjs.Dropdown,
579
+ {
580
+ open,
581
+ onOpenChange: setOpen,
582
+ placement: isSelf ? "top-end" : "top-start",
583
+ trigger: button,
584
+ children: action.submenu.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
585
+ ActionMenuItem,
586
+ {
587
+ item,
588
+ onSelect: (fn) => {
589
+ setOpen(false);
590
+ fn();
591
+ }
592
+ },
593
+ item.id
594
+ ))
595
+ }
596
+ );
597
+ }
598
+ var MessageActionsBar = React2__namespace.forwardRef(function MessageActionsBar2({ actions, isSelf }, ref) {
599
+ return /* @__PURE__ */ jsxRuntime.jsx(
600
+ "div",
601
+ {
602
+ ref,
603
+ "data-slot": "superchat-message-actions",
604
+ className: chunkS5RVSXDV_cjs.cn(
605
+ "flex items-center gap-0.5",
606
+ isSelf && "justify-end",
607
+ actionRevealClass
608
+ ),
609
+ children: actions.map((action) => /* @__PURE__ */ jsxRuntime.jsx(FooterActionButton, { action, isSelf }, action.id))
610
+ }
611
+ );
612
+ });
613
+ function MessageOverflowMenu({
614
+ isSelf,
615
+ actions,
616
+ footerVisible
617
+ }) {
618
+ const [open, setOpen] = React2__namespace.useState(false);
619
+ const select = (fn) => {
620
+ setOpen(false);
621
+ fn();
622
+ };
531
623
  return /* @__PURE__ */ jsxRuntime.jsx(
532
624
  "div",
533
625
  {
534
626
  className: chunkS5RVSXDV_cjs.cn(
535
- "sticky bottom-2 shrink-0 self-end",
627
+ "sticky bottom-2 shrink-0 self-end transition-opacity",
536
628
  // Rich content (e.g. NITRO tables) layers internals up to z-50, so the
537
629
  // open menu's stacking context must clear that.
538
- open ? "z-[60]" : "z-10"
630
+ open ? "z-[60]" : "z-10",
631
+ // Hand off to the footer bar when it's visible. `invisible` (not
632
+ // just opacity) drops the hidden button from the tab order so
633
+ // keyboard users can't focus an unseen control.
634
+ footerVisible && !open && "pointer-events-none invisible opacity-0"
539
635
  ),
540
- children: /* @__PURE__ */ jsxRuntime.jsxs(
541
- chunkBOW7ZGI2_cjs.Dropdown,
636
+ children: /* @__PURE__ */ jsxRuntime.jsx(
637
+ chunkQOJ4V7YX_cjs.Dropdown,
542
638
  {
543
639
  open,
544
640
  onOpenChange: setOpen,
@@ -547,32 +643,32 @@ function CopyMenu({ isSelf, markdown, getHtml, getText }) {
547
643
  "button",
548
644
  {
549
645
  type: "button",
550
- "data-slot": "superchat-copy-button",
551
- "aria-label": "Copy message",
552
- className: "rounded p-1 text-neutral-400 opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100 hover:text-neutral-600 focus-visible:opacity-100 dark:hover:text-neutral-200",
553
- children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clipboard, { size: 14, "aria-hidden": "true" })
646
+ "data-slot": "superchat-overflow-button",
647
+ "aria-label": "Message actions",
648
+ className: chunkS5RVSXDV_cjs.cn(actionButtonClass, actionRevealClass),
649
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ellipsis, { size: 14, "aria-hidden": "true" })
554
650
  }
555
651
  ),
556
- children: [
557
- /* @__PURE__ */ jsxRuntime.jsx(chunkBOW7ZGI2_cjs.DropdownItem, { onClick: () => run(writeBoth), children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col items-start", children: [
558
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy" }),
559
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-normal text-neutral-400", children: "Rich text + Markdown" })
560
- ] }) }),
561
- /* @__PURE__ */ jsxRuntime.jsx(
562
- chunkBOW7ZGI2_cjs.DropdownItem,
652
+ children: actions.map(
653
+ (action) => action.submenu ? (
654
+ // Actions with variants collapse to just their submenu — a
655
+ // top-level default item would duplicate the flyout's options.
656
+ /* @__PURE__ */ jsxRuntime.jsx(chunkQOJ4V7YX_cjs.DropdownSubmenu, { label: action.submenu.label, children: action.submenu.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(ActionMenuItem, { item, onSelect: select }, item.id)) }, action.id)
657
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
658
+ chunkQOJ4V7YX_cjs.DropdownItem,
563
659
  {
564
- onClick: () => run(() => writeText(markdown || getText())),
565
- children: "Copy as Markdown"
566
- }
567
- ),
568
- /* @__PURE__ */ jsxRuntime.jsx(chunkBOW7ZGI2_cjs.DropdownItem, { onClick: () => run(() => writeText(getText())), children: "Copy as plain text" })
569
- ]
660
+ onClick: () => select(action.onSelect),
661
+ children: action.label
662
+ },
663
+ action.id
664
+ )
665
+ )
570
666
  }
571
667
  )
572
668
  }
573
669
  );
574
670
  }
575
- var MessageRow = React4__namespace.memo(function MessageRow2({
671
+ var MessageRow = React2__namespace.memo(function MessageRow2({
576
672
  message,
577
673
  participant,
578
674
  isSelf,
@@ -580,21 +676,22 @@ var MessageRow = React4__namespace.memo(function MessageRow2({
580
676
  linkBuilder,
581
677
  onReferenceClick,
582
678
  editable,
583
- onMessageEdited
679
+ onMessageEdited,
680
+ defaultCopyFormat = "rich"
584
681
  }) {
585
682
  const streaming = message.status === "streaming";
586
683
  const hasBody = !!message.text || (message.content?.length ?? 0) > 0;
587
- const [isEditing, setIsEditing] = React4__namespace.useState(false);
588
- const [draft, setDraft] = React4__namespace.useState(message.text ?? "");
589
- const editRef = React4__namespace.useRef(null);
590
- const bubbleRef = React4__namespace.useRef(null);
591
- const autosize = React4__namespace.useCallback(() => {
684
+ const [isEditing, setIsEditing] = React2__namespace.useState(false);
685
+ const [draft, setDraft] = React2__namespace.useState(message.text ?? "");
686
+ const editRef = React2__namespace.useRef(null);
687
+ const bubbleRef = React2__namespace.useRef(null);
688
+ const autosize = React2__namespace.useCallback(() => {
592
689
  const el = editRef.current;
593
690
  if (!el) return;
594
691
  el.style.height = "auto";
595
692
  el.style.height = `${el.scrollHeight}px`;
596
693
  }, []);
597
- React4__namespace.useEffect(() => {
694
+ React2__namespace.useEffect(() => {
598
695
  if (!isEditing) return;
599
696
  const el = editRef.current;
600
697
  if (!el) return;
@@ -602,6 +699,37 @@ var MessageRow = React4__namespace.memo(function MessageRow2({
602
699
  el.setSelectionRange(el.value.length, el.value.length);
603
700
  autosize();
604
701
  }, [isEditing, autosize]);
702
+ const canEdit = !!editable && isSelf && !streaming && typeof message.text === "string" && !message.content?.length;
703
+ const markdownSource = typeof message.text === "string" && message.text ? message.text : message.content?.map((block) => {
704
+ if (block.type === "code" && block.text) {
705
+ return `\`\`\`${block.language ?? ""}
706
+ ${block.text}
707
+ \`\`\``;
708
+ }
709
+ if ((block.type === "text" || block.type === "thinking") && block.text) {
710
+ return block.text;
711
+ }
712
+ return "";
713
+ }).filter(Boolean).join("\n\n") ?? "";
714
+ const canCopy = !isEditing && (!!message.content?.length || typeof message.text === "string" && message.text.length > 0);
715
+ const hasActions = canCopy || canEdit && !isEditing;
716
+ const copy = useMessageCopy({
717
+ markdown: markdownSource,
718
+ getHtml: () => bubbleRef.current?.innerHTML ?? "",
719
+ getText: () => bubbleRef.current?.textContent ?? "",
720
+ defaultFormat: defaultCopyFormat
721
+ });
722
+ const actionsBarRef = React2__namespace.useRef(null);
723
+ const [footerVisible, setFooterVisible] = React2__namespace.useState(true);
724
+ React2__namespace.useEffect(() => {
725
+ const el = actionsBarRef.current;
726
+ if (!el || typeof globalThis.IntersectionObserver === "undefined") return;
727
+ const observer = new globalThis.IntersectionObserver(([entry]) => {
728
+ setFooterVisible(entry?.isIntersecting ?? false);
729
+ });
730
+ observer.observe(el);
731
+ return () => observer.disconnect();
732
+ }, [hasActions]);
605
733
  if (message.type === "system") {
606
734
  return /* @__PURE__ */ jsxRuntime.jsx(
607
735
  "div",
@@ -633,7 +761,6 @@ var MessageRow = React4__namespace.memo(function MessageRow2({
633
761
  const accent = participant?.color;
634
762
  const accentTextColor = accessibleAccentTextColor(accent);
635
763
  const authorName = participant?.name ?? "Unknown";
636
- const canEdit = !!editable && isSelf && !streaming && typeof message.text === "string" && !message.content?.length;
637
764
  const startEdit = () => {
638
765
  setDraft(message.text ?? "");
639
766
  setIsEditing(true);
@@ -677,18 +804,46 @@ var MessageRow = React4__namespace.memo(function MessageRow2({
677
804
  requestAnimationFrame(autosize);
678
805
  });
679
806
  };
680
- const markdownSource = typeof message.text === "string" && message.text ? message.text : message.content?.map((block) => {
681
- if (block.type === "code" && block.text) {
682
- return `\`\`\`${block.language ?? ""}
683
- ${block.text}
684
- \`\`\``;
685
- }
686
- if ((block.type === "text" || block.type === "thinking") && block.text) {
687
- return block.text;
688
- }
689
- return "";
690
- }).filter(Boolean).join("\n\n") ?? "";
691
- const canCopy = !isEditing && (!!message.content?.length || typeof message.text === "string" && message.text.length > 0);
807
+ const actions = [
808
+ ...canCopy ? [
809
+ {
810
+ id: "copy",
811
+ label: "Copy message",
812
+ title: "Copy message (\u2318/Ctrl-click: default format)",
813
+ icon: copy.copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clipboard, { size: 14, "aria-hidden": "true" }),
814
+ onSelect: copy.copyDefault,
815
+ submenu: {
816
+ label: "Copy as",
817
+ items: [
818
+ {
819
+ id: "copy-rich",
820
+ label: "Copy as rich text",
821
+ description: "Rich text + Markdown",
822
+ onSelect: copy.copyRich
823
+ },
824
+ {
825
+ id: "copy-markdown",
826
+ label: "Copy as Markdown",
827
+ onSelect: copy.copyMarkdown
828
+ },
829
+ {
830
+ id: "copy-plain",
831
+ label: "Copy as plain text",
832
+ onSelect: copy.copyPlain
833
+ }
834
+ ]
835
+ }
836
+ }
837
+ ] : [],
838
+ ...canEdit && !isEditing ? [
839
+ {
840
+ id: "edit",
841
+ label: "Edit message",
842
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { size: 14, "aria-hidden": "true" }),
843
+ onSelect: startEdit
844
+ }
845
+ ] : []
846
+ ];
692
847
  return /* @__PURE__ */ jsxRuntime.jsxs(
693
848
  "div",
694
849
  {
@@ -726,17 +881,6 @@ ${block.text}
726
881
  title: `Edited ${formatTime(message.editedAt)}`,
727
882
  children: "(edited)"
728
883
  }
729
- ),
730
- canEdit && !isEditing && /* @__PURE__ */ jsxRuntime.jsx(
731
- "button",
732
- {
733
- type: "button",
734
- "data-slot": "superchat-edit-button",
735
- onClick: startEdit,
736
- "aria-label": "Edit message",
737
- className: "rounded p-0.5 text-neutral-400 opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100 hover:text-neutral-600 focus-visible:opacity-100 dark:hover:text-neutral-200",
738
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { size: 14, "aria-hidden": "true" })
739
- }
740
884
  )
741
885
  ]
742
886
  }
@@ -749,13 +893,12 @@ ${block.text}
749
893
  isSelf ? "flex-row-reverse" : "flex-row"
750
894
  ),
751
895
  children: [
752
- canCopy && /* @__PURE__ */ jsxRuntime.jsx(
753
- CopyMenu,
896
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(
897
+ MessageOverflowMenu,
754
898
  {
755
899
  isSelf,
756
- markdown: markdownSource,
757
- getHtml: () => bubbleRef.current?.innerHTML ?? "",
758
- getText: () => bubbleRef.current?.textContent ?? ""
900
+ actions,
901
+ footerVisible
759
902
  }
760
903
  ),
761
904
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -868,6 +1011,14 @@ ${block.text}
868
1011
  )
869
1012
  ]
870
1013
  }
1014
+ ),
1015
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(
1016
+ MessageActionsBar,
1017
+ {
1018
+ ref: actionsBarRef,
1019
+ actions,
1020
+ isSelf
1021
+ }
871
1022
  )
872
1023
  ] })
873
1024
  ]
@@ -895,11 +1046,12 @@ function VirtualThread({
895
1046
  onReferenceClick,
896
1047
  editable,
897
1048
  onMessageEdited,
1049
+ defaultCopyFormat,
898
1050
  order,
899
1051
  conversationId,
900
1052
  containerProps
901
1053
  }) {
902
- const parentRef = React4__namespace.useRef(null);
1054
+ const parentRef = React2__namespace.useRef(null);
903
1055
  const virtualizer = reactVirtual.useVirtualizer({
904
1056
  count: items.length,
905
1057
  getScrollElement: () => parentRef.current,
@@ -909,7 +1061,7 @@ function VirtualThread({
909
1061
  getItemKey: (index) => items[index]?.id ?? index
910
1062
  });
911
1063
  const count = items.length;
912
- React4__namespace.useEffect(() => {
1064
+ React2__namespace.useEffect(() => {
913
1065
  if (count === 0) return;
914
1066
  if (order === "desc") {
915
1067
  virtualizer.scrollToIndex(0, { align: "start" });
@@ -951,7 +1103,8 @@ function VirtualThread({
951
1103
  linkBuilder,
952
1104
  onReferenceClick,
953
1105
  editable,
954
- onMessageEdited
1106
+ onMessageEdited,
1107
+ defaultCopyFormat
955
1108
  }
956
1109
  ) })
957
1110
  },
@@ -972,6 +1125,7 @@ function SuperChat({
972
1125
  order = "asc",
973
1126
  virtualized = false,
974
1127
  linkBuilder,
1128
+ defaultCopyFormat,
975
1129
  className,
976
1130
  onMessageSent,
977
1131
  onMessageEdited,
@@ -979,35 +1133,35 @@ function SuperChat({
979
1133
  onReferenceClick,
980
1134
  onBack
981
1135
  }) {
982
- const headingId = React4__namespace.useId();
983
- const renderText = React4__namespace.useMemo(
1136
+ const headingId = React2__namespace.useId();
1137
+ const renderText = React2__namespace.useMemo(
984
1138
  () => renderTextContent ?? createMarkdownRenderer({
985
1139
  plugins: renderPlugins,
986
1140
  trusted: trustedContent
987
1141
  }),
988
1142
  [renderTextContent, renderPlugins, trustedContent]
989
1143
  );
990
- const threadRef = React4__namespace.useRef(null);
991
- React4__namespace.useEffect(() => {
1144
+ const threadRef = React2__namespace.useRef(null);
1145
+ React2__namespace.useEffect(() => {
992
1146
  if (virtualized) return;
993
1147
  const el = threadRef.current;
994
1148
  if (!el) return;
995
1149
  el.scrollTop = order === "desc" ? 0 : el.scrollHeight;
996
1150
  }, [conversation.thread.length, conversation.id, order, virtualized]);
997
- const participantById = React4__namespace.useMemo(() => {
1151
+ const participantById = React2__namespace.useMemo(() => {
998
1152
  const map = /* @__PURE__ */ new Map();
999
1153
  conversation.participants.forEach((p) => map.set(p.id, p));
1000
1154
  return map;
1001
1155
  }, [conversation]);
1002
- const orderedThread = React4__namespace.useMemo(() => {
1156
+ const orderedThread = React2__namespace.useMemo(() => {
1003
1157
  const sorted = [...conversation.thread].sort(byTime);
1004
1158
  return order === "desc" ? sorted.reverse() : sorted;
1005
1159
  }, [conversation, order]);
1006
- const onMessageEditedRef = React4__namespace.useRef(onMessageEdited);
1160
+ const onMessageEditedRef = React2__namespace.useRef(onMessageEdited);
1007
1161
  onMessageEditedRef.current = onMessageEdited;
1008
- const conversationRef = React4__namespace.useRef(conversation);
1162
+ const conversationRef = React2__namespace.useRef(conversation);
1009
1163
  conversationRef.current = conversation;
1010
- const handleMessageEdited = React4__namespace.useCallback(
1164
+ const handleMessageEdited = React2__namespace.useCallback(
1011
1165
  (messageId, text) => {
1012
1166
  onMessageEditedRef.current?.(messageId, text, {
1013
1167
  conversation: conversationRef.current
@@ -1016,7 +1170,7 @@ function SuperChat({
1016
1170
  []
1017
1171
  );
1018
1172
  const editable = !readOnly && !!onMessageEdited;
1019
- const mentionOptions = React4__namespace.useMemo(
1173
+ const mentionOptions = React2__namespace.useMemo(
1020
1174
  () => conversation.participants.filter((p) => p.kind !== "system").map((p) => ({
1021
1175
  id: p.id,
1022
1176
  label: p.name,
@@ -1026,11 +1180,11 @@ function SuperChat({
1026
1180
  })),
1027
1181
  [conversation.participants]
1028
1182
  );
1029
- const composerAccept = React4__namespace.useMemo(
1183
+ const composerAccept = React2__namespace.useMemo(
1030
1184
  () => acceptTokensFor(acceptedFileTypes),
1031
1185
  [acceptedFileTypes]
1032
1186
  );
1033
- const handleComposerSend = React4__namespace.useCallback(
1187
+ const handleComposerSend = React2__namespace.useCallback(
1034
1188
  async (message) => {
1035
1189
  const text = message.content;
1036
1190
  const mentions = detectMentions(text, conversation.participants);
@@ -1128,6 +1282,7 @@ function SuperChat({
1128
1282
  onReferenceClick,
1129
1283
  editable,
1130
1284
  onMessageEdited: handleMessageEdited,
1285
+ defaultCopyFormat,
1131
1286
  order,
1132
1287
  conversationId: conversation.id,
1133
1288
  containerProps: {
@@ -1160,14 +1315,15 @@ function SuperChat({
1160
1315
  linkBuilder,
1161
1316
  onReferenceClick,
1162
1317
  editable,
1163
- onMessageEdited: handleMessageEdited
1318
+ onMessageEdited: handleMessageEdited,
1319
+ defaultCopyFormat
1164
1320
  },
1165
1321
  m.id
1166
1322
  ))
1167
1323
  }
1168
1324
  ),
1169
1325
  /* @__PURE__ */ jsxRuntime.jsx(
1170
- chunk26DPQUSB_cjs.MessageComposer,
1326
+ chunkG52YRAJC_cjs.MessageComposer,
1171
1327
  {
1172
1328
  onSend: handleComposerSend,
1173
1329
  disabled: readOnly,
@@ -1191,12 +1347,12 @@ function SuperChatConversations({
1191
1347
  onConversationOpened,
1192
1348
  onNewConversation
1193
1349
  }) {
1194
- const [internalActive, setInternalActive] = React4__namespace.useState(
1350
+ const [internalActive, setInternalActive] = React2__namespace.useState(
1195
1351
  defaultActiveConversationId ?? conversations[0]?.id
1196
1352
  );
1197
1353
  const requestedId = activeConversationId ?? internalActive;
1198
1354
  const activeId = conversations.some((c) => c.id === requestedId) ? requestedId : conversations[0]?.id;
1199
- const sortedConversations = React4__namespace.useMemo(
1355
+ const sortedConversations = React2__namespace.useMemo(
1200
1356
  () => [...conversations].sort((a, b) => lastActivityOf(b) - lastActivityOf(a)),
1201
1357
  [conversations]
1202
1358
  );
@@ -1276,6 +1432,7 @@ function SuperChatInbox({
1276
1432
  virtualized,
1277
1433
  showSidebar = true,
1278
1434
  linkBuilder,
1435
+ defaultCopyFormat,
1279
1436
  className,
1280
1437
  onMessageSent,
1281
1438
  onMessageEdited,
@@ -1284,13 +1441,13 @@ function SuperChatInbox({
1284
1441
  onNewConversation,
1285
1442
  onReferenceClick
1286
1443
  }) {
1287
- const [internalActive, setInternalActive] = React4__namespace.useState(
1444
+ const [internalActive, setInternalActive] = React2__namespace.useState(
1288
1445
  defaultActiveConversationId ?? conversations[0]?.id
1289
1446
  );
1290
1447
  const requestedId = activeConversationId ?? internalActive;
1291
1448
  const active = conversations.find((c) => c.id === requestedId) ?? conversations[0];
1292
1449
  const activeId = active?.id;
1293
- const [mobileView, setMobileView] = React4__namespace.useState("list");
1450
+ const [mobileView, setMobileView] = React2__namespace.useState("list");
1294
1451
  const handleOpen = (c) => {
1295
1452
  if (activeConversationId === void 0) setInternalActive(c.id);
1296
1453
  setMobileView("chat");
@@ -1333,6 +1490,7 @@ function SuperChatInbox({
1333
1490
  order,
1334
1491
  virtualized,
1335
1492
  linkBuilder,
1493
+ defaultCopyFormat,
1336
1494
  onMessageSent,
1337
1495
  onMessageEdited,
1338
1496
  onConversationClosed,