@jvs-milkdown/crepe 1.2.4 → 1.2.7

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 (130) hide show
  1. package/lib/cjs/builder.js +2 -0
  2. package/lib/cjs/builder.js.map +1 -1
  3. package/lib/cjs/feature/block-edit/index.js +6 -2
  4. package/lib/cjs/feature/block-edit/index.js.map +1 -1
  5. package/lib/cjs/feature/code-mirror/index.js +2 -0
  6. package/lib/cjs/feature/code-mirror/index.js.map +1 -1
  7. package/lib/cjs/feature/cursor/index.js +2 -0
  8. package/lib/cjs/feature/cursor/index.js.map +1 -1
  9. package/lib/cjs/feature/image-block/index.js +3 -4
  10. package/lib/cjs/feature/image-block/index.js.map +1 -1
  11. package/lib/cjs/feature/latex/index.js +2 -0
  12. package/lib/cjs/feature/latex/index.js.map +1 -1
  13. package/lib/cjs/feature/link-tooltip/index.js +2 -0
  14. package/lib/cjs/feature/link-tooltip/index.js.map +1 -1
  15. package/lib/cjs/feature/list-item/index.js +2 -0
  16. package/lib/cjs/feature/list-item/index.js.map +1 -1
  17. package/lib/cjs/feature/placeholder/index.js +4 -1
  18. package/lib/cjs/feature/placeholder/index.js.map +1 -1
  19. package/lib/cjs/feature/table/index.js +2 -0
  20. package/lib/cjs/feature/table/index.js.map +1 -1
  21. package/lib/cjs/feature/toolbar/index.js +242 -7
  22. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  23. package/lib/cjs/index.js +1254 -960
  24. package/lib/cjs/index.js.map +1 -1
  25. package/lib/esm/builder.js +2 -0
  26. package/lib/esm/builder.js.map +1 -1
  27. package/lib/esm/feature/block-edit/index.js +6 -2
  28. package/lib/esm/feature/block-edit/index.js.map +1 -1
  29. package/lib/esm/feature/code-mirror/index.js +2 -0
  30. package/lib/esm/feature/code-mirror/index.js.map +1 -1
  31. package/lib/esm/feature/cursor/index.js +2 -0
  32. package/lib/esm/feature/cursor/index.js.map +1 -1
  33. package/lib/esm/feature/image-block/index.js +3 -4
  34. package/lib/esm/feature/image-block/index.js.map +1 -1
  35. package/lib/esm/feature/latex/index.js +2 -0
  36. package/lib/esm/feature/latex/index.js.map +1 -1
  37. package/lib/esm/feature/link-tooltip/index.js +2 -0
  38. package/lib/esm/feature/link-tooltip/index.js.map +1 -1
  39. package/lib/esm/feature/list-item/index.js +2 -0
  40. package/lib/esm/feature/list-item/index.js.map +1 -1
  41. package/lib/esm/feature/placeholder/index.js +4 -1
  42. package/lib/esm/feature/placeholder/index.js.map +1 -1
  43. package/lib/esm/feature/table/index.js +2 -0
  44. package/lib/esm/feature/table/index.js.map +1 -1
  45. package/lib/esm/feature/toolbar/index.js +242 -7
  46. package/lib/esm/feature/toolbar/index.js.map +1 -1
  47. package/lib/esm/index.js +1329 -1035
  48. package/lib/esm/index.js.map +1 -1
  49. package/lib/theme/common/table.css +11 -7
  50. package/lib/theme/common/toolbar.css +6 -6
  51. package/lib/tsconfig.tsbuildinfo +1 -1
  52. package/lib/types/core/locale.d.ts +2 -0
  53. package/lib/types/core/locale.d.ts.map +1 -1
  54. package/lib/types/feature/attachment/view/components/attachment-block.d.ts.map +1 -1
  55. package/lib/types/feature/attachment/view/index.d.ts.map +1 -1
  56. package/lib/types/feature/block-edit/handle/component.d.ts.map +1 -1
  57. package/lib/types/feature/block-edit/handle/index.d.ts.map +1 -1
  58. package/lib/types/feature/block-edit/index.d.ts.map +1 -1
  59. package/lib/types/feature/block-edit/menu/api.d.ts.map +1 -1
  60. package/lib/types/feature/block-edit/menu/component.d.ts.map +1 -1
  61. package/lib/types/feature/block-edit/menu/index.d.ts.map +1 -1
  62. package/lib/types/feature/fixed-toolbar/component.d.ts.map +1 -1
  63. package/lib/types/feature/fixed-toolbar/config.d.ts +9 -1
  64. package/lib/types/feature/fixed-toolbar/config.d.ts.map +1 -1
  65. package/lib/types/feature/fixed-toolbar/document-header.d.ts.map +1 -1
  66. package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
  67. package/lib/types/feature/fixed-toolbar/menu-bar.d.ts.map +1 -1
  68. package/lib/types/feature/fixed-toolbar/outline-panel.d.ts.map +1 -1
  69. package/lib/types/feature/fixed-toolbar/shortcut-help-modal.d.ts.map +1 -1
  70. package/lib/types/feature/fixed-toolbar/view-menu-state.d.ts.map +1 -1
  71. package/lib/types/feature/index.d.ts +1 -1
  72. package/lib/types/feature/index.d.ts.map +1 -1
  73. package/lib/types/feature/latex/inline-tooltip/component.d.ts.map +1 -1
  74. package/lib/types/feature/latex/inline-tooltip/view.d.ts.map +1 -1
  75. package/lib/types/feature/loader.d.ts.map +1 -1
  76. package/lib/types/feature/placeholder/index.d.ts.map +1 -1
  77. package/lib/types/feature/toolbar/color.d.ts +1 -1
  78. package/lib/types/feature/toolbar/color.d.ts.map +1 -1
  79. package/lib/types/feature/toolbar/component.d.ts.map +1 -1
  80. package/lib/types/feature/toolbar/font.d.ts +1 -1
  81. package/lib/types/feature/toolbar/highlight-mark.d.ts +1 -1
  82. package/lib/types/feature/toolbar/index.d.ts.map +1 -1
  83. package/lib/types/feature/toolbar/underline.d.ts +1 -1
  84. package/lib/types/icons/crop.d.ts +1 -1
  85. package/lib/types/icons/crop.d.ts.map +1 -1
  86. package/lib/types/icons/format-painter.d.ts +2 -0
  87. package/lib/types/icons/format-painter.d.ts.map +1 -0
  88. package/lib/types/icons/index.d.ts +1 -0
  89. package/lib/types/icons/index.d.ts.map +1 -1
  90. package/package.json +4 -4
  91. package/src/core/locale.ts +2 -0
  92. package/src/feature/attachment/view/components/attachment-block.tsx +12 -7
  93. package/src/feature/attachment/view/index.ts +1 -0
  94. package/src/feature/block-edit/handle/component.tsx +5 -4
  95. package/src/feature/block-edit/handle/index.ts +1 -0
  96. package/src/feature/block-edit/index.ts +4 -1
  97. package/src/feature/block-edit/menu/api.ts +6 -1
  98. package/src/feature/block-edit/menu/component.tsx +49 -46
  99. package/src/feature/block-edit/menu/index.ts +1 -0
  100. package/src/feature/fixed-toolbar/component.tsx +3 -2
  101. package/src/feature/fixed-toolbar/config.ts +198 -146
  102. package/src/feature/fixed-toolbar/document-header.tsx +45 -14
  103. package/src/feature/fixed-toolbar/index.ts +2 -1
  104. package/src/feature/fixed-toolbar/menu-bar.tsx +15 -10
  105. package/src/feature/fixed-toolbar/outline-panel.tsx +17 -16
  106. package/src/feature/fixed-toolbar/shortcut-help-modal.tsx +3 -2
  107. package/src/feature/fixed-toolbar/view-menu-state.ts +1 -0
  108. package/src/feature/index.ts +1 -1
  109. package/src/feature/latex/inline-tooltip/component.tsx +3 -2
  110. package/src/feature/latex/inline-tooltip/view.ts +1 -0
  111. package/src/feature/loader.ts +1 -1
  112. package/src/feature/placeholder/index.ts +2 -1
  113. package/src/feature/toolbar/color.ts +77 -73
  114. package/src/feature/toolbar/component.tsx +321 -35
  115. package/src/feature/toolbar/index.ts +1 -0
  116. package/src/icons/align-center.ts +1 -1
  117. package/src/icons/bold.ts +1 -1
  118. package/src/icons/bullet-list.ts +1 -1
  119. package/src/icons/crop.ts +1 -4
  120. package/src/icons/divider.ts +1 -1
  121. package/src/icons/format-painter.ts +5 -0
  122. package/src/icons/h2.ts +1 -1
  123. package/src/icons/index.ts +1 -0
  124. package/src/icons/ordered-list.ts +1 -1
  125. package/src/icons/quote.ts +1 -1
  126. package/src/icons/strikethrough.ts +1 -1
  127. package/src/icons/text.ts +0 -1
  128. package/src/theme/common/table.css +11 -7
  129. package/src/theme/common/toolbar.css +6 -6
  130. package/src/feature/table/test.ts +0 -9
package/lib/cjs/index.js CHANGED
@@ -3,18 +3,18 @@
3
3
  var lodashEs = require('lodash-es');
4
4
  var languageData = require('@codemirror/language-data');
5
5
  var themeOneDark = require('@codemirror/theme-one-dark');
6
- var block = require('@jvs-milkdown/kit/plugin/block');
7
6
  var ctx = require('@jvs-milkdown/kit/ctx');
7
+ var utils = require('@jvs-milkdown/kit/utils');
8
+ var vue = require('vue');
9
+ var component = require('@jvs-milkdown/kit/component');
10
+ var block = require('@jvs-milkdown/kit/plugin/block');
8
11
  var core = require('@jvs-milkdown/kit/core');
9
12
  var prose = require('@jvs-milkdown/kit/prose');
10
13
  var state = require('@jvs-milkdown/kit/prose/state');
11
- var vue = require('vue');
12
14
  var dom = require('@floating-ui/dom');
13
15
  var slash = require('@jvs-milkdown/kit/plugin/slash');
14
- var component = require('@jvs-milkdown/kit/component');
15
16
  var commonmark = require('@jvs-milkdown/kit/preset/commonmark');
16
17
  var gfm = require('@jvs-milkdown/kit/preset/gfm');
17
- var utils = require('@jvs-milkdown/kit/utils');
18
18
  var unistUtilVisit = require('unist-util-visit');
19
19
  var imageBlock$1 = require('@jvs-milkdown/kit/component/image-block');
20
20
  var commands = require('@jvs-milkdown/kit/prose/commands');
@@ -629,10 +629,7 @@ const wordWrapIcon = `
629
629
  `;
630
630
 
631
631
  const cropIcon = `
632
- <svg viewBox="0 0 1024 1024" height="24px" width="24px">
633
- <path d="M192 128v128H128v64h192V128h-128z m0 0h64v128h-64V128z m512 0v128h192v64H640V128h64z m-512 640H128v-64h192v192h-128v-128z m0 128h64v-128h-64v128z m512 0v-128h192v64h-128v128h-64z m0 0h64v-128h-64v128z" fill="currentColor"/>
634
- <path d="M256 256h512v512H256z" fill="none" stroke="currentColor" stroke-width="64"/>
635
- </svg>
632
+ <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7429" width="24px" height="24px"><path d="M279.296 46.592a46.592 46.592 0 1 0-93.1328 0v139.5712H46.592a46.592 46.592 0 1 0 0 93.1328h139.6224v512c0 25.7024 20.8384 46.5408 46.592 46.5408h512v139.6224a46.592 46.592 0 0 0 93.0816 0v-139.6224h139.6224a46.592 46.592 0 1 0 0-93.1328H279.296V46.592z m139.6224 139.5712a46.592 46.592 0 1 0 0 93.1328h325.7856v325.7856a46.592 46.592 0 0 0 93.1328 0V232.704a46.592 46.592 0 0 0-46.592-46.5408H418.9696z" fill="currentColor" p-id="7430"></path></svg>
636
633
  `;
637
634
 
638
635
  const borderIcon = `
@@ -641,6 +638,12 @@ const borderIcon = `
641
638
  </svg>
