tiptap-markdown-react 0.14.5 → 0.16.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
@@ -1,24 +1,25 @@
1
1
  "use client";
2
2
  import { Markdown, MarkdownManager } from "@tiptap/markdown";
3
- import { c as renderOrUpdateChart, d as destroyChart } from "./scrollToTocHeading-DKL19FQG.js";
4
- import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-DKL19FQG.js";
5
- import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
3
+ import { c as renderOrUpdateChart, d as destroyChart } from "./scrollToTocHeading-CBvptTaQ.js";
4
+ import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-CBvptTaQ.js";
5
+ import { jsx, jsxs, Fragment as Fragment$2 } from "react/jsx-runtime";
6
6
  import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
7
7
  import FindAndReplace, { FindAndReplacePluginKey, createSearchRegex } from "@tiptap/extension-find-and-replace";
8
8
  import { default as default2 } from "@tiptap/extension-find-and-replace";
9
9
  import Image from "@tiptap/extension-image";
10
10
  import { TableOfContents } from "@tiptap/extension-table-of-contents";
11
- import { NodeViewWrapper, ReactNodeViewRenderer, useEditorState, NodeViewContent, useEditor, EditorContent } from "@tiptap/react";
11
+ import { NodeViewWrapper, ReactNodeViewRenderer, useEditorState, ReactRenderer, NodeViewContent, useEditor, EditorContent } from "@tiptap/react";
12
12
  import { createPortal } from "react-dom";
13
- import { useState, useEffect, useCallback, useRef, useMemo, forwardRef, useImperativeHandle, useId, useContext, createContext } from "react";
14
- import { e as enrichMarkdownCitations, c as styles$6 } from "./ReportContent-DxldXfpO.js";
15
- import { R as R2, a as a2, b as b2, s as s2 } from "./ReportContent-DxldXfpO.js";
16
- 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-C2zqDjSP.js";
17
- import { g, e, s as s3 } from "./extractToc-C2zqDjSP.js";
13
+ import { useState, useEffect, useCallback, useRef, useMemo, forwardRef, useImperativeHandle, Fragment as Fragment$1, useId, useContext, createContext } from "react";
14
+ import { e as enrichMarkdownCitations, c as styles$8 } from "./ReportContent-CwcppHl8.js";
15
+ import { R as R2, a as a2, b as b2, s as s2 } from "./ReportContent-CwcppHl8.js";
16
+ 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-CheLC9kh.js";
17
+ import { g, e, s as s3 } from "./extractToc-CheLC9kh.js";
18
18
  import { Slice, Fragment } from "@tiptap/pm/model";
19
19
  import { Extension, Node as Node$1 } from "@tiptap/core";
20
20
  import { PluginKey, Plugin, NodeSelection, TextSelection } from "@tiptap/pm/state";
21
21
  import { DecorationSet, Decoration } from "@tiptap/pm/view";
22
+ import Suggestion from "@tiptap/suggestion";
22
23
  import { FileHandlePlugin } from "@tiptap/extension-file-handler";
23
24
  import { skipTrailingNodeMeta } from "@tiptap/extensions";
24
25
  import { CellSelection, isInTable, selectedRect, rowIsHeader } from "@tiptap/pm/tables";
@@ -533,6 +534,18 @@ const ChevronsUpDownIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
533
534
  /* @__PURE__ */ jsx("path", { d: "m7 15 5 5 5-5" }),
534
535
  /* @__PURE__ */ jsx("path", { d: "m7 9 5-5 5 5" })
535
536
  ] });
