tiptap-markdown-react 0.18.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +97 -15
  2. package/THIRD_PARTY_LICENSES.md +45 -1
  3. package/dist/{ReportContent-MgbebxPV.js → ReportContent-B8jIzhy3.js} +8 -8
  4. package/dist/ReportContent-B8jIzhy3.js.map +1 -0
  5. package/dist/chart/columnMatching.d.ts +1 -1
  6. package/dist/chart/types.d.ts +1 -1
  7. package/dist/commentAnchor/commentMapper.d.ts +1 -1
  8. package/dist/components/EditorToolbar.d.ts +1 -1
  9. package/dist/components/ImageAlignTools.d.ts +19 -0
  10. package/dist/components/ImageUploadView.d.ts +10 -0
  11. package/dist/components/MarkdownWysiwygEditor.d.ts +47 -1
  12. package/dist/components/imageUpload.dom.test.d.ts +1 -0
  13. package/dist/extensions.d.ts +12 -0
  14. package/dist/{extractToc-BaR6LP1f.js → extractToc-CGrBMGvM.js} +433 -9
  15. package/dist/extractToc-CGrBMGvM.js.map +1 -0
  16. package/dist/icons/index.d.ts +9 -0
  17. package/dist/imageAlign.d.ts +29 -0
  18. package/dist/imageAlign.dom.test.d.ts +1 -0
  19. package/dist/imageCaption.d.ts +12 -0
  20. package/dist/imageMarkdown.d.ts +86 -0
  21. package/dist/imageResize.dom.test.d.ts +1 -0
  22. package/dist/imageUpload.d.ts +63 -0
  23. package/dist/index.d.ts +9 -2
  24. package/dist/index.js +1355 -245
  25. package/dist/index.js.map +1 -1
  26. package/dist/labels.d.ts +52 -0
  27. package/dist/paragraphMarkdown.d.ts +19 -0
  28. package/dist/paragraphStyles.d.ts +38 -0
  29. package/dist/paragraphStyles.dom.test.d.ts +1 -0
  30. package/dist/reader.js +2 -2
  31. package/dist/resetImageSize.d.ts +12 -0
  32. package/dist/{scrollToTocHeading-BTQWajGD.js → scrollToTocHeading-B2QmL4wi.js} +2 -2
  33. package/dist/{scrollToTocHeading-BTQWajGD.js.map → scrollToTocHeading-B2QmL4wi.js.map} +1 -1
  34. package/dist/server.d.ts +1 -1
  35. package/dist/server.js +4 -4
  36. package/dist/style-inline.css +671 -140
  37. package/dist/style.css +671 -140
  38. package/package.json +5 -2
  39. package/dist/ReportContent-MgbebxPV.js.map +0 -1
  40. package/dist/extractToc-BaR6LP1f.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Markdown, MarkdownManager } from "@tiptap/markdown";
3
- import { c as renderOrUpdateChart, d as destroyChart } from "./scrollToTocHeading-BTQWajGD.js";
4
- import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-BTQWajGD.js";
3
+ import { c as renderOrUpdateChart, d as destroyChart } from "./scrollToTocHeading-B2QmL4wi.js";
4
+ import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-B2QmL4wi.js";
5
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";
@@ -10,15 +10,15 @@ import Image from "@tiptap/extension-image";
10
10
  import { TableOfContents } from "@tiptap/extension-table-of-contents";
11
11
  import { skipTrailingNodeMeta, Placeholder } from "@tiptap/extensions";
12
12
  import { NodeViewWrapper, ReactNodeViewRenderer, useEditorState, ReactRenderer, NodeViewContent, useEditor, EditorContent } from "@tiptap/react";
13
+ import { Extension, Node as Node$1, mergeAttributes } from "@tiptap/core";
13
14
  import { createPortal } from "react-dom";
14
15
  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$a } from "./ReportContent-MgbebxPV.js";
16
- import { R as R2, a as a2, b as b2, s as s2 } from "./ReportContent-MgbebxPV.js";
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
- import { g, e, s as s3 } from "./extractToc-BaR6LP1f.js";
16
+ import { e as enrichMarkdownCitations, c as styles$c } from "./ReportContent-B8jIzhy3.js";
17
+ import { R as R2, a as a2, b as b2, s as s2 } from "./ReportContent-B8jIzhy3.js";
18
+ import { C as CitationRef, i as mergeCommentIntervals, h as mapCommentAnchors, n as normalizeImageAlign, p as prepareChartMarkdown, j as reportChart, b as baseExtensions, f as CommentMark, l as lowlight, m as makeTocGetId, k as parseCodeTokenAsChartOrCodeBlock, o as imageMarkdownTokenizer, q as imageParseMarkdown, t as imageRenderMarkdown, u as imageNodeHtml, v as imageFigureParseRule, w as imageCaptionAttribute, x as imageAlignAttribute, y as normalizeImageCaption, a as pureCodeBlock, c as pureImage, z as renderMathInto, A as subscribeMathClick, d as pureChart } from "./extractToc-CGrBMGvM.js";
19
+ import { P, g, e, s as s3 } from "./extractToc-CGrBMGvM.js";
19
20
  import { Slice, Fragment } from "@tiptap/pm/model";
20
- import { Extension, Node as Node$1 } from "@tiptap/core";
21
- import { PluginKey, Plugin, NodeSelection, TextSelection } from "@tiptap/pm/state";
21
+ import { PluginKey, Plugin, Selection, TextSelection, NodeSelection } from "@tiptap/pm/state";
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";
@@ -425,6 +425,71 @@ const ImageIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
425
425
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
426
426
  /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
427
427
  ] });
428
+ const BlockSvg = ({ size = "1em", children, ...rest }) => /* @__PURE__ */ jsx(
429
+ "svg",
430
+ {
431
+ xmlns: "http://www.w3.org/2000/svg",
432
+ width: size,
433
+ height: size,
434
+ viewBox: "0 0 24 24",
435
+ fill: "currentColor",
436
+ stroke: "none",
437
+ "aria-hidden": "true",
438
+ focusable: "false",
439
+ ...rest,
440
+ children
441
+ }
442
+ );
443
+ const AlignLeftIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
444
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.4", width: "18", height: "2.4", rx: "1.2" }),
445
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "8.6", width: "12", height: "2.4", rx: "1.2" }),
446
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "13.8", width: "18", height: "2.4", rx: "1.2" }),
447
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "19", width: "12", height: "2.4", rx: "1.2" })
448
+ ] });
449
+ const AlignCenterIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
450
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.4", width: "18", height: "2.4", rx: "1.2" }),
451
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "8.6", width: "12", height: "2.4", rx: "1.2" }),
452
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "13.8", width: "18", height: "2.4", rx: "1.2" }),
453
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "19", width: "12", height: "2.4", rx: "1.2" })
454
+ ] });
455
+ const AlignRightIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
456
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.4", width: "18", height: "2.4", rx: "1.2" }),
457
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "8.6", width: "12", height: "2.4", rx: "1.2" }),
458
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "13.8", width: "18", height: "2.4", rx: "1.2" }),
459
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "19", width: "12", height: "2.4", rx: "1.2" })
460
+ ] });
461
+ const AlignJustifyIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
462
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.4", width: "18", height: "2.4", rx: "1.2" }),
463
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "8.6", width: "18", height: "2.4", rx: "1.2" }),
464
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "13.8", width: "18", height: "2.4", rx: "1.2" }),
465
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "19", width: "18", height: "2.4", rx: "1.2" })
466
+ ] });
467
+ const IndentIncreaseIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
468
+ /* @__PURE__ */ jsx("path", { d: "M3 6.6 8.5 10.8 3 15 Z" }),
469
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "3.6", width: "10.5", height: "2.4", rx: "1.2" }),
470
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "10.8", width: "10.5", height: "2.4", rx: "1.2" }),
471
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "18", width: "10.5", height: "2.4", rx: "1.2" })
472
+ ] });
473
+ const IndentDecreaseIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
474
+ /* @__PURE__ */ jsx("path", { d: "M8.5 6.6 3 10.8 8.5 15 Z" }),
475
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "3.6", width: "10.5", height: "2.4", rx: "1.2" }),
476
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "10.8", width: "10.5", height: "2.4", rx: "1.2" }),
477
+ /* @__PURE__ */ jsx("rect", { x: "10.5", y: "18", width: "10.5", height: "2.4", rx: "1.2" })
478
+ ] });
479
+ const LineHeightIcon = (p) => /* @__PURE__ */ jsxs(BlockSvg, { ...p, children: [
480
+ /* @__PURE__ */ jsx("rect", { x: "1.8", y: "4.4", width: "2.4", height: "15.2", rx: "1.2" }),
481
+ /* @__PURE__ */ jsx("path", { d: "M3 2.4 5.4 5.8 H0.6 Z" }),
482
+ /* @__PURE__ */ jsx("path", { d: "M3 21.6 0.6 18.2 H5.4 Z" }),
483
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "5.6", width: "12", height: "2.4", rx: "1.2" }),
484
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "16", width: "12", height: "2.4", rx: "1.2" })
485
+ ] });
486
+ const CaptionsIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
487
+ /* @__PURE__ */ jsx("rect", { width: "18", height: "14", x: "3", y: "5", rx: "2", ry: "2" }),
488
+ /* @__PURE__ */ jsx("path", { d: "M7 15h4" }),
489
+ /* @__PURE__ */ jsx("path", { d: "M15 15h2" }),
490
+ /* @__PURE__ */ jsx("path", { d: "M7 11h2" }),
491
+ /* @__PURE__ */ jsx("path", { d: "M13 11h4" })
492
+ ] });
428
493
  const ImportIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
429
494
  /* @__PURE__ */ jsx("path", { d: "M12 3v12" }),
430
495
  /* @__PURE__ */ jsx("path", { d: "m8 11 4 4 4-4" }),