642
639
  `;
643
640
 
641
+ const formatPainterIcon = `
642
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
643
+ <path d="M454.698667 302.506667H323.84q-23.04 0-41.6 13.824-18.517333 13.824-25.130667 35.968l-31.36 104.704q-10.112 33.621333 10.794667 61.738666 11.52 15.445333 27.221333 22.442667 0.853333 46.165333-0.810666 105.6-1.408 51.84-58.368 138.496-23.338667 35.413333-3.413334 72.96 20.053333 37.76 62.677334 37.76h477.994666q39.509333 0 69.077334-26.325333 29.738667-26.453333 34.090666-65.962667 10.24-93.738667 10.24-155.946667 0-57.088-8.618666-103.68 20.949333-6.058667 35.285333-25.344 20.864-28.117333 10.837333-61.738666l-31.36-104.704q-6.656-22.144-25.173333-35.968-18.517333-13.781333-41.6-13.781334h-130.858667V197.802667q0-28.885333-20.437333-49.365334Q622.933333 128 594.090667 128H524.373333q-28.842667 0-49.237333 20.48-20.437333 20.437333-20.437333 49.322667v104.746666z m68.992 41.728q0.682667-3.370667 0.682666-6.784V197.802667h69.717334V337.493333q0 3.413333 0.64 6.826667 0.682667 3.370667 2.005333 6.528 1.28 3.2 3.2 6.058667 1.92 2.816 4.352 5.248 2.389333 2.474667 5.248 4.352 2.901333 1.92 6.058667 3.242666 3.157333 1.322667 6.528 1.962667 3.328 0.682667 6.826666 0.682667h165.674667l31.36 104.746666H292.48l31.36-104.746666h165.717333q3.413333 0 6.826667-0.64 3.328-0.682667 6.528-2.005334 3.157333-1.322667 5.973333-3.242666 2.858667-1.877333 5.290667-4.352 2.432-2.432 4.309333-5.248 1.92-2.901333 3.242667-6.058667 1.322667-3.157333 1.962667-6.570667z m252.501333 202.666666q9.429333 43.648 9.429333 100.864 0 58.368-9.813333 148.352-1.450667 12.757333-11.093333 21.376-9.813333 8.704-22.826667 8.704h-100.309333q22.058667-81.493333 22.058666-174.592h-69.674666q0 94.421333-24.96 174.592h-121.514667q41.941333-81.450667 41.941333-174.592H419.754667q0 94.378667-52.992 174.592H263.808q-0.725333 0-1.109333-0.725333-0.469333-0.981333 0.042666-1.749333 67.968-103.253333 69.888-175.018667 1.536-56.533333 0.938667-101.802667H776.106667z" fill="currentColor" p-id="11997"></path>
644
+ </svg>
645
+ `;
646
+
644
647
  const defaultConfig = {
645
648
  [CrepeFeature.CodeMirror]: {
646
649
  theme: themeOneDark.oneDark,
@@ -663,6 +666,7 @@ const zhCN = {
663
666
  "toolbar.heading": "\u6807\u9898",
664
667
  "toolbar.formatting": "\u683C\u5F0F",
665
668
  "toolbar.function": "\u529F\u80FD",
669
+ "toolbar.formatPainter": "\u683C\u5F0F\u5237",
666
670
  // menu bar
667
671
  "menuBar.file": "\u6587\u4EF6",
668
672
  "menuBar.edit": "\u7F16\u8F91",
@@ -816,6 +820,7 @@ const enUS = {
816
820
  "toolbar.heading": "Heading",
817
821
  "toolbar.formatting": "Formatting",
818
822
  "toolbar.function": "Function",
823
+ "toolbar.formatPainter": "Format Painter",
819
824
  "menuBar.file": "File",
820
825
  "menuBar.edit": "Edit",
821
826
  "menuBar.view": "View",
@@ -983,98 +988,489 @@ function crepeFeatureConfig(feature) {
983
988
  };
984
989
  }
985
990
 
986
- function isInCodeBlock(selection) {
987
- const type = selection.$from.parent.type;
988
- return type.name === "code_block";
989
- }
990
- function isInList(selection) {
991
- var _a;
992
- const type = (_a = selection.$from.node(selection.$from.depth - 1)) == null ? void 0 : _a.type;
993
- return (type == null ? void 0 : type.name) === "list_item";
994
- }
991
+ const attachmentConfig = utils.$ctx(
992
+ {
993
+ onUpload: async (file) => {
994
+ return {
995
+ url: URL.createObjectURL(file),
996
+ name: file.name,
997
+ size: file.size
998
+ };
999
+ },
1000
+ uploadButton: "Upload file",
1001
+ uploadPlaceholderText: "or paste link",
1002
+ downloadText: "Download"
1003
+ },
1004
+ "attachmentConfig"
1005
+ );
995
1006
 
996
- var __typeError$6 = (msg) => {
997
- throw TypeError(msg);
998
- };
999
- var __accessCheck$6 = (obj, member, msg) => member.has(obj) || __typeError$6("Cannot " + msg);
1000
- var __privateGet$6 = (obj, member, getter) => (__accessCheck$6(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
1001
- var __privateAdd$6 = (obj, member, value) => member.has(obj) ? __typeError$6("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1002
- var __privateSet$6 = (obj, member, value, setter) => (__accessCheck$6(obj, member, "write to private field"), member.set(obj, value), value);
1003
- var _groups, _getGroupInstance;
1004
- class GroupBuilder {
1005
- constructor() {
1006
- __privateAdd$6(this, _groups, []);
1007
- this.clear = () => {
1008
- __privateSet$6(this, _groups, []);
1009
- return this;
1010
- };
1011
- __privateAdd$6(this, _getGroupInstance, (group) => {
1012
- const groupInstance = {
1013
- group,
1014
- addItem: (key, item) => {
1015
- const data = { ...item, key };
1016
- group.items.push(data);
1017
- return groupInstance;
1018
- },
1019
- clear: () => {
1020
- group.items = [];
1021
- return groupInstance;
1007
+ const ATTACHMENT_DATA_TYPE = "attachment-block";
1008
+ const attachmentSchema = utils.$nodeSchema("attachment", () => {
1009
+ return {
1010
+ inline: false,
1011
+ group: "block",
1012
+ selectable: true,
1013
+ draggable: true,
1014
+ isolating: true,
1015
+ marks: "",
1016
+ atom: true,
1017
+ priority: 100,
1018
+ attrs: {
1019
+ src: { default: "", validate: "string" },
1020
+ name: { default: "", validate: "string" },
1021
+ size: { default: 0, validate: "number" },
1022
+ videoWidth: { default: 0, validate: "number" }
1023
+ },
1024
+ parseDOM: [
1025
+ {
1026
+ tag: `a[data-type="${ATTACHMENT_DATA_TYPE}"]`,
1027
+ getAttrs: (dom) => {
1028
+ if (!(dom instanceof HTMLElement))
1029
+ throw new TypeError("Expect dom to be HTMLElement");
1030
+ return {
1031
+ src: dom.getAttribute("href") || "",
1032
+ name: dom.getAttribute("data-name") || "",
1033
+ size: Number(dom.getAttribute("data-size") || 0),
1034
+ videoWidth: Number(dom.getAttribute("data-video-width") || 0)
1035
+ };
1022
1036
  }
1023
- };
1024
- return groupInstance;
1037
+ }
1038
+ ],
1039
+ toDOM: (node) => [
1040
+ "a",
1041
+ {
1042
+ "data-type": ATTACHMENT_DATA_TYPE,
1043
+ href: node.attrs.src,
1044
+ "data-name": node.attrs.name,
1045
+ "data-size": String(node.attrs.size),
1046
+ "data-video-width": String(node.attrs.videoWidth || 0),
1047
+ class: "attachment"
1048
+ },
1049
+ node.attrs.name
1050
+ ],
1051
+ parseMarkdown: {
1052
+ match: (node) => {
1053
+ return node.type === "attachment";
1054
+ },
1055
+ runner: (state, node, type) => {
1056
+ state.addNode(type, {
1057
+ src: node.url,
1058
+ name: node.name || "",
1059
+ size: Number(node.size || 0)
1060
+ });
1061
+ }
1062
+ },
1063
+ toMarkdown: {
1064
+ match: (node) => node.type.name === "attachment",
1065
+ runner: (state, node) => {
1066
+ state.openNode("paragraph");
1067
+ state.addNode(
1068
+ "html",
1069
+ void 0,
1070
+ `<a href="${node.attrs.src}" data-size="${node.attrs.size}" data-name="${node.attrs.name}" data-video-width="${node.attrs.videoWidth || 0}" data-type="${ATTACHMENT_DATA_TYPE}" class="attachment">${node.attrs.name}</a>`
1071
+ );
1072
+ state.closeNode();
1073
+ }
1074
+ }
1075
+ };
1076
+ });
1077
+
1078
+ const downloadIcon = `<svg viewBox="0 0 1024 1024" width="20" height="20" fill="currentColor">
1079
+ <path d="M464.96 743.936L194.304 479.68c-4.928-4.8-10.24-9.408-14.592-14.656-20.736-24.768-21.376-45.76-2.368-63.424 17.664-16.384 43.328-16 65.472 4.8 49.088 46.144 96.64 93.824 144.896 140.8l69.376 67.52 11.968 11.392v-184.96c0-36.096-0.128-86.272-0.32-136.96-0.192-54.912-0.32-110.464-0.32-149.504l-0.064-9.28a208 208 0 0 1 0.704-26.56c3.52-31.168 19.328-46.592 45.248-45.76 25.344 0.832 41.088 16.96 42.688 48.576 1.28 24.384 1.024 48.896 0.768 73.408l-0.128 28.928c0 53.376 0.128 120.32 0.256 188.096 0.192 76.352 0.384 153.792 0.32 214.016 74.432-72.704 185.6-181.12 216.32-210.88 7.424-7.168 14.912-15.168 24-19.52 18.688-8.96 37.632-8.32 52.672 7.872 14.72 15.744 16.448 33.408 4.032 51.392-3.84 5.632-8.576 10.816-13.44 15.616-45.696 44.736-243.328 238.272-289.728 282.24a62.592 62.592 0 0 1-8.064 6.4 43.392 43.392 0 0 1-15.872 10.432c-20.544 7.616-37.504-0.512-51.968-14.848l-11.2-10.88z m430.784-39.744c24-0.576 42.176 14.4 43.328 41.6 1.728 40.832 2.944 82.176-1.088 122.816-5.312 54.144-51.52 89.792-114.752 91.008-50.112 0.896-100.224 0.704-150.4 0.512L608 960H434.944c-64.832 0.128-129.6 0.192-194.432-0.192-90.624-0.512-130.752-40.192-131.392-128.64l-0.192-18.56c-0.32-21.12-0.576-42.304 0.768-63.36 1.92-29.76 20.48-46.528 45.76-45.184 23.488 1.28 37.312 16.32 40.064 45.184 0.896 9.792 0.832 19.648 0.704 29.504l-0.064 11.52c0.384 76.544 7.36 83.392 88.128 83.456a163213.952 163213.952 0 0 0 351.68 0.064l43.968 0.128c36.096 0.128 72.192 0.256 108.288-0.448 52.672-1.024 64-12.864 65.152-64.32 0.192-7.68 0.128-15.488 0-23.232a414.72 414.72 0 0 1 0.704-38.208c2.24-27.712 17.92-42.944 41.664-43.52z" fill="currentColor"></path>
1080
+ </svg>`;
1081
+ function formatBytes(bytes, decimals = 2) {
1082
+ if (!+bytes) return "0 Bytes";
1083
+ const k = 1024;
1084
+ const dm = decimals < 0 ? 0 : decimals;
1085
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
1086
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1087
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
1088
+ }
1089
+ const MilkdownAttachmentBlock = vue.defineComponent({
1090
+ props: {
1091
+ src: { type: Object, required: true },
1092
+ name: { type: Object, required: true },
1093
+ size: { type: Object, required: true },
1094
+ videoWidth: { type: Object, required: true },
1095
+ selected: { type: Object, required: true },
1096
+ readonly: { type: Object, required: true },
1097
+ setAttr: { type: Function, required: true },
1098
+ config: { type: Object, required: true }
1099
+ },
1100
+ setup(props) {
1101
+ const { src, name, size, videoWidth } = props;
1102
+ const isUploading = vue.shallowRef(false);
1103
+ const fileInput = vue.shallowRef(null);
1104
+ const videoWrapperRef = vue.ref(null);
1105
+ const currentWidth = vue.ref(0);
1106
+ const isResizing = vue.ref(false);
1107
+ const isVideo = vue.computed(() => {
1108
+ return name.value && /\.(mp4|webm|ogg|mov|avi|mkv|flv|wmv|m4v|3gp|ts)$/i.test(name.value);
1025
1109
  });
1026
- this.addGroup = (key, label) => {
1027
- const items = [];
1028
- const group = {
1029
- key,
1030
- label,
1031
- items
1032
- };
1033
- __privateGet$6(this, _groups).push(group);
1034
- return __privateGet$6(this, _getGroupInstance).call(this, group);
1110
+ let resizeDir = "";
1111
+ let startX = 0;
1112
+ let startWidth = 0;
1113
+ const triggerUpload = () => {
1114
+ var _a;
1115
+ (_a = fileInput.value) == null ? void 0 : _a.click();
1035
1116
  };
1036
- this.getGroup = (key) => {
1037
- const group = __privateGet$6(this, _groups).find((group2) => group2.key === key);
1038
- if (!group) throw new Error(`Group with key ${key} not found`);
1039
- return __privateGet$6(this, _getGroupInstance).call(this, group);
1117
+ const onFileChange = async (e) => {
1118
+ var _a;
1119
+ const target = e.target;
1120
+ const file = (_a = target.files) == null ? void 0 : _a[0];
1121
+ if (!file) return;
1122
+ isUploading.value = true;
1123
+ try {
1124
+ const result = await props.config.onUpload(file);
1125
+ props.setAttr("src", result.url);
1126
+ props.setAttr("name", result.name);
1127
+ props.setAttr("size", result.size);
1128
+ } catch (err) {
1129
+ console.error("Failed to upload file", err);
1130
+ } finally {
1131
+ isUploading.value = false;
1132
+ target.value = "";
1133
+ }
1040
1134
  };
1041
- this.build = () => {
1042
- return __privateGet$6(this, _groups);
1135
+ const openLink = () => {
1136
+ if (src.value) {
1137
+ window.open(src.value, "_blank");
1138
+ }
1043
1139
  };
1044
- }
1045
- }
1046
- _groups = new WeakMap();
1047
- _getGroupInstance = new WeakMap();
1048
-
1049
- function keepAlive(..._args) {
1050
- }
1051
-
1052
- const remarkTextColorPlugin = utils.$remark(
1053
- "remarkTextColor",
1054
- () => function() {
1055
- const data = this.data();
1056
- function add(key, value) {
1057
- if (Array.isArray(data[key])) {
1058
- data[key].push(value);
1059
- } else {
1060
- data[key] = [value];
1140
+ let activeHandle = null;
1141
+ const onResizePointerMove = (e) => {
1142
+ e.preventDefault();
1143
+ const deltaX = e.clientX - startX;
1144
+ let dw = 0;
1145
+ if (resizeDir.includes("right")) {
1146
+ dw = deltaX;
1147
+ } else if (resizeDir.includes("left")) {
1148
+ dw = -deltaX;
1061
1149
  }
1062
- }
1063
- add("toMarkdownExtensions", {
1064
- handlers: {
1065
- textColor: (node, _, state) => {
1066
- return `<span style="color:${node.color}">${state.containerPhrasing(node, state)}</span>`;
1067
- },
1068
- bgColor: (node, _, state) => {
1069
- return `<span style="background-color:${node.color}">${state.containerPhrasing(node, state)}</span>`;
1150
+ let newWidth = startWidth + dw;
1151
+ if (newWidth < 200) newWidth = 200;
1152
+ const wrapper = videoWrapperRef.value;
1153
+ if (wrapper) {
1154
+ const parent = wrapper.closest(".milkdown-attachment-block-wrapper");
1155
+ if (parent) {
1156
+ const maxWidth = parent.getBoundingClientRect().width;
1157
+ if (newWidth > maxWidth) newWidth = maxWidth;
1070
1158
  }
1071
1159
  }
1072
- });
1073
- return (ast) => {
1074
- unistUtilVisit.visit(ast, (node, index, parent) => {
1075
- if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<span") && parent && index != null) {
1076
- const hasTextColor = node.value.includes("color:") && !node.value.match(/background-color:\s*([^"';>]+)/);
1077
- const hasBgColor = node.value.includes("background-color:");
1160
+ currentWidth.value = newWidth;
1161
+ };
1162
+ const onResizePointerUp = (e) => {
1163
+ if (activeHandle) {
1164
+ activeHandle.releasePointerCapture(e.pointerId);
1165
+ activeHandle.removeEventListener(
1166
+ "pointermove",
1167
+ onResizePointerMove
1168
+ );
1169
+ activeHandle.removeEventListener(
1170
+ "pointerup",
1171
+ onResizePointerUp
1172
+ );
1173
+ activeHandle = null;
1174
+ }
1175
+ isResizing.value = false;
1176
+ if (currentWidth.value > 0) {
1177
+ props.setAttr("videoWidth", Math.round(currentWidth.value));
1178
+ }
1179
+ };
1180
+ const onResizePointerDown = (e, dir) => {
1181
+ if (props.readonly.value) return;
1182
+ e.preventDefault();
1183
+ e.stopPropagation();
1184
+ resizeDir = dir;
1185
+ startX = e.clientX;
1186
+ isResizing.value = true;
1187
+ const handle = e.currentTarget;
1188
+ activeHandle = handle;
1189
+ handle.setPointerCapture(e.pointerId);
1190
+ const wrapper = videoWrapperRef.value;
1191
+ if (wrapper) {
1192
+ startWidth = wrapper.getBoundingClientRect().width;
1193
+ currentWidth.value = startWidth;
1194
+ }
1195
+ handle.addEventListener("pointermove", onResizePointerMove);
1196
+ handle.addEventListener("pointerup", onResizePointerUp);
1197
+ };
1198
+ return () => {
1199
+ var _a;
1200
+ if (!((_a = src.value) == null ? void 0 : _a.length)) {
1201
+ return /* @__PURE__ */ h(
1202
+ "div",
1203
+ {
1204
+ class: [
1205
+ "milkdown-attachment-placeholder",
1206
+ props.selected.value ? "selected" : ""
1207
+ ]
1208
+ },
1209
+ /* @__PURE__ */ h("div", { class: "milkdown-attachment-uploader", onClick: triggerUpload }, /* @__PURE__ */ h(component.Icon, { icon: fileLinkIcon }), /* @__PURE__ */ h("span", { class: "milkdown-attachment-upload-text" }, isUploading.value ? "Uploading..." : props.config.uploadButton), /* @__PURE__ */ h(
1210
+ "input",
1211
+ {
1212
+ type: "file",
1213
+ ref: fileInput,
1214
+ onChange: onFileChange,
1215
+ style: "display: none;"
1216
+ }
1217
+ ))
1218
+ );
1219
+ }
1220
+ if (isVideo.value) {
1221
+ const savedWidth = videoWidth.value;
1222
+ const widthStyle = isResizing.value && currentWidth.value > 0 ? `${currentWidth.value}px` : savedWidth && savedWidth > 0 ? `${savedWidth}px` : "100%";
1223
+ return /* @__PURE__ */ h(
1224
+ "div",
1225
+ {
1226
+ ref: videoWrapperRef,
1227
+ class: [
1228
+ "milkdown-attachment-video-viewer",
1229
+ props.selected.value ? "selected" : ""
1230
+ ],
1231
+ style: {
1232
+ width: widthStyle,
1233
+ margin: "0 auto",
1234
+ position: "relative"
1235
+ }
1236
+ },
1237
+ /* @__PURE__ */ h(
1238
+ "video",
1239
+ {
1240
+ src: src.value,
1241
+ controls: true,
1242
+ style: "width: 100%; display: block; border-radius: 8px;",
1243
+ onMousedown: (e) => e.stopPropagation()
1244
+ }
1245
+ ),
1246
+ /* @__PURE__ */ h(
1247
+ "div",
1248
+ {
1249
+ class: "video-resize-handle top-left",
1250
+ onPointerdown: (e) => onResizePointerDown(e, "top-left")
1251
+ }
1252
+ ),
1253
+ /* @__PURE__ */ h(
1254
+ "div",
1255
+ {
1256
+ class: "video-resize-handle top-right",
1257
+ onPointerdown: (e) => onResizePointerDown(e, "top-right")
1258
+ }
1259
+ ),
1260
+ /* @__PURE__ */ h(
1261
+ "div",
1262
+ {
1263
+ class: "video-resize-handle bottom-left",
1264
+ onPointerdown: (e) => onResizePointerDown(e, "bottom-left")
1265
+ }
1266
+ ),
1267
+ /* @__PURE__ */ h(
1268
+ "div",
1269
+ {
1270
+ class: "video-resize-handle bottom-right",
1271
+ onPointerdown: (e) => onResizePointerDown(e, "bottom-right")
1272
+ }
1273
+ )
1274
+ );
1275
+ }
1276
+ return /* @__PURE__ */ h(
1277
+ "div",
1278
+ {
1279
+ class: [
1280
+ "milkdown-attachment-viewer",
1281
+ props.selected.value ? "selected" : ""
1282
+ ]
1283
+ },
1284
+ /* @__PURE__ */ h("div", { class: "milkdown-attachment-icon-wrapper" }, /* @__PURE__ */ h("div", { class: "milkdown-attachment-raw-icon-bg" }, /* @__PURE__ */ h(component.Icon, { icon: fileLinkIcon }))),
1285
+ /* @__PURE__ */ h("div", { class: "milkdown-attachment-info" }, /* @__PURE__ */ h("div", { class: "milkdown-attachment-name" }, name.value), /* @__PURE__ */ h("div", { class: "milkdown-attachment-size" }, (size.value || 0) > 0 ? formatBytes(size.value) : "")),
1286
+ /* @__PURE__ */ h(
1287
+ "div",
1288
+ {
1289
+ class: "milkdown-attachment-action",
1290
+ onClick: openLink,
1291
+ title: props.config.downloadText
1292
+ },
1293
+ /* @__PURE__ */ h(component.Icon, { icon: downloadIcon })
1294
+ )
1295
+ );
1296
+ };
1297
+ }
1298
+ });
1299
+
1300
+ const attachmentView = utils.$view(
1301
+ attachmentSchema.node,
1302
+ (ctx) => {
1303
+ return (initialNode, view, getPos) => {
1304
+ const src = vue.ref(initialNode.attrs.src);
1305
+ const name = vue.ref(initialNode.attrs.name);
1306
+ const size = vue.ref(initialNode.attrs.size);
1307
+ const videoWidth = vue.ref(initialNode.attrs.videoWidth);
1308
+ const selected = vue.ref(false);
1309
+ const readonly = vue.ref(!view.editable);
1310
+ const setAttr = (attr, value) => {
1311
+ if (!view.editable) return;
1312
+ const pos = getPos();
1313
+ if (pos == null) return;
1314
+ view.dispatch(view.state.tr.setNodeAttribute(pos, attr, value));
1315
+ };
1316
+ const config = ctx.get(attachmentConfig.key);
1317
+ const app = vue.createApp(MilkdownAttachmentBlock, {
1318
+ src,
1319
+ name,
1320
+ size,
1321
+ videoWidth,
1322
+ selected,
1323
+ readonly,
1324
+ setAttr,
1325
+ config
1326
+ });
1327
+ const dom = document.createElement("div");
1328
+ dom.className = "milkdown-attachment-block-wrapper";
1329
+ const disposeSelectedWatcher = vue.watchEffect(() => {
1330
+ if (selected.value) {
1331
+ dom.classList.add("selected");
1332
+ } else {
1333
+ dom.classList.remove("selected");
1334
+ }
1335
+ });
1336
+ const bindAttrs = (node) => {
1337
+ src.value = node.attrs.src;
1338
+ name.value = node.attrs.name;
1339
+ size.value = node.attrs.size;
1340
+ videoWidth.value = node.attrs.videoWidth;
1341
+ readonly.value = !view.editable;
1342
+ };
1343
+ bindAttrs(initialNode);
1344
+ app.mount(dom);
1345
+ return {
1346
+ dom,
1347
+ update: (updatedNode) => {
1348
+ if (updatedNode.type !== initialNode.type) return false;
1349
+ bindAttrs(updatedNode);
1350
+ return true;
1351
+ },
1352
+ selectNode: () => {
1353
+ selected.value = true;
1354
+ },
1355
+ deselectNode: () => {
1356
+ selected.value = false;
1357
+ },
1358
+ destroy: () => {
1359
+ disposeSelectedWatcher();
1360
+ app.unmount();
1361
+ dom.remove();
1362
+ }
1363
+ };
1364
+ };
1365
+ }
1366
+ );
1367
+
1368
+ const attachment = (editor, config) => {
1369
+ editor.config(crepeFeatureConfig(CrepeFeature.Attachment)).config((ctx) => {
1370
+ ctx.update(attachmentConfig.key, (value) => {
1371
+ var _a, _b, _c, _d;
1372
+ return {
1373
+ uploadButton: (_a = config == null ? void 0 : config.uploadButton) != null ? _a : i18n(ctx, "attachmentBlock.uploadButton"),
1374
+ uploadPlaceholderText: (_b = config == null ? void 0 : config.uploadPlaceholderText) != null ? _b : i18n(ctx, "attachmentBlock.uploadPlaceholderText"),
1375
+ downloadText: (_c = config == null ? void 0 : config.downloadText) != null ? _c : i18n(ctx, "attachmentBlock.download"),
1376
+ onUpload: (_d = config == null ? void 0 : config.onUpload) != null ? _d : value.onUpload
1377
+ };
1378
+ });
1379
+ }).use(attachmentConfig).use(attachmentSchema).use(attachmentView);
1380
+ };
1381
+
1382
+ function isInCodeBlock(selection) {
1383
+ const type = selection.$from.parent.type;
1384
+ return type.name === "code_block";
1385
+ }
1386
+ function isInList(selection) {
1387
+ var _a;
1388
+ const type = (_a = selection.$from.node(selection.$from.depth - 1)) == null ? void 0 : _a.type;
1389
+ return (type == null ? void 0 : type.name) === "list_item";
1390
+ }
1391
+
1392
+ var __typeError$6 = (msg) => {
1393
+ throw TypeError(msg);
1394
+ };
1395
+ var __accessCheck$6 = (obj, member, msg) => member.has(obj) || __typeError$6("Cannot " + msg);
1396
+ var __privateGet$6 = (obj, member, getter) => (__accessCheck$6(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
1397
+ var __privateAdd$6 = (obj, member, value) => member.has(obj) ? __typeError$6("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
1398
+ var __privateSet$6 = (obj, member, value, setter) => (__accessCheck$6(obj, member, "write to private field"), member.set(obj, value), value);
1399
+ var _groups, _getGroupInstance;
1400
+ class GroupBuilder {
1401
+ constructor() {
1402
+ __privateAdd$6(this, _groups, []);
1403
+ this.clear = () => {
1404
+ __privateSet$6(this, _groups, []);
1405
+ return this;
1406
+ };
1407
+ __privateAdd$6(this, _getGroupInstance, (group) => {
1408
+ const groupInstance = {
1409
+ group,
1410
+ addItem: (key, item) => {
1411
+ const data = { ...item, key };
1412
+ group.items.push(data);
1413
+ return groupInstance;
1414
+ },
1415
+ clear: () => {
1416
+ group.items = [];
1417
+ return groupInstance;
1418
+ }
1419
+ };
1420
+ return groupInstance;
1421
+ });
1422
+ this.addGroup = (key, label) => {
1423
+ const items = [];
1424
+ const group = {
1425
+ key,
1426
+ label,
1427
+ items
1428
+ };
1429
+ __privateGet$6(this, _groups).push(group);
1430
+ return __privateGet$6(this, _getGroupInstance).call(this, group);
1431
+ };
1432
+ this.getGroup = (key) => {
1433
+ const group = __privateGet$6(this, _groups).find((group2) => group2.key === key);
1434
+ if (!group) throw new Error(`Group with key ${key} not found`);
1435
+ return __privateGet$6(this, _getGroupInstance).call(this, group);
1436
+ };
1437
+ this.build = () => {
1438
+ return __privateGet$6(this, _groups);
1439
+ };
1440
+ }
1441
+ }
1442
+ _groups = new WeakMap();
1443
+ _getGroupInstance = new WeakMap();
1444
+
1445
+ function keepAlive(..._args) {
1446
+ }
1447
+
1448
+ const remarkTextColorPlugin = utils.$remark(
1449
+ "remarkTextColor",
1450
+ () => function() {
1451
+ const data = this.data();
1452
+ function add(key, value) {
1453
+ if (Array.isArray(data[key])) {
1454
+ data[key].push(value);
1455
+ } else {
1456
+ data[key] = [value];
1457
+ }
1458
+ }
1459
+ add("toMarkdownExtensions", {
1460
+ handlers: {
1461
+ textColor: (node, _, state) => {
1462
+ return `<span style="color:${node.color}">${state.containerPhrasing(node, state)}</span>`;
1463
+ },
1464
+ bgColor: (node, _, state) => {
1465
+ return `<span style="background-color:${node.color}">${state.containerPhrasing(node, state)}</span>`;
1466
+ }
1467
+ }
1468
+ });
1469
+ return (ast) => {
1470
+ unistUtilVisit.visit(ast, (node, index, parent) => {
1471
+ if ((node == null ? void 0 : node.type) === "html" && node.value.startsWith("<span") && parent && index != null) {
1472
+ const hasTextColor = node.value.includes("color:") && !node.value.match(/background-color:\s*([^"';>]+)/);
1473
+ const hasBgColor = node.value.includes("background-color:");
1078
1474
  if (!hasTextColor && !hasBgColor) return;
1079
1475
  let color = null;
1080
1476
  let markType = null;
@@ -1282,86 +1678,15 @@ const menuAPI = utils.$ctx(
1282
1678
  },
1283
1679
  onHoverDelayHide: () => {
1284
1680
  },
1285
- cancelHide: () => {
1286
- },
1287
- isProgrammatic: () => false,
1288
- getPos: () => null,
1289
- isShow: () => false,
1290
- getMode: () => null
1291
- },
1292
- "menuAPICtx"
1293
- );
1294
-
1295
- const ATTACHMENT_DATA_TYPE = "attachment-block";
1296
- const attachmentSchema = utils.$nodeSchema("attachment", () => {
1297
- return {
1298
- inline: false,
1299
- group: "block",
1300
- selectable: true,
1301
- draggable: true,
1302
- isolating: true,
1303
- marks: "",
1304
- atom: true,
1305
- priority: 100,
1306
- attrs: {
1307
- src: { default: "", validate: "string" },
1308
- name: { default: "", validate: "string" },
1309
- size: { default: 0, validate: "number" },
1310
- videoWidth: { default: 0, validate: "number" }
1311
- },
1312
- parseDOM: [
1313
- {
1314
- tag: `a[data-type="${ATTACHMENT_DATA_TYPE}"]`,
1315
- getAttrs: (dom) => {
1316
- if (!(dom instanceof HTMLElement))
1317
- throw new TypeError("Expect dom to be HTMLElement");
1318
- return {
1319
- src: dom.getAttribute("href") || "",
1320
- name: dom.getAttribute("data-name") || "",
1321
- size: Number(dom.getAttribute("data-size") || 0),
1322
- videoWidth: Number(dom.getAttribute("data-video-width") || 0)
1323
- };
1324
- }
1325
- }
1326
- ],
1327
- toDOM: (node) => [
1328
- "a",
1329
- {
1330
- "data-type": ATTACHMENT_DATA_TYPE,
1331
- href: node.attrs.src,
1332
- "data-name": node.attrs.name,
1333
- "data-size": String(node.attrs.size),
1334
- "data-video-width": String(node.attrs.videoWidth || 0),
1335
- class: "attachment"
1336
- },
1337
- node.attrs.name
1338
- ],
1339
- parseMarkdown: {
1340
- match: (node) => {
1341
- return node.type === "attachment";
1342
- },
1343
- runner: (state, node, type) => {
1344
- state.addNode(type, {
1345
- src: node.url,
1346
- name: node.name || "",
1347
- size: Number(node.size || 0)
1348
- });
1349
- }
1350
- },
1351
- toMarkdown: {
1352
- match: (node) => node.type.name === "attachment",
1353
- runner: (state, node) => {
1354
- state.openNode("paragraph");
1355
- state.addNode(
1356
- "html",
1357
- void 0,
1358
- `<a href="${node.attrs.src}" data-size="${node.attrs.size}" data-name="${node.attrs.name}" data-video-width="${node.attrs.videoWidth || 0}" data-type="${ATTACHMENT_DATA_TYPE}" class="attachment">${node.attrs.name}</a>`
1359
- );
1360
- state.closeNode();
1361
- }
1362
- }
1363
- };
1364
- });
1681
+ cancelHide: () => {
1682
+ },
1683
+ isProgrammatic: () => false,
1684
+ getPos: () => null,
1685
+ isShow: () => false,
1686
+ getMode: () => null
1687
+ },
1688
+ "menuAPICtx"
1689
+ );
1365
1690
 
1366
1691
  const mathInlineId = "math_inline";
1367
1692
  const mathInlineSchema = utils.$nodeSchema(mathInlineId, () => ({
@@ -2500,7 +2825,7 @@ const Menu = vue.defineComponent({
2500
2825
  });
2501
2826
  return () => {
2502
2827
  var _a, _b, _c;
2503
- show.value;
2828
+ void show.value;
2504
2829
  const api = ctx.get(menuAPI.key);
2505
2830
  const showListMenu = (api == null ? void 0 : api.getMode()) === "list" || !(api == null ? void 0 : api.isProgrammatic()) || filter.value !== "";
2506
2831
  if (showListMenu) {
@@ -3246,7 +3571,9 @@ const Menu = vue.defineComponent({
3246
3571
  var _a2;
3247
3572
  e.preventDefault();
3248
3573
  e.stopPropagation();
3249
- (_a2 = host.value) == null ? void 0 : _a2.querySelectorAll(`[data-index="${item.index}"]`).forEach((el) => el.classList.remove("active"));
3574
+ (_a2 = host.value) == null ? void 0 : _a2.querySelectorAll(`[data-index="${item.index}"]`).forEach(
3575
+ (el) => el.classList.remove("active")
3576
+ );
3250
3577
  runByIndexForAddBelow(item.index);
3251
3578
  }
3252
3579
  },
@@ -5000,6 +5327,10 @@ const activeIconMap = {
5000
5327
  // [highLineCodeIcon]: highLineCodeIconActive,
5001
5328
  };
5002
5329
  keepAlive(vue.h, vue.Fragment);
5330
+ const formatPainterStates = /* @__PURE__ */ new WeakMap();
5331
+ const formatPainterHandlers = /* @__PURE__ */ new WeakMap();
5332
+ const formatPainterIgnoreNext = /* @__PURE__ */ new WeakMap();
5333
+ const cursorStyleEls = /* @__PURE__ */ new WeakMap();
5003
5334
  const Toolbar = vue.defineComponent({
5004
5335
  props: {
5005
5336
  ctx: { type: Object, required: true },
@@ -5030,6 +5361,184 @@ const Toolbar = vue.defineComponent({
5030
5361
  const tableMenuPos = vue.ref({ top: 0, left: 0 });
5031
5362
  const tableHoverIndices = vue.ref({ r: 0, c: 0 });
5032
5363
  let hideTableTimer = null;
5364
+ let formatPainterState = formatPainterStates.get(ctx);
5365
+ if (!formatPainterState) {
5366
+ formatPainterState = vue.ref(null);
5367
+ formatPainterStates.set(ctx, formatPainterState);
5368
+ }
5369
+ let formatPainterIgnore = formatPainterIgnoreNext.get(ctx);
5370
+ if (!formatPainterIgnore) {
5371
+ formatPainterIgnore = { value: false };
5372
+ formatPainterIgnoreNext.set(ctx, formatPainterIgnore);
5373
+ }
5374
+ let formatPainterHandler = formatPainterHandlers.get(ctx);
5375
+ if (!formatPainterHandler) {
5376
+ formatPainterHandler = (ev) => {
5377
+ if (!formatPainterState.value) return;
5378
+ if (formatPainterIgnore.value) {
5379
+ formatPainterIgnore.value = false;
5380
+ return;
5381
+ }
5382
+ const currentView = ctx.get(core.editorViewCtx);
5383
+ const targetElement = ev.target instanceof Element ? ev.target : ev.target.parentElement;
5384
+ if (targetElement && targetElement.closest(".milkdown-toolbar, .milkdown-fixed-toolbar")) {
5385
+ return;
5386
+ }
5387
+ setTimeout(() => {
5388
+ if (!formatPainterState.value) return;
5389
+ const { state: curState, dispatch } = currentView;
5390
+ const { selection: curSelection, tr } = curState;
5391
+ const {
5392
+ marks: savedMarks,
5393
+ align: savedAlign,
5394
+ isPersistent
5395
+ } = formatPainterState.value;
5396
+ let applied = false;
5397
+ if (!curSelection.empty) {
5398
+ savedMarks.forEach((m) => {
5399
+ tr.addMark(curSelection.from, curSelection.to, m);
5400
+ });
5401
+ if (savedAlign) {
5402
+ curState.doc.nodesBetween(
5403
+ curSelection.from,
5404
+ curSelection.to,
5405
+ (node, pos) => {
5406
+ if (node.type.name === "paragraph" || node.type.name === "heading") {
5407
+ tr.setNodeMarkup(pos, null, {
5408
+ ...node.attrs,
5409
+ align: savedAlign
5410
+ });
5411
+ }
5412
+ }
5413
+ );
5414
+ }
5415
+ dispatch(tr);
5416
+ applied = true;
5417
+ } else {
5418
+ if (savedMarks.length > 0) {
5419
+ const $pos = curSelection.$from;
5420
+ if ($pos.parent.isTextblock) {
5421
+ const text = $pos.parent.textContent;
5422
+ const offset = $pos.parentOffset;
5423
+ let start = offset;
5424
+ let end = offset;
5425
+ const isWordChar = (char) => !/[\s,.\-!?;:()[\]{}"'“”‘’,。!?;:()【】《》、\n\r]/.test(
5426
+ char
5427
+ );
5428
+ while (start > 0 && isWordChar(text[start - 1])) start--;
5429
+ while (end < text.length && isWordChar(text[end])) end++;
5430
+ if (start < end) {
5431
+ savedMarks.forEach((m) => {
5432
+ tr.addMark($pos.start() + start, $pos.start() + end, m);
5433
+ });
5434
+ }
5435
+ }
5436
+ }
5437
+ if (savedAlign) {
5438
+ const pos = curSelection.$from.before(curSelection.$from.depth);
5439
+ const node = curState.doc.nodeAt(pos);
5440
+ if (node && (node.type.name === "paragraph" || node.type.name === "heading")) {
5441
+ tr.setNodeMarkup(pos, null, {
5442
+ ...node.attrs,
5443
+ align: savedAlign
5444
+ });
5445
+ }
5446
+ }
5447
+ tr.setStoredMarks(savedMarks);
5448
+ dispatch(tr);
5449
+ applied = true;
5450
+ }
5451
+ if (applied && !isPersistent) {
5452
+ formatPainterState.value = null;
5453
+ document.removeEventListener("pointerup", formatPainterHandler);
5454
+ }
5455
+ }, 50);
5456
+ };
5457
+ formatPainterHandlers.set(ctx, formatPainterHandler);
5458
+ }
5459
+ const toggleFormatPainter = (isPersistent) => {
5460
+ const view = ctx.get(core.editorViewCtx);
5461
+ const { state } = view;
5462
+ const { selection } = state;
5463
+ let marks = [];
5464
+ if (selection.empty) {
5465
+ marks = state.storedMarks ? [...state.storedMarks] : [...selection.$from.marks()];
5466
+ } else {
5467
+ let foundMarks = null;
5468
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
5469
+ if (foundMarks) return false;
5470
+ if (node.isInline) {
5471
+ foundMarks = [...node.marks];
5472
+ return false;
5473
+ }
5474
+ return void 0;
5475
+ });
5476
+ marks = foundMarks || [];
5477
+ }
5478
+ let align = null;
5479
+ let foundAlign = null;
5480
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
5481
+ if (foundAlign) return false;
5482
+ if (node.isBlock && (node.type.name === "paragraph" || node.type.name === "heading")) {
5483
+ foundAlign = node.attrs.align || null;
5484
+ return false;
5485
+ }
5486
+ return void 0;
5487
+ });
5488
+ if (!foundAlign) {
5489
+ const parent = selection.$from.parent;
5490
+ if (parent && (parent.type.name === "paragraph" || parent.type.name === "heading")) {
5491
+ foundAlign = parent.attrs.align || null;
5492
+ }
5493
+ }
5494
+ align = foundAlign;
5495
+ formatPainterState.value = { marks, align, isPersistent };
5496
+ document.removeEventListener("pointerup", formatPainterHandler);
5497
+ setTimeout(() => {
5498
+ document.addEventListener("pointerup", formatPainterHandler);
5499
+ }, 0);
5500
+ };
5501
+ const handleFormatPainterClick = (e) => {
5502
+ e.preventDefault();
5503
+ e.stopPropagation();
5504
+ if (formatPainterState.value) {
5505
+ formatPainterState.value = null;
5506
+ document.removeEventListener("pointerup", formatPainterHandler);
5507
+ } else {
5508
+ formatPainterIgnore.value = true;
5509
+ toggleFormatPainter(false);
5510
+ }
5511
+ };
5512
+ const handleFormatPainterDblClick = (e) => {
5513
+ e.preventDefault();
5514
+ e.stopPropagation();
5515
+ toggleFormatPainter(true);
5516
+ };
5517
+ vue.watch(
5518
+ () => formatPainterState.value,
5519
+ (newVal) => {
5520
+ if (newVal) {
5521
+ let cursorStyleEl = cursorStyleEls.get(ctx);
5522
+ if (!cursorStyleEl) {
5523
+ cursorStyleEl = document.createElement("style");
5524
+ const encodedSvg = encodeURIComponent(
5525
+ formatPainterIcon.replace(/currentColor/g, "#363B4C")
5526
+ );
5527
+ cursorStyleEl.innerHTML = `.milkdown .ProseMirror, .milkdown .ProseMirror * { cursor: url("data:image/svg+xml;utf8,${encodedSvg}") 0 16, auto !important; }`;
5528
+ document.head.appendChild(cursorStyleEl);
5529
+ cursorStyleEls.set(ctx, cursorStyleEl);
5530
+ }
5531
+ } else {
5532
+ const cursorStyleEl = cursorStyleEls.get(ctx);
5533
+ if (cursorStyleEl) {
5534
+ cursorStyleEl.remove();
5535
+ cursorStyleEls.delete(ctx);
5536
+ }
5537
+ }
5538
+ }
5539
+ );
5540
+ vue.onUnmounted(() => {
5541
+ });
5033
5542
  const toolbarContainerRef = vue.ref(null);
5034
5543
  const overflowVisibleCount = vue.ref(Infinity);
5035
5544
  const totalSectionCount = vue.ref(Infinity);
@@ -5736,7 +6245,7 @@ const Toolbar = vue.defineComponent({
5736
6245
  position: "relative",
5737
6246
  display: isSectionOverflowed(0) ? "none" : "flex",
5738
6247
  alignItems: "center",
5739
- padding: "0 8px",
6248
+ padding: "0 6px",
5740
6249
  flexShrink: 0
5741
6250
  }
5742
6251
  },
@@ -5755,6 +6264,49 @@ const Toolbar = vue.defineComponent({
5755
6264
  /* @__PURE__ */ vue.h(component.Icon, { icon: chevronDownIcon })
5756
6265
  )
5757
6266
  ),
6267
+ /* @__PURE__ */ vue.h(
6268
+ "div",
6269
+ {
6270
+ style: {
6271
+ position: "relative",
6272
+ display: isSectionOverflowed(0) ? "none" : "flex",
6273
+ flexShrink: 0
6274
+ }
6275
+ },
6276
+ /* @__PURE__ */ vue.h(
6277
+ "button",
6278
+ {
6279
+ type: "button",
6280
+ class: clsx(
6281
+ "toolbar-item",
6282
+ formatPainterState.value && "active"
6283
+ ),
6284
+ onPointerdown: (e) => {
6285
+ e.preventDefault();
6286
+ handleFormatPainterClick(e);
6287
+ },
6288
+ onDblclick: handleFormatPainterDblClick,
6289
+ title: i18n(ctx, "toolbar.formatPainter") || "Format Painter",
6290
+ style: {
6291
+ display: "flex",
6292
+ alignItems: "center",
6293
+ justifyContent: "center",
6294
+ backgroundColor: formatPainterState.value ? "var(--crepe-color-selected, var(--crepe-color-hover))" : void 0
6295
+ }
6296
+ },
6297
+ /* @__PURE__ */ vue.h(
6298
+ "span",
6299
+ {
6300
+ style: {
6301
+ display: "inline-flex",
6302
+ alignItems: "center",
6303
+ "--toolbar-icon-color": formatPainterState.value ? "var(--crepe-color-primary)" : "#363B4C"
6304
+ },
6305
+ innerHTML: formatPainterIcon
6306
+ }
6307
+ )
6308
+ )
6309
+ ),
5758
6310
  /* @__PURE__ */ vue.h(
5759
6311
  "div",
5760
6312
  {
@@ -5777,7 +6329,7 @@ const Toolbar = vue.defineComponent({
5777
6329
  position: "relative",
5778
6330
  display: isSectionOverflowed(2) ? "none" : "flex",
5779
6331
  alignItems: "center",
5780
- padding: "0 8px",
6332
+ padding: "0 6px",
5781
6333
  minWidth: "50px",
5782
6334
  flexShrink: 0
5783
6335
  }
@@ -5819,7 +6371,7 @@ const Toolbar = vue.defineComponent({
5819
6371
  position: "relative",
5820
6372
  display: isSectionOverflowed(3) ? "none" : "flex",
5821
6373
  alignItems: "center",
5822
- padding: "0 8px",
6374
+ padding: "0 6px",
5823
6375
  minWidth: "40px",
5824
6376
  flexShrink: 0
5825
6377
  }
@@ -5860,7 +6412,7 @@ const Toolbar = vue.defineComponent({
5860
6412
  position: "relative",
5861
6413
  display: isSectionOverflowed(5) ? "none" : "flex",
5862
6414
  alignItems: "center",
5863
- padding: "0 8px",
6415
+ padding: "0 6px",
5864
6416
  flexShrink: 0
5865
6417
  }
5866
6418
  },
@@ -6897,7 +7449,7 @@ const Toolbar = vue.defineComponent({
6897
7449
  ctx && checkActive(item.active) ? activeIconMap[item.icon] || item.icon : item.icon,
6898
7450
  item.label,
6899
7451
  ctx ? checkActive(item.active) : false,
6900
- isTable ? void 0 : (e) => {
7452
+ isTable ? void 0 : (_e) => {
6901
7453
  item.onRun(ctx);
6902
7454
  showOverflowMenu.value = false;
6903
7455
  },
@@ -6979,7 +7531,7 @@ const ToggleSwitch = vue.defineComponent({
6979
7531
  },
6980
7532
  emits: ["update:modelValue"],
6981
7533
  setup(props, { emit }) {
6982
- return () => /* @__PURE__ */ vue.h(
7534
+ return () => /* @__PURE__ */ h(
6983
7535
  "div",
6984
7536
  {
6985
7537
  onClick: (e) => {
@@ -6996,7 +7548,7 @@ const ToggleSwitch = vue.defineComponent({
6996
7548
  transition: "background-color 0.2s"
6997
7549
  }
6998
7550
  },
6999
- /* @__PURE__ */ vue.h(
7551
+ /* @__PURE__ */ h(
7000
7552
  "div",
7001
7553
  {
7002
7554
  style: {
@@ -7082,7 +7634,7 @@ const MenuBar = vue.defineComponent({
7082
7634
  const hasSubmenu = (key) => key === "view";
7083
7635
  return () => {
7084
7636
  const state = viewState.value;
7085
- return /* @__PURE__ */ vue.h(
7637
+ return /* @__PURE__ */ h(
7086
7638
  "div",
7087
7639
  {
7088
7640
  class: "milkdown-menu-bar",
@@ -7094,7 +7646,7 @@ const MenuBar = vue.defineComponent({
7094
7646
  position: "relative"
7095
7647
  }
7096
7648
  },
7097
- /* @__PURE__ */ vue.h(
7649
+ /* @__PURE__ */ h(
7098
7650
  "div",
7099
7651
  {
7100
7652
  ref: buttonRef,
@@ -7117,7 +7669,7 @@ const MenuBar = vue.defineComponent({
7117
7669
  e.currentTarget.style.backgroundColor = "transparent";
7118
7670
  }
7119
7671
  },
7120
- /* @__PURE__ */ vue.h(
7672
+ /* @__PURE__ */ h(
7121
7673
  "span",
7122
7674
  {
7123
7675
  style: {
@@ -7128,9 +7680,9 @@ const MenuBar = vue.defineComponent({
7128
7680
  justifyContent: "center"
7129
7681
  }
7130
7682
  },
7131
- /* @__PURE__ */ vue.h(component.Icon, { icon: menuIcon })
7683
+ /* @__PURE__ */ h(component.Icon, { icon: menuIcon })
7132
7684
  ),
7133
- /* @__PURE__ */ vue.h(
7685
+ /* @__PURE__ */ h(
7134
7686
  "span",
7135
7687
  {
7136
7688
  style: {
@@ -7143,7 +7695,7 @@ const MenuBar = vue.defineComponent({
7143
7695
  "\u83DC\u5355"
7144
7696
  )
7145
7697
  ),
7146
- showMenu.value ? /* @__PURE__ */ vue.h(
7698
+ showMenu.value ? /* @__PURE__ */ h(
7147
7699
  "div",
7148
7700
  {
7149
7701
  ref: mainRef,
@@ -7163,16 +7715,20 @@ const MenuBar = vue.defineComponent({
7163
7715
  boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
7164
7716
  cursor: "default"
7165
7717
  },
7166
- onClick: (e) => e.stopPropagation()
7718
+ onClick: (e) => {
7719
+ e.stopPropagation();
7720
+ }
7167
7721
  },
7168
7722
  menuKeys.map((menuKey) => {
7169
7723
  const isHovered = activeSubmenu.value === menuKey;
7170
7724
  const label = i18n(props.ctx, `menuBar.${menuKey}`) || menuKey;
7171
- return /* @__PURE__ */ vue.h(
7725
+ return /* @__PURE__ */ h(
7172
7726
  "div",
7173
7727
  {
7174
7728
  key: menuKey,
7175
- onMouseenter: () => onMouseEnterItem(menuKey),
7729
+ onMouseenter: () => {
7730
+ onMouseEnterItem(menuKey);
7731
+ },
7176
7732
  onMouseleave: () => {
7177
7733
  if (hasSubmenu(menuKey)) {
7178
7734
  activeSubmenu.value = null;
@@ -7188,7 +7744,7 @@ const MenuBar = vue.defineComponent({
7188
7744
  backgroundColor: isHovered ? "var(--crepe-color-hover, #f5f5f5)" : "transparent"
7189
7745
  }
7190
7746
  },
7191
- /* @__PURE__ */ vue.h(
7747
+ /* @__PURE__ */ h(
7192
7748
  "span",
7193
7749
  {
7194
7750
  style: {
@@ -7198,7 +7754,7 @@ const MenuBar = vue.defineComponent({
7198
7754
  },
7199
7755
  label
7200
7756
  ),
7201
- hasSubmenu(menuKey) ? /* @__PURE__ */ vue.h(
7757
+ hasSubmenu(menuKey) ? /* @__PURE__ */ h(
7202
7758
  "span",
7203
7759
  {
7204
7760
  style: {
@@ -7207,7 +7763,7 @@ const MenuBar = vue.defineComponent({
7207
7763
  display: "flex"
7208
7764
  }
7209
7765
  },
7210
- /* @__PURE__ */ vue.h(
7766
+ /* @__PURE__ */ h(
7211
7767
  "svg",
7212
7768
  {
7213
7769
  width: "12",
@@ -7219,10 +7775,10 @@ const MenuBar = vue.defineComponent({
7219
7775
  "stroke-linecap": "round",
7220
7776
  "stroke-linejoin": "round"
7221
7777
  },
7222
- /* @__PURE__ */ vue.h("polyline", { points: "9 18 15 12 9 6" })
7778
+ /* @__PURE__ */ h("polyline", { points: "9 18 15 12 9 6" })
7223
7779
  )
7224
7780
  ) : null,
7225
- menuKey === "view" && isHovered ? /* @__PURE__ */ vue.h(
7781
+ menuKey === "view" && isHovered ? /* @__PURE__ */ h(
7226
7782
  "div",
7227
7783
  {
7228
7784
  style: {
@@ -7240,7 +7796,7 @@ const MenuBar = vue.defineComponent({
7240
7796
  cursor: "default"
7241
7797
  }
7242
7798
  },
7243
- /* @__PURE__ */ vue.h(
7799
+ /* @__PURE__ */ h(
7244
7800
  "div",
7245
7801
  {
7246
7802
  style: {
@@ -7250,7 +7806,7 @@ const MenuBar = vue.defineComponent({
7250
7806
  alignItems: "center"
7251
7807
  }
7252
7808
  },
7253
- /* @__PURE__ */ vue.h(
7809
+ /* @__PURE__ */ h(
7254
7810
  "span",
7255
7811
  {
7256
7812
  style: {
@@ -7260,7 +7816,7 @@ const MenuBar = vue.defineComponent({
7260
7816
  },
7261
7817
  i18n(props.ctx, "view.title") || "\u6807\u9898"
7262
7818
  ),
7263
- /* @__PURE__ */ vue.h(
7819
+ /* @__PURE__ */ h(
7264
7820
  ToggleSwitch,
7265
7821
  {
7266
7822
  modelValue: state.showTitle,
@@ -7268,7 +7824,7 @@ const MenuBar = vue.defineComponent({
7268
7824
  }
7269
7825
  )
7270
7826
  ),
7271
- /* @__PURE__ */ vue.h(
7827
+ /* @__PURE__ */ h(
7272
7828
  "div",
7273
7829
  {
7274
7830
  style: {
@@ -7278,7 +7834,7 @@ const MenuBar = vue.defineComponent({
7278
7834
  alignItems: "center"
7279
7835
  }
7280
7836
  },
7281
- /* @__PURE__ */ vue.h(
7837
+ /* @__PURE__ */ h(
7282
7838
  "span",
7283
7839
  {
7284
7840
  style: {
@@ -7288,7 +7844,7 @@ const MenuBar = vue.defineComponent({
7288
7844
  },
7289
7845
  i18n(props.ctx, "view.outline") || "\u5927\u7EB2"
7290
7846
  ),
7291
- /* @__PURE__ */ vue.h(
7847
+ /* @__PURE__ */ h(
7292
7848
  ToggleSwitch,
7293
7849
  {
7294
7850
  modelValue: state.outlineVisible,
@@ -7296,7 +7852,7 @@ const MenuBar = vue.defineComponent({
7296
7852
  }
7297
7853
  )
7298
7854
  ),
7299
- /* @__PURE__ */ vue.h(
7855
+ /* @__PURE__ */ h(
7300
7856
  "div",
7301
7857
  {
7302
7858
  style: {
@@ -7306,7 +7862,7 @@ const MenuBar = vue.defineComponent({
7306
7862
  alignItems: "center"
7307
7863
  }
7308
7864
  },
7309
- /* @__PURE__ */ vue.h(
7865
+ /* @__PURE__ */ h(
7310
7866
  "span",
7311
7867
  {
7312
7868
  style: {
@@ -7316,7 +7872,7 @@ const MenuBar = vue.defineComponent({
7316
7872
  },
7317
7873
  i18n(props.ctx, "view.cover") || "\u5C01\u9762"
7318
7874
  ),
7319
- /* @__PURE__ */ vue.h(
7875
+ /* @__PURE__ */ h(
7320
7876
  ToggleSwitch,
7321
7877
  {
7322
7878
  modelValue: state.showCover,
@@ -7332,7 +7888,7 @@ const MenuBar = vue.defineComponent({
7332
7888
  }
7333
7889
  )
7334
7890
  ),
7335
- /* @__PURE__ */ vue.h(
7891
+ /* @__PURE__ */ h(
7336
7892
  "div",
7337
7893
  {
7338
7894
  style: {
@@ -7342,7 +7898,7 @@ const MenuBar = vue.defineComponent({
7342
7898
  }
7343
7899
  }
7344
7900
  ),
7345
- /* @__PURE__ */ vue.h(
7901
+ /* @__PURE__ */ h(
7346
7902
  "div",
7347
7903
  {
7348
7904
  style: {
@@ -7352,7 +7908,7 @@ const MenuBar = vue.defineComponent({
7352
7908
  alignItems: "center"
7353
7909
  }
7354
7910
  },
7355
- /* @__PURE__ */ vue.h(
7911
+ /* @__PURE__ */ h(
7356
7912
  "span",
7357
7913
  {
7358
7914
  style: {
@@ -7363,7 +7919,7 @@ const MenuBar = vue.defineComponent({
7363
7919
  i18n(props.ctx, "view.docBackground") || "\u6587\u6863\u80CC\u666F"
7364
7920
  )
7365
7921
  ),
7366
- /* @__PURE__ */ vue.h(
7922
+ /* @__PURE__ */ h(
7367
7923
  "div",
7368
7924
  {
7369
7925
  style: {
@@ -7373,7 +7929,7 @@ const MenuBar = vue.defineComponent({
7373
7929
  gap: "6px"
7374
7930
  }
7375
7931
  },
7376
- bgColors.map((bg) => /* @__PURE__ */ vue.h(
7932
+ bgColors.map((bg) => /* @__PURE__ */ h(
7377
7933
  "div",
7378
7934
  {
7379
7935
  key: bg.value || "default",
@@ -7395,7 +7951,7 @@ const MenuBar = vue.defineComponent({
7395
7951
  justifyContent: "center"
7396
7952
  }
7397
7953
  },
7398
- bg.value === null ? /* @__PURE__ */ vue.h(
7954
+ bg.value === null ? /* @__PURE__ */ h(
7399
7955
  "div",
7400
7956
  {
7401
7957
  style: {
@@ -7408,7 +7964,7 @@ const MenuBar = vue.defineComponent({
7408
7964
  borderRadius: "3px"
7409
7965
  }
7410
7966
  },
7411
- /* @__PURE__ */ vue.h(
7967
+ /* @__PURE__ */ h(
7412
7968
  "div",
7413
7969
  {
7414
7970
  style: {
@@ -7426,7 +7982,7 @@ const MenuBar = vue.defineComponent({
7426
7982
  ) : null
7427
7983
  ))
7428
7984
  ),
7429
- /* @__PURE__ */ vue.h(
7985
+ /* @__PURE__ */ h(
7430
7986
  "div",
7431
7987
  {
7432
7988
  style: {
@@ -7436,7 +7992,7 @@ const MenuBar = vue.defineComponent({
7436
7992
  }
7437
7993
  }
7438
7994
  ),
7439
- /* @__PURE__ */ vue.h(
7995
+ /* @__PURE__ */ h(
7440
7996
  "div",
7441
7997
  {
7442
7998
  style: {
@@ -7446,7 +8002,7 @@ const MenuBar = vue.defineComponent({
7446
8002
  alignItems: "center"
7447
8003
  }
7448
8004
  },
7449
- /* @__PURE__ */ vue.h(
8005
+ /* @__PURE__ */ h(
7450
8006
  "span",
7451
8007
  {
7452
8008
  style: {
@@ -7457,7 +8013,7 @@ const MenuBar = vue.defineComponent({
7457
8013
  i18n(props.ctx, "view.editorWidth") || "\u5185\u5BB9\u5BBD\u5EA6"
7458
8014
  )
7459
8015
  ),
7460
- /* @__PURE__ */ vue.h(
8016
+ /* @__PURE__ */ h(
7461
8017
  "div",
7462
8018
  {
7463
8019
  style: {
@@ -7479,7 +8035,7 @@ const MenuBar = vue.defineComponent({
7479
8035
  key: "full",
7480
8036
  labelKey: "view.widthFull"
7481
8037
  }
7482
- ].map(({ key, labelKey }) => /* @__PURE__ */ vue.h(
8038
+ ].map(({ key, labelKey }) => /* @__PURE__ */ h(
7483
8039
  "button",
7484
8040
  {
7485
8041
  key,
@@ -7706,7 +8262,7 @@ const FixedToolbarComponent = vue.defineComponent({
7706
8262
  },
7707
8263
  setup(props) {
7708
8264
  const showShortcuts = vue.ref(false);
7709
- return () => /* @__PURE__ */ vue.h(
8265
+ return () => /* @__PURE__ */ h(
7710
8266
  "div",
7711
8267
  {
7712
8268
  style: {
@@ -7717,8 +8273,8 @@ const FixedToolbarComponent = vue.defineComponent({
7717
8273
  gap: "0px"
7718
8274
  }
7719
8275
  },
7720
- /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
7721
- /* @__PURE__ */ vue.h(
8276
+ /* @__PURE__ */ h(MenuBar, { ctx: props.ctx, config: props.config }),
8277
+ /* @__PURE__ */ h(
7722
8278
  "div",
7723
8279
  {
7724
8280
  style: {
@@ -7729,7 +8285,7 @@ const FixedToolbarComponent = vue.defineComponent({
7729
8285
  }
7730
8286
  }
7731
8287
  ),
7732
- /* @__PURE__ */ vue.h(
8288
+ /* @__PURE__ */ h(
7733
8289
  Toolbar,
7734
8290
  {
7735
8291
  ctx: props.ctx,
@@ -7737,189 +8293,61 @@ const FixedToolbarComponent = vue.defineComponent({
7737
8293
  show: props.show,
7738
8294
  selection: props.selection,
7739
8295
  config: props.config,
7740
- isFixed: true
7741
- }
7742
- ),
7743
- /* @__PURE__ */ vue.h(
7744
- "div",
7745
- {
7746
- style: {
7747
- width: "1px",
7748
- minWidth: "1px",
7749
- height: "20px",
7750
- flexShrink: 0,
7751
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
7752
- }
7753
- }
7754
- ),
7755
- /* @__PURE__ */ vue.h(
7756
- "button",
7757
- {
7758
- type: "button",
7759
- class: "toolbar-shortcut-btn",
7760
- title: i18n(props.ctx, "shortcuts.title"),
7761
- onClick: () => {
7762
- showShortcuts.value = true;
7763
- }
7764
- },
7765
- /* @__PURE__ */ vue.h(component.Icon, { icon: keyboardIcon })
7766
- ),
7767
- showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
7768
- );
7769
- }
7770
- });
7771
-
7772
- function convertHeadingToParagraphIfNeeded(ctx) {
7773
- const commands = ctx.get(core.commandsCtx);
7774
- const view = ctx.get(core.editorViewCtx);
7775
- const heading = commonmark.headingSchema.type(ctx);
7776
- const { from, to } = view.state.selection;
7777
- let hasHeading = false;
7778
- view.state.doc.nodesBetween(from, to, (node) => {
7779
- if (node.type === heading) hasHeading = true;
7780
- });
7781
- if (hasHeading) {
7782
- commands.call(commonmark.setBlockTypeCommand.key, {
7783
- nodeType: commonmark.paragraphSchema.type(ctx)
7784
- });
7785
- }
7786
- }
7787
- function buildDefaultFixedToolbar(builder, _config, ctx) {
7788
- const flags = ctx && useCrepeFeatures(ctx).get();
7789
- const isLatexEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Latex);
7790
- const isImageBlockEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.ImageBlock);
7791
- const isTableEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Table);
7792
- const hasFunctionGroup = builder.build().some((g) => g.key === "function");
7793
- const embedGroup = hasFunctionGroup ? builder.getGroup("function") : builder.addGroup("embed", "Embed");
7794
- if (isImageBlockEnabled) {
7795
- embedGroup.addItem("image", {
7796
- label: ctx ? i18n(ctx, "menu.item.image") : "Image",
7797
- icon: imageIcon,
7798
- active: () => false,
7799
- onRun: (ctx2) => {
7800
- const commands = ctx2.get(core.commandsCtx);
7801
- commands.call(commonmark.addBlockTypeCommand.key, {
7802
- nodeType: imageBlock$1.imageBlockSchema.type(ctx2)
7803
- });
7804
- }
7805
- });
7806
- }
7807
- const isAttachmentEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Attachment);
7808
- if (isAttachmentEnabled) {
7809
- embedGroup.addItem("attachment", {
7810
- label: ctx ? i18n(ctx, "menu.item.attachment") : "Video or File",
7811
- icon: fileLinkIcon,
7812
- active: () => false,
7813
- onRun: (ctx2) => {
7814
- const commands = ctx2.get(core.commandsCtx);
7815
- commands.call(commonmark.addBlockTypeCommand.key, {
7816
- nodeType: attachmentSchema.type(ctx2)
7817
- });
7818
- }
7819
- });
7820
- }
7821
- embedGroup.addItem("code-block", {
7822
- label: ctx ? i18n(ctx, "menu.item.code") : "Code Block",
7823
- icon: codeIcon,
7824
- active: (ctx2) => {
7825
- var _a, _b;
7826
- const view = ctx2.get(core.editorViewCtx);
7827
- const result = prose.findNodeInSelection(view.state, commonmark.codeBlockSchema.type(ctx2));
7828
- return result.hasNode && ((_b = (_a = result.target) == null ? void 0 : _a.attrs) == null ? void 0 : _b.language) !== "LaTex";
7829
- },
7830
- onRun: (ctx2) => {
7831
- const commands = ctx2.get(core.commandsCtx);
7832
- const view = ctx2.get(core.editorViewCtx);
7833
- const { state, dispatch } = view;
7834
- const { selection, tr } = state;
7835
- const { from, to } = selection;
7836
- let text = "";
7837
- let blockCount = 0;
7838
- state.doc.nodesBetween(from, to, (node) => {
7839
- if (node.isTextblock) {
7840
- text += (blockCount > 0 ? "\n" : "") + node.textContent;
7841
- blockCount++;
7842
- }
7843
- });
7844
- if (blockCount > 1) {
7845
- if (dispatch) {
7846
- const range = selection.$from.blockRange(selection.$to);
7847
- const codeBlock = commonmark.codeBlockSchema.type(ctx2).createAndFill({}, text ? state.schema.text(text) : void 0);
7848
- if (range && codeBlock) {
7849
- tr.replaceWith(range.start, range.end, codeBlock);
7850
- dispatch(tr.scrollIntoView());
8296
+ isFixed: true
8297
+ }
8298
+ ),
8299
+ /* @__PURE__ */ h(
8300
+ "div",
8301
+ {
8302
+ style: {
8303
+ width: "1px",
8304
+ minWidth: "1px",
8305
+ height: "20px",
8306
+ flexShrink: 0,
8307
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
7851
8308
  }
7852
8309
  }
7853
- return;
7854
- }
7855
- commands.call(commonmark.setBlockTypeCommand.key, {
7856
- nodeType: commonmark.codeBlockSchema.type(ctx2)
7857
- });
7858
- }
7859
- });
7860
- if (isTableEnabled) {
7861
- embedGroup.addItem("table", {
7862
- label: ctx ? i18n(ctx, "menu.item.table") : "Table",
7863
- icon: tableIcon,
7864
- active: () => false,
7865
- onRun: (ctx2) => {
7866
- const commands = ctx2.get(core.commandsCtx);
7867
- const view = ctx2.get(core.editorViewCtx);
7868
- const { from } = view.state.selection;
7869
- commands.call(commonmark.addBlockTypeCommand.key, {
7870
- nodeType: gfm.createTable(ctx2, 3, 3)
7871
- });
7872
- commands.call(commonmark.selectTextNearPosCommand.key, { pos: from });
7873
- }
7874
- });
8310
+ ),
8311
+ /* @__PURE__ */ h(
8312
+ "button",
8313
+ {
8314
+ type: "button",
8315
+ class: "toolbar-shortcut-btn",
8316
+ title: i18n(props.ctx, "shortcuts.title"),
8317
+ onClick: () => {
8318
+ showShortcuts.value = true;
8319
+ }
8320
+ },
8321
+ /* @__PURE__ */ h(component.Icon, { icon: keyboardIcon })
8322
+ ),
8323
+ showShortcuts.value && /* @__PURE__ */ h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8324
+ );
7875
8325
  }
7876
- if (isLatexEnabled) {
7877
- embedGroup.addItem("math-block", {
7878
- label: ctx ? i18n(ctx, "menu.item.math") : "Math Block",
7879
- icon: functionsIcon,
7880
- active: (ctx2) => {
7881
- var _a, _b;
7882
- const view = ctx2.get(core.editorViewCtx);
7883
- const result = prose.findNodeInSelection(
7884
- view.state,
7885
- commonmark.codeBlockSchema.type(ctx2)
7886
- );
7887
- return result.hasNode && ((_b = (_a = result.target) == null ? void 0 : _a.attrs) == null ? void 0 : _b.language) === "LaTex";
7888
- },
7889
- onRun: (ctx2) => {
7890
- const commands = ctx2.get(core.commandsCtx);
7891
- commands.call(toggleLatexCommand.key);
7892
- }
8326
+ });
8327
+
8328
+ function convertHeadingToParagraphIfNeeded(ctx) {
8329
+ const commands = ctx.get(core.commandsCtx);
8330
+ const view = ctx.get(core.editorViewCtx);
8331
+ const heading = commonmark.headingSchema.type(ctx);
8332
+ const { from, to } = view.state.selection;
8333
+ let hasHeading = false;
8334
+ view.state.doc.nodesBetween(from, to, (node) => {
8335
+ if (node.type === heading) hasHeading = true;
8336
+ });
8337
+ if (hasHeading) {
8338
+ commands.call(commonmark.setBlockTypeCommand.key, {
8339
+ nodeType: commonmark.paragraphSchema.type(ctx)
7893
8340
  });
7894
8341
  }
7895
- const blockGroup = builder.addGroup("block", "Block");
7896
- blockGroup.addItem("quote", {
7897
- label: ctx ? i18n(ctx, "menu.item.quote") : "Quote",
7898
- icon: quoteIcon,
7899
- active: (ctx2) => {
7900
- const view = ctx2.get(core.editorViewCtx);
7901
- const result = prose.findNodeInSelection(
7902
- view.state,
7903
- commonmark.blockquoteSchema.type(ctx2)
7904
- );
7905
- return result.hasNode;
7906
- },
7907
- onRun: (ctx2) => {
7908
- const view = ctx2.get(core.editorViewCtx);
7909
- const commands$1 = ctx2.get(core.commandsCtx);
7910
- const isActive = prose.findNodeInSelection(
7911
- view.state,
7912
- commonmark.blockquoteSchema.type(ctx2)
7913
- ).hasNode;
7914
- if (isActive) {
7915
- commands.lift(view.state, view.dispatch);
7916
- } else {
7917
- commands$1.call(commonmark.wrapInBlockTypeCommand.key, {
7918
- nodeType: commonmark.blockquoteSchema.type(ctx2)
7919
- });
7920
- }
7921
- }
7922
- }).addItem("divider", {
8342
+ }
8343
+ function buildDefaultFixedToolbar(builder, _config, ctx) {
8344
+ const flags = ctx && useCrepeFeatures(ctx).get();
8345
+ const isLatexEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Latex);
8346
+ const isImageBlockEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.ImageBlock);
8347
+ const isTableEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Table);
8348
+ const isAttachmentEnabled = flags == null ? void 0 : flags.includes(CrepeFeature.Attachment);
8349
+ const listGroup = builder.addGroup("list", "List");
8350
+ listGroup.addItem("divider", {
7923
8351
  label: ctx ? i18n(ctx, "menu.item.divider") : "Divider",
7924
8352
  icon: dividerIcon,
7925
8353
  active: () => false,
@@ -7927,9 +8355,7 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
7927
8355
  const commands = ctx2.get(core.commandsCtx);
7928
8356
  commands.call(commonmark.addBlockTypeCommand.key, { nodeType: commonmark.hrSchema.type(ctx2) });
7929
8357
  }
7930
- });
7931
- const listGroup = blockGroup;
7932
- listGroup.addItem("bullet-list", {
8358
+ }).addItem("bullet-list", {
7933
8359
  label: ctx ? i18n(ctx, "menu.item.bulletList") : "Bullet List",
7934
8360
  icon: bulletListIcon,
7935
8361
  active: (ctx2) => {
@@ -8154,6 +8580,174 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8154
8580
  if (result) return;
8155
8581
  }
8156
8582
  });
8583
+ const blockGroup = builder.addGroup("block", "Block");
8584
+ blockGroup.addItem("quote", {
8585
+ label: ctx ? i18n(ctx, "menu.item.quote") : "Quote",
8586
+ icon: quoteIcon,
8587
+ active: (ctx2) => {
8588
+ const view = ctx2.get(core.editorViewCtx);
8589
+ const result = prose.findNodeInSelection(
8590
+ view.state,
8591
+ commonmark.blockquoteSchema.type(ctx2)
8592
+ );
8593
+ return result.hasNode;
8594
+ },
8595
+ onRun: (ctx2) => {
8596
+ const view = ctx2.get(core.editorViewCtx);
8597
+ const commands$1 = ctx2.get(core.commandsCtx);
8598
+ const isActive = prose.findNodeInSelection(
8599
+ view.state,
8600
+ commonmark.blockquoteSchema.type(ctx2)
8601
+ ).hasNode;
8602
+ if (isActive) {
8603
+ commands.lift(view.state, view.dispatch);
8604
+ } else {
8605
+ commands$1.call(commonmark.wrapInBlockTypeCommand.key, {
8606
+ nodeType: commonmark.blockquoteSchema.type(ctx2)
8607
+ });
8608
+ }
8609
+ }
8610
+ }).addItem("highlight", {
8611
+ label: ctx ? i18n(ctx, "menu.item.highlight") : "Highlight",
8612
+ icon: highLineCodeIcon,
8613
+ active: (ctx2) => {
8614
+ const commands = ctx2.get(core.commandsCtx);
8615
+ return commands.call(
8616
+ commonmark.isMarkSelectedCommand.key,
8617
+ highlightMarkSchema.type(ctx2)
8618
+ );
8619
+ },
8620
+ onRun: (ctx2) => {
8621
+ const commands = ctx2.get(core.commandsCtx);
8622
+ commands.call(toggleHighlightMarkCommand.key);
8623
+ }
8624
+ }).addItem("code", {
8625
+ label: ctx ? i18n(ctx, "menu.item.lineCode") : "Inline Code",
8626
+ icon: linCodeIcon,
8627
+ active: (ctx2) => {
8628
+ const commands = ctx2.get(core.commandsCtx);
8629
+ return commands.call(
8630
+ commonmark.isMarkSelectedCommand.key,
8631
+ commonmark.inlineCodeSchema.type(ctx2)
8632
+ );
8633
+ },
8634
+ onRun: (ctx2) => {
8635
+ const commands = ctx2.get(core.commandsCtx);
8636
+ commands.call(commonmark.toggleInlineCodeCommand.key);
8637
+ }
8638
+ }).addItem("link", {
8639
+ label: ctx ? i18n(ctx, "menu.item.link") : "Link",
8640
+ icon: linkIcon,
8641
+ active: (ctx2) => {
8642
+ const commands = ctx2.get(core.commandsCtx);
8643
+ return commands.call(commonmark.isMarkSelectedCommand.key, commonmark.linkSchema.type(ctx2));
8644
+ },
8645
+ onRun: (ctx2) => {
8646
+ const commands = ctx2.get(core.commandsCtx);
8647
+ commands.call(linkTooltip$1.toggleLinkCommand.key);
8648
+ }
8649
+ });
8650
+ if (isImageBlockEnabled) {
8651
+ blockGroup.addItem("image", {
8652
+ label: ctx ? i18n(ctx, "menu.item.image") : "Image",
8653
+ icon: imageIcon,
8654
+ active: () => false,
8655
+ onRun: (ctx2) => {
8656
+ const commands = ctx2.get(core.commandsCtx);
8657
+ commands.call(commonmark.addBlockTypeCommand.key, {
8658
+ nodeType: imageBlock$1.imageBlockSchema.type(ctx2)
8659
+ });
8660
+ }
8661
+ });
8662
+ }
8663
+ if (isAttachmentEnabled) {
8664
+ blockGroup.addItem("attachment", {
8665
+ label: ctx ? i18n(ctx, "menu.item.attachment") : "Video or File",
8666
+ icon: fileLinkIcon,
8667
+ active: () => false,
8668
+ onRun: (ctx2) => {
8669
+ const commands = ctx2.get(core.commandsCtx);
8670
+ commands.call(commonmark.addBlockTypeCommand.key, {
8671
+ nodeType: attachmentSchema.type(ctx2)
8672
+ });
8673
+ }
8674
+ });
8675
+ }
8676
+ blockGroup.addItem("code-block", {
8677
+ label: ctx ? i18n(ctx, "menu.item.code") : "Code Block",
8678
+ icon: codeIcon,
8679
+ active: (ctx2) => {
8680
+ var _a, _b;
8681
+ const view = ctx2.get(core.editorViewCtx);
8682
+ const result = prose.findNodeInSelection(view.state, commonmark.codeBlockSchema.type(ctx2));
8683
+ return result.hasNode && ((_b = (_a = result.target) == null ? void 0 : _a.attrs) == null ? void 0 : _b.language) !== "LaTex";
8684
+ },
8685
+ onRun: (ctx2) => {
8686
+ const commands = ctx2.get(core.commandsCtx);
8687
+ const view = ctx2.get(core.editorViewCtx);
8688
+ const { state, dispatch } = view;
8689
+ const { selection, tr } = state;
8690
+ const { from, to } = selection;
8691
+ let text = "";
8692
+ let blockCount = 0;
8693
+ state.doc.nodesBetween(from, to, (node) => {
8694
+ if (node.isTextblock) {
8695
+ text += (blockCount > 0 ? "\n" : "") + node.textContent;
8696
+ blockCount++;
8697
+ }
8698
+ });
8699
+ if (blockCount > 1) {
8700
+ if (dispatch) {
8701
+ const range = selection.$from.blockRange(selection.$to);
8702
+ const codeBlock = commonmark.codeBlockSchema.type(ctx2).createAndFill({}, text ? state.schema.text(text) : void 0);
8703
+ if (range && codeBlock) {
8704
+ tr.replaceWith(range.start, range.end, codeBlock);
8705
+ dispatch(tr.scrollIntoView());
8706
+ }
8707
+ }
8708
+ return;
8709
+ }
8710
+ commands.call(commonmark.setBlockTypeCommand.key, {
8711
+ nodeType: commonmark.codeBlockSchema.type(ctx2)
8712
+ });
8713
+ }
8714
+ });
8715
+ if (isTableEnabled) {
8716
+ blockGroup.addItem("table", {
8717
+ label: ctx ? i18n(ctx, "menu.item.table") : "Table",
8718
+ icon: tableIcon,
8719
+ active: () => false,
8720
+ onRun: (ctx2) => {
8721
+ const commands = ctx2.get(core.commandsCtx);
8722
+ const view = ctx2.get(core.editorViewCtx);
8723
+ const { from } = view.state.selection;
8724
+ commands.call(commonmark.addBlockTypeCommand.key, {
8725
+ nodeType: gfm.createTable(ctx2, 3, 3)
8726
+ });
8727
+ commands.call(commonmark.selectTextNearPosCommand.key, { pos: from });
8728
+ }
8729
+ });
8730
+ }
8731
+ if (isLatexEnabled) {
8732
+ blockGroup.addItem("math-block", {
8733
+ label: ctx ? i18n(ctx, "menu.item.math") : "Math Block",
8734
+ icon: functionsIcon,
8735
+ active: (ctx2) => {
8736
+ var _a, _b;
8737
+ const view = ctx2.get(core.editorViewCtx);
8738
+ const result = prose.findNodeInSelection(
8739
+ view.state,
8740
+ commonmark.codeBlockSchema.type(ctx2)
8741
+ );
8742
+ return result.hasNode && ((_b = (_a = result.target) == null ? void 0 : _a.attrs) == null ? void 0 : _b.language) === "LaTex";
8743
+ },
8744
+ onRun: (ctx2) => {
8745
+ const commands = ctx2.get(core.commandsCtx);
8746
+ commands.call(toggleLatexCommand.key);
8747
+ }
8748
+ });
8749
+ }
8750
+ return builder.build();
8157
8751
  }
8158
8752
 
8159
8753
  const DocumentHeader = vue.defineComponent({
@@ -8174,12 +8768,26 @@ const DocumentHeader = vue.defineComponent({
8174
8768
  titleTextareaRef.value.style.height = titleTextareaRef.value.scrollHeight + "px";
8175
8769
  }
8176
8770
  };
8771
+ let resizeObserver = null;
8772
+ vue.onMounted(() => {
8773
+ setTimeout(adjustTitleHeight, 0);
8774
+ if (titleTextareaRef.value) {
8775
+ resizeObserver = new ResizeObserver(() => {
8776
+ adjustTitleHeight();
8777
+ });
8778
+ resizeObserver.observe(titleTextareaRef.value);
8779
+ }
8780
+ });
8781
+ vue.onUnmounted(() => {
8782
+ if (resizeObserver) {
8783
+ resizeObserver.disconnect();
8784
+ }
8785
+ });
8177
8786
  vue.watch(
8178
8787
  () => title.value,
8179
8788
  () => {
8180
8789
  setTimeout(adjustTitleHeight, 0);
8181
- },
8182
- { immediate: true }
8790
+ }
8183
8791
  );
8184
8792
  vue.watch(
8185
8793
  () => viewState.value.showCover,
@@ -8218,13 +8826,13 @@ const DocumentHeader = vue.defineComponent({
8218
8826
  var _a, _b;
8219
8827
  const state = viewState.value;
8220
8828
  if (!state.showTitle && !state.showCover) return null;
8221
- return /* @__PURE__ */ vue.h(
8829
+ return /* @__PURE__ */ h(
8222
8830
  "div",
8223
8831
  {
8224
8832
  class: "milkdown-document-header",
8225
8833
  style: { width: "100%", display: "flex", flexDirection: "column" }
8226
8834
  },
8227
- state.showCover ? /* @__PURE__ */ vue.h(
8835
+ state.showCover ? /* @__PURE__ */ h(
8228
8836
  "div",
8229
8837
  {
8230
8838
  class: "milkdown-document-cover",
@@ -8242,7 +8850,7 @@ const DocumentHeader = vue.defineComponent({
8242
8850
  overflow: "hidden"
8243
8851
  }
8244
8852
  },
8245
- /* @__PURE__ */ vue.h(
8853
+ /* @__PURE__ */ h(
8246
8854
  "img",
8247
8855
  {
8248
8856
  src: state.coverUrl,
@@ -8255,7 +8863,7 @@ const DocumentHeader = vue.defineComponent({
8255
8863
  }
8256
8864
  }
8257
8865
  ),
8258
- /* @__PURE__ */ vue.h(
8866
+ /* @__PURE__ */ h(
8259
8867
  "div",
8260
8868
  {
8261
8869
  style: {
@@ -8272,7 +8880,7 @@ const DocumentHeader = vue.defineComponent({
8272
8880
  background: "linear-gradient(transparent, rgba(0,0,0,0.7))"
8273
8881
  }
8274
8882
  },
8275
- /* @__PURE__ */ vue.h(
8883
+ /* @__PURE__ */ h(
8276
8884
  "div",
8277
8885
  {
8278
8886
  style: {
@@ -8284,7 +8892,7 @@ const DocumentHeader = vue.defineComponent({
8284
8892
  },
8285
8893
  (lastUploadedUrl.value ? [lastUploadedUrl.value] : []).concat(
8286
8894
  ((_b = (_a = props.config) == null ? void 0 : _a.defaultCoverImages) == null ? void 0 : _b.length) ? props.config.defaultCoverImages : builtInCoverImages
8287
- ).map((src, i) => /* @__PURE__ */ vue.h(
8895
+ ).map((src, i) => /* @__PURE__ */ h(
8288
8896
  "img",
8289
8897
  {
8290
8898
  key: i,
@@ -8314,7 +8922,7 @@ const DocumentHeader = vue.defineComponent({
8314
8922
  }
8315
8923
  ))
8316
8924
  ),
8317
- /* @__PURE__ */ vue.h(
8925
+ /* @__PURE__ */ h(
8318
8926
  "div",
8319
8927
  {
8320
8928
  onClick: () => {
@@ -8342,7 +8950,7 @@ const DocumentHeader = vue.defineComponent({
8342
8950
  e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.2)";
8343
8951
  }
8344
8952
  },
8345
- /* @__PURE__ */ vue.h(
8953
+ /* @__PURE__ */ h(
8346
8954
  "svg",
8347
8955
  {
8348
8956
  width: "14",
@@ -8354,14 +8962,14 @@ const DocumentHeader = vue.defineComponent({
8354
8962
  "stroke-linecap": "round",
8355
8963
  "stroke-linejoin": "round"
8356
8964
  },
8357
- /* @__PURE__ */ vue.h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
8358
- /* @__PURE__ */ vue.h("polyline", { points: "17 8 12 3 7 8" }),
8359
- /* @__PURE__ */ vue.h("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
8965
+ /* @__PURE__ */ h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
8966
+ /* @__PURE__ */ h("polyline", { points: "17 8 12 3 7 8" }),
8967
+ /* @__PURE__ */ h("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
8360
8968
  ),
8361
8969
  "\u4E0A\u4F20"
8362
8970
  )
8363
8971
  ),
8364
- /* @__PURE__ */ vue.h(
8972
+ /* @__PURE__ */ h(
8365
8973
  "input",
8366
8974
  {
8367
8975
  type: "file",
@@ -8372,7 +8980,7 @@ const DocumentHeader = vue.defineComponent({
8372
8980
  }
8373
8981
  )
8374
8982
  ) : null,
8375
- state.showTitle ? /* @__PURE__ */ vue.h(
8983
+ state.showTitle ? /* @__PURE__ */ h(
8376
8984
  "div",
8377
8985
  {
8378
8986
  class: "milkdown-document-title-wrapper",
@@ -8383,14 +8991,18 @@ const DocumentHeader = vue.defineComponent({
8383
8991
  padding: `40px ${editorWidthMap[state.editorWidth] === "none" ? "80px" : "0"} 0`
8384
8992
  }
8385
8993
  },
8386
- /* @__PURE__ */ vue.h("style", null, `.milkdown-document-title::placeholder { color: #BFBFBF; }`),
8387
- /* @__PURE__ */ vue.h(
8994
+ /* @__PURE__ */ h("style", null, `.milkdown-document-title::placeholder { color: #BFBFBF; }`),
8995
+ /* @__PURE__ */ h(
8388
8996
  "textarea",
8389
8997
  {
8390
8998
  ref: titleTextareaRef,
8391
8999
  class: "milkdown-document-title",
8392
9000
  placeholder: "\u8BF7\u8F93\u5165\u6807\u9898",
8393
- "v-model": title.value,
9001
+ value: title.value,
9002
+ onInput: (e) => {
9003
+ title.value = e.target.value;
9004
+ adjustTitleHeight();
9005
+ },
8394
9006
  rows: 1,
8395
9007
  style: {
8396
9008
  width: "100%",
@@ -8598,7 +9210,7 @@ const OutlinePanel = vue.defineComponent({
8598
9210
  const state = viewState.value;
8599
9211
  if (!state.outlineVisible) return null;
8600
9212
  const isLeft = state.outlinePosition === "left";
8601
- return /* @__PURE__ */ vue.h(
9213
+ return /* @__PURE__ */ h(
8602
9214
  "div",
8603
9215
  {
8604
9216
  class: "milkdown-outline-panel",
@@ -8619,7 +9231,7 @@ const OutlinePanel = vue.defineComponent({
8619
9231
  overflow: "hidden"
8620
9232
  }
8621
9233
  },
8622
- /* @__PURE__ */ vue.h(
9234
+ /* @__PURE__ */ h(
8623
9235
  "div",
8624
9236
  {
8625
9237
  style: {
@@ -8633,8 +9245,8 @@ const OutlinePanel = vue.defineComponent({
8633
9245
  alignItems: "center"
8634
9246
  }
8635
9247
  },
8636
- /* @__PURE__ */ vue.h("span", null, i18n(props.ctx, "view.outline")),
8637
- /* @__PURE__ */ vue.h(
9248
+ /* @__PURE__ */ h("span", null, i18n(props.ctx, "view.outline")),
9249
+ /* @__PURE__ */ h(
8638
9250
  "div",
8639
9251
  {
8640
9252
  style: {
@@ -8658,7 +9270,7 @@ const OutlinePanel = vue.defineComponent({
8658
9270
  },
8659
9271
  title: "\u5173\u95ED\u5927\u7EB2"
8660
9272
  },
8661
- /* @__PURE__ */ vue.h(
9273
+ /* @__PURE__ */ h(
8662
9274
  "svg",
8663
9275
  {
8664
9276
  width: "16",
@@ -8670,12 +9282,12 @@ const OutlinePanel = vue.defineComponent({
8670
9282
  "stroke-linecap": "round",
8671
9283
  "stroke-linejoin": "round"
8672
9284
  },
8673
- /* @__PURE__ */ vue.h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
8674
- /* @__PURE__ */ vue.h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
9285
+ /* @__PURE__ */ h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
9286
+ /* @__PURE__ */ h("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
8675
9287
  )
8676
9288
  )
8677
9289
  ),
8678
- /* @__PURE__ */ vue.h("div", { style: { flexGrow: 1, overflowY: "auto", padding: "12px 0" } }, items.value.length === 0 ? /* @__PURE__ */ vue.h(
9290
+ /* @__PURE__ */ h("div", { style: { flexGrow: 1, overflowY: "auto", padding: "12px 0" } }, items.value.length === 0 ? /* @__PURE__ */ h(
8679
9291
  "div",
8680
9292
  {
8681
9293
  style: {
@@ -8688,7 +9300,7 @@ const OutlinePanel = vue.defineComponent({
8688
9300
  ) : null, visibleItems.value.map(({ item, hasChildren: hasKids }) => {
8689
9301
  const isActive = activeId.value === item.id;
8690
9302
  const collapsed = collapsedIds.value.has(item.id);
8691
- return /* @__PURE__ */ vue.h(
9303
+ return /* @__PURE__ */ h(
8692
9304
  "div",
8693
9305
  {
8694
9306
  key: item.id,
@@ -8721,7 +9333,7 @@ const OutlinePanel = vue.defineComponent({
8721
9333
  }
8722
9334
  }
8723
9335
  },
8724
- /* @__PURE__ */ vue.h(
9336
+ /* @__PURE__ */ h(
8725
9337
  "span",
8726
9338
  {
8727
9339
  onClick: (e) => {
@@ -8751,9 +9363,10 @@ const OutlinePanel = vue.defineComponent({
8751
9363
  e.currentTarget.style.backgroundColor = "transparent";
8752
9364
  }
8753
9365
  },
8754
- "\u25BC"
9366
+ "\uFFFD?",
9367
+ " "
8755
9368
  ),
8756
- /* @__PURE__ */ vue.h(
9369
+ /* @__PURE__ */ h(
8757
9370
  "span",
8758
9371
  {
8759
9372
  title: item.text,
@@ -8766,7 +9379,7 @@ const OutlinePanel = vue.defineComponent({
8766
9379
  )
8767
9380
  );
8768
9381
  })),
8769
- /* @__PURE__ */ vue.h(
9382
+ /* @__PURE__ */ h(
8770
9383
  "div",
8771
9384
  {
8772
9385
  onPointerdown: onPointerDown,
@@ -9477,551 +10090,232 @@ const linkTooltip = (editor, config) => {
9477
10090
  editor.config(crepeFeatureConfig(CrepeFeature.LinkTooltip)).config(linkTooltip$1.configureLinkTooltip).config((ctx) => {
9478
10091
  ctx.update(linkTooltip$1.linkTooltipConfig.key, (prev) => {
9479
10092
  var _a, _b, _c, _d, _e, _f;
9480
- return {
9481
- ...prev,
9482
- linkIcon: (_a = config == null ? void 0 : config.linkIcon) != null ? _a : copyIcon,
9483
- editButton: (_b = config == null ? void 0 : config.editButton) != null ? _b : editIcon,
9484
- removeButton: (_c = config == null ? void 0 : config.removeButton) != null ? _c : removeIcon,
9485
- confirmButton: (_d = config == null ? void 0 : config.confirmButton) != null ? _d : confirmIcon,
9486
- inputPlaceholder: (_e = config == null ? void 0 : config.inputPlaceholder) != null ? _e : i18n(ctx, "linkTooltip.pasteLink"),
9487
- onCopyLink: (_f = config == null ? void 0 : config.onCopyLink) != null ? _f : (() => {
9488
- })
9489
- };
9490
- });
9491
- }).use(linkTooltip$1.linkTooltipPlugin);
9492
- };
9493
-
9494
- function configureListItem(ctx, config) {
9495
- ctx.set(listItemBlock.listItemBlockConfig.key, {
9496
- renderLabel: ({ label, listType, checked }) => {
9497
- var _a, _b, _c;
9498
- if (checked == null) {
9499
- if (listType === "bullet") return (_a = config == null ? void 0 : config.bulletIcon) != null ? _a : bulletIcon;
9500
- return label;
9501
- }
9502
- if (checked) return (_b = config == null ? void 0 : config.checkBoxCheckedIcon) != null ? _b : checkBoxCheckedIcon;
9503
- return (_c = config == null ? void 0 : config.checkBoxUncheckedIcon) != null ? _c : checkBoxUncheckedIcon;
9504
- }
9505
- });
9506
- }
9507
- const listItem = (editor, config) => {
9508
- editor.config(crepeFeatureConfig(CrepeFeature.ListItem)).config((ctx) => configureListItem(ctx, config)).use(listItemBlock.listItemBlockComponent);
9509
- };
9510
-
9511
- function isDocEmpty(doc) {
9512
- var _a;
9513
- return doc.childCount <= 1 && !((_a = doc.firstChild) == null ? void 0 : _a.content.size);
9514
- }
9515
- function createPlaceholderDecoration(state, placeholderText) {
9516
- const { selection } = state;
9517
- if (!selection.empty) return null;
9518
- const $pos = selection.$anchor;
9519
- const node = $pos.parent;
9520
- if (node.content.size > 0) return null;
9521
- const inTable = prose.findParent((node2) => node2.type.name === "table")($pos);
9522
- if (inTable) return null;
9523
- const before = $pos.before();
9524
- return view$1.Decoration.node(before, before + node.nodeSize, {
9525
- class: "crepe-placeholder",
9526
- "data-placeholder": placeholderText
9527
- });
9528
- }
9529
- const placeholderConfig = utils.$ctx(
9530
- {
9531
- mode: "doc"
9532
- },
9533
- "placeholderConfigCtx"
9534
- );
9535
- const placeholderPlugin = utils.$prose((ctx) => {
9536
- return new state.Plugin({
9537
- key: new state.PluginKey("CREPE_PLACEHOLDER"),
9538
- props: {
9539
- decorations: (state) => {
9540
- var _a;
9541
- const crepe = useCrepe(ctx);
9542
- if (crepe.readonly) return view$1.DecorationSet.empty;
9543
- const config = ctx.get(placeholderConfig.key);
9544
- if (config.mode === "doc" && !isDocEmpty(state.doc)) return view$1.DecorationSet.empty;
9545
- if (isInCodeBlock(state.selection) || isInList(state.selection))
9546
- return view$1.DecorationSet.empty;
9547
- const placeholderText = (_a = config.text) != null ? _a : i18n(ctx, "placeholder.text");
9548
- const deco = createPlaceholderDecoration(state, placeholderText);
9549
- if (!deco) return view$1.DecorationSet.empty;
9550
- return view$1.DecorationSet.create(state.doc, [deco]);
9551
- }
9552
- }
9553
- });
9554
- });
9555
- const placeholder = (editor, config) => {
9556
- editor.config(crepeFeatureConfig(CrepeFeature.Placeholder)).config((ctx) => {
9557
- if (config) {
9558
- ctx.update(placeholderConfig.key, (prev) => {
9559
- return {
9560
- ...prev,
9561
- ...config
9562
- };
9563
- });
9564
- }
9565
- }).use(placeholderPlugin).use(placeholderConfig);
9566
- };
9567
-
9568
- const table = (editor, config) => {
9569
- editor.config(crepeFeatureConfig(CrepeFeature.Table)).config((ctx) => {
9570
- ctx.update(tableBlock.tableBlockConfig.key, (defaultConfig) => ({
9571
- ...defaultConfig,
9572
- renderButton: (renderType) => {
9573
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9574
- switch (renderType) {
9575
- case "add_row":
9576
- return (_a = config == null ? void 0 : config.addRowIcon) != null ? _a : plusIcon;
9577
- case "add_col":
9578
- return (_b = config == null ? void 0 : config.addColIcon) != null ? _b : plusIcon;
9579
- case "delete_row":
9580
- return (_c = config == null ? void 0 : config.deleteRowIcon) != null ? _c : removeIcon;
9581
- case "delete_col":
9582
- return (_d = config == null ? void 0 : config.deleteColIcon) != null ? _d : removeIcon;
9583
- case "align_col_left":
9584
- return (_e = config == null ? void 0 : config.alignLeftIcon) != null ? _e : alignLeftIcon;
9585
- case "align_col_center":
9586
- return (_f = config == null ? void 0 : config.alignCenterIcon) != null ? _f : alignCenterIcon;
9587
- case "align_col_right":
9588
- return (_g = config == null ? void 0 : config.alignRightIcon) != null ? _g : alignRightIcon;
9589
- case "col_drag_handle":
9590
- return (_h = config == null ? void 0 : config.colDragHandleIcon) != null ? _h : dragHandleIcon;
9591
- case "row_drag_handle":
9592
- return (_i = config == null ? void 0 : config.rowDragHandleIcon) != null ? _i : dragHandleIcon;
9593
- case "merge_cells":
9594
- return (_j = config == null ? void 0 : config.mergeCellsIcon) != null ? _j : mergeCellIcon;
9595
- case "split_cell":
9596
- return (_k = config == null ? void 0 : config.splitCellIcon) != null ? _k : splitCellIcon;
9597
- }
9598
- }
9599
- }));
9600
- }).use(tableBlock.tableBlock);
9601
- };
9602
-
9603
- var __typeError$1 = (msg) => {
9604
- throw TypeError(msg);
9605
- };
9606
- var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Cannot " + msg);
9607
- var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9608
- var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
9609
- var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
9610
- var _tooltipProvider, _content, _app, _selection, _show, _mousePressed;
9611
- const toolbarTooltip = tooltip.tooltipFactory("CREPE_TOOLBAR");
9612
- class ToolbarView {
9613
- constructor(ctx, view, config) {
9614
- __privateAdd$1(this, _tooltipProvider);
9615
- __privateAdd$1(this, _content);
9616
- __privateAdd$1(this, _app);
9617
- __privateAdd$1(this, _selection);
9618
- __privateAdd$1(this, _show, vue.ref(false));
9619
- __privateAdd$1(this, _mousePressed, false);
9620
- this.update = (view, prevState) => {
9621
- __privateGet$1(this, _tooltipProvider).update(view, prevState);
9622
- __privateGet$1(this, _selection).value = view.state.selection;
9623
- };
9624
- this.destroy = () => {
9625
- __privateGet$1(this, _tooltipProvider).destroy();
9626
- __privateGet$1(this, _app).unmount();
9627
- __privateGet$1(this, _content).remove();
9628
- };
9629
- this.hide = () => {
9630
- __privateGet$1(this, _tooltipProvider).hide();
9631
- };
9632
- const content = document.createElement("div");
9633
- content.className = "milkdown-toolbar";
9634
- __privateSet$1(this, _selection, vue.shallowRef(view.state.selection));
9635
- const app = vue.createApp(Toolbar, {
9636
- ctx,
9637
- hide: this.hide,
9638
- config,
9639
- selection: __privateGet$1(this, _selection),
9640
- show: __privateGet$1(this, _show)
9641
- });
9642
- app.mount(content);
9643
- __privateSet$1(this, _content, content);
9644
- __privateSet$1(this, _app, app);
9645
- view.dom.addEventListener("mousedown", () => {
9646
- __privateSet$1(this, _mousePressed, true);
9647
- });
9648
- view.dom.addEventListener("mouseup", () => {
9649
- __privateSet$1(this, _mousePressed, false);
9650
- setTimeout(() => {
9651
- this.update(view);
9652
- }, 0);
9653
- });
9654
- __privateSet$1(this, _tooltipProvider, new tooltip.TooltipProvider({
9655
- content: __privateGet$1(this, _content),
9656
- debounce: 20,
9657
- offset: 10,
9658
- shouldShow: (view2) => {
9659
- if (__privateGet$1(this, _mousePressed)) return false;
9660
- const { doc, selection } = view2.state;
9661
- const { empty, from, to } = selection;
9662
- const isEmptyTextBlock = !doc.textBetween(from, to).length && selection instanceof state.TextSelection;
9663
- const isNotTextBlock = !(selection instanceof state.TextSelection) && !(selection instanceof state.AllSelection);
9664
- const activeElement = view2.dom.getRootNode().activeElement;
9665
- const isTooltipChildren = content.contains(activeElement);
9666
- const notHasFocus = !view2.hasFocus() && !isTooltipChildren;
9667
- const isReadonly = !view2.editable;
9668
- if (notHasFocus || isNotTextBlock || empty || isEmptyTextBlock || isReadonly)
9669
- return false;
9670
- return true;
9671
- }
9672
- }));
9673
- __privateGet$1(this, _tooltipProvider).onShow = () => {
9674
- __privateGet$1(this, _show).value = true;
9675
- };
9676
- __privateGet$1(this, _tooltipProvider).onHide = () => {
9677
- __privateGet$1(this, _show).value = false;
9678
- };
9679
- this.update(view);
9680
- }
9681
- }
9682
- _tooltipProvider = new WeakMap();
9683
- _content = new WeakMap();
9684
- _app = new WeakMap();
9685
- _selection = new WeakMap();
9686
- _show = new WeakMap();
9687
- _mousePressed = new WeakMap();
9688
- const toolbar = (editor, config) => {
9689
- editor.config(crepeFeatureConfig(CrepeFeature.Toolbar)).config((ctx) => {
9690
- ctx.set(toolbarTooltip.key, {
9691
- view: (view) => new ToolbarView(ctx, view, config)
9692
- });
9693
- }).config((ctx) => {
9694
- ctx.update(core.editorViewOptionsCtx, (prev) => {
9695
- const prevTransform = prev.transformPastedHTML;
9696
- return {
9697
- ...prev,
9698
- transformPastedHTML: (html, view) => {
9699
- if (prevTransform) html = prevTransform(html, view);
9700
- return stripFontFamilyFromExternalHTML(html);
9701
- }
10093
+ return {
10094
+ ...prev,
10095
+ linkIcon: (_a = config == null ? void 0 : config.linkIcon) != null ? _a : copyIcon,
10096
+ editButton: (_b = config == null ? void 0 : config.editButton) != null ? _b : editIcon,
10097
+ removeButton: (_c = config == null ? void 0 : config.removeButton) != null ? _c : removeIcon,
10098
+ confirmButton: (_d = config == null ? void 0 : config.confirmButton) != null ? _d : confirmIcon,
10099
+ inputPlaceholder: (_e = config == null ? void 0 : config.inputPlaceholder) != null ? _e : i18n(ctx, "linkTooltip.pasteLink"),
10100
+ onCopyLink: (_f = config == null ? void 0 : config.onCopyLink) != null ? _f : (() => {
10101
+ })
9702
10102
  };
9703
10103
  });
9704
- }).use(underline).use(highlightMark).use(colorPlugins).use(fontPlugins).use(toolbarTooltip);
10104
+ }).use(linkTooltip$1.linkTooltipPlugin);
9705
10105
  };
9706
10106
 
9707
- const attachmentConfig = utils.$ctx(
9708
- {
9709
- onUpload: async (file) => {
9710
- return {
9711
- url: URL.createObjectURL(file),
9712
- name: file.name,
9713
- size: file.size
9714
- };
9715
- },
9716
- uploadButton: "Upload file",
9717
- uploadPlaceholderText: "or paste link",
9718
- downloadText: "Download"
9719
- },
9720
- "attachmentConfig"
9721
- );
10107
+ function configureListItem(ctx, config) {
10108
+ ctx.set(listItemBlock.listItemBlockConfig.key, {
10109
+ renderLabel: ({ label, listType, checked }) => {
10110
+ var _a, _b, _c;
10111
+ if (checked == null) {
10112
+ if (listType === "bullet") return (_a = config == null ? void 0 : config.bulletIcon) != null ? _a : bulletIcon;
10113
+ return label;
10114
+ }
10115
+ if (checked) return (_b = config == null ? void 0 : config.checkBoxCheckedIcon) != null ? _b : checkBoxCheckedIcon;
10116
+ return (_c = config == null ? void 0 : config.checkBoxUncheckedIcon) != null ? _c : checkBoxUncheckedIcon;
10117
+ }
10118
+ });
10119
+ }
10120
+ const listItem = (editor, config) => {
10121
+ editor.config(crepeFeatureConfig(CrepeFeature.ListItem)).config((ctx) => configureListItem(ctx, config)).use(listItemBlock.listItemBlockComponent);
10122
+ };
9722
10123
 
9723
- const downloadIcon = `<svg viewBox="0 0 1024 1024" width="20" height="20" fill="currentColor">
9724
- <path d="M464.96 743.936L194.304 479.68c-4.928-4.8-10.24-9.408-14.592-14.656-20.736-24.768-21.376-45.76-2.368-63.424 17.664-16.384 43.328-16 65.472 4.8 49.088 46.144 96.64 93.824 144.896 140.8l69.376 67.52 11.968 11.392v-184.96c0-36.096-0.128-86.272-0.32-136.96-0.192-54.912-0.32-110.464-0.32-149.504l-0.064-9.28a208 208 0 0 1 0.704-26.56c3.52-31.168 19.328-46.592 45.248-45.76 25.344 0.832 41.088 16.96 42.688 48.576 1.28 24.384 1.024 48.896 0.768 73.408l-0.128 28.928c0 53.376 0.128 120.32 0.256 188.096 0.192 76.352 0.384 153.792 0.32 214.016 74.432-72.704 185.6-181.12 216.32-210.88 7.424-7.168 14.912-15.168 24-19.52 18.688-8.96 37.632-8.32 52.672 7.872 14.72 15.744 16.448 33.408 4.032 51.392-3.84 5.632-8.576 10.816-13.44 15.616-45.696 44.736-243.328 238.272-289.728 282.24a62.592 62.592 0 0 1-8.064 6.4 43.392 43.392 0 0 1-15.872 10.432c-20.544 7.616-37.504-0.512-51.968-14.848l-11.2-10.88z m430.784-39.744c24-0.576 42.176 14.4 43.328 41.6 1.728 40.832 2.944 82.176-1.088 122.816-5.312 54.144-51.52 89.792-114.752 91.008-50.112 0.896-100.224 0.704-150.4 0.512L608 960H434.944c-64.832 0.128-129.6 0.192-194.432-0.192-90.624-0.512-130.752-40.192-131.392-128.64l-0.192-18.56c-0.32-21.12-0.576-42.304 0.768-63.36 1.92-29.76 20.48-46.528 45.76-45.184 23.488 1.28 37.312 16.32 40.064 45.184 0.896 9.792 0.832 19.648 0.704 29.504l-0.064 11.52c0.384 76.544 7.36 83.392 88.128 83.456a163213.952 163213.952 0 0 0 351.68 0.064l43.968 0.128c36.096 0.128 72.192 0.256 108.288-0.448 52.672-1.024 64-12.864 65.152-64.32 0.192-7.68 0.128-15.488 0-23.232a414.72 414.72 0 0 1 0.704-38.208c2.24-27.712 17.92-42.944 41.664-43.52z" fill="currentColor"></path>
9725
- </svg>`;
9726
- function formatBytes(bytes, decimals = 2) {
9727
- if (!+bytes) return "0 Bytes";
9728
- const k = 1024;
9729
- const dm = decimals < 0 ? 0 : decimals;
9730
- const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
9731
- const i = Math.floor(Math.log(bytes) / Math.log(k));
9732
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
10124
+ function isDocEmpty(doc) {
10125
+ var _a;
10126
+ return doc.childCount <= 1 && !((_a = doc.firstChild) == null ? void 0 : _a.content.size);
9733
10127
  }
9734
- const MilkdownAttachmentBlock = vue.defineComponent({
9735
- props: {
9736
- src: { type: Object, required: true },
9737
- name: { type: Object, required: true },
9738
- size: { type: Object, required: true },
9739
- videoWidth: { type: Object, required: true },
9740
- selected: { type: Object, required: true },
9741
- readonly: { type: Object, required: true },
9742
- setAttr: { type: Function, required: true },
9743
- config: { type: Object, required: true }
10128
+ function createPlaceholderDecoration(state, placeholderText) {
10129
+ const { selection } = state;
10130
+ if (!selection.empty) return null;
10131
+ const $pos = selection.$anchor;
10132
+ const node = $pos.parent;
10133
+ if (node.content.size > 0) return null;
10134
+ const inTable = prose.findParent((node2) => node2.type.name === "table")($pos);
10135
+ if (inTable) return null;
10136
+ const before = $pos.before();
10137
+ return view$1.Decoration.node(before, before + node.nodeSize, {
10138
+ class: "crepe-placeholder",
10139
+ "data-placeholder": placeholderText
10140
+ });
10141
+ }
10142
+ const placeholderConfig = utils.$ctx(
10143
+ {
10144
+ mode: "doc"
9744
10145
  },
9745
- setup(props) {
9746
- const { src, name, size, videoWidth } = props;
9747
- const isUploading = vue.shallowRef(false);
9748
- const fileInput = vue.shallowRef(null);
9749
- const videoWrapperRef = vue.ref(null);
9750
- const currentWidth = vue.ref(0);
9751
- const isResizing = vue.ref(false);
9752
- const isVideo = vue.computed(() => {
9753
- return name.value && /\.(mp4|webm|ogg|mov|avi|mkv|flv|wmv|m4v|3gp|ts)$/i.test(name.value);
9754
- });
9755
- let resizeDir = "";
9756
- let startX = 0;
9757
- let startWidth = 0;
9758
- const triggerUpload = () => {
9759
- var _a;
9760
- (_a = fileInput.value) == null ? void 0 : _a.click();
9761
- };
9762
- const onFileChange = async (e) => {
9763
- var _a;
9764
- const target = e.target;
9765
- const file = (_a = target.files) == null ? void 0 : _a[0];
9766
- if (!file) return;
9767
- isUploading.value = true;
9768
- try {
9769
- const result = await props.config.onUpload(file);
9770
- props.setAttr("src", result.url);
9771
- props.setAttr("name", result.name);
9772
- props.setAttr("size", result.size);
9773
- } catch (err) {
9774
- console.error("Failed to upload file", err);
9775
- } finally {
9776
- isUploading.value = false;
9777
- target.value = "";
9778
- }
9779
- };
9780
- const openLink = () => {
9781
- if (src.value) {
9782
- window.open(src.value, "_blank");
9783
- }
9784
- };
9785
- let activeHandle = null;
9786
- const onResizePointerMove = (e) => {
9787
- e.preventDefault();
9788
- const deltaX = e.clientX - startX;
9789
- let dw = 0;
9790
- if (resizeDir.includes("right")) {
9791
- dw = deltaX;
9792
- } else if (resizeDir.includes("left")) {
9793
- dw = -deltaX;
9794
- }
9795
- let newWidth = startWidth + dw;
9796
- if (newWidth < 200) newWidth = 200;
9797
- const wrapper = videoWrapperRef.value;
9798
- if (wrapper) {
9799
- const parent = wrapper.closest(".milkdown-attachment-block-wrapper");
9800
- if (parent) {
9801
- const maxWidth = parent.getBoundingClientRect().width;
9802
- if (newWidth > maxWidth) newWidth = maxWidth;
9803
- }
9804
- }
9805
- currentWidth.value = newWidth;
9806
- };
9807
- const onResizePointerUp = (e) => {
9808
- if (activeHandle) {
9809
- activeHandle.releasePointerCapture(e.pointerId);
9810
- activeHandle.removeEventListener(
9811
- "pointermove",
9812
- onResizePointerMove
9813
- );
9814
- activeHandle.removeEventListener(
9815
- "pointerup",
9816
- onResizePointerUp
9817
- );
9818
- activeHandle = null;
9819
- }
9820
- isResizing.value = false;
9821
- if (currentWidth.value > 0) {
9822
- props.setAttr("videoWidth", Math.round(currentWidth.value));
9823
- }
9824
- };
9825
- const onResizePointerDown = (e, dir) => {
9826
- if (props.readonly.value) return;
9827
- e.preventDefault();
9828
- e.stopPropagation();
9829
- resizeDir = dir;
9830
- startX = e.clientX;
9831
- isResizing.value = true;
9832
- const handle = e.currentTarget;
9833
- activeHandle = handle;
9834
- handle.setPointerCapture(e.pointerId);
9835
- const wrapper = videoWrapperRef.value;
9836
- if (wrapper) {
9837
- startWidth = wrapper.getBoundingClientRect().width;
9838
- currentWidth.value = startWidth;
9839
- }
9840
- handle.addEventListener("pointermove", onResizePointerMove);
9841
- handle.addEventListener("pointerup", onResizePointerUp);
9842
- };
9843
- return () => {
9844
- var _a;
9845
- if (!((_a = src.value) == null ? void 0 : _a.length)) {
9846
- return /* @__PURE__ */ vue.h(
9847
- "div",
9848
- {
9849
- class: [
9850
- "milkdown-attachment-placeholder",
9851
- props.selected.value ? "selected" : ""
9852
- ]
9853
- },
9854
- /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-uploader", onClick: triggerUpload }, /* @__PURE__ */ vue.h(component.Icon, { icon: fileLinkIcon }), /* @__PURE__ */ vue.h("span", { class: "milkdown-attachment-upload-text" }, isUploading.value ? "Uploading..." : props.config.uploadButton), /* @__PURE__ */ vue.h(
9855
- "input",
9856
- {
9857
- type: "file",
9858
- ref: fileInput,
9859
- onChange: onFileChange,
9860
- style: "display: none;"
9861
- }
9862
- ))
9863
- );
9864
- }
9865
- if (isVideo.value) {
9866
- const savedWidth = videoWidth.value;
9867
- const widthStyle = isResizing.value && currentWidth.value > 0 ? `${currentWidth.value}px` : savedWidth && savedWidth > 0 ? `${savedWidth}px` : "100%";
9868
- return /* @__PURE__ */ vue.h(
9869
- "div",
9870
- {
9871
- ref: videoWrapperRef,
9872
- class: [
9873
- "milkdown-attachment-video-viewer",
9874
- props.selected.value ? "selected" : ""
9875
- ],
9876
- style: {
9877
- width: widthStyle,
9878
- margin: "0 auto",
9879
- position: "relative"
9880
- }
9881
- },
9882
- /* @__PURE__ */ vue.h(
9883
- "video",
9884
- {
9885
- src: src.value,
9886
- controls: true,
9887
- style: "width: 100%; display: block; border-radius: 8px;",
9888
- onMousedown: (e) => e.stopPropagation()
9889
- }
9890
- ),
9891
- /* @__PURE__ */ vue.h(
9892
- "div",
9893
- {
9894
- class: "video-resize-handle top-left",
9895
- onPointerdown: (e) => onResizePointerDown(e, "top-left")
9896
- }
9897
- ),
9898
- /* @__PURE__ */ vue.h(
9899
- "div",
9900
- {
9901
- class: "video-resize-handle top-right",
9902
- onPointerdown: (e) => onResizePointerDown(e, "top-right")
9903
- }
9904
- ),
9905
- /* @__PURE__ */ vue.h(
9906
- "div",
9907
- {
9908
- class: "video-resize-handle bottom-left",
9909
- onPointerdown: (e) => onResizePointerDown(e, "bottom-left")
9910
- }
9911
- ),
9912
- /* @__PURE__ */ vue.h(
9913
- "div",
9914
- {
9915
- class: "video-resize-handle bottom-right",
9916
- onPointerdown: (e) => onResizePointerDown(e, "bottom-right")
9917
- }
9918
- )
9919
- );
10146
+ "placeholderConfigCtx"
10147
+ );
10148
+ const placeholderPlugin = utils.$prose((ctx) => {
10149
+ return new state.Plugin({
10150
+ key: new state.PluginKey("CREPE_PLACEHOLDER"),
10151
+ props: {
10152
+ decorations: (state) => {
10153
+ var _a;
10154
+ const crepe = useCrepe(ctx);
10155
+ if (crepe.readonly) return view$1.DecorationSet.empty;
10156
+ const config = ctx.get(placeholderConfig.key);
10157
+ if (config.mode === "doc" && !isDocEmpty(state.doc))
10158
+ return view$1.DecorationSet.empty;
10159
+ if (isInCodeBlock(state.selection) || isInList(state.selection))
10160
+ return view$1.DecorationSet.empty;
10161
+ const placeholderText = (_a = config.text) != null ? _a : i18n(ctx, "placeholder.text");
10162
+ const deco = createPlaceholderDecoration(state, placeholderText);
10163
+ if (!deco) return view$1.DecorationSet.empty;
10164
+ return view$1.DecorationSet.create(state.doc, [deco]);
9920
10165
  }
9921
- return /* @__PURE__ */ vue.h(
9922
- "div",
9923
- {
9924
- class: [
9925
- "milkdown-attachment-viewer",
9926
- props.selected.value ? "selected" : ""
9927
- ]
9928
- },
9929
- /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-icon-wrapper" }, /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-raw-icon-bg" }, /* @__PURE__ */ vue.h(component.Icon, { icon: fileLinkIcon }))),
9930
- /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-info" }, /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-name" }, name.value), /* @__PURE__ */ vue.h("div", { class: "milkdown-attachment-size" }, (size.value || 0) > 0 ? formatBytes(size.value) : "")),
9931
- /* @__PURE__ */ vue.h(
9932
- "div",
9933
- {
9934
- class: "milkdown-attachment-action",
9935
- onClick: openLink,
9936
- title: props.config.downloadText
9937
- },
9938
- /* @__PURE__ */ vue.h(component.Icon, { icon: downloadIcon })
9939
- )
9940
- );
9941
- };
9942
- }
10166
+ }
10167
+ });
9943
10168
  });
9944
-
9945
- const attachmentView = utils.$view(
9946
- attachmentSchema.node,
9947
- (ctx) => {
9948
- return (initialNode, view, getPos) => {
9949
- const src = vue.ref(initialNode.attrs.src);
9950
- const name = vue.ref(initialNode.attrs.name);
9951
- const size = vue.ref(initialNode.attrs.size);
9952
- const videoWidth = vue.ref(initialNode.attrs.videoWidth);
9953
- const selected = vue.ref(false);
9954
- const readonly = vue.ref(!view.editable);
9955
- const setAttr = (attr, value) => {
9956
- if (!view.editable) return;
9957
- const pos = getPos();
9958
- if (pos == null) return;
9959
- view.dispatch(view.state.tr.setNodeAttribute(pos, attr, value));
9960
- };
9961
- const config = ctx.get(attachmentConfig.key);
9962
- const app = vue.createApp(MilkdownAttachmentBlock, {
9963
- src,
9964
- name,
9965
- size,
9966
- videoWidth,
9967
- selected,
9968
- readonly,
9969
- setAttr,
9970
- config
9971
- });
9972
- const dom = document.createElement("div");
9973
- dom.className = "milkdown-attachment-block-wrapper";
9974
- const disposeSelectedWatcher = vue.watchEffect(() => {
9975
- if (selected.value) {
9976
- dom.classList.add("selected");
9977
- } else {
9978
- dom.classList.remove("selected");
9979
- }
10169
+ const placeholder = (editor, config) => {
10170
+ editor.config(crepeFeatureConfig(CrepeFeature.Placeholder)).config((ctx) => {
10171
+ if (config) {
10172
+ ctx.update(placeholderConfig.key, (prev) => {
10173
+ return {
10174
+ ...prev,
10175
+ ...config
10176
+ };
9980
10177
  });
9981
- const bindAttrs = (node) => {
9982
- src.value = node.attrs.src;
9983
- name.value = node.attrs.name;
9984
- size.value = node.attrs.size;
9985
- videoWidth.value = node.attrs.videoWidth;
9986
- readonly.value = !view.editable;
9987
- };
9988
- bindAttrs(initialNode);
9989
- app.mount(dom);
9990
- return {
9991
- dom,
9992
- update: (updatedNode) => {
9993
- if (updatedNode.type !== initialNode.type) return false;
9994
- bindAttrs(updatedNode);
9995
- return true;
9996
- },
9997
- selectNode: () => {
9998
- selected.value = true;
9999
- },
10000
- deselectNode: () => {
10001
- selected.value = false;
10002
- },
10003
- destroy: () => {
10004
- disposeSelectedWatcher();
10005
- app.unmount();
10006
- dom.remove();
10178
+ }
10179
+ }).use(placeholderPlugin).use(placeholderConfig);
10180
+ };
10181
+
10182
+ const table = (editor, config) => {
10183
+ editor.config(crepeFeatureConfig(CrepeFeature.Table)).config((ctx) => {
10184
+ ctx.update(tableBlock.tableBlockConfig.key, (defaultConfig) => ({
10185
+ ...defaultConfig,
10186
+ renderButton: (renderType) => {
10187
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
10188
+ switch (renderType) {
10189
+ case "add_row":
10190
+ return (_a = config == null ? void 0 : config.addRowIcon) != null ? _a : plusIcon;
10191
+ case "add_col":
10192
+ return (_b = config == null ? void 0 : config.addColIcon) != null ? _b : plusIcon;
10193
+ case "delete_row":
10194
+ return (_c = config == null ? void 0 : config.deleteRowIcon) != null ? _c : removeIcon;
10195
+ case "delete_col":
10196
+ return (_d = config == null ? void 0 : config.deleteColIcon) != null ? _d : removeIcon;
10197
+ case "align_col_left":
10198
+ return (_e = config == null ? void 0 : config.alignLeftIcon) != null ? _e : alignLeftIcon;
10199
+ case "align_col_center":
10200
+ return (_f = config == null ? void 0 : config.alignCenterIcon) != null ? _f : alignCenterIcon;
10201
+ case "align_col_right":
10202
+ return (_g = config == null ? void 0 : config.alignRightIcon) != null ? _g : alignRightIcon;
10203
+ case "col_drag_handle":
10204
+ return (_h = config == null ? void 0 : config.colDragHandleIcon) != null ? _h : dragHandleIcon;
10205
+ case "row_drag_handle":
10206
+ return (_i = config == null ? void 0 : config.rowDragHandleIcon) != null ? _i : dragHandleIcon;
10207
+ case "merge_cells":
10208
+ return (_j = config == null ? void 0 : config.mergeCellsIcon) != null ? _j : mergeCellIcon;
10209
+ case "split_cell":
10210
+ return (_k = config == null ? void 0 : config.splitCellIcon) != null ? _k : splitCellIcon;
10007
10211
  }
10008
- };
10212
+ }
10213
+ }));
10214
+ }).use(tableBlock.tableBlock);
10215
+ };
10216
+
10217
+ var __typeError$1 = (msg) => {
10218
+ throw TypeError(msg);
10219
+ };
10220
+ var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Cannot " + msg);
10221
+ var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
10222
+ var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10223
+ var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
10224
+ var _tooltipProvider, _content, _app, _selection, _show, _mousePressed;
10225
+ const toolbarTooltip = tooltip.tooltipFactory("CREPE_TOOLBAR");
10226
+ class ToolbarView {
10227
+ constructor(ctx, view, config) {
10228
+ __privateAdd$1(this, _tooltipProvider);
10229
+ __privateAdd$1(this, _content);
10230
+ __privateAdd$1(this, _app);
10231
+ __privateAdd$1(this, _selection);
10232
+ __privateAdd$1(this, _show, vue.ref(false));
10233
+ __privateAdd$1(this, _mousePressed, false);
10234
+ this.update = (view, prevState) => {
10235
+ __privateGet$1(this, _tooltipProvider).update(view, prevState);
10236
+ __privateGet$1(this, _selection).value = view.state.selection;
10237
+ };
10238
+ this.destroy = () => {
10239
+ __privateGet$1(this, _tooltipProvider).destroy();
10240
+ __privateGet$1(this, _app).unmount();
10241
+ __privateGet$1(this, _content).remove();
10242
+ };
10243
+ this.hide = () => {
10244
+ __privateGet$1(this, _tooltipProvider).hide();
10245
+ };
10246
+ const content = document.createElement("div");
10247
+ content.className = "milkdown-toolbar";
10248
+ __privateSet$1(this, _selection, vue.shallowRef(view.state.selection));
10249
+ const app = vue.createApp(Toolbar, {
10250
+ ctx,
10251
+ hide: this.hide,
10252
+ config,
10253
+ selection: __privateGet$1(this, _selection),
10254
+ show: __privateGet$1(this, _show)
10255
+ });
10256
+ app.mount(content);
10257
+ __privateSet$1(this, _content, content);
10258
+ __privateSet$1(this, _app, app);
10259
+ view.dom.addEventListener("mousedown", () => {
10260
+ __privateSet$1(this, _mousePressed, true);
10261
+ });
10262
+ view.dom.addEventListener("mouseup", () => {
10263
+ __privateSet$1(this, _mousePressed, false);
10264
+ setTimeout(() => {
10265
+ this.update(view);
10266
+ }, 0);
10267
+ });
10268
+ __privateSet$1(this, _tooltipProvider, new tooltip.TooltipProvider({
10269
+ content: __privateGet$1(this, _content),
10270
+ debounce: 20,
10271
+ offset: 10,
10272
+ shouldShow: (view2) => {
10273
+ if (__privateGet$1(this, _mousePressed)) return false;
10274
+ const { doc, selection } = view2.state;
10275
+ const { empty, from, to } = selection;
10276
+ const isEmptyTextBlock = !doc.textBetween(from, to).length && selection instanceof state.TextSelection;
10277
+ const isNotTextBlock = !(selection instanceof state.TextSelection) && !(selection instanceof state.AllSelection);
10278
+ const activeElement = view2.dom.getRootNode().activeElement;
10279
+ const isTooltipChildren = content.contains(activeElement);
10280
+ const notHasFocus = !view2.hasFocus() && !isTooltipChildren;
10281
+ const isReadonly = !view2.editable;
10282
+ if (notHasFocus || isNotTextBlock || empty || isEmptyTextBlock || isReadonly)
10283
+ return false;
10284
+ return true;
10285
+ }
10286
+ }));
10287
+ __privateGet$1(this, _tooltipProvider).onShow = () => {
10288
+ __privateGet$1(this, _show).value = true;
10009
10289
  };
10290
+ __privateGet$1(this, _tooltipProvider).onHide = () => {
10291
+ __privateGet$1(this, _show).value = false;
10292
+ };
10293
+ this.update(view);
10010
10294
  }
10011
- );
10012
-
10013
- const attachment = (editor, config) => {
10014
- editor.config(crepeFeatureConfig(CrepeFeature.Attachment)).config((ctx) => {
10015
- ctx.update(attachmentConfig.key, (value) => {
10016
- var _a, _b, _c, _d;
10295
+ }
10296
+ _tooltipProvider = new WeakMap();
10297
+ _content = new WeakMap();
10298
+ _app = new WeakMap();
10299
+ _selection = new WeakMap();
10300
+ _show = new WeakMap();
10301
+ _mousePressed = new WeakMap();
10302
+ const toolbar = (editor, config) => {
10303
+ editor.config(crepeFeatureConfig(CrepeFeature.Toolbar)).config((ctx) => {
10304
+ ctx.set(toolbarTooltip.key, {
10305
+ view: (view) => new ToolbarView(ctx, view, config)
10306
+ });
10307
+ }).config((ctx) => {
10308
+ ctx.update(core.editorViewOptionsCtx, (prev) => {
10309
+ const prevTransform = prev.transformPastedHTML;
10017
10310
  return {
10018
- uploadButton: (_a = config == null ? void 0 : config.uploadButton) != null ? _a : i18n(ctx, "attachmentBlock.uploadButton"),
10019
- uploadPlaceholderText: (_b = config == null ? void 0 : config.uploadPlaceholderText) != null ? _b : i18n(ctx, "attachmentBlock.uploadPlaceholderText"),
10020
- downloadText: (_c = config == null ? void 0 : config.downloadText) != null ? _c : i18n(ctx, "attachmentBlock.download"),
10021
- onUpload: (_d = config == null ? void 0 : config.onUpload) != null ? _d : value.onUpload
10311
+ ...prev,
10312
+ transformPastedHTML: (html, view) => {
10313
+ if (prevTransform) html = prevTransform(html, view);
10314
+ return stripFontFamilyFromExternalHTML(html);
10315
+ }
10022
10316
  };
10023
10317
  });
10024
- }).use(attachmentConfig).use(attachmentSchema).use(attachmentView);
10318
+ }).use(underline).use(highlightMark).use(colorPlugins).use(fontPlugins).use(toolbarTooltip);
10025
10319
  };
10026
10320
 
10027
10321
  function loadFeature(feature, editor, config) {