537
+ const KeyboardIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
538
+ /* @__PURE__ */ jsx("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" }),
539
+ /* @__PURE__ */ jsx("path", { d: "M6 8h.01" }),
540
+ /* @__PURE__ */ jsx("path", { d: "M10 8h.01" }),
541
+ /* @__PURE__ */ jsx("path", { d: "M14 8h.01" }),
542
+ /* @__PURE__ */ jsx("path", { d: "M18 8h.01" }),
543
+ /* @__PURE__ */ jsx("path", { d: "M6 12h.01" }),
544
+ /* @__PURE__ */ jsx("path", { d: "M10 12h.01" }),
545
+ /* @__PURE__ */ jsx("path", { d: "M14 12h.01" }),
546
+ /* @__PURE__ */ jsx("path", { d: "M18 12h.01" }),
547
+ /* @__PURE__ */ jsx("path", { d: "M7 16h10" })
548
+ ] });
536
549
  const defaultChartLabels = {
537
550
  tabLabel: (chartType, index) => `${chartType} ${index + 1}`,
538
551
  done: "Done",
@@ -605,6 +618,51 @@ const defaultToolbarLabels = {
605
618
  mathNewInline: "New equation",
606
619
  mathNewBlock: "Add a TeX equation"
607
620
  };
621
+ const defaultSlashMenuLabels = {
622
+ menuLabel: "Insert block",
623
+ groupText: "Text",
624
+ groupList: "Lists",
625
+ groupAdvanced: "Advanced",
626
+ normalText: "Normal text",
627
+ headingLabel: (level) => `Heading ${level}`,
628
+ bulletList: "Bullet list",
629
+ orderedList: "Ordered list",
630
+ taskList: "Task list",
631
+ blockquote: "Blockquote",
632
+ codeBlock: "Code block",
633
+ divider: "Divider",
634
+ table: "Table",
635
+ inlineMath: "Inline equation",
636
+ blockMath: "Block equation"
637
+ };
638
+ const defaultShortcutLabels = {
639
+ panelTitle: "Shortcuts",
640
+ close: "Close",
641
+ colFormat: "Format",
642
+ colShortcut: "Shortcut",
643
+ colMarkdown: "Markdown",
644
+ formatGroup: "Formatting",
645
+ insertGroup: "Insert",
646
+ editGroup: "Editing",
647
+ bold: "Bold",
648
+ italic: "Italic",
649
+ strike: "Strikethrough",
650
+ underline: "Underline",
651
+ inlineCode: "Inline code",
652
+ highlight: "Highlight",
653
+ headingLabel: (level) => `Heading ${level}`,
654
+ paragraph: "Normal text",
655
+ blockquote: "Blockquote",
656
+ bulletList: "Bullet list",
657
+ orderedList: "Ordered list",
658
+ taskList: "Task list",
659
+ codeBlock: "Code block",
660
+ divider: "Divider",
661
+ undo: "Undo",
662
+ redo: "Redo",
663
+ hardBreak: "Hard break",
664
+ findReplace: "Find & replace"
665
+ };
608
666
  const defaultColorPaletteLabels = {
609
667
  none: "None",
610
668
  theme: "THEME"
@@ -646,7 +704,7 @@ const defaultFindLabels = {
646
704
  readOnly: "Read-only"
647
705
  };
648
706
  const bar = "_bar_1h61e_3";
649
- const row = "_row_1h61e_25";
707
+ const row$1 = "_row_1h61e_25";
650
708
  const field = "_field_1h61e_43";
651
709
  const fieldIcon = "_fieldIcon_1h61e_62";
652
710
  const input = "_input_1h61e_67";
@@ -658,9 +716,9 @@ const toggleOn = "_toggleOn_1h61e_135";
658
716
  const iconGroup = "_iconGroup_1h61e_29";
659
717
  const spacer = "_spacer_1h61e_150";
660
718
  const readOnly = "_readOnly_1h61e_155";
661
- const styles$5 = {
719
+ const styles$7 = {
662
720
  bar,
663
- row,
721
+ row: row$1,
664
722
  field,
665
723
  fieldIcon,
666
724
  input,
@@ -778,11 +836,11 @@ function FindReplaceBar({
778
836
  });
779
837
  };
780
838
  if (!hasExtension) return null;
781
- const toggleClass = (on) => `${styles$5.btn} ${styles$5.toggle}${on ? ` ${styles$5.toggleOn}` : ""}`;
839
+ const toggleClass = (on) => `${styles$7.btn} ${styles$7.toggle}${on ? ` ${styles$7.toggleOn}` : ""}`;
782
840
  return /* @__PURE__ */ jsxs(
783
841
  "div",
784
842
  {
785
- className: className ? `${styles$5.bar} ${className}` : styles$5.bar,
843
+ className: className ? `${styles$7.bar} ${className}` : styles$7.bar,
786
844
  style,
787
845
  role: "dialog",
788
846
  "aria-label": t.find,
@@ -793,14 +851,14 @@ function FindReplaceBar({
793
851
  }
794
852
  },
795
853
  children: [
796
- /* @__PURE__ */ jsxs("div", { className: styles$5.row, children: [
797
- /* @__PURE__ */ jsxs("span", { className: styles$5.field, children: [
798
- /* @__PURE__ */ jsx(SearchIcon, { size: 14, className: styles$5.fieldIcon }),
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 }),
799
857
  /* @__PURE__ */ jsx(
800
858
  "input",
801
859
  {
802
860
  ref: inputRef,
803
- className: styles$5.input,
861
+ className: styles$7.input,
804
862
  value: term,
805
863
  onChange: (e2) => setTerm(e2.target.value),
806
864
  onKeyDown: onFindKeyDown,
@@ -813,7 +871,7 @@ function FindReplaceBar({
813
871
  /* @__PURE__ */ jsx(
814
872
  "span",
815
873
  {
816
- className: `${styles$5.counter}${invalidPattern ? ` ${styles$5.counterInvalid}` : ""}`,
874
+ className: `${styles$7.counter}${invalidPattern ? ` ${styles$7.counterInvalid}` : ""}`,
817
875
  "aria-live": "polite",
818
876
  title: invalidPattern ? t.invalidRegex : void 0,
819
877
  children: invalidPattern ? t.invalidRegex : counter2
@@ -846,13 +904,13 @@ function FindReplaceBar({
846
904
  children: "ab"
847
905
  }
848
906
  ),
849
- /* @__PURE__ */ jsx("span", { className: styles$5.spacer }),
850
- /* @__PURE__ */ jsxs("span", { className: styles$5.iconGroup, children: [
907
+ /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
908
+ /* @__PURE__ */ jsxs("span", { className: styles$7.iconGroup, children: [
851
909
  /* @__PURE__ */ jsx(
852
910
  "button",
853
911
  {
854
912
  type: "button",
855
- className: styles$5.btn,
913
+ className: styles$7.btn,
856
914
  title: t.previous,
857
915
  "aria-label": t.previous,
858
916
  disabled: state.total === 0,
@@ -865,7 +923,7 @@ function FindReplaceBar({
865
923
  "button",
866
924
  {
867
925
  type: "button",
868
- className: styles$5.btn,
926
+ className: styles$7.btn,
869
927
  title: t.next,
870
928
  "aria-label": t.next,
871
929
  disabled: state.total === 0,
@@ -878,7 +936,7 @@ function FindReplaceBar({
878
936
  "button",
879
937
  {
880
938
  type: "button",
881
- className: styles$5.btn,
939
+ className: styles$7.btn,
882
940
  title: t.close,
883
941
  "aria-label": t.close,
884
942
  onClick: onClose,
@@ -887,11 +945,11 @@ function FindReplaceBar({
887
945
  )
888
946
  ] })
889
947
  ] }),
890
- editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$5.row, children: [
891
- /* @__PURE__ */ jsx("span", { className: styles$5.field, children: /* @__PURE__ */ jsx(
948
+ editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
949
+ /* @__PURE__ */ jsx("span", { className: styles$7.field, children: /* @__PURE__ */ jsx(
892
950
  "input",
893
951
  {
894
- className: styles$5.input,
952
+ className: styles$7.input,
895
953
  value: replaceTerm,
896
954
  onChange: (e2) => setReplaceTerm(e2.target.value),
897
955
  onKeyDown: onReplaceKeyDown,
@@ -900,12 +958,12 @@ function FindReplaceBar({
900
958
  spellCheck: false
901
959
  }
902
960
  ) }),
903
- /* @__PURE__ */ jsx("span", { className: styles$5.spacer }),
961
+ /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
904
962
  /* @__PURE__ */ jsx(
905
963
  "button",
906
964
  {
907
965
  type: "button",
908
- className: styles$5.btn,
966
+ className: styles$7.btn,
909
967
  title: t.replaceOne,
910
968
  "aria-label": t.replaceOne,
911
969
  disabled: state.total === 0,
@@ -918,7 +976,7 @@ function FindReplaceBar({
918
976
  "button",
919
977
  {
920
978
  type: "button",
921
- className: styles$5.btn,
979
+ className: styles$7.btn,
922
980
  title: t.replaceAll,
923
981
  "aria-label": t.replaceAll,
924
982
  disabled: state.total === 0,
@@ -927,7 +985,7 @@ function FindReplaceBar({
927
985
  children: /* @__PURE__ */ jsx(ReplaceAllIcon, { size: 16 })
928
986
  }
929
987
  )
930
- ] }) : /* @__PURE__ */ jsx("div", { className: styles$5.row, children: /* @__PURE__ */ jsx("span", { className: styles$5.readOnly, children: t.readOnly }) })
988
+ ] }) : /* @__PURE__ */ jsx("div", { className: styles$7.row, children: /* @__PURE__ */ jsx("span", { className: styles$7.readOnly, children: t.readOnly }) })
931
989
  ]
932
990
  }
933
991
  );
@@ -1014,6 +1072,455 @@ const ImportPlaceholder = Node$1.create({
1014
1072
  };
1015
1073
  }
1016
1074
  });
1075
+ const popupHost = "_popupHost_1noza_11";
1076
+ const menu$1 = "_menu_1noza_1";
1077
+ const groupLabel = "_groupLabel_1noza_43";
1078
+ const item$1 = "_item_1noza_53";
1079
+ const itemActive = "_itemActive_1noza_54";
1080
+ const itemIcon = "_itemIcon_1noza_79";
1081
+ const itemTitle = "_itemTitle_1noza_102";
1082
+ const styles$6 = {
1083
+ popupHost,
1084
+ menu: menu$1,
1085
+ groupLabel,
1086
+ item: item$1,
1087
+ itemActive,
1088
+ itemIcon,
1089
+ itemTitle
1090
+ };
1091
+ function createDefaultSlashMenuItems(labels = defaultSlashMenuLabels) {
1092
+ return [
1093
+ {
1094
+ id: "normal-text",
1095
+ title: labels.normalText,
1096
+ group: labels.groupText,
1097
+ icon: "¶",
1098
+ aliases: ["zhengwen", "正文", "paragraph", "text"],
1099
+ order: 0,
1100
+ apply: (editor, range) => {
1101
+ editor.chain().focus().deleteRange(range).setParagraph().run();
1102
+ }
1103
+ },
1104
+ ...[1, 2, 3].map((level) => ({
1105
+ id: `heading-${level}`,
1106
+ title: labels.headingLabel(level),
1107
+ group: labels.groupText,
1108
+ icon: `H${level}`,
1109
+ aliases: [`h${level}`, "biaoti", "标题", "heading"],
1110
+ order: level,
1111
+ apply: (editor, range) => {
1112
+ editor.chain().focus().deleteRange(range).setHeading({ level }).run();
1113
+ }
1114
+ })),
1115
+ {
1116
+ id: "bullet-list",
1117
+ title: labels.bulletList,
1118
+ group: labels.groupList,
1119
+ icon: "•",
1120
+ aliases: ["wuxu", "无序", "列表", "bullet", "ul"],
1121
+ order: 4,
1122
+ apply: (editor, range) => {
1123
+ editor.chain().focus().deleteRange(range).toggleBulletList().run();
1124
+ }
1125
+ },
1126
+ {
1127
+ id: "ordered-list",
1128
+ title: labels.orderedList,
1129
+ group: labels.groupList,
1130
+ icon: "1.",
1131
+ aliases: ["youxu", "有序", "列表", "ordered", "ol"],
1132
+ order: 5,
1133
+ apply: (editor, range) => {
1134
+ editor.chain().focus().deleteRange(range).toggleOrderedList().run();
1135
+ }
1136
+ },
1137
+ {
1138
+ id: "task-list",
1139
+ title: labels.taskList,
1140
+ group: labels.groupList,
1141
+ icon: "✓",
1142
+ aliases: ["renwu", "任务", "待办", "task", "todo", "checklist"],
1143
+ order: 6,
1144
+ apply: (editor, range) => {
1145
+ editor.chain().focus().deleteRange(range).toggleTaskList().run();
1146
+ }
1147
+ },
1148
+ {
1149
+ id: "blockquote",
1150
+ title: labels.blockquote,
1151
+ group: labels.groupAdvanced,
1152
+ icon: "❝",
1153
+ aliases: ["yinyong", "引用", "quote", "blockquote"],
1154
+ order: 7,
1155
+ apply: (editor, range) => {
1156
+ editor.chain().focus().deleteRange(range).toggleBlockquote().run();
1157
+ }
1158
+ },
1159
+ {
1160
+ id: "code-block",
1161
+ title: labels.codeBlock,
1162
+ group: labels.groupAdvanced,
1163
+ icon: "{ }",
1164
+ aliases: ["daima", "代码", "code", "fence"],
1165
+ order: 8,
1166
+ apply: (editor, range) => {
1167
+ editor.chain().focus().deleteRange(range).toggleCodeBlock().run();
1168
+ }
1169
+ },
1170
+ {
1171
+ id: "divider",
1172
+ title: labels.divider,
1173
+ group: labels.groupAdvanced,
1174
+ icon: "—",
1175
+ aliases: ["fenge", "分割线", "分隔线", "hr", "divider"],
1176
+ order: 9,
1177
+ apply: (editor, range) => {
1178
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
1179
+ }
1180
+ },
1181
+ {
1182
+ id: "table",
1183
+ title: labels.table,
1184
+ group: labels.groupAdvanced,
1185
+ icon: "▦",
1186
+ aliases: ["biaoge", "表格", "table"],
1187
+ order: 10,
1188
+ apply: (editor, range) => {
1189
+ editor.chain().focus().deleteRange(range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
1190
+ }
1191
+ },
1192
+ {
1193
+ id: "inline-math",
1194
+ title: labels.inlineMath,
1195
+ group: labels.groupAdvanced,
1196
+ icon: "√x",
1197
+ aliases: ["gongshi", "公式", "行内公式", "math", "latex"],
1198
+ order: 11,
1199
+ apply: (editor, range) => {
1200
+ editor.chain().focus().deleteRange(range).insertContent({ type: "inlineMath", attrs: { latex: "E=mc^2" } }).run();
1201
+ }
1202
+ },
1203
+ {
1204
+ id: "block-math",
1205
+ title: labels.blockMath,
1206
+ group: labels.groupAdvanced,
1207
+ icon: "∑",
1208
+ aliases: ["gongshi", "公式", "块级公式", "mathblock", "latex"],
1209
+ order: 12,
1210
+ apply: (editor, range) => {
1211
+ editor.chain().focus().deleteRange(range).insertContent({ type: "blockMath", attrs: { latex: "E=mc^2" } }).run();
1212
+ }
1213
+ }
1214
+ ];
1215
+ }
1216
+ function filterSlashItems(items, query) {
1217
+ const q = query.trim().toLowerCase();
1218
+ if (!q) return items;
1219
+ return items.filter(
1220
+ (item2) => {
1221
+ var _a;
1222
+ return item2.title.toLowerCase().includes(q) || ((_a = item2.aliases) == null ? void 0 : _a.some((alias) => alias.toLowerCase().includes(q)));
1223
+ }
1224
+ );
1225
+ }
1226
+ function withGroupHeaders(items) {
1227
+ const rows = [];
1228
+ let lastGroup;
1229
+ for (const item2 of items) {
1230
+ if (item2.group && item2.group !== lastGroup) {
1231
+ rows.push([item2.group, item2]);
1232
+ lastGroup = item2.group;
1233
+ } else {
1234
+ if (!item2.group) lastGroup = void 0;
1235
+ rows.push([null, item2]);
1236
+ }
1237
+ }
1238
+ return rows;
1239
+ }
1240
+ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuLabel, command }, ref) {
1241
+ const [index, setIndex] = useState(0);
1242
+ useEffect(() => {
1243
+ setIndex(0);
1244
+ }, [query]);
1245
+ useImperativeHandle(
1246
+ ref,
1247
+ () => ({
1248
+ onKeyDown(event) {
1249
+ if (!items.length) return false;
1250
+ if (event.key === "ArrowDown" || event.key === "Tab" && !event.shiftKey) {
1251
+ setIndex((i) => (i + 1) % items.length);
1252
+ return true;
1253
+ }
1254
+ if (event.key === "ArrowUp" || event.key === "Tab" && event.shiftKey) {
1255
+ setIndex((i) => (i - 1 + items.length) % items.length);
1256
+ return true;
1257
+ }
1258
+ if (event.key === "Enter") {
1259
+ const item2 = items[index];
1260
+ if (!item2) return false;
1261
+ command(item2);
1262
+ return true;
1263
+ }
1264
+ return false;
1265
+ }
1266
+ }),
1267
+ [items, index, command]
1268
+ );
1269
+ if (!items.length) return null;
1270
+ let optionIndex = -1;
1271
+ return /* @__PURE__ */ jsx("div", { className: styles$6.menu, role: "listbox", "aria-label": menuLabel, children: withGroupHeaders(items).map(([header2, item2]) => {
1272
+ optionIndex += 1;
1273
+ const i = optionIndex;
1274
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1275
+ header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$6.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1276
+ /* @__PURE__ */ jsxs(
1277
+ "button",
1278
+ {
1279
+ type: "button",
1280
+ role: "option",
1281
+ "aria-selected": i === index,
1282
+ title: item2.title,
1283
+ className: i === index ? styles$6.itemActive : styles$6.item,
1284
+ tabIndex: -1,
1285
+ onMouseEnter: () => setIndex(i),
1286
+ onMouseDown: (e2) => {
1287
+ e2.preventDefault();
1288
+ command(item2);
1289
+ },
1290
+ 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 })
1293
+ ]
1294
+ }
1295
+ )
1296
+ ] }, item2.id);
1297
+ }) });
1298
+ });
1299
+ function isComposing(event, view) {
1300
+ return view.composing || event.isComposing || event.keyCode === 229;
1301
+ }
1302
+ const SlashMenu = Extension.create({
1303
+ name: "slashMenu",
1304
+ addOptions() {
1305
+ return { items: void 0, labels: void 0 };
1306
+ },
1307
+ addProseMirrorPlugins() {
1308
+ const { items: extraItems, labels } = this.options;
1309
+ const allItems = [
1310
+ ...createDefaultSlashMenuItems({ ...defaultSlashMenuLabels, ...labels }),
1311
+ ...extraItems ?? []
1312
+ ];
1313
+ let renderer = null;
1314
+ let unmountPopup = null;
1315
+ return [
1316
+ Suggestion({
1317
+ editor: this.editor,
1318
+ pluginKey: new PluginKey("tmrSlashMenu"),
1319
+ char: "/",
1320
+ // 行首(节点内起始,空 prefix 天然放行)或空白后触发
1321
+ allowedPrefixes: [" ", " ", " "],
1322
+ allowSpaces: false,
1323
+ decorationClass: "tmr-slash-suggestion",
1324
+ decorationEmptyClass: "tmr-slash-suggestion-empty",
1325
+ items: ({ query }) => filterSlashItems(allItems, query),
1326
+ command: ({ editor, range, props: item2 }) => {
1327
+ item2.apply(editor, range);
1328
+ },
1329
+ allow: ({ editor }) => editor.isEditable && !editor.isActive("codeBlock"),
1330
+ render: () => ({
1331
+ onStart: (props) => {
1332
+ var _a;
1333
+ renderer = new ReactRenderer(
1334
+ SlashMenuPopup,
1335
+ {
1336
+ editor: props.editor,
1337
+ props: {
1338
+ items: props.items,
1339
+ query: props.query,
1340
+ menuLabel: ((_a = this.options.labels) == null ? void 0 : _a.menuLabel) ?? defaultSlashMenuLabels.menuLabel,
1341
+ command: props.command
1342
+ },
1343
+ className: styles$6.popupHost
1344
+ }
1345
+ );
1346
+ const pmStyle = getComputedStyle(props.editor.view.dom);
1347
+ for (const name of [
1348
+ "--tmr-text",
1349
+ "--tmr-accent",
1350
+ "--tmr-toolbar-border",
1351
+ "--tmr-toolbar-muted"
1352
+ ]) {
1353
+ const value = pmStyle.getPropertyValue(name);
1354
+ if (value) renderer.element.style.setProperty(name, value);
1355
+ }
1356
+ unmountPopup = props.mount(renderer.element);
1357
+ },
1358
+ onUpdate: (props) => {
1359
+ renderer == null ? void 0 : renderer.updateProps({
1360
+ items: props.items,
1361
+ query: props.query,
1362
+ command: props.command
1363
+ });
1364
+ },
1365
+ onKeyDown: (props) => {
1366
+ var _a;
1367
+ if (!renderer || isComposing(props.event, props.view)) return false;
1368
+ return ((_a = renderer.ref) == null ? void 0 : _a.onKeyDown(props.event)) ?? false;
1369
+ },
1370
+ onExit: () => {
1371
+ unmountPopup == null ? void 0 : unmountPopup();
1372
+ unmountPopup = null;
1373
+ renderer == null ? void 0 : renderer.destroy();
1374
+ renderer = null;
1375
+ }
1376
+ })
1377
+ })
1378
+ ];
1379
+ }
1380
+ });
1381
+ const drawer = "_drawer_ljnq6_5";
1382
+ const closeBtn = "_closeBtn_ljnq6_44";
1383
+ const head = "_head_ljnq6_68";
1384
+ const colShortcut = "_colShortcut_ljnq6_79";
1385
+ const colMarkdown = "_colMarkdown_ljnq6_83";
1386
+ const body = "_body_ljnq6_88";
1387
+ const group = "_group_ljnq6_95";
1388
+ const groupTitle = "_groupTitle_ljnq6_99";
1389
+ const row = "_row_ljnq6_107";
1390
+ const rowLabel = "_rowLabel_ljnq6_120";
1391
+ const rowKeys = "_rowKeys_ljnq6_127";
1392
+ const rowMd = "_rowMd_ljnq6_128";
1393
+ const keycap = "_keycap_ljnq6_138";
1394
+ const none = "_none_ljnq6_163";
1395
+ const styles$5 = {
1396
+ drawer,
1397
+ closeBtn,
1398
+ head,
1399
+ colShortcut,
1400
+ colMarkdown,
1401
+ body,
1402
+ group,
1403
+ groupTitle,
1404
+ row,
1405
+ rowLabel,
1406
+ rowKeys,
1407
+ rowMd,
1408
+ keycap,
1409
+ none
1410
+ };
1411
+ function buildShortcutGroups(labels) {
1412
+ return [
1413
+ {
1414
+ id: "format",
1415
+ title: labels.formatGroup,
1416
+ entries: [
1417
+ { id: "bold", label: labels.bold, keys: ["Mod", "b"], markdown: { marker: "**x**" } },
1418
+ { id: "italic", label: labels.italic, keys: ["Mod", "i"], markdown: { marker: "*x*" } },
1419
+ { id: "strike", label: labels.strike, keys: ["Mod", "Shift", "s"], markdown: { marker: "~~x~~" } },
1420
+ { id: "underline", label: labels.underline, keys: ["Mod", "u"] },
1421
+ { id: "inline-code", label: labels.inlineCode, keys: ["Mod", "e"], markdown: { marker: "`x`" } },
1422
+ { id: "highlight", label: labels.highlight, keys: ["Mod", "Shift", "h"], markdown: { marker: "==x==" } },
1423
+ ...[1, 2, 3, 4, 5, 6].map((level) => ({
1424
+ id: `heading-${level}`,
1425
+ label: labels.headingLabel(level),
1426
+ keys: ["Mod", "Alt", String(level)],
1427
+ markdown: { marker: "#".repeat(level), terminator: "Space" }
1428
+ })),
1429
+ { id: "paragraph", label: labels.paragraph, keys: ["Mod", "Alt", "0"] }
1430
+ ]
1431
+ },
1432
+ {
1433
+ id: "insert",
1434
+ title: labels.insertGroup,
1435
+ entries: [
1436
+ { id: "blockquote", label: labels.blockquote, keys: ["Mod", "Shift", "b"], markdown: { marker: ">", terminator: "Space" } },
1437
+ { id: "bullet-list", label: labels.bulletList, keys: ["Mod", "Shift", "8"], markdown: { marker: "-", terminator: "Space" } },
1438
+ { id: "ordered-list", label: labels.orderedList, keys: ["Mod", "Shift", "7"], markdown: { marker: "1.", terminator: "Space" } },
1439
+ { id: "task-list", label: labels.taskList, markdown: { marker: "[]", terminator: "Space" } },
1440
+ { id: "code-block", label: labels.codeBlock, markdown: { marker: "```", terminator: "Space" } },
1441
+ { id: "divider", label: labels.divider, markdown: { marker: "---", terminator: "Space" } }
1442
+ ]
1443
+ },
1444
+ {
1445
+ id: "edit",
1446
+ title: labels.editGroup,
1447
+ entries: [
1448
+ { id: "undo", label: labels.undo, keys: ["Mod", "z"] },
1449
+ { id: "redo", label: labels.redo, keys: ["Mod", "Shift", "z"] },
1450
+ { id: "hard-break", label: labels.hardBreak, keys: ["Shift", "Enter"] },
1451
+ { id: "find-replace", label: labels.findReplace, keys: ["Mod", "f"] }
1452
+ ]
1453
+ }
1454
+ ];
1455
+ }
1456
+ function isMacPlatform() {
1457
+ if (typeof navigator === "undefined") return false;
1458
+ return /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
1459
+ }
1460
+ function keycapText(key, mac) {
1461
+ if (key === "Mod") return mac ? "Cmd" : "Ctrl";
1462
+ if (key === "Alt") return mac ? "Opt" : "Alt";
1463
+ if (/^[a-z]$/.test(key)) return key.toUpperCase();
1464
+ return key;
1465
+ }
1466
+ function ShortcutPanel({ open, onClose, labels }) {
1467
+ const t = useMemo(
1468
+ () => ({ ...defaultShortcutLabels, ...labels }),
1469
+ [labels]
1470
+ );
1471
+ useEffect(() => {
1472
+ if (!open) return;
1473
+ const onKey = (e2) => {
1474
+ if (e2.key === "Escape") onClose();
1475
+ };
1476
+ document.addEventListener("keydown", onKey);
1477
+ return () => document.removeEventListener("keydown", onKey);
1478
+ }, [open, onClose]);
1479
+ const groups = useMemo(
1480
+ () => open ? buildShortcutGroups(t) : [],
1481
+ [open, t]
1482
+ );
1483
+ const mac = useMemo(isMacPlatform, []);
1484
+ if (!open) return null;
1485
+ return /* @__PURE__ */ jsxs(
1486
+ "aside",
1487
+ {
1488
+ className: styles$5.drawer,
1489
+ role: "dialog",
1490
+ "aria-modal": "false",
1491
+ "aria-label": t.panelTitle,
1492
+ children: [
1493
+ /* @__PURE__ */ jsx(
1494
+ "button",
1495
+ {
1496
+ type: "button",
1497
+ className: styles$5.closeBtn,
1498
+ title: t.close,
1499
+ "aria-label": t.close,
1500
+ onClick: onClose,
1501
+ children: /* @__PURE__ */ jsx(XIcon, { size: 16 })
1502
+ }
1503
+ ),
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 })
1508
+ ] }),
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: "—" }) })
1518
+ ] }, entry.id))
1519
+ ] }, group2.id)) })
1520
+ ]
1521
+ }
1522
+ );
1523
+ }
1017
1524
  const MD_FILE_RE$1 = /\.(md|markdown)$/i;
