tiptap-markdown-react 0.17.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +171 -17
  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 +13 -2
  9. package/dist/components/EditorToolbar.dom.test.d.ts +1 -0
  10. package/dist/components/FindReplaceBar.d.ts +0 -7
  11. package/dist/components/ImageAlignTools.d.ts +19 -0
  12. package/dist/components/ImageUploadView.d.ts +10 -0
  13. package/dist/components/LinkPopover.d.ts +28 -0
  14. package/dist/components/LinkPopover.dom.test.d.ts +1 -0
  15. package/dist/components/MarkdownWysiwygEditor.d.ts +59 -1
  16. package/dist/components/TableHandles.d.ts +19 -0
  17. package/dist/components/TableHandles.dom.test.d.ts +1 -0
  18. package/dist/components/findEntry.dom.test.d.ts +1 -0
  19. package/dist/components/imageUpload.dom.test.d.ts +1 -0
  20. package/dist/extensions.d.ts +12 -0
  21. package/dist/{extractToc-BaR6LP1f.js → extractToc-CGrBMGvM.js} +433 -9
  22. package/dist/extractToc-CGrBMGvM.js.map +1 -0
  23. package/dist/findReplace.d.ts +18 -4
  24. package/dist/icons/index.d.ts +15 -0
  25. package/dist/imageAlign.d.ts +29 -0
  26. package/dist/imageAlign.dom.test.d.ts +1 -0
  27. package/dist/imageCaption.d.ts +12 -0
  28. package/dist/imageMarkdown.d.ts +86 -0
  29. package/dist/imageResize.dom.test.d.ts +1 -0
  30. package/dist/imageUpload.d.ts +63 -0
  31. package/dist/index.d.ts +11 -2
  32. package/dist/index.js +2354 -537
  33. package/dist/index.js.map +1 -1
  34. package/dist/labels.d.ts +93 -1
  35. package/dist/linkEditing.d.ts +45 -0
  36. package/dist/linkEditing.test.d.ts +1 -0
  37. package/dist/paragraphMarkdown.d.ts +19 -0
  38. package/dist/paragraphStyles.d.ts +38 -0
  39. package/dist/paragraphStyles.dom.test.d.ts +1 -0
  40. package/dist/reader.js +2 -2
  41. package/dist/resetImageSize.d.ts +12 -0
  42. package/dist/{scrollToTocHeading-BTQWajGD.js → scrollToTocHeading-B2QmL4wi.js} +2 -2
  43. package/dist/{scrollToTocHeading-BTQWajGD.js.map → scrollToTocHeading-B2QmL4wi.js.map} +1 -1
  44. package/dist/server.d.ts +1 -1
  45. package/dist/server.js +4 -4
  46. package/dist/style-inline.css +932 -180
  47. package/dist/style.css +932 -180
  48. package/dist/tableSelection.d.ts +25 -5
  49. package/package.json +5 -2
  50. package/dist/ReportContent-MgbebxPV.js.map +0 -1
  51. 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,19 +10,19 @@ 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$8 } 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";
25
- import { CellSelection, isInTable, selectedRect, rowIsHeader } from "@tiptap/pm/tables";
25
+ import { CellSelection, TableMap, isInTable, selectedRect, rowIsHeader, cellAround } from "@tiptap/pm/tables";
26
26
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
27
27
  import * as Popover from "@radix-ui/react-popover";
28
28
  function CitationRefView({ node, extension }) {
@@ -336,6 +336,17 @@ function nextComment(editor, dir = "next") {
336
336
  focusComment(editor, target);
337
337
  return target;
338
338
  }
339
+ const FIND_EXTENSION_NAME = "findAndReplace";
340
+ function isComposingKeyEvent(event) {
341
+ return event.isComposing || event.keyCode === 229;
342
+ }
343
+ function hasFindReplaceExtension(editor) {
344
+ var _a;
345
+ if (!editor || editor.isDestroyed) return false;
346
+ return ((_a = editor.extensionManager) == null ? void 0 : _a.extensions.some(
347
+ (extension) => extension.name === FIND_EXTENSION_NAME
348
+ )) ?? false;
349
+ }
339
350
  const FIND_DEBOUNCE_MS = 120;
340
351
  const MISMATCH_RE = /Applying a mismatched transaction/;
341
352
  function runFindCommand(run) {
@@ -395,11 +406,90 @@ const LinkIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
395
406
  /* @__PURE__ */ jsx("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
396
407
  /* @__PURE__ */ jsx("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
397
408
  ] });
409
+ const EraserIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
410
+ /* @__PURE__ */ jsx("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
411
+ /* @__PURE__ */ jsx("path", { d: "M22 21H7" }),
412
+ /* @__PURE__ */ jsx("path", { d: "m5 11 9 9" })
413
+ ] });
414
+ const RotateCcwIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
415
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
416
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" })
417
+ ] });
418
+ const ExternalLinkIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
419
+ /* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
420
+ /* @__PURE__ */ jsx("path", { d: "M10 14 21 3" }),
421
+ /* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
422
+ ] });
398
423
  const ImageIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
399
424
  /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
400
425
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
401
426
  /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
402
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
+ ] });
403
493
  const ImportIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
404
494
  /* @__PURE__ */ jsx("path", { d: "M12 3v12" }),
405
495
  /* @__PURE__ */ jsx("path", { d: "m8 11 4 4 4-4" }),
