@jvs-milkdown/crepe 1.2.5 → 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 +1238 -962
  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 +1251 -975
  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 +22 -12
  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
- }
1681
+ cancelHide: () => {
1350
1682
  },
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
- });
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,197 +8285,69 @@ 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,
7736
8292
  hide: props.hide,
7737
8293
  show: props.show,
7738
8294
  selection: props.selection,
7739
- 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());
8295
+ config: props.config,
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) => {
@@ -8149,11 +8575,179 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8149
8575
  }
8150
8576
  }
8151
8577
  );
8152
- view.dispatch(tr);
8153
- });
8154
- if (result) return;
8155
- }
8156
- });
8578
+ view.dispatch(tr);
8579
+ });
8580
+ if (result) return;
8581
+ }
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({
@@ -8232,13 +8826,13 @@ const DocumentHeader = vue.defineComponent({
8232
8826
  var _a, _b;
8233
8827
  const state = viewState.value;
8234
8828
  if (!state.showTitle && !state.showCover) return null;
8235
- return /* @__PURE__ */ vue.h(
8829
+ return /* @__PURE__ */ h(
8236
8830
  "div",
8237
8831
  {
8238
8832
  class: "milkdown-document-header",
8239
8833
  style: { width: "100%", display: "flex", flexDirection: "column" }
8240
8834
  },
8241
- state.showCover ? /* @__PURE__ */ vue.h(
8835
+ state.showCover ? /* @__PURE__ */ h(
8242
8836
  "div",
8243
8837
  {
8244
8838
  class: "milkdown-document-cover",
@@ -8256,7 +8850,7 @@ const DocumentHeader = vue.defineComponent({
8256
8850
  overflow: "hidden"
8257
8851
  }
8258
8852
  },
8259
- /* @__PURE__ */ vue.h(
8853
+ /* @__PURE__ */ h(
8260
8854
  "img",
8261
8855
  {
8262
8856
  src: state.coverUrl,
@@ -8269,7 +8863,7 @@ const DocumentHeader = vue.defineComponent({
8269
8863
  }
8270
8864
  }
8271
8865
  ),
8272
- /* @__PURE__ */ vue.h(
8866
+ /* @__PURE__ */ h(
8273
8867
  "div",
8274
8868
  {
8275
8869
  style: {
@@ -8286,7 +8880,7 @@ const DocumentHeader = vue.defineComponent({
8286
8880
  background: "linear-gradient(transparent, rgba(0,0,0,0.7))"
8287
8881
  }
8288
8882
  },
8289
- /* @__PURE__ */ vue.h(
8883
+ /* @__PURE__ */ h(
8290
8884
  "div",
8291
8885
  {
8292
8886
  style: {
@@ -8298,7 +8892,7 @@ const DocumentHeader = vue.defineComponent({
8298
8892
  },
8299
8893
  (lastUploadedUrl.value ? [lastUploadedUrl.value] : []).concat(
8300
8894
  ((_b = (_a = props.config) == null ? void 0 : _a.defaultCoverImages) == null ? void 0 : _b.length) ? props.config.defaultCoverImages : builtInCoverImages
8301
- ).map((src, i) => /* @__PURE__ */ vue.h(
8895
+ ).map((src, i) => /* @__PURE__ */ h(
8302
8896
  "img",
8303
8897
  {
8304
8898
  key: i,
@@ -8328,7 +8922,7 @@ const DocumentHeader = vue.defineComponent({
8328
8922
  }
8329
8923
  ))
8330
8924
  ),
8331
- /* @__PURE__ */ vue.h(
8925
+ /* @__PURE__ */ h(
8332
8926
  "div",
8333
8927
  {
8334
8928
  onClick: () => {
@@ -8356,7 +8950,7 @@ const DocumentHeader = vue.defineComponent({
8356
8950
  e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.2)";
8357
8951
  }
8358
8952
  },
8359
- /* @__PURE__ */ vue.h(
8953
+ /* @__PURE__ */ h(
8360
8954
  "svg",
8361
8955
  {
8362
8956
  width: "14",
@@ -8368,14 +8962,14 @@ const DocumentHeader = vue.defineComponent({
8368
8962
  "stroke-linecap": "round",
8369
8963
  "stroke-linejoin": "round"
8370
8964
  },
8371
- /* @__PURE__ */ vue.h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
8372
- /* @__PURE__ */ vue.h("polyline", { points: "17 8 12 3 7 8" }),
8373
- /* @__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" })
8374
8968
  ),
8375
8969
  "\u4E0A\u4F20"
8376
8970
  )
8377
8971
  ),
8378
- /* @__PURE__ */ vue.h(
8972
+ /* @__PURE__ */ h(
8379
8973
  "input",
8380
8974
  {
8381
8975
  type: "file",
@@ -8386,7 +8980,7 @@ const DocumentHeader = vue.defineComponent({
8386
8980
  }
8387
8981
  )
8388
8982
  ) : null,
8389
- state.showTitle ? /* @__PURE__ */ vue.h(
8983
+ state.showTitle ? /* @__PURE__ */ h(
8390
8984
  "div",
8391
8985
  {
8392
8986
  class: "milkdown-document-title-wrapper",
@@ -8397,8 +8991,8 @@ const DocumentHeader = vue.defineComponent({
8397
8991
  padding: `40px ${editorWidthMap[state.editorWidth] === "none" ? "80px" : "0"} 0`
8398
8992
  }
8399
8993
  },
8400
- /* @__PURE__ */ vue.h("style", null, `.milkdown-document-title::placeholder { color: #BFBFBF; }`),
8401
- /* @__PURE__ */ vue.h(
8994
+ /* @__PURE__ */ h("style", null, `.milkdown-document-title::placeholder { color: #BFBFBF; }`),
8995
+ /* @__PURE__ */ h(
8402
8996
  "textarea",
8403
8997
  {
8404
8998
  ref: titleTextareaRef,
@@ -8616,7 +9210,7 @@ const OutlinePanel = vue.defineComponent({
8616
9210
  const state = viewState.value;
8617
9211
  if (!state.outlineVisible) return null;
8618
9212
  const isLeft = state.outlinePosition === "left";
8619
- return /* @__PURE__ */ vue.h(
9213
+ return /* @__PURE__ */ h(
8620
9214
  "div",
8621
9215
  {
8622
9216
  class: "milkdown-outline-panel",
@@ -8637,7 +9231,7 @@ const OutlinePanel = vue.defineComponent({
8637
9231
  overflow: "hidden"
8638
9232
  }
8639
9233
  },
8640
- /* @__PURE__ */ vue.h(
9234
+ /* @__PURE__ */ h(
8641
9235
  "div",
8642
9236
  {
8643
9237
  style: {
@@ -8651,8 +9245,8 @@ const OutlinePanel = vue.defineComponent({
8651
9245
  alignItems: "center"
8652
9246
  }
8653
9247
  },
8654
- /* @__PURE__ */ vue.h("span", null, i18n(props.ctx, "view.outline")),
8655
- /* @__PURE__ */ vue.h(
9248
+ /* @__PURE__ */ h("span", null, i18n(props.ctx, "view.outline")),
9249
+ /* @__PURE__ */ h(
8656
9250
  "div",
8657
9251
  {
8658
9252
  style: {
@@ -8676,7 +9270,7 @@ const OutlinePanel = vue.defineComponent({
8676
9270
  },
8677
9271
  title: "\u5173\u95ED\u5927\u7EB2"
8678
9272
  },
8679
- /* @__PURE__ */ vue.h(
9273
+ /* @__PURE__ */ h(
8680
9274
  "svg",
8681
9275
  {
8682
9276
  width: "16",
@@ -8688,12 +9282,12 @@ const OutlinePanel = vue.defineComponent({
8688
9282
  "stroke-linecap": "round",
8689
9283
  "stroke-linejoin": "round"
8690
9284
  },
8691
- /* @__PURE__ */ vue.h("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
8692
- /* @__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" })
8693
9287
  )
8694
9288
  )
8695
9289
  ),
8696
- /* @__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(
8697
9291
  "div",
8698
9292
  {
8699
9293
  style: {
@@ -8706,7 +9300,7 @@ const OutlinePanel = vue.defineComponent({
8706
9300
  ) : null, visibleItems.value.map(({ item, hasChildren: hasKids }) => {
8707
9301
  const isActive = activeId.value === item.id;
8708
9302
  const collapsed = collapsedIds.value.has(item.id);
8709
- return /* @__PURE__ */ vue.h(
9303
+ return /* @__PURE__ */ h(
8710
9304
  "div",
8711
9305
  {
8712
9306
  key: item.id,
@@ -8739,7 +9333,7 @@ const OutlinePanel = vue.defineComponent({
8739
9333
  }
8740
9334
  }
8741
9335
  },
8742
- /* @__PURE__ */ vue.h(
9336
+ /* @__PURE__ */ h(
8743
9337
  "span",
8744
9338
  {
8745
9339
  onClick: (e) => {
@@ -8769,9 +9363,10 @@ const OutlinePanel = vue.defineComponent({
8769
9363
  e.currentTarget.style.backgroundColor = "transparent";
8770
9364
  }
8771
9365
  },
8772
- "\u25BC"
9366
+ "\uFFFD?",
9367
+ " "
8773
9368
  ),
8774
- /* @__PURE__ */ vue.h(
9369
+ /* @__PURE__ */ h(
8775
9370
  "span",
8776
9371
  {
8777
9372
  title: item.text,
@@ -8784,7 +9379,7 @@ const OutlinePanel = vue.defineComponent({
8784
9379
  )
8785
9380
  );
8786
9381
  })),
8787
- /* @__PURE__ */ vue.h(
9382
+ /* @__PURE__ */ h(
8788
9383
  "div",
8789
9384
  {
8790
9385
  onPointerdown: onPointerDown,
@@ -9495,551 +10090,232 @@ const linkTooltip = (editor, config) => {
9495
10090
  editor.config(crepeFeatureConfig(CrepeFeature.LinkTooltip)).config(linkTooltip$1.configureLinkTooltip).config((ctx) => {
9496
10091
  ctx.update(linkTooltip$1.linkTooltipConfig.key, (prev) => {
9497
10092
  var _a, _b, _c, _d, _e, _f;
9498
- return {
9499
- ...prev,
9500
- linkIcon: (_a = config == null ? void 0 : config.linkIcon) != null ? _a : copyIcon,
9501
- editButton: (_b = config == null ? void 0 : config.editButton) != null ? _b : editIcon,
9502
- removeButton: (_c = config == null ? void 0 : config.removeButton) != null ? _c : removeIcon,
9503
- confirmButton: (_d = config == null ? void 0 : config.confirmButton) != null ? _d : confirmIcon,
9504
- inputPlaceholder: (_e = config == null ? void 0 : config.inputPlaceholder) != null ? _e : i18n(ctx, "linkTooltip.pasteLink"),
9505
- onCopyLink: (_f = config == null ? void 0 : config.onCopyLink) != null ? _f : (() => {
9506
- })
9507
- };
9508
- });
9509
- }).use(linkTooltip$1.linkTooltipPlugin);
9510
- };
9511
-
9512
- function configureListItem(ctx, config) {
9513
- ctx.set(listItemBlock.listItemBlockConfig.key, {
9514
- renderLabel: ({ label, listType, checked }) => {
9515
- var _a, _b, _c;
9516
- if (checked == null) {
9517
- if (listType === "bullet") return (_a = config == null ? void 0 : config.bulletIcon) != null ? _a : bulletIcon;
9518
- return label;
9519
- }
9520
- if (checked) return (_b = config == null ? void 0 : config.checkBoxCheckedIcon) != null ? _b : checkBoxCheckedIcon;
9521
- return (_c = config == null ? void 0 : config.checkBoxUncheckedIcon) != null ? _c : checkBoxUncheckedIcon;
9522
- }
9523
- });
9524
- }
9525
- const listItem = (editor, config) => {
9526
- editor.config(crepeFeatureConfig(CrepeFeature.ListItem)).config((ctx) => configureListItem(ctx, config)).use(listItemBlock.listItemBlockComponent);
9527
- };
9528
-
9529
- function isDocEmpty(doc) {
9530
- var _a;
9531
- return doc.childCount <= 1 && !((_a = doc.firstChild) == null ? void 0 : _a.content.size);
9532
- }
9533
- function createPlaceholderDecoration(state, placeholderText) {
9534
- const { selection } = state;
9535
- if (!selection.empty) return null;
9536
- const $pos = selection.$anchor;
9537
- const node = $pos.parent;
9538
- if (node.content.size > 0) return null;
9539
- const inTable = prose.findParent((node2) => node2.type.name === "table")($pos);
9540
- if (inTable) return null;
9541
- const before = $pos.before();
9542
- return view$1.Decoration.node(before, before + node.nodeSize, {
9543
- class: "crepe-placeholder",
9544
- "data-placeholder": placeholderText
9545
- });
9546
- }
9547
- const placeholderConfig = utils.$ctx(
9548
- {
9549
- mode: "doc"
9550
- },
9551
- "placeholderConfigCtx"
9552
- );
9553
- const placeholderPlugin = utils.$prose((ctx) => {
9554
- return new state.Plugin({
9555
- key: new state.PluginKey("CREPE_PLACEHOLDER"),
9556
- props: {
9557
- decorations: (state) => {
9558
- var _a;
9559
- const crepe = useCrepe(ctx);
9560
- if (crepe.readonly) return view$1.DecorationSet.empty;
9561
- const config = ctx.get(placeholderConfig.key);
9562
- if (config.mode === "doc" && !isDocEmpty(state.doc)) return view$1.DecorationSet.empty;
9563
- if (isInCodeBlock(state.selection) || isInList(state.selection))
9564
- return view$1.DecorationSet.empty;
9565
- const placeholderText = (_a = config.text) != null ? _a : i18n(ctx, "placeholder.text");
9566
- const deco = createPlaceholderDecoration(state, placeholderText);
9567
- if (!deco) return view$1.DecorationSet.empty;
9568
- return view$1.DecorationSet.create(state.doc, [deco]);
9569
- }
9570
- }
9571
- });
9572
- });
9573
- const placeholder = (editor, config) => {
9574
- editor.config(crepeFeatureConfig(CrepeFeature.Placeholder)).config((ctx) => {
9575
- if (config) {
9576
- ctx.update(placeholderConfig.key, (prev) => {
9577
- return {
9578
- ...prev,
9579
- ...config
9580
- };
9581
- });
9582
- }
9583
- }).use(placeholderPlugin).use(placeholderConfig);
9584
- };
9585
-
9586
- const table = (editor, config) => {
9587
- editor.config(crepeFeatureConfig(CrepeFeature.Table)).config((ctx) => {
9588
- ctx.update(tableBlock.tableBlockConfig.key, (defaultConfig) => ({
9589
- ...defaultConfig,
9590
- renderButton: (renderType) => {
9591
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9592
- switch (renderType) {
9593
- case "add_row":
9594
- return (_a = config == null ? void 0 : config.addRowIcon) != null ? _a : plusIcon;
9595
- case "add_col":
9596
- return (_b = config == null ? void 0 : config.addColIcon) != null ? _b : plusIcon;
9597
- case "delete_row":
9598
- return (_c = config == null ? void 0 : config.deleteRowIcon) != null ? _c : removeIcon;
9599
- case "delete_col":
9600
- return (_d = config == null ? void 0 : config.deleteColIcon) != null ? _d : removeIcon;
9601
- case "align_col_left":
9602
- return (_e = config == null ? void 0 : config.alignLeftIcon) != null ? _e : alignLeftIcon;
9603
- case "align_col_center":
9604
- return (_f = config == null ? void 0 : config.alignCenterIcon) != null ? _f : alignCenterIcon;
9605
- case "align_col_right":
9606
- return (_g = config == null ? void 0 : config.alignRightIcon) != null ? _g : alignRightIcon;
9607
- case "col_drag_handle":
9608
- return (_h = config == null ? void 0 : config.colDragHandleIcon) != null ? _h : dragHandleIcon;
9609
- case "row_drag_handle":
9610
- return (_i = config == null ? void 0 : config.rowDragHandleIcon) != null ? _i : dragHandleIcon;
9611
- case "merge_cells":
9612
- return (_j = config == null ? void 0 : config.mergeCellsIcon) != null ? _j : mergeCellIcon;
9613
- case "split_cell":
9614
- return (_k = config == null ? void 0 : config.splitCellIcon) != null ? _k : splitCellIcon;
9615
- }
9616
- }
9617
- }));
9618
- }).use(tableBlock.tableBlock);
9619
- };
9620
-
9621
- var __typeError$1 = (msg) => {
9622
- throw TypeError(msg);
9623
- };
9624
- var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Cannot " + msg);
9625
- var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9626
- 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);
9627
- var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
9628
- var _tooltipProvider, _content, _app, _selection, _show, _mousePressed;
9629
- const toolbarTooltip = tooltip.tooltipFactory("CREPE_TOOLBAR");
9630
- class ToolbarView {
9631
- constructor(ctx, view, config) {
9632
- __privateAdd$1(this, _tooltipProvider);
9633
- __privateAdd$1(this, _content);
9634
- __privateAdd$1(this, _app);
9635
- __privateAdd$1(this, _selection);
9636
- __privateAdd$1(this, _show, vue.ref(false));
9637
- __privateAdd$1(this, _mousePressed, false);
9638
- this.update = (view, prevState) => {
9639
- __privateGet$1(this, _tooltipProvider).update(view, prevState);
9640
- __privateGet$1(this, _selection).value = view.state.selection;
9641
- };
9642
- this.destroy = () => {
9643
- __privateGet$1(this, _tooltipProvider).destroy();
9644
- __privateGet$1(this, _app).unmount();
9645
- __privateGet$1(this, _content).remove();
9646
- };
9647
- this.hide = () => {
9648
- __privateGet$1(this, _tooltipProvider).hide();
9649
- };
9650
- const content = document.createElement("div");
9651
- content.className = "milkdown-toolbar";
9652
- __privateSet$1(this, _selection, vue.shallowRef(view.state.selection));
9653
- const app = vue.createApp(Toolbar, {
9654
- ctx,
9655
- hide: this.hide,
9656
- config,
9657
- selection: __privateGet$1(this, _selection),
9658
- show: __privateGet$1(this, _show)
9659
- });
9660
- app.mount(content);
9661
- __privateSet$1(this, _content, content);
9662
- __privateSet$1(this, _app, app);
9663
- view.dom.addEventListener("mousedown", () => {
9664
- __privateSet$1(this, _mousePressed, true);
9665
- });
9666
- view.dom.addEventListener("mouseup", () => {
9667
- __privateSet$1(this, _mousePressed, false);
9668
- setTimeout(() => {
9669
- this.update(view);
9670
- }, 0);
9671
- });
9672
- __privateSet$1(this, _tooltipProvider, new tooltip.TooltipProvider({
9673
- content: __privateGet$1(this, _content),
9674
- debounce: 20,
9675
- offset: 10,
9676
- shouldShow: (view2) => {
9677
- if (__privateGet$1(this, _mousePressed)) return false;
9678
- const { doc, selection } = view2.state;
9679
- const { empty, from, to } = selection;
9680
- const isEmptyTextBlock = !doc.textBetween(from, to).length && selection instanceof state.TextSelection;
9681
- const isNotTextBlock = !(selection instanceof state.TextSelection) && !(selection instanceof state.AllSelection);
9682
- const activeElement = view2.dom.getRootNode().activeElement;
9683
- const isTooltipChildren = content.contains(activeElement);
9684
- const notHasFocus = !view2.hasFocus() && !isTooltipChildren;
9685
- const isReadonly = !view2.editable;
9686
- if (notHasFocus || isNotTextBlock || empty || isEmptyTextBlock || isReadonly)
9687
- return false;
9688
- return true;
9689
- }
9690
- }));
9691
- __privateGet$1(this, _tooltipProvider).onShow = () => {
9692
- __privateGet$1(this, _show).value = true;
9693
- };
9694
- __privateGet$1(this, _tooltipProvider).onHide = () => {
9695
- __privateGet$1(this, _show).value = false;
9696
- };
9697
- this.update(view);
9698
- }
9699
- }
9700
- _tooltipProvider = new WeakMap();
9701
- _content = new WeakMap();
9702
- _app = new WeakMap();
9703
- _selection = new WeakMap();
9704
- _show = new WeakMap();
9705
- _mousePressed = new WeakMap();
9706
- const toolbar = (editor, config) => {
9707
- editor.config(crepeFeatureConfig(CrepeFeature.Toolbar)).config((ctx) => {
9708
- ctx.set(toolbarTooltip.key, {
9709
- view: (view) => new ToolbarView(ctx, view, config)
9710
- });
9711
- }).config((ctx) => {
9712
- ctx.update(core.editorViewOptionsCtx, (prev) => {
9713
- const prevTransform = prev.transformPastedHTML;
9714
- return {
9715
- ...prev,
9716
- transformPastedHTML: (html, view) => {
9717
- if (prevTransform) html = prevTransform(html, view);
9718
- return stripFontFamilyFromExternalHTML(html);
9719
- }
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
+ })
9720
10102
  };
9721
10103
  });
9722
- }).use(underline).use(highlightMark).use(colorPlugins).use(fontPlugins).use(toolbarTooltip);
10104
+ }).use(linkTooltip$1.linkTooltipPlugin);
9723
10105
  };
9724
10106
 
9725
- const attachmentConfig = utils.$ctx(
9726
- {
9727
- onUpload: async (file) => {
9728
- return {
9729
- url: URL.createObjectURL(file),
9730
- name: file.name,
9731
- size: file.size
9732
- };
9733
- },
9734
- uploadButton: "Upload file",
9735
- uploadPlaceholderText: "or paste link",
9736
- downloadText: "Download"
9737
- },
9738
- "attachmentConfig"
9739
- );
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
+ };
9740
10123
 
9741
- const downloadIcon = `<svg viewBox="0 0 1024 1024" width="20" height="20" fill="currentColor">
9742
- <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>
9743
- </svg>`;
9744
- function formatBytes(bytes, decimals = 2) {
9745
- if (!+bytes) return "0 Bytes";
9746
- const k = 1024;
9747
- const dm = decimals < 0 ? 0 : decimals;
9748
- const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
9749
- const i = Math.floor(Math.log(bytes) / Math.log(k));
9750
- 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);
9751
10127
  }
9752
- const MilkdownAttachmentBlock = vue.defineComponent({
9753
- props: {
9754
- src: { type: Object, required: true },
9755
- name: { type: Object, required: true },
9756
- size: { type: Object, required: true },
9757
- videoWidth: { type: Object, required: true },
9758
- selected: { type: Object, required: true },
9759
- readonly: { type: Object, required: true },
9760
- setAttr: { type: Function, required: true },
9761
- 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"
9762
10145
  },
9763
- setup(props) {
9764
- const { src, name, size, videoWidth } = props;
9765
- const isUploading = vue.shallowRef(false);
9766
- const fileInput = vue.shallowRef(null);
9767
- const videoWrapperRef = vue.ref(null);
9768
- const currentWidth = vue.ref(0);
9769
- const isResizing = vue.ref(false);
9770
- const isVideo = vue.computed(() => {
9771
- return name.value && /\.(mp4|webm|ogg|mov|avi|mkv|flv|wmv|m4v|3gp|ts)$/i.test(name.value);
9772
- });
9773
- let resizeDir = "";
9774
- let startX = 0;
9775
- let startWidth = 0;
9776
- const triggerUpload = () => {
9777
- var _a;
9778
- (_a = fileInput.value) == null ? void 0 : _a.click();
9779
- };
9780
- const onFileChange = async (e) => {
9781
- var _a;
9782
- const target = e.target;
9783
- const file = (_a = target.files) == null ? void 0 : _a[0];
9784
- if (!file) return;
9785
- isUploading.value = true;
9786
- try {
9787
- const result = await props.config.onUpload(file);
9788
- props.setAttr("src", result.url);
9789
- props.setAttr("name", result.name);
9790
- props.setAttr("size", result.size);
9791
- } catch (err) {
9792
- console.error("Failed to upload file", err);
9793
- } finally {
9794
- isUploading.value = false;
9795
- target.value = "";
9796
- }
9797
- };
9798
- const openLink = () => {
9799
- if (src.value) {
9800
- window.open(src.value, "_blank");
9801
- }
9802
- };
9803
- let activeHandle = null;
9804
- const onResizePointerMove = (e) => {
9805
- e.preventDefault();
9806
- const deltaX = e.clientX - startX;
9807
- let dw = 0;
9808
- if (resizeDir.includes("right")) {
9809
- dw = deltaX;
9810
- } else if (resizeDir.includes("left")) {
9811
- dw = -deltaX;
9812
- }
9813
- let newWidth = startWidth + dw;
9814
- if (newWidth < 200) newWidth = 200;
9815
- const wrapper = videoWrapperRef.value;
9816
- if (wrapper) {
9817
- const parent = wrapper.closest(".milkdown-attachment-block-wrapper");
9818
- if (parent) {
9819
- const maxWidth = parent.getBoundingClientRect().width;
9820
- if (newWidth > maxWidth) newWidth = maxWidth;
9821
- }
9822
- }
9823
- currentWidth.value = newWidth;
9824
- };
9825
- const onResizePointerUp = (e) => {
9826
- if (activeHandle) {
9827
- activeHandle.releasePointerCapture(e.pointerId);
9828
- activeHandle.removeEventListener(
9829
- "pointermove",
9830
- onResizePointerMove
9831
- );
9832
- activeHandle.removeEventListener(
9833
- "pointerup",
9834
- onResizePointerUp
9835
- );
9836
- activeHandle = null;
9837
- }
9838
- isResizing.value = false;
9839
- if (currentWidth.value > 0) {
9840
- props.setAttr("videoWidth", Math.round(currentWidth.value));
9841
- }
9842
- };
9843
- const onResizePointerDown = (e, dir) => {
9844
- if (props.readonly.value) return;
9845
- e.preventDefault();
9846
- e.stopPropagation();
9847
- resizeDir = dir;
9848
- startX = e.clientX;
9849
- isResizing.value = true;
9850
- const handle = e.currentTarget;
9851
- activeHandle = handle;
9852
- handle.setPointerCapture(e.pointerId);
9853
- const wrapper = videoWrapperRef.value;
9854
- if (wrapper) {
9855
- startWidth = wrapper.getBoundingClientRect().width;
9856
- currentWidth.value = startWidth;
9857
- }
9858
- handle.addEventListener("pointermove", onResizePointerMove);
9859
- handle.addEventListener("pointerup", onResizePointerUp);
9860
- };
9861
- return () => {
9862
- var _a;
9863
- if (!((_a = src.value) == null ? void 0 : _a.length)) {
9864
- return /* @__PURE__ */ vue.h(
9865
- "div",
9866
- {
9867
- class: [
9868
- "milkdown-attachment-placeholder",
9869
- props.selected.value ? "selected" : ""
9870
- ]
9871
- },
9872
- /* @__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(
9873
- "input",
9874
- {
9875
- type: "file",
9876
- ref: fileInput,
9877
- onChange: onFileChange,
9878
- style: "display: none;"
9879
- }
9880
- ))
9881
- );
9882
- }
9883
- if (isVideo.value) {
9884
- const savedWidth = videoWidth.value;
9885
- const widthStyle = isResizing.value && currentWidth.value > 0 ? `${currentWidth.value}px` : savedWidth && savedWidth > 0 ? `${savedWidth}px` : "100%";
9886
- return /* @__PURE__ */ vue.h(
9887
- "div",
9888
- {
9889
- ref: videoWrapperRef,
9890
- class: [
9891
- "milkdown-attachment-video-viewer",
9892
- props.selected.value ? "selected" : ""
9893
- ],
9894
- style: {
9895
- width: widthStyle,
9896
- margin: "0 auto",
9897
- position: "relative"
9898
- }
9899
- },
9900
- /* @__PURE__ */ vue.h(
9901
- "video",
9902
- {
9903
- src: src.value,
9904
- controls: true,
9905
- style: "width: 100%; display: block; border-radius: 8px;",
9906
- onMousedown: (e) => e.stopPropagation()
9907
- }
9908
- ),
9909
- /* @__PURE__ */ vue.h(
9910
- "div",
9911
- {
9912
- class: "video-resize-handle top-left",
9913
- onPointerdown: (e) => onResizePointerDown(e, "top-left")
9914
- }
9915
- ),
9916
- /* @__PURE__ */ vue.h(
9917
- "div",
9918
- {
9919
- class: "video-resize-handle top-right",
9920
- onPointerdown: (e) => onResizePointerDown(e, "top-right")
9921
- }
9922
- ),
9923
- /* @__PURE__ */ vue.h(
9924
- "div",
9925
- {
9926
- class: "video-resize-handle bottom-left",
9927
- onPointerdown: (e) => onResizePointerDown(e, "bottom-left")
9928
- }
9929
- ),
9930
- /* @__PURE__ */ vue.h(
9931
- "div",
9932
- {
9933
- class: "video-resize-handle bottom-right",
9934
- onPointerdown: (e) => onResizePointerDown(e, "bottom-right")
9935
- }
9936
- )
9937
- );
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]);
9938
10165
  }
9939
- return /* @__PURE__ */ vue.h(
9940
- "div",
9941
- {
9942
- class: [
9943
- "milkdown-attachment-viewer",
9944
- props.selected.value ? "selected" : ""
9945
- ]
9946
- },
9947
- /* @__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 }))),
9948
- /* @__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) : "")),
9949
- /* @__PURE__ */ vue.h(
9950
- "div",
9951
- {
9952
- class: "milkdown-attachment-action",
9953
- onClick: openLink,
9954
- title: props.config.downloadText
9955
- },
9956
- /* @__PURE__ */ vue.h(component.Icon, { icon: downloadIcon })
9957
- )
9958
- );
9959
- };
9960
- }
10166
+ }
10167
+ });
9961
10168
  });
9962
-
9963
- const attachmentView = utils.$view(
9964
- attachmentSchema.node,
9965
- (ctx) => {
9966
- return (initialNode, view, getPos) => {
9967
- const src = vue.ref(initialNode.attrs.src);
9968
- const name = vue.ref(initialNode.attrs.name);
9969
- const size = vue.ref(initialNode.attrs.size);
9970
- const videoWidth = vue.ref(initialNode.attrs.videoWidth);
9971
- const selected = vue.ref(false);
9972
- const readonly = vue.ref(!view.editable);
9973
- const setAttr = (attr, value) => {
9974
- if (!view.editable) return;
9975
- const pos = getPos();
9976
- if (pos == null) return;
9977
- view.dispatch(view.state.tr.setNodeAttribute(pos, attr, value));
9978
- };
9979
- const config = ctx.get(attachmentConfig.key);
9980
- const app = vue.createApp(MilkdownAttachmentBlock, {
9981
- src,
9982
- name,
9983
- size,
9984
- videoWidth,
9985
- selected,
9986
- readonly,
9987
- setAttr,
9988
- config
9989
- });
9990
- const dom = document.createElement("div");
9991
- dom.className = "milkdown-attachment-block-wrapper";
9992
- const disposeSelectedWatcher = vue.watchEffect(() => {
9993
- if (selected.value) {
9994
- dom.classList.add("selected");
9995
- } else {
9996
- dom.classList.remove("selected");
9997
- }
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
+ };
9998
10177
  });
9999
- const bindAttrs = (node) => {
10000
- src.value = node.attrs.src;
10001
- name.value = node.attrs.name;
10002
- size.value = node.attrs.size;
10003
- videoWidth.value = node.attrs.videoWidth;
10004
- readonly.value = !view.editable;
10005
- };
10006
- bindAttrs(initialNode);
10007
- app.mount(dom);
10008
- return {
10009
- dom,
10010
- update: (updatedNode) => {
10011
- if (updatedNode.type !== initialNode.type) return false;
10012
- bindAttrs(updatedNode);
10013
- return true;
10014
- },
10015
- selectNode: () => {
10016
- selected.value = true;
10017
- },
10018
- deselectNode: () => {
10019
- selected.value = false;
10020
- },
10021
- destroy: () => {
10022
- disposeSelectedWatcher();
10023
- app.unmount();
10024
- 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;
10025
10211
  }
10026
- };
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;
10027
10289
  };
10290
+ __privateGet$1(this, _tooltipProvider).onHide = () => {
10291
+ __privateGet$1(this, _show).value = false;
10292
+ };
10293
+ this.update(view);
10028
10294
  }
10029
- );
10030
-
10031
- const attachment = (editor, config) => {
10032
- editor.config(crepeFeatureConfig(CrepeFeature.Attachment)).config((ctx) => {
10033
- ctx.update(attachmentConfig.key, (value) => {
10034
- 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;
10035
10310
  return {
10036
- uploadButton: (_a = config == null ? void 0 : config.uploadButton) != null ? _a : i18n(ctx, "attachmentBlock.uploadButton"),
10037
- uploadPlaceholderText: (_b = config == null ? void 0 : config.uploadPlaceholderText) != null ? _b : i18n(ctx, "attachmentBlock.uploadPlaceholderText"),
10038
- downloadText: (_c = config == null ? void 0 : config.downloadText) != null ? _c : i18n(ctx, "attachmentBlock.download"),
10039
- 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
+ }
10040
10316
  };
10041
10317
  });
10042
- }).use(attachmentConfig).use(attachmentSchema).use(attachmentView);
10318
+ }).use(underline).use(highlightMark).use(colorPlugins).use(fontPlugins).use(toolbarTooltip);
10043
10319
  };
10044
10320
 
10045
10321
  function loadFeature(feature, editor, config) {