1018
1525
  const MD_MIME_TYPES = ["text/markdown", "text/x-markdown", ""];
1019
1526
  async function insertMarkdownFiles(editor, files, pos) {
@@ -1609,12 +2116,18 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
1609
2116
  findBarContainer,
1610
2117
  findBarOffset = DEFAULT_FIND_BAR_OFFSET,
1611
2118
  findShortcut = true,
1612
- findLabels
2119
+ findLabels,
2120
+ slashMenu = true,
2121
+ slashMenuLabels,
2122
+ shortcutPanel = true,
2123
+ shortcutLabels,
2124
+ shortcutFabContainer
1613
2125
  }, ref) {
1614
2126
  const preparedInitial = prepareChartMarkdown(
1615
2127
  enrichMarkdownCitations(initialMarkdown, sources ?? [])
1616
2128
  );
1617
2129
  const [findOpen, setFindOpen] = useState(false);
2130
+ const [shortcutsOpen, setShortcutsOpen] = useState(false);
1618
2131
  const findInputRef = useRef(null);
1619
2132
  const editor = useEditor({
1620
2133
  extensions: [
@@ -1647,6 +2160,8 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
1647
2160
  }),
1648
2161
  ...markdownPaste ? [MarkdownPaste] : [],
1649
2162
  ...markdownFileDrop ? [MarkdownFileDrop] : [],
2163
+ // 斜杠菜单(键入 / 唤起):默认开,只读态由 suggestion 状态机自身短路
2164
+ ...slashMenu ? [SlashMenu.configure({ labels: slashMenuLabels })] : [],
1650
2165
  ...extraExtensions ?? []
1651
2166
  ],
1652
2167
  content: preparedInitial,
@@ -1656,7 +2171,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
1656
2171
  immediatelyRender: false,
1657
2172
  editorProps: {
1658
2173
  attributes: {
1659
- class: styles$6.editorContent,
2174
+ class: styles$8.editorContent,
1660
2175
  "data-placeholder": placeholder ?? ""
1661
2176
  }
1662
2177
  }
@@ -1822,20 +2337,46 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
1822
2337
  labels: findLabels,
1823
2338
  onClose: closeFind,
1824
2339
  inputRef: findInputRef,
1825
- className: styles$6.findBar,
2340
+ className: styles$8.findBar,
1826
2341
  style: findBarOffsetStyle(findBarOffset)
1827
2342
  }