@@ -576,9 +666,29 @@ const defaultToolbarLabels = {
576
666
  superscript: "Superscript",
577
667
  subscript: "Subscript",
578
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",
579
679
  linkPrompt: "Enter URL",
680
+ linkApply: "Apply link",
681
+ linkOpen: "Open in new window",
682
+ linkRemove: "Remove link",
683
+ linkInvalid: "The editor rejected this address",
580
684
  image: "Image",
581
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…",
582
692
  importMarkdownFailed: "Markdown import failed",
583
693
  importDocument: "Import",
584
694
  importDocumentHint: "Import a file",
@@ -592,10 +702,17 @@ const defaultToolbarLabels = {
592
702
  orderedList: "Ordered list",
593
703
  taskList: "Task list",
594
704
  more: "More",
705
+ search: "Find & replace",
595
706
  codeBlock: "Code block",
596
707
  hr: "Divider",
597
708
  importMarkdown: "Markdown",
598
709
  tableInsert: "Insert table",
710
+ tableRowMenu: "Row actions",
711
+ tableColumnMenu: "Column actions",
712
+ tableClearContent: "Clear content",
713
+ tableResetCellStyles: "Reset cell styles",
714
+ tableAppendRow: "Add row",
715
+ tableAppendColumn: "Add column",
599
716
  tableSizeSelected: (cols, rows) => `${cols} × ${rows}`,
600
717
  tableAddColumnBefore: "Add column before",
601
718
  tableAddColumnAfter: "Add column after",
@@ -661,7 +778,19 @@ const defaultShortcutLabels = {
661
778
  undo: "Undo",
662
779
  redo: "Redo",
663
780
  hardBreak: "Hard break",
664
- 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"
787
+ };
788
+ const defaultLinkPopoverLabels = {
789
+ field: "Enter URL",
790
+ apply: "Apply link",
791
+ open: "Open in new window",
792
+ remove: "Remove link",
793
+ invalid: "The editor rejected this address"
665
794
  };
666
795
  const defaultColorPaletteLabels = {
667
796
  none: "None",
@@ -703,34 +832,55 @@ const defaultFindLabels = {
703
832
  invalidRegex: "Invalid pattern",
704
833
  readOnly: "Read-only"
705
834
  };
706
- 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";
707
849
  const row$1 = "_row_1h61e_25";
708
- const field = "_field_1h61e_43";
850
+ const field$1 = "_field_1h61e_43";
709
851
  const fieldIcon = "_fieldIcon_1h61e_62";
710
- const input = "_input_1h61e_67";
852
+ const input$1 = "_input_1h61e_67";
711
853
  const counter = "_counter_1h61e_79";
712
854
  const counterInvalid = "_counterInvalid_1h61e_89";
713
- const btn$1 = "_btn_1h61e_93";
855
+ const btn$3 = "_btn_1h61e_93";
714
856
  const toggle = "_toggle_1h61e_29";
715
857
  const toggleOn = "_toggleOn_1h61e_135";
716
858
  const iconGroup = "_iconGroup_1h61e_29";
717
859
  const spacer = "_spacer_1h61e_150";
718
860
  const readOnly = "_readOnly_1h61e_155";
719
- const styles$7 = {
720
- bar,
861
+ const styles$b = {
862
+ bar: bar$1,
721
863
  row: row$1,
722
- field,
864
+ field: field$1,
723
865
  fieldIcon,
724
- input,
866
+ input: input$1,
725
867
  counter,
726
868
  counterInvalid,
727
- btn: btn$1,
869
+ btn: btn$3,
728
870
  toggle,
729
871
  toggleOn,
730
872
  iconGroup,
731
873
  spacer,
732
874
  readOnly
733
875
  };
876
+ let warnedMissingExtension = false;
877
+ function warnMissingExtensionOnce() {
878
+ if (warnedMissingExtension) return;
879
+ warnedMissingExtension = true;
880
+ console.warn(
881
+ "[tiptap-markdown-react] FindReplaceBar 需要官方 find 扩展:请让 <MarkdownWysiwygEditor findReplace> 保持开启(默认 true),否则 setSearchTerm / replaceAll 等命令不存在。"
882
+ );
883
+ }
734
884
  function FindReplaceBar({
735
885
  editor,
736
886
  onClose,
@@ -742,13 +892,9 @@ function FindReplaceBar({
742
892
  const t = { ...defaultFindLabels, ...labels };
743
893
  const [term, setTerm] = useState("");
744
894
  const [replaceTerm, setReplaceTerm] = useState("");
745
- const hasExtension = typeof editor.commands.setSearchTerm === "function";
895
+ const hasExtension = hasFindReplaceExtension(editor);
746
896
  useEffect(() => {
747
- if (!hasExtension) {
748
- console.warn(
749
- "[tiptap-markdown-react] FindReplaceBar 需要官方 find 扩展:请让 <MarkdownWysiwygEditor findReplace> 保持开启(默认 true),否则 setSearchTerm / replaceAll 等命令不存在。"
750
- );
751
- }
897
+ if (!hasExtension) warnMissingExtensionOnce();
752
898
  }, [hasExtension]);
753
899
  const state = useEditorState({
754
900
  editor,
@@ -809,12 +955,11 @@ function FindReplaceBar({
809
955
  }) === null,
810
956
  [term, state.useRegex, state.caseSensitive]
811
957
  );
812
- const counter2 = t.counter(
813
- state.total === 0 ? 0 : (state.currentIndex ?? 0) + 1,
814
- state.total
815
- );
958
+ const current = state.total === 0 || state.currentIndex === null ? 0 : state.currentIndex + 1;
959
+ const counter2 = t.counter(current, state.total);
816
960
  const keepFocus = (e2) => e2.preventDefault();
817
961
  const onFindKeyDown = (e2) => {
962
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
818
963
  if (e2.key === "Enter") {
819
964
  e2.preventDefault();
820
965
  runAction(() => {
@@ -824,6 +969,7 @@ function FindReplaceBar({
824
969
  }
825
970
  };
826
971
  const onReplaceKeyDown = (e2) => {
972
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
827
973
  if (e2.key === "Enter") {
828
974
  e2.preventDefault();
829
975
  runAction(() => editor.commands.replace());
@@ -836,29 +982,32 @@ function FindReplaceBar({
836
982
  });
837
983
  };
838
984
  if (!hasExtension) return null;
839
- const toggleClass = (on) => `${styles$7.btn} ${styles$7.toggle}${on ? ` ${styles$7.toggleOn}` : ""}`;
985
+ const toggleClass = (on) => `${styles$b.btn} ${styles$b.toggle}${on ? ` ${styles$b.toggleOn}` : ""}`;
840
986
  return /* @__PURE__ */ jsxs(
841
987
  "div",
842
988
  {
843
- className: className ? `${styles$7.bar} ${className}` : styles$7.bar,
989
+ className: className ? `${styles$b.bar} ${className}` : styles$b.bar,
844
990
  style,
991
+ "data-find-bar": "",
845
992
  role: "dialog",
846
993
  "aria-label": t.find,
847
994
  onKeyDown: (e2) => {
848
- if (e2.key === "Escape") {
849
- e2.preventDefault();
850
- onClose();
851
- }
995
+ if (isComposingKeyEvent(e2.nativeEvent)) return;
996
+ if (e2.key !== "Escape") return;
997
+ e2.preventDefault();
998
+ e2.stopPropagation();
999
+ onClose();
852
1000
  },
853
1001
  children: [
854
- /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
855
- /* @__PURE__ */ jsxs("span", { className: styles$7.field, children: [
856
- /* @__PURE__ */ jsx(SearchIcon, { size: 14, className: styles$7.fieldIcon }),
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 }),
857
1005
  /* @__PURE__ */ jsx(
858
1006
  "input",
859
1007
  {
860
1008
  ref: inputRef,
861
- className: styles$7.input,
1009
+ className: styles$b.input,
1010
+ "data-find-field": "search",
862
1011
  value: term,
863
1012
  onChange: (e2) => setTerm(e2.target.value),
864
1013
  onKeyDown: onFindKeyDown,
@@ -871,7 +1020,8 @@ function FindReplaceBar({
871
1020
  /* @__PURE__ */ jsx(
872
1021
  "span",
873
1022
  {
874
- className: `${styles$7.counter}${invalidPattern ? ` ${styles$7.counterInvalid}` : ""}`,
1023
+ className: `${styles$b.counter}${invalidPattern ? ` ${styles$b.counterInvalid}` : ""}`,
1024
+ "data-find-counter": "",
875
1025
  "aria-live": "polite",
876
1026
  title: invalidPattern ? t.invalidRegex : void 0,
877
1027
  children: invalidPattern ? t.invalidRegex : counter2
@@ -883,6 +1033,7 @@ function FindReplaceBar({
883
1033
  {
884
1034
  type: "button",
885
1035
  className: toggleClass(state.caseSensitive),
1036
+ "data-find-option": "match-case",
886
1037
  title: t.caseSensitive,
887
1038
  "aria-label": t.caseSensitive,
888
1039
  "aria-pressed": state.caseSensitive,
@@ -896,6 +1047,7 @@ function FindReplaceBar({
896
1047
  {
897
1048
  type: "button",
898
1049
  className: toggleClass(state.wholeWord),
1050
+ "data-find-option": "whole-words",
899
1051
  title: t.wholeWord,
900
1052
  "aria-label": t.wholeWord,
901
1053
  "aria-pressed": state.wholeWord,
@@ -904,13 +1056,14 @@ function FindReplaceBar({
904
1056
  children: "ab"
905
1057
  }
906
1058
  ),
907
- /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
908
- /* @__PURE__ */ jsxs("span", { className: styles$7.iconGroup, children: [
1059
+ /* @__PURE__ */ jsx("span", { className: styles$b.spacer }),
1060
+ /* @__PURE__ */ jsxs("span", { className: styles$b.iconGroup, children: [
909
1061
  /* @__PURE__ */ jsx(
910
1062
  "button",
911
1063
  {
912
1064
  type: "button",
913
- className: styles$7.btn,
1065
+ className: styles$b.btn,
1066
+ "data-find-action": "previous",
914
1067
  title: t.previous,
915
1068
  "aria-label": t.previous,
916
1069
  disabled: state.total === 0,
@@ -923,7 +1076,8 @@ function FindReplaceBar({
923
1076
  "button",
924
1077
  {
925
1078
  type: "button",
926
- className: styles$7.btn,
1079
+ className: styles$b.btn,
1080
+ "data-find-action": "next",
927
1081
  title: t.next,
928
1082
  "aria-label": t.next,
929
1083
  disabled: state.total === 0,
@@ -936,7 +1090,8 @@ function FindReplaceBar({
936
1090
  "button",
937
1091
  {
938
1092
  type: "button",
939
- className: styles$7.btn,
1093
+ className: styles$b.btn,
1094
+ "data-find-action": "close",
940
1095
  title: t.close,
941
1096
  "aria-label": t.close,
942
1097
  onClick: onClose,
@@ -945,11 +1100,12 @@ function FindReplaceBar({
945
1100
  )
946
1101
  ] })
947
1102
  ] }),
948
- editor.isEditable ? /* @__PURE__ */ jsxs("div", { className: styles$7.row, children: [
949
- /* @__PURE__ */ jsx("span", { className: styles$7.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(
950
1105
  "input",
951
1106
  {
952
- className: styles$7.input,
1107
+ className: styles$b.input,
1108
+ "data-find-field": "replace",
953
1109
  value: replaceTerm,
954
1110
  onChange: (e2) => setReplaceTerm(e2.target.value),
955
1111
  onKeyDown: onReplaceKeyDown,
@@ -958,12 +1114,13 @@ function FindReplaceBar({
958
1114
  spellCheck: false
959
1115
  }
960
1116
  ) }),
961
- /* @__PURE__ */ jsx("span", { className: styles$7.spacer }),
1117
+ /* @__PURE__ */ jsx("span", { className: styles$b.spacer }),
962
1118
  /* @__PURE__ */ jsx(
963
1119
  "button",
964
1120
  {
965
1121
  type: "button",
966
- className: styles$7.btn,
1122
+ className: styles$b.btn,
1123
+ "data-find-action": "replace",
967
1124
  title: t.replaceOne,
968
1125
  "aria-label": t.replaceOne,
969
1126
  disabled: state.total === 0,
@@ -976,7 +1133,8 @@ function FindReplaceBar({
976
1133
  "button",
977
1134
  {
978
1135
  type: "button",
979
- className: styles$7.btn,
1136
+ className: styles$b.btn,
1137
+ "data-find-action": "replace-all",
980
1138
  title: t.replaceAll,
981
1139
  "aria-label": t.replaceAll,
982
1140
  disabled: state.total === 0,
@@ -985,7 +1143,7 @@ function FindReplaceBar({
985
1143
  children: /* @__PURE__ */ jsx(ReplaceAllIcon, { size: 16 })
986
1144
  }
987
1145
  )
988
- ] }) : /* @__PURE__ */ jsx("div", { className: styles$7.row, children: /* @__PURE__ */ jsx("span", { className: styles$7.readOnly, children: t.readOnly }) })
1146
+ ] }) : /* @__PURE__ */ jsx("div", { className: styles$b.row, children: /* @__PURE__ */ jsx("span", { className: styles$b.readOnly, children: t.readOnly }) })
989
1147
  ]
990
1148
  }
991
1149
  );
@@ -1072,6 +1230,515 @@ const ImportPlaceholder = Node$1.create({
1072
1230
  };
1073
1231
  }
1074
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
+ }
1075
1742
  const popupHost = "_popupHost_1noza_11";
1076
1743
  const menu$1 = "_menu_1noza_1";
1077
1744
  const groupLabel = "_groupLabel_1noza_43";
@@ -1079,7 +1746,7 @@ const item$1 = "_item_1noza_53";
1079
1746
  const itemActive = "_itemActive_1noza_54";
1080
1747
  const itemIcon = "_itemIcon_1noza_79";
1081
1748
  const itemTitle = "_itemTitle_1noza_102";
1082
- const styles$6 = {
1749
+ const styles$9 = {
1083
1750
  popupHost,
1084
1751
  menu: menu$1,
1085
1752
  groupLabel,
@@ -1268,11 +1935,11 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1268
1935
  );
1269
1936
  if (!items.length) return null;
1270
1937
  let optionIndex = -1;
1271
- return /* @__PURE__ */ jsx("div", { className: styles$6.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]) => {
1272
1939
  optionIndex += 1;
1273
1940
  const i = optionIndex;
1274
1941
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1275
- header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$6.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1942
+ header2 !== null ? /* @__PURE__ */ jsx("div", { className: styles$9.groupLabel, "aria-hidden": "true", children: header2 }) : null,
1276
1943
  /* @__PURE__ */ jsxs(
1277
1944
  "button",
1278
1945
  {
@@ -1280,7 +1947,7 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1280
1947
  role: "option",
1281
1948
  "aria-selected": i === index,
1282
1949
  title: item2.title,
1283
- className: i === index ? styles$6.itemActive : styles$6.item,
1950
+ className: i === index ? styles$9.itemActive : styles$9.item,
1284
1951
  tabIndex: -1,
1285
1952
  onMouseEnter: () => setIndex(i),
1286
1953
  onMouseDown: (e2) => {
@@ -1288,8 +1955,8 @@ const SlashMenuPopup = forwardRef(function SlashMenuPopup2({ items, query, menuL
1288
1955
  command(item2);
1289
1956
  },
1290
1957
  children: [
1291
- item2.icon != null ? /* @__PURE__ */ jsx("span", { className: styles$6.itemIcon, "aria-hidden": "true", children: item2.icon }) : /* @__PURE__ */ jsx("span", { className: styles$6.itemIcon, "aria-hidden": "true" }),
1292
- /* @__PURE__ */ jsx("span", { className: styles$6.itemTitle, children: item2.title })
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 })
1293
1960
  ]
1294
1961
  }
1295
1962
  )
@@ -1340,7 +2007,7 @@ const SlashMenu = Extension.create({
1340
2007
  menuLabel: ((_a = this.options.labels) == null ? void 0 : _a.menuLabel) ?? defaultSlashMenuLabels.menuLabel,
1341
2008
  command: props.command
1342
2009
  },
1343
- className: styles$6.popupHost
2010
+ className: styles$9.popupHost
1344
2011
  }
1345
2012
  );
1346
2013
  const pmStyle = getComputedStyle(props.editor.view.dom);
@@ -1392,7 +2059,7 @@ const rowKeys = "_rowKeys_ljnq6_127";
1392
2059
  const rowMd = "_rowMd_ljnq6_128";
1393
2060
  const keycap = "_keycap_ljnq6_138";
1394
2061
  const none = "_none_ljnq6_163";
1395
- const styles$5 = {
2062
+ const styles$8 = {
1396
2063
  drawer,
1397
2064
  closeBtn,
1398
2065
  head,
@@ -1420,6 +2087,10 @@ function buildShortcutGroups(labels) {
1420
2087
  { id: "underline", label: labels.underline, keys: ["Mod", "u"] },
1421
2088
  { id: "inline-code", label: labels.inlineCode, keys: ["Mod", "e"], markdown: { marker: "`x`" } },
1422
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"] },
1423
2094
  ...[1, 2, 3, 4, 5, 6].map((level) => ({
1424
2095
  id: `heading-${level}`,
1425
2096
  label: labels.headingLabel(level),
@@ -1433,6 +2104,7 @@ function buildShortcutGroups(labels) {
1433
2104
  id: "insert",
1434
2105
  title: labels.insertGroup,
1435
2106
  entries: [
2107
+ { id: "image-upload", label: labels.imageUpload, keys: ["Mod", "Shift", "i"] },
1436
2108
  { id: "blockquote", label: labels.blockquote, keys: ["Mod", "Shift", "b"], markdown: { marker: ">", terminator: "Space" } },
1437
2109
  { id: "bullet-list", label: labels.bulletList, keys: ["Mod", "Shift", "8"], markdown: { marker: "-", terminator: "Space" } },
1438
2110
  { id: "ordered-list", label: labels.orderedList, keys: ["Mod", "Shift", "7"], markdown: { marker: "1.", terminator: "Space" } },
@@ -1485,7 +2157,7 @@ function ShortcutPanel({ open, onClose, labels }) {
1485
2157
  return /* @__PURE__ */ jsxs(
1486
2158
  "aside",
1487
2159
  {
1488
- className: styles$5.drawer,
2160
+ className: styles$8.drawer,
1489
2161
  role: "dialog",
1490
2162
  "aria-modal": "false",
1491
2163
  "aria-label": t.panelTitle,
@@ -1494,27 +2166,27 @@ function ShortcutPanel({ open, onClose, labels }) {
1494
2166
  "button",
1495
2167
  {
1496
2168
  type: "button",
1497
- className: styles$5.closeBtn,
2169
+ className: styles$8.closeBtn,
1498
2170
  title: t.close,
1499
2171
  "aria-label": t.close,
1500
2172
  onClick: onClose,
1501
2173
  children: /* @__PURE__ */ jsx(XIcon, { size: 16 })
1502
2174
  }
1503
2175
  ),
1504
- /* @__PURE__ */ jsxs("div", { className: styles$5.head, children: [
1505
- /* @__PURE__ */ jsx("span", { className: styles$5.colFormat, children: t.colFormat }),
1506
- /* @__PURE__ */ jsx("span", { className: styles$5.colShortcut, children: t.colShortcut }),
1507
- /* @__PURE__ */ jsx("span", { className: styles$5.colMarkdown, children: t.colMarkdown })
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 })
1508
2180
  ] }),
1509
- /* @__PURE__ */ jsx("div", { className: styles$5.body, children: groups.map((group2) => /* @__PURE__ */ jsxs("section", { className: styles$5.group, children: [
1510
- /* @__PURE__ */ jsx("h3", { className: styles$5.groupTitle, children: group2.title }),
1511
- group2.entries.map((entry) => /* @__PURE__ */ jsxs("div", { className: styles$5.row, children: [
1512
- /* @__PURE__ */ jsx("span", { className: styles$5.rowLabel, children: entry.label }),
1513
- /* @__PURE__ */ jsx("span", { className: styles$5.rowKeys, children: entry.keys ? entry.keys.map((key, i) => /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: keycapText(key, mac) }, i)) : /* @__PURE__ */ jsx("span", { className: styles$5.none, children: "—" }) }),
1514
- /* @__PURE__ */ jsx("span", { className: styles$5.rowMd, children: entry.markdown ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
1515
- /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: entry.markdown.marker }),
1516
- entry.markdown.terminator ? /* @__PURE__ */ jsx("kbd", { className: styles$5.keycap, children: entry.markdown.terminator }) : null
1517
- ] }) : /* @__PURE__ */ jsx("span", { className: styles$5.none, children: "—" }) })
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: "—" }) })
1518
2190
  ] }, entry.id))
1519
2191
  ] }, group2.id)) })
1520
2192
  ]
@@ -1631,18 +2303,18 @@ function selectionKind(selection) {
1631
2303
  if (selection instanceof TextSelection) return "text";
1632
2304
  return "text";
1633
2305
  }
1634
- function looksLikeMarkdown(text) {
1635
- return /^#{1,6}\s/m.test(text) || // 标题
1636
- /\*\*[^*\n]+\*\*/.test(text) || // 加粗
1637
- /(^|[^!])\[[^\]\n]+\]\([^)\n]+\)/.test(text) || // 链接
1638
- /!\[[^\]\n]*\]\([^)\n]+\)/.test(text) || // 图片
1639
- /^[-*+]\s+\S/m.test(text) || // 无序列表
1640
- /^\d+\.\s+\S/m.test(text) || // 有序列表
1641
- /^>\s/m.test(text) || // 引用
1642
- /^```/m.test(text) || // 代码围栏
1643
- /^\|.+\|\s*$/m.test(text) || // 表格行
1644
- /^(-{3,}|\*{3,})\s*$/m.test(text) || // 分割线
1645
- /<!--\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);
1646
2318
  }
1647
2319
  const MarkdownPaste = Extension.create({
1648
2320
  name: "markdownPaste",
@@ -1655,16 +2327,16 @@ const MarkdownPaste = Extension.create({
1655
2327
  handlePaste(view, event) {
1656
2328
  const clipboard = event.clipboardData;
1657
2329
  if (!clipboard) return false;
1658
- const text = clipboard.getData("text/plain");
1659
- if (!text) return false;
2330
+ const text2 = clipboard.getData("text/plain");
2331
+ if (!text2) return false;
1660
2332
  const input2 = view.input;
1661
2333
  if (input2 == null ? void 0 : input2.shiftKey) return false;
1662
2334
  if (view.state.selection.$from.parent.type.spec.code) return false;
1663
- if (!looksLikeMarkdown(text)) return false;
2335
+ if (!looksLikeMarkdown(text2)) return false;
1664
2336
  const markdown = editor.markdown;
1665
2337
  if (!markdown) return false;
1666
2338
  try {
1667
- const json = markdown.parse(prepareChartMarkdown(text));
2339
+ const json = markdown.parse(prepareChartMarkdown(text2));
1668
2340
  editor.commands.insertContent(json);
1669
2341
  return true;
1670
2342
  } catch (err) {
@@ -1818,7 +2490,7 @@ const gutterLine = "_gutterLine_k8th1_184";
1818
2490
  const readonlyActions = "_readonlyActions_k8th1_188";
1819
2491
  const actionBtn = "_actionBtn_k8th1_194";
1820
2492
  const langBraces = "_langBraces_k8th1_213";
1821
- const styles$4 = {
2493
+ const styles$7 = {
1822
2494
  wrapper,
1823
2495
  header: header$1,
1824
2496
  langTrigger,
@@ -1896,18 +2568,18 @@ function CodeBlockView({
1896
2568
  }, [readonly2]);
1897
2569
  const handleCopy = () => {
1898
2570
  var _a2;
1899
- const text = node.textContent ?? "";
2571
+ const text2 = node.textContent ?? "";
1900
2572
  const done = () => {
1901
2573
  setCopied(true);
1902
2574
  window.setTimeout(() => setCopied(false), 1500);
1903
2575
  };
1904
2576
  if ((_a2 = navigator.clipboard) == null ? void 0 : _a2.writeText) {
1905
- navigator.clipboard.writeText(text).then(done, () => {
2577
+ navigator.clipboard.writeText(text2).then(done, () => {
1906
2578
  });
1907
2579
  return;
1908
2580
  }
1909
2581
  const ta = document.createElement("textarea");
1910
- ta.value = text;
2582
+ ta.value = text2;
1911
2583
  document.body.appendChild(ta);
1912
2584
  ta.select();
1913
2585
  try {
@@ -1918,29 +2590,29 @@ function CodeBlockView({
1918
2590
  ta.remove();
1919
2591
  };
1920
2592
  const wrapperClass = [
1921
- styles$4.wrapper,
1922
- readonly2 ? styles$4.readonly : "",
1923
- folded2 ? styles$4.folded : ""
2593
+ styles$7.wrapper,
2594
+ readonly2 ? styles$7.readonly : "",
2595
+ folded2 ? styles$7.folded : ""
1924
2596
  ].filter(Boolean).join(" ");
1925
2597
  return /* @__PURE__ */ jsxs(NodeViewWrapper, { className: wrapperClass, children: [
1926
- editable ? /* @__PURE__ */ jsxs("div", { className: styles$4.header, contentEditable: false, children: [
2598
+ editable ? /* @__PURE__ */ jsxs("div", { className: styles$7.header, contentEditable: false, children: [
1927
2599
  /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
1928
2600
  /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1929
2601
  "button",
1930
2602
  {
1931
2603
  type: "button",
1932
- className: styles$4.langTrigger,
2604
+ className: styles$7.langTrigger,
1933
2605
  "aria-label": "Code language",
1934
2606
  children: [
1935
2607
  /* @__PURE__ */ jsx("span", { children: currentLabel }),
1936
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$4.langChevron })
2608
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14, className: styles$7.langChevron })
1937
2609
  ]
1938
2610
  }
1939
2611
  ) }),
1940
2612
  /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
1941
2613
  DropdownMenu.Content,
1942
2614
  {
1943
- className: styles$4.langMenu,
2615
+ className: styles$7.langMenu,
1944
2616
  sideOffset: 4,
1945
2617
  align: "end",
1946
2618
  children: LANGUAGES.map((l) => {
@@ -1949,10 +2621,10 @@ function CodeBlockView({
1949
2621
  return /* @__PURE__ */ jsxs(
1950
2622
  DropdownMenu.Item,
1951
2623
  {
1952
- className: `${styles$4.langItem}${selected ? ` ${styles$4.langItemSelected}` : ""}`,
2624
+ className: `${styles$7.langItem}${selected ? ` ${styles$7.langItemSelected}` : ""}`,
1953
2625
  onSelect: () => updateAttributes({ language: l.value }),
1954
2626
  children: [
1955
- /* @__PURE__ */ jsx("span", { className: styles$4.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 }),
1956
2628
  optionLabel
1957
2629
  ]
1958
2630
  },
@@ -1966,7 +2638,7 @@ function CodeBlockView({
1966
2638
  "button",
1967
2639
  {
1968
2640
  type: "button",
1969
- className: styles$4.deleteBtn,
2641
+ className: styles$7.deleteBtn,
1970
2642
  title: labels.delete,
1971
2643
  "aria-label": labels.delete,
1972
2644
  onClick: () => deleteNode(),
@@ -1975,17 +2647,17 @@ function CodeBlockView({
1975
2647
  )
1976
2648
  ] }) : (
1977
2649
  // 只读头部:左侧语言标签,右侧复制 + 展开收起(展开后按钮保留,供收回)
1978
- /* @__PURE__ */ jsxs("div", { className: styles$4.readonlyHeader, contentEditable: false, children: [
1979
- /* @__PURE__ */ jsxs("span", { className: styles$4.langBadge, children: [
1980
- /* @__PURE__ */ jsx("span", { className: styles$4.langBraces, children: "{}" }),
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: "{}" }),
1981
2653
  currentLabel
1982
2654
  ] }),
1983
- /* @__PURE__ */ jsxs("span", { className: styles$4.readonlyActions, children: [
2655
+ /* @__PURE__ */ jsxs("span", { className: styles$7.readonlyActions, children: [
1984
2656
  /* @__PURE__ */ jsx(
1985
2657
  "button",
1986
2658
  {
1987
2659
  type: "button",
1988
- className: styles$4.actionBtn,
2660
+ className: styles$7.actionBtn,
1989
2661
  onClick: handleCopy,
1990
2662
  "aria-label": labels.copy,
1991
2663
  title: labels.copy,
@@ -1996,7 +2668,7 @@ function CodeBlockView({
1996
2668
  "button",
1997
2669
  {
1998
2670
  type: "button",
1999
- className: styles$4.actionBtn,
2671
+ className: styles$7.actionBtn,
2000
2672
  onClick: () => setFolded((v) => !v),
2001
2673
  "aria-label": folded2 ? labels.expand : labels.collapse,
2002
2674
  title: folded2 ? labels.expand : labels.collapse,
@@ -2007,14 +2679,14 @@ function CodeBlockView({
2007
2679
  ] })
2008
2680
  ] })
2009
2681
  ),
2010
- /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$4.pre, children: [
2682
+ /* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$7.pre, children: [
2011
2683
  readonly2 ? /* @__PURE__ */ jsx(
2012
2684
  "span",
2013
2685
  {
2014
- className: styles$4.gutter,
2686
+ className: styles$7.gutter,
2015
2687
  contentEditable: false,
2016
2688
  "aria-hidden": "true",
2017
- children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$4.gutterLine, children: i + 1 }, i))
2689
+ children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$7.gutterLine, children: i + 1 }, i))
2018
2690
  }
2019
2691
  ) : null,
2020
2692
  /* @__PURE__ */ jsx(NodeViewContent, { as: "code" })
@@ -2059,6 +2731,34 @@ const CodeBlock = CodeBlockLowlight.extend({
2059
2731
  }
2060
2732
  });
2061
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,
2062
2762
  addKeyboardShortcuts() {
2063
2763
  return {
2064
2764
  Backspace: () => {
@@ -2074,7 +2774,74 @@ const ImageWithConfirmDelete = Image.extend({
2074
2774
  }
2075
2775
  }
2076
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);
2077
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;
2078
2845
  };
2079
2846
  }
2080
2847
  });
@@ -2089,6 +2856,13 @@ function findBarOffsetStyle(offset) {
2089
2856
  left: px(offset.left)
2090
2857
  };
2091
2858
  }
2859
+ function editorOwnsKeyboard(editor) {
2860
+ const active2 = document.activeElement;
2861
+ const inEditor = !!active2 && editor.view.dom.contains(active2);
2862
+ if (inEditor || editor.isFocused) return true;
2863
+ const nothingFocused = active2 === null || active2 === document.body;
2864
+ return nothingFocused && document.querySelectorAll(".ProseMirror").length <= 1;
2865
+ }
2092
2866
  const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2093
2867
  initialMarkdown = "",
2094
2868
  editable = true,
@@ -2117,11 +2891,14 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2117
2891
  findBarOffset = DEFAULT_FIND_BAR_OFFSET,
2118
2892
  findShortcut = true,
2119
2893
  findLabels,
2894
+ onFindOpenChange,
2120
2895
  slashMenu = true,
2121
2896
  slashMenuLabels,
2122
2897
  shortcutPanel = true,
2123
2898
  shortcutLabels,
2124
- shortcutFabContainer
2899
+ shortcutFabContainer,
2900
+ imageUpload,
2901
+ imageResize = true
2125
2902
  }, ref) {
2126
2903
  const preparedInitial = prepareChartMarkdown(
2127
2904
  enrichMarkdownCitations(initialMarkdown, sources ?? [])
@@ -2133,7 +2910,24 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2133
2910
  extensions: [
2134
2911
  ...baseExtensions,
2135
2912
  CodeBlock.configure({ lowlight, codeBlockLabels }),
2136
- 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)] : [],
2137
2931
  ImportPlaceholder,
2138
2932
  // 空文档占位符:官方 Placeholder 把 data-placeholder 属性与
2139
2933
  // is-empty / is-editor-empty 类打在**空文本块节点**上——CSS
@@ -2177,7 +2971,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2177
2971
  immediatelyRender: false,
2178
2972
  editorProps: {
2179
2973
  attributes: {
2180
- class: styles$8.editorContent
2974
+ class: styles$c.editorContent
2181
2975
  }
2182
2976
  }
2183
2977
  });
@@ -2188,10 +2982,40 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2188
2982
  useEffect(() => {
2189
2983
  editor == null ? void 0 : editor.setEditable(editable);
2190
2984
  }, [editor, editable]);
2985
+ const openFind = useCallback(() => {
2986
+ setFindOpen(true);
2987
+ requestAnimationFrame(() => {
2988
+ var _a;
2989
+ return (_a = findInputRef.current) == null ? void 0 : _a.select();
2990
+ });
2991
+ }, []);
2191
2992
  const closeFind = useCallback(() => {
2192
2993
  setFindOpen(false);
2193
2994
  editor == null ? void 0 : editor.commands.focus();
2194
2995
  }, [editor]);
2996
+ const toggleFind = useCallback(() => {
2997
+ if (findOpen) closeFind();
2998
+ else openFind();
2999
+ }, [findOpen, closeFind, openFind]);
3000
+ const findBarOpen = findOpen && findBar && findReplace;
3001
+ const onFindOpenChangeRef = useRef(onFindOpenChange);
3002
+ onFindOpenChangeRef.current = onFindOpenChange;
3003
+ const notifiedFindOpenRef = useRef(false);
3004
+ useEffect(() => {
3005
+ var _a;
3006
+ if (notifiedFindOpenRef.current === findBarOpen) return;
3007
+ notifiedFindOpenRef.current = findBarOpen;
3008
+ (_a = onFindOpenChangeRef.current) == null ? void 0 : _a.call(onFindOpenChangeRef, findBarOpen);
3009
+ }, [findBarOpen]);
3010
+ const findBarOpenRef = useRef(findBarOpen);
3011
+ findBarOpenRef.current = findBarOpen;
3012
+ useEffect(
3013
+ () => () => {
3014
+ var _a;
3015
+ if (findBarOpenRef.current) (_a = onFindOpenChangeRef.current) == null ? void 0 : _a.call(onFindOpenChangeRef, false);
3016
+ },
3017
+ []
3018
+ );
2195
3019
  useEffect(() => {
2196
3020
  if (!editor || !findReplace || !findBar || !findShortcut) return;
2197
3021
  const onKeyDown = (event) => {
@@ -2199,24 +3023,27 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2199
3023
  return;
2200
3024
  }
2201
3025
  if (event.key !== "f" && event.key !== "F") return;
2202
- const active2 = document.activeElement;
2203
- const inEditor = !!active2 && editor.view.dom.contains(active2);
2204
- const nothingFocused = active2 === null || active2 === document.body;
2205
- const soleEditor = document.querySelectorAll(".ProseMirror").length <= 1;
2206
- if (!inEditor && !editor.isFocused && !(nothingFocused && soleEditor)) {
2207
- return;
2208
- }
3026
+ if (!editorOwnsKeyboard(editor)) return;
2209
3027
  event.preventDefault();
2210
- setFindOpen(true);
2211
- requestAnimationFrame(() => {
2212
- var _a;
2213
- return (_a = findInputRef.current) == null ? void 0 : _a.select();
2214
- });
3028
+ openFind();
2215
3029
  };
2216
3030
  document.addEventListener("keydown", onKeyDown, true);
2217
3031
  return () => document.removeEventListener("keydown", onKeyDown, true);
2218
- }, [editor, findReplace, findBar, findShortcut]);
2219
- const commentsSignatureRef = useRef("");
3032
+ }, [editor, findReplace, findBar, findShortcut, openFind]);
3033
+ useEffect(() => {
3034
+ if (!editor || !findBarOpen) return;
3035
+ const onKeyDown = (event) => {
3036
+ if (event.key !== "Escape") return;
3037
+ if (isComposingKeyEvent(event)) return;
3038
+ if (!editorOwnsKeyboard(editor)) return;
3039
+ event.preventDefault();
3040
+ event.stopPropagation();
3041
+ closeFind();
3042
+ };
3043
+ document.addEventListener("keydown", onKeyDown);
3044
+ return () => document.removeEventListener("keydown", onKeyDown);
3045
+ }, [editor, findBarOpen, closeFind]);
3046
+ const commentsSignatureRef = useRef("");
2220
3047
  useEffect(() => {
2221
3048
  if (!editor || !editable) return;
2222
3049
  const signature = (comments ?? []).map((c) => `${c.commentId}:${c.segments.length}`).join("|");
@@ -2323,10 +3150,11 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2323
3150
  focusComment: (commentId) => editor ? focusComment(editor, commentId) : false,
2324
3151
  nextComment: (dir) => editor ? nextComment(editor, dir ?? "next") : null,
2325
3152
  getCommentIds: () => editor ? collectCommentIds(editor) : [],
2326
- openFind: () => setFindOpen(true),
2327
- closeFind
3153
+ openFind: () => openFind(),
3154
+ closeFind,
3155
+ toggleFind: () => toggleFind()
2328
3156
  }),
2329
- [editor, closeFind]
3157
+ [editor, closeFind, openFind, toggleFind]
2330
3158
  );
2331
3159
  const findBarTarget = typeof findBarContainer === "function" ? findBarContainer() : findBarContainer ?? null;
2332
3160
  useEffect(() => {
@@ -2342,7 +3170,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2342
3170
  labels: findLabels,
2343
3171
  onClose: closeFind,
2344
3172
  inputRef: findInputRef,
2345
- className: styles$8.findBar,
3173
+ className: styles$c.findBar,
2346
3174
  style: findBarOffsetStyle(findBarOffset)
2347
3175
  }
2348
3176
  ) : null;
@@ -2362,7 +3190,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2362
3190
  "button",
2363
3191
  {
2364
3192
  type: "button",
2365
- className: shortcutFabTarget ? `${styles$8.shortcutFab} ${styles$8.shortcutFabHosted}` : styles$8.shortcutFab,
3193
+ className: shortcutFabTarget ? `${styles$c.shortcutFab} ${styles$c.shortcutFabHosted}` : styles$c.shortcutFab,
2366
3194
  title: shortcutT.panelTitle,
2367
3195
  "aria-label": shortcutT.panelTitle,
2368
3196
  "aria-expanded": shortcutsOpen,
@@ -2370,14 +3198,14 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
2370
3198
  children: /* @__PURE__ */ jsx(KeyboardIcon, { size: 18 })
2371
3199
  }
2372
3200
  ) : null;
2373
- return /* @__PURE__ */ jsxs("div", { className: styles$8.editorHost, children: [
2374
- findBarNode && !findBarTarget ? /* @__PURE__ */ jsx("div", { className: styles$8.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,
2375
3203
  findBarNode && findBarTarget ? createPortal(findBarNode, findBarTarget) : null,
2376
3204
  /* @__PURE__ */ jsx(
2377
3205
  EditorContent,
2378
3206
  {
2379
3207
  editor,
2380
- className: className ? `${styles$8.editorScroll} ${className}` : styles$8.editorScroll
3208
+ className: className ? `${styles$c.editorScroll} ${className}` : styles$c.editorScroll
2381
3209
  }
2382
3210
  ),
2383
3211
  shortcutFabNode && shortcutFabTarget ? createPortal(shortcutFabNode, shortcutFabTarget) : shortcutFabNode,
@@ -2430,7 +3258,7 @@ function MarkdownPreview({
2430
3258
  editable: false,
2431
3259
  immediatelyRender: false,
2432
3260
  editorProps: {
2433
- attributes: { class: styles$8.editorContent }
3261
+ attributes: { class: styles$c.editorContent }
2434
3262
  }
2435
3263
  },
2436
3264
  [extensions]
@@ -2443,7 +3271,7 @@ function MarkdownPreview({
2443
3271
  EditorContent,
2444
3272
  {
2445
3273
  editor,
2446
- className: className ?? styles$8.editorScroll
3274
+ className: className ?? styles$c.editorScroll
2447
3275
  }
2448
3276
  );
2449
3277
  }
@@ -2491,11 +3319,11 @@ function tryInsertMarkdown(editor, markdown) {
2491
3319
  return false;
2492
3320
  }
2493
3321
  }
2494
- function insertPlainParagraph(editor, text) {
2495
- if (!text) return;
3322
+ function insertPlainParagraph(editor, text2) {
3323
+ if (!text2) return;
2496
3324
  editor.chain().focus().insertContent({
2497
3325
  type: "paragraph",
2498
- content: [{ type: "text", text }]
3326
+ content: [{ type: "text", text: text2 }]
2499
3327
  }).run();
2500
3328
  }
2501
3329
  function splitTopLevelBlocks(markdown) {
@@ -2515,150 +3343,61 @@ function splitTopLevelBlocks(markdown) {
2515
3343
  function stripToPlainText(markdown) {
2516
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();
2517
3345
  }
2518
- function getTableSelectionInfo(state) {
2519
- if (!isInTable(state)) return null;
2520
- const rect = selectedRect(state);
2521
- const rowCount = Math.max(1, rect.bottom - rect.top);
2522
- const colCount = Math.max(1, rect.right - rect.left);
2523
- let includesHeaderRow = false;
2524
- for (let row2 = rect.top; row2 < rect.bottom; row2++) {
2525
- if (rowIsHeader(rect.map, rect.table, row2)) {
2526
- includesHeaderRow = true;
2527
- break;
2528
- }
2529
- }
2530
- return {
2531
- rowCount,
2532
- colCount,
2533
- isMultiCell: rowCount > 1 || colCount > 1,
2534
- includesHeaderRow,
2535
- coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,
2536
- coversAllCols: rect.left === 0 && rect.right === rect.map.width
2537
- };
2538
- }
2539
- function isPosInCellSelection(selection, pos) {
2540
- let found = false;
2541
- selection.forEachCell((node, cellPos) => {
2542
- if (pos >= cellPos && pos <= cellPos + node.nodeSize) {
2543
- found = true;
2544
- }
2545
- });
2546
- return found;
2547
- }
2548
- function preserveTableSelectionOnContextMenu(editor, pos) {
2549
- const { selection } = editor.state;
2550
- if (selection instanceof CellSelection && isPosInCellSelection(selection, pos)) {
2551
- editor.view.focus();
2552
- return;
2553
- }
2554
- editor.chain().focus().setTextSelection(pos).run();
2555
- }
2556
- function addRowsBefore(editor, count) {
2557
- const n = Math.max(1, count);
2558
- for (let i = 0; i < n; i++) {
2559
- if (!editor.commands.addRowBefore()) return false;
2560
- }
2561
- return true;
2562
- }
2563
- function addRowsAfter(editor, count) {
2564
- const n = Math.max(1, count);
2565
- for (let i = 0; i < n; i++) {
2566
- if (!editor.commands.addRowAfter()) return false;
2567
- }
2568
- return true;
2569
- }
2570
- function addColumnsBefore(editor, count) {
2571
- const n = Math.max(1, count);
2572
- for (let i = 0; i < n; i++) {
2573
- if (!editor.commands.addColumnBefore()) return false;
2574
- }
2575
- return true;
2576
- }
2577
- function addColumnsAfter(editor, count) {
2578
- const n = Math.max(1, count);
2579
- for (let i = 0; i < n; i++) {
2580
- if (!editor.commands.addColumnAfter()) return false;
2581
- }
2582
- return true;
2583
- }
2584
- function deleteSelectedRows(editor) {
2585
- const info = getTableSelectionInfo(editor.state);
2586
- if (!info) return false;
2587
- if (info.coversAllRows) return editor.commands.deleteTable();
2588
- return editor.commands.deleteRow();
2589
- }
2590
- function deleteSelectedColumns(editor) {
2591
- const info = getTableSelectionInfo(editor.state);
2592
- if (!info) return false;
2593
- if (info.coversAllCols) {
2594
- if (info.coversAllRows) return editor.commands.deleteTable();
2595
- return false;
2596
- }
2597
- return editor.commands.deleteColumn();
2598
- }
2599
- const toolbar = "_toolbar_1f7fb_2";
2600
- const inner = "_inner_1f7fb_15";
2601
- const btn = "_btn_1f7fb_27";
2602
- const btnActive = "_btnActive_1f7fb_50";
2603
- const tableBubble = "_tableBubble_1f7fb_66";
2604
- const tableMenuItem = "_tableMenuItem_1f7fb_77";
2605
- const tableMenuItemIcon = "_tableMenuItemIcon_1f7fb_103";
2606
- const tableMenuItemLabel = "_tableMenuItemLabel_1f7fb_113";
2607
- const tableMenuDivider = "_tableMenuDivider_1f7fb_118";
2608
- const txtIcon = "_txtIcon_1f7fb_126";
2609
- const colorIcon = "_colorIcon_1f7fb_134";
2610
- const colorIconGlyph = "_colorIconGlyph_1f7fb_142";
2611
- const colorIconBar = "_colorIconBar_1f7fb_148";
2612
- const scriptTrigger = "_scriptTrigger_1f7fb_155";
2613
- const scriptTriggerGlyph = "_scriptTriggerGlyph_1f7fb_175";
2614
- const divider = "_divider_1f7fb_183";
2615
- const styleTrigger = "_styleTrigger_1f7fb_192";
2616
- const styleTriggerLabel = "_styleTriggerLabel_1f7fb_221";
2617
- const styleTriggerCaret = "_styleTriggerCaret_1f7fb_229";
2618
- const styleItem = "_styleItem_1f7fb_235";
2619
- const styleIcon = "_styleIcon_1f7fb_241";
2620
- const scriptGlyph = "_scriptGlyph_1f7fb_251";
2621
- const menu = "_menu_1f7fb_263";
2622
- const menuItem = "_menuItem_1f7fb_274";
2623
- const menuItemSelected = "_menuItemSelected_1f7fb_301";
2624
- const tableInsertCaret = "_tableInsertCaret_1f7fb_314";
2625
- const tableSizePicker = "_tableSizePicker_1f7fb_322";
2626
- const tableSizeGrid = "_tableSizeGrid_1f7fb_332";
2627
- const tableSizeCell = "_tableSizeCell_1f7fb_337";
2628
- const tableSizeCellActive = "_tableSizeCellActive_1f7fb_347";
2629
- const tableSizeLabel = "_tableSizeLabel_1f7fb_352";
2630
- const popoverContent$1 = "_popoverContent_1f7fb_361";
2631
- const mathLayer = "_mathLayer_1f7fb_365";
2632
- const mathStack = "_mathStack_1f7fb_370";
2633
- const mathStackBlock = "_mathStackBlock_1f7fb_377";
2634
- const mathHint = "_mathHint_1f7fb_382";
2635
- const mathHintBlock = "_mathHintBlock_1f7fb_394";
2636
- const mathHintIcon = "_mathHintIcon_1f7fb_400";
2637
- const mathField = "_mathField_1f7fb_431";
2638
- const mathFieldBlock = "_mathFieldBlock_1f7fb_443";
2639
- const mathInput = "_mathInput_1f7fb_450";
2640
- const mathDone = "_mathDone_1f7fb_468";
2641
- const mathDoneKbd = "_mathDoneKbd_1f7fb_493";
2642
- const styles$3 = {
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 = {
2643
3386
  toolbar,
2644
3387
  inner,
2645
- btn,
2646
- btnActive,
2647
- tableBubble,
2648
- tableMenuItem,
2649
- tableMenuItemIcon,
2650
- tableMenuItemLabel,
2651
- tableMenuDivider,
3388
+ btn: btn$2,
3389
+ btnActive: btnActive$1,
2652
3390
  txtIcon,
2653
3391
  colorIcon,
2654
3392
  colorIconGlyph,
2655
3393
  colorIconBar,
2656
3394
  scriptTrigger,
2657
3395
  scriptTriggerGlyph,
2658
- divider,
3396
+ divider: divider$2,
2659
3397
  styleTrigger,
2660
3398
  styleTriggerLabel,
2661
3399
  styleTriggerCaret,
3400
+ iconTrigger,
2662
3401
  styleItem,
2663
3402
  styleIcon,
2664
3403
  scriptGlyph,
@@ -2693,7 +3432,7 @@ const swatch = "_swatch_x5lrq_54";
2693
3432
  const swatchActive = "_swatchActive_x5lrq_70";
2694
3433
  const themeLabel = "_themeLabel_x5lrq_76";
2695
3434
  const themeRow = "_themeRow_x5lrq_84";
2696
- const styles$2 = {
3435
+ const styles$5 = {
2697
3436
  palette,
2698
3437
  noneRow,
2699
3438
  noneIcon,
@@ -2716,25 +3455,25 @@ const THEME_COLORS = ["#ff6719", "#ff5500"];
2716
3455
  function ColorPalette({ value, onPick, labels }) {
2717
3456
  const t = { ...defaultColorPaletteLabels, ...labels };
2718
3457
  const current = value == null ? void 0 : value.toLowerCase();
2719
- return /* @__PURE__ */ jsxs("div", { className: styles$2.palette, children: [
3458
+ return /* @__PURE__ */ jsxs("div", { className: styles$5.palette, children: [
2720
3459
  /* @__PURE__ */ jsxs(
2721
3460
  "button",
2722
3461
  {
2723
3462
  type: "button",
2724
- className: styles$2.noneRow,
3463
+ className: styles$5.noneRow,
2725
3464
  onMouseDown: (e2) => e2.preventDefault(),
2726
3465
  onClick: () => onPick(null),
2727
3466
  children: [
2728
- /* @__PURE__ */ jsx("span", { className: styles$2.noneIcon, "aria-hidden": true }),
2729
- /* @__PURE__ */ jsx("span", { className: styles$2.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 })
2730
3469
  ]
2731
3470
  }
2732
3471
  ),
2733
- /* @__PURE__ */ jsx("div", { className: styles$2.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
3472
+ /* @__PURE__ */ jsx("div", { className: styles$5.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
2734
3473
  "button",
2735
3474
  {
2736
3475
  type: "button",
2737
- className: `${styles$2.swatch} ${current === c.toLowerCase() ? styles$2.swatchActive : ""}`,
3476
+ className: `${styles$5.swatch} ${current === c.toLowerCase() ? styles$5.swatchActive : ""}`,
2738
3477
  style: { background: c },
2739
3478
  title: c,
2740
3479
  "aria-label": c,
@@ -2743,12 +3482,12 @@ function ColorPalette({ value, onPick, labels }) {
2743
3482
  },
2744
3483
  c
2745
3484
  )) }),
2746
- /* @__PURE__ */ jsx("div", { className: styles$2.themeLabel, children: t.theme }),
2747
- /* @__PURE__ */ jsx("div", { className: styles$2.themeRow, children: THEME_COLORS.map((c) => /* @__PURE__ */ jsx(
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(
2748
3487
  "button",
2749
3488
  {
2750
3489
  type: "button",
2751
- className: `${styles$2.swatch} ${current === c.toLowerCase() ? styles$2.swatchActive : ""}`,
3490
+ className: `${styles$5.swatch} ${current === c.toLowerCase() ? styles$5.swatchActive : ""}`,
2752
3491
  style: { background: c },
2753
3492
  title: c,
2754
3493
  "aria-label": c,
@@ -2759,6 +3498,1067 @@ function ColorPalette({ value, onPick, labels }) {
2759
3498
  )) })
2760
3499
  ] });
2761
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
+ }
3730
+ const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set([
3731
+ "http:",
3732
+ "https:",
3733
+ "ftp:",
3734
+ "ftps:",
3735
+ "mailto:",
3736
+ "tel:",
3737
+ "callto:",
3738
+ "sms:",
3739
+ "cid:",
3740
+ "xmpp:"
3741
+ ]);
3742
+ const HAS_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
3743
+ const SITE_RELATIVE_RE = /^[/#?]/;
3744
+ const HOST_PORT_RE = /^(localhost|127\.0\.0\.1|0\.0\.0\.0|\[[0-9a-f:]+\]):\d+($|[/#?])/i;
3745
+ const BARE_HOST_RE = /^[^/?#]*\.[^/?#]*/;
3746
+ function canSetLink(editor) {
3747
+ if (!editor || editor.isEditable === false) return false;
3748
+ try {
3749
+ return editor.can().setMark("link");
3750
+ } catch {
3751
+ return false;
3752
+ }
3753
+ }
3754
+ function isLinkActive(editor) {
3755
+ if (!editor) return false;
3756
+ return editor.isActive("link");
3757
+ }
3758
+ function readLinkHref(editor) {
3759
+ if (!editor) return "";
3760
+ const { href } = editor.getAttributes("link");
3761
+ return typeof href === "string" ? href : "";
3762
+ }
3763
+ function defaultProtocol(editor) {
3764
+ var _a, _b;
3765
+ const link = (_a = editor.extensionManager) == null ? void 0 : _a.extensions.find(
3766
+ (extension) => extension.name === "link"
3767
+ );
3768
+ const configured = (_b = link == null ? void 0 : link.options) == null ? void 0 : _b.defaultProtocol;
3769
+ return configured || "http";
3770
+ }
3771
+ function normalizeLinkHref(editor, raw) {
3772
+ const value = raw.trim();
3773
+ if (!value) return "";
3774
+ if (SITE_RELATIVE_RE.test(value)) return value;
3775
+ if (HOST_PORT_RE.test(value)) return `${defaultProtocol(editor)}://${value}`;
3776
+ if (HAS_SCHEME_RE.test(value)) return value;
3777
+ if (!BARE_HOST_RE.test(value)) return value;
3778
+ return `${defaultProtocol(editor)}://${value}`;
3779
+ }
3780
+ function applyLink(editor, raw) {
3781
+ if (!editor) return false;
3782
+ const href = normalizeLinkHref(editor, raw);
3783
+ if (!href) return false;
3784
+ if (!editor.can().setLink({ href })) return false;
3785
+ const isEmpty = editor.state.selection.empty;
3786
+ const insideLink = isLinkActive(editor);
3787
+ const chain = editor.chain().focus().extendMarkRange("link").setLink({ href });
3788
+ if (isEmpty && !insideLink) chain.insertContent({ type: "text", text: href });
3789
+ return chain.run();
3790
+ }
3791
+ function removeLink(editor) {
3792
+ if (!editor) return false;
3793
+ return editor.chain().focus().extendMarkRange("link").unsetLink().setMeta("preventAutolink", true).run();
3794
+ }
3795
+ function sanitizeLinkUrl(input2, baseUrl) {
3796
+ try {
3797
+ const url = new URL(input2, baseUrl);
3798
+ if (OPENABLE_PROTOCOLS.has(url.protocol)) return url.href;
3799
+ } catch {
3800
+ }
3801
+ return "#";
3802
+ }
3803
+ function openLinkUrl(input2, baseUrl) {
3804
+ if (!input2.trim()) return false;
3805
+ const safe = sanitizeLinkUrl(input2, baseUrl);
3806
+ if (safe === "#") return false;
3807
+ window.open(safe, "_blank", "noopener,noreferrer");
3808
+ return true;
3809
+ }
3810
+ function isApplyKey(event) {
3811
+ if (event.key !== "Enter") return false;
3812
+ return !isComposingKeyEvent(event.nativeEvent);
3813
+ }
3814
+ const panel = "_panel_qysb1_7";
3815
+ const field = "_field_qysb1_28";
3816
+ const fieldInvalid = "_fieldInvalid_qysb1_47";
3817
+ const input = "_input_qysb1_52";
3818
+ const divider = "_divider_qysb1_63";
3819
+ const btn = "_btn_qysb1_71";
3820
+ const apply = "_apply_qysb1_99";
3821
+ const styles$3 = {
3822
+ panel,
3823
+ field,
3824
+ fieldInvalid,
3825
+ input,
3826
+ divider,
3827
+ btn,
3828
+ apply
3829
+ };
3830
+ function LinkPopover({
3831
+ editor,
3832
+ trigger,
3833
+ labels,
3834
+ className,
3835
+ style
3836
+ }) {
3837
+ const [open, setOpen] = useState(false);
3838
+ return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange: setOpen, children: [
3839
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: trigger }),
3840
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3841
+ Popover.Content,
3842
+ {
3843
+ sideOffset: 4,
3844
+ align: "start",
3845
+ onCloseAutoFocus: (e2) => e2.preventDefault(),
3846
+ children: /* @__PURE__ */ jsx(
3847
+ LinkPanel,
3848
+ {
3849
+ editor,
3850
+ labels,
3851
+ className,
3852
+ style,
3853
+ onClose: () => setOpen(false)
3854
+ }
3855
+ )
3856
+ }
3857
+ ) })
3858
+ ] });
3859
+ }
3860
+ function LinkPanel({
3861
+ editor,
3862
+ labels,
3863
+ className,
3864
+ style,
3865
+ onClose
3866
+ }) {
3867
+ const t = { ...defaultLinkPopoverLabels, ...labels };
3868
+ const [url, setUrl] = useState(() => readLinkHref(editor));
3869
+ const [invalid, setInvalid] = useState(false);
3870
+ const canEdit = canSetLink(editor);
3871
+ const hasUrl = url.trim().length > 0;
3872
+ const keepFocus = (e2) => e2.preventDefault();
3873
+ const apply2 = () => {
3874
+ if (!applyLink(editor, url)) {
3875
+ setInvalid(true);
3876
+ return;
3877
+ }
3878
+ setInvalid(false);
3879
+ onClose();
3880
+ };
3881
+ const openInNewWindow = () => {
3882
+ openLinkUrl(normalizeLinkHref(editor, url), window.location.href);
3883
+ };
3884
+ const remove2 = () => {
3885
+ removeLink(editor);
3886
+ onClose();
3887
+ };
3888
+ const onInputKeyDown = (e2) => {
3889
+ if (!isApplyKey(e2)) return;
3890
+ e2.preventDefault();
3891
+ apply2();
3892
+ };
3893
+ return /* @__PURE__ */ jsxs(
3894
+ "div",
3895
+ {
3896
+ className: className ? `${styles$3.panel} ${className}` : styles$3.panel,
3897
+ style,
3898
+ "data-link-popover": "",
3899
+ role: "dialog",
3900
+ "aria-label": t.field,
3901
+ children: [
3902
+ /* @__PURE__ */ jsx("span", { className: `${styles$3.field}${invalid ? ` ${styles$3.fieldInvalid}` : ""}`, children: /* @__PURE__ */ jsx(
3903
+ "input",
3904
+ {
3905
+ className: styles$3.input,
3906
+ "data-link-field": "",
3907
+ "data-link-invalid": invalid ? "" : void 0,
3908
+ type: "url",
3909
+ value: url,
3910
+ onChange: (e2) => {
3911
+ setUrl(e2.target.value);
3912
+ setInvalid(false);
3913
+ },
3914
+ onKeyDown: onInputKeyDown,
3915
+ placeholder: t.field,
3916
+ "aria-label": t.field,
3917
+ "aria-invalid": invalid || void 0,
3918
+ title: invalid ? t.invalid : void 0,
3919
+ autoFocus: true,
3920
+ autoComplete: "off",
3921
+ autoCorrect: "off",
3922
+ autoCapitalize: "off",
3923
+ spellCheck: false
3924
+ }
3925
+ ) }),
3926
+ /* @__PURE__ */ jsx(
3927
+ "button",
3928
+ {
3929
+ type: "button",
3930
+ className: `${styles$3.btn} ${styles$3.apply}`,
3931
+ "data-link-action": "apply",
3932
+ title: t.apply,
3933
+ "aria-label": t.apply,
3934
+ disabled: !canEdit || !hasUrl,
3935
+ onMouseDown: keepFocus,
3936
+ onClick: apply2,
3937
+ children: /* @__PURE__ */ jsx(CheckIcon, { size: 16 })
3938
+ }
3939
+ ),
3940
+ /* @__PURE__ */ jsx("span", { className: styles$3.divider, "aria-hidden": "true" }),
3941
+ /* @__PURE__ */ jsx(
3942
+ "button",
3943
+ {
3944
+ type: "button",
3945
+ className: styles$3.btn,
3946
+ "data-link-action": "open",
3947
+ title: t.open,
3948
+ "aria-label": t.open,
3949
+ disabled: !hasUrl,
3950
+ onMouseDown: keepFocus,
3951
+ onClick: openInNewWindow,
3952
+ children: /* @__PURE__ */ jsx(ExternalLinkIcon, { size: 16 })
3953
+ }
3954
+ ),
3955
+ /* @__PURE__ */ jsx(
3956
+ "button",
3957
+ {
3958
+ type: "button",
3959
+ className: styles$3.btn,
3960
+ "data-link-action": "remove",
3961
+ title: t.remove,
3962
+ "aria-label": t.remove,
3963
+ disabled: !canEdit,
3964
+ onMouseDown: keepFocus,
3965
+ onClick: remove2,
3966
+ children: /* @__PURE__ */ jsx(TrashIcon, { size: 16 })
3967
+ }
3968
+ )
3969
+ ]
3970
+ }
3971
+ );
3972
+ }
3973
+ function getTableSelectionInfo(state) {
3974
+ if (!isInTable(state)) return null;
3975
+ const rect = selectedRect(state);
3976
+ const rowCount = Math.max(1, rect.bottom - rect.top);
3977
+ const colCount = Math.max(1, rect.right - rect.left);
3978
+ let includesHeaderRow = false;
3979
+ for (let row2 = rect.top; row2 < rect.bottom; row2++) {
3980
+ if (rowIsHeader(rect.map, rect.table, row2)) {
3981
+ includesHeaderRow = true;
3982
+ break;
3983
+ }
3984
+ }
3985
+ return {
3986
+ rowCount,
3987
+ colCount,
3988
+ isMultiCell: rowCount > 1 || colCount > 1,
3989
+ includesHeaderRow,
3990
+ coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,
3991
+ coversAllCols: rect.left === 0 && rect.right === rect.map.width
3992
+ };
3993
+ }
3994
+ function isPosInCellSelection(selection, pos) {
3995
+ let found = false;
3996
+ selection.forEachCell((node, cellPos) => {
3997
+ if (pos >= cellPos && pos <= cellPos + node.nodeSize) {
3998
+ found = true;
3999
+ }
4000
+ });
4001
+ return found;
4002
+ }
4003
+ function addRowsBefore(editor, count) {
4004
+ const n = Math.max(1, count);
4005
+ for (let i = 0; i < n; i++) {
4006
+ if (!editor.commands.addRowBefore()) return false;
4007
+ }
4008
+ return true;
4009
+ }
4010
+ function addRowsAfter(editor, count) {
4011
+ const n = Math.max(1, count);
4012
+ for (let i = 0; i < n; i++) {
4013
+ if (!editor.commands.addRowAfter()) return false;
4014
+ }
4015
+ return true;
4016
+ }
4017
+ function addColumnsBefore(editor, count) {
4018
+ const n = Math.max(1, count);
4019
+ for (let i = 0; i < n; i++) {
4020
+ if (!editor.commands.addColumnBefore()) return false;
4021
+ }
4022
+ return true;
4023
+ }
4024
+ function addColumnsAfter(editor, count) {
4025
+ const n = Math.max(1, count);
4026
+ for (let i = 0; i < n; i++) {
4027
+ if (!editor.commands.addColumnAfter()) return false;
4028
+ }
4029
+ return true;
4030
+ }
4031
+ function deleteSelectedRows(editor) {
4032
+ const info = getTableSelectionInfo(editor.state);
4033
+ if (!info) return false;
4034
+ if (info.coversAllRows) return editor.commands.deleteTable();
4035
+ return editor.commands.deleteRow();
4036
+ }
4037
+ function deleteSelectedColumns(editor) {
4038
+ const info = getTableSelectionInfo(editor.state);
4039
+ if (!info) return false;
4040
+ if (info.coversAllCols) {
4041
+ if (info.coversAllRows) return editor.commands.deleteTable();
4042
+ return false;
4043
+ }
4044
+ return editor.commands.deleteColumn();
4045
+ }
4046
+ const STRUCTURAL_CELL_ATTRS = /* @__PURE__ */ new Set(["colspan", "rowspan"]);
4047
+ function selectedCellEntries(editor) {
4048
+ const { selection } = editor.state;
4049
+ const entries = [];
4050
+ if (selection instanceof CellSelection) {
4051
+ selection.forEachCell((node2, pos2) => {
4052
+ entries.push({ pos: pos2, node: node2 });
4053
+ });
4054
+ return entries;
4055
+ }
4056
+ const $cell = cellAround(selection.$from);
4057
+ if (!$cell) return entries;
4058
+ const pos = $cell.before($cell.depth);
4059
+ const node = editor.state.doc.nodeAt(pos);
4060
+ if (node) entries.push({ pos, node });
4061
+ return entries;
4062
+ }
4063
+ function clearSelectedCellContents(editor) {
4064
+ var _a;
4065
+ const entries = selectedCellEntries(editor);
4066
+ if (!entries.length) return false;
4067
+ const paragraph = editor.state.schema.nodes.paragraph;
4068
+ if (!paragraph) return false;
4069
+ const tr = editor.state.tr;
4070
+ for (const { pos, node } of [...entries].sort((a3, b3) => b3.pos - a3.pos)) {
4071
+ const isEmpty = node.childCount === 1 && !!((_a = node.firstChild) == null ? void 0 : _a.isTextblock) && node.firstChild.content.size === 0;
4072
+ if (isEmpty) continue;
4073
+ tr.replaceWith(pos + 1, pos + node.nodeSize - 1, paragraph.createAndFill());
4074
+ }
4075
+ if (!tr.docChanged) return false;
4076
+ editor.view.dispatch(tr.scrollIntoView());
4077
+ return true;
4078
+ }
4079
+ function resetSelectedCellStyles(editor) {
4080
+ const entries = selectedCellEntries(editor);
4081
+ if (!entries.length) return false;
4082
+ const tr = editor.state.tr;
4083
+ for (const { pos, node } of entries) {
4084
+ const attrs = node.type.spec.attrs ?? {};
4085
+ const next = { ...node.attrs };
4086
+ let changed = false;
4087
+ for (const [key, spec] of Object.entries(attrs)) {
4088
+ if (STRUCTURAL_CELL_ATTRS.has(key)) continue;
4089
+ const fallback = (spec == null ? void 0 : spec.default) ?? null;
4090
+ if (next[key] !== fallback) {
4091
+ next[key] = fallback;
4092
+ changed = true;
4093
+ }
4094
+ }
4095
+ if (changed) tr.setNodeMarkup(pos, void 0, next);
4096
+ }
4097
+ if (!tr.docChanged) return false;
4098
+ editor.view.dispatch(tr);
4099
+ return true;
4100
+ }
4101
+ function findTable(editor) {
4102
+ const $from = editor.state.selection.$from;
4103
+ for (let d = $from.depth; d > 0; d -= 1) {
4104
+ if ($from.node(d).type.name === "table") {
4105
+ return { pos: $from.before(d), node: $from.node(d) };
4106
+ }
4107
+ }
4108
+ let found = null;
4109
+ editor.state.doc.descendants((node, pos) => {
4110
+ if (found !== null) return false;
4111
+ if (node.type.name === "table") {
4112
+ found = { pos, node };
4113
+ return false;
4114
+ }
4115
+ return true;
4116
+ });
4117
+ return found;
4118
+ }
4119
+ function selectLineAt(editor, table, kind, index) {
4120
+ const map = TableMap.get(table.node);
4121
+ const start = table.pos + 1;
4122
+ const anchorCell = start + map.positionAt(kind === "row" ? index : 0, kind === "col" ? index : 0, table.node);
4123
+ const headCell = start + map.positionAt(
4124
+ kind === "row" ? index : map.height - 1,
4125
+ kind === "col" ? index : map.width - 1,
4126
+ table.node
4127
+ );
4128
+ editor.view.dispatch(
4129
+ editor.state.tr.setSelection(
4130
+ new CellSelection(
4131
+ editor.state.doc.resolve(anchorCell),
4132
+ editor.state.doc.resolve(headCell)
4133
+ )
4134
+ )
4135
+ );
4136
+ }
4137
+ function appendRowToTable(editor) {
4138
+ const table = findTable(editor);
4139
+ if (!table) return false;
4140
+ selectLineAt(editor, table, "row", TableMap.get(table.node).height - 1);
4141
+ return addRowsAfter(editor, 1);
4142
+ }
4143
+ function appendColumnToTable(editor) {
4144
+ const table = findTable(editor);
4145
+ if (!table) return false;
4146
+ selectLineAt(editor, table, "col", TableMap.get(table.node).width - 1);
4147
+ return addColumnsAfter(editor, 1);
4148
+ }
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";
4158
+ const styles$2 = {
4159
+ handle,
4160
+ handleRow,
4161
+ handleCol,
4162
+ extend,
4163
+ tableBubble,
4164
+ tableMenuItem,
4165
+ tableMenuItemIcon,
4166
+ tableMenuItemLabel,
4167
+ tableMenuDivider
4168
+ };
4169
+ function edgeFlags(editor, cell) {
4170
+ try {
4171
+ const $cell = cellAround(editor.state.doc.resolve(editor.view.posAtDOM(cell, 0)));
4172
+ if (!$cell) return { onLastRow: false, onLastCol: false };
4173
+ const map = TableMap.get($cell.node(-1));
4174
+ const rect = map.findCell($cell.pos - $cell.start(-1));
4175
+ return {
4176
+ onLastRow: rect.bottom === map.height,
4177
+ onLastCol: rect.right === map.width
4178
+ };
4179
+ } catch {
4180
+ return { onLastRow: false, onLastCol: false };
4181
+ }
4182
+ }
4183
+ const COL_HANDLE_GAP = 22;
4184
+ const ROW_HANDLE_GAP = 26;
4185
+ const EXTEND_GAP = 6;
4186
+ const EXTEND_THICKNESS = 16;
4187
+ const HOVER_KEEP_MS = 160;
4188
+ function measureCell(editor, cell) {
4189
+ const table = cell.closest("table");
4190
+ const row2 = cell.closest("tr");
4191
+ if (!table || !row2) return null;
4192
+ try {
4193
+ editor.view.posAtDOM(cell, 0);
4194
+ } catch {
4195
+ return null;
4196
+ }
4197
+ const cellRect = cell.getBoundingClientRect();
4198
+ const rowRect = row2.getBoundingClientRect();
4199
+ const tableRect = table.getBoundingClientRect();
4200
+ const edges = edgeFlags(editor, cell);
4201
+ return {
4202
+ cell,
4203
+ ...edges,
4204
+ rowTop: rowRect.top,
4205
+ rowHeight: rowRect.height,
4206
+ colLeft: cellRect.left,
4207
+ colWidth: cellRect.width,
4208
+ tableLeft: tableRect.left,
4209
+ tableTop: tableRect.top,
4210
+ tableRight: tableRect.right,
4211
+ tableBottom: tableRect.bottom
4212
+ };
4213
+ }
4214
+ function selectRowOrColumn(editor, cell, kind) {
4215
+ let pos;
4216
+ try {
4217
+ pos = editor.view.posAtDOM(cell, 0);
4218
+ } catch {
4219
+ return false;
4220
+ }
4221
+ const $cell = cellAround(editor.state.doc.resolve(pos));
4222
+ if (!$cell) return false;
4223
+ const selection = kind === "row" ? CellSelection.rowSelection($cell) : CellSelection.colSelection($cell);
4224
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
4225
+ return true;
4226
+ }
4227
+ function menuItemsFor(editor, labels, kind) {
4228
+ const info = getTableSelectionInfo(editor.state);
4229
+ const rowN = (info == null ? void 0 : info.rowCount) ?? 1;
4230
+ const colN = (info == null ? void 0 : info.colCount) ?? 1;
4231
+ const multi = kind === "multi";
4232
+ const items = [];
4233
+ if (kind === "col" || kind === "multi") {
4234
+ items.push(
4235
+ {
4236
+ key: "col-before",
4237
+ group: "col",
4238
+ label: multi ? labels.tableAddColumnBeforeN(colN) : labels.tableAddColumnBefore,
4239
+ icon: /* @__PURE__ */ jsx(ColumnBeforeIcon, {}),
4240
+ run: () => addColumnsBefore(editor, colN)
4241
+ },
4242
+ {
4243
+ key: "col-after",
4244
+ group: "col",
4245
+ label: multi ? labels.tableAddColumnAfterN(colN) : labels.tableAddColumnAfter,
4246
+ icon: /* @__PURE__ */ jsx(ColumnAfterIcon, {}),
4247
+ run: () => addColumnsAfter(editor, colN)
4248
+ },
4249
+ {
4250
+ key: "col-delete",
4251
+ group: "col",
4252
+ label: multi ? labels.tableDeleteColumnN(colN) : labels.tableDeleteColumn,
4253
+ icon: /* @__PURE__ */ jsx(ColumnDeleteIcon, {}),
4254
+ // 只选了全部列、却没选全部行:删列会把表格删没,禁掉
4255
+ disabled: !!(info == null ? void 0 : info.coversAllCols) && !(info == null ? void 0 : info.coversAllRows),
4256
+ run: () => deleteSelectedColumns(editor)
4257
+ }
4258
+ );
4259
+ }
4260
+ if (kind === "row" || kind === "multi") {
4261
+ items.push(
4262
+ {
4263
+ key: "row-before",
4264
+ group: "row",
4265
+ label: multi ? labels.tableAddRowBeforeN(rowN) : labels.tableAddRowBefore,
4266
+ icon: /* @__PURE__ */ jsx(RowBeforeIcon, {}),
4267
+ // 上方是表头行时插行没意义
4268
+ disabled: !!(info == null ? void 0 : info.includesHeaderRow),
4269
+ run: () => addRowsBefore(editor, rowN)
4270
+ },
4271
+ {
4272
+ key: "row-after",
4273
+ group: "row",
4274
+ label: multi ? labels.tableAddRowAfterN(rowN) : labels.tableAddRowAfter,
4275
+ icon: /* @__PURE__ */ jsx(RowAfterIcon, {}),
4276
+ run: () => addRowsAfter(editor, rowN)
4277
+ },
4278
+ {
4279
+ key: "row-delete",
4280
+ group: "row",
4281
+ label: multi ? labels.tableDeleteRowN(rowN) : labels.tableDeleteRow,
4282
+ icon: /* @__PURE__ */ jsx(RowDeleteIcon, {}),
4283
+ disabled: !!(info == null ? void 0 : info.includesHeaderRow),
4284
+ run: () => deleteSelectedRows(editor)
4285
+ }
4286
+ );
4287
+ }
4288
+ items.push(
4289
+ {
4290
+ key: "cells-clear",
4291
+ group: "cells",
4292
+ label: labels.tableClearContent,
4293
+ icon: /* @__PURE__ */ jsx(EraserIcon, {}),
4294
+ run: () => clearSelectedCellContents(editor)
4295
+ },
4296
+ {
4297
+ key: "cells-reset",
4298
+ group: "cells",
4299
+ label: labels.tableResetCellStyles,
4300
+ icon: /* @__PURE__ */ jsx(RotateCcwIcon, {}),
4301
+ run: () => resetSelectedCellStyles(editor)
4302
+ }
4303
+ );
4304
+ return items;
4305
+ }
4306
+ function TableHandles({ editor, labels }) {
4307
+ const [hover, setHover] = useState(null);
4308
+ const [menu2, setMenu] = useState(null);
4309
+ const hoverRef = useRef(null);
4310
+ const menuRef = useRef(null);
4311
+ menuRef.current = menu2;
4312
+ const clearHover = useCallback(() => {
4313
+ if (!hoverRef.current) return;
4314
+ hoverRef.current = null;
4315
+ setHover(null);
4316
+ }, []);
4317
+ const closeMenu = useCallback(() => setMenu(null), []);
4318
+ const remeasureHover = useCallback(() => {
4319
+ var _a;
4320
+ const cell = (_a = hoverRef.current) == null ? void 0 : _a.cell;
4321
+ if (!cell) return;
4322
+ const next = cell.isConnected ? measureCell(editor, cell) : null;
4323
+ hoverRef.current = next;
4324
+ setHover(next);
4325
+ }, [editor]);
4326
+ const clearTimerRef = useRef(null);
4327
+ const cancelPendingClear = useCallback(() => {
4328
+ if (clearTimerRef.current === null) return;
4329
+ clearTimeout(clearTimerRef.current);
4330
+ clearTimerRef.current = null;
4331
+ }, []);
4332
+ useEffect(() => {
4333
+ const onMove = (event) => {
4334
+ var _a, _b;
4335
+ if (!editor.isEditable || menuRef.current) return;
4336
+ const target = event.target;
4337
+ if ((_a = target == null ? void 0 : target.closest) == null ? void 0 : _a.call(target, "[data-table-handle], [data-table-extend]")) {
4338
+ cancelPendingClear();
4339
+ return;
4340
+ }
4341
+ const cell = target && editor.view.dom.contains(target) ? target.closest("td, th") : null;
4342
+ if (!cell) {
4343
+ if (hoverRef.current && clearTimerRef.current === null) {
4344
+ clearTimerRef.current = setTimeout(() => {
4345
+ clearTimerRef.current = null;
4346
+ clearHover();
4347
+ }, HOVER_KEEP_MS);
4348
+ }
4349
+ return;
4350
+ }
4351
+ cancelPendingClear();
4352
+ if (((_b = hoverRef.current) == null ? void 0 : _b.cell) === cell) return;
4353
+ const next = measureCell(editor, cell);
4354
+ hoverRef.current = next;
4355
+ setHover(next);
4356
+ };
4357
+ const onBlurWindow = () => {
4358
+ cancelPendingClear();
4359
+ clearHover();
4360
+ };
4361
+ document.addEventListener("mousemove", onMove);
4362
+ document.addEventListener("mouseleave", onBlurWindow);
4363
+ window.addEventListener("scroll", remeasureHover, true);
4364
+ window.addEventListener("resize", remeasureHover);
4365
+ return () => {
4366
+ cancelPendingClear();
4367
+ document.removeEventListener("mousemove", onMove);
4368
+ document.removeEventListener("mouseleave", onBlurWindow);
4369
+ window.removeEventListener("scroll", remeasureHover, true);
4370
+ window.removeEventListener("resize", remeasureHover);
4371
+ };
4372
+ }, [editor, clearHover, cancelPendingClear, remeasureHover]);
4373
+ useEffect(() => {
4374
+ const dom = editor.view.dom;
4375
+ const onContextMenu = (event) => {
4376
+ const info = getTableSelectionInfo(editor.state);
4377
+ const { selection } = editor.state;
4378
+ if (!(info == null ? void 0 : info.isMultiCell) || !(selection instanceof CellSelection)) return;
4379
+ const coords = editor.view.posAtCoords({
4380
+ left: event.clientX,
4381
+ top: event.clientY
4382
+ });
4383
+ if (!coords || !isPosInCellSelection(selection, coords.pos)) return;
4384
+ event.preventDefault();
4385
+ hoverRef.current = null;
4386
+ setHover(null);
4387
+ setMenu({ kind: "multi", x: event.clientX, y: event.clientY });
4388
+ };
4389
+ dom.addEventListener("contextmenu", onContextMenu);
4390
+ return () => dom.removeEventListener("contextmenu", onContextMenu);
4391
+ }, [editor]);
4392
+ useEffect(() => {
4393
+ if (!menu2) return;
4394
+ const onKey = (event) => {
4395
+ if (event.key === "Escape") closeMenu();
4396
+ };
4397
+ const onDown = (event) => {
4398
+ var _a;
4399
+ const target = event.target;
4400
+ if ((_a = target == null ? void 0 : target.closest) == null ? void 0 : _a.call(target, "[data-table-menu]")) return;
4401
+ closeMenu();
4402
+ };
4403
+ document.addEventListener("keydown", onKey, true);
4404
+ document.addEventListener("mousedown", onDown);
4405
+ return () => {
4406
+ document.removeEventListener("keydown", onKey, true);
4407
+ document.removeEventListener("mousedown", onDown);
4408
+ };
4409
+ }, [menu2, closeMenu]);
4410
+ if (typeof document === "undefined") return null;
4411
+ const openHandleMenu = (kind) => {
4412
+ if (!hover) return;
4413
+ if (!selectRowOrColumn(editor, hover.cell, kind)) return;
4414
+ setHover(null);
4415
+ hoverRef.current = null;
4416
+ setMenu(
4417
+ kind === "row" ? { kind, x: hover.tableLeft + 6, y: hover.rowTop } : { kind, x: hover.colLeft, y: hover.tableTop + 6 }
4418
+ );
4419
+ };
4420
+ const items = menu2 ? menuItemsFor(editor, labels, menu2.kind) : [];
4421
+ const showHandles = !!hover && !menu2 && editor.isEditable;
4422
+ return createPortal(
4423
+ /* @__PURE__ */ jsxs(Fragment$2, { children: [
4424
+ showHandles && hover ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
4425
+ /* @__PURE__ */ jsx(
4426
+ "button",
4427
+ {
4428
+ type: "button",
4429
+ "data-table-handle": "row",
4430
+ className: `${styles$2.handle} ${styles$2.handleRow}`,
4431
+ style: {
4432
+ left: hover.tableLeft - ROW_HANDLE_GAP,
4433
+ // 长度跟着行高走(原来固定 28px 居中,行高时就显得太短)
4434
+ top: hover.rowTop,
4435
+ height: hover.rowHeight
4436
+ },
4437
+ title: labels.tableRowMenu,
4438
+ "aria-label": labels.tableRowMenu,
4439
+ onMouseDown: (e2) => e2.preventDefault(),
4440
+ onClick: () => openHandleMenu("row"),
4441
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "⋮" })
4442
+ }
4443
+ ),
4444
+ /* @__PURE__ */ jsx(
4445
+ "button",
4446
+ {
4447
+ type: "button",
4448
+ "data-table-handle": "col",
4449
+ className: `${styles$2.handle} ${styles$2.handleCol}`,
4450
+ style: {
4451
+ // 长度跟着列宽走,两端与单元格对齐
4452
+ left: hover.colLeft,
4453
+ top: hover.tableTop - COL_HANDLE_GAP,
4454
+ width: hover.colWidth
4455
+ },
4456
+ title: labels.tableColumnMenu,
4457
+ "aria-label": labels.tableColumnMenu,
4458
+ onMouseDown: (e2) => e2.preventDefault(),
4459
+ onClick: () => openHandleMenu("col"),
4460
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "⋯" })
4461
+ }
4462
+ ),
4463
+ hover.onLastCol ? /* @__PURE__ */ jsx(
4464
+ "button",
4465
+ {
4466
+ type: "button",
4467
+ "data-table-extend": "col",
4468
+ className: styles$2.extend,
4469
+ style: {
4470
+ left: hover.tableRight + EXTEND_GAP,
4471
+ top: hover.tableTop,
4472
+ width: EXTEND_THICKNESS,
4473
+ height: Math.max(EXTEND_THICKNESS, hover.tableBottom - hover.tableTop)
4474
+ },
4475
+ title: labels.tableAppendColumn,
4476
+ "aria-label": labels.tableAppendColumn,
4477
+ onMouseDown: (e2) => e2.preventDefault(),
4478
+ onClick: () => {
4479
+ appendColumnToTable(editor);
4480
+ remeasureHover();
4481
+ },
4482
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "+" })
4483
+ }
4484
+ ) : null,
4485
+ hover.onLastRow ? /* @__PURE__ */ jsx(
4486
+ "button",
4487
+ {
4488
+ type: "button",
4489
+ "data-table-extend": "row",
4490
+ className: styles$2.extend,
4491
+ style: {
4492
+ left: hover.tableLeft,
4493
+ top: hover.tableBottom + EXTEND_GAP,
4494
+ width: Math.max(EXTEND_THICKNESS, hover.tableRight - hover.tableLeft),
4495
+ height: EXTEND_THICKNESS
4496
+ },
4497
+ title: labels.tableAppendRow,
4498
+ "aria-label": labels.tableAppendRow,
4499
+ onMouseDown: (e2) => e2.preventDefault(),
4500
+ onClick: () => {
4501
+ appendRowToTable(editor);
4502
+ remeasureHover();
4503
+ },
4504
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "+" })
4505
+ }
4506
+ ) : null
4507
+ ] }) : null,
4508
+ menu2 ? /* @__PURE__ */ jsxs(
4509
+ "div",
4510
+ {
4511
+ className: styles$2.tableBubble,
4512
+ "data-table-menu": "",
4513
+ style: { left: menu2.x, top: menu2.y },
4514
+ role: "menu",
4515
+ onMouseDown: (e2) => e2.stopPropagation(),
4516
+ onContextMenu: (e2) => e2.preventDefault(),
4517
+ children: [
4518
+ items.map((item2, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
4519
+ index > 0 && item2.group !== items[index - 1].group ? /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuDivider, "aria-hidden": true }) : null,
4520
+ /* @__PURE__ */ jsxs(
4521
+ "button",
4522
+ {
4523
+ type: "button",
4524
+ role: "menuitem",
4525
+ className: styles$2.tableMenuItem,
4526
+ disabled: item2.disabled,
4527
+ onClick: () => {
4528
+ item2.run();
4529
+ closeMenu();
4530
+ },
4531
+ children: [
4532
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemIcon, "aria-hidden": true, children: item2.icon }),
4533
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemLabel, children: item2.label })
4534
+ ]
4535
+ }
4536
+ )
4537
+ ] }, item2.key)),
4538
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuDivider, "aria-hidden": true }),
4539
+ /* @__PURE__ */ jsxs(
4540
+ "button",
4541
+ {
4542
+ type: "button",
4543
+ role: "menuitem",
4544
+ className: styles$2.tableMenuItem,
4545
+ onClick: () => {
4546
+ editor.commands.deleteTable();
4547
+ closeMenu();
4548
+ },
4549
+ children: [
4550
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemIcon, "aria-hidden": true, children: /* @__PURE__ */ jsx(TableDeleteIcon, {}) }),
4551
+ /* @__PURE__ */ jsx("span", { className: styles$2.tableMenuItemLabel, children: labels.tableDeleteTable })
4552
+ ]
4553
+ }
4554
+ )
4555
+ ]
4556
+ }
4557
+ ) : null
4558
+ ] }),
4559
+ document.body
4560
+ );
4561
+ }
2762
4562
  function resolveNodeEl(editor, pos) {
2763
4563
  const dom = editor.view.nodeDOM(pos);
2764
4564
  if (dom instanceof HTMLElement) return dom;
@@ -2907,7 +4707,7 @@ function MathEditorPopover({
2907
4707
  "textarea",
2908
4708
  {
2909
4709
  ref: inputRef,
2910
- className: styles$3.mathInput,
4710
+ className: styles$6.mathInput,
2911
4711
  value: draft,
2912
4712
  placeholder,
2913
4713
  rows: Math.max(3, draft.split("\n").length),
@@ -2919,7 +4719,7 @@ function MathEditorPopover({
2919
4719
  "input",
2920
4720
  {
2921
4721
  ref: inputRef,
2922
- className: styles$3.mathInput,
4722
+ className: styles$6.mathInput,
2923
4723
  value: draft,
2924
4724
  placeholder,
2925
4725
  "aria-labelledby": titleId,
@@ -2933,7 +4733,7 @@ function MathEditorPopover({
2933
4733
  "div",
2934
4734
  {
2935
4735
  ref: rootRef,
2936
- className: styles$3.mathLayer,
4736
+ className: styles$6.mathLayer,
2937
4737
  style: layerStyle,
2938
4738
  role: "dialog",
2939
4739
  "aria-modal": "false",
@@ -2941,15 +4741,15 @@ function MathEditorPopover({
2941
4741
  children: /* @__PURE__ */ jsxs(
2942
4742
  "div",
2943
4743
  {
2944
- className: isBlock ? `${styles$3.mathStack} ${styles$3.mathStackBlock}` : styles$3.mathStack,
4744
+ className: isBlock ? `${styles$6.mathStack} ${styles$6.mathStackBlock}` : styles$6.mathStack,
2945
4745
  children: [
2946
4746
  showHint ? /* @__PURE__ */ jsxs(
2947
4747
  "div",
2948
4748
  {
2949
4749
  id: titleId,
2950
- className: isBlock ? `${styles$3.mathHint} ${styles$3.mathHintBlock}` : styles$3.mathHint,
4750
+ className: isBlock ? `${styles$6.mathHint} ${styles$6.mathHintBlock}` : styles$6.mathHint,
2951
4751
  children: [
2952
- /* @__PURE__ */ jsx("span", { className: styles$3.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
4752
+ /* @__PURE__ */ jsx("span", { className: styles$6.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
2953
4753
  newLabel
2954
4754
  ]
2955
4755
  }
@@ -2958,20 +4758,20 @@ function MathEditorPopover({
2958
4758
  "div",
2959
4759
  {
2960
4760
  id: showHint ? void 0 : titleId,
2961
- className: isBlock ? `${styles$3.mathField} ${styles$3.mathFieldBlock}` : styles$3.mathField,
4761
+ className: isBlock ? `${styles$6.mathField} ${styles$6.mathFieldBlock}` : styles$6.mathField,
2962
4762
  children: [
2963
4763
  field2,
2964
4764
  /* @__PURE__ */ jsxs(
2965
4765
  "button",
2966
4766
  {
2967
4767
  type: "button",
2968
- className: styles$3.mathDone,
4768
+ className: styles$6.mathDone,
2969
4769
  disabled: !canSubmit,
2970
4770
  title: isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`,
2971
4771
  onClick: submit,
2972
4772
  children: [
2973
4773
  doneLabel,
2974
- /* @__PURE__ */ jsx("span", { className: styles$3.mathDoneKbd, "aria-hidden": true, children: "↵" })
4774
+ /* @__PURE__ */ jsx("span", { className: styles$6.mathDoneKbd, "aria-hidden": true, children: "↵" })
2975
4775
  ]
2976
4776
  }
2977
4777
  )
@@ -2986,56 +4786,31 @@ function MathEditorPopover({
2986
4786
  host
2987
4787
  );
2988
4788
  }
2989
- function ToolbarButton({
2990
- title,
2991
- active: active2,
2992
- disabled,
2993
- busy,
2994
- onClick,
2995
- children
2996
- }) {
4789
+ const ToolbarButton = forwardRef(function ToolbarButton2({ title, active: active2, disabled, busy, onClick, children, className, ...rest }, ref) {
2997
4790
  return /* @__PURE__ */ jsx(
2998
4791
  "button",
2999
4792
  {
4793
+ ...rest,
4794
+ ref,
3000
4795
  type: "button",
3001
4796
  title,
3002
4797
  "aria-label": title,
3003
4798
  "aria-pressed": active2,
3004
4799
  "aria-busy": busy,
3005
4800
  disabled,
3006
- className: `${styles$3.btn} ${active2 ? styles$3.btnActive : ""}`,
4801
+ className: `${styles$6.btn} ${active2 ? styles$6.btnActive : ""}${className ? ` ${className}` : ""}`,
3007
4802
  onMouseDown: (e2) => e2.preventDefault(),
3008
4803
  onClick,
3009
4804
  children
3010
4805
  }
3011
4806
  );
3012
- }
4807
+ });
3013
4808
  function Divider() {
3014
- return /* @__PURE__ */ jsx("span", { className: styles$3.divider, "aria-hidden": true });
3015
- }
3016
- function TableMenuItem({
3017
- label,
3018
- disabled,
3019
- onClick,
3020
- children
3021
- }) {
3022
- return /* @__PURE__ */ jsxs(
3023
- "button",
3024
- {
3025
- type: "button",
3026
- disabled,
3027
- className: styles$3.tableMenuItem,
3028
- onMouseDown: (e2) => e2.preventDefault(),
3029
- onClick,
3030
- children: [
3031
- /* @__PURE__ */ jsx("span", { className: styles$3.tableMenuItemIcon, "aria-hidden": true, children }),
3032
- /* @__PURE__ */ jsx("span", { className: styles$3.tableMenuItemLabel, children: label })
3033
- ]
3034
- }
3035
- );
4809
+ return /* @__PURE__ */ jsx("span", { className: styles$6.divider, "aria-hidden": true });
3036
4810
  }
3037
- function TableMenuDivider() {
3038
- return /* @__PURE__ */ jsx("div", { className: styles$3.tableMenuDivider, "aria-hidden": true });
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;
3039
4814
  }
3040
4815
  const MenuCloseCtx = createContext(() => {
3041
4816
  });
@@ -3050,7 +4825,7 @@ function MenuPopover({
3050
4825
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3051
4826
  Popover.Content,
3052
4827
  {
3053
- className: styles$3.menu,
4828
+ className: styles$6.menu,
3054
4829
  sideOffset: 4,
3055
4830
  align: "start",
3056
4831
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -3072,7 +4847,7 @@ function MenuItem({
3072
4847
  {
3073
4848
  type: "button",
3074
4849
  disabled,
3075
- className: `${styles$3.menuItem} ${selected ? styles$3.menuItemSelected : ""}`,
4850
+ className: `${styles$6.menuItem} ${selected ? styles$6.menuItemSelected : ""}`,
3076
4851
  onMouseDown: (e2) => e2.preventDefault(),
3077
4852
  onClick: () => {
3078
4853
  onSelect();
@@ -3107,21 +4882,21 @@ function TableInsertItem({
3107
4882
  {
3108
4883
  type: "button",
3109
4884
  disabled,
3110
- className: `${styles$3.menuItem} ${open ? styles$3.menuItemSelected : ""}`,
4885
+ className: `${styles$6.menuItem} ${open ? styles$6.menuItemSelected : ""}`,
3111
4886
  onMouseDown: (e2) => e2.preventDefault(),
3112
4887
  children: [
3113
- /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3114
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "⊞" }),
4888
+ /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
4889
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "⊞" }),
3115
4890
  labels.tableInsert
3116
4891
  ] }),
3117
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.tableInsertCaret })
4892
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.tableInsertCaret })
3118
4893
  ]
3119
4894
  }
3120
4895
  ) }),
3121
4896
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
3122
4897
  Popover.Content,
3123
4898
  {
3124
- className: styles$3.tableSizePicker,
4899
+ className: styles$6.tableSizePicker,
3125
4900
  side: "right",
3126
4901
  align: "start",
3127
4902
  sideOffset: 6,
@@ -3131,7 +4906,7 @@ function TableInsertItem({
3131
4906
  /* @__PURE__ */ jsx(
3132
4907
  "div",
3133
4908
  {
3134
- className: styles$3.tableSizeGrid,
4909
+ className: styles$6.tableSizeGrid,
3135
4910
  style: {
3136
4911
  gridTemplateColumns: `repeat(${TABLE_PICKER_COLS}, 1fr)`
3137
4912
  },
@@ -3145,7 +4920,7 @@ function TableInsertItem({
3145
4920
  {
3146
4921
  type: "button",
3147
4922
  "aria-label": labels.tableSizeSelected(col, row2),
3148
- className: `${styles$3.tableSizeCell} ${active2 ? styles$3.tableSizeCellActive : ""}`,
4923
+ className: `${styles$6.tableSizeCell} ${active2 ? styles$6.tableSizeCellActive : ""}`,
3149
4924
  onMouseDown: (e2) => e2.preventDefault(),
3150
4925
  onMouseEnter: () => setHover({ cols: col, rows: row2 }),
3151
4926
  onClick: () => {
@@ -3160,7 +4935,7 @@ function TableInsertItem({
3160
4935
  })
3161
4936
  }
3162
4937
  ),
3163
- /* @__PURE__ */ jsx("div", { className: styles$3.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 })
3164
4939
  ]
3165
4940
  }
3166
4941
  ) })
@@ -3182,20 +4957,20 @@ function ColorPopover({
3182
4957
  "button",
3183
4958
  {
3184
4959
  type: "button",
3185
- className: styles$3.btn,
4960
+ className: styles$6.btn,
3186
4961
  title,
3187
4962
  "aria-label": title,
3188
4963
  onMouseDown: (e2) => e2.preventDefault(),
3189
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.colorIcon, children: [
3190
- /* @__PURE__ */ jsx("span", { className: styles$3.colorIconGlyph, children: glyph }),
3191
- /* @__PURE__ */ jsx("span", { className: styles$3.colorIconBar, style: { background: bar2 } })
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 } })
3192
4967
  ] })
3193
4968
  }
3194
4969
  ) }),
3195
4970
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3196
4971
  Popover.Content,
3197
4972
  {
3198
- className: styles$3.popoverContent,
4973
+ className: styles$6.popoverContent,
3199
4974
  sideOffset: 4,
3200
4975
  align: "start",
3201
4976
  onOpenAutoFocus: (e2) => e2.preventDefault(),
@@ -3226,6 +5001,8 @@ function EditorToolbar({
3226
5001
  importMenuItems,
3227
5002
  showImport = true,
3228
5003
  labels,
5004
+ onSearch,
5005
+ searchActive = false,
3229
5006
  extraToolbarItems,
3230
5007
  className
3231
5008
  }) {
@@ -3252,6 +5029,9 @@ function EditorToolbar({
3252
5029
  highlightColor: e2.getAttributes("highlight").color || void 0,
3253
5030
  superscript: e2.isActive("superscript"),
3254
5031
  subscript: e2.isActive("subscript"),
5032
+ textAlign: readParaAttr(e2, "textAlign"),
5033
+ indent: readParaAttr(e2, "indent"),
5034
+ lineHeight: readParaAttr(e2, "lineHeight"),
3255
5035
  inTable: e2.isActive("table"),
3256
5036
  canUndo: e2.can().undo(),
3257
5037
  canRedo: e2.can().redo()
@@ -3270,63 +5050,14 @@ function EditorToolbar({
3270
5050
  }, [editor]);
3271
5051
  const fileInputRef = useRef(null);
3272
5052
  const chain = () => editor.chain().focus();
3273
- const [tableMenu, setTableMenu] = useState(
3274
- null
3275
- );
3276
- const closeTableMenu = useCallback(() => setTableMenu(null), []);
3277
- useEffect(() => {
3278
- const dom = editor.view.dom;
3279
- const onContextMenu = (e2) => {
3280
- const coords = editor.view.posAtCoords({
3281
- left: e2.clientX,
3282
- top: e2.clientY
3283
- });
3284
- if (!coords) return;
3285
- const $pos = editor.state.doc.resolve(coords.pos);
3286
- let inTable = false;
3287
- for (let d = $pos.depth; d > 0; d--) {
3288
- if ($pos.node(d).type.name === "table") {
3289
- inTable = true;
3290
- break;
3291
- }
3292
- }
3293
- if (!inTable) return;
3294
- e2.preventDefault();
3295
- preserveTableSelectionOnContextMenu(editor, coords.pos);
3296
- setTableMenu({ x: e2.clientX, y: e2.clientY });
3297
- };
3298
- dom.addEventListener("contextmenu", onContextMenu);
3299
- return () => dom.removeEventListener("contextmenu", onContextMenu);
3300
- }, [editor]);
3301
- useEffect(() => {
3302
- if (!tableMenu) return;
3303
- const onKey = (e2) => {
3304
- if (e2.key === "Escape") closeTableMenu();
3305
- };
3306
- document.addEventListener("mousedown", closeTableMenu);
3307
- document.addEventListener("keydown", onKey, true);
3308
- return () => {
3309
- document.removeEventListener("mousedown", closeTableMenu);
3310
- document.removeEventListener("keydown", onKey, true);
3311
- };
3312
- }, [tableMenu, closeTableMenu]);
3313
- const runTable = useCallback(
3314
- (fn) => {
3315
- fn();
3316
- closeTableMenu();
3317
- },
3318
- [closeTableMenu]
3319
- );
3320
- const tableSel = tableMenu ? getTableSelectionInfo(editor.state) : null;
3321
- const tableRowN = (tableSel == null ? void 0 : tableSel.rowCount) ?? 1;
3322
- const tableColN = (tableSel == null ? void 0 : tableSel.colCount) ?? 1;
3323
- const tableMulti = (tableSel == null ? void 0 : tableSel.isMultiCell) ?? false;
3324
- const disableAddRowBefore = !!(tableSel == null ? void 0 : tableSel.includesHeaderRow);
3325
- const disableDeleteRow = !!(tableSel == null ? void 0 : tableSel.includesHeaderRow);
3326
- const disableDeleteColumn = !!(tableSel == null ? void 0 : tableSel.coversAllCols) && !(tableSel == null ? void 0 : tableSel.coversAllRows);
5053
+ const imageUploadEnabled = hasImageUpload(editor);
3327
5054
  const handlePickImage = () => {
3328
5055
  var _a;
3329
- 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();
3330
5061
  };
3331
5062
  const handleImageChange = async (e2) => {
3332
5063
  var _a;
@@ -3420,14 +5151,6 @@ function EditorToolbar({
3420
5151
  if (color) chain().setHighlight({ color }).run();
3421
5152
  else chain().unsetHighlight().run();
3422
5153
  };
3423
- const toggleLink = () => {
3424
- if (state.link) {
3425
- chain().unsetLink().run();
3426
- return;
3427
- }
3428
- const url = window.prompt(t.linkPrompt);
3429
- if (url) chain().setLink({ href: url }).run();
3430
- };
3431
5154
  const setBlockStyle = (level) => {
3432
5155
  if (level === 0) chain().setParagraph().run();
3433
5156
  else
@@ -3511,8 +5234,8 @@ function EditorToolbar({
3511
5234
  /* @__PURE__ */ jsx(
3512
5235
  "div",
3513
5236
  {
3514
- className: className ? `${styles$3.toolbar} ${className}` : styles$3.toolbar,
3515
- children: /* @__PURE__ */ jsxs("div", { className: styles$3.inner, children: [
5237
+ className: className ? `${styles$6.toolbar} ${className}` : styles$6.toolbar,
5238
+ children: /* @__PURE__ */ jsxs("div", { className: styles$6.inner, children: [
3516
5239
  /* @__PURE__ */ jsx(
3517
5240
  ToolbarButton,
3518
5241
  {
@@ -3539,12 +5262,12 @@ function EditorToolbar({
3539
5262
  "button",
3540
5263
  {
3541
5264
  type: "button",
3542
- className: styles$3.styleTrigger,
5265
+ className: styles$6.styleTrigger,
3543
5266
  title: t.style,
3544
5267
  onMouseDown: (e2) => e2.preventDefault(),
3545
5268
  children: [
3546
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.style }),
3547
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
5269
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.style }),
5270
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
3548
5271
  ]
3549
5272
  }
3550
5273
  ),
@@ -3554,8 +5277,8 @@ function EditorToolbar({
3554
5277
  {
3555
5278
  selected: (state.headingLevel ?? 0) === 0,
3556
5279
  onSelect: () => setBlockStyle(0),
3557
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3558
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "¶" }),
5280
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5281
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "¶" }),
3559
5282
  t.normalText
3560
5283
  ] })
3561
5284
  }
@@ -3565,8 +5288,8 @@ function EditorToolbar({
3565
5288
  {
3566
5289
  selected: state.headingLevel === lv,
3567
5290
  onSelect: () => setBlockStyle(lv),
3568
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3569
- /* @__PURE__ */ jsx("span", { className: styles$3.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}` }),
3570
5293
  t.headingLabel(lv)
3571
5294
  ] })
3572
5295
  },
@@ -3582,14 +5305,14 @@ function EditorToolbar({
3582
5305
  "button",
3583
5306
  {
3584
5307
  type: "button",
3585
- className: styles$3.styleTrigger,
5308
+ className: styles$6.styleTrigger,
3586
5309
  title: t.fontSize,
3587
5310
  "aria-label": t.fontSize,
3588
5311
  disabled: !canEditFontSize,
3589
5312
  onMouseDown: (e2) => e2.preventDefault(),
3590
5313
  children: [
3591
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: state.fontSize || t.fontSize }),
3592
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
5314
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: state.fontSize || t.fontSize }),
5315
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
3593
5316
  ]
3594
5317
  }
3595
5318
  ),
@@ -3599,8 +5322,8 @@ function EditorToolbar({
3599
5322
  {
3600
5323
  selected: !state.fontSize,
3601
5324
  onSelect: () => applyFontSize(""),
3602
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3603
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "A" }),
5325
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5326
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "A" }),
3604
5327
  t.fontSizeDefault
3605
5328
  ] })
3606
5329
  }
@@ -3610,8 +5333,8 @@ function EditorToolbar({
3610
5333
  {
3611
5334
  selected: state.fontSize === size,
3612
5335
  onSelect: () => applyFontSize(size),
3613
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3614
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: parseInt(size, 10) }),
5336
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5337
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: parseInt(size, 10) }),
3615
5338
  size
3616
5339
  ] })
3617
5340
  },
@@ -3695,13 +5418,13 @@ function EditorToolbar({
3695
5418
  "button",
3696
5419
  {
3697
5420
  type: "button",
3698
- className: `${styles$3.scriptTrigger} ${scriptActive !== "normal" ? styles$3.btnActive : ""}`,
5421
+ className: `${styles$6.scriptTrigger} ${scriptActive !== "normal" ? styles$6.btnActive : ""}`,
3699
5422
  title: t.scriptMenu,
3700
5423
  "aria-label": t.scriptMenu,
3701
5424
  onMouseDown: (e2) => e2.preventDefault(),
3702
5425
  children: [
3703
- /* @__PURE__ */ jsx("span", { className: styles$3.scriptTriggerGlyph, children: "A" }),
3704
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
5426
+ /* @__PURE__ */ jsx("span", { className: styles$6.scriptTriggerGlyph, children: "A" }),
5427
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
3705
5428
  ]
3706
5429
  }
3707
5430
  ),
@@ -3711,8 +5434,8 @@ function EditorToolbar({
3711
5434
  {
3712
5435
  selected: scriptActive === "normal",
3713
5436
  onSelect: () => chain().unsetSuperscript().unsetSubscript().run(),
3714
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3715
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "A" }),
5437
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5438
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: "A" }),
3716
5439
  t.scriptNormal
3717
5440
  ] })
3718
5441
  }
@@ -3722,8 +5445,8 @@ function EditorToolbar({
3722
5445
  {
3723
5446
  selected: scriptActive === "superscript",
3724
5447
  onSelect: () => chain().unsetSubscript().toggleSuperscript().run(),
3725
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3726
- /* @__PURE__ */ jsxs("span", { className: `${styles$3.styleIcon} ${styles$3.scriptGlyph}`, children: [
5448
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5449
+ /* @__PURE__ */ jsxs("span", { className: `${styles$6.styleIcon} ${styles$6.scriptGlyph}`, children: [
3727
5450
  "x",
3728
5451
  /* @__PURE__ */ jsx("sup", { children: "2" })
3729
5452
  ] }),
@@ -3736,8 +5459,8 @@ function EditorToolbar({
3736
5459
  {
3737
5460
  selected: scriptActive === "subscript",
3738
5461
  onSelect: () => chain().unsetSuperscript().toggleSubscript().run(),
3739
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3740
- /* @__PURE__ */ jsxs("span", { className: `${styles$3.styleIcon} ${styles$3.scriptGlyph}`, children: [
5462
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5463
+ /* @__PURE__ */ jsxs("span", { className: `${styles$6.styleIcon} ${styles$6.scriptGlyph}`, children: [
3741
5464
  "x",
3742
5465
  /* @__PURE__ */ jsx("sub", { children: "2" })
3743
5466
  ] }),
@@ -3749,10 +5472,23 @@ function EditorToolbar({
3749
5472
  }
3750
5473
  ),
3751
5474
  /* @__PURE__ */ jsx(Divider, {}),
3752
- /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, onClick: toggleLink, children: /* @__PURE__ */ jsx(LinkIcon, {}) }),
3753
- onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
5475
+ /* @__PURE__ */ jsx(
5476
+ LinkPopover,
5477
+ {
5478
+ editor,
5479
+ labels: {
5480
+ field: t.linkPrompt,
5481
+ apply: t.linkApply,
5482
+ open: t.linkOpen,
5483
+ remove: t.linkRemove,
5484
+ invalid: t.linkInvalid
5485
+ },
5486
+ trigger: /* @__PURE__ */ jsx(ToolbarButton, { title: t.link, active: state.link, children: /* @__PURE__ */ jsx(LinkIcon, {}) })
5487
+ }
5488
+ ),
5489
+ imageUploadEnabled || onImageUpload ? /* @__PURE__ */ jsxs(Fragment$2, { children: [
3754
5490
  /* @__PURE__ */ jsx(ToolbarButton, { title: t.image, onClick: handlePickImage, children: /* @__PURE__ */ jsx(ImageIcon, {}) }),
3755
- /* @__PURE__ */ jsx(
5491
+ !imageUploadEnabled && /* @__PURE__ */ jsx(
3756
5492
  "input",
3757
5493
  {
3758
5494
  ref: fileInputRef,
@@ -3770,19 +5506,19 @@ function EditorToolbar({
3770
5506
  "button",
3771
5507
  {
3772
5508
  type: "button",
3773
- className: styles$3.styleTrigger,
5509
+ className: styles$6.styleTrigger,
3774
5510
  title: importTitle,
3775
5511
  "aria-label": importTitle,
3776
5512
  "aria-busy": !!importing,
3777
5513
  disabled: !!importing,
3778
5514
  onMouseDown: (e2) => e2.preventDefault(),
3779
5515
  children: [
3780
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.importDocument }),
5516
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.importDocument }),
3781
5517
  /* @__PURE__ */ jsx(
3782
5518
  ChevronDownIcon,
3783
5519
  {
3784
5520
  size: 12,
3785
- className: styles$3.styleTriggerCaret
5521
+ className: styles$6.styleTriggerCaret
3786
5522
  }
3787
5523
  )
3788
5524
  ]
@@ -3804,7 +5540,117 @@ function EditorToolbar({
3804
5540
  title: t.blockquote,
3805
5541
  active: state.blockquote,
3806
5542
  onClick: () => chain().toggleBlockquote().run(),
3807
- children: /* @__PURE__ */ jsx("span", { className: styles$3.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
+ ]
3808
5654
  }
3809
5655
  ),
3810
5656
  /* @__PURE__ */ jsx(Divider, {}),
@@ -3836,6 +5682,15 @@ function EditorToolbar({
3836
5682
  }
3837
5683
  ),
3838
5684
  /* @__PURE__ */ jsx(Divider, {}),
5685
+ onSearch ? /* @__PURE__ */ jsx(
5686
+ ToolbarButton,
5687
+ {
5688
+ title: t.search,
5689
+ active: searchActive,
5690
+ onClick: onSearch,
5691
+ children: /* @__PURE__ */ jsx(SearchIcon, {})
5692
+ }
5693
+ ) : null,
3839
5694
  /* @__PURE__ */ jsxs(
3840
5695
  MenuPopover,
3841
5696
  {
@@ -3843,30 +5698,30 @@ function EditorToolbar({
3843
5698
  "button",
3844
5699
  {
3845
5700
  type: "button",
3846
- className: styles$3.styleTrigger,
5701
+ className: styles$6.styleTrigger,
3847
5702
  title: t.more,
3848
5703
  onMouseDown: (e2) => e2.preventDefault(),
3849
5704
  children: [
3850
- /* @__PURE__ */ jsx("span", { className: styles$3.styleTriggerLabel, children: t.more }),
3851
- /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$3.styleTriggerCaret })
5705
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleTriggerLabel, children: t.more }),
5706
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$6.styleTriggerCaret })
3852
5707
  ]
3853
5708
  }
3854
5709
  ),
3855
5710
  children: [
3856
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().toggleCodeBlock().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3857
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "{ }" }),
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: "{ }" }),
3858
5713
  t.codeBlock
3859
5714
  ] }) }),
3860
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("inline"), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3861
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "√x" }),
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" }),
3862
5717
  t.inlineMath
3863
5718
  ] }) }),
3864
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => openInsertMath("block"), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3865
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "∑" }),
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: "∑" }),
3866
5721
  t.blockMath
3867
5722
  ] }) }),