@@ -601,6 +666,16 @@ const defaultToolbarLabels = {
601
666
  superscript: "Superscript",
602
667
  subscript: "Subscript",
603
668
  link: "Link",
669
+ align: "Alignment",
670
+ alignLeft: "Align left",
671
+ alignCenter: "Align center",
672
+ alignRight: "Align right",
673
+ alignJustify: "Justify",
674
+ indent: "Indent",
675
+ indentIncrease: "Increase indent",
676
+ indentDecrease: "Decrease indent",
677
+ lineHeight: "Line height",
678
+ lineHeightDefault: "Default",
604
679
  linkPrompt: "Enter URL",
605
680
  linkApply: "Apply link",
606
681
  linkOpen: "Open in new window",
@@ -608,6 +683,12 @@ const defaultToolbarLabels = {
608
683
  linkInvalid: "The editor rejected this address",
609
684
  image: "Image",
610
685
  imageUploadFailed: "Image upload failed",
686
+ imageAlign: "Image alignment",
687
+ imageAlignLeft: "Align left",
688
+ imageAlignCenter: "Align center",
689
+ imageAlignRight: "Align right",
690
+ imageCaption: "Caption",
691
+ imageCaptionPlaceholder: "Add a caption…",
611
692
  importMarkdownFailed: "Markdown import failed",
612
693
  importDocument: "Import",
613
694
  importDocumentHint: "Import a file",
@@ -697,7 +778,12 @@ const defaultShortcutLabels = {
697
778
  undo: "Undo",
698
779
  redo: "Redo",
699
780
  hardBreak: "Hard break",
700
- findReplace: "Find & replace"
781
+ findReplace: "Find & replace",
782
+ alignLeft: "Align left",
783
+ alignCenter: "Align center",
784
+ alignRight: "Align right",
785
+ alignJustify: "Justify",
786
+ imageUpload: "Upload image"
701
787
  };
702
788
  const defaultLinkPopoverLabels = {
703
789
  field: "Enter URL",
@@ -746,28 +832,41 @@ const defaultFindLabels = {
746
832
  invalidRegex: "Invalid pattern",
747
833
  readOnly: "Read-only"
748
834
  };
749
- const bar = "_bar_1h61e_3";
835
+ const defaultImageUploadLabels = {
836
+ dropzoneClick: "Click to upload",
837
+ dropzoneRest: " or drag and drop",
838
+ dropzoneLimits: (limit, maxSizeMb) => {
839
+ const count = `Maximum ${limit} file${limit === 1 ? "" : "s"}`;
840
+ return maxSizeMb == null ? `${count}.` : `${count}, ${maxSizeMb}MB each.`;
841
+ },
842
+ uploadingCount: (count) => `Uploading ${count} files`,
843
+ clearAll: "Clear all",
844
+ remove: "Remove",
845
+ failed: "Upload failed",
846
+ fallbackAlt: "image"
847
+ };
848
+ const bar$1 = "_bar_1h61e_3";
750
849
  const row$1 = "_row_1h61e_25";
751
850
  const field$1 = "_field_1h61e_43";
752
851
  const fieldIcon = "_fieldIcon_1h61e_62";
753
852
  const input$1 = "_input_1h61e_67";
754
853
  const counter = "_counter_1h61e_79";
755
854
  const counterInvalid = "_counterInvalid_1h61e_89";
756
- const btn$2 = "_btn_1h61e_93";
855
+ const btn$3 = "_btn_1h61e_93";
757
856
  const toggle = "_toggle_1h61e_29";
758
857
  const toggleOn = "_toggleOn_1h61e_135";
759
858
  const iconGroup = "_iconGroup_1h61e_29";
760
859
  const spacer = "_spacer_1h61e_150";
761
860
  const readOnly = "_readOnly_1h61e_155";
762
- const styles$9 = {
763
- bar,
861
+ const styles$b = {
862
+ bar: bar$1,
764
863
  row: row$1,
765
864
  field: field$1,
766
865
  fieldIcon,
767
866
  input: input$1,
768
867
  counter,
769
868
  counterInvalid,
770
- btn: btn$2,
869
+ btn: btn$3,
771
870
  toggle,
772
871
  toggleOn,
773
872
  iconGroup,
@@ -883,11 +982,11 @@ function FindReplaceBar({
883
982
  });
884
983
  };
885
984
  if (!hasExtension) return null;
886
- const toggleClass = (on) => `${styles$9.btn} ${styles$9.toggle}${on ? ` ${styles$9.toggleOn}` : ""}`;
985
+ const toggleClass = (on) => `${styles$b.btn} ${styles$b.toggle}${on ? ` ${styles$b.toggleOn}` : ""}`;
887
986
  return /* @__PURE__ */ jsxs(
888
987
  "div",
889
988
  {
890
- className: className ? `${styles$9.bar} ${className}` : styles$9.bar,
989
+ className: className ? `${styles$b.bar} ${className}` : styles$b.bar,
891
990
  style,
892
991
  "data-find-bar": "",
893
992
  role: "dialog",
@@ -900,14 +999,14 @@ function FindReplaceBar({
900
999
  onClose();
901
1000
  },
902
1001
  children: [
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 }),
1002
+ /* @__PURE__ */ jsxs("div", { className: styles$b.row, children: [
1003
+ /* @__PURE__ */ jsxs("span", { className: styles$b.field, children: [
1004
+ /* @__PURE__ */ jsx(SearchIcon, { size: 14, className: styles$b.fieldIcon }),
906
1005
  /* @__PURE__ */ jsx(
907
1006
  "input",
908
1007
  {
909
1008
  ref: inputRef,
910
- className: styles$9.input,
1009
+ className: styles$b.input,
911
1010
  "data-find-field": "search",
912
1011
  value: term,
913
1012
  onChange: (e2) => setTerm(e2.target.value),
@@ -921,7 +1020,7 @@ function FindReplaceBar({
921
1020
  /* @__PURE__ */ jsx(
922
1021
  "span",
923
1022
  {
924
- className: `${styles$9.counter}${invalidPattern ? ` ${styles$9.counterInvalid}` : ""}`,
1023
+ className: `${styles$b.counter}${invalidPattern ? ` ${styles$b.counterInvalid}` : ""}`,
925
1024
  "data-find-counter": "",
926
1025
  "aria-live": "polite",
927
1026
  title: invalidPattern ? t.invalidRegex : void 0,
@@ -957,13 +1056,13 @@ function FindReplaceBar({
957
1056
  children: "ab"
958
1057
  }
959
1058
  ),
960
- /* @__PURE__ */ jsx("span", { className: styles$9.spacer }),
961
- /* @__PURE__ */ jsxs("span", { className: styles$9.iconGroup, children: [
1059
+ /* @__PURE__ */ jsx("span", { className: styles$b.spacer }),
1060
+ /* @__PURE__ */ jsxs("span", { className: styles$b.iconGroup, children: [
962
1061
  /* @__PURE__ */ jsx(
963
1062
  "button",
964
1063
  {
965
1064
  type: "button",
966
- className: styles$9.btn,
1065
+ className: styles$b.btn,
967
1066
  "data-find-action": "previous",
968
1067
  title: t.previous,
969
1068
  "aria-label": t.previous,
@@ -977,7 +1076,7 @@ function FindReplaceBar({
977
1076
  "button",
978
1077
  {
979
1078
  type: "button",
980
- className: styles$9.btn,
1079
+ className: styles$b.btn,
981
1080
  "data-find-action": "next",
982
1081
  title: t.next,
983
1082
  "aria-label": t.next,
@@ -991,7 +1090,7 @@ function FindReplaceBar({
991
1090
  "button",
992
1091
  {
993
1092
  type: "button",
994
- className: styles$9.btn,
1093
+ className: styles$b.btn,
995
1094
  "data-find-action": "close",
996
1095
  title: t.close,
997
1096
  "aria-label": t.close,
@@ -1001,11 +1100,11 @@ function FindReplaceBar({
1001
1100
  )
1002
1101
  ] })
1003
1102
  ] }),
1004
- editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$9.row, children: [
1005
- /* @__PURE__ */ jsx("span", { className: styles$9.field, children: /* @__PURE__ */ jsx(
1103
+ editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$b.row, children: [
1104
+ /* @__PURE__ */ jsx("span", { className: styles$b.field, children: /* @__PURE__ */ jsx(
1006
1105
  "input",
1007
1106
  {
1008
- className: styles$9.input,
1107
+ className: styles$b.input,
1009
1108
  "data-find-field": "replace",
1010
1109
  value: replaceTerm,
1011
1110
  onChange: (e2) => setReplaceTerm(e2.target.value),
@@ -1015,12 +1114,12 @@ function FindReplaceBar({
1015
1114
  spellCheck: false
1016
1115
  }
1017
1116
  ) }),
1018
- /* @__PURE__ */ jsx("span", { className: styles$9.spacer }),
1117
+ /* @__PURE__ */ jsx("span", { className: styles$b.spacer }),
1019
1118
  /* @__PURE__ */ jsx(
1020
1119
  "button",
1021
1120
  {
1022
1121
  type: "button",
1023
- className: styles$9.btn,
1122
+ className: styles$b.btn,
1024
1123
  "data-find-action": "replace",
1025
1124
  title: t.replaceOne,
1026
1125
  "aria-label": t.replaceOne,
@@ -1034,7 +1133,7 @@ function FindReplaceBar({
1034
1133
  "button",
1035
1134
  {
1036
1135
  type: "button",
1037
- className: styles$9.btn,
1136
+ className: styles$b.btn,
1038
1137
  "data-find-action": "replace-all",
1039
1138
  title: t.replaceAll,
1040
1139
  "aria-label": t.replaceAll,
@@ -1044,7 +1143,7 @@ function FindReplaceBar({
1044
1143
  children: /* @__PURE__ */ jsx(ReplaceAllIcon, { size: 16 })
1045
1144
  }
1046
1145
  )
1047
- ] }) : /* @__PURE__ */ jsx("div", { className: styles$9.row, children: /* @__PURE__ */ jsx("span", { className: styles$9.readOnly, children: t.readOnly }) })
1146
+ ] }) : /* @__PURE__ */ jsx("div", { className: styles$b.row, children: /* @__PURE__ */ jsx("span", { className: styles$b.readOnly, children: t.readOnly }) })
1048
1147
  ]
1049
1148
  }
1050
1149
  );
@@ -1131,6 +1230,515 @@ const ImportPlaceholder = Node$1.create({
1131
1230
  };
1132
1231
  }
1133
1232
  });
1233
+ const wrap = "_wrap_1k6n1_8";
1234
+ const dropzone = "_dropzone_1k6n1_24";
1235
+ const dragActive = "_dragActive_1k6n1_43";
1236
+ const dragOver = "_dragOver_1k6n1_51";
1237
+ const fileShape = "_fileShape_1k6n1_56";
1238
+ const fileShapeDoc = "_fileShapeDoc_1k6n1_65";
1239
+ const fileShapeCorner = "_fileShapeCorner_1k6n1_71";
1240
+ const fileBadge = "_fileBadge_1k6n1_78";
1241
+ const text = "_text_1k6n1_92";
1242
+ const textMain = "_textMain_1k6n1_100";
1243
+ const textEm = "_textEm_1k6n1_107";
1244
+ const subtext = "_subtext_1k6n1_112";
1245
+ const previews = "_previews_1k6n1_121";
1246
+ const header$2 = "_header_1k6n1_127";
1247
+ const clearAll = "_clearAll_1k6n1_139";
1248
+ const preview = "_preview_1k6n1_121";
1249
+ const progress = "_progress_1k6n1_161";
1250
+ const previewContent = "_previewContent_1k6n1_169";
1251
+ const fileInfo = "_fileInfo_1k6n1_180";
1252
+ const fileIcon = "_fileIcon_1k6n1_187";
1253
+ const details = "_details_1k6n1_199";
1254
+ const fileName = "_fileName_1k6n1_205";
1255
+ const actions = "_actions_1k6n1_215";
1256
+ const progressText = "_progressText_1k6n1_222";
1257
+ const remove = "_remove_1k6n1_228";
1258
+ const styles$a = {
1259
+ wrap,
1260
+ dropzone,
1261
+ dragActive,
1262
+ dragOver,
1263
+ fileShape,
1264
+ fileShapeDoc,
1265
+ fileShapeCorner,
1266
+ fileBadge,
1267
+ text,
1268
+ textMain,
1269
+ textEm,
1270
+ subtext,
1271
+ previews,
1272
+ header: header$2,
1273
+ clearAll,
1274
+ preview,
1275
+ progress,
1276
+ previewContent,
1277
+ fileInfo,
1278
+ fileIcon,
1279
+ details,
1280
+ fileName,
1281
+ actions,
1282
+ progressText,
1283
+ remove
1284
+ };
1285
+ let seq = 0;
1286
+ const nextId = () => `image-upload-${++seq}`;
1287
+ function formatFileSize(bytes) {
1288
+ if (bytes <= 0) return "0 B";
1289
+ const units = ["B", "KB", "MB", "GB"];
1290
+ const i = Math.min(
1291
+ Math.floor(Math.log(bytes) / Math.log(1024)),
1292
+ units.length - 1
1293
+ );
1294
+ return `${parseFloat((bytes / 1024 ** i).toFixed(1))} ${units[i]}`;
1295
+ }
1296
+ const toMb = (bytes) => parseFloat((bytes / 1024 / 1024).toFixed(1));
1297
+ function focusNextNode(editor) {
1298
+ const { state, view } = editor;
1299
+ const next = Selection.findFrom(state.selection.$to, 1, true);
1300
+ if (next) {
1301
+ view.dispatch(state.tr.setSelection(next).scrollIntoView());
1302
+ return;
1303
+ }
1304
+ const paragraph = state.schema.nodes.paragraph;
1305
+ if (!paragraph) return;
1306
+ const end = state.doc.content.size;
1307
+ const tr = state.tr.insert(end, paragraph.create());
1308
+ view.dispatch(
1309
+ tr.setSelection(TextSelection.near(tr.doc.resolve(end + 1))).scrollIntoView()
1310
+ );
1311
+ }
1312
+ function ImageUploadView(props) {
1313
+ const { node, extension, editor, getPos } = props;
1314
+ const options = extension.options;
1315
+ const labels = {
1316
+ ...defaultImageUploadLabels,
1317
+ ...options.labels
1318
+ };
1319
+ const accept = String(node.attrs.accept ?? "image/*");
1320
+ const limit = Number(node.attrs.limit ?? 1) || 1;
1321
+ const maxSize = Number(node.attrs.maxSize ?? 0) || 0;
1322
+ const [items, setItems] = useState([]);
1323
+ const [dragActive2, setDragActive] = useState(false);
1324
+ const [dragOver2, setDragOver] = useState(false);
1325
+ const inputRef = useRef(null);
1326
+ const itemsRef = useRef(items);
1327
+ itemsRef.current = items;
1328
+ useEffect(
1329
+ () => () => itemsRef.current.forEach((it) => it.abort.abort()),
1330
+ []
1331
+ );
1332
+ const patchItem = (id, partial) => {
1333
+ setItems(
1334
+ (prev) => prev.map((it) => it.id === id ? { ...it, ...partial } : it)
1335
+ );
1336
+ };
1337
+ const uploadOne = async (file) => {
1338
+ var _a, _b, _c, _d;
1339
+ if (maxSize > 0 && file.size > maxSize) {
1340
+ (_a = options.onError) == null ? void 0 : _a.call(
1341
+ options,
1342
+ new Error(
1343
+ `File size exceeds the maximum of ${formatFileSize(maxSize)}`
1344
+ )
1345
+ );
1346
+ return null;
1347
+ }
1348
+ if (!options.upload) {
1349
+ (_b = options.onError) == null ? void 0 : _b.call(options, new Error("Upload function is not defined"));
1350
+ return null;
1351
+ }
1352
+ const abort = new AbortController();
1353
+ const id = nextId();
1354
+ setItems((prev) => [
1355
+ ...prev,
1356
+ { id, file, progress: 0, status: "uploading", abort }
1357
+ ]);
1358
+ try {
1359
+ const url = await options.upload(
1360
+ file,
1361
+ ({ progress: progress2 }) => patchItem(id, { progress: progress2 }),
1362
+ abort.signal
1363
+ );
1364
+ if (!url) throw new Error("Upload returned no URL");
1365
+ if (abort.signal.aborted) return null;
1366
+ (_c = options.onSuccess) == null ? void 0 : _c.call(options, url);
1367
+ return url;
1368
+ } catch (err) {
1369
+ if (!abort.signal.aborted) {
1370
+ patchItem(id, { status: "error", progress: 0 });
1371
+ (_d = options.onError) == null ? void 0 : _d.call(options, err instanceof Error ? err : new Error(String(err)));
1372
+ }
1373
+ return null;
1374
+ }
1375
+ };
1376
+ const uploadFiles = async (files) => {
1377
+ var _a;
1378
+ if (files.length === 0) return;
1379
+ if (limit > 0 && files.length > limit) {
1380
+ (_a = options.onError) == null ? void 0 : _a.call(
1381
+ options,
1382
+ new Error(`Maximum ${limit} file${limit === 1 ? "" : "s"} at a time`)
1383
+ );
1384
+ return;
1385
+ }
1386
+ const settled = await Promise.all(
1387
+ files.map(async (file) => ({ file, url: await uploadOne(file) }))
1388
+ );
1389
+ const uploaded = settled.filter(
1390
+ (s4) => s4.url != null
1391
+ );
1392
+ if (uploaded.length === 0) return;
1393
+ const pos = getPos();
1394
+ if (typeof pos !== "number") return;
1395
+ const imageType = options.type ?? "image";
1396
+ const nodes = uploaded.map(({ file, url }) => {
1397
+ const alt = file.name.replace(/\.[^/.]+$/, "") || labels.fallbackAlt;
1398
+ return { type: imageType, attrs: { src: url, alt, title: alt } };
1399
+ });
1400
+ editor.chain().focus().deleteRange({ from: pos, to: pos + node.nodeSize }).insertContentAt(pos, nodes).run();
1401
+ focusNextNode(editor);
1402
+ };
1403
+ const removeItem = (id) => {
1404
+ var _a;
1405
+ (_a = itemsRef.current.find((it) => it.id === id)) == null ? void 0 : _a.abort.abort();
1406
+ setItems((prev) => prev.filter((it) => it.id !== id));
1407
+ };
1408
+ const clearAll2 = () => {
1409
+ itemsRef.current.forEach((it) => it.abort.abort());
1410
+ setItems([]);
1411
+ };
1412
+ const openPicker = () => {
1413
+ if (!editor.isEditable || items.length > 0) return;
1414
+ const input2 = inputRef.current;
1415
+ if (!input2) return;
1416
+ input2.value = "";
1417
+ input2.click();
1418
+ };
1419
+ const onInputChange = (e2) => {
1420
+ const files = Array.from(e2.target.files ?? []);
1421
+ e2.target.value = "";
1422
+ if (files.length > 0) void uploadFiles(files);
1423
+ };
1424
+ const onDrop = (e2) => {
1425
+ e2.preventDefault();
1426
+ e2.stopPropagation();
1427
+ setDragActive(false);
1428
+ setDragOver(false);
1429
+ const files = Array.from(e2.dataTransfer.files);
1430
+ if (files.length > 0) void uploadFiles(files);
1431
+ };
1432
+ const editable = editor.isEditable;
1433
+ const hasFiles = items.length > 0;
1434
+ const maxSizeMb = maxSize > 0 ? toMb(maxSize) : null;
1435
+ const dropzoneClass = [
1436
+ styles$a.dropzone,
1437
+ dragActive2 ? styles$a.dragActive : "",
1438
+ dragOver2 ? styles$a.dragOver : ""
1439
+ ].filter(Boolean).join(" ");
1440
+ return /* @__PURE__ */ jsxs(
1441
+ NodeViewWrapper,
1442
+ {
1443
+ className: styles$a.wrap,
1444
+ "data-image-upload": "",
1445
+ tabIndex: editable ? 0 : void 0,
1446
+ onClick: openPicker,
1447
+ children: [
1448
+ !hasFiles ? /* @__PURE__ */ jsxs(
1449
+ "div",
1450
+ {
1451
+ className: dropzoneClass,
1452
+ "data-image-upload-dropzone": "",
1453
+ role: editable ? "button" : void 0,
1454
+ "aria-label": editable ? `${labels.dropzoneClick}${labels.dropzoneRest}` : void 0,
1455
+ onDragEnter: (e2) => {
1456
+ e2.preventDefault();
1457
+ e2.stopPropagation();
1458
+ setDragActive(true);
1459
+ },
1460
+ onDragOver: (e2) => {
1461
+ e2.preventDefault();
1462
+ e2.stopPropagation();
1463
+ setDragOver(true);
1464
+ },
1465
+ onDragLeave: (e2) => {
1466
+ e2.preventDefault();
1467
+ e2.stopPropagation();
1468
+ if (!e2.currentTarget.contains(e2.relatedTarget)) {
1469
+ setDragActive(false);
1470
+ setDragOver(false);
1471
+ }
1472
+ },
1473
+ onDrop,
1474
+ children: [
1475
+ /* @__PURE__ */ jsxs("span", { className: styles$a.fileShape, "aria-hidden": true, children: [
1476
+ /* @__PURE__ */ jsx(FileDocIcon, {}),
1477
+ /* @__PURE__ */ jsx(FileCornerIcon, {}),
1478
+ /* @__PURE__ */ jsx("span", { className: styles$a.fileBadge, children: /* @__PURE__ */ jsx(CloudUploadIcon, {}) })
1479
+ ] }),
1480
+ /* @__PURE__ */ jsxs("span", { className: styles$a.text, children: [
1481
+ /* @__PURE__ */ jsxs("span", { className: styles$a.textMain, children: [
1482
+ /* @__PURE__ */ jsx("em", { className: styles$a.textEm, children: labels.dropzoneClick }),
1483
+ labels.dropzoneRest
1484
+ ] }),
1485
+ /* @__PURE__ */ jsx("span", { className: styles$a.subtext, children: labels.dropzoneLimits(limit, maxSizeMb) })
1486
+ ] })
1487
+ ]
1488
+ }
1489
+ ) : /* @__PURE__ */ jsxs("div", { className: styles$a.previews, "data-image-upload-list": "", children: [
1490
+ items.length > 1 && /* @__PURE__ */ jsxs("div", { className: styles$a.header, children: [
1491
+ /* @__PURE__ */ jsx("span", { children: labels.uploadingCount(items.length) }),
1492
+ /* @__PURE__ */ jsx(
1493
+ "button",
1494
+ {
1495
+ type: "button",
1496
+ className: styles$a.clearAll,
1497
+ onClick: (e2) => {
1498
+ e2.stopPropagation();
1499
+ clearAll2();
1500
+ },
1501
+ children: labels.clearAll
1502
+ }
1503
+ )
1504
+ ] }),
1505
+ items.map((it) => /* @__PURE__ */ jsxs(
1506
+ "div",
1507
+ {
1508
+ className: styles$a.preview,
1509
+ "data-image-upload-item": "",
1510
+ children: [
1511
+ it.status === "uploading" && /* @__PURE__ */ jsx(
1512
+ "div",
1513
+ {
1514
+ className: styles$a.progress,
1515
+ style: { width: `${it.progress}%` },
1516
+ "aria-hidden": true
1517
+ }
1518
+ ),
1519
+ /* @__PURE__ */ jsxs("div", { className: styles$a.previewContent, children: [
1520
+ /* @__PURE__ */ jsxs("span", { className: styles$a.fileInfo, children: [
1521
+ /* @__PURE__ */ jsx("span", { className: styles$a.fileIcon, "aria-hidden": true, children: /* @__PURE__ */ jsx(CloudUploadIcon, {}) }),
1522
+ /* @__PURE__ */ jsxs("span", { className: styles$a.details, children: [
1523
+ /* @__PURE__ */ jsx("span", { className: styles$a.fileName, children: it.file.name }),
1524
+ /* @__PURE__ */ jsx("span", { className: styles$a.subtext, children: it.status === "error" ? labels.failed : formatFileSize(it.file.size) })
1525
+ ] })
1526
+ ] }),
1527
+ /* @__PURE__ */ jsxs("span", { className: styles$a.actions, children: [
1528
+ it.status === "uploading" && /* @__PURE__ */ jsxs("span", { className: styles$a.progressText, children: [
1529
+ Math.round(it.progress),
1530
+ "%"
1531
+ ] }),
1532
+ /* @__PURE__ */ jsx(
1533
+ "button",
1534
+ {
1535
+ type: "button",
1536
+ className: styles$a.remove,
1537
+ "data-image-upload-remove": "",
1538
+ title: labels.remove,
1539
+ "aria-label": labels.remove,
1540
+ onClick: (e2) => {
1541
+ e2.stopPropagation();
1542
+ removeItem(it.id);
1543
+ },
1544
+ children: /* @__PURE__ */ jsx(XIcon, { size: 14 })
1545
+ }
1546
+ )
1547
+ ] })
1548
+ ] })
1549
+ ]
1550
+ },
1551
+ it.id
1552
+ ))
1553
+ ] }),
1554
+ editable && /* @__PURE__ */ jsx(
1555
+ "input",
1556
+ {
1557
+ ref: inputRef,
1558
+ type: "file",
1559
+ accept,
1560
+ multiple: limit > 1,
1561
+ hidden: true,
1562
+ onChange: onInputChange,
1563
+ onClick: (e2) => e2.stopPropagation()
1564
+ }
1565
+ )
1566
+ ]
1567
+ }
1568
+ );
1569
+ }
1570
+ function CloudUploadIcon({ size = 14 }) {
1571
+ return /* @__PURE__ */ jsxs(
1572
+ "svg",
1573
+ {
1574
+ width: size,
1575
+ height: size,
1576
+ viewBox: "0 0 24 24",
1577
+ fill: "currentColor",
1578
+ "aria-hidden": true,
1579
+ children: [
1580
+ /* @__PURE__ */ jsx("path", { d: "M11.1953 4.41771C10.3478 4.08499 9.43578 3.94949 8.5282 4.02147C7.62062 4.09345 6.74133 4.37102 5.95691 4.83316C5.1725 5.2953 4.50354 5.92989 4.00071 6.68886C3.49788 7.44783 3.17436 8.31128 3.05465 9.2138C2.93495 10.1163 3.0222 11.0343 3.3098 11.8981C3.5974 12.7619 4.07781 13.5489 4.71463 14.1995C5.10094 14.5942 5.09414 15.2274 4.69945 15.6137C4.30476 16 3.67163 15.9932 3.28532 15.5985C2.43622 14.731 1.79568 13.6816 1.41221 12.5299C1.02875 11.3781 0.91241 10.1542 1.07201 8.95084C1.23162 7.74748 1.66298 6.59621 2.33343 5.58425C3.00387 4.57229 3.89581 3.72617 4.9417 3.10998C5.98758 2.4938 7.15998 2.1237 8.37008 2.02773C9.58018 1.93176 10.7963 2.11243 11.9262 2.55605C13.0561 2.99968 14.0703 3.69462 14.8919 4.58825C15.5423 5.29573 16.0585 6.11304 16.4177 7.00002H17.4999C18.6799 6.99991 19.8288 7.37933 20.7766 8.08222C21.7245 8.78515 22.4212 9.7743 22.7637 10.9036C23.1062 12.0328 23.0765 13.2423 22.6788 14.3534C22.2812 15.4644 21.5367 16.4181 20.5554 17.0736C20.0962 17.3803 19.4752 17.2567 19.1684 16.7975C18.8617 16.3382 18.9853 15.7172 19.4445 15.4105C20.069 14.9934 20.5427 14.3865 20.7958 13.6794C21.0488 12.9724 21.0678 12.2027 20.8498 11.4841C20.6318 10.7655 20.1885 10.136 19.5853 9.6887C18.9821 9.24138 18.251 8.99993 17.5001 9.00002H15.71C15.2679 9.00002 14.8783 8.70973 14.7518 8.28611C14.4913 7.41374 14.0357 6.61208 13.4195 5.94186C12.8034 5.27164 12.0427 4.75043 11.1953 4.41771Z" }),
1581
+ /* @__PURE__ */ jsx("path", { d: "M11 14.4142V21C11 21.5523 11.4477 22 12 22C12.5523 22 13 21.5523 13 21V14.4142L15.2929 16.7071C15.6834 17.0976 16.3166 17.0976 16.7071 16.7071C17.0976 16.3166 17.0976 15.6834 16.7071 15.2929L12.7078 11.2936C12.7054 11.2912 12.703 11.2888 12.7005 11.2864C12.5208 11.1099 12.2746 11.0008 12.003 11L12 11L11.997 11C11.8625 11.0004 11.7343 11.0273 11.6172 11.0759C11.502 11.1236 11.3938 11.1937 11.2995 11.2864C11.297 11.2888 11.2946 11.2912 11.2922 11.2936L7.29289 15.2929C6.90237 15.6834 6.90237 16.3166 7.29289 16.7071C7.68342 17.0976 8.31658 17.0976 8.70711 16.7071L11 14.4142Z" })
1582
+ ]
1583
+ }
1584
+ );
1585
+ }
1586
+ function FileDocIcon() {
1587
+ return /* @__PURE__ */ jsx(
1588
+ "svg",
1589
+ {
1590
+ width: "43",
1591
+ height: "57",
1592
+ viewBox: "0 0 43 57",
1593
+ fill: "none",
1594
+ "aria-hidden": true,
1595
+ className: styles$a.fileShapeDoc,
1596
+ children: /* @__PURE__ */ jsx(
1597
+ "path",
1598
+ {
1599
+ d: "M0.75 10.75C0.75 5.64137 4.89137 1.5 10 1.5H32.3431C33.2051 1.5 34.0317 1.84241 34.6412 2.4519L40.2981 8.10876C40.9076 8.71825 41.25 9.5449 41.25 10.4069V46.75C41.25 51.8586 37.1086 56 32 56H10C4.89137 56 0.75 51.8586 0.75 46.75V10.75Z",
1600
+ fill: "currentColor",
1601
+ fillOpacity: "0.11",
1602
+ stroke: "currentColor",
1603
+ strokeWidth: "1.5"
1604
+ }
1605
+ )
1606
+ }
1607
+ );
1608
+ }
1609
+ function FileCornerIcon() {
1610
+ return /* @__PURE__ */ jsx(
1611
+ "svg",
1612
+ {
1613
+ width: "10",
1614
+ height: "10",
1615
+ viewBox: "0 0 10 10",
1616
+ fill: "currentColor",
1617
+ "aria-hidden": true,
1618
+ className: styles$a.fileShapeCorner,
1619
+ children: /* @__PURE__ */ jsx("path", { d: "M0 0.75H0.343146C1.40401 0.75 2.42143 1.17143 3.17157 1.92157L8.82843 7.57843C9.57857 8.32857 10 9.34599 10 10.4069V10.75H4C1.79086 10.75 0 8.95914 0 6.75V0.75Z" })
1620
+ }
1621
+ );
1622
+ }
1623
+ function hasImageUpload(editor) {
1624
+ return editor.extensionManager.extensions.some(
1625
+ (ext) => ext.name === ImageUploadNode.name
1626
+ );
1627
+ }
1628
+ const ImageUploadNode = Node$1.create({
1629
+ name: "imageUpload",
1630
+ group: "block",
1631
+ atom: true,
1632
+ draggable: true,
1633
+ selectable: true,
1634
+ addOptions() {
1635
+ return {
1636
+ upload: void 0,
1637
+ accept: "image/*",
1638
+ limit: 1,
1639
+ maxSize: 0,
1640
+ type: "image",
1641
+ onError: void 0,
1642
+ onSuccess: void 0,
1643
+ labels: void 0
1644
+ };
1645
+ },
1646
+ addAttributes() {
1647
+ return {
1648
+ accept: { default: this.options.accept },
1649
+ limit: { default: this.options.limit },
1650
+ maxSize: { default: this.options.maxSize }
1651
+ };
1652
+ },
1653
+ parseHTML() {
1654
+ return [{ tag: 'div[data-type="image-upload"]' }];
1655
+ },
1656
+ renderHTML({ HTMLAttributes }) {
1657
+ return [
1658
+ "div",
1659
+ mergeAttributes({ "data-type": "image-upload" }, HTMLAttributes)
1660
+ ];
1661
+ },
1662
+ /** 占位块不进 Markdown(与 ImportPlaceholder 同):上传中的状态不该被保存。 */
1663
+ renderMarkdown() {
1664
+ return "";
1665
+ },
1666
+ addNodeView() {
1667
+ return ReactNodeViewRenderer(ImageUploadView);
1668
+ },
1669
+ addCommands() {
1670
+ return {
1671
+ setImageUploadNode: (options) => ({ commands }) => commands.insertContent({ type: this.name, attrs: options })
1672
+ };
1673
+ },
1674
+ addKeyboardShortcuts() {
1675
+ return {
1676
+ // 官方图片按钮的快捷键(Cmd/Ctrl+Shift+I)。Windows 上 Ctrl+Shift+I 是
1677
+ // DevTools 的键位,冲突时浏览器优先——与官方行为一致。
1678
+ "Mod-Shift-i": () => this.editor.commands.setImageUploadNode(),
1679
+ // 选中占位块时按 Enter = 打开文件选择框。借 NodeView 的点击路径(NodeViewWrapper
1680
+ // 外包一层 div,所以要点它的第一个子元素),与官方同款实现。
1681
+ Enter: ({ editor }) => {
1682
+ const { selection } = editor.state;
1683
+ const { nodeAfter } = selection.$from;
1684
+ if ((nodeAfter == null ? void 0 : nodeAfter.type.name) !== this.name || !editor.isActive(this.name)) {
1685
+ return false;
1686
+ }
1687
+ const nodeEl = editor.view.nodeDOM(selection.$from.pos);
1688
+ const clickable = nodeEl instanceof HTMLElement ? nodeEl.firstChild : null;
1689
+ if (clickable instanceof HTMLElement) {
1690
+ clickable.click();
1691
+ return true;
1692
+ }
1693
+ return false;
1694
+ }
1695
+ };
1696
+ }
1697
+ });
1698
+ function findImagePos(editor) {
1699
+ var _a, _b;
1700
+ const { selection } = editor.state;
1701
+ if (selection instanceof NodeSelection && selection.node.type.name === "image") {
1702
+ return selection.from;
1703
+ }
1704
+ const { $from } = selection;
1705
+ if (((_a = $from.nodeAfter) == null ? void 0 : _a.type.name) === "image") return $from.pos;
1706
+ if (((_b = $from.nodeBefore) == null ? void 0 : _b.type.name) === "image") {
1707
+ return $from.pos - $from.nodeBefore.nodeSize;
1708
+ }
1709
+ return null;
1710
+ }
1711
+ function readAlign(editor, pos) {
1712
+ var _a;
1713
+ return normalizeImageAlign((_a = editor.state.doc.nodeAt(pos)) == null ? void 0 : _a.attrs.align);
1714
+ }
1715
+ function isImageAlignActive(editor, align) {
1716
+ const pos = findImagePos(editor);
1717
+ return pos != null && readAlign(editor, pos) === align;
1718
+ }
1719
+ function setImageAlign(editor, align) {
1720
+ const pos = findImagePos(editor);
1721
+ if (pos == null) return false;
1722
+ if (readAlign(editor, pos) === align) return true;
1723
+ return editor.chain().focus().setNodeSelection(pos).updateAttributes("image", { align }).run();
1724
+ }
1725
+ function setImageAlignAtPos(editor, pos, align) {
1726
+ const node = editor.state.doc.nodeAt(pos);
1727
+ if (!node || node.type.name !== "image") return false;
1728
+ if (normalizeImageAlign(node.attrs.align) === align) return true;
1729
+ editor.view.dispatch(editor.state.tr.setNodeAttribute(pos, "align", align));
1730
+ return true;
1731
+ }
1732
+ function setImageAlignAt(editor, imageElement, align) {
1733
+ try {
1734
+ const pos = editor.view.posAtDOM(imageElement, 0);
1735
+ const node = editor.state.doc.nodeAt(pos);
1736
+ if (!node || node.type.name !== "image") return false;
1737
+ return setImageAlignAtPos(editor, pos, align);
1738
+ } catch {
1739
+ return false;
1740
+ }
1741
+ }
1134
1742
  const popupHost = "_popupHost_1noza_11";
1135
1743
  const menu$1 = "_menu_1noza_1";
1136
1744
  const groupLabel = "_groupLabel_1noza_43";
@@ -1138,7 +1746,7 @@ const item$1 = "_item_1noza_53";
1138
1746
  const itemActive = "_itemActive_1noza_54";
1139
1747
  const itemIcon = "_itemIcon_1noza_79";
1140
1748
  const itemTitle = "_itemTitle_1noza_102";
1141
- const styles$8 = {
1749
+ const styles$9 = {
1142
1750
  popupHost,
1143
1751
  menu: menu$1,
1144
1752
  groupLabel,
@@ -1327,11 +1935,11 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1327
1935
  );
1328
1936
  if (!items.length) return null;
1329
1937
  let optionIndex = -1;
1330
- return /* @__PURE__ */ jsx("div", { className: styles$8.menu, role: "listbox", "aria-label": menuLabel, children: withGroupHeaders(items).map(([header2, item2]) => {
1938
+ return /* @__PURE__ */ jsx("div", { className: styles$9.menu, role: "listbox", "aria-label": menuLabel, children: withGroupHeaders(items).map(([header2, item2]) => {
1331
1939
  optionIndex += 1;
1332
1940
  const i = optionIndex;
1333
1941
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1334
- header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$8.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1942
+ header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$9.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1335
1943
  /* @__PURE__ */ jsxs(
1336
1944
  "button",
1337
1945
  {
@@ -1339,7 +1947,7 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1339
1947
  role: "option",
1340
1948
  "aria-selected": i === index,
1341
1949
  title: item2.title,
1342
- className: i === index ? styles$8.itemActive : styles$8.item,
1950
+ className: i === index ? styles$9.itemActive : styles$9.item,
1343
1951
  tabIndex: -1,
1344
1952
  onMouseEnter: () => setIndex(i),
1345
1953
  onMouseDown: (e2) => {
@@ -1347,8 +1955,8 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1347
1955
  command(item2);
1348
1956
  },
1349
1957
  children: [
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 })
1958
+ item2.icon != null ? /* @__PURE__ */ jsx("span", { className: styles$9.itemIcon, "aria-hidden": "true", children: item2.icon }) : /* @__PURE__ */ jsx("span", { className: styles$9.itemIcon, "aria-hidden": "true" }),
1959
+ /* @__PURE__ */ jsx("span", { className: styles$9.itemTitle, children: item2.title })
1352
1960
  ]
1353
1961
  }
1354
1962
  )
@@ -1399,7 +2007,7 @@ const SlashMenu = Extension.create({
1399
2007
  menuLabel: ((_a = this.options.labels) == null ? void 0 : _a.menuLabel) ?? defaultSlashMenuLabels.menuLabel,
1400
2008
  command: props.command
1401
2009
  },
1402
- className: styles$8.popupHost
2010
+ className: styles$9.popupHost
1403
2011
  }
1404
2012
  );
1405
2013
  const pmStyle = getComputedStyle(props.editor.view.dom);
@@ -1451,7 +2059,7 @@ const rowKeys = "_rowKeys_ljnq6_127";
1451
2059
  const rowMd = "_rowMd_ljnq6_128";
1452
2060
  const keycap = "_keycap_ljnq6_138";
1453
2061
  const none = "_none_ljnq6_163";
1454
- const styles$7 = {
2062
+ const styles$8 = {
1455
2063
  drawer,
1456
2064
  closeBtn,
1457
2065
  head,
@@ -1479,6 +2087,10 @@ function buildShortcutGroups(labels) {
1479
2087
  { id: "underline", label: labels.underline, keys: ["Mod", "u"] },
1480
2088
  { id: "inline-code", label: labels.inlineCode, keys: ["Mod", "e"], markdown: { marker: "`x`" } },
1481
2089
  { id: "highlight", label: labels.highlight, keys: ["Mod", "Shift", "h"], markdown: { marker: "==x==" } },
2090
+ { id: "align-left", label: labels.alignLeft, keys: ["Mod", "Shift", "l"] },
2091
+ { id: "align-center", label: labels.alignCenter, keys: ["Mod", "Shift", "e"] },
2092
+ { id: "align-right", label: labels.alignRight, keys: ["Mod", "Shift", "r"] },
2093
+ { id: "align-justify", label: labels.alignJustify, keys: ["Mod", "Shift", "j"] },
1482
2094
  ...[1, 2, 3, 4, 5, 6].map((level) => ({
1483
2095
  id: `heading-${level}`,
1484
2096
  label: labels.headingLabel(level),
@@ -1492,6 +2104,7 @@ function buildShortcutGroups(labels) {
1492
2104
  id: "insert",
1493
2105
  title: labels.insertGroup,
1494
2106
  entries: [
2107
+ { id: "image-upload", label: labels.imageUpload, keys: ["Mod", "Shift", "i"] },
1495
2108
  { id: "blockquote", label: labels.blockquote, keys: ["Mod", "Shift", "b"], markdown: { marker: ">", terminator: "Space" } },
1496
2109
  { id: "bullet-list", label: labels.bulletList, keys: ["Mod", "Shift", "8"], markdown: { marker: "-", terminator: "Space" } },
1497
2110
  { id: "ordered-list", label: labels.orderedList, keys: ["Mod", "Shift", "7"], markdown: { marker: "1.", terminator: "Space" } },
@@ -1544,7 +2157,7 @@ function ShortcutPanel({ open, onClose, labels }) {
1544
2157
  return /* @__PURE__ */ jsxs(
1545
2158
  "aside",
1546
2159
  {
1547
- className: styles$7.drawer,
2160
+ className: styles$8.drawer,
1548
2161
  role: "dialog",
1549
2162
  "aria-modal": "false",
1550
2163
  "aria-label": t.panelTitle,
@@ -1553,27 +2166,27 @@ function ShortcutPanel({ open, onClose, labels }) {
1553
2166
  "button",
1554
2167
  {
1555
2168
  type: "button",
1556
- className: styles$7.closeBtn,
2169
+ className: styles$8.closeBtn,
1557
2170
  title: t.close,
1558
2171
  "aria-label": t.close,
1559
2172
  onClick: onClose,
1560
2173
  children: /* @__PURE__ */ jsx(XIcon, { size: 16 })
1561
2174
  }
1562
2175
  ),
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 })
2176
+ /* @__PURE__ */ jsxs("div", { className: styles$8.head, children: [
2177
+ /* @__PURE__ */ jsx("span", { className: styles$8.colFormat, children: t.colFormat }),
2178
+ /* @__PURE__ */ jsx("span", { className: styles$8.colShortcut, children: t.colShortcut }),
2179
+ /* @__PURE__ */ jsx("span", { className: styles$8.colMarkdown, children: t.colMarkdown })
1567
2180
  ] }),
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: "—" }) })
2181
+ /* @__PURE__ */ jsx("div", { className: styles$8.body, children: groups.map((group2) => /* @__PURE__ */ jsxs("section", { className: styles$8.group, children: [
2182
+ /* @__PURE__ */ jsx("h3", { className: styles$8.groupTitle, children: group2.title }),
2183
+ group2.entries.map((entry) => /* @__PURE__ */ jsxs("div", { className: styles$8.row, children: [
2184
+ /* @__PURE__ */ jsx("span", { className: styles$8.rowLabel, children: entry.label }),
2185
+ /* @__PURE__ */ jsx("span", { className: styles$8.rowKeys, children: entry.keys ? entry.keys.map((key, i) => /* @__PURE__ */ jsx("kbd", { className: styles$8.keycap, children: keycapText(key, mac) }, i)) : /* @__PURE__ */ jsx("span", { className: styles$8.none, children: "—" }) }),
2186
+ /* @__PURE__ */ jsx("span", { className: styles$8.rowMd, children: entry.markdown ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
2187
+ /* @__PURE__ */ jsx("kbd", { className: styles$8.keycap, children: entry.markdown.marker }),
2188
+ entry.markdown.terminator ? /* @__PURE__ */ jsx("kbd", { className: styles$8.keycap, children: entry.markdown.terminator }) : null
2189
+ ] }) : /* @__PURE__ */ jsx("span", { className: styles$8.none, children: "—" }) })
1577
2190
  ] }, entry.id))
1578
2191
  ] }, group2.id)) })
1579
2192
  ]
@@ -1690,18 +2303,18 @@ function selectionKind(selection) {
1690
2303
  if (selection instanceof TextSelection) return "text";
1691
2304
  return "text";
1692
2305
  }
1693
- function looksLikeMarkdown(text) {
1694
- return /^#{1,6}\s/m.test(text) || // 标题
1695
- /\*\*[^*\n]+\*\*/.test(text) || // 加粗
1696
- /(^|[^!])\[[^\]\n]+\]\([^)\n]+\)/.test(text) || // 链接
1697
- /!\[[^\]\n]*\]\([^)\n]+\)/.test(text) || // 图片
1698
- /^[-*+]\s+\S/m.test(text) || // 无序列表
1699
- /^\d+\.\s+\S/m.test(text) || // 有序列表
1700
- /^>\s/m.test(text) || // 引用
1701
- /^```/m.test(text) || // 代码围栏
1702
- /^\|.+\|\s*$/m.test(text) || // 表格行
1703
- /^(-{3,}|\*{3,})\s*$/m.test(text) || // 分割线
1704
- /<!--\s*[\[{][\s\S]*?"chartType"[\s\S]*?-->/.test(text);
2306
+ function looksLikeMarkdown(text2) {
2307
+ return /^#{1,6}\s/m.test(text2) || // 标题
2308
+ /\*\*[^*\n]+\*\*/.test(text2) || // 加粗
2309
+ /(^|[^!])\[[^\]\n]+\]\([^)\n]+\)/.test(text2) || // 链接
2310
+ /!\[[^\]\n]*\]\([^)\n]+\)/.test(text2) || // 图片
2311
+ /^[-*+]\s+\S/m.test(text2) || // 无序列表
2312
+ /^\d+\.\s+\S/m.test(text2) || // 有序列表
2313
+ /^>\s/m.test(text2) || // 引用
2314
+ /^```/m.test(text2) || // 代码围栏
2315
+ /^\|.+\|\s*$/m.test(text2) || // 表格行
2316
+ /^(-{3,}|\*{3,})\s*$/m.test(text2) || // 分割线
2317
+ /<!--\s*[\[{][\s\S]*?"chartType"[\s\S]*?-->/.test(text2);
1705
2318
  }
1706
2319
  const MarkdownPaste = Extension.create({
1707
2320
  name: "markdownPaste",
@@ -1714,16 +2327,16 @@ const MarkdownPaste = Extension.create({
1714
2327
  handlePaste(view, event) {
1715
2328
  const clipboard = event.clipboardData;
1716
2329
  if (!clipboard) return false;
1717
- const text = clipboard.getData("text/plain");
1718
- if (!text) return false;
2330
+ const text2 = clipboard.getData("text/plain");
2331
+ if (!text2) return false;
1719
2332
  const input2 = view.input;
1720
2333
  if (input2 == null ? void 0 : input2.shiftKey) return false;
1721
2334
  if (view.state.selection.$from.parent.type.spec.code) return false;
1722
- if (!looksLikeMarkdown(text)) return false;
2335
+ if (!looksLikeMarkdown(text2)) return false;
1723
2336
  const markdown = editor.markdown;
1724
2337
  if (!markdown) return false;
1725
2338
  try {
1726
- const json = markdown.parse(prepareChartMarkdown(text));
2339
+ const json = markdown.parse(prepareChartMarkdown(text2));
1727
2340
  editor.commands.insertContent(json);
1728
2341
  return true;
1729
2342
  } catch (err) {
@@ -1877,7 +2490,7 @@ const gutterLine = "_gutterLine_k8th1_184";
1877
2490
  const readonlyActions = "_readonlyActions_k8th1_188";
1878
2491
  const actionBtn = "_actionBtn_k8th1_194";
1879
2492
  const langBraces = "_langBraces_k8th1_213";
1880
- const styles$6 = {
2493
+ const styles$7 = {
1881
2494
  wrapper,
1882
2495
  header: header$1,
1883
2496
  langTrigger,
@@ -1955,18 +2568,18 @@ function CodeBlockView({
1955
2568
  }, [readonly2]);
1956
2569
  const handleCopy = () => {
1957
2570
  var _a2;
1958
- const text = node.textContent ?? "";
2571
+ const text2 = node.textContent ?? "";
1959
2572
  const done = () => {
1960
2573
  setCopied(true);
1961
2574
  window.setTimeout(() => setCopied(false), 1500);
1962
2575
  };
1963
2576
  if ((_a2 = navigator.clipboard) == null ? void 0 : _a2.writeText) {
1964
- navigator.clipboard.writeText(text).then(done, () => {
2577
+ navigator.clipboard.writeText(text2).then(done, () => {
1965
2578
  });
1966
2579
  return;
1967
2580
  }
1968
2581
  const ta = document.createElement("textarea");
1969
- ta.value = text;
2582
+ ta.value = text2;
1970
2583
  document.body.appendChild(ta);
1971
2584
  ta.select();
1972
2585
  try {
@@ -1977,29 +2590,29 @@ function CodeBlockView({
1977
2590
  ta.remove();
1978
2591
  };
1979
2592
  const wrapperClass = [
1980
- styles$6.wrapper,
1981
- readonly2 ? styles$6.readonly : "",
1982
- folded2 ? styles$6.folded : ""
2593
+ styles$7.wrapper,
2594
+ readonly2 ? styles$7.readonly : "",
2595
+ folded2 ? styles$7.folded : ""
1983
2596
  ].filter(Boolean).join(" ");
1984
2597
  return /* @__PURE__ */ jsxs(NodeViewWrapper, { className: wrapperClass, children: [
1985
- editable ? /* @__PURE__ */ jsxs("div", { className: styles$6.header, contentEditable: false, children: [
2598
+ editable ? /* @__PURE__ */ jsxs("div", { className: styles$7.header, contentEditable: false, children: [
1986
2599
  /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
1987
2600
  /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1988
2601
  "button",
1989
2602
  {
1990
2603
  type: "button",
1991
- className: styles$6.langTrigger,
2604
+ className: styles$7.langTrigger,
1992
2605
  "aria-label": "Code language",
1993
2606
  children: [
1994
2607
  /* @__PURE__ */ jsx("span", { children: currentLabel }),
1995
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$6.langChevron })
2608
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$7.langChevron })
1996
2609
  ]
1997
2610
  }
1998
2611
  ) }),
1999
2612
  /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
2000
2613
  DropdownMenu.Content,
2001
2614
  {
2002
- className: styles$6.langMenu,
2615
+ className: styles$7.langMenu,
2003
2616
  sideOffset: 4,
2004
2617
  align: "end",
2005
2618
  children: LANGUAGES.map((l) => {
@@ -2008,10 +2621,10 @@ function CodeBlockView({
2008
2621
  return /* @__PURE__ */ jsxs(
2009
2622
  DropdownMenu.Item,
2010
2623
  {
2011
- className: `${styles$6.langItem}${selected ? ` ${styles$6.langItemSelected}` : ""}`,
2624
+ className: `${styles$7.langItem}${selected ? ` ${styles$7.langItemSelected}` : ""}`,
2012
2625
  onSelect: () => updateAttributes({ language: l.value }),
2013
2626
  children: [
2014
- /* @__PURE__ */ jsx("span", { className: styles$6.langItemCheck, children: selected ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : null }),
2627
+ /* @__PURE__ */ jsx("span", { className: styles$7.langItemCheck, children: selected ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : null }),
2015
2628
  optionLabel
2016
2629
  ]
2017
2630
  },
@@ -2025,7 +2638,7 @@ function CodeBlockView({
2025
2638
  "button",
2026
2639
  {
2027
2640
  type: "button",
2028
- className: styles$6.deleteBtn,
2641
+ className: styles$7.deleteBtn,
2029
2642
  title: labels.delete,
2030
2643
  "aria-label": labels.delete,
2031
2644
  onClick: () => deleteNode(),
@@ -2034,17 +2647,17 @@ function CodeBlockView({
2034
2647
  )
2035
2648
  ] }) : (
2036
2649
  // 只读头部:左侧语言标签,右侧复制 + 展开收起(展开后按钮保留,供收回)
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: "{}" }),
2650
+ /* @__PURE__ */ jsxs("div", { className: styles$7.readonlyHeader, contentEditable: false, children: [
2651
+ /* @__PURE__ */ jsxs("span", { className: styles$7.langBadge, children: [
2652
+ /* @__PURE__ */ jsx("span", { className: styles$7.langBraces, children: "{}" }),
2040
2653
  currentLabel
2041
2654
  ] }),
2042
- /* @__PURE__ */ jsxs("span", { className: styles$6.readonlyActions, children: [
2655
+ /* @__PURE__ */ jsxs("span", { className: styles$7.readonlyActions, children: [
2043
2656
  /* @__PURE__ */ jsx(
2044
2657
  "button",
2045
2658
  {
2046
2659
  type: "button",
2047
- className: styles$6.actionBtn,
2660
+ className: styles$7.actionBtn,
2048
2661
  onClick: handleCopy,
2049
2662
  "aria-label": labels.copy,
2050
2663
  title: labels.copy,
@@ -2055,7 +2668,7 @@ function CodeBlockView({
2055
2668
  "button",
2056
2669
  {
2057
2670
  type: "button",
2058
- className: styles$6.actionBtn,
2671
+ className: styles$7.actionBtn,
2059
2672
  onClick: () => setFolded((v) => !v),
2060
2673
  "aria-label": folded2 ? labels.expand : labels.collapse,
2061
2674
  title: folded2 ? labels.expand : labels.collapse,
@@ -2066,14 +2679,14 @@ function CodeBlockView({
2066
2679
  ] })
2067
2680
  ] })
2068
2681
  ),
2069
- /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$6.pre, children: [
2682
+ /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$7.pre, children: [
2070
2683
  readonly2 ? /* @__PURE__ */ jsx(
2071
2684
  "span",
2072
2685
  {
2073
- className: styles$6.gutter,
2686
+ className: styles$7.gutter,
2074
2687
  contentEditable: false,
2075
2688
  "aria-hidden": "true",
2076
- children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$6.gutterLine, children: i + 1 }, i))
2689
+ children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$7.gutterLine, children: i + 1 }, i))
2077
2690
  }
2078
2691
  ) : null,
2079
2692
  /* @__PURE__ */ jsx(NodeViewContent, { as: "code" })
@@ -2118,6 +2731,34 @@ const CodeBlock = CodeBlockLowlight.extend({
2118
2731
  }
2119
2732
  });
2120
2733
  const ImageWithConfirmDelete = Image.extend({
2734
+ addAttributes() {
2735
+ var _a;
2736
+ return {
2737
+ ...((_a = Image.config.addAttributes) == null ? void 0 : _a.call(this)) ?? {},
2738
+ align: imageAlignAttribute,
2739
+ caption: imageCaptionAttribute
2740
+ };
2741
+ },
2742
+ parseHTML() {
2743
+ return [
2744
+ imageFigureParseRule(),
2745
+ {
2746
+ tag: this.options.allowBase64 ? "img[src]" : 'img[src]:not([src^="data:"])'
2747
+ }
2748
+ ];
2749
+ },
2750
+ renderHTML({ node, HTMLAttributes }) {
2751
+ return imageNodeHtml({
2752
+ attrs: node.attrs,
2753
+ htmlAttributes: mergeAttributes(
2754
+ this.options.HTMLAttributes,
2755
+ HTMLAttributes
2756
+ )
2757
+ });
2758
+ },
2759
+ renderMarkdown: imageRenderMarkdown,
2760
+ parseMarkdown: imageParseMarkdown,
2761
+ markdownTokenizer: imageMarkdownTokenizer,
2121
2762
  addKeyboardShortcuts() {
2122
2763
  return {
2123
2764
  Backspace: () => {
@@ -2133,7 +2774,74 @@ const ImageWithConfirmDelete = Image.extend({
2133
2774
  }
2134
2775
  }
2135
2776
  return false;
2777
+ },
2778
+ // 图片对齐:键位对齐官方 image-align-button(L 左 / E 中 / R 右),
2779
+ // 选中图片或光标紧邻图片时生效。工具函数见 imageAlign.ts。
2780
+ "Alt-Shift-l": () => setImageAlign(this.editor, "left"),
2781
+ "Alt-Shift-e": () => setImageAlign(this.editor, "center"),
2782
+ "Alt-Shift-r": () => setImageAlign(this.editor, "right")
2783
+ };
2784
+ },
2785
+ addNodeView() {
2786
+ var _a;
2787
+ const createView = (_a = Image.config.addNodeView) == null ? void 0 : _a.call(this);
2788
+ if (!createView) return null;
2789
+ const resizeOptions = this.options.resize;
2790
+ const explicitMaxWidth = resizeOptions && typeof resizeOptions === "object" ? resizeOptions.maxWidth : void 0;
2791
+ const explicitMaxHeight = resizeOptions && typeof resizeOptions === "object" ? resizeOptions.maxHeight : void 0;
2792
+ return (props) => {
2793
+ var _a2, _b;
2794
+ const nodeView = createView(props);
2795
+ if (!nodeView) return nodeView;
2796
+ const resizable = nodeView;
2797
+ if (!props.editor.isEditable) (_a2 = resizable.removeHandles) == null ? void 0 : _a2.call(resizable);
2798
+ const applyMaxSize = () => {
2799
+ resizable.maxSize = explicitMaxWidth || explicitMaxHeight ? { width: explicitMaxWidth, height: explicitMaxHeight } : { width: props.editor.view.dom.clientWidth || void 0 };
2800
+ };
2801
+ if (explicitMaxWidth || explicitMaxHeight) applyMaxSize();
2802
+ let syncCaption = null;
2803
+ if (nodeView.dom instanceof HTMLElement && resizable.element) {
2804
+ const { element } = resizable;
2805
+ const container = nodeView.dom;
2806
+ const captionEl = document.createElement("div");
2807
+ captionEl.className = "tmr-image-caption";
2808
+ captionEl.dataset.imageCaption = "";
2809
+ (element.parentElement ?? container).appendChild(captionEl);
2810
+ const syncHandleTop = () => {
2811
+ const height = element.offsetHeight;
2812
+ if (height > 0) {
2813
+ container.style.setProperty("--tmr-image-h", `${height}px`);
2814
+ } else {
2815
+ container.style.removeProperty("--tmr-image-h");
2816
+ }
2817
+ };
2818
+ syncCaption = (attrs) => {
2819
+ const caption = normalizeImageCaption(attrs.caption) ?? "";
2820
+ captionEl.textContent = caption;
2821
+ captionEl.hidden = caption === "";
2822
+ syncHandleTop();
2823
+ };
2824
+ syncCaption(props.node.attrs);
2825
+ element.addEventListener("load", syncHandleTop);
2826
+ container.addEventListener("mousedown", applyMaxSize, true);
2136
2827
  }
2828
+ if (resizable.element) {
2829
+ const { element } = resizable;
2830
+ const originalUpdate = (_b = nodeView.update) == null ? void 0 : _b.bind(nodeView);
2831
+ if (originalUpdate) {
2832
+ nodeView.update = (...args) => {
2833
+ const ok = originalUpdate(...args);
2834
+ if (ok) {
2835
+ const attrs = args[0].attrs;
2836
+ element.style.width = attrs.width ? `${attrs.width}px` : "";
2837
+ element.style.height = attrs.height ? `${attrs.height}px` : "";
2838
+ syncCaption == null ? void 0 : syncCaption(attrs);
2839
+ }
2840
+ return ok;
2841
+ };
2842
+ }
2843
+ }
2844
+ return nodeView;
2137
2845
  };
2138
2846
  }
2139
2847
  });
@@ -2188,7 +2896,9 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2188
2896
  slashMenuLabels,
2189
2897
  shortcutPanel = true,
2190
2898
  shortcutLabels,
2191
- shortcutFabContainer
2899
+ shortcutFabContainer,
2900
+ imageUpload,
2901
+ imageResize = true
2192
2902
  }, ref) {
2193
2903
  const preparedInitial = prepareChartMarkdown(
2194
2904
  enrichMarkdownCitations(initialMarkdown, sources ?? [])
@@ -2200,7 +2910,24 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2200
2910
  extensions: [
2201
2911
  ...baseExtensions,
2202
2912
  CodeBlock.configure({ lowlight, codeBlockLabels }),
2203
- ImageWithConfirmDelete.configure({ inline: false }),
2913
+ ImageWithConfirmDelete.configure({
2914
+ inline: false,
2915
+ // 图片缩放(默认开、默认等比、默认左右两条手柄):false 关掉;对象透传官方配置
2916
+ // ——等比与手柄方向都有本库默认,显式传值可覆盖。
2917
+ resize: imageResize === false ? false : {
2918
+ enabled: true,
2919
+ alwaysPreserveAspectRatio: true,
2920
+ directions: ["left", "right"],
2921
+ // 默认下限。上限默认跟随内容区宽度(maxWidth/maxHeight 由 addNodeView
2922
+ // 包装读取并注入 maxSize,见 ImageWithConfirmDelete)。
2923
+ minWidth: 80,
2924
+ minHeight: 80,
2925
+ ...typeof imageResize === "object" ? imageResize : null
2926
+ }
2927
+ }),
2928
+ // 图片上传占位块:空态拖拽 / 点选 → 进度就地 → 成功原地换成 image。
2929
+ // 不配置 imageUpload 就不注册(工具栏退回旧的直传路径)。
2930
+ ...imageUpload ? [ImageUploadNode.configure(imageUpload)] : [],
2204
2931
  ImportPlaceholder,
2205
2932
  // 空文档占位符:官方 Placeholder 把 data-placeholder 属性与
2206
2933
  // is-empty / is-editor-empty 类打在**空文本块节点**上——CSS
@@ -2244,7 +2971,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2244
2971
  immediatelyRender: false,
2245
2972
  editorProps: {
2246
2973
  attributes: {
2247
- class: styles$a.editorContent
2974
+ class: styles$c.editorContent
2248
2975
  }
2249
2976
  }
2250
2977
  });
@@ -2443,7 +3170,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2443
3170
  labels: findLabels,
2444
3171
  onClose: closeFind,
2445
3172
  inputRef: findInputRef,
2446
- className: styles$a.findBar,
3173
+ className: styles$c.findBar,
2447
3174
  style: findBarOffsetStyle(findBarOffset)
2448
3175
  }
2449
3176
  ) : null;
@@ -2463,7 +3190,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2463
3190
  "button",
2464
3191
  {
2465
3192
  type: "button",
2466
- className: shortcutFabTarget ? `${styles$a.shortcutFab} ${styles$a.shortcutFabHosted}` : styles$a.shortcutFab,
3193
+ className: shortcutFabTarget ? `${styles$c.shortcutFab} ${styles$c.shortcutFabHosted}` : styles$c.shortcutFab,
2467
3194
  title: shortcutT.panelTitle,
2468
3195
  "aria-label": shortcutT.panelTitle,
2469
3196
  "aria-expanded": shortcutsOpen,
@@ -2471,14 +3198,14 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2471
3198
  children: /* @__PURE__ */ jsx(KeyboardIcon, { size: 18 })
2472
3199
  }
2473
3200
  ) : null;
2474
- return /* @__PURE__ */ jsxs("div", { className: styles$a.editorHost, children: [
2475
- findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$a.findBarAnchor, children: findBarNode }) : null,
3201
+ return /* @__PURE__ */ jsxs("div", { className: styles$c.editorHost, children: [
3202
+ findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$c.findBarAnchor, children: findBarNode }) : null,
2476
3203
  findBarNode && findBarTarget ? createPortal(findBarNode, findBarTarget) : null,
2477
3204
  /* @__PURE__ */ jsx(
2478
3205
  EditorContent,
2479
3206
  {
2480
3207
  editor,
2481
- className: className ? `${styles$a.editorScroll} ${className}` : styles$a.editorScroll
3208
+ className: className ? `${styles$c.editorScroll} ${className}` : styles$c.editorScroll
2482
3209
  }
2483
3210
  ),
2484
3211
  shortcutFabNode && shortcutFabTarget ? createPortal(shortcutFabNode, shortcutFabTarget) : shortcutFabNode,
@@ -2531,7 +3258,7 @@ function MarkdownPreview({
2531
3258
  editable: false,
2532
3259
  immediatelyRender: false,
2533
3260
  editorProps: {
2534
- attributes: { class: styles$a.editorContent }
3261
+ attributes: { class: styles$c.editorContent }
2535
3262
  }
2536
3263
  },
2537
3264
  [extensions]
@@ -2544,7 +3271,7 @@ function MarkdownPreview({
2544
3271
  EditorContent,
2545
3272
  {
2546
3273
  editor,
2547
- className: className ?? styles$a.editorScroll
3274
+ className: className ?? styles$c.editorScroll
2548
3275
  }
2549
3276
  );
2550
3277
  }
@@ -2592,11 +3319,11 @@ function tryInsertMarkdown(editor, markdown) {
2592
3319
  return false;
2593
3320
  }
2594
3321
  }
2595
- function insertPlainParagraph(editor, text) {
2596
- if (!text) return;
3322
+ function insertPlainParagraph(editor, text2) {
3323
+ if (!text2) return;
2597
3324
  editor.chain().focus().insertContent({
2598
3325
  type: "paragraph",
2599
- content: [{ type: "text", text }]
3326
+ content: [{ type: "text", text: text2 }]
2600
3327
  }).run();
2601
3328
  }
2602
3329
  function splitTopLevelBlocks(markdown) {
@@ -2616,59 +3343,61 @@ function splitTopLevelBlocks(markdown) {
2616
3343
  function stripToPlainText(markdown) {
2617
3344
  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();
2618
3345
  }
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 = {
3346
+ const toolbar = "_toolbar_vghdk_2";
3347
+ const inner = "_inner_vghdk_15";
3348
+ const btn$2 = "_btn_vghdk_35";
3349
+ const btnActive$1 = "_btnActive_vghdk_58";
3350
+ const txtIcon = "_txtIcon_vghdk_74";
3351
+ const colorIcon = "_colorIcon_vghdk_82";
3352
+ const colorIconGlyph = "_colorIconGlyph_vghdk_90";
3353
+ const colorIconBar = "_colorIconBar_vghdk_96";
3354
+ const scriptTrigger = "_scriptTrigger_vghdk_103";
3355
+ const scriptTriggerGlyph = "_scriptTriggerGlyph_vghdk_123";
3356
+ const divider$2 = "_divider_vghdk_131";
3357
+ const styleTrigger = "_styleTrigger_vghdk_140";
3358
+ const styleTriggerLabel = "_styleTriggerLabel_vghdk_169";
3359
+ const styleTriggerCaret = "_styleTriggerCaret_vghdk_177";
3360
+ const iconTrigger = "_iconTrigger_vghdk_184";
3361
+ const styleItem = "_styleItem_vghdk_192";
3362
+ const styleIcon = "_styleIcon_vghdk_198";
3363
+ const scriptGlyph = "_scriptGlyph_vghdk_208";
3364
+ const menu = "_menu_vghdk_220";
3365
+ const menuItem = "_menuItem_vghdk_231";
3366
+ const menuItemSelected = "_menuItemSelected_vghdk_258";
3367
+ const tableInsertCaret = "_tableInsertCaret_vghdk_271";
3368
+ const tableSizePicker = "_tableSizePicker_vghdk_279";
3369
+ const tableSizeGrid = "_tableSizeGrid_vghdk_289";
3370
+ const tableSizeCell = "_tableSizeCell_vghdk_294";
3371
+ const tableSizeCellActive = "_tableSizeCellActive_vghdk_304";
3372
+ const tableSizeLabel = "_tableSizeLabel_vghdk_309";
3373
+ const popoverContent$1 = "_popoverContent_vghdk_318";
3374
+ const mathLayer = "_mathLayer_vghdk_322";
3375
+ const mathStack = "_mathStack_vghdk_327";
3376
+ const mathStackBlock = "_mathStackBlock_vghdk_334";
3377
+ const mathHint = "_mathHint_vghdk_339";
3378
+ const mathHintBlock = "_mathHintBlock_vghdk_351";
3379
+ const mathHintIcon = "_mathHintIcon_vghdk_357";
3380
+ const mathField = "_mathField_vghdk_388";
3381
+ const mathFieldBlock = "_mathFieldBlock_vghdk_400";
3382
+ const mathInput = "_mathInput_vghdk_407";
3383
+ const mathDone = "_mathDone_vghdk_425";
3384
+ const mathDoneKbd = "_mathDoneKbd_vghdk_450";
3385
+ const styles$6 = {
2658
3386
  toolbar,
2659
3387
  inner,
2660
- btn: btn$1,
2661
- btnActive,
3388
+ btn: btn$2,
3389
+ btnActive: btnActive$1,
2662
3390
  txtIcon,
2663
3391
  colorIcon,
2664
3392
  colorIconGlyph,
2665
3393
  colorIconBar,
2666
3394
  scriptTrigger,
2667
3395
  scriptTriggerGlyph,
2668
- divider: divider$1,
3396
+ divider: divider$2,
2669
3397
  styleTrigger,
2670
3398
  styleTriggerLabel,
2671
3399
  styleTriggerCaret,
3400
+ iconTrigger,
2672
3401
  styleItem,
2673
3402
  styleIcon,
2674
3403
  scriptGlyph,
@@ -2703,7 +3432,7 @@ const swatch = "_swatch_x5lrq_54";
2703
3432
  const swatchActive = "_swatchActive_x5lrq_70";
2704
3433
  const themeLabel = "_themeLabel_x5lrq_76";
2705
3434
  const themeRow = "_themeRow_x5lrq_84";
2706
- const styles$4 = {
3435
+ const styles$5 = {
2707
3436
  palette,
2708
3437
  noneRow,
2709
3438
  noneIcon,
@@ -2726,25 +3455,25 @@ const THEME_COLORS = ["#ff6719", "#ff5500"];
2726
3455
  function ColorPalette({ value, onPick, labels }) {
2727
3456
  const t = { ...defaultColorPaletteLabels, ...labels };
2728
3457
  const current = value == null ? void 0 : value.toLowerCase();
2729
- return /* @__PURE__ */ jsxs("div", { className: styles$4.palette, children: [
3458
+ return /* @__PURE__ */ jsxs("div", { className: styles$5.palette, children: [
2730
3459
  /* @__PURE__ */ jsxs(
2731
3460
  "button",
2732
3461
  {
2733
3462
  type: "button",
2734
- className: styles$4.noneRow,
3463
+ className: styles$5.noneRow,
2735
3464
  onMouseDown: (e2) => e2.preventDefault(),
2736
3465
  onClick: () => onPick(null),
2737
3466
  children: [
2738
- /* @__PURE__ */ jsx("span", { className: styles$4.noneIcon, "aria-hidden": true }),
2739
- /* @__PURE__ */ jsx("span", { className: styles$4.noneLabel, children: t.none })
3467
+ /* @__PURE__ */ jsx("span", { className: styles$5.noneIcon, "aria-hidden": true }),
3468
+ /* @__PURE__ */ jsx("span", { className: styles$5.noneLabel, children: t.none })
2740
3469
  ]
2741
3470
  }
2742
3471
  ),
2743
- /* @__PURE__ */ jsx("div", { className: styles$4.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
3472
+ /* @__PURE__ */ jsx("div", { className: styles$5.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
2744
3473
  "button",
2745
3474
  {
2746
3475
  type: "button",
2747
- className: `${styles$4.swatch} ${current === c.toLowerCase() ? styles$4.swatchActive : ""}`,
3476
+ className: `${styles$5.swatch} ${current === c.toLowerCase() ? styles$5.swatchActive : ""}`,
2748
3477
  style: { background: c },
2749
3478
  title: c,
2750
3479
  "aria-label": c,
@@ -2753,12 +3482,12 @@ function ColorPalette({ value, onPick, labels }) {
2753
3482
  },
2754
3483
  c
2755
3484
  )) }),
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(
3485
+ /* @__PURE__ */ jsx("div", { className: styles$5.themeLabel, children: t.theme }),
3486
+ /* @__PURE__ */ jsx("div", { className: styles$5.themeRow, children: THEME_COLORS.map((c) => /* @__PURE__ */ jsx(
2758
3487
  "button",
2759
3488
  {
2760
3489
  type: "button",
2761
- className: `${styles$4.swatch} ${current === c.toLowerCase() ? styles$4.swatchActive : ""}`,
3490
+ className: `${styles$5.swatch} ${current === c.toLowerCase() ? styles$5.swatchActive : ""}`,
2762
3491
  style: { background: c },
2763
3492
  title: c,
2764
3493
  "aria-label": c,
@@ -2769,6 +3498,235 @@ function ColorPalette({ value, onPick, labels }) {
2769
3498
  )) })
2770
3499
  ] });
2771
3500
  }
3501
+ function setImageCaptionAtPos(editor, pos, caption) {
3502
+ const node = editor.state.doc.nodeAt(pos);
3503
+ if (!node || node.type.name !== "image") return false;
3504
+ const next = normalizeImageCaption(caption);
3505
+ const current = normalizeImageCaption(node.attrs.caption);
3506
+ if (current === next) return true;
3507
+ editor.view.dispatch(editor.state.tr.setNodeAttribute(pos, "caption", next));
3508
+ return true;
3509
+ }
3510
+ function setImageCaption(editor, caption) {
3511
+ const pos = findImagePos(editor);
3512
+ if (pos == null) return false;
3513
+ return setImageCaptionAtPos(editor, pos, caption);
3514
+ }
3515
+ const bar = "_bar_mp2o5_7";
3516
+ const divider$1 = "_divider_mp2o5_24";
3517
+ const captionRow = "_captionRow_mp2o5_13";
3518
+ const captionInput = "_captionInput_mp2o5_40";
3519
+ const btn$1 = "_btn_mp2o5_58";
3520
+ const btnActive = "_btnActive_mp2o5_76";
3521
+ const styles$4 = {
3522
+ bar,
3523
+ divider: divider$1,
3524
+ captionRow,
3525
+ captionInput,
3526
+ btn: btn$1,
3527
+ btnActive
3528
+ };
3529
+ const TOOLBAR_HEIGHT = 34;
3530
+ const TOOLBAR_GAP = 8;
3531
+ const HOVER_KEEP_MS$1 = 160;
3532
+ const ALIGNS = ["left", "center", "right"];
3533
+ const ICONS = {
3534
+ left: AlignLeftIcon,
3535
+ center: AlignCenterIcon,
3536
+ right: AlignRightIcon
3537
+ };
3538
+ function measureImage(editor, img) {
3539
+ if (!img.isConnected) return null;
3540
+ let pos;
3541
+ try {
3542
+ pos = editor.view.posAtDOM(img, 0);
3543
+ } catch {
3544
+ return null;
3545
+ }
3546
+ const node = editor.state.doc.nodeAt(pos);
3547
+ if (!node || node.type.name !== "image") return null;
3548
+ const rect = img.getBoundingClientRect();
3549
+ return {
3550
+ pos,
3551
+ img,
3552
+ left: rect.left,
3553
+ top: rect.top,
3554
+ right: rect.right,
3555
+ bottom: rect.bottom
3556
+ };
3557
+ }
3558
+ function ImageAlignTools({ editor, labels }) {
3559
+ var _a;
3560
+ const [hover, setHover] = useState(null);
3561
+ const hoverRef = useRef(null);
3562
+ const [captionDraft, setCaptionDraft] = useState(null);
3563
+ const captionDraftRef = useRef(null);
3564
+ captionDraftRef.current = captionDraft;
3565
+ const clearHover = useCallback(() => {
3566
+ if (!hoverRef.current) return;
3567
+ hoverRef.current = null;
3568
+ setHover(null);
3569
+ setCaptionDraft(null);
3570
+ }, []);
3571
+ const remeasureHover = useCallback(() => {
3572
+ const current = hoverRef.current;
3573
+ if (!current) return;
3574
+ const el = editor.view.nodeDOM(current.pos);
3575
+ const img = el instanceof HTMLImageElement ? el : el instanceof HTMLElement ? el.querySelector("img") : null;
3576
+ const next = img ? measureImage(editor, img) : null;
3577
+ hoverRef.current = next;
3578
+ setHover(next);
3579
+ }, [editor]);
3580
+ const clearTimerRef = useRef(null);
3581
+ const cancelPendingClear = useCallback(() => {
3582
+ if (clearTimerRef.current === null) return;
3583
+ clearTimeout(clearTimerRef.current);
3584
+ clearTimerRef.current = null;
3585
+ }, []);
3586
+ useEffect(() => {
3587
+ const onMove = (event) => {
3588
+ var _a2, _b;
3589
+ if (!editor.isEditable) return;
3590
+ const target = event.target;
3591
+ if ((_a2 = target == null ? void 0 : target.closest) == null ? void 0 : _a2.call(target, "[data-image-align]")) {
3592
+ cancelPendingClear();
3593
+ return;
3594
+ }
3595
+ const img = target && editor.view.dom.contains(target) ? target.closest("img") : null;
3596
+ if (!img) {
3597
+ if (captionDraftRef.current !== null) return;
3598
+ if (hoverRef.current && clearTimerRef.current === null) {
3599
+ clearTimerRef.current = setTimeout(() => {
3600
+ clearTimerRef.current = null;
3601
+ clearHover();
3602
+ }, HOVER_KEEP_MS$1);
3603
+ }
3604
+ return;
3605
+ }
3606
+ cancelPendingClear();
3607
+ if (((_b = hoverRef.current) == null ? void 0 : _b.img) === img) return;
3608
+ const next = measureImage(editor, img);
3609
+ hoverRef.current = next;
3610
+ setHover(next);
3611
+ };
3612
+ const onBlurWindow = () => {
3613
+ cancelPendingClear();
3614
+ clearHover();
3615
+ };
3616
+ document.addEventListener("mousemove", onMove);
3617
+ document.addEventListener("mouseleave", onBlurWindow);
3618
+ window.addEventListener("scroll", remeasureHover, true);
3619
+ window.addEventListener("resize", remeasureHover);
3620
+ return () => {
3621
+ cancelPendingClear();
3622
+ document.removeEventListener("mousemove", onMove);
3623
+ document.removeEventListener("mouseleave", onBlurWindow);
3624
+ window.removeEventListener("scroll", remeasureHover, true);
3625
+ window.removeEventListener("resize", remeasureHover);
3626
+ };
3627
+ }, [editor, clearHover, cancelPendingClear, remeasureHover]);
3628
+ useEffect(() => {
3629
+ const onUpdate = () => remeasureHover();
3630
+ editor.on("update", onUpdate);
3631
+ return () => {
3632
+ editor.off("update", onUpdate);
3633
+ };
3634
+ }, [editor, remeasureHover]);
3635
+ if (typeof document === "undefined") return null;
3636
+ if (!hover || !editor.isEditable) return null;
3637
+ const above = hover.top - TOOLBAR_HEIGHT - TOOLBAR_GAP >= 8;
3638
+ const nodeAttrs = (_a = editor.state.doc.nodeAt(hover.pos)) == null ? void 0 : _a.attrs;
3639
+ const active2 = normalizeImageAlign(nodeAttrs == null ? void 0 : nodeAttrs.align);
3640
+ const caption = normalizeImageCaption(nodeAttrs == null ? void 0 : nodeAttrs.caption);
3641
+ const labelOf = {
3642
+ left: labels.imageAlignLeft,
3643
+ center: labels.imageAlignCenter,
3644
+ right: labels.imageAlignRight
3645
+ };
3646
+ const commitCaption = () => {
3647
+ if (captionDraft === null) return;
3648
+ setImageCaptionAtPos(editor, hover.pos, captionDraft);
3649
+ setCaptionDraft(null);
3650
+ remeasureHover();
3651
+ };
3652
+ return createPortal(
3653
+ /* @__PURE__ */ jsxs(
3654
+ "div",
3655
+ {
3656
+ "data-image-align": "",
3657
+ className: styles$4.bar,
3658
+ role: "toolbar",
3659
+ "aria-label": labels.imageAlign,
3660
+ style: {
3661
+ left: hover.left,
3662
+ top: above ? hover.top - TOOLBAR_HEIGHT - TOOLBAR_GAP : hover.bottom + TOOLBAR_GAP
3663
+ },
3664
+ onMouseDown: (e2) => {
3665
+ var _a2, _b;
3666
+ if ((_b = (_a2 = e2.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b.call(_a2, "input")) return;
3667
+ e2.preventDefault();
3668
+ },
3669
+ children: [
3670
+ ALIGNS.map((align) => {
3671
+ const Icon = ICONS[align];
3672
+ return /* @__PURE__ */ jsx(
3673
+ "button",
3674
+ {
3675
+ type: "button",
3676
+ "data-image-align-action": align,
3677
+ className: `${styles$4.btn} ${active2 === align ? styles$4.btnActive : ""}`,
3678
+ title: labelOf[align],
3679
+ "aria-label": labelOf[align],
3680
+ "aria-pressed": active2 === align,
3681
+ onClick: () => {
3682
+ setImageAlignAtPos(editor, hover.pos, align);
3683
+ remeasureHover();
3684
+ },
3685
+ children: /* @__PURE__ */ jsx(Icon, { size: 14 })
3686
+ },
3687
+ align
3688
+ );
3689
+ }),
3690
+ /* @__PURE__ */ jsx("span", { className: styles$4.divider, "aria-hidden": true }),
3691
+ /* @__PURE__ */ jsx(
3692
+ "button",
3693
+ {
3694
+ type: "button",
3695
+ "data-image-align-action": "caption",
3696
+ className: `${styles$4.btn} ${caption ? styles$4.btnActive : ""}`,
3697
+ title: labels.imageCaption,
3698
+ "aria-label": labels.imageCaption,
3699
+ "aria-pressed": !!caption,
3700
+ onClick: () => {
3701
+ if (captionDraftRef.current !== null) return;
3702
+ setCaptionDraft(caption ?? "");
3703
+ },
3704
+ children: /* @__PURE__ */ jsx(CaptionsIcon, { size: 14 })
3705
+ }
3706
+ ),
3707
+ captionDraft !== null ? /* @__PURE__ */ jsx("div", { className: styles$4.captionRow, children: /* @__PURE__ */ jsx(
3708
+ "input",
3709
+ {
3710
+ className: styles$4.captionInput,
3711
+ value: captionDraft,
3712
+ placeholder: labels.imageCaptionPlaceholder,
3713
+ "aria-label": labels.imageCaptionPlaceholder,
3714
+ autoFocus: true,
3715
+ onChange: (e2) => setCaptionDraft(e2.target.value),
3716
+ onKeyDown: (e2) => {
3717
+ e2.stopPropagation();
3718
+ if (e2.key === "Enter") commitCaption();
3719
+ else if (e2.key === "Escape") setCaptionDraft(null);
3720
+ },
3721
+ onBlur: commitCaption
3722
+ }
3723
+ ) }) : null
3724
+ ]
3725
+ }
3726
+ ),
3727
+ document.body
3728
+ );
3729
+ }
2772
3730
  const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set([
2773
3731
  "http:",
2774
3732
  "https:",
@@ -2923,7 +3881,7 @@ function LinkPanel({
2923
3881
  const openInNewWindow = () => {
2924
3882
  openLinkUrl(normalizeLinkHref(editor, url), window.location.href);
2925
3883
  };
2926
- const remove = () => {
3884
+ const remove2 = () => {
2927
3885
  removeLink(editor);
2928
3886
  onClose();
2929
3887
  };
@@ -3004,7 +3962,7 @@ function LinkPanel({
3004
3962
  "aria-label": t.remove,
3005
3963
  disabled: !canEdit,
3006
3964
  onMouseDown: keepFocus,
3007
- onClick: remove,
3965
+ onClick: remove2,
3008
3966
  children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
3009
3967
  }
3010
3968
  )
@@ -3188,15 +4146,15 @@ function appendColumnToTable(editor) {
3188
4146
  selectLineAt(editor, table, "col", TableMap.get(table.node).width - 1);
3189
4147
  return addColumnsAfter(editor, 1);
3190
4148
  }
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";
4149
+ const handle = "_handle_qjreh_9";
4150
+ const handleRow = "_handleRow_qjreh_30";
4151
+ const handleCol = "_handleCol_qjreh_40";
4152
+ const extend = "_extend_qjreh_71";
4153
+ const tableBubble = "_tableBubble_qjreh_117";
4154
+ const tableMenuItem = "_tableMenuItem_qjreh_130";
4155
+ const tableMenuItemIcon = "_tableMenuItemIcon_qjreh_156";
4156
+ const tableMenuItemLabel = "_tableMenuItemLabel_qjreh_166";
4157
+ const tableMenuDivider = "_tableMenuDivider_qjreh_171";
3200
4158
  const styles$2 = {
3201
4159
  handle,
3202
4160
  handleRow,
@@ -3749,7 +4707,7 @@ function MathEditorPopover({
3749
4707
  "textarea",
3750
4708
  {
3751
4709
  ref: inputRef,
3752
- className: styles$5.mathInput,
4710
+ className: styles$6.mathInput,
3753
4711
  value: draft,
3754
4712
  placeholder,
3755
4713
  rows: Math.max(3, draft.split("\n").length),
@@ -3761,7 +4719,7 @@ function MathEditorPopover({
3761
4719
  "input",
3762
4720
  {
3763
4721
  ref: inputRef,
3764
- className: styles$5.mathInput,
4722
+ className: styles$6.mathInput,
3765
4723
  value: draft,
3766
4724
  placeholder,
3767
4725
  "aria-labelledby": titleId,
@@ -3775,7 +4733,7 @@ function MathEditorPopover({
3775
4733
  "div",
3776
4734
  {
3777
4735
  ref: rootRef,
3778
- className: styles$5.mathLayer,
4736
+ className: styles$6.mathLayer,
3779
4737
  style: layerStyle,
3780
4738
  role: "dialog",
3781
4739
  "aria-modal": "false",
@@ -3783,15 +4741,15 @@ function MathEditorPopover({
3783
4741
  children: /* @__PURE__ */ jsxs(
3784
4742
  "div",
3785
4743
  {
3786
- className: isBlock ? `${styles$5.mathStack} ${styles$5.mathStackBlock}` : styles$5.mathStack,
4744
+ className: isBlock ? `${styles$6.mathStack} ${styles$6.mathStackBlock}` : styles$6.mathStack,
3787
4745
  children: [
3788
4746
  showHint ? /* @__PURE__ */ jsxs(
3789
4747
  "div",
3790
4748
  {
3791
4749
  id: titleId,
3792
- className: isBlock ? `${styles$5.mathHint} ${styles$5.mathHintBlock}` : styles$5.mathHint,
4750
+ className: isBlock ? `${styles$6.mathHint} ${styles$6.mathHintBlock}` : styles$6.mathHint,
3793
4751
  children: [
3794
- /* @__PURE__ */ jsx("span", { className: styles$5.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
4752
+ /* @__PURE__ */ jsx("span", { className: styles$6.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
3795
4753
  newLabel
3796
4754
  ]
3797
4755
  }
@@ -3800,20 +4758,20 @@ function MathEditorPopover({
3800
4758
  "div",
3801
4759
  {
3802
4760
  id: showHint ? void 0 : titleId,
3803
- className: isBlock ? `${styles$5.mathField} ${styles$5.mathFieldBlock}` : styles$5.mathField,
4761
+ className: isBlock ? `${styles$6.mathField} ${styles$6.mathFieldBlock}` : styles$6.mathField,
3804
4762
  children: [
3805
4763
  field2,
3806
4764
  /* @__PURE__ */ jsxs(
3807
4765
  "button",
3808
4766
  {
3809
4767
  type: "button",
3810
- className: styles$5.mathDone,
4768
+ className: styles$6.mathDone,
3811
4769
  disabled: !canSubmit,
3812
4770
  title: isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`,
3813
4771
  onClick: submit,
3814
4772
  children: [
3815
4773
  doneLabel,
3816
- /* @__PURE__ */ jsx("span", { className: styles$5.mathDoneKbd, "aria-hidden": true, children: "↵" })
4774
+ /* @__PURE__ */ jsx("span", { className: styles$6.mathDoneKbd, "aria-hidden": true, children: "↵" })
3817
4775
  ]
3818
4776
  }
3819
4777
  )
@@ -3840,7 +4798,7 @@ const ToolbarButton = forwardRef(function ToolbarButton2({ title, active: active
3840
4798
  "aria-pressed": active2,
3841
4799
  "aria-busy": busy,
3842
4800
  disabled,
3843
- className: `${styles$5.btn} ${active2 ? styles$5.btnActive : ""}${className ? ` ${className}` : ""}`,
4801
+ className: `${styles$6.btn} ${active2 ? styles$6.btnActive : ""}${className ? ` ${className}` : ""}`,
3844
4802
  onMouseDown: (e2) => e2.preventDefault(),
3845
4803
  onClick,
3846
4804
  children
@@ -3848,7 +4806,11 @@ const ToolbarButton = forwardRef(function ToolbarButton2({ title, active: active
3848
4806
  );
3849
4807
  });
3850
4808
  function Divider() {
3851
- return /* @__PURE__ */ jsx("span", { className: styles$5.divider, "aria-hidden": true });
4809
+ return /* @__PURE__ */ jsx("span", { className: styles$6.divider, "aria-hidden": true });
4810
+ }
4811
+ const LINE_HEIGHTS = ["1", "1.15", "1.5", "2", "2.5", "3"];
4812
+ function readParaAttr(editor, name) {
4813
+ return editor.getAttributes("paragraph")[name] ?? editor.getAttributes("heading")[name] ?? null;
3852
4814
  }
3853
4815
  const MenuCloseCtx = createContext(() => {
3854
4816
  });
@@ -3863,7 +4825,7 @@ function MenuPopover({
3863
4825
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3864
4826
  Popover.Content,
3865
4827
  {
3866
- className: styles$5.menu,
4828
+ className: styles$6.menu,
3867
4829
  sideOffset: 4,
3868
4830
  align: "start",
3869
4831
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -3885,7 +4847,7 @@ function MenuItem({
3885
4847
  {
3886
4848
  type: "button",
3887
4849
  disabled,
3888
- className: `${styles$5.menuItem} ${selected ? styles$5.menuItemSelected : ""}`,
4850
+ className: `${styles$6.menuItem} ${selected ? styles$6.menuItemSelected : ""}`,
3889
4851
  onMouseDown: (e2) => e2.preventDefault(),
3890
4852
  onClick: () => {
3891
4853
  onSelect();
@@ -3920,21 +4882,21 @@ function TableInsertItem({
3920
4882
  {
3921
4883
  type: "button",
3922
4884
  disabled,
3923
- className: `${styles$5.menuItem} ${open ? styles$5.menuItemSelected : ""}`,
4885
+ className: `${styles$6.menuItem} ${open ? styles$6.menuItemSelected : ""}`,
3924
4886
  onMouseDown: (e2) => e2.preventDefault(),
3925
4887
  children: [
3926
- /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
3927
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "⊞" }),
4888
+ /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
4889
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "⊞" }),
3928
4890
  labels.tableInsert
3929
4891
  ] }),
3930
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.tableInsertCaret })
4892
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.tableInsertCaret })
3931
4893
  ]
3932
4894
  }
3933
4895
  ) }),
3934
4896
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
3935
4897
  Popover.Content,
3936
4898
  {
3937
- className: styles$5.tableSizePicker,
4899
+ className: styles$6.tableSizePicker,
3938
4900
  side: "right",
3939
4901
  align: "start",
3940
4902
  sideOffset: 6,
@@ -3944,7 +4906,7 @@ function TableInsertItem({
3944
4906
  /* @__PURE__ */ jsx(
3945
4907
  "div",
3946
4908
  {
3947
- className: styles$5.tableSizeGrid,
4909
+ className: styles$6.tableSizeGrid,
3948
4910
  style: {
3949
4911
  gridTemplateColumns: `repeat(${TABLE_PICKER_COLS}, 1fr)`
3950
4912
  },
@@ -3958,7 +4920,7 @@ function TableInsertItem({
3958
4920
  {
3959
4921
  type: "button",
3960
4922
  "aria-label": labels.tableSizeSelected(col, row2),
3961
- className: `${styles$5.tableSizeCell} ${active2 ? styles$5.tableSizeCellActive : ""}`,
4923
+ className: `${styles$6.tableSizeCell} ${active2 ? styles$6.tableSizeCellActive : ""}`,
3962
4924
  onMouseDown: (e2) => e2.preventDefault(),
3963
4925
  onMouseEnter: () => setHover({ cols: col, rows: row2 }),
3964
4926
  onClick: () => {
@@ -3973,7 +4935,7 @@ function TableInsertItem({
3973
4935
  })
3974
4936
  }
3975
4937
  ),
3976
- /* @__PURE__ */ jsx("div", { className: styles$5.tableSizeLabel, children: hover.cols > 0 ? labels.tableSizeSelected(hover.cols, hover.rows) : labels.tableInsert })
4938
+ /* @__PURE__ */ jsx("div", { className: styles$6.tableSizeLabel, children: hover.cols > 0 ? labels.tableSizeSelected(hover.cols, hover.rows) : labels.tableInsert })
3977
4939
  ]
3978
4940
  }
3979
4941
  ) })
@@ -3995,20 +4957,20 @@ function ColorPopover({
3995
4957
  "button",
3996
4958
  {
3997
4959
  type: "button",
3998
- className: styles$5.btn,
4960
+ className: styles$6.btn,
3999
4961
  title,
4000
4962
  "aria-label": title,
4001
4963
  onMouseDown: (e2) => e2.preventDefault(),
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 } })
4964
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.colorIcon, children: [
4965
+ /* @__PURE__ */ jsx("span", { className: styles$6.colorIconGlyph, children: glyph }),
4966
+ /* @__PURE__ */ jsx("span", { className: styles$6.colorIconBar, style: { background: bar2 } })
4005
4967
  ] })
4006
4968
  }
4007
4969
  ) }),
4008
4970
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
4009
4971
  Popover.Content,
4010
4972
  {
4011
- className: styles$5.popoverContent,
4973
+ className: styles$6.popoverContent,
4012
4974
  sideOffset: 4,
4013
4975
  align: "start",
4014
4976
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -4067,6 +5029,9 @@ function EditorToolbar({
4067
5029
  highlightColor: e2.getAttributes("highlight").color || void 0,
4068
5030
  superscript: e2.isActive("superscript"),
4069
5031
  subscript: e2.isActive("subscript"),
5032
+ textAlign: readParaAttr(e2, "textAlign"),
5033
+ indent: readParaAttr(e2, "indent"),
5034
+ lineHeight: readParaAttr(e2, "lineHeight"),
4070
5035
  inTable: e2.isActive("table"),
4071
5036
  canUndo: e2.can().undo(),
4072
5037
  canRedo: e2.can().redo()
@@ -4085,9 +5050,14 @@ function EditorToolbar({
4085
5050
  }, [editor]);
4086
5051
  const fileInputRef = useRef(null);
4087
5052
  const chain = () => editor.chain().focus();
5053
+ const imageUploadEnabled = hasImageUpload(editor);
4088
5054
  const handlePickImage = () => {
4089
5055
  var _a;
4090
- return (_a = fileInputRef.current) == null ? void 0 : _a.click();
5056
+ if (imageUploadEnabled) {
5057
+ chain().setImageUploadNode().run();
5058
+ return;
5059
+ }
5060
+ (_a = fileInputRef.current) == null ? void 0 : _a.click();
4091
5061
  };
4092
5062
  const handleImageChange = async (e2) => {
4093
5063
  var _a;
@@ -4264,8 +5234,8 @@ function EditorToolbar({
4264
5234
  /* @__PURE__ */ jsx(
4265
5235
  "div",
4266
5236
  {
4267
- className: className ? `${styles$5.toolbar} ${className}` : styles$5.toolbar,
4268
- children: /* @__PURE__ */ jsxs("div", { className: styles$5.inner, children: [
5237
+ className: className ? `${styles$6.toolbar} ${className}` : styles$6.toolbar,
5238
+ children: /* @__PURE__ */ jsxs("div", { className: styles$6.inner, children: [
4269
5239
  /* @__PURE__ */ jsx(
4270
5240
  ToolbarButton,
4271
5241
  {
@@ -4292,12 +5262,12 @@ function EditorToolbar({
4292
5262
  "button",
4293
5263
  {
4294
5264
  type: "button",
4295
- className: styles$5.styleTrigger,
5265
+ className: styles$6.styleTrigger,
4296
5266
  title: t.style,
4297
5267
  onMouseDown: (e2) => e2.preventDefault(),
4298
5268
  children: [
4299
- /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.style }),
4300
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
5269
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.style }),
5270
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
4301
5271
  ]
4302
5272
  }
4303
5273
  ),
@@ -4307,8 +5277,8 @@ function EditorToolbar({
4307
5277
  {
4308
5278
  selected: (state.headingLevel ?? 0) === 0,
4309
5279
  onSelect: () => setBlockStyle(0),
4310
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4311
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "¶" }),
5280
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5281
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "¶" }),
4312
5282
  t.normalText
4313
5283
  ] })
4314
5284
  }
@@ -4318,8 +5288,8 @@ function EditorToolbar({
4318
5288
  {
4319
5289
  selected: state.headingLevel === lv,
4320
5290
  onSelect: () => setBlockStyle(lv),
4321
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4322
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: `H${lv}` }),
5291
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5292
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: `H${lv}` }),
4323
5293
  t.headingLabel(lv)
4324
5294
  ] })
4325
5295
  },
@@ -4335,14 +5305,14 @@ function EditorToolbar({
4335
5305
  "button",
4336
5306
  {
4337
5307
  type: "button",
4338
- className: styles$5.styleTrigger,
5308
+ className: styles$6.styleTrigger,
4339
5309
  title: t.fontSize,
4340
5310
  "aria-label": t.fontSize,
4341
5311
  disabled: !canEditFontSize,
4342
5312
  onMouseDown: (e2) => e2.preventDefault(),
4343
5313
  children: [
4344
- /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: state.fontSize || t.fontSize }),
4345
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
5314
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: state.fontSize || t.fontSize }),
5315
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
4346
5316
  ]
4347
5317
  }
4348
5318
  ),
@@ -4352,8 +5322,8 @@ function EditorToolbar({
4352
5322
  {
4353
5323
  selected: !state.fontSize,
4354
5324
  onSelect: () => applyFontSize(""),
4355
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4356
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "A" }),
5325
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5326
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "A" }),
4357
5327
  t.fontSizeDefault
4358
5328
  ] })
4359
5329
  }
@@ -4363,8 +5333,8 @@ function EditorToolbar({
4363
5333
  {
4364
5334
  selected: state.fontSize === size,
4365
5335
  onSelect: () => applyFontSize(size),
4366
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4367
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: parseInt(size, 10) }),
5336
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5337
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: parseInt(size, 10) }),
4368
5338
  size
4369
5339
  ] })
4370
5340
  },
@@ -4448,13 +5418,13 @@ function EditorToolbar({
4448
5418
  "button",
4449
5419
  {
4450
5420
  type: "button",
4451
- className: `${styles$5.scriptTrigger} ${scriptActive !== "normal" ? styles$5.btnActive : ""}`,
5421
+ className: `${styles$6.scriptTrigger} ${scriptActive !== "normal" ? styles$6.btnActive : ""}`,
4452
5422
  title: t.scriptMenu,
4453
5423
  "aria-label": t.scriptMenu,
4454
5424
  onMouseDown: (e2) => e2.preventDefault(),
4455
5425
  children: [
4456
- /* @__PURE__ */ jsx("span", { className: styles$5.scriptTriggerGlyph, children: "A" }),
4457
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
5426
+ /* @__PURE__ */ jsx("span", { className: styles$6.scriptTriggerGlyph, children: "A" }),
5427
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
4458
5428
  ]
4459
5429
  }
4460
5430
  ),
@@ -4464,8 +5434,8 @@ function EditorToolbar({
4464
5434
  {
4465
5435
  selected: scriptActive === "normal",
4466
5436
  onSelect: () => chain().unsetSuperscript().unsetSubscript().run(),
4467
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4468
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: "A" }),
5437
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5438
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "A" }),
4469
5439
  t.scriptNormal
4470
5440
  ] })
4471
5441
  }
@@ -4475,8 +5445,8 @@ function EditorToolbar({
4475
5445
  {
4476
5446
  selected: scriptActive === "superscript",
4477
5447
  onSelect: () => chain().unsetSubscript().toggleSuperscript().run(),
4478
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4479
- /* @__PURE__ */ jsxs("span", { className: `${styles$5.styleIcon} ${styles$5.scriptGlyph}`, children: [
5448
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5449
+ /* @__PURE__ */ jsxs("span", { className: `${styles$6.styleIcon} ${styles$6.scriptGlyph}`, children: [
4480
5450
  "x",
4481
5451
  /* @__PURE__ */ jsx("sup", { children: "2" })
4482
5452
  ] }),
@@ -4489,8 +5459,8 @@ function EditorToolbar({
4489
5459
  {
4490
5460
  selected: scriptActive === "subscript",
4491
5461
  onSelect: () => chain().unsetSuperscript().toggleSubscript().run(),
4492
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4493
- /* @__PURE__ */ jsxs("span", { className: `${styles$5.styleIcon} ${styles$5.scriptGlyph}`, children: [
5462
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5463
+ /* @__PURE__ */ jsxs("span", { className: `${styles$6.styleIcon} ${styles$6.scriptGlyph}`, children: [
4494
5464
  "x",
4495
5465
  /* @__PURE__ */ jsx("sub", { children: "2" })
4496
5466
  ] }),
@@ -4516,9 +5486,9 @@ function EditorToolbar({
4516
5486
  trigger: /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, children: /* @__PURE__ */ jsx(LinkIcon, {}) })
4517
5487
  }
4518
5488
  ),
4519
- onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
5489
+ imageUploadEnabled || onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
4520
5490
  /* @__PURE__ */ jsx(ToolbarButton, { title: t.image, onClick: handlePickImage, children: /* @__PURE__ */ jsx(ImageIcon, {}) }),
4521
- /* @__PURE__ */ jsx(
5491
+ !imageUploadEnabled && /* @__PURE__ */ jsx(
4522
5492
  "input",
4523
5493
  {
4524
5494
  ref: fileInputRef,
@@ -4536,19 +5506,19 @@ function EditorToolbar({
4536
5506
  "button",
4537
5507
  {
4538
5508
  type: "button",
4539
- className: styles$5.styleTrigger,
5509
+ className: styles$6.styleTrigger,
4540
5510
  title: importTitle,
4541
5511
  "aria-label": importTitle,
4542
5512
  "aria-busy": !!importing,
4543
5513
  disabled: !!importing,
4544
5514
  onMouseDown: (e2) => e2.preventDefault(),
4545
5515
  children: [
4546
- /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.importDocument }),
5516
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.importDocument }),
4547
5517
  /* @__PURE__ */ jsx(
4548
5518
  ChevronDownIcon,
4549
5519
  {
4550
5520
  size: 12,
4551
- className: styles$5.styleTriggerCaret
5521
+ className: styles$6.styleTriggerCaret
4552
5522
  }
4553
5523
  )
4554
5524
  ]
@@ -4570,7 +5540,117 @@ function EditorToolbar({
4570
5540
  title: t.blockquote,
4571
5541
  active: state.blockquote,
4572
5542
  onClick: () => chain().toggleBlockquote().run(),
4573
- children: /* @__PURE__ */ jsx("span", { className: styles$5.txtIcon, children: "❝" })
5543
+ children: /* @__PURE__ */ jsx("span", { className: styles$6.txtIcon, children: "❝" })
5544
+ }
5545
+ ),
5546
+ /* @__PURE__ */ jsx(Divider, {}),
5547
+ /* @__PURE__ */ jsx(
5548
+ MenuPopover,
5549
+ {
5550
+ trigger: /* @__PURE__ */ jsxs(
5551
+ "button",
5552
+ {
5553
+ type: "button",
5554
+ className: `${styles$6.styleTrigger} ${styles$6.iconTrigger}`,
5555
+ title: t.align,
5556
+ "aria-label": t.align,
5557
+ onMouseDown: (e2) => e2.preventDefault(),
5558
+ children: [
5559
+ state.textAlign === "center" ? /* @__PURE__ */ jsx(AlignCenterIcon, {}) : state.textAlign === "right" ? /* @__PURE__ */ jsx(AlignRightIcon, {}) : state.textAlign === "justify" ? /* @__PURE__ */ jsx(AlignJustifyIcon, {}) : /* @__PURE__ */ jsx(AlignLeftIcon, {}),
5560
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
5561
+ ]
5562
+ }
5563
+ ),
5564
+ children: [
5565
+ { value: "left", label: t.alignLeft, Icon: AlignLeftIcon },
5566
+ { value: "center", label: t.alignCenter, Icon: AlignCenterIcon },
5567
+ { value: "right", label: t.alignRight, Icon: AlignRightIcon },
5568
+ { value: "justify", label: t.alignJustify, Icon: AlignJustifyIcon }
5569
+ ].map(({ value, label, Icon }) => /* @__PURE__ */ jsx(
5570
+ MenuItem,
5571
+ {
5572
+ selected: state.textAlign === value,
5573
+ onSelect: () => chain().setTextAlign(value).run(),
5574
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5575
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: /* @__PURE__ */ jsx(Icon, { size: 14 }) }),
5576
+ label
5577
+ ] })
5578
+ },
5579
+ value
5580
+ ))
5581
+ }
5582
+ ),
5583
+ /* @__PURE__ */ jsxs(
5584
+ MenuPopover,
5585
+ {
5586
+ trigger: /* @__PURE__ */ jsxs(
5587
+ "button",
5588
+ {
5589
+ type: "button",
5590
+ className: `${styles$6.styleTrigger} ${styles$6.iconTrigger}`,
5591
+ title: t.indent,
5592
+ "aria-label": t.indent,
5593
+ onMouseDown: (e2) => e2.preventDefault(),
5594
+ children: [
5595
+ /* @__PURE__ */ jsx(IndentIncreaseIcon, {}),
5596
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
5597
+ ]
5598
+ }
5599
+ ),
5600
+ children: [
5601
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().increaseIndent().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5602
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: /* @__PURE__ */ jsx(IndentIncreaseIcon, { size: 14 }) }),
5603
+ t.indentIncrease
5604
+ ] }) }),
5605
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().decreaseIndent().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5606
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: /* @__PURE__ */ jsx(IndentDecreaseIcon, { size: 14 }) }),
5607
+ t.indentDecrease
5608
+ ] }) })
5609
+ ]
5610
+ }
5611
+ ),
5612
+ /* @__PURE__ */ jsxs(
5613
+ MenuPopover,
5614
+ {
5615
+ trigger: /* @__PURE__ */ jsxs(
5616
+ "button",
5617
+ {
5618
+ type: "button",
5619
+ className: `${styles$6.styleTrigger} ${styles$6.iconTrigger}`,
5620
+ title: t.lineHeight,
5621
+ "aria-label": t.lineHeight,
5622
+ onMouseDown: (e2) => e2.preventDefault(),
5623
+ children: [
5624
+ /* @__PURE__ */ jsx(LineHeightIcon, {}),
5625
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
5626
+ ]
5627
+ }
5628
+ ),
5629
+ children: [
5630
+ /* @__PURE__ */ jsx(
5631
+ MenuItem,
5632
+ {
5633
+ selected: !state.lineHeight,
5634
+ onSelect: () => chain().setLineHeight(null).run(),
5635
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5636
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "—" }),
5637
+ t.lineHeightDefault
5638
+ ] })
5639
+ }
5640
+ ),
5641
+ LINE_HEIGHTS.map((value) => /* @__PURE__ */ jsx(
5642
+ MenuItem,
5643
+ {
5644
+ selected: state.lineHeight === Number(value),
5645
+ onSelect: () => chain().setLineHeight(Number(value)).run(),
5646
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5647
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "≡" }),
5648
+ value
5649
+ ] })
5650
+ },
5651
+ value
5652
+ ))
5653
+ ]
4574
5654
  }
4575
5655
  ),
4576
5656
  /* @__PURE__ */ jsx(Divider, {}),
@@ -4618,30 +5698,30 @@ function EditorToolbar({
4618
5698
  "button",
4619
5699
  {
4620
5700
  type: "button",
4621
- className: styles$5.styleTrigger,
5701
+ className: styles$6.styleTrigger,
4622
5702
  title: t.more,
4623
5703
  onMouseDown: (e2) => e2.preventDefault(),
4624
5704
  children: [
4625
- /* @__PURE__ */ jsx("span", { className: styles$5.styleTriggerLabel, children: t.more }),
4626
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$5.styleTriggerCaret })
5705
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.more }),
5706
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
4627
5707
  ]
4628
5708
  }
4629
5709
  ),
4630
5710
  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: "{ }" }),
5711
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().toggleCodeBlock().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5712
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "{ }" }),
4633
5713
  t.codeBlock
4634
5714
  ] }) }),
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" }),
5715
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("inline"), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5716
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "√x" }),
4637
5717
  t.inlineMath
4638
5718
  ] }) }),
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: "∑" }),
5719
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("block"), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5720
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "∑" }),
4641
5721
  t.blockMath
4642
5722
  ] }) }),
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: "—" }),
5723
+ /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().setHorizontalRule().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5724
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "—" }),
4645
5725
  t.hr
4646
5726
  ] }) }),
4647
5727
  /* @__PURE__ */ jsx(
@@ -4657,8 +5737,8 @@ function EditorToolbar({
4657
5737
  {
4658
5738
  disabled: item2.disabled,
4659
5739
  onSelect: () => item2.onSelect(editor),
4660
- children: /* @__PURE__ */ jsxs("span", { className: styles$5.styleItem, children: [
4661
- /* @__PURE__ */ jsx("span", { className: styles$5.styleIcon, children: item2.icon }),
5740
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5741
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: item2.icon }),
4662
5742
  item2.label
4663
5743
  ] })
4664
5744
  },
@@ -4695,7 +5775,8 @@ function EditorToolbar({
4695
5775
  onCancel: cancelMath
4696
5776
  }
4697
5777
  ) : null,
4698
- /* @__PURE__ */ jsx(TableHandles, { editor, labels: t })
5778
+ /* @__PURE__ */ jsx(TableHandles, { editor, labels: t }),
5779
+ /* @__PURE__ */ jsx(ImageAlignTools, { editor, labels: t })
4699
5780
  ] });
4700
5781
  }
4701
5782
  function useIsMobile(breakpoint = 768) {
@@ -4857,6 +5938,11 @@ function TocPanel({ items, activeId, onItemClick, labels }) {
4857
5938
  list2
4858
5939
  ] });
4859
5940
  }
5941
+ function resetImageSize(editor) {
5942
+ const pos = findImagePos(editor);
5943
+ if (pos == null) return false;
5944
+ return editor.chain().focus().setNodeSelection(pos).updateAttributes("image", { width: null, height: null }).run();
5945
+ }
4860
5946
  const popoverAnchor = "_popoverAnchor_9y5t0_55";
4861
5947
  const popoverContent = "_popoverContent_9y5t0_62";
4862
5948
  const styles = {
@@ -5001,11 +6087,11 @@ function tryInsertMarkdownAt(editor, from, to, markdown) {
5001
6087
  return false;
5002
6088
  }
5003
6089
  }
5004
- function insertPlainParagraphAt(editor, from, to, text) {
6090
+ function insertPlainParagraphAt(editor, from, to, text2) {
5005
6091
  try {
5006
6092
  return editor.chain().insertContentAt(
5007
6093
  { from, to },
5008
- { type: "paragraph", content: text ? [{ type: "text", text }] : [] }
6094
+ { type: "paragraph", content: text2 ? [{ type: "text", text: text2 }] : [] }
5009
6095
  ).run();
5010
6096
  } catch {
5011
6097
  return false;
@@ -5023,10 +6109,15 @@ function insertSlashMarkdown(editor, range, markdown) {
5023
6109
  insertMarkdown(editor, prepared);
5024
6110
  }
5025
6111
  export {
6112
+ AlignCenterIcon,
6113
+ AlignJustifyIcon,
6114
+ AlignLeftIcon,
6115
+ AlignRightIcon,
5026
6116
  BoldIcon,
5027
6117
  COMMENT_ACTIVE_META,
5028
6118
  COMMENT_CLICK_META,
5029
6119
  COMMENT_GUTTER_META,
6120
+ CaptionsIcon,
5030
6121
  C as ChartMount,
5031
6122
  CheckIcon,
5032
6123
  ChevronDownIcon,
@@ -5049,11 +6140,16 @@ export {
5049
6140
  FIND_DEBOUNCE_MS,
5050
6141
  default2 as FindAndReplace,
5051
6142
  FindReplaceBar,
6143
+ ImageAlignTools,
5052
6144
  ImageIcon,
6145
+ ImageUploadNode,
5053
6146
  ImportIcon,
5054
6147
  ImportPlaceholder,
6148
+ IndentDecreaseIcon,
6149
+ IndentIncreaseIcon,
5055
6150
  ItalicIcon,
5056
6151
  KeyboardIcon,
6152
+ LineHeightIcon,
5057
6153
  LinkIcon,
5058
6154
  LinkPopover,
5059
6155
  ListChecksIcon,
@@ -5066,6 +6162,7 @@ export {
5066
6162
  MarkdownWysiwygEditor,
5067
6163
  MenuIcon,
5068
6164
  PENDING_ANCHOR_CLASS,
6165
+ P as ParagraphStyles,
5069
6166
  RedoIcon,
5070
6167
  ReplaceAllIcon,
5071
6168
  ReplaceIcon,
@@ -5106,6 +6203,7 @@ export {
5106
6203
  defaultColorPaletteLabels,
5107
6204
  defaultCommentLabels,
5108
6205
  defaultFindLabels,
6206
+ defaultImageUploadLabels,
5109
6207
  defaultLinkPopoverLabels,
5110
6208
  defaultShortcutLabels,
5111
6209
  defaultSlashMenuLabels,
@@ -5119,8 +6217,13 @@ export {
5119
6217
  findRangeByAnchor,
5120
6218
  focusComment,
5121
6219
  getMarkdownForRange,
6220
+ hasImageUpload,
6221
+ imageMarkdownTokenizer,
6222
+ imageParseMarkdown,
6223
+ imageRenderMarkdown,
5122
6224
  insertMarkdown,
5123
6225
  insertSlashMarkdown,
6226
+ isImageAlignActive,
5124
6227
  isLinkActive,
5125
6228
  looksLikeMarkdown,
5126
6229
  lowlight,
@@ -5129,6 +6232,8 @@ export {
5129
6232
  mergeCommentIntervals,
5130
6233
  m as mountChartsInContainer,
5131
6234
  nextComment,
6235
+ normalizeImageAlign,
6236
+ normalizeImageCaption,
5132
6237
  normalizeLinkHref,
5133
6238
  normalizeMarkdown,
5134
6239
  openLinkUrl,
@@ -5141,11 +6246,16 @@ export {
5141
6246
  removeLink,
5142
6247
  replaceRangeWithMarkdown,
5143
6248
  reportChart,
6249
+ resetImageSize,
5144
6250
  runFindCommand,
5145
6251
  sanitizeLinkUrl,
5146
6252
  s as scrollToTocHeading,
5147
6253
  selectionKind,
5148
6254
  s2 as serializeChartPayload,
6255
+ setImageAlign,
6256
+ setImageAlignAt,
6257
+ setImageCaption,
6258
+ setImageCaptionAtPos,
5149
6259
  s3 as stabilizeMarkdown,
5150
6260
  stripCommentAnchorMarks,
5151
6261
  useIsMobile