1828
2343
  ) : null;
1829
- return /* @__PURE__ */ jsxs("div", { className: styles$6.editorHost, children: [
1830
- findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$6.findBarAnchor, children: findBarNode }) : null,
2344
+ const shortcutT = useMemo(
2345
+ () => ({ ...defaultShortcutLabels, ...shortcutLabels }),
2346
+ [shortcutLabels]
2347
+ );
2348
+ const shortcutFabTarget = typeof shortcutFabContainer === "function" ? shortcutFabContainer() : shortcutFabContainer ?? null;
2349
+ const shortcutFabNode = shortcutPanel && editable ? /* @__PURE__ */ jsx(
2350
+ "button",
2351
+ {
2352
+ type: "button",
2353
+ className: shortcutFabTarget ? `${styles$8.shortcutFab} ${styles$8.shortcutFabHosted}` : styles$8.shortcutFab,
2354
+ title: shortcutT.panelTitle,
2355
+ "aria-label": shortcutT.panelTitle,
2356
+ "aria-expanded": shortcutsOpen,
2357
+ onClick: () => setShortcutsOpen((v) => !v),
2358
+ children: /* @__PURE__ */ jsx(KeyboardIcon, { size: 18 })
2359
+ }
2360
+ ) : null;
2361
+ return /* @__PURE__ */ jsxs("div", { className: styles$8.editorHost, children: [
2362
+ findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$8.findBarAnchor, children: findBarNode }) : null,
1831
2363
  findBarNode && findBarTarget ? createPortal(findBarNode, findBarTarget) : null,
1832
2364
  /* @__PURE__ */ jsx(
1833
2365
  EditorContent,
1834
2366
  {
1835
2367
  editor,
1836
- className: className ? `${styles$6.editorScroll} ${className}` : styles$6.editorScroll
2368
+ className: className ? `${styles$8.editorScroll} ${className}` : styles$8.editorScroll
1837
2369
  }
1838
- )
2370
+ ),
2371
+ shortcutFabNode && shortcutFabTarget ? createPortal(shortcutFabNode, shortcutFabTarget) : shortcutFabNode,
2372
+ shortcutPanel && editable ? /* @__PURE__ */ jsx(
2373
+ ShortcutPanel,
2374
+ {
2375
+ open: shortcutsOpen,
2376
+ onClose: () => setShortcutsOpen(false),
2377
+ labels: shortcutLabels
2378
+ }
2379
+ ) : null
1839
2380
  ] });