3868
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => chain().setHorizontalRule().run(), children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3869
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "—" }),
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: "—" }),
3870
5725
  t.hr
3871
5726
  ] }) }),
3872
5727
  /* @__PURE__ */ jsx(
@@ -3882,8 +5737,8 @@ function EditorToolbar({
3882
5737
  {
3883
5738
  disabled: item2.disabled,
3884
5739
  onSelect: () => item2.onSelect(editor),
3885
- children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
3886
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: item2.icon }),
5740
+ children: /* @__PURE__ */ jsxs("span", { className: styles$6.styleItem, children: [
5741
+ /* @__PURE__ */ jsx("span", { className: styles$6.styleIcon, children: item2.icon }),
3887
5742
  item2.label
3888
5743
  ] })
3889
5744
  },
@@ -3920,88 +5775,8 @@ function EditorToolbar({
3920
5775
  onCancel: cancelMath
3921
5776
  }
3922
5777
  ) : null,
3923
- tableMenu && createPortal(
3924
- /* @__PURE__ */ jsxs(
3925
- "div",
3926
- {
3927
- className: styles$3.tableBubble,
3928
- style: { position: "fixed", left: tableMenu.x, top: tableMenu.y },
3929
- role: "menu",
3930
- onMouseDown: (e2) => e2.stopPropagation(),
3931
- onContextMenu: (e2) => e2.preventDefault(),
3932
- children: [
3933
- /* @__PURE__ */ jsx(
3934
- TableMenuItem,
3935
- {
3936
- label: tableMulti ? t.tableAddColumnBeforeN(tableColN) : t.tableAddColumnBefore,
3937
- onClick: () => runTable(() => addColumnsBefore(editor, tableColN)),
3938
- children: /* @__PURE__ */ jsx(ColumnBeforeIcon, {})
3939
- }
3940
- ),
3941
- /* @__PURE__ */ jsx(
3942
- TableMenuItem,
3943
- {
3944
- label: tableMulti ? t.tableAddColumnAfterN(tableColN) : t.tableAddColumnAfter,
3945
- onClick: () => runTable(() => addColumnsAfter(editor, tableColN)),
3946
- children: /* @__PURE__ */ jsx(ColumnAfterIcon, {})
3947
- }
3948
- ),
3949
- /* @__PURE__ */ jsx(
3950
- TableMenuItem,
3951
- {
3952
- label: tableMulti ? t.tableDeleteColumnN(tableColN) : t.tableDeleteColumn,
3953
- disabled: disableDeleteColumn,
3954
- onClick: () => runTable(() => {
3955
- deleteSelectedColumns(editor);
3956
- }),
3957
- children: /* @__PURE__ */ jsx(ColumnDeleteIcon, {})
3958
- }
3959
- ),
3960
- /* @__PURE__ */ jsx(TableMenuDivider, {}),
3961
- /* @__PURE__ */ jsx(
3962
- TableMenuItem,
3963
- {
3964
- label: tableMulti ? t.tableAddRowBeforeN(tableRowN) : t.tableAddRowBefore,
3965
- disabled: disableAddRowBefore,
3966
- onClick: () => runTable(() => addRowsBefore(editor, tableRowN)),
3967
- children: /* @__PURE__ */ jsx(RowBeforeIcon, {})
3968
- }
3969
- ),
3970
- /* @__PURE__ */ jsx(
3971
- TableMenuItem,
3972
- {
3973
- label: tableMulti ? t.tableAddRowAfterN(tableRowN) : t.tableAddRowAfter,
3974
- onClick: () => runTable(() => addRowsAfter(editor, tableRowN)),
3975
- children: /* @__PURE__ */ jsx(RowAfterIcon, {})
3976
- }
3977
- ),
3978
- /* @__PURE__ */ jsx(
3979
- TableMenuItem,
3980
- {
3981
- label: tableMulti ? t.tableDeleteRowN(tableRowN) : t.tableDeleteRow,
3982
- disabled: disableDeleteRow,
3983
- onClick: () => runTable(() => {
3984
- deleteSelectedRows(editor);
3985
- }),
3986
- children: /* @__PURE__ */ jsx(RowDeleteIcon, {})
3987
- }
3988
- ),
3989
- /* @__PURE__ */ jsx(TableMenuDivider, {}),
3990
- /* @__PURE__ */ jsx(
3991
- TableMenuItem,
3992
- {
3993
- label: t.tableDeleteTable,
3994
- onClick: () => runTable(() => {
3995
- editor.commands.deleteTable();
3996
- }),
3997
- children: /* @__PURE__ */ jsx(TableDeleteIcon, {})
3998
- }
3999
- )
4000
- ]
4001
- }
4002
- ),
4003
- document.body
4004
- )
5778
+ /* @__PURE__ */ jsx(TableHandles, { editor, labels: t }),
5779
+ /* @__PURE__ */ jsx(ImageAlignTools, { editor, labels: t })
4005
5780
  ] });
