tiptap-markdown-react 0.17.1 → 0.18.0

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.
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { skipTrailingNodeMeta, Placeholder } from "@tiptap/extensions";
12
12
  import { NodeViewWrapper, ReactNodeViewRenderer, useEditorState, ReactRenderer, NodeViewContent, useEditor, EditorContent } from "@tiptap/react";
13
13
  import { createPortal } from "react-dom";
14
14
  import { useState, useEffect, useCallback, useRef, useMemo, forwardRef, useImperativeHandle, Fragment as Fragment$1, useLayoutEffect, useId, useContext, createContext } from "react";
15
- import { e as enrichMarkdownCitations, c as styles$8 } from "./ReportContent-MgbebxPV.js";
15
+ import { e as enrichMarkdownCitations, c as styles$a } from "./ReportContent-MgbebxPV.js";
16
16
  import { R as R2, a as a2, b as b2, s as s2 } from "./ReportContent-MgbebxPV.js";
17
17
  import { C as CitationRef, i as mergeCommentIntervals, h as mapCommentAnchors, p as prepareChartMarkdown, j as reportChart, b as baseExtensions, f as CommentMark, l as lowlight, m as makeTocGetId, k as parseCodeTokenAsChartOrCodeBlock, a as pureCodeBlock, c as pureImage, n as renderMathInto, o as subscribeMathClick, d as pureChart } from "./extractToc-BaR6LP1f.js";
18
18
  import { g, e, s as s3 } from "./extractToc-BaR6LP1f.js";
@@ -22,7 +22,7 @@ import { PluginKey, Plugin, NodeSelection, TextSelection } from "@tiptap/pm/stat
22
22
  import { DecorationSet, Decoration } from "@tiptap/pm/view";
23
23
  import Suggestion from "@tiptap/suggestion";
24
24
  import { FileHandlePlugin } from "@tiptap/extension-file-handler";
25
- import { CellSelection, isInTable, selectedRect, rowIsHeader } from "@tiptap/pm/tables";
25
+ import { CellSelection, TableMap, isInTable, selectedRect, rowIsHeader, cellAround } from "@tiptap/pm/tables";
26
26
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
27
27
  import * as Popover from "@radix-ui/react-popover";