1840
2381
  });
1841
2382
  function MarkdownPreview({
@@ -1877,7 +2418,7 @@ function MarkdownPreview({
1877
2418
  editable: false,
1878
2419
  immediatelyRender: false,
1879
2420
  editorProps: {
1880
- attributes: { class: styles$6.editorContent }
2421
+ attributes: { class: styles$8.editorContent }
1881
2422
  }
1882
2423
  },
1883
2424
  [extensions]
@@ -1890,7 +2431,7 @@ function MarkdownPreview({
1890
2431
  EditorContent,
1891
2432
  {
1892
2433
  editor,
1893
- className: className ?? styles$6.editorScroll
2434
+ className: className ?? styles$8.editorScroll
1894
2435
  }
1895
2436
  );
1896
2437
  }
@@ -2954,7 +3495,7 @@ function EditorToolbar({
2954
3495
  setMathEdit(null);
2955
3496
  };
2956
3497
  const scriptActive = state.superscript ? "superscript" : state.subscript ? "subscript" : "normal";
2957
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
3498
+ return /* @__PURE__ */ jsxs(Fragment$2, { children: [
2958
3499
  /* @__PURE__ */ jsx(
2959
3500
  "div",
2960
3501
  {
@@ -3197,7 +3738,7 @@ function EditorToolbar({
3197
3738
  ),
3198
3739
  /* @__PURE__ */ jsx(Divider, {}),
3199
3740
  /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, onClick: toggleLink, children: /* @__PURE__ */ jsx(LinkIcon, {}) }),
3200
- onImageUpload ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
3741
+ onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
3201
3742
  /* @__PURE__ */ jsx(ToolbarButton, { title: t.image, onClick: handlePickImage, children: /* @__PURE__ */ jsx(ImageIcon, {}) }),
3202
3743
  /* @__PURE__ */ jsx(
3203
3744
  "input",
@@ -3764,6 +4305,17 @@ function insertPlainParagraphAt(editor, from, to, text) {
3764
4305
  return false;
3765
4306
  }
3766
4307
  }
4308
+ function insertSlashMarkdown(editor, range, markdown) {
4309
+ const prepared = prepareChartMarkdown(markdown);
4310
+ if (!prepared) return;
4311
+ try {
4312
+ const ok = editor.chain().focus().deleteRange(range).insertContent(prepared, { contentType: "markdown" }).run();
4313
+ if (ok) return;
4314
+ } catch {
4315
+ }
4316
+ editor.chain().focus().deleteRange(range).run();
4317
+ insertMarkdown(editor, prepared);
4318
+ }
3767
4319
  export {
3768
4320
  BoldIcon,
3769
4321
  COMMENT_ACTIVE_META,
@@ -3793,6 +4345,7 @@ export {
3793
4345
  ImportIcon,
3794
4346
  ImportPlaceholder,
3795
4347
  ItalicIcon,
4348
+ KeyboardIcon,
3796
4349
  LinkIcon,
3797
4350
  ListChecksIcon,
3798
4351
  ListOrderedIcon,
@@ -3814,6 +4367,8 @@ export {
3814
4367
  RowBeforeIcon,
3815
4368
  RowDeleteIcon,
3816
4369
  SearchIcon,
4370
+ ShortcutPanel,
4371
+ SlashMenu,
3817
4372
  StrikethroughIcon,
3818
4373
  TableDeleteIcon,
3819
4374
  TocPanel,
@@ -3825,6 +4380,7 @@ export {
3825
4380
  applyCommentAnchorsToEditor,
3826
4381
  baseExtensions,
3827
4382
  g as blockTextHash,
4383
+ buildShortcutGroups,
3828
4384
  collectCommentIds,
3829
4385
  commentAnchorExtension,
3830
4386
  commentAnchorPlugin,
@@ -3832,21 +4388,26 @@ export {
3832
4388
  commentRangesById,
3833
4389
  createChart,
3834
4390
  createCitationRef,
4391
+ createDefaultSlashMenuItems,
3835
4392
  defaultChartLabels,
3836
4393
  defaultCodeBlockLabels,
3837
4394
  defaultColorPaletteLabels,
3838
4395
  defaultCommentLabels,
3839
4396
  defaultFindLabels,
4397
+ defaultShortcutLabels,
4398
+ defaultSlashMenuLabels,
3840
4399
  defaultTocLabels,
3841
4400
  defaultToolbarLabels,
3842
4401
  enrichMarkdownCitations,
3843
4402
  b2 as extractFootnoteSources,
3844
4403
  e as extractToc,
4404
+ filterSlashItems,
3845
4405
  f as findCitationRefElement,
3846
4406
  findRangeByAnchor,
3847
4407
  focusComment,
3848
4408
  getMarkdownForRange,
3849
4409
  insertMarkdown,
4410
+ insertSlashMarkdown,
3850
4411
  looksLikeMarkdown,
3851
4412
  lowlight,
3852
4413
  makeTocGetId,