4006
5781
  }
4007
5782
  function useIsMobile(breakpoint = 768) {
@@ -4163,6 +5938,11 @@ function TocPanel({ items, activeId, onItemClick, labels }) {
4163
5938
  list2
4164
5939
  ] });
4165
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
+ }
4166
5946
  const popoverAnchor = "_popoverAnchor_9y5t0_55";
4167
5947
  const popoverContent = "_popoverContent_9y5t0_62";
4168
5948
  const styles = {
@@ -4307,11 +6087,11 @@ function tryInsertMarkdownAt(editor, from, to, markdown) {
4307
6087
  return false;
4308
6088
  }
4309
6089
  }
4310
- function insertPlainParagraphAt(editor, from, to, text) {
6090
+ function insertPlainParagraphAt(editor, from, to, text2) {
4311
6091
  try {
4312
6092
  return editor.chain().insertContentAt(
4313
6093
  { from, to },
4314
- { type: "paragraph", content: text ? [{ type: "text", text }] : [] }
6094
+ { type: "paragraph", content: text2 ? [{ type: "text", text: text2 }] : [] }
4315
6095
  ).run();
4316
6096
  } catch {
4317
6097
  return false;
@@ -4329,10 +6109,15 @@ function insertSlashMarkdown(editor, range, markdown) {
4329
6109
  insertMarkdown(editor, prepared);
4330
6110
  }
4331
6111
  export {
6112
+ AlignCenterIcon,
6113
+ AlignJustifyIcon,
6114
+ AlignLeftIcon,
6115
+ AlignRightIcon,
4332
6116
  BoldIcon,
4333
6117
  COMMENT_ACTIVE_META,
4334
6118
  COMMENT_CLICK_META,
4335
6119
  COMMENT_GUTTER_META,
6120
+ CaptionsIcon,
4336
6121
  C as ChartMount,
4337
6122
  CheckIcon,
4338
6123
  ChevronDownIcon,
@@ -4350,15 +6135,23 @@ export {
4350
6135
  CommentPopover,
4351
6136
  CopyIcon,
4352
6137
  EditorToolbar,
6138
+ EraserIcon,
6139
+ ExternalLinkIcon,
4353
6140
  FIND_DEBOUNCE_MS,
4354
6141
  default2 as FindAndReplace,
4355
6142
  FindReplaceBar,
6143
+ ImageAlignTools,
4356
6144
  ImageIcon,
6145
+ ImageUploadNode,
4357
6146
  ImportIcon,
4358
6147
  ImportPlaceholder,
6148
+ IndentDecreaseIcon,
6149
+ IndentIncreaseIcon,
4359
6150
  ItalicIcon,
4360
6151
  KeyboardIcon,
6152
+ LineHeightIcon,
4361
6153
  LinkIcon,
6154
+ LinkPopover,
4362
6155
  ListChecksIcon,
4363
6156
  ListOrderedIcon,
4364
6157
  ListUnorderedIcon,
@@ -4369,12 +6162,14 @@ export {
4369
6162
  MarkdownWysiwygEditor,
4370
6163
  MenuIcon,
4371
6164
  PENDING_ANCHOR_CLASS,
6165
+ P as ParagraphStyles,
4372
6166
  RedoIcon,
4373
6167
  ReplaceAllIcon,
4374
6168
  ReplaceIcon,
4375
6169
  R2 as ReportContent,
4376
6170
  R as ReportContentInteractive,
4377
6171
  b as ReportContentWithCharts,
6172
+ RotateCcwIcon,
4378
6173
  RowAfterIcon,
4379
6174
  RowBeforeIcon,
4380
6175
  RowDeleteIcon,
@@ -4390,9 +6185,11 @@ export {
4390
6185
  XIcon,
4391
6186
  a2 as applyCitationSources,
4392
6187
  applyCommentAnchorsToEditor,
6188
+ applyLink,
4393
6189
  baseExtensions,
4394
6190
  g as blockTextHash,
4395
6191
  buildShortcutGroups,
6192
+ canSetLink,
4396
6193
  collectCommentIds,
4397
6194
  commentAnchorExtension,
4398
6195
  commentAnchorPlugin,
@@ -4406,6 +6203,8 @@ export {
4406
6203
  defaultColorPaletteLabels,
4407
6204
  defaultCommentLabels,
4408
6205
  defaultFindLabels,
6206
+ defaultImageUploadLabels,
6207
+ defaultLinkPopoverLabels,
4409
6208
  defaultShortcutLabels,
4410
6209
  defaultSlashMenuLabels,
4411
6210
  defaultTocLabels,
@@ -4418,8 +6217,14 @@ export {
4418
6217
  findRangeByAnchor,
4419
6218
  focusComment,
4420
6219
  getMarkdownForRange,
6220
+ hasImageUpload,
6221
+ imageMarkdownTokenizer,
6222
+ imageParseMarkdown,
6223
+ imageRenderMarkdown,
4421
6224
  insertMarkdown,
4422
6225
  insertSlashMarkdown,
6226
+ isImageAlignActive,
6227
+ isLinkActive,
4423
6228
  looksLikeMarkdown,
4424
6229
  lowlight,
4425
6230
  makeTocGetId,
@@ -4427,18 +6232,30 @@ export {
4427
6232
  mergeCommentIntervals,
4428
6233
  m as mountChartsInContainer,
4429
6234
  nextComment,
6235
+ normalizeImageAlign,
6236
+ normalizeImageCaption,
6237
+ normalizeLinkHref,
4430
6238
  normalizeMarkdown,
6239
+ openLinkUrl,
4431
6240
  prepareChartMarkdown,
4432
6241
  pureChart,
4433
6242
  pureCodeBlock,
4434
6243
  pureImage,
4435
6244
  r as readCitationAttrs,
6245
+ readLinkHref,
6246
+ removeLink,
4436
6247
  replaceRangeWithMarkdown,
4437
6248
  reportChart,
6249
+ resetImageSize,
4438
6250
  runFindCommand,
6251
+ sanitizeLinkUrl,
4439
6252
  s as scrollToTocHeading,
4440
6253
  selectionKind,
4441
6254
  s2 as serializeChartPayload,
6255
+ setImageAlign,
6256
+ setImageAlignAt,
6257
+ setImageCaption,
6258
+ setImageCaptionAtPos,
4442
6259
  s3 as stabilizeMarkdown,
4443
6260
  stripCommentAnchorMarks,
4444
6261
  useIsMobile