28
28
  function CitationRefView({ node, extension }) {
@@ -336,6 +336,17 @@ function nextComment(editor, dir = "next") {
336
336
  focusComment(editor, target);
337
337
  return target;
338
338
  }
339
+ const FIND_EXTENSION_NAME = "findAndReplace";
340
+ function isComposingKeyEvent(event) {
341
+ return event.isComposing || event.keyCode === 229;
342
+ }
343
+ function hasFindReplaceExtension(editor) {
344
+ var _a;
345
+ if (!editor || editor.isDestroyed) return false;
346
+ return ((_a = editor.extensionManager) == null ? void 0 : _a.extensions.some(
347
+ (extension) => extension.name === FIND_EXTENSION_NAME
348
+ )) ?? false;
349
+ }
339
350
  const FIND_DEBOUNCE_MS = 120;
340
351
  const MISMATCH_RE = /Applying a mismatched transaction/;
341
352
  function runFindCommand(run) {
@@ -395,6 +406,20 @@ const LinkIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
395
406
  /* @__PURE__ */ jsx("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
396
407
  /* @__PURE__ */ jsx("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
397
408
  ] });
409
+ const EraserIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
410
+ /* @__PURE__ */ jsx("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
411
+ /* @__PURE__ */ jsx("path", { d: "M22 21H7" }),
412
+ /* @__PURE__ */ jsx("path", { d: "m5 11 9 9" })
413
+ ] });
414
+ const RotateCcwIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
415
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
416
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" })
417
+ ] });
418
+ const ExternalLinkIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
419
+ /* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
420
+ /* @__PURE__ */ jsx("path", { d: "M10 14 21 3" }),
421
+ /* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
422
+ ] });
398
423
  const ImageIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
399
424
  /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
400
425
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
@@ -577,6 +602,10 @@ const defaultToolbarLabels = {
577
602
  subscript: "Subscript",
578
603
  link: "Link",
579
604
  linkPrompt: "Enter URL",
605
+ linkApply: "Apply link",
606
+ linkOpen: "Open in new window",
607
+ linkRemove: "Remove link",
608
+ linkInvalid: "The editor rejected this address",
580
609
  image: "Image",
581
610
  imageUploadFailed: "Image upload failed",
582
611
  importMarkdownFailed: "Markdown import failed",
@@ -592,10 +621,17 @@ const defaultToolbarLabels = {
592
621
  orderedList: "Ordered list",
593
622
  taskList: "Task list",
594
623
  more: "More",
624
+ search: "Find & replace",
595
625
  codeBlock: "Code block",
596
626
  hr: "Divider",
597
627
  importMarkdown: "Markdown",
598
628
  tableInsert: "Insert table",
629
+ tableRowMenu: "Row actions",
630
+ tableColumnMenu: "Column actions",
631
+ tableClearContent: "Clear content",
632
+ tableResetCellStyles: "Reset cell styles",
633
+ tableAppendRow: "Add row",
634
+ tableAppendColumn: "Add column",
599
635
  tableSizeSelected: (cols, rows) => `${cols} × ${rows}`,
600
636
  tableAddColumnBefore: "Add column before",
601
637
  tableAddColumnAfter: "Add column after",
@@ -663,6 +699,13 @@ const defaultShortcutLabels = {
663
699
  hardBreak: "Hard break",
664
700
  findReplace: "Find & replace"
665
701
  };
702
+ const defaultLinkPopoverLabels = {
703
+ field: "Enter URL",
704
+ apply: "Apply link",
705
+ open: "Open in new window",
706
+ remove: "Remove link",
707
+ invalid: "The editor rejected this address"
708
+ };
666
709
  const defaultColorPaletteLabels = {
667
710
  none: "None",
668
711
  theme: "THEME"
@@ -705,32 +748,40 @@ const defaultFindLabels = {
705
748
  };
706
749
  const bar = "_bar_1h61e_3";
707
750
  const row$1 = "_row_1h61e_25";
708
- const field = "_field_1h61e_43";
751
+ const field$1 = "_field_1h61e_43";
709
752
  const fieldIcon = "_fieldIcon_1h61e_62";
710
- const input = "_input_1h61e_67";
753
+ const input$1 = "_input_1h61e_67";
711
754
  const counter = "_counter_1h61e_79";
712
755
  const counterInvalid = "_counterInvalid_1h61e_89";
713
- const btn$1 = "_btn_1h61e_93";
756
+ const btn$2 = "_btn_1h61e_93";
714
757
  const toggle = "_toggle_1h61e_29";
715
758
  const toggleOn = "_toggleOn_1h61e_135";
716
759
  const iconGroup = "_iconGroup_1h61e_29";
717
760
  const spacer = "_spacer_1h61e_150";
718
761
  const readOnly = "_readOnly_1h61e_155";
719
- const styles$7 = {
762
+ const styles$9 = {
720
763
  bar,
721
764
  row: row$1,
722
- field,
765
+ field: field$1,
723
766
  fieldIcon,
724
- input,
767
+ input: input$1,
725
768
  counter,
726
769
  counterInvalid,
727
- btn: btn$1,
770
+ btn: btn$2,
728
771
  toggle,
729
772
  toggleOn,
730
773
  iconGroup,
731
774
  spacer,
732
775
  readOnly
733
776
  };
777
+ let warnedMissingExtension = false;
778
+ function warnMissingExtensionOnce() {
779
+ if (warnedMissingExtension) return;
780
+ warnedMissingExtension = true;
781
+ console.warn(
782
+ "[tiptap-markdown-react] FindReplaceBar 需要官方 find 扩展:请让 <MarkdownWysiwygEditor findReplace> 保持开启(默认 true),否则 setSearchTerm / replaceAll 等命令不存在。"
783
+ );
784
+ }
734
785
  function FindReplaceBar({
735
786
  editor,
736
787
  onClose,
@@ -742,13 +793,9 @@ function FindReplaceBar({
742
793
  const t = { ...defaultFindLabels, ...labels };
743
794
  const [term, setTerm] = useState("");
744
795
  const [replaceTerm, setReplaceTerm] = useState("");
745
- const hasExtension = typeof editor.commands.setSearchTerm === "function";
796
+ const hasExtension = hasFindReplaceExtension(editor);
746
797
  useEffect(() => {
747
- if (!hasExtension) {
748
- console.warn(
749
- "[tiptap-markdown-react] FindReplaceBar 需要官方 find 扩展:请让 <MarkdownWysiwygEditor findReplace> 保持开启(默认 true),否则 setSearchTerm / replaceAll 等命令不存在。"
750
- );
751
- }
798
+ if (!hasExtension) warnMissingExtensionOnce();
752
799
  }, [hasExtension]);
753
800
  const state = useEditorState({
754
801
  editor,
@@ -809,12 +856,11 @@ function FindReplaceBar({
809
856
  }) === null,
810
857
  [term, state.useRegex, state.caseSensitive]
811
858
  );
812
- const counter2 = t.counter(
813
- state.total === 0 ? 0 : (state.currentIndex ?? 0) + 1,
814
- state.total
815
- );
859
+ const current = state.total === 0 || state.currentIndex === null ? 0 : state.currentIndex + 1;
860
+ const counter2 = t.counter(current, state.total);
816
861
  const keepFocus = (e2) => e2.preventDefault();
817
862
  const onFindKeyDown = (e2) => {
863
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
818
864
  if (e2.key === "Enter") {
819
865
  e2.preventDefault();
820
866
  runAction(() => {
@@ -824,6 +870,7 @@ function FindReplaceBar({
824
870
  }
825
871
  };
826
872
  const onReplaceKeyDown = (e2) => {
873
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
827
874
  if (e2.key === "Enter") {
828
875
  e2.preventDefault();
829
876
  runAction(() => editor.commands.replace());
@@ -836,29 +883,32 @@ function FindReplaceBar({
836
883
  });
837
884
  };
838
885
  if (!hasExtension) return null;
839
- const toggleClass = (on) => `${styles$7.btn} ${styles$7.toggle}${on ? ` ${styles$7.toggleOn}` : ""}`;
886
+ const toggleClass = (on) => `${styles$9.btn} ${styles$9.toggle}${on ? ` ${styles$9.toggleOn}` : ""}`;
840
887
  return /* @__PURE__ */ jsxs(
841
888
  "div",
842
889
  {
843
- className: className ? `${styles$7.bar} ${className}` : styles$7.bar,
890
+ className: className ? `${styles$9.bar} ${className}` : styles$9.bar,
844
891
  style,
892
+ "data-find-bar": "",
845
893
  role: "dialog",
846
894
  "aria-label": t.find,
847
895
  onKeyDown: (e2) => {
848
- if (e2.key === "Escape") {
849
- e2.preventDefault();
850
- onClose();
851
- }
896
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
897
+ if (e2.key !== "Escape") return;
898
+ e2.preventDefault();
899
+ e2.stopPropagation();
900
+ onClose();
852
901
  },
853
902
  children: [
854
- /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
855
- /* @__PURE__ */ jsxs("span", { className: styles$7.field, children: [
856
- /* @__PURE__ */ jsx(SearchIcon, { size: 14, className: styles$7.fieldIcon }),
903
+ /* @__PURE__ */ jsxs("div", { className: styles$9.row, children: [
904
+ /* @__PURE__ */ jsxs("span", { className: styles$9.field, children: [
905
+ /* @__PURE__ */ jsx(SearchIcon, { size: 14, className: styles$9.fieldIcon }),
857
906
  /* @__PURE__ */ jsx(
858
907
  "input",
859
908
  {
860
909
  ref: inputRef,
861
- className: styles$7.input,
910
+ className: styles$9.input,
911
+ "data-find-field": "search",
862
912
  value: term,
863
913
  onChange: (e2) => setTerm(e2.target.value),
864
914
  onKeyDown: onFindKeyDown,
@@ -871,7 +921,8 @@ function FindReplaceBar({
871
921
  /* @__PURE__ */ jsx(
872
922
  "span",
873
923
  {
874
- className: `${styles$7.counter}${invalidPattern ? ` ${styles$7.counterInvalid}` : ""}`,
924
+ className: `${styles$9.counter}${invalidPattern ? ` ${styles$9.counterInvalid}` : ""}`,
925
+ "data-find-counter": "",
875
926
  "aria-live": "polite",
876
927
  title: invalidPattern ? t.invalidRegex : void 0,
877
928
  children: invalidPattern ? t.invalidRegex : counter2
@@ -883,6 +934,7 @@ function FindReplaceBar({
883
934
  {
884
935
  type: "button",
885
936
  className: toggleClass(state.caseSensitive),
937
+ "data-find-option": "match-case",
886
938
  title: t.caseSensitive,
887
939
  "aria-label": t.caseSensitive,
888
940
  "aria-pressed": state.caseSensitive,
@@ -896,6 +948,7 @@ function FindReplaceBar({
896
948
  {
897
949
  type: "button",
898
950
  className: toggleClass(state.wholeWord),
951
+ "data-find-option": "whole-words",
899
952
  title: t.wholeWord,
900
953
  "aria-label": t.wholeWord,
901
954
  "aria-pressed": state.wholeWord,
@@ -904,13 +957,14 @@ function FindReplaceBar({
904
957
  children: "ab"
905
958
  }
906
959
  ),
907
- /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
908
- /* @__PURE__ */ jsxs("span", { className: styles$7.iconGroup, children: [
960
+ /* @__PURE__ */ jsx("span", { className: styles$9.spacer }),
961
+ /* @__PURE__ */ jsxs("span", { className: styles$9.iconGroup, children: [
909
962
  /* @__PURE__ */ jsx(
910
963
  "button",
911
964
  {
912
965
  type: "button",
913
- className: styles$7.btn,
966
+ className: styles$9.btn,
967
+ "data-find-action": "previous",
914
968
  title: t.previous,
915
969
  "aria-label": t.previous,
916
970
  disabled: state.total === 0,
@@ -923,7 +977,8 @@ function FindReplaceBar({
923
977
  "button",
924
978
  {
925
979
  type: "button",
926
- className: styles$7.btn,
980
+ className: styles$9.btn,
981
+ "data-find-action": "next",
927
982
  title: t.next,
928
983
  "aria-label": t.next,
929
984
  disabled: state.total === 0,
@@ -936,7 +991,8 @@ function FindReplaceBar({
936
991
  "button",
937
992
  {
938
993
  type: "button",
939
- className: styles$7.btn,
994
+ className: styles$9.btn,
995
+ "data-find-action": "close",
940
996
  title: t.close,
941
997
  "aria-label": t.close,
942
998
  onClick: onClose,
@@ -945,11 +1001,12 @@ function FindReplaceBar({
945
1001
  )
946
1002
  ] })
947
1003
  ] }),
948
- editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
949
- /* @__PURE__ */ jsx("span", { className: styles$7.field, children: /* @__PURE__ */ jsx(
1004
+ editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$9.row, children: [
1005
+ /* @__PURE__ */ jsx("span", { className: styles$9.field, children: /* @__PURE__ */ jsx(
950
1006
  "input",
951
1007
  {
952
- className: styles$7.input,
1008
+ className: styles$9.input,
1009
+ "data-find-field": "replace",
953
1010
  value: replaceTerm,
954
1011
  onChange: (e2) => setReplaceTerm(e2.target.value),
955
1012
  onKeyDown: onReplaceKeyDown,
@@ -958,12 +1015,13 @@ function FindReplaceBar({
958
1015
  spellCheck: false
959
1016
  }
960
1017
  ) }),
961
- /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
1018
+ /* @__PURE__ */ jsx("span", { className: styles$9.spacer }),
962
1019
  /* @__PURE__ */ jsx(
963
1020
  "button",
964
1021
  {
965
1022
  type: "button",
966
- className: styles$7.btn,
1023
+ className: styles$9.btn,
1024
+ "data-find-action": "replace",
967
1025
  title: t.replaceOne,
968
1026
  "aria-label": t.replaceOne,
969
1027
  disabled: state.total === 0,
@@ -976,7 +1034,8 @@ function FindReplaceBar({
976
1034
  "button",
977
1035
  {
978
1036
  type: "button",
979
- className: styles$7.btn,
1037
+ className: styles$9.btn,
1038
+ "data-find-action": "replace-all",
980
1039
  title: t.replaceAll,
981
1040
  "aria-label": t.replaceAll,
982
1041
  disabled: state.total === 0,
@@ -985,7 +1044,7 @@ function FindReplaceBar({
985
1044
  children: /* @__PURE__ */ jsx(ReplaceAllIcon, { size: 16 })
986
1045
  }
987
1046
  )
988
- ] }) : /* @__PURE__ */ jsx("div", { className: styles$7.row, children: /* @__PURE__ */ jsx("span", { className: styles$7.readOnly, children: t.readOnly }) })
1047
+ ] }) : /* @__PURE__ */ jsx("div", { className: styles$9.row, children: /* @__PURE__ */ jsx("span", { className: styles$9.readOnly, children: t.readOnly }) })
989
1048
  ]
990
1049
  }
991
1050
  );
@@ -1079,7 +1138,7 @@ const item$1 = "_item_1noza_53";
1079
1138
  const itemActive = "_itemActive_1noza_54";
1080
1139
  const itemIcon = "_itemIcon_1noza_79";
1081
1140
  const itemTitle = "_itemTitle_1noza_102";
1082
- const styles$6 = {
1141
+ const styles$8 = {
1083
1142
  popupHost,
1084
1143
  menu: menu$1,
1085
1144
  groupLabel,
@@ -1268,11 +1327,11 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1268
1327
  );
1269
1328
  if (!items.length) return null;
1270
1329
  let optionIndex = -1;
1271
- return /* @__PURE__ */ jsx("div", { className: styles$6.menu, role: "listbox", "aria-label": menuLabel, children: withGroupHeaders(items).map(([header2, item2]) => {
1330
+ return /* @__PURE__ */ jsx("div", { className: styles$8.menu, role: "listbox", "aria-label": menuLabel, children: withGroupHeaders(items).map(([header2, item2]) => {
1272
1331
  optionIndex += 1;
1273
1332
  const i = optionIndex;
1274
1333
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1275
- header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$6.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1334
+ header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$8.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1276
1335
  /* @__PURE__ */ jsxs(
1277
1336
  "button",
1278
1337
  {
@@ -1280,7 +1339,7 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1280
1339
  role: "option",
1281
1340
  "aria-selected": i === index,
1282
1341
  title: item2.title,
1283
- className: i === index ? styles$6.itemActive : styles$6.item,
1342
+ className: i === index ? styles$8.itemActive : styles$8.item,
1284
1343
  tabIndex: -1,
1285
1344
  onMouseEnter: () => setIndex(i),
1286
1345
  onMouseDown: (e2) => {
@@ -1288,8 +1347,8 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1288
1347
  command(item2);
1289
1348
  },
1290
1349
  children: [
1291
- item2.icon != null ? /* @__PURE__ */ jsx("span", { className: styles$6.itemIcon, "aria-hidden": "true", children: item2.icon }) : /* @__PURE__ */ jsx("span", { className: styles$6.itemIcon, "aria-hidden": "true" }),
1292
- /* @__PURE__ */ jsx("span", { className: styles$6.itemTitle, children: item2.title })
1350
+ item2.icon != null ? /* @__PURE__ */ jsx("span", { className: styles$8.itemIcon, "aria-hidden": "true", children: item2.icon }) : /* @__PURE__ */ jsx("span", { className: styles$8.itemIcon, "aria-hidden": "true" }),
1351
+ /* @__PURE__ */ jsx("span", { className: styles$8.itemTitle, children: item2.title })
1293
1352
  ]
1294
1353
  }
1295
1354
  )
@@ -1340,7 +1399,7 @@ const SlashMenu = Extension.create({
1340
1399
  menuLabel: ((_a = this.options.labels) == null ? void 0 : _a.menuLabel) ?? defaultSlashMenuLabels.menuLabel,
1341
1400
  command: props.command
1342
1401
  },
1343
- className: styles$6.popupHost
1402
+ className: styles$8.popupHost
1344
1403
  }
1345
1404
  );
1346
1405
  const pmStyle = getComputedStyle(props.editor.view.dom);
@@ -1392,7 +1451,7 @@ const rowKeys = "_rowKeys_ljnq6_127";
1392
1451
  const rowMd = "_rowMd_ljnq6_128";
1393
1452
  const keycap = "_keycap_ljnq6_138";
1394
1453
  const none = "_none_ljnq6_163";
1395
- const styles$5 = {
1454
+ const styles$7 = {
1396
1455
  drawer,
1397
1456
  closeBtn,
1398
1457
  head,
@@ -1485,7 +1544,7 @@ function ShortcutPanel({ open, onClose, labels }) {
1485
1544
  return /* @__PURE__ */ jsxs(
1486
1545
  "aside",
1487
1546
  {
1488
- className: styles$5.drawer,
1547
+ className: styles$7.drawer,
1489
1548
  role: "dialog",
1490
1549
  "aria-modal": "false",
1491
1550
  "aria-label": t.panelTitle,
@@ -1494,27 +1553,27 @@ function ShortcutPanel({ open, onClose, labels }) {
1494
1553
  "button",
1495
1554
  {
1496
1555
  type: "button",
1497
- className: styles$5.closeBtn,
1556
+ className: styles$7.closeBtn,
1498
1557
  title: t.close,
1499
1558
  "aria-label": t.close,
1500
1559
  onClick: onClose,
1501
1560
  children: /* @__PURE__ */ jsx(XIcon, { size: 16 })
1502
1561
  }
1503
1562
  ),
1504
- /* @__PURE__ */ jsxs("div", { className: styles$5.head, children: [
1505
- /* @__PURE__ */ jsx("span", { className: styles$5.colFormat, children: t.colFormat }),
1506
- /* @__PURE__ */ jsx("span", { className: styles$5.colShortcut, children: t.colShortcut }),
1507
- /* @__PURE__ */ jsx("span", { className: styles$5.colMarkdown, children: t.colMarkdown })
1563
+ /* @__PURE__ */ jsxs("div", { className: styles$7.head, children: [
1564
+ /* @__PURE__ */ jsx("span", { className: styles$7.colFormat, children: t.colFormat }),
1565
+ /* @__PURE__ */ jsx("span", { className: styles$7.colShortcut, children: t.colShortcut }),
1566
+ /* @__PURE__ */ jsx("span", { className: styles$7.colMarkdown, children: t.colMarkdown })
1508
1567
  ] }),
1509
- /* @__PURE__ */ jsx("div", { className: styles$5.body, children: groups.map((group2) => /* @__PURE__ */ jsxs("section", { className: styles$5.group, children: [
1510
- /* @__PURE__ */ jsx("h3", { className: styles$5.groupTitle, children: group2.title }),
1511
- group2.entries.map((entry) => /* @__PURE__ */ jsxs("div", { className: styles$5.row, children: [
1512
- /* @__PURE__ */ jsx("span", { className: styles$5.rowLabel, children: entry.label }),
1513
- /* @__PURE__ */ jsx("span", { className: styles$5.rowKeys, children: entry.keys ? entry.keys.map((key, i) => /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: keycapText(key, mac) }, i)) : /* @__PURE__ */ jsx("span", { className: styles$5.none, children: "—" }) }),
1514
- /* @__PURE__ */ jsx("span", { className: styles$5.rowMd, children: entry.markdown ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
1515
- /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: entry.markdown.marker }),
1516
- entry.markdown.terminator ? /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: entry.markdown.terminator }) : null
1517
- ] }) : /* @__PURE__ */ jsx("span", { className: styles$5.none, children: "—" }) })
1568
+ /* @__PURE__ */ jsx("div", { className: styles$7.body, children: groups.map((group2) => /* @__PURE__ */ jsxs("section", { className: styles$7.group, children: [
1569
+ /* @__PURE__ */ jsx("h3", { className: styles$7.groupTitle, children: group2.title }),
1570
+ group2.entries.map((entry) => /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
1571
+ /* @__PURE__ */ jsx("span", { className: styles$7.rowLabel, children: entry.label }),
1572
+ /* @__PURE__ */ jsx("span", { className: styles$7.rowKeys, children: entry.keys ? entry.keys.map((key, i) => /* @__PURE__ */ jsx("kbd", { className: styles$7.keycap, children: keycapText(key, mac) }, i)) : /* @__PURE__ */ jsx("span", { className: styles$7.none, children: "—" }) }),
1573
+ /* @__PURE__ */ jsx("span", { className: styles$7.rowMd, children: entry.markdown ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
1574
+ /* @__PURE__ */ jsx("kbd", { className: styles$7.keycap, children: entry.markdown.marker }),
1575
+ entry.markdown.terminator ? /* @__PURE__ */ jsx("kbd", { className: styles$7.keycap, children: entry.markdown.terminator }) : null
1576
+ ] }) : /* @__PURE__ */ jsx("span", { className: styles$7.none, children: "—" }) })
1518
1577
  ] }, entry.id))
1519
1578
  ] }, group2.id)) })
1520
1579
  ]
@@ -1818,7 +1877,7 @@ const gutterLine = "_gutterLine_k8th1_184";
1818
1877
  const readonlyActions = "_readonlyActions_k8th1_188";
1819
1878
  const actionBtn = "_actionBtn_k8th1_194";
1820
1879
  const langBraces = "_langBraces_k8th1_213";
1821
- const styles$4 = {
1880
+ const styles$6 = {
1822
1881
  wrapper,
1823
1882
  header: header$1,
1824
1883
  langTrigger,
@@ -1918,29 +1977,29 @@ function CodeBlockView({
1918
1977
  ta.remove();
1919
1978
  };
1920
1979
  const wrapperClass = [
1921
- styles$4.wrapper,
1922
- readonly2 ? styles$4.readonly : "",
1923
- folded2 ? styles$4.folded : ""
1980
+ styles$6.wrapper,
1981
+ readonly2 ? styles$6.readonly : "",
1982
+ folded2 ? styles$6.folded : ""
1924
1983
  ].filter(Boolean).join(" ");
1925
1984
  return /* @__PURE__ */ jsxs(NodeViewWrapper, { className: wrapperClass, children: [
1926
- editable ? /* @__PURE__ */ jsxs("div", { className: styles$4.header, contentEditable: false, children: [
1985
+ editable ? /* @__PURE__ */ jsxs("div", { className: styles$6.header, contentEditable: false, children: [
1927
1986
  /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
1928
1987
  /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1929
1988
  "button",
1930
1989
  {
1931
1990
  type: "button",
1932
- className: styles$4.langTrigger,
1991
+ className: styles$6.langTrigger,
1933
1992
  "aria-label": "Code language",
1934
1993
  children: [
1935
1994
  /* @__PURE__ */ jsx("span", { children: currentLabel }),
1936
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$4.langChevron })
1995
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$6.langChevron })
1937
1996
  ]
1938
1997
  }
1939
1998
  ) }),
1940
1999
  /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
1941
2000
  DropdownMenu.Content,
1942
2001
  {
1943
- className: styles$4.langMenu,
2002
+ className: styles$6.langMenu,
1944
2003
  sideOffset: 4,
1945
2004
  align: "end",
1946
2005
  children: LANGUAGES.map((l) => {
@@ -1949,10 +2008,10 @@ function CodeBlockView({
1949
2008
  return /* @__PURE__ */ jsxs(
1950
2009
  DropdownMenu.Item,
1951
2010
  {
1952
- className: `${styles$4.langItem}${selected ? ` ${styles$4.langItemSelected}` : ""}`,
2011
+ className: `${styles$6.langItem}${selected ? ` ${styles$6.langItemSelected}` : ""}`,
1953
2012
  onSelect: () => updateAttributes({ language: l.value }),
1954
2013
  children: [
1955
- /* @__PURE__ */ jsx("span", { className: styles$4.langItemCheck, children: selected ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : null }),
2014
+ /* @__PURE__ */ jsx("span", { className: styles$6.langItemCheck, children: selected ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : null }),
1956
2015
  optionLabel
1957
2016
  ]
1958
2017
  },
@@ -1966,7 +2025,7 @@ function CodeBlockView({
1966
2025
  "button",
1967
2026
  {
1968
2027
  type: "button",
1969
- className: styles$4.deleteBtn,
2028
+ className: styles$6.deleteBtn,
1970
2029
  title: labels.delete,
1971
2030
  "aria-label": labels.delete,
1972
2031
  onClick: () => deleteNode(),
@@ -1975,17 +2034,17 @@ function CodeBlockView({
1975
2034
  )
1976
2035
  ] }) : (
1977
2036
  // 只读头部:左侧语言标签,右侧复制 + 展开收起(展开后按钮保留,供收回)
1978
- /* @__PURE__ */ jsxs("div", { className: styles$4.readonlyHeader, contentEditable: false, children: [
1979
- /* @__PURE__ */ jsxs("span", { className: styles$4.langBadge, children: [
1980
- /* @__PURE__ */ jsx("span", { className: styles$4.langBraces, children: "{}" }),
2037
+ /* @__PURE__ */ jsxs("div", { className: styles$6.readonlyHeader, contentEditable: false, children: [
2038
+ /* @__PURE__ */ jsxs("span", { className: styles$6.langBadge, children: [
2039
+ /* @__PURE__ */ jsx("span", { className: styles$6.langBraces, children: "{}" }),
1981
2040
  currentLabel
1982
2041
  ] }),
1983
- /* @__PURE__ */ jsxs("span", { className: styles$4.readonlyActions, children: [
2042
+ /* @__PURE__ */ jsxs("span", { className: styles$6.readonlyActions, children: [
1984
2043
  /* @__PURE__ */ jsx(
1985
2044
  "button",
1986
2045
  {
1987
2046
  type: "button",
1988
- className: styles$4.actionBtn,
2047
+ className: styles$6.actionBtn,
1989
2048
  onClick: handleCopy,
1990
2049
  "aria-label": labels.copy,
1991
2050
  title: labels.copy,
@@ -1996,7 +2055,7 @@ function CodeBlockView({
1996
2055
  "button",
1997
2056
  {
1998
2057
  type: "button",
1999
- className: styles$4.actionBtn,
2058
+ className: styles$6.actionBtn,
2000
2059
  onClick: () => setFolded((v) => !v),
2001
2060
  "aria-label": folded2 ? labels.expand : labels.collapse,
2002
2061
  title: folded2 ? labels.expand : labels.collapse,
@@ -2007,14 +2066,14 @@ function CodeBlockView({
2007
2066
  ] })
2008
2067
  ] })
2009
2068
  ),
2010
- /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$4.pre, children: [
2069
+ /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$6.pre, children: [
2011
2070
  readonly2 ? /* @__PURE__ */ jsx(
2012
2071
  "span",
2013
2072
  {
2014
- className: styles$4.gutter,
2073
+ className: styles$6.gutter,
2015
2074
  contentEditable: false,
2016
2075
  "aria-hidden": "true",
2017
- children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$4.gutterLine, children: i + 1 }, i))
2076
+ children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$6.gutterLine, children: i + 1 }, i))
2018
2077
  }
2019
2078
  ) : null,
2020
2079
  /* @__PURE__ */ jsx(NodeViewContent, { as: "code" })
@@ -2089,6 +2148,13 @@ function findBarOffsetStyle(offset) {
2089
2148
  left: px(offset.left)
2090
2149
  };
2091
2150
  }
2151
+ function editorOwnsKeyboard(editor) {
2152
+ const active2 = document.activeElement;
2153
+ const inEditor = !!active2 && editor.view.dom.contains(active2);
2154
+ if (inEditor || editor.isFocused) return true;
2155
+ const nothingFocused = active2 === null || active2 === document.body;
2156
+ return nothingFocused && document.querySelectorAll(".ProseMirror").length <= 1;
2157
+ }
2092
2158
  const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2093
2159
  initialMarkdown = "",
2094
2160
  editable = true,
@@ -2117,6 +2183,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2117
2183
  findBarOffset = DEFAULT_FIND_BAR_OFFSET,
2118
2184
  findShortcut = true,
2119
2185
  findLabels,
2186
+ onFindOpenChange,
2120
2187
  slashMenu = true,
2121
2188
  slashMenuLabels,
2122
2189
  shortcutPanel = true,
@@ -2177,7 +2244,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2177
2244
  immediatelyRender: false,
2178
2245
  editorProps: {
2179
2246
  attributes: {
2180
- class: styles$8.editorContent
2247
+ class: styles$a.editorContent
2181
2248
  }
2182
2249
  }
2183
2250
  });
@@ -2188,10 +2255,40 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2188
2255
  useEffect(() => {
2189
2256
  editor == null ? void 0 : editor.setEditable(editable);
2190
2257
  }, [editor, editable]);
2258
+ const openFind = useCallback(() => {
2259
+ setFindOpen(true);
2260
+ requestAnimationFrame(() => {
2261
+ var _a;
2262
+ return (_a = findInputRef.current) == null ? void 0 : _a.select();
2263
+ });
2264
+ }, []);
2191
2265
  const closeFind = useCallback(() => {
2192
2266
  setFindOpen(false);
2193
2267
  editor == null ? void 0 : editor.commands.focus();
2194
2268
  }, [editor]);
2269
+ const toggleFind = useCallback(() => {
2270
+ if (findOpen) closeFind();
2271
+ else openFind();
2272
+ }, [findOpen, closeFind, openFind]);
2273
+ const findBarOpen = findOpen && findBar && findReplace;
2274
+ const onFindOpenChangeRef = useRef(onFindOpenChange);
2275
+ onFindOpenChangeRef.current = onFindOpenChange;
2276
+ const notifiedFindOpenRef = useRef(false);
2277
+ useEffect(() => {
2278
+ var _a;
2279
+ if (notifiedFindOpenRef.current === findBarOpen) return;
2280
+ notifiedFindOpenRef.current = findBarOpen;
2281
+ (_a = onFindOpenChangeRef.current) == null ? void 0 : _a.call(onFindOpenChangeRef, findBarOpen);
2282
+ }, [findBarOpen]);
2283
+ const findBarOpenRef = useRef(findBarOpen);
2284
+ findBarOpenRef.current = findBarOpen;
2285
+ useEffect(
2286
+ () => () => {
2287
+ var _a;
2288
+ if (findBarOpenRef.current) (_a = onFindOpenChangeRef.current) == null ? void 0 : _a.call(onFindOpenChangeRef, false);
2289
+ },
2290
+ []
2291
+ );
2195
2292
  useEffect(() => {
2196
2293
  if (!editor || !findReplace || !findBar || !findShortcut) return;
2197
2294
  const onKeyDown = (event) => {
@@ -2199,23 +2296,26 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2199
2296
  return;
2200
2297
  }
2201
2298
  if (event.key !== "f" && event.key !== "F") return;
2202
- const active2 = document.activeElement;
2203
- const inEditor = !!active2 && editor.view.dom.contains(active2);
2204
- const nothingFocused = active2 === null || active2 === document.body;
2205
- const soleEditor = document.querySelectorAll(".ProseMirror").length <= 1;
2206
- if (!inEditor && !editor.isFocused && !(nothingFocused && soleEditor)) {
2207
- return;
2208
- }
2299
+ if (!editorOwnsKeyboard(editor)) return;
2209
2300
  event.preventDefault();
2210
- setFindOpen(true);
2211
- requestAnimationFrame(() => {
2212
- var _a;
2213
- return (_a = findInputRef.current) == null ? void 0 : _a.select();
2214
- });
2301
+ openFind();
2215
2302
  };
2216
2303
  document.addEventListener("keydown", onKeyDown, true);
2217
2304
  return () => document.removeEventListener("keydown", onKeyDown, true);
2218
- }, [editor, findReplace, findBar, findShortcut]);
2305
+ }, [editor, findReplace, findBar, findShortcut, openFind]);
2306
+ useEffect(() => {
2307
+ if (!editor || !findBarOpen) return;
2308
+ const onKeyDown = (event) => {
2309
+ if (event.key !== "Escape") return;
2310
+ if (isComposingKeyEvent(event)) return;
2311
+ if (!editorOwnsKeyboard(editor)) return;
2312
+ event.preventDefault();
2313
+ event.stopPropagation();
2314
+ closeFind();
2315
+ };
2316
+ document.addEventListener("keydown", onKeyDown);
2317
+ return () => document.removeEventListener("keydown", onKeyDown);
2318
+ }, [editor, findBarOpen, closeFind]);
2219
2319
  const commentsSignatureRef = useRef("");
2220
2320
  useEffect(() => {
2221
2321
  if (!editor || !editable) return;
@@ -2323,10 +2423,11 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2323
2423
  focusComment: (commentId) => editor ? focusComment(editor, commentId) : false,
2324
2424
  nextComment: (dir) => editor ? nextComment(editor, dir ?? "next") : null,
2325
2425
  getCommentIds: () => editor ? collectCommentIds(editor) : [],
2326
- openFind: () => setFindOpen(true),
2327
- closeFind
2426
+ openFind: () => openFind(),
2427
+ closeFind,
2428
+ toggleFind: () => toggleFind()
2328
2429
  }),
2329
- [editor, closeFind]
2430
+ [editor, closeFind, openFind, toggleFind]
2330
2431
  );
2331
2432
  const findBarTarget = typeof findBarContainer === "function" ? findBarContainer() : findBarContainer ?? null;
2332
2433
  useEffect(() => {
@@ -2342,7 +2443,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2342
2443
  labels: findLabels,
2343
2444
  onClose: closeFind,
2344
2445
  inputRef: findInputRef,
2345
- className: styles$8.findBar,
2446
+ className: styles$a.findBar,
2346
2447
  style: findBarOffsetStyle(findBarOffset)
2347
2448
  }
2348
2449
  ) : null;
@@ -2362,7 +2463,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2362
2463
  "button",
2363
2464
  {
2364
2465
  type: "button",
2365
- className: shortcutFabTarget ? `${styles$8.shortcutFab} ${styles$8.shortcutFabHosted}` : styles$8.shortcutFab,
2466
+ className: shortcutFabTarget ? `${styles$a.shortcutFab} ${styles$a.shortcutFabHosted}` : styles$a.shortcutFab,
2366
2467
  title: shortcutT.panelTitle,
2367
2468
  "aria-label": shortcutT.panelTitle,
2368
2469
  "aria-expanded": shortcutsOpen,
@@ -2370,14 +2471,14 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2370
2471
  children: /* @__PURE__ */ jsx(KeyboardIcon, { size: 18 })
2371
2472
  }
2372
2473
  ) : null;
2373
- return /* @__PURE__ */ jsxs("div", { className: styles$8.editorHost, children: [
2374
- findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$8.findBarAnchor, children: findBarNode }) : null,
2474
+ return /* @__PURE__ */ jsxs("div", { className: styles$a.editorHost, children: [
2475
+ findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$a.findBarAnchor, children: findBarNode }) : null,
2375
2476
  findBarNode && findBarTarget ? createPortal(findBarNode, findBarTarget) : null,
2376
2477
  /* @__PURE__ */ jsx(
2377
2478
  EditorContent,
2378
2479
  {
2379
2480
  editor,
2380
- className: className ? `${styles$8.editorScroll} ${className}` : styles$8.editorScroll
2481
+ className: className ? `${styles$a.editorScroll} ${className}` : styles$a.editorScroll
2381
2482
  }
2382
2483
  ),
2383
2484
  shortcutFabNode && shortcutFabTarget ? createPortal(shortcutFabNode, shortcutFabTarget) : shortcutFabNode,
@@ -2430,7 +2531,7 @@ function MarkdownPreview({
2430
2531
  editable: false,
2431
2532
  immediatelyRender: false,
2432
2533
  editorProps: {
2433
- attributes: { class: styles$8.editorContent }
2534
+ attributes: { class: styles$a.editorContent }
2434
2535
  }
2435
2536
  },
2436
2537
  [extensions]
@@ -2443,7 +2544,7 @@ function MarkdownPreview({
2443
2544
  EditorContent,
2444
2545
  {
2445
2546
  editor,
2446
- className: className ?? styles$8.editorScroll
2547
+ className: className ?? styles$a.editorScroll
2447
2548
  }
2448
2549
  );
2449
2550
  }
@@ -2515,147 +2616,56 @@ function splitTopLevelBlocks(markdown) {
2515
2616
  function stripToPlainText(markdown) {
2516
2617
  return markdown.replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^[ \t]*[-*+]\s+/gm, "").replace(/^[ \t]*\d+\.\s+/gm, "").replace(/[*_~`]+/g, "").replace(/<[^>]+>/g, "").replace(/\|/g, " ").replace(/\s+/g, " ").trim();
2517
2618
  }
2518
- function getTableSelectionInfo(state) {
2519
- if (!isInTable(state)) return null;
2520
- const rect = selectedRect(state);
2521
- const rowCount = Math.max(1, rect.bottom - rect.top);
2522
- const colCount = Math.max(1, rect.right - rect.left);
2523
- let includesHeaderRow = false;
2524
- for (let row2 = rect.top; row2 < rect.bottom; row2++) {
2525
- if (rowIsHeader(rect.map, rect.table, row2)) {
2526
- includesHeaderRow = true;
2527
- break;
2528
- }
2529
- }
2530
- return {
2531
- rowCount,
2532
- colCount,
2533
- isMultiCell: rowCount > 1 || colCount > 1,
2534
- includesHeaderRow,
2535
- coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,
2536
- coversAllCols: rect.left === 0 && rect.right === rect.map.width
2537
- };
2538
- }
2539
- function isPosInCellSelection(selection, pos) {
2540
- let found = false;
2541
- selection.forEachCell((node, cellPos) => {
2542
- if (pos >= cellPos && pos <= cellPos + node.nodeSize) {
2543
- found = true;
2544
- }
2545
- });
2546
- return found;
2547
- }
2548
- function preserveTableSelectionOnContextMenu(editor, pos) {
2549
- const { selection } = editor.state;
2550
- if (selection instanceof CellSelection && isPosInCellSelection(selection, pos)) {
2551
- editor.view.focus();
2552
- return;
2553
- }
2554
- editor.chain().focus().setTextSelection(pos).run();
2555
- }
2556
- function addRowsBefore(editor, count) {
2557
- const n = Math.max(1, count);
2558
- for (let i = 0; i < n; i++) {
2559
- if (!editor.commands.addRowBefore()) return false;
2560
- }
2561
- return true;
2562
- }
2563
- function addRowsAfter(editor, count) {
2564
- const n = Math.max(1, count);
2565
- for (let i = 0; i < n; i++) {
2566
- if (!editor.commands.addRowAfter()) return false;
2567
- }
2568
- return true;
2569
- }
2570
- function addColumnsBefore(editor, count) {
2571
- const n = Math.max(1, count);
2572
- for (let i = 0; i < n; i++) {
2573
- if (!editor.commands.addColumnBefore()) return false;
2574
- }
2575
- return true;
2576
- }
2577
- function addColumnsAfter(editor, count) {
2578
- const n = Math.max(1, count);
2579
- for (let i = 0; i < n; i++) {
2580
- if (!editor.commands.addColumnAfter()) return false;
2581
- }
2582
- return true;
2583
- }
2584
- function deleteSelectedRows(editor) {
2585
- const info = getTableSelectionInfo(editor.state);
2586
- if (!info) return false;
2587
- if (info.coversAllRows) return editor.commands.deleteTable();
2588
- return editor.commands.deleteRow();
2589
- }
2590
- function deleteSelectedColumns(editor) {
2591
- const info = getTableSelectionInfo(editor.state);
2592
- if (!info) return false;
2593
- if (info.coversAllCols) {
2594
- if (info.coversAllRows) return editor.commands.deleteTable();
2595
- return false;
2596
- }
2597
- return editor.commands.deleteColumn();
2598
- }
2599
- const toolbar = "_toolbar_1f7fb_2";
2600
- const inner = "_inner_1f7fb_15";
2601
- const btn = "_btn_1f7fb_27";
2602
- const btnActive = "_btnActive_1f7fb_50";
2603
- const tableBubble = "_tableBubble_1f7fb_66";
2604
- const tableMenuItem = "_tableMenuItem_1f7fb_77";
2605
- const tableMenuItemIcon = "_tableMenuItemIcon_1f7fb_103";
2606
- const tableMenuItemLabel = "_tableMenuItemLabel_1f7fb_113";
2607
- const tableMenuDivider = "_tableMenuDivider_1f7fb_118";
2608
- const txtIcon = "_txtIcon_1f7fb_126";
2609
- const colorIcon = "_colorIcon_1f7fb_134";
2610
- const colorIconGlyph = "_colorIconGlyph_1f7fb_142";
2611
- const colorIconBar = "_colorIconBar_1f7fb_148";
2612
- const scriptTrigger = "_scriptTrigger_1f7fb_155";
2613
- const scriptTriggerGlyph = "_scriptTriggerGlyph_1f7fb_175";
2614
- const divider = "_divider_1f7fb_183";
2615
- const styleTrigger = "_styleTrigger_1f7fb_192";
2616
- const styleTriggerLabel = "_styleTriggerLabel_1f7fb_221";
2617
- const styleTriggerCaret = "_styleTriggerCaret_1f7fb_229";
2618
- const styleItem = "_styleItem_1f7fb_235";
2619
- const styleIcon = "_styleIcon_1f7fb_241";
2620
- const scriptGlyph = "_scriptGlyph_1f7fb_251";
2621
- const menu = "_menu_1f7fb_263";
2622
- const menuItem = "_menuItem_1f7fb_274";
2623
- const menuItemSelected = "_menuItemSelected_1f7fb_301";
2624
- const tableInsertCaret = "_tableInsertCaret_1f7fb_314";
2625
- const tableSizePicker = "_tableSizePicker_1f7fb_322";
2626
- const tableSizeGrid = "_tableSizeGrid_1f7fb_332";
2627
- const tableSizeCell = "_tableSizeCell_1f7fb_337";
2628
- const tableSizeCellActive = "_tableSizeCellActive_1f7fb_347";
2629
- const tableSizeLabel = "_tableSizeLabel_1f7fb_352";
2630
- const popoverContent$1 = "_popoverContent_1f7fb_361";
2631
- const mathLayer = "_mathLayer_1f7fb_365";
2632
- const mathStack = "_mathStack_1f7fb_370";
2633
- const mathStackBlock = "_mathStackBlock_1f7fb_377";
2634
- const mathHint = "_mathHint_1f7fb_382";
2635
- const mathHintBlock = "_mathHintBlock_1f7fb_394";
2636
- const mathHintIcon = "_mathHintIcon_1f7fb_400";
2637
- const mathField = "_mathField_1f7fb_431";
2638
- const mathFieldBlock = "_mathFieldBlock_1f7fb_443";
2639
- const mathInput = "_mathInput_1f7fb_450";
2640
- const mathDone = "_mathDone_1f7fb_468";
2641
- const mathDoneKbd = "_mathDoneKbd_1f7fb_493";
2642
- const styles$3 = {
2619
+ const toolbar = "_toolbar_6osph_2";
2620
+ const inner = "_inner_6osph_15";
2621
+ const btn$1 = "_btn_6osph_33";
2622
+ const btnActive = "_btnActive_6osph_56";
2623
+ const txtIcon = "_txtIcon_6osph_72";
2624
+ const colorIcon = "_colorIcon_6osph_80";
2625
+ const colorIconGlyph = "_colorIconGlyph_6osph_88";
2626
+ const colorIconBar = "_colorIconBar_6osph_94";
2627
+ const scriptTrigger = "_scriptTrigger_6osph_101";
2628
+ const scriptTriggerGlyph = "_scriptTriggerGlyph_6osph_121";
2629
+ const divider$1 = "_divider_6osph_129";
2630
+ const styleTrigger = "_styleTrigger_6osph_138";
2631
+ const styleTriggerLabel = "_styleTriggerLabel_6osph_167";
2632
+ const styleTriggerCaret = "_styleTriggerCaret_6osph_175";
2633
+ const styleItem = "_styleItem_6osph_181";
2634
+ const styleIcon = "_styleIcon_6osph_187";
2635
+ const scriptGlyph = "_scriptGlyph_6osph_197";
2636
+ const menu = "_menu_6osph_209";
2637
+ const menuItem = "_menuItem_6osph_220";
2638
+ const menuItemSelected = "_menuItemSelected_6osph_247";
2639
+ const tableInsertCaret = "_tableInsertCaret_6osph_260";
2640
+ const tableSizePicker = "_tableSizePicker_6osph_268";
2641
+ const tableSizeGrid = "_tableSizeGrid_6osph_278";
2642
+ const tableSizeCell = "_tableSizeCell_6osph_283";
2643
+ const tableSizeCellActive = "_tableSizeCellActive_6osph_293";
2644
+ const tableSizeLabel = "_tableSizeLabel_6osph_298";
2645
+ const popoverContent$1 = "_popoverContent_6osph_307";
2646
+ const mathLayer = "_mathLayer_6osph_311";
2647
+ const mathStack = "_mathStack_6osph_316";
2648
+ const mathStackBlock = "_mathStackBlock_6osph_323";
2649
+ const mathHint = "_mathHint_6osph_328";
2650
+ const mathHintBlock = "_mathHintBlock_6osph_340";
2651
+ const mathHintIcon = "_mathHintIcon_6osph_346";
2652
+ const mathField = "_mathField_6osph_377";
2653
+ const mathFieldBlock = "_mathFieldBlock_6osph_389";
2654
+ const mathInput = "_mathInput_6osph_396";
2655
+ const mathDone = "_mathDone_6osph_414";
2656
+ const mathDoneKbd = "_mathDoneKbd_6osph_439";
2657
+ const styles$5 = {
2643
2658
  toolbar,
2644
2659
  inner,
2645
- btn,
2660
+ btn: btn$1,
2646
2661
  btnActive,
2647
- tableBubble,
2648
- tableMenuItem,
2649
- tableMenuItemIcon,
2650
- tableMenuItemLabel,
2651
- tableMenuDivider,
2652
2662
  txtIcon,
2653
2663
  colorIcon,
2654
2664
  colorIconGlyph,
2655
2665
  colorIconBar,
2656
2666
  scriptTrigger,
2657
2667
  scriptTriggerGlyph,
2658
- divider,
2668
+ divider: divider$1,
2659
2669
  styleTrigger,
2660
2670
  styleTriggerLabel,
2661
2671
  styleTriggerCaret,
@@ -2693,7 +2703,7 @@ const swatch = "_swatch_x5lrq_54";
2693
2703
  const swatchActive = "_swatchActive_x5lrq_70";
2694
2704
  const themeLabel = "_themeLabel_x5lrq_76";
2695
2705
  const themeRow = "_themeRow_x5lrq_84";
2696
- const styles$2 = {
2706
+ const styles$4 = {
2697
2707
  palette,
2698
2708
  noneRow,
2699
2709
  noneIcon,
@@ -2716,25 +2726,25 @@ const THEME_COLORS = ["#ff6719", "#ff5500"];
2716
2726
  function ColorPalette({ value, onPick, labels }) {
2717
2727
  const t = { ...defaultColorPaletteLabels, ...labels };
2718
2728
  const current = value == null ? void 0 : value.toLowerCase();
2719
- return /* @__PURE__ */ jsxs("div", { className: styles$2.palette, children: [
2729
+ return /* @__PURE__ */ jsxs("div", { className: styles$4.palette, children: [
2720
2730
  /* @__PURE__ */ jsxs(
2721
2731
  "button",
2722
2732
  {
2723
2733
  type: "button",
2724
- className: styles$2.noneRow,
2734
+ className: styles$4.noneRow,
2725
2735
  onMouseDown: (e2) => e2.preventDefault(),
2726
2736
  onClick: () => onPick(null),
2727
2737
  children: [
2728
- /* @__PURE__ */ jsx("span", { className: styles$2.noneIcon, "aria-hidden": true }),
2729
- /* @__PURE__ */ jsx("span", { className: styles$2.noneLabel, children: t.none })
2738
+ /* @__PURE__ */ jsx("span", { className: styles$4.noneIcon, "aria-hidden": true }),
2739
+ /* @__PURE__ */ jsx("span", { className: styles$4.noneLabel, children: t.none })
2730
2740
  ]
2731
2741
  }
2732
2742
  ),
2733
- /* @__PURE__ */ jsx("div", { className: styles$2.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
2743
+ /* @__PURE__ */ jsx("div", { className: styles$4.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
2734
2744
  "button",
2735
2745
  {
2736
2746
  type: "button",
2737
- className: `${styles$2.swatch} ${current === c.toLowerCase() ? styles$2.swatchActive : ""}`,
2747
+ className: `${styles$4.swatch} ${current === c.toLowerCase() ? styles$4.swatchActive : ""}`,
2738
2748
  style: { background: c },
2739
2749
  title: c,
2740
2750
  "aria-label": c,
@@ -2743,12 +2753,12 @@ function ColorPalette({ value, onPick, labels }) {
2743
2753
  },
2744
2754
  c
2745
2755
  )) }),
2746
- /* @__PURE__ */ jsx("div", { className: styles$2.themeLabel, children: t.theme }),
2747
- /* @__PURE__ */ jsx("div", { className: styles$2.themeRow, children: THEME_COLORS.map((c) => /* @__PURE__ */ jsx(
2756
+ /* @__PURE__ */ jsx("div", { className: styles$4.themeLabel, children: t.theme }),
2757
+ /* @__PURE__ */ jsx("div", { className: styles$4.themeRow, children: THEME_COLORS.map((c) => /* @__PURE__ */ jsx(
2748
2758
  "button",
2749
2759
  {
2750
2760
  type: "button",
2751
- className: `${styles$2.swatch} ${current === c.toLowerCase() ? styles$2.swatchActive : ""}`,
2761
+ className: `${styles$4.swatch} ${current === c.toLowerCase() ? styles$4.swatchActive : ""}`,
2752
2762
  style: { background: c },
2753
2763
  title: c,
2754
2764
  "aria-label": c,
@@ -2759,116 +2769,948 @@ function ColorPalette({ value, onPick, labels }) {
2759
2769
  )) })
2760
2770
  ] });
2761
2771
  }
2762
- function resolveNodeEl(editor, pos) {
2763
- const dom = editor.view.nodeDOM(pos);
2764
- if (dom instanceof HTMLElement) return dom;
2765
- if (dom instanceof Node) return dom.parentElement;
2766
- return null;
2772
+ const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set([
2773
+ "http:",
2774
+ "https:",
2775
+ "ftp:",
2776
+ "ftps:",
2777
+ "mailto:",
2778
+ "tel:",
2779
+ "callto:",
2780
+ "sms:",
2781
+ "cid:",
2782
+ "xmpp:"
2783
+ ]);
2784
+ const HAS_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
2785
+ const SITE_RELATIVE_RE = /^[/#?]/;
2786
+ const HOST_PORT_RE = /^(localhost|127\.0\.0\.1|0\.0\.0\.0|\[[0-9a-f:]+\]):\d+($|[/#?])/i;
2787
+ const BARE_HOST_RE = /^[^/?#]*\.[^/?#]*/;
2788
+ function canSetLink(editor) {
2789
+ if (!editor || editor.isEditable === false) return false;
2790
+ try {
2791
+ return editor.can().setMark("link");
2792
+ } catch {
2793
+ return false;
2794
+ }
2767
2795
  }
2768
- function mathRenderTarget(el, isBlock) {
2769
- if (!isBlock) return el;
2770
- return el.querySelector(".block-math-inner") ?? el;
2796
+ function isLinkActive(editor) {
2797
+ if (!editor) return false;
2798
+ return editor.isActive("link");
2771
2799
  }
2772
- function getMathLayerStyle(editor, kind, pos) {
2773
- const host = editor.view.dom.parentElement;
2774
- if (!host) return {};
2775
- const hostRect = host.getBoundingClientRect();
2776
- const editorRect = editor.view.dom.getBoundingClientRect();
2777
- const gap = 6;
2778
- const blockWidth = editor.view.dom.clientWidth;
2779
- if (pos != null) {
2780
- const el = resolveNodeEl(editor, pos);
2781
- if (el) {
2782
- const r2 = el.getBoundingClientRect();
2783
- const top = r2.bottom - hostRect.top + gap;
2784
- if (kind === "block") {
2785
- return {
2786
- left: editorRect.left - hostRect.left,
2787
- top,
2788
- width: blockWidth
2789
- };
2790
- }
2791
- return {
2792
- left: r2.left - hostRect.left,
2793
- top
2794
- };
2795
- }
2796
- }
2797
- const coords = editor.view.coordsAtPos(editor.state.selection.from);
2798
- if (kind === "block") {
2799
- return {
2800
- left: editorRect.left - hostRect.left,
2801
- top: coords.bottom - hostRect.top + gap,
2802
- width: blockWidth
2803
- };
2800
+ function readLinkHref(editor) {
2801
+ if (!editor) return "";
2802
+ const { href } = editor.getAttributes("link");
2803
+ return typeof href === "string" ? href : "";
2804
+ }
2805
+ function defaultProtocol(editor) {
2806
+ var _a, _b;
2807
+ const link = (_a = editor.extensionManager) == null ? void 0 : _a.extensions.find(
2808
+ (extension) => extension.name === "link"
2809
+ );
2810
+ const configured = (_b = link == null ? void 0 : link.options) == null ? void 0 : _b.defaultProtocol;
2811
+ return configured || "http";
2812
+ }
2813
+ function normalizeLinkHref(editor, raw) {
2814
+ const value = raw.trim();
2815
+ if (!value) return "";
2816
+ if (SITE_RELATIVE_RE.test(value)) return value;
2817
+ if (HOST_PORT_RE.test(value)) return `${defaultProtocol(editor)}://${value}`;
2818
+ if (HAS_SCHEME_RE.test(value)) return value;
2819
+ if (!BARE_HOST_RE.test(value)) return value;
2820
+ return `${defaultProtocol(editor)}://${value}`;
2821
+ }
2822
+ function applyLink(editor, raw) {
2823
+ if (!editor) return false;
2824
+ const href = normalizeLinkHref(editor, raw);
2825
+ if (!href) return false;
2826
+ if (!editor.can().setLink({ href })) return false;
2827
+ const isEmpty = editor.state.selection.empty;
2828
+ const insideLink = isLinkActive(editor);
2829
+ const chain = editor.chain().focus().extendMarkRange("link").setLink({ href });
2830
+ if (isEmpty && !insideLink) chain.insertContent({ type: "text", text: href });
2831
+ return chain.run();
2832
+ }
2833
+ function removeLink(editor) {
2834
+ if (!editor) return false;
2835
+ return editor.chain().focus().extendMarkRange("link").unsetLink().setMeta("preventAutolink", true).run();
2836
+ }
2837
+ function sanitizeLinkUrl(input2, baseUrl) {
2838
+ try {
2839
+ const url = new URL(input2, baseUrl);
2840
+ if (OPENABLE_PROTOCOLS.has(url.protocol)) return url.href;
2841
+ } catch {
2804
2842
  }
2805
- return {
2806
- left: coords.left - hostRect.left,
2807
- top: coords.bottom - hostRect.top + gap
2808
- };
2843
+ return "#";
2809
2844
  }
2810
- function MathEditorPopover({
2845
+ function openLinkUrl(input2, baseUrl) {
2846
+ if (!input2.trim()) return false;
2847
+ const safe = sanitizeLinkUrl(input2, baseUrl);
2848
+ if (safe === "#") return false;
2849
+ window.open(safe, "_blank", "noopener,noreferrer");
2850
+ return true;
2851
+ }
2852
+ function isApplyKey(event) {
2853
+ if (event.key !== "Enter") return false;
2854
+ return !isComposingKeyEvent(event.nativeEvent);
2855
+ }
2856
+ const panel = "_panel_qysb1_7";
2857
+ const field = "_field_qysb1_28";
2858
+ const fieldInvalid = "_fieldInvalid_qysb1_47";
2859
+ const input = "_input_qysb1_52";
2860
+ const divider = "_divider_qysb1_63";
2861
+ const btn = "_btn_qysb1_71";
2862
+ const apply = "_apply_qysb1_99";
2863
+ const styles$3 = {
2864
+ panel,
2865
+ field,
2866
+ fieldInvalid,
2867
+ input,
2868
+ divider,
2869
+ btn,
2870
+ apply
2871
+ };
2872
+ function LinkPopover({
2811
2873
  editor,
2812
- kind,
2813
- mode,
2814
- pos,
2815
- latex,
2816
- isNew = false,
2817
- newLabel,
2818
- placeholder,
2819
- doneLabel,
2820
- onConfirm,
2821
- onCancel
2874
+ trigger,
2875
+ labels,
2876
+ className,
2877
+ style
2822
2878
  }) {
2823
- const [draft, setDraft] = useState(latex);
2824
- const [layerStyle, setLayerStyle] = useState(
2825
- () => getMathLayerStyle(editor, kind, pos)
2826
- );
2827
- const titleId = useId();
2828
- const inputRef = useRef(null);
2829
- const rootRef = useRef(null);
2830
- const isBlock = kind === "block";
2831
- const host = editor.view.dom.parentElement;
2832
- useEffect(() => {
2833
- setDraft(latex);
2834
- }, [latex]);
2835
- useEffect(() => {
2836
- const update = () => setLayerStyle(getMathLayerStyle(editor, kind, pos));
2837
- update();
2838
- window.addEventListener("resize", update);
2839
- return () => window.removeEventListener("resize", update);
2840
- }, [editor, kind, pos, draft]);
2841
- useEffect(() => {
2842
- var _a;
2843
- (_a = inputRef.current) == null ? void 0 : _a.focus();
2844
- }, []);
2845
- useEffect(() => {
2846
- if (pos == null) return;
2847
- const el = resolveNodeEl(editor, pos);
2848
- if (!el) return;
2849
- el.classList.add("tmr-math-editing");
2850
- return () => {
2851
- el.classList.remove("tmr-math-editing");
2852
- };
2853
- }, [editor, pos]);
2854
- useEffect(() => {
2855
- if (pos == null) return;
2856
- const el = resolveNodeEl(editor, pos);
2857
- if (!el) return;
2858
- const target = mathRenderTarget(el, isBlock);
2859
- const src = draft.trim();
2860
- if (src) renderMathInto(target, src, isBlock);
2861
- else target.textContent = "";
2862
- }, [draft, pos, editor, isBlock]);
2863
- useEffect(() => {
2864
- if (pos == null || isNew) return;
2865
- const el = resolveNodeEl(editor, pos);
2866
- if (!el) return;
2867
- const target = mathRenderTarget(el, isBlock);
2868
- return () => {
2869
- const restore = latex.trim();
2870
- if (restore) renderMathInto(target, restore, isBlock);
2871
- else target.textContent = "";
2879
+ const [open, setOpen] = useState(false);
2880
+ return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange: setOpen, children: [
2881
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: trigger }),
2882
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
2883
+ Popover.Content,
2884
+ {
2885
+ sideOffset: 4,
2886
+ align: "start",
2887
+ onCloseAutoFocus: (e2) => e2.preventDefault(),
2888
+ children: /* @__PURE__ */ jsx(
2889
+ LinkPanel,
2890
+ {
2891
+ editor,
2892
+ labels,
2893
+ className,
2894
+ style,
2895
+ onClose: () => setOpen(false)
2896
+ }
2897
+ )
2898
+ }
2899
+ ) })
2900
+ ] });
2901
+ }
2902
+ function LinkPanel({
2903
+ editor,
2904
+ labels,
2905
+ className,
2906
+ style,
2907
+ onClose
2908
+ }) {
2909
+ const t = { ...defaultLinkPopoverLabels, ...labels };
2910
+ const [url, setUrl] = useState(() => readLinkHref(editor));
2911
+ const [invalid, setInvalid] = useState(false);
2912
+ const canEdit = canSetLink(editor);
2913
+ const hasUrl = url.trim().length > 0;
2914
+ const keepFocus = (e2) => e2.preventDefault();
2915
+ const apply2 = () => {
2916
+ if (!applyLink(editor, url)) {
2917
+ setInvalid(true);
2918
+ return;
2919
+ }
2920
+ setInvalid(false);
2921
+ onClose();
2922
+ };
2923
+ const openInNewWindow = () => {
2924
+ openLinkUrl(normalizeLinkHref(editor, url), window.location.href);
2925
+ };
2926
+ const remove = () => {
2927
+ removeLink(editor);
2928
+ onClose();
2929
+ };
2930
+ const onInputKeyDown = (e2) => {
2931
+ if (!isApplyKey(e2)) return;
2932
+ e2.preventDefault();
2933
+ apply2();
2934
+ };
2935
+ return /* @__PURE__ */ jsxs(
2936
+ "div",
2937
+ {
2938
+ className: className ? `${styles$3.panel} ${className}` : styles$3.panel,
2939
+ style,
2940
+ "data-link-popover": "",
2941
+ role: "dialog",
2942
+ "aria-label": t.field,
2943
+ children: [
2944
+ /* @__PURE__ */ jsx("span", { className: `${styles$3.field}${invalid ? ` ${styles$3.fieldInvalid}` : ""}`, children: /* @__PURE__ */ jsx(
2945
+ "input",
2946
+ {
2947
+ className: styles$3.input,
2948
+ "data-link-field": "",
2949
+ "data-link-invalid": invalid ? "" : void 0,
2950
+ type: "url",
2951
+ value: url,
2952
+ onChange: (e2) => {
2953
+ setUrl(e2.target.value);
2954
+ setInvalid(false);
2955
+ },
2956
+ onKeyDown: onInputKeyDown,
2957
+ placeholder: t.field,
2958
+ "aria-label": t.field,
2959
+ "aria-invalid": invalid || void 0,
2960
+ title: invalid ? t.invalid : void 0,
2961
+ autoFocus: true,
2962
+ autoComplete: "off",
2963
+ autoCorrect: "off",
2964
+ autoCapitalize: "off",
2965
+ spellCheck: false
2966
+ }
2967
+ ) }),
2968
+ /* @__PURE__ */ jsx(
2969
+ "button",
2970
+ {
2971
+ type: "button",
2972
+ className: `${styles$3.btn} ${styles$3.apply}`,
2973
+ "data-link-action": "apply",
2974
+ title: t.apply,
2975
+ "aria-label": t.apply,
2976
+ disabled: !canEdit || !hasUrl,
2977
+ onMouseDown: keepFocus,
2978
+ onClick: apply2,
2979
+ children: /* @__PURE__ */ jsx(CheckIcon, { size: 16 })
2980
+ }
2981
+ ),
2982
+ /* @__PURE__ */ jsx("span", { className: styles$3.divider, "aria-hidden": "true" }),
2983
+ /* @__PURE__ */ jsx(
2984
+ "button",
2985
+ {
2986
+ type: "button",
2987
+ className: styles$3.btn,
2988
+ "data-link-action": "open",
2989
+ title: t.open,
2990
+ "aria-label": t.open,
2991
+ disabled: !hasUrl,
2992
+ onMouseDown: keepFocus,
2993
+ onClick: openInNewWindow,
2994
+ children: /* @__PURE__ */ jsx(ExternalLinkIcon, { size: 16 })
2995
+ }
2996
+ ),
2997
+ /* @__PURE__ */ jsx(
2998
+ "button",
2999
+ {
3000
+ type: "button",
3001
+ className: styles$3.btn,
3002
+ "data-link-action": "remove",
3003
+ title: t.remove,
3004
+ "aria-label": t.remove,
3005
+ disabled: !canEdit,
3006
+ onMouseDown: keepFocus,
3007
+ onClick: remove,
3008
+ children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
3009
+ }
3010
+ )
3011
+ ]
3012
+ }
3013
+ );
3014
+ }
3015
+ function getTableSelectionInfo(state) {
3016
+ if (!isInTable(state)) return null;
3017
+ const rect = selectedRect(state);
3018
+ const rowCount = Math.max(1, rect.bottom - rect.top);
3019
+ const colCount = Math.max(1, rect.right - rect.left);
3020
+ let includesHeaderRow = false;
3021
+ for (let row2 = rect.top; row2 < rect.bottom; row2++) {
3022
+ if (rowIsHeader(rect.map, rect.table, row2)) {
3023
+ includesHeaderRow = true;
3024
+ break;
3025
+ }
3026
+ }
3027
+ return {
3028
+ rowCount,
3029
+ colCount,
3030
+ isMultiCell: rowCount > 1 || colCount > 1,
3031
+ includesHeaderRow,
3032
+ coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,
3033
+ coversAllCols: rect.left === 0 && rect.right === rect.map.width
3034
+ };
3035
+ }
3036
+ function isPosInCellSelection(selection, pos) {
3037
+ let found = false;
3038
+ selection.forEachCell((node, cellPos) => {
3039
+ if (pos >= cellPos && pos <= cellPos + node.nodeSize) {
3040
+ found = true;
3041
+ }
3042
+ });
3043
+ return found;
3044
+ }
3045
+ function addRowsBefore(editor, count) {
3046
+ const n = Math.max(1, count);
3047
+ for (let i = 0; i < n; i++) {
3048
+ if (!editor.commands.addRowBefore()) return false;
3049
+ }
3050
+ return true;
3051
+ }
3052
+ function addRowsAfter(editor, count) {
3053
+ const n = Math.max(1, count);
3054
+ for (let i = 0; i < n; i++) {
3055
+ if (!editor.commands.addRowAfter()) return false;
3056
+ }
3057
+ return true;
3058
+ }
3059
+ function addColumnsBefore(editor, count) {
3060
+ const n = Math.max(1, count);
3061
+ for (let i = 0; i < n; i++) {
3062
+ if (!editor.commands.addColumnBefore()) return false;
3063
+ }
3064
+ return true;
3065
+ }
3066
+ function addColumnsAfter(editor, count) {
3067
+ const n = Math.max(1, count);
3068
+ for (let i = 0; i < n; i++) {
3069
+ if (!editor.commands.addColumnAfter()) return false;
3070
+ }
3071
+ return true;
3072
+ }
3073
+ function deleteSelectedRows(editor) {
3074
+ const info = getTableSelectionInfo(editor.state);
3075
+ if (!info) return false;
3076
+ if (info.coversAllRows) return editor.commands.deleteTable();
3077
+ return editor.commands.deleteRow();
3078
+ }
3079
+ function deleteSelectedColumns(editor) {
3080
+ const info = getTableSelectionInfo(editor.state);
3081
+ if (!info) return false;
3082
+ if (info.coversAllCols) {
3083
+ if (info.coversAllRows) return editor.commands.deleteTable();
3084
+ return false;
3085
+ }
3086
+ return editor.commands.deleteColumn();
3087
+ }
3088
+ const STRUCTURAL_CELL_ATTRS = /* @__PURE__ */ new Set(["colspan", "rowspan"]);
3089
+ function selectedCellEntries(editor) {
3090
+ const { selection } = editor.state;
3091
+ const entries = [];
3092
+ if (selection instanceof CellSelection) {
3093
+ selection.forEachCell((node2, pos2) => {
3094
+ entries.push({ pos: pos2, node: node2 });
3095
+ });
3096
+ return entries;
3097
+ }
3098
+ const $cell = cellAround(selection.$from);
3099
+ if (!$cell) return entries;
3100
+ const pos = $cell.before($cell.depth);
3101
+ const node = editor.state.doc.nodeAt(pos);
3102
+ if (node) entries.push({ pos, node });
3103
+ return entries;
3104
+ }
3105
+ function clearSelectedCellContents(editor) {
3106
+ var _a;
3107
+ const entries = selectedCellEntries(editor);
3108
+ if (!entries.length) return false;
3109
+ const paragraph = editor.state.schema.nodes.paragraph;
3110
+ if (!paragraph) return false;
3111
+ const tr = editor.state.tr;
3112
+ for (const { pos, node } of [...entries].sort((a3, b3) => b3.pos - a3.pos)) {
3113
+ const isEmpty = node.childCount === 1 && !!((_a = node.firstChild) == null ? void 0 : _a.isTextblock) && node.firstChild.content.size === 0;
3114
+ if (isEmpty) continue;
3115
+ tr.replaceWith(pos + 1, pos + node.nodeSize - 1, paragraph.createAndFill());
3116
+ }
3117
+ if (!tr.docChanged) return false;
3118
+ editor.view.dispatch(tr.scrollIntoView());
3119
+ return true;
3120
+ }
3121
+ function resetSelectedCellStyles(editor) {
3122
+ const entries = selectedCellEntries(editor);
3123
+ if (!entries.length) return false;
3124
+ const tr = editor.state.tr;
3125
+ for (const { pos, node } of entries) {
3126
+ const attrs = node.type.spec.attrs ?? {};
3127
+ const next = { ...node.attrs };
3128
+ let changed = false;
3129
+ for (const [key, spec] of Object.entries(attrs)) {
3130
+ if (STRUCTURAL_CELL_ATTRS.has(key)) continue;
3131
+ const fallback = (spec == null ? void 0 : spec.default) ?? null;
3132
+ if (next[key] !== fallback) {
3133
+ next[key] = fallback;
3134
+ changed = true;
3135
+ }
3136
+ }
3137
+ if (changed) tr.setNodeMarkup(pos, void 0, next);
3138
+ }
3139
+ if (!tr.docChanged) return false;
3140
+ editor.view.dispatch(tr);
3141
+ return true;
3142
+ }
3143
+ function findTable(editor) {
3144
+ const $from = editor.state.selection.$from;
3145
+ for (let d = $from.depth; d > 0; d -= 1) {
3146
+ if ($from.node(d).type.name === "table") {
3147
+ return { pos: $from.before(d), node: $from.node(d) };
3148
+ }
3149
+ }
3150
+ let found = null;
3151
+ editor.state.doc.descendants((node, pos) => {
3152
+ if (found !== null) return false;
3153
+ if (node.type.name === "table") {
3154
+ found = { pos, node };
3155
+ return false;
3156
+ }
3157
+ return true;
3158
+ });
3159
+ return found;
3160
+ }
3161
+ function selectLineAt(editor, table, kind, index) {
3162
+ const map = TableMap.get(table.node);
3163
+ const start = table.pos + 1;
3164
+ const anchorCell = start + map.positionAt(kind === "row" ? index : 0, kind === "col" ? index : 0, table.node);
3165
+ const headCell = start + map.positionAt(
3166
+ kind === "row" ? index : map.height - 1,
3167
+ kind === "col" ? index : map.width - 1,
3168
+ table.node
3169
+ );
3170
+ editor.view.dispatch(
3171
+ editor.state.tr.setSelection(
3172
+ new CellSelection(
3173
+ editor.state.doc.resolve(anchorCell),
3174
+ editor.state.doc.resolve(headCell)
3175
+ )
3176
+ )
3177
+ );
3178
+ }
3179
+ function appendRowToTable(editor) {
3180
+ const table = findTable(editor);
3181
+ if (!table) return false;
3182
+ selectLineAt(editor, table, "row", TableMap.get(table.node).height - 1);
3183
+ return addRowsAfter(editor, 1);
3184
+ }
3185
+ function appendColumnToTable(editor) {
3186
+ const table = findTable(editor);
3187
+ if (!table) return false;
3188
+ selectLineAt(editor, table, "col", TableMap.get(table.node).width - 1);
3189
+ return addColumnsAfter(editor, 1);
3190
+ }
3191
+ const handle = "_handle_cco3n_9";
3192
+ const handleRow = "_handleRow_cco3n_30";
3193
+ const handleCol = "_handleCol_cco3n_40";
3194
+ const extend = "_extend_cco3n_70";
3195
+ const tableBubble = "_tableBubble_cco3n_115";
3196
+ const tableMenuItem = "_tableMenuItem_cco3n_128";
3197
+ const tableMenuItemIcon = "_tableMenuItemIcon_cco3n_154";
3198
+ const tableMenuItemLabel = "_tableMenuItemLabel_cco3n_164";
3199
+ const tableMenuDivider = "_tableMenuDivider_cco3n_169";
3200
+ const styles$2 = {
3201
+ handle,
3202
+ handleRow,
3203
+ handleCol,
3204
+ extend,
3205
+ tableBubble,
3206
+ tableMenuItem,
3207
+ tableMenuItemIcon,
3208
+ tableMenuItemLabel,
3209
+ tableMenuDivider
3210
+ };
3211
+ function edgeFlags(editor, cell) {
3212
+ try {
3213
+ const $cell = cellAround(editor.state.doc.resolve(editor.view.posAtDOM(cell, 0)));
3214
+ if (!$cell) return { onLastRow: false, onLastCol: false };
3215
+ const map = TableMap.get($cell.node(-1));
3216
+ const rect = map.findCell($cell.pos - $cell.start(-1));
3217
+ return {
3218
+ onLastRow: rect.bottom === map.height,
3219
+ onLastCol: rect.right === map.width
3220
+ };
3221
+ } catch {
3222
+ return { onLastRow: false, onLastCol: false };
3223
+ }
3224
+ }
3225
+ const COL_HANDLE_GAP = 22;
3226
+ const ROW_HANDLE_GAP = 26;
3227
+ const EXTEND_GAP = 6;
3228
+ const EXTEND_THICKNESS = 16;
3229
+ const HOVER_KEEP_MS = 160;
3230
+ function measureCell(editor, cell) {
3231
+ const table = cell.closest("table");
3232
+ const row2 = cell.closest("tr");
3233
+ if (!table || !row2) return null;
3234
+ try {
3235
+ editor.view.posAtDOM(cell, 0);
3236
+ } catch {
3237
+ return null;
3238
+ }
3239
+ const cellRect = cell.getBoundingClientRect();
3240
+ const rowRect = row2.getBoundingClientRect();
3241
+ const tableRect = table.getBoundingClientRect();
3242
+ const edges = edgeFlags(editor, cell);
3243
+ return {
3244
+ cell,
3245
+ ...edges,
3246
+ rowTop: rowRect.top,
3247
+ rowHeight: rowRect.height,
3248
+ colLeft: cellRect.left,
3249
+ colWidth: cellRect.width,
3250
+ tableLeft: tableRect.left,
3251
+ tableTop: tableRect.top,
3252
+ tableRight: tableRect.right,
3253
+ tableBottom: tableRect.bottom
3254
+ };
3255
+ }
3256
+ function selectRowOrColumn(editor, cell, kind) {
3257
+ let pos;
3258
+ try {
3259
+ pos = editor.view.posAtDOM(cell, 0);
3260
+ } catch {
3261
+ return false;
3262
+ }
3263
+ const $cell = cellAround(editor.state.doc.resolve(pos));
3264
+ if (!$cell) return false;
3265
+ const selection = kind === "row" ? CellSelection.rowSelection($cell) : CellSelection.colSelection($cell);
3266
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
3267
+ return true;
3268
+ }
3269
+ function menuItemsFor(editor, labels, kind) {
3270
+ const info = getTableSelectionInfo(editor.state);
3271
+ const rowN = (info == null ? void 0 : info.rowCount) ?? 1;
3272
+ const colN = (info == null ? void 0 : info.colCount) ?? 1;
3273
+ const multi = kind === "multi";
3274
+ const items = [];
3275
+ if (kind === "col" || kind === "multi") {
3276
+ items.push(
3277
+ {
3278
+ key: "col-before",
3279
+ group: "col",
3280
+ label: multi ? labels.tableAddColumnBeforeN(colN) : labels.tableAddColumnBefore,
3281
+ icon: /* @__PURE__ */ jsx(ColumnBeforeIcon, {}),
3282
+ run: () => addColumnsBefore(editor, colN)
3283
+ },
3284
+ {
3285
+ key: "col-after",
3286
+ group: "col",
3287
+ label: multi ? labels.tableAddColumnAfterN(colN) : labels.tableAddColumnAfter,
3288
+ icon: /* @__PURE__ */ jsx(ColumnAfterIcon, {}),
3289
+ run: () => addColumnsAfter(editor, colN)
3290
+ },
3291
+ {
3292
+ key: "col-delete",
3293
+ group: "col",
3294
+ label: multi ? labels.tableDeleteColumnN(colN) : labels.tableDeleteColumn,
3295
+ icon: /* @__PURE__ */ jsx(ColumnDeleteIcon, {}),
3296
+ // 只选了全部列、却没选全部行:删列会把表格删没,禁掉
3297
+ disabled: !!(info == null ? void 0 : info.coversAllCols) && !(info == null ? void 0 : info.coversAllRows),
3298
+ run: () => deleteSelectedColumns(editor)
3299
+ }
3300
+ );
3301
+ }
3302
+ if (kind === "row" || kind === "multi") {
3303
+ items.push(
3304
+ {
3305
+ key: "row-before",
3306
+ group: "row",
3307
+ label: multi ? labels.tableAddRowBeforeN(rowN) : labels.tableAddRowBefore,
3308
+ icon: /* @__PURE__ */ jsx(RowBeforeIcon, {}),
3309
+ // 上方是表头行时插行没意义
3310
+ disabled: !!(info == null ? void 0 : info.includesHeaderRow),
3311
+ run: () => addRowsBefore(editor, rowN)
3312
+ },
3313
+ {
3314
+ key: "row-after",
3315
+ group: "row",
3316
+ label: multi ? labels.tableAddRowAfterN(rowN) : labels.tableAddRowAfter,
3317
+ icon: /* @__PURE__ */ jsx(RowAfterIcon, {}),
3318
+ run: () => addRowsAfter(editor, rowN)
3319
+ },
3320
+ {
3321
+ key: "row-delete",
3322
+ group: "row",
3323
+ label: multi ? labels.tableDeleteRowN(rowN) : labels.tableDeleteRow,
3324
+ icon: /* @__PURE__ */ jsx(RowDeleteIcon, {}),
3325
+ disabled: !!(info == null ? void 0 : info.includesHeaderRow),
3326
+ run: () => deleteSelectedRows(editor)
3327
+ }
3328
+ );
3329
+ }
3330
+ items.push(
3331
+ {
3332
+ key: "cells-clear",
3333
+ group: "cells",
3334
+ label: labels.tableClearContent,
3335
+ icon: /* @__PURE__ */ jsx(EraserIcon, {}),
3336
+ run: () => clearSelectedCellContents(editor)
3337
+ },
3338
+ {
3339
+ key: "cells-reset",
3340
+ group: "cells",
3341
+ label: labels.tableResetCellStyles,
3342
+ icon: /* @__PURE__ */ jsx(RotateCcwIcon, {}),
3343
+ run: () => resetSelectedCellStyles(editor)
3344
+ }
3345
+ );
3346
+ return items;
3347
+ }
3348
+ function TableHandles({ editor, labels }) {
3349
+ const [hover, setHover] = useState(null);
3350
+ const [menu2, setMenu] = useState(null);
3351
+ const hoverRef = useRef(null);
3352
+ const menuRef = useRef(null);
3353
+ menuRef.current = menu2;
3354
+ const clearHover = useCallback(() => {
3355
+ if (!hoverRef.current) return;
3356
+ hoverRef.current = null;
3357
+ setHover(null);
3358
+ }, []);
3359
+ const closeMenu = useCallback(() => setMenu(null), []);
3360
+ const remeasureHover = useCallback(() => {
3361
+ var _a;
3362
+ const cell = (_a = hoverRef.current) == null ? void 0 : _a.cell;
3363
+ if (!cell) return;
3364
+ const next = cell.isConnected ? measureCell(editor, cell) : null;
3365
+ hoverRef.current = next;
3366
+ setHover(next);
3367
+ }, [editor]);
3368
+ const clearTimerRef = useRef(null);
3369
+ const cancelPendingClear = useCallback(() => {
3370
+ if (clearTimerRef.current === null) return;
3371
+ clearTimeout(clearTimerRef.current);
3372
+ clearTimerRef.current = null;
3373
+ }, []);
3374
+ useEffect(() => {
3375
+ const onMove = (event) => {
3376
+ var _a, _b;
3377
+ if (!editor.isEditable || menuRef.current) return;
3378
+ const target = event.target;
3379
+ if ((_a = target == null ? void 0 : target.closest) == null ? void 0 : _a.call(target, "[data-table-handle], [data-table-extend]")) {
3380
+ cancelPendingClear();
3381
+ return;
3382
+ }
3383
+ const cell = target && editor.view.dom.contains(target) ? target.closest("td, th") : null;
3384
+ if (!cell) {
3385
+ if (hoverRef.current && clearTimerRef.current === null) {
3386
+ clearTimerRef.current = setTimeout(() => {
3387
+ clearTimerRef.current = null;
3388
+ clearHover();
3389
+ }, HOVER_KEEP_MS);
3390
+ }
3391
+ return;
3392
+ }
3393
+ cancelPendingClear();
3394
+ if (((_b = hoverRef.current) == null ? void 0 : _b.cell) === cell) return;
3395
+ const next = measureCell(editor, cell);
3396
+ hoverRef.current = next;
3397
+ setHover(next);
3398
+ };
3399
+ const onBlurWindow = () => {
3400
+ cancelPendingClear();
3401
+ clearHover();
3402
+ };
3403
+ document.addEventListener("mousemove", onMove);
3404
+ document.addEventListener("mouseleave", onBlurWindow);
3405
+ window.addEventListener("scroll", remeasureHover, true);
3406
+ window.addEventListener("resize", remeasureHover);
3407
+ return () => {
3408
+ cancelPendingClear();
3409
+ document.removeEventListener("mousemove", onMove);
3410
+ document.removeEventListener("mouseleave", onBlurWindow);
3411
+ window.removeEventListener("scroll", remeasureHover, true);
3412
+ window.removeEventListener("resize", remeasureHover);
3413
+ };
3414
+ }, [editor, clearHover, cancelPendingClear, remeasureHover]);
3415
+ useEffect(() => {
3416
+ const dom = editor.view.dom;
3417
+ const onContextMenu = (event) => {
3418
+ const info = getTableSelectionInfo(editor.state);
3419
+ const { selection } = editor.state;
3420
+ if (!(info == null ? void 0 : info.isMultiCell) || !(selection instanceof CellSelection)) return;
3421
+ const coords = editor.view.posAtCoords({
3422
+ left: event.clientX,
3423
+ top: event.clientY
3424
+ });
3425
+ if (!coords || !isPosInCellSelection(selection, coords.pos)) return;
3426
+ event.preventDefault();
3427
+ hoverRef.current = null;
3428
+ setHover(null);
3429
+ setMenu({ kind: "multi", x: event.clientX, y: event.clientY });
3430
+ };
3431
+ dom.addEventListener("contextmenu", onContextMenu);
3432
+ return () => dom.removeEventListener("contextmenu", onContextMenu);
3433
+ }, [editor]);
3434
+ useEffect(() => {
3435
+ if (!menu2) return;
3436
+ const onKey = (event) => {
3437
+ if (event.key === "Escape") closeMenu();
3438
+ };
3439
+ const onDown = (event) => {
3440
+ var _a;
3441
+ const target = event.target;
3442
+ if ((_a = target == null ? void 0 : target.closest) == null ? void 0 : _a.call(target, "[data-table-menu]")) return;
3443
+ closeMenu();
3444
+ };
3445
+ document.addEventListener("keydown", onKey, true);
3446
+ document.addEventListener("mousedown", onDown);
3447
+ return () => {
3448
+ document.removeEventListener("keydown", onKey, true);
3449
+ document.removeEventListener("mousedown", onDown);
3450
+ };
3451
+ }, [menu2, closeMenu]);
3452
+ if (typeof document === "undefined") return null;
3453
+ const openHandleMenu = (kind) => {
3454
+ if (!hover) return;
3455
+ if (!selectRowOrColumn(editor, hover.cell, kind)) return;
3456
+ setHover(null);
3457
+ hoverRef.current = null;
3458
+ setMenu(
3459
+ kind === "row" ? { kind, x: hover.tableLeft + 6, y: hover.rowTop } : { kind, x: hover.colLeft, y: hover.tableTop + 6 }
3460
+ );
3461
+ };
3462
+ const items = menu2 ? menuItemsFor(editor, labels, menu2.kind) : [];
3463
+ const showHandles = !!hover && !menu2 && editor.isEditable;
3464
+ return createPortal(
3465
+ /* @__PURE__ */ jsxs(Fragment$2, { children: [
3466
+ showHandles && hover ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
3467
+ /* @__PURE__ */ jsx(
3468
+ "button",
3469
+ {
3470
+ type: "button",
3471
+ "data-table-handle": "row",
3472
+ className: `${styles$2.handle} ${styles$2.handleRow}`,
3473
+ style: {
3474
+ left: hover.tableLeft - ROW_HANDLE_GAP,
3475
+ // 长度跟着行高走(原来固定 28px 居中,行高时就显得太短)
3476
+ top: hover.rowTop,
3477
+ height: hover.rowHeight
3478
+ },
3479
+ title: labels.tableRowMenu,
3480
+ "aria-label": labels.tableRowMenu,
3481
+ onMouseDown: (e2) => e2.preventDefault(),
3482
+ onClick: () => openHandleMenu("row"),
3483
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "⋮" })
3484
+ }
3485
+ ),
3486
+ /* @__PURE__ */ jsx(
3487
+ "button",
3488
+ {
3489
+ type: "button",
3490
+ "data-table-handle": "col",
3491
+ className: `${styles$2.handle} ${styles$2.handleCol}`,
3492
+ style: {
3493
+ // 长度跟着列宽走,两端与单元格对齐
3494
+ left: hover.colLeft,
3495
+ top: hover.tableTop - COL_HANDLE_GAP,
3496
+ width: hover.colWidth
3497
+ },
3498
+ title: labels.tableColumnMenu,
3499
+ "aria-label": labels.tableColumnMenu,
3500
+ onMouseDown: (e2) => e2.preventDefault(),
3501
+ onClick: () => openHandleMenu("col"),
3502
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "⋯" })
3503
+ }
3504
+ ),
3505
+ hover.onLastCol ? /* @__PURE__ */ jsx(
3506
+ "button",
3507
+ {
3508
+ type: "button",
3509
+ "data-table-extend": "col",
3510
+ className: styles$2.extend,
3511
+ style: {
3512
+ left: hover.tableRight + EXTEND_GAP,
3513
+ top: hover.tableTop,
3514
+ width: EXTEND_THICKNESS,
3515
+ height: Math.max(EXTEND_THICKNESS, hover.tableBottom - hover.tableTop)
3516
+ },
3517
+ title: labels.tableAppendColumn,
3518
+ "aria-label": labels.tableAppendColumn,
3519
+ onMouseDown: (e2) => e2.preventDefault(),
3520
+ onClick: () => {
3521
+ appendColumnToTable(editor);
3522
+ remeasureHover();
3523
+ },
3524
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "+" })
3525
+ }
3526
+ ) : null,
3527
+ hover.onLastRow ? /* @__PURE__ */ jsx(
3528
+ "button",
3529
+ {
3530
+ type: "button",
3531
+ "data-table-extend": "row",
3532
+ className: styles$2.extend,
3533
+ style: {
3534
+ left: hover.tableLeft,
3535
+ top: hover.tableBottom + EXTEND_GAP,
3536
+ width: Math.max(EXTEND_THICKNESS, hover.tableRight - hover.tableLeft),
3537
+ height: EXTEND_THICKNESS
3538
+ },
3539
+ title: labels.tableAppendRow,
3540
+ "aria-label": labels.tableAppendRow,
3541
+ onMouseDown: (e2) => e2.preventDefault(),
3542
+ onClick: () => {
3543
+ appendRowToTable(editor);
3544
+ remeasureHover();
3545
+ },
3546
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "+" })
3547
+ }
3548
+ ) : null
3549
+ ] }) : null,
3550
+ menu2 ? /* @__PURE__ */ jsxs(
3551
+ "div",
3552
+ {
3553
+ className: styles$2.tableBubble,
3554
+ "data-table-menu": "",
3555
+ style: { left: menu2.x, top: menu2.y },
3556
+ role: "menu",
3557
+ onMouseDown: (e2) => e2.stopPropagation(),
3558
+ onContextMenu: (e2) => e2.preventDefault(),
3559
+ children: [
3560
+ items.map((item2, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
3561
+ index > 0 && item2.group !== items[index - 1].group ? /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuDivider, "aria-hidden": true }) : null,
3562
+ /* @__PURE__ */ jsxs(
3563
+ "button",
3564
+ {
3565
+ type: "button",
3566
+ role: "menuitem",
3567
+ className: styles$2.tableMenuItem,
3568
+ disabled: item2.disabled,
3569
+ onClick: () => {
3570
+ item2.run();
3571
+ closeMenu();
3572
+ },
3573
+ children: [
3574
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemIcon, "aria-hidden": true, children: item2.icon }),
3575
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemLabel, children: item2.label })
3576
+ ]
3577
+ }
3578
+ )
3579
+ ] }, item2.key)),
3580
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuDivider, "aria-hidden": true }),
3581
+ /* @__PURE__ */ jsxs(
3582
+ "button",
3583
+ {
3584
+ type: "button",
3585
+ role: "menuitem",
3586
+ className: styles$2.tableMenuItem,
3587
+ onClick: () => {
3588
+ editor.commands.deleteTable();
3589
+ closeMenu();
3590
+ },
3591
+ children: [
3592
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemIcon, "aria-hidden": true, children: /* @__PURE__ */ jsx(TableDeleteIcon, {}) }),
3593
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemLabel, children: labels.tableDeleteTable })
3594
+ ]
3595
+ }
3596
+ )
3597
+ ]
3598
+ }
3599
+ ) : null
3600
+ ] }),
3601
+ document.body
3602
+ );
3603
+ }
3604
+ function resolveNodeEl(editor, pos) {
3605
+ const dom = editor.view.nodeDOM(pos);
3606
+ if (dom instanceof HTMLElement) return dom;
3607
+ if (dom instanceof Node) return dom.parentElement;
3608
+ return null;
3609
+ }
3610
+ function mathRenderTarget(el, isBlock) {
3611
+ if (!isBlock) return el;
3612
+ return el.querySelector(".block-math-inner") ?? el;
3613
+ }
3614
+ function getMathLayerStyle(editor, kind, pos) {
3615
+ const host = editor.view.dom.parentElement;
3616
+ if (!host) return {};
3617
+ const hostRect = host.getBoundingClientRect();
3618
+ const editorRect = editor.view.dom.getBoundingClientRect();
3619
+ const gap = 6;
3620
+ const blockWidth = editor.view.dom.clientWidth;
3621
+ if (pos != null) {
3622
+ const el = resolveNodeEl(editor, pos);
3623
+ if (el) {
3624
+ const r2 = el.getBoundingClientRect();
3625
+ const top = r2.bottom - hostRect.top + gap;
3626
+ if (kind === "block") {
3627
+ return {
3628
+ left: editorRect.left - hostRect.left,
3629
+ top,
3630
+ width: blockWidth
3631
+ };
3632
+ }
3633
+ return {
3634
+ left: r2.left - hostRect.left,
3635
+ top
3636
+ };
3637
+ }
3638
+ }
3639
+ const coords = editor.view.coordsAtPos(editor.state.selection.from);
3640
+ if (kind === "block") {
3641
+ return {
3642
+ left: editorRect.left - hostRect.left,
3643
+ top: coords.bottom - hostRect.top + gap,
3644
+ width: blockWidth
3645
+ };
3646
+ }
3647
+ return {
3648
+ left: coords.left - hostRect.left,
3649
+ top: coords.bottom - hostRect.top + gap
3650
+ };
3651
+ }
3652
+ function MathEditorPopover({
3653
+ editor,
3654
+ kind,
3655
+ mode,
3656
+ pos,
3657
+ latex,
3658
+ isNew = false,
3659
+ newLabel,
3660
+ placeholder,
3661
+ doneLabel,
3662
+ onConfirm,
3663
+ onCancel
3664
+ }) {
3665
+ const [draft, setDraft] = useState(latex);
3666
+ const [layerStyle, setLayerStyle] = useState(
3667
+ () => getMathLayerStyle(editor, kind, pos)
3668
+ );
3669
+ const titleId = useId();
3670
+ const inputRef = useRef(null);
3671
+ const rootRef = useRef(null);
3672
+ const isBlock = kind === "block";
3673
+ const host = editor.view.dom.parentElement;
3674
+ useEffect(() => {
3675
+ setDraft(latex);
3676
+ }, [latex]);
3677
+ useEffect(() => {
3678
+ const update = () => setLayerStyle(getMathLayerStyle(editor, kind, pos));
3679
+ update();
3680
+ window.addEventListener("resize", update);
3681
+ return () => window.removeEventListener("resize", update);
3682
+ }, [editor, kind, pos, draft]);
3683
+ useEffect(() => {
3684
+ var _a;
3685
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
3686
+ }, []);
3687
+ useEffect(() => {
3688
+ if (pos == null) return;
3689
+ const el = resolveNodeEl(editor, pos);
3690
+ if (!el) return;
3691
+ el.classList.add("tmr-math-editing");
3692
+ return () => {
3693
+ el.classList.remove("tmr-math-editing");
3694
+ };
3695
+ }, [editor, pos]);
3696
+ useEffect(() => {
3697
+ if (pos == null) return;
3698
+ const el = resolveNodeEl(editor, pos);
3699
+ if (!el) return;
3700
+ const target = mathRenderTarget(el, isBlock);
3701
+ const src = draft.trim();
3702
+ if (src) renderMathInto(target, src, isBlock);
3703
+ else target.textContent = "";
3704
+ }, [draft, pos, editor, isBlock]);
3705
+ useEffect(() => {
3706
+ if (pos == null || isNew) return;
3707
+ const el = resolveNodeEl(editor, pos);
3708
+ if (!el) return;
3709
+ const target = mathRenderTarget(el, isBlock);
3710
+ return () => {
3711
+ const restore = latex.trim();
3712
+ if (restore) renderMathInto(target, restore, isBlock);
3713
+ else target.textContent = "";
2872
3714
  };
2873
3715
  }, [pos, editor, isBlock, latex, isNew]);
2874
3716
  useEffect(() => {
@@ -2907,7 +3749,7 @@ function MathEditorPopover({
2907
3749
  "textarea",
2908
3750
  {
2909
3751
  ref: inputRef,
2910
- className: styles$3.mathInput,
3752
+ className: styles$5.mathInput,
2911
3753
  value: draft,
2912
3754
  placeholder,
2913
3755
  rows: Math.max(3, draft.split("\n").length),
@@ -2919,7 +3761,7 @@ function MathEditorPopover({
2919
3761
  "input",
2920
3762
  {
2921
3763
  ref: inputRef,
2922
- className: styles$3.mathInput,
3764
+ className: styles$5.mathInput,
2923
3765
  value: draft,
2924
3766
  placeholder,
2925
3767
  "aria-labelledby": titleId,
@@ -2933,7 +3775,7 @@ function MathEditorPopover({
2933
3775
  "div",
2934
3776
  {
2935
3777
  ref: rootRef,
2936
- className: styles$3.mathLayer,
3778
+ className: styles$5.mathLayer,
2937
3779
  style: layerStyle,
2938
3780
  role: "dialog",
2939
3781
  "aria-modal": "false",
@@ -2941,15 +3783,15 @@ function MathEditorPopover({
2941
3783
  children: /* @__PURE__ */ jsxs(
2942
3784
  "div",
2943
3785
  {
2944
- className: isBlock ? `${styles$3.mathStack} ${styles$3.mathStackBlock}` : styles$3.mathStack,
3786
+ className: isBlock ? `${styles$5.mathStack} ${styles$5.mathStackBlock}` : styles$5.mathStack,
2945
3787
  children: [
2946
3788
  showHint ? /* @__PURE__ */ jsxs(
2947
3789
  "div",
2948
3790
  {
2949
3791
  id: titleId,
2950
- className: isBlock ? `${styles$3.mathHint} ${styles$3.mathHintBlock}` : styles$3.mathHint,
3792
+ className: isBlock ? `${styles$5.mathHint} ${styles$5.mathHintBlock}` : styles$5.mathHint,
2951
3793
  children: [
2952
- /* @__PURE__ */ jsx("span", { className: styles$3.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
3794
+ /* @__PURE__ */ jsx("span", { className: styles$5.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
2953
3795
  newLabel
2954
3796
  ]
2955
3797
  }
@@ -2958,20 +3800,20 @@ function MathEditorPopover({
2958
3800
  "div",
2959
3801
  {
2960
3802
  id: showHint ? void 0 : titleId,
2961
- className: isBlock ? `${styles$3.mathField} ${styles$3.mathFieldBlock}` : styles$3.mathField,
3803
+ className: isBlock ? `${styles$5.mathField} ${styles$5.mathFieldBlock}` : styles$5.mathField,
2962
3804
  children: [
2963
3805
  field2,
2964
3806
  /* @__PURE__ */ jsxs(
2965
3807
  "button",
2966
3808
  {
2967
3809
  type: "button",
2968
- className: styles$3.mathDone,
3810
+ className: styles$5.mathDone,
2969
3811
  disabled: !canSubmit,
2970
3812
  title: isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`,
2971
3813
  onClick: submit,
2972
3814
  children: [
2973
3815
  doneLabel,
2974
- /* @__PURE__ */ jsx("span", { className: styles$3.mathDoneKbd, "aria-hidden": true, children: "↵" })
3816
+ /* @__PURE__ */ jsx("span", { className: styles$5.mathDoneKbd, "aria-hidden": true, children: "↵" })
2975
3817
  ]
2976
3818
  }
2977
3819
  )
@@ -2986,56 +3828,27 @@ function MathEditorPopover({
2986
3828
  host
2987
3829
  );
2988
3830
  }
2989
- function ToolbarButton({
2990
- title,
2991
- active: active2,
2992
- disabled,
2993
- busy,
2994
- onClick,
2995
- children
2996
- }) {
3831
+ const ToolbarButton = forwardRef(function ToolbarButton2({ title, active: active2, disabled, busy, onClick, children, className, ...rest }, ref) {
2997
3832
  return /* @__PURE__ */ jsx(
2998
3833
  "button",
2999
3834
  {
3835
+ ...rest,
3836
+ ref,
3000
3837
  type: "button",
3001
3838
  title,
3002
3839
  "aria-label": title,
3003
3840
  "aria-pressed": active2,
3004
3841
  "aria-busy": busy,
3005
3842
  disabled,
3006
- className: `${styles$3.btn} ${active2 ? styles$3.btnActive : ""}`,
3843
+ className: `${styles$5.btn} ${active2 ? styles$5.btnActive : ""}${className ? ` ${className}` : ""}`,
3007
3844
  onMouseDown: (e2) => e2.preventDefault(),
3008
3845
  onClick,
3009
3846
  children
3010
3847
  }
3011
3848
  );
3012
- }
3849
+ });
3013
3850
  function Divider() {
3014
- return /* @__PURE__ */ jsx("span", { className: styles$3.divider, "aria-hidden": true });
3015
- }
3016
- function TableMenuItem({
3017
- label,
3018
- disabled,
3019
- onClick,
3020
- children
3021
- }) {
3022
- return /* @__PURE__ */ jsxs(
3023
- "button",
3024
- {
3025
- type: "button",
3026
- disabled,
3027
- className: styles$3.tableMenuItem,
3028
- onMouseDown: (e2) => e2.preventDefault(),
3029
- onClick,
3030
- children: [
3031
- /* @__PURE__ */ jsx("span", { className: styles$3.tableMenuItemIcon, "aria-hidden": true, children }),
3032
- /* @__PURE__ */ jsx("span", { className: styles$3.tableMenuItemLabel, children: label })
3033
- ]
3034
- }
3035
- );
3036
- }
3037
- function TableMenuDivider() {
3038
- return /* @__PURE__ */ jsx("div", { className: styles$3.tableMenuDivider, "aria-hidden": true });
3851
+ return /* @__PURE__ */ jsx("span", { className: styles$5.divider, "aria-hidden": true });
3039
3852
  }
3040
3853
  const MenuCloseCtx = createContext(() => {
3041
3854
  });
@@ -3050,7 +3863,7 @@ function MenuPopover({
3050
3863
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3051
3864
  Popover.Content,
3052
3865
  {
3053
- className: styles$3.menu,
3866
+ className: styles$5.menu,
3054
3867
  sideOffset: 4,
3055
3868
  align: "start",
3056
3869
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -3072,7 +3885,7 @@ function MenuItem({
3072
3885
  {
3073
3886
  type: "button",
3074
3887
  disabled,
3075
- className: `${styles$3.menuItem} ${selected ? styles$3.menuItemSelected : ""}`,
3888
+ className: `${styles$5.menuItem} ${selected ? styles$5.menuItemSelected : ""}`,
3076
3889
  onMouseDown: (e2) => e2.preventDefault(),
3077
3890
  onClick: () => {
3078
3891
  onSelect();
@@ -3107,21 +3920,21 @@ function TableInsertItem({
3107
3920
  {
3108
3921
  type: "button",
3109
3922
  disabled,
3110
- className: `${styles$3.menuItem} ${open ? styles$3.menuItemSelected : ""}`,
3923
+ className: `${styles$5.menuItem} ${open ? styles$5.menuItemSelected : ""}`,
3111
3924
  onMouseDown: (e2) => e2.preventDefault(),
3112
3925
  children: [
3113
- /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3114
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "⊞" }),
3926
+ /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
3927
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "⊞" }),
3115
3928
  labels.tableInsert
3116
3929
  ] }),
3117
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.tableInsertCaret })
3930
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.tableInsertCaret })
3118
3931
  ]
3119
3932
  }
3120
3933
  ) }),
3121
3934
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
3122
3935
  Popover.Content,
3123
3936
  {
3124
- className: styles$3.tableSizePicker,
3937
+ className: styles$5.tableSizePicker,
3125
3938
  side: "right",
3126
3939
  align: "start",
3127
3940
  sideOffset: 6,
@@ -3131,7 +3944,7 @@ function TableInsertItem({
3131
3944
  /* @__PURE__ */ jsx(
3132
3945
  "div",
3133
3946
  {
3134
- className: styles$3.tableSizeGrid,
3947
+ className: styles$5.tableSizeGrid,
3135
3948
  style: {
3136
3949
  gridTemplateColumns: `repeat(${TABLE_PICKER_COLS}, 1fr)`
3137
3950
  },
@@ -3145,7 +3958,7 @@ function TableInsertItem({
3145
3958
  {
3146
3959
  type: "button",
3147
3960
  "aria-label": labels.tableSizeSelected(col, row2),
3148
- className: `${styles$3.tableSizeCell} ${active2 ? styles$3.tableSizeCellActive : ""}`,
3961
+ className: `${styles$5.tableSizeCell} ${active2 ? styles$5.tableSizeCellActive : ""}`,
3149
3962
  onMouseDown: (e2) => e2.preventDefault(),
3150
3963
  onMouseEnter: () => setHover({ cols: col, rows: row2 }),
3151
3964
  onClick: () => {
@@ -3160,7 +3973,7 @@ function TableInsertItem({
3160
3973
  })
3161
3974
  }
3162
3975
  ),
3163
- /* @__PURE__ */ jsx("div", { className: styles$3.tableSizeLabel, children: hover.cols > 0 ? labels.tableSizeSelected(hover.cols, hover.rows) : labels.tableInsert })
3976
+ /* @__PURE__ */ jsx("div", { className: styles$5.tableSizeLabel, children: hover.cols > 0 ? labels.tableSizeSelected(hover.cols, hover.rows) : labels.tableInsert })
3164
3977
  ]
3165
3978
  }
3166
3979
  ) })
@@ -3182,20 +3995,20 @@ function ColorPopover({
3182
3995
  "button",
3183
3996
  {
3184
3997
  type: "button",
3185
- className: styles$3.btn,
3998
+ className: styles$5.btn,
3186
3999
  title,
3187
4000
  "aria-label": title,
3188
4001
  onMouseDown: (e2) => e2.preventDefault(),
3189
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.colorIcon, children: [
3190
- /* @__PURE__ */ jsx("span", { className: styles$3.colorIconGlyph, children: glyph }),
3191
- /* @__PURE__ */ jsx("span", { className: styles$3.colorIconBar, style: { background: bar2 } })
4002
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.colorIcon, children: [
4003
+ /* @__PURE__ */ jsx("span", { className: styles$5.colorIconGlyph, children: glyph }),
4004
+ /* @__PURE__ */ jsx("span", { className: styles$5.colorIconBar, style: { background: bar2 } })
3192
4005
  ] })
3193
4006
  }
3194
4007
  ) }),
3195
4008
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3196
4009
  Popover.Content,
3197
4010
  {
3198
- className: styles$3.popoverContent,
4011
+ className: styles$5.popoverContent,
3199
4012
  sideOffset: 4,
3200
4013
  align: "start",
3201
4014
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -3226,6 +4039,8 @@ function EditorToolbar({
3226
4039
  importMenuItems,
3227
4040
  showImport = true,
3228
4041
  labels,
4042
+ onSearch,
4043
+ searchActive = false,
3229
4044
  extraToolbarItems,
3230
4045
  className
3231
4046
  }) {
@@ -3270,60 +4085,6 @@ function EditorToolbar({
3270
4085
  }, [editor]);
3271
4086
  const fileInputRef = useRef(null);
3272
4087
  const chain = () => editor.chain().focus();
3273
- const [tableMenu, setTableMenu] = useState(
3274
- null
3275
- );
3276
- const closeTableMenu = useCallback(() => setTableMenu(null), []);
3277
- useEffect(() => {
3278
- const dom = editor.view.dom;
3279
- const onContextMenu = (e2) => {
3280
- const coords = editor.view.posAtCoords({
3281
- left: e2.clientX,
3282
- top: e2.clientY
3283
- });
3284
- if (!coords) return;
3285
- const $pos = editor.state.doc.resolve(coords.pos);
3286
- let inTable = false;
3287
- for (let d = $pos.depth; d > 0; d--) {
3288
- if ($pos.node(d).type.name === "table") {
3289
- inTable = true;
3290
- break;
3291
- }
3292
- }
3293
- if (!inTable) return;
3294
- e2.preventDefault();
3295
- preserveTableSelectionOnContextMenu(editor, coords.pos);
3296
- setTableMenu({ x: e2.clientX, y: e2.clientY });
3297
- };
3298
- dom.addEventListener("contextmenu", onContextMenu);
3299
- return () => dom.removeEventListener("contextmenu", onContextMenu);
3300
- }, [editor]);
3301
- useEffect(() => {
3302
- if (!tableMenu) return;
3303
- const onKey = (e2) => {
3304
- if (e2.key === "Escape") closeTableMenu();
3305
- };
3306
- document.addEventListener("mousedown", closeTableMenu);
3307
- document.addEventListener("keydown", onKey, true);
3308
- return () => {
3309
- document.removeEventListener("mousedown", closeTableMenu);
3310
- document.removeEventListener("keydown", onKey, true);
3311
- };
3312
- }, [tableMenu, closeTableMenu]);
3313
- const runTable = useCallback(
3314
- (fn) => {
3315
- fn();
3316
- closeTableMenu();
3317
- },
3318
- [closeTableMenu]
3319
- );
3320
- const tableSel = tableMenu ? getTableSelectionInfo(editor.state) : null;
3321
- const tableRowN = (tableSel == null ? void 0 : tableSel.rowCount) ?? 1;
3322
- const tableColN = (tableSel == null ? void 0 : tableSel.colCount) ?? 1;
3323
- const tableMulti = (tableSel == null ? void 0 : tableSel.isMultiCell) ?? false;
3324
- const disableAddRowBefore = !!(tableSel == null ? void 0 : tableSel.includesHeaderRow);
3325
- const disableDeleteRow = !!(tableSel == null ? void 0 : tableSel.includesHeaderRow);
3326
- const disableDeleteColumn = !!(tableSel == null ? void 0 : tableSel.coversAllCols) && !(tableSel == null ? void 0 : tableSel.coversAllRows);
3327
4088
  const handlePickImage = () => {
3328
4089
  var _a;
3329
4090
  return (_a = fileInputRef.current) == null ? void 0 : _a.click();
@@ -3420,14 +4181,6 @@ function EditorToolbar({
3420
4181
  if (color) chain().setHighlight({ color }).run();
3421
4182
  else chain().unsetHighlight().run();
3422
4183
  };
3423
- const toggleLink = () => {
3424
- if (state.link) {
3425
- chain().unsetLink().run();
3426
- return;
3427
- }
3428
- const url = window.prompt(t.linkPrompt);
3429
- if (url) chain().setLink({ href: url }).run();
3430
- };
3431
4184
  const setBlockStyle = (level) => {
3432
4185
  if (level === 0) chain().setParagraph().run();
3433
4186
  else
@@ -3511,8 +4264,8 @@ function EditorToolbar({
3511
4264
  /* @__PURE__ */ jsx(
3512
4265
  "div",
3513
4266
  {
3514
- className: className ? `${styles$3.toolbar} ${className}` : styles$3.toolbar,
3515
- children: /* @__PURE__ */ jsxs("div", { className: styles$3.inner, children: [
4267
+ className: className ? `${styles$5.toolbar} ${className}` : styles$5.toolbar,
4268
+ children: /* @__PURE__ */ jsxs("div", { className: styles$5.inner, children: [
3516
4269
  /* @__PURE__ */ jsx(
3517
4270
  ToolbarButton,
3518
4271
  {
@@ -3539,12 +4292,12 @@ function EditorToolbar({
3539
4292
  "button",
3540
4293
  {
3541
4294
  type: "button",
3542
- className: styles$3.styleTrigger,
4295
+ className: styles$5.styleTrigger,
3543
4296
  title: t.style,
3544
4297
  onMouseDown: (e2) => e2.preventDefault(),
3545
4298
  children: [
3546
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.style }),
3547
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
4299
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.style }),
4300
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
3548
4301
  ]
3549
4302
  }
3550
4303
  ),
@@ -3554,8 +4307,8 @@ function EditorToolbar({
3554
4307
  {
3555
4308
  selected: (state.headingLevel ?? 0) === 0,
3556
4309
  onSelect: () => setBlockStyle(0),
3557
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3558
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "¶" }),
4310
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4311
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "¶" }),
3559
4312
  t.normalText
3560
4313
  ] })
3561
4314
  }
@@ -3565,8 +4318,8 @@ function EditorToolbar({
3565
4318
  {
3566
4319
  selected: state.headingLevel === lv,
3567
4320
  onSelect: () => setBlockStyle(lv),
3568
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3569
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: `H${lv}` }),
4321
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4322
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: `H${lv}` }),
3570
4323
  t.headingLabel(lv)
3571
4324
  ] })
3572
4325
  },
@@ -3582,14 +4335,14 @@ function EditorToolbar({
3582
4335
  "button",
3583
4336
  {
3584
4337
  type: "button",
3585
- className: styles$3.styleTrigger,
4338
+ className: styles$5.styleTrigger,
3586
4339
  title: t.fontSize,
3587
4340
  "aria-label": t.fontSize,
3588
4341
  disabled: !canEditFontSize,
3589
4342
  onMouseDown: (e2) => e2.preventDefault(),
3590
4343
  children: [
3591
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: state.fontSize || t.fontSize }),
3592
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
4344
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: state.fontSize || t.fontSize }),
4345
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
3593
4346
  ]
3594
4347
  }
3595
4348
  ),
@@ -3599,8 +4352,8 @@ function EditorToolbar({
3599
4352
  {
3600
4353
  selected: !state.fontSize,
3601
4354
  onSelect: () => applyFontSize(""),
3602
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3603
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "A" }),
4355
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4356
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "A" }),
3604
4357
  t.fontSizeDefault
3605
4358
  ] })
3606
4359
  }
@@ -3610,8 +4363,8 @@ function EditorToolbar({
3610
4363
  {
3611
4364
  selected: state.fontSize === size,
3612
4365
  onSelect: () => applyFontSize(size),
3613
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3614
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: parseInt(size, 10) }),
4366
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4367
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: parseInt(size, 10) }),
3615
4368
  size
3616
4369
  ] })
3617
4370
  },
@@ -3695,13 +4448,13 @@ function EditorToolbar({
3695
4448
  "button",
3696
4449
  {
3697
4450
  type: "button",
3698
- className: `${styles$3.scriptTrigger} ${scriptActive !== "normal" ? styles$3.btnActive : ""}`,
4451
+ className: `${styles$5.scriptTrigger} ${scriptActive !== "normal" ? styles$5.btnActive : ""}`,
3699
4452
  title: t.scriptMenu,
3700
4453
  "aria-label": t.scriptMenu,
3701
4454
  onMouseDown: (e2) => e2.preventDefault(),
3702
4455
  children: [
3703
- /* @__PURE__ */ jsx("span", { className: styles$3.scriptTriggerGlyph, children: "A" }),
3704
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
4456
+ /* @__PURE__ */ jsx("span", { className: styles$5.scriptTriggerGlyph, children: "A" }),
4457
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
3705
4458
  ]
3706
4459
  }
3707
4460
  ),
@@ -3711,8 +4464,8 @@ function EditorToolbar({
3711
4464
  {
3712
4465
  selected: scriptActive === "normal",
3713
4466
  onSelect: () => chain().unsetSuperscript().unsetSubscript().run(),
3714
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3715
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "A" }),
4467
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4468
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "A" }),
3716
4469
  t.scriptNormal
3717
4470
  ] })
3718
4471
  }
@@ -3722,8 +4475,8 @@ function EditorToolbar({
3722
4475
  {
3723
4476
  selected: scriptActive === "superscript",
3724
4477
  onSelect: () => chain().unsetSubscript().toggleSuperscript().run(),
3725
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3726
- /* @__PURE__ */ jsxs("span", { className: `${styles$3.styleIcon} ${styles$3.scriptGlyph}`, children: [
4478
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4479
+ /* @__PURE__ */ jsxs("span", { className: `${styles$5.styleIcon} ${styles$5.scriptGlyph}`, children: [
3727
4480
  "x",
3728
4481
  /* @__PURE__ */ jsx("sup", { children: "2" })
3729
4482
  ] }),
@@ -3736,8 +4489,8 @@ function EditorToolbar({
3736
4489
  {
3737
4490
  selected: scriptActive === "subscript",
3738
4491
  onSelect: () => chain().unsetSuperscript().toggleSubscript().run(),
3739
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3740
- /* @__PURE__ */ jsxs("span", { className: `${styles$3.styleIcon} ${styles$3.scriptGlyph}`, children: [
4492
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4493
+ /* @__PURE__ */ jsxs("span", { className: `${styles$5.styleIcon} ${styles$5.scriptGlyph}`, children: [
3741
4494
  "x",
3742
4495
  /* @__PURE__ */ jsx("sub", { children: "2" })
3743
4496
  ] }),
@@ -3749,7 +4502,20 @@ function EditorToolbar({
3749
4502
  }
3750
4503
  ),
3751
4504
  /* @__PURE__ */ jsx(Divider, {}),
3752
- /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, onClick: toggleLink, children: /* @__PURE__ */ jsx(LinkIcon, {}) }),
4505
+ /* @__PURE__ */ jsx(
4506
+ LinkPopover,
4507
+ {
4508
+ editor,
4509
+ labels: {
4510
+ field: t.linkPrompt,
4511
+ apply: t.linkApply,
4512
+ open: t.linkOpen,
4513
+ remove: t.linkRemove,
4514
+ invalid: t.linkInvalid
4515
+ },
4516
+ trigger: /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, children: /* @__PURE__ */ jsx(LinkIcon, {}) })
4517
+ }
4518
+ ),
3753
4519
  onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
3754
4520
  /* @__PURE__ */ jsx(ToolbarButton, { title: t.image, onClick: handlePickImage, children: /* @__PURE__ */ jsx(ImageIcon, {}) }),
3755
4521
  /* @__PURE__ */ jsx(
@@ -3770,19 +4536,19 @@ function EditorToolbar({
3770
4536
  "button",
3771
4537
  {
3772
4538
  type: "button",
3773
- className: styles$3.styleTrigger,
4539
+ className: styles$5.styleTrigger,
3774
4540
  title: importTitle,
3775
4541
  "aria-label": importTitle,
3776
4542
  "aria-busy": !!importing,
3777
4543
  disabled: !!importing,
3778
4544
  onMouseDown: (e2) => e2.preventDefault(),
3779
4545
  children: [
3780
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.importDocument }),
4546
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.importDocument }),
3781
4547
  /* @__PURE__ */ jsx(
3782
4548
  ChevronDownIcon,
3783
4549
  {
3784
4550
  size: 12,
3785
- className: styles$3.styleTriggerCaret
4551
+ className: styles$5.styleTriggerCaret
3786
4552
  }
3787
4553
  )
3788
4554
  ]
@@ -3804,7 +4570,7 @@ function EditorToolbar({
3804
4570
  title: t.blockquote,
3805
4571
  active: state.blockquote,
3806
4572
  onClick: () => chain().toggleBlockquote().run(),
3807
- children: /* @__PURE__ */ jsx("span", { className: styles$3.txtIcon, children: "❝" })
4573
+ children: /* @__PURE__ */ jsx("span", { className: styles$5.txtIcon, children: "❝" })
3808
4574
  }
3809
4575
  ),
3810
4576
  /* @__PURE__ */ jsx(Divider, {}),
@@ -3836,6 +4602,15 @@ function EditorToolbar({
3836
4602
  }
3837
4603
  ),
3838
4604
  /* @__PURE__ */ jsx(Divider, {}),
4605
+ onSearch ? /* @__PURE__ */ jsx(
4606
+ ToolbarButton,
4607
+ {
4608
+ title: t.search,
4609
+ active: searchActive,
4610
+ onClick: onSearch,
4611
+ children: /* @__PURE__ */ jsx(SearchIcon, {})
4612
+ }
4613
+ ) : null,
3839
4614
  /* @__PURE__ */ jsxs(
3840
4615
  MenuPopover,
3841
4616
  {
@@ -3843,30 +4618,30 @@ function EditorToolbar({
3843
4618
  "button",
3844
4619
  {
3845
4620
  type: "button",
3846
- className: styles$3.styleTrigger,
4621
+ className: styles$5.styleTrigger,
3847
4622
  title: t.more,
3848
4623
  onMouseDown: (e2) => e2.preventDefault(),
3849
4624
  children: [
3850
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.more }),
3851
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
4625
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.more }),
4626
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
3852
4627
  ]
3853
4628
  }
3854
4629
  ),
3855
4630
  children: [
3856
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().toggleCodeBlock().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3857
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "{ }" }),
4631
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().toggleCodeBlock().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4632
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "{ }" }),
3858
4633
  t.codeBlock
3859
4634
  ] }) }),
3860
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("inline"), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3861
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "√x" }),
4635
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("inline"), children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4636
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "√x" }),
3862
4637
  t.inlineMath
3863
4638
  ] }) }),
3864
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("block"), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3865
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "∑" }),
4639
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("block"), children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4640
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "∑" }),
3866
4641
  t.blockMath
3867
4642
  ] }) }),
3868
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().setHorizontalRule().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3869
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "—" }),
4643
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().setHorizontalRule().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4644
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "—" }),
3870
4645
  t.hr
3871
4646
  ] }) }),
3872
4647
  /* @__PURE__ */ jsx(
@@ -3882,8 +4657,8 @@ function EditorToolbar({
3882
4657
  {
3883
4658
  disabled: item2.disabled,
3884
4659
  onSelect: () => item2.onSelect(editor),
3885
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3886
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: item2.icon }),
4660
+ children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4661
+ /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: item2.icon }),
3887
4662
  item2.label
3888
4663
  ] })
3889
4664
  },
@@ -3920,88 +4695,7 @@ function EditorToolbar({
3920
4695
  onCancel: cancelMath
3921
4696
  }
3922
4697
  ) : null,
3923
- tableMenu && createPortal(
3924
- /* @__PURE__ */ jsxs(
3925
- "div",
3926
- {
3927
- className: styles$3.tableBubble,
3928
- style: { position: "fixed", left: tableMenu.x, top: tableMenu.y },
3929
- role: "menu",
3930
- onMouseDown: (e2) => e2.stopPropagation(),
3931
- onContextMenu: (e2) => e2.preventDefault(),
3932
- children: [
3933
- /* @__PURE__ */ jsx(
3934
- TableMenuItem,
3935
- {
3936
- label: tableMulti ? t.tableAddColumnBeforeN(tableColN) : t.tableAddColumnBefore,
3937
- onClick: () => runTable(() => addColumnsBefore(editor, tableColN)),
3938
- children: /* @__PURE__ */ jsx(ColumnBeforeIcon, {})
3939
- }
3940
- ),
3941
- /* @__PURE__ */ jsx(
3942
- TableMenuItem,
3943
- {
3944
- label: tableMulti ? t.tableAddColumnAfterN(tableColN) : t.tableAddColumnAfter,
3945
- onClick: () => runTable(() => addColumnsAfter(editor, tableColN)),
3946
- children: /* @__PURE__ */ jsx(ColumnAfterIcon, {})
3947
- }
3948
- ),
3949
- /* @__PURE__ */ jsx(
3950
- TableMenuItem,
3951
- {
3952
- label: tableMulti ? t.tableDeleteColumnN(tableColN) : t.tableDeleteColumn,
3953
- disabled: disableDeleteColumn,
3954
- onClick: () => runTable(() => {
3955
- deleteSelectedColumns(editor);
3956
- }),
3957
- children: /* @__PURE__ */ jsx(ColumnDeleteIcon, {})
3958
- }
3959
- ),
3960
- /* @__PURE__ */ jsx(TableMenuDivider, {}),
3961
- /* @__PURE__ */ jsx(
3962
- TableMenuItem,
3963
- {
3964
- label: tableMulti ? t.tableAddRowBeforeN(tableRowN) : t.tableAddRowBefore,
3965
- disabled: disableAddRowBefore,
3966
- onClick: () => runTable(() => addRowsBefore(editor, tableRowN)),
3967
- children: /* @__PURE__ */ jsx(RowBeforeIcon, {})
3968
- }
3969
- ),
3970
- /* @__PURE__ */ jsx(
3971
- TableMenuItem,
3972
- {
3973
- label: tableMulti ? t.tableAddRowAfterN(tableRowN) : t.tableAddRowAfter,
3974
- onClick: () => runTable(() => addRowsAfter(editor, tableRowN)),
3975
- children: /* @__PURE__ */ jsx(RowAfterIcon, {})
3976
- }
3977
- ),
3978
- /* @__PURE__ */ jsx(
3979
- TableMenuItem,
3980
- {
3981
- label: tableMulti ? t.tableDeleteRowN(tableRowN) : t.tableDeleteRow,
3982
- disabled: disableDeleteRow,
3983
- onClick: () => runTable(() => {
3984
- deleteSelectedRows(editor);
3985
- }),
3986
- children: /* @__PURE__ */ jsx(RowDeleteIcon, {})
3987
- }
3988
- ),
3989
- /* @__PURE__ */ jsx(TableMenuDivider, {}),
3990
- /* @__PURE__ */ jsx(
3991
- TableMenuItem,
3992
- {
3993
- label: t.tableDeleteTable,
3994
- onClick: () => runTable(() => {
3995
- editor.commands.deleteTable();
3996
- }),
3997
- children: /* @__PURE__ */ jsx(TableDeleteIcon, {})
3998
- }
3999
- )
4000
- ]
4001
- }
4002
- ),
4003
- document.body
4004
- )
4698
+ /* @__PURE__ */ jsx(TableHandles, { editor, labels: t })
4005
4699
  ] });
4006
4700
  }
4007
4701
  function useIsMobile(breakpoint = 768) {
@@ -4350,6 +5044,8 @@ export {
4350
5044
  CommentPopover,
4351
5045
  CopyIcon,
4352
5046
  EditorToolbar,
5047
+ EraserIcon,
5048
+ ExternalLinkIcon,
4353
5049
  FIND_DEBOUNCE_MS,
4354
5050
  default2 as FindAndReplace,
4355
5051
  FindReplaceBar,
@@ -4359,6 +5055,7 @@ export {
4359
5055
  ItalicIcon,
4360
5056
  KeyboardIcon,
4361
5057
  LinkIcon,
5058
+ LinkPopover,
4362
5059
  ListChecksIcon,
4363
5060
  ListOrderedIcon,
4364
5061
  ListUnorderedIcon,
@@ -4375,6 +5072,7 @@ export {
4375
5072
  R2 as ReportContent,
4376
5073
  R as ReportContentInteractive,
4377
5074
  b as ReportContentWithCharts,
5075
+ RotateCcwIcon,
4378
5076
  RowAfterIcon,
4379
5077
  RowBeforeIcon,
4380
5078
  RowDeleteIcon,
@@ -4390,9 +5088,11 @@ export {
4390
5088
  XIcon,
4391
5089
  a2 as applyCitationSources,
4392
5090
  applyCommentAnchorsToEditor,
5091
+ applyLink,
4393
5092
  baseExtensions,
4394
5093
  g as blockTextHash,
4395
5094
  buildShortcutGroups,
5095
+ canSetLink,
4396
5096
  collectCommentIds,
4397
5097
  commentAnchorExtension,
4398
5098
  commentAnchorPlugin,
@@ -4406,6 +5106,7 @@ export {
4406
5106
  defaultColorPaletteLabels,
4407
5107
  defaultCommentLabels,
4408
5108
  defaultFindLabels,
5109
+ defaultLinkPopoverLabels,
4409
5110
  defaultShortcutLabels,
4410
5111
  defaultSlashMenuLabels,
4411
5112
  defaultTocLabels,
@@ -4420,6 +5121,7 @@ export {
4420
5121
  getMarkdownForRange,
4421
5122
  insertMarkdown,
4422
5123
  insertSlashMarkdown,
5124
+ isLinkActive,
4423
5125
  looksLikeMarkdown,
4424
5126
  lowlight,
4425
5127
  makeTocGetId,
@@ -4427,15 +5129,20 @@ export {
4427
5129
  mergeCommentIntervals,
4428
5130
  m as mountChartsInContainer,
4429
5131
  nextComment,
5132
+ normalizeLinkHref,
4430
5133
  normalizeMarkdown,
5134
+ openLinkUrl,
4431
5135
  prepareChartMarkdown,
4432
5136
  pureChart,
4433
5137
  pureCodeBlock,
4434
5138
  pureImage,
4435
5139
  r as readCitationAttrs,
5140
+ readLinkHref,
5141
+ removeLink,
4436
5142
  replaceRangeWithMarkdown,
4437
5143
  reportChart,
4438
5144
  runFindCommand,
5145
+ sanitizeLinkUrl,
4439
5146
  s as scrollToTocHeading,
4440
5147
  selectionKind,
4441
5148
  s2 as serializeChartPayload,