@jvs-milkdown/crepe 1.2.16 → 1.2.18

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 (93) hide show
  1. package/lib/cjs/builder.js +4 -0
  2. package/lib/cjs/builder.js.map +1 -1
  3. package/lib/cjs/feature/block-edit/index.js +39 -16
  4. package/lib/cjs/feature/block-edit/index.js.map +1 -1
  5. package/lib/cjs/feature/code-mirror/index.js +4 -0
  6. package/lib/cjs/feature/code-mirror/index.js.map +1 -1
  7. package/lib/cjs/feature/cursor/index.js +4 -0
  8. package/lib/cjs/feature/cursor/index.js.map +1 -1
  9. package/lib/cjs/feature/image-block/index.js +4 -0
  10. package/lib/cjs/feature/image-block/index.js.map +1 -1
  11. package/lib/cjs/feature/inline-diff/index.js +4 -0
  12. package/lib/cjs/feature/inline-diff/index.js.map +1 -1
  13. package/lib/cjs/feature/latex/index.js +4 -0
  14. package/lib/cjs/feature/latex/index.js.map +1 -1
  15. package/lib/cjs/feature/link-tooltip/index.js +4 -0
  16. package/lib/cjs/feature/link-tooltip/index.js.map +1 -1
  17. package/lib/cjs/feature/list-item/index.js +4 -0
  18. package/lib/cjs/feature/list-item/index.js.map +1 -1
  19. package/lib/cjs/feature/placeholder/index.js +4 -0
  20. package/lib/cjs/feature/placeholder/index.js.map +1 -1
  21. package/lib/cjs/feature/table/index.js +4 -0
  22. package/lib/cjs/feature/table/index.js.map +1 -1
  23. package/lib/cjs/feature/toolbar/index.js +56 -18
  24. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  25. package/lib/cjs/index.js +604 -135
  26. package/lib/cjs/index.js.map +1 -1
  27. package/lib/esm/builder.js +4 -0
  28. package/lib/esm/builder.js.map +1 -1
  29. package/lib/esm/feature/block-edit/index.js +40 -17
  30. package/lib/esm/feature/block-edit/index.js.map +1 -1
  31. package/lib/esm/feature/code-mirror/index.js +4 -0
  32. package/lib/esm/feature/code-mirror/index.js.map +1 -1
  33. package/lib/esm/feature/cursor/index.js +4 -0
  34. package/lib/esm/feature/cursor/index.js.map +1 -1
  35. package/lib/esm/feature/image-block/index.js +4 -0
  36. package/lib/esm/feature/image-block/index.js.map +1 -1
  37. package/lib/esm/feature/inline-diff/index.js +4 -0
  38. package/lib/esm/feature/inline-diff/index.js.map +1 -1
  39. package/lib/esm/feature/latex/index.js +4 -0
  40. package/lib/esm/feature/latex/index.js.map +1 -1
  41. package/lib/esm/feature/link-tooltip/index.js +4 -0
  42. package/lib/esm/feature/link-tooltip/index.js.map +1 -1
  43. package/lib/esm/feature/list-item/index.js +4 -0
  44. package/lib/esm/feature/list-item/index.js.map +1 -1
  45. package/lib/esm/feature/placeholder/index.js +4 -0
  46. package/lib/esm/feature/placeholder/index.js.map +1 -1
  47. package/lib/esm/feature/table/index.js +4 -0
  48. package/lib/esm/feature/table/index.js.map +1 -1
  49. package/lib/esm/feature/toolbar/index.js +57 -19
  50. package/lib/esm/feature/toolbar/index.js.map +1 -1
  51. package/lib/esm/index.js +604 -135
  52. package/lib/esm/index.js.map +1 -1
  53. package/lib/theme/common/toolbar.css +6 -0
  54. package/lib/tsconfig.tsbuildinfo +1 -1
  55. package/lib/types/core/crepe.d.ts +1 -1
  56. package/lib/types/core/crepe.d.ts.map +1 -1
  57. package/lib/types/core/locale.d.ts +4 -0
  58. package/lib/types/core/locale.d.ts.map +1 -1
  59. package/lib/types/feature/block-edit/menu/component.d.ts.map +1 -1
  60. package/lib/types/feature/fixed-toolbar/component.d.ts +2 -0
  61. package/lib/types/feature/fixed-toolbar/component.d.ts.map +1 -1
  62. package/lib/types/feature/fixed-toolbar/config.d.ts.map +1 -1
  63. package/lib/types/feature/fixed-toolbar/index.d.ts +16 -0
  64. package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
  65. package/lib/types/feature/fixed-toolbar/menu-bar.d.ts.map +1 -1
  66. package/lib/types/feature/fixed-toolbar/outline-panel.d.ts.map +1 -1
  67. package/lib/types/feature/toolbar/component.d.ts.map +1 -1
  68. package/lib/types/icons/export.d.ts +2 -0
  69. package/lib/types/icons/export.d.ts.map +1 -0
  70. package/lib/types/icons/import.d.ts +2 -0
  71. package/lib/types/icons/import.d.ts.map +1 -0
  72. package/lib/types/icons/index.d.ts +4 -0
  73. package/lib/types/icons/index.d.ts.map +1 -1
  74. package/lib/types/icons/redo.d.ts +2 -0
  75. package/lib/types/icons/redo.d.ts.map +1 -0
  76. package/lib/types/icons/undo.d.ts +2 -0
  77. package/lib/types/icons/undo.d.ts.map +1 -0
  78. package/package.json +4 -4
  79. package/src/core/crepe.ts +60 -7
  80. package/src/core/locale.ts +4 -0
  81. package/src/feature/block-edit/menu/component.tsx +41 -17
  82. package/src/feature/fixed-toolbar/component.tsx +155 -51
  83. package/src/feature/fixed-toolbar/config.ts +70 -2
  84. package/src/feature/fixed-toolbar/index.ts +86 -1
  85. package/src/feature/fixed-toolbar/menu-bar.tsx +18 -3
  86. package/src/feature/fixed-toolbar/outline-panel.tsx +219 -32
  87. package/src/feature/toolbar/component.tsx +25 -2
  88. package/src/icons/export.ts +5 -0
  89. package/src/icons/import.ts +6 -0
  90. package/src/icons/index.ts +4 -0
  91. package/src/icons/redo.ts +5 -0
  92. package/src/icons/undo.ts +5 -0
  93. package/src/theme/common/toolbar.css +16 -0
package/lib/cjs/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var utils$1 = require('@jvs-milkdown/utils');
3
4
  var lodashEs = require('lodash-es');
4
5
  var languageData = require('@codemirror/language-data');
5
6
  var themeOneDark = require('@codemirror/theme-one-dark');
@@ -27,16 +28,16 @@ var codemirror = require('codemirror');
27
28
  var cursor$1 = require('@jvs-milkdown/kit/plugin/cursor');
28
29
  var prosemirrorVirtualCursor = require('prosemirror-virtual-cursor');
29
30
  var diffBlock = require('@jvs-milkdown/kit/component/diff-block');
31
+ var history = require('@jvs-milkdown/prose/history');
30
32
  var view$1 = require('@jvs-milkdown/kit/prose/view');
31
33
  var tables = require('@jvs-milkdown/kit/prose/tables');
32
34
  var clsx = require('clsx');
33
35
  var linkTooltip$1 = require('@jvs-milkdown/kit/component/link-tooltip');
34
36
  var imageInline = require('@jvs-milkdown/kit/component/image-inline');
35
37
  var state$1 = require('@jvs-milkdown/prose/state');
36
- var utils$1 = require('@jvs-milkdown/utils');
37
38
  var Diff = require('diff');
38
39
  var tooltip = require('@jvs-milkdown/kit/plugin/tooltip');
39
- var history = require('@jvs-milkdown/kit/prose/history');
40
+ var history$1 = require('@jvs-milkdown/kit/prose/history');
40
41
  var keymap = require('@jvs-milkdown/kit/prose/keymap');
41
42
  var model = require('@jvs-milkdown/kit/prose/model');
42
43
  var inputrules = require('@jvs-milkdown/kit/prose/inputrules');
@@ -44,7 +45,7 @@ var remarkMath = require('remark-math');
44
45
  var listItemBlock = require('@jvs-milkdown/kit/component/list-item-block');
45
46
  var tableBlock = require('@jvs-milkdown/kit/component/table-block');
46
47
  var clipboard = require('@jvs-milkdown/kit/plugin/clipboard');
47
- var history$1 = require('@jvs-milkdown/kit/plugin/history');
48
+ var history$2 = require('@jvs-milkdown/kit/plugin/history');
48
49
  var indent = require('@jvs-milkdown/kit/plugin/indent');
49
50
  var listener = require('@jvs-milkdown/kit/plugin/listener');
50
51
  var trailing = require('@jvs-milkdown/kit/plugin/trailing');
@@ -670,6 +671,31 @@ const formatPainterIcon = `
670
671
  </svg>
671
672
  `;
672
673
 
674
+ const undoIcon = `
675
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
676
+ <path d="M328.768 243.52a42.688 42.688 0 0 0-60.352-60.352L97.92 353.664A43.008 43.008 0 0 0 85.248 384a42.56 42.56 0 0 0 12.48 30.208l170.688 170.624a42.688 42.688 0 1 0 60.352-60.288l-97.92-97.92h451.712a170.688 170.688 0 1 1 0 341.376H469.248a42.688 42.688 0 1 0 0 85.312h213.312a256 256 0 1 0 0-512H230.912l97.856-97.792z" fill="currentColor"></path>
677
+ </svg>
678
+ `;
679
+
680
+ const redoIcon = `
681
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
682
+ <path d="M755.584 183.168a42.688 42.688 0 0 0-60.352 60.352l97.856 97.792H341.44a256 256 0 0 0 0 512h213.312a42.688 42.688 0 0 0 0-85.312H341.44a170.688 170.688 0 0 1 0-341.312h451.648l-97.856 97.856a42.688 42.688 0 0 0 60.352 60.288l170.048-170.048a42.56 42.56 0 0 0 0-61.568l-170.048-170.048z" fill="currentColor"></path>
683
+ </svg>
684
+ `;
685
+
686
+ const exportIcon = `
687
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
688
+ <path d="M452.288 725.12L246.016 537.6c-4.928-4.48-10.432-8.832-14.72-13.696-20.8-23.232-21.312-42.944-2.304-59.52 17.664-15.36 43.392-14.976 65.536 4.48 49.088 43.328 32.256 27.712 80.512 71.744l69.376 63.36 11.968 10.688v-173.44c0-33.92-0.128-80.96-0.32-128.448-0.192-51.52-0.32-103.616-0.32-140.16L455.68 163.84a183.04 183.04 0 0 1 0.704-24.896c3.52-29.248 19.328-43.712 45.248-42.88 25.344 0.768 41.088 15.872 42.688 45.504 1.28 22.848 1.024 45.888 0.768 68.864l-0.128 27.136c0 50.048 0.128 112.832 0.256 176.384 0.192 71.552 0.384 144.192 0.32 200.704 74.432-68.224 131.968-119.68 162.688-147.584 7.424-6.72 14.912-14.272 24-18.304 18.688-8.448 37.76-7.808 52.8 7.36 14.72 14.72 16.384 31.36 3.968 48.192-3.84 5.248-8.64 10.112-13.44 14.656-45.76 41.92-189.76 173.248-236.16 214.464a62.336 62.336 0 0 1-8.064 6.016 43.712 43.712 0 0 1-15.872 9.792c-20.544 7.104-37.504-0.512-51.968-13.952l-11.2-10.24z m430.784-37.248c24-0.576 42.176 13.44 43.328 39.04 1.728 38.208 2.944 76.992-1.088 115.136-5.312 50.752-51.52 84.16-114.752 85.312-50.112 0.832-100.224 0.64-150.4 0.512l-64.832-0.128H422.272a26252.8 26252.8 0 0 1-194.432-0.192c-90.624-0.512-130.752-37.696-131.392-120.64l-0.192-17.408c-0.32-19.84-0.576-39.68 0.768-59.392 1.92-27.904 20.48-43.648 45.76-42.368 23.488 1.152 37.312 15.296 40.064 42.368 0.896 9.152 0.832 18.432 0.704 27.648l-0.064 10.816c0.384 71.744 7.36 78.208 88.128 78.272 117.248 0.128 234.432 0.128 351.68 0l43.968 0.192c36.096 0.064 72.192 0.192 108.288-0.448 52.672-0.96 64-12.096 65.152-60.288a494.464 494.464 0 0 0 0-21.76 365.632 365.632 0 0 1 0.704-35.84c2.24-26.048 17.92-40.32 41.664-40.832z" fill="currentColor"></path>
689
+ </svg>
690
+ `;
691
+
692
+ const importIcon = `
693
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
694
+ <path d="M838.656 594.432a41.152 41.152 0 0 0-40.768 41.472v176.128c0 0.384-0.384 0.96-1.216 0.96H210.688c-0.768 0-1.216-0.576-1.216-0.96V275.968c0-0.384 0.448-0.96 1.216-0.96h143.616a41.088 41.088 0 0 0 41.28-41.472A41.088 41.088 0 0 0 354.304 192H210.688C165.12 192 128 229.76 128 275.968v536.064C128 858.368 165.12 896 210.688 896h585.984c45.632 0 82.688-37.632 82.688-83.968V635.904a41.152 41.152 0 0 0-40.704-41.472z" fill="currentColor"></path>
695
+ <path d="M895.744 229.056a40.896 40.896 0 0 0-44.864-36.8c-4.032 0.448-99.456 11.52-200.576 68.352-106.24 59.776-179.2 147.648-214.656 257.28l-44.672-131.584a40.576 40.576 0 0 0-51.84-25.792 41.664 41.664 0 0 0-25.152 52.928l80.064 235.968a40.576 40.576 0 0 0 51.84 25.6l0.512-0.128 232.192-85.312a41.728 41.728 0 0 0 24-52.928 40.576 40.576 0 0 0-51.648-25.152l-144 52.928c26.048-99.2 86.464-176.256 180.416-229.76a508.672 508.672 0 0 1 172.416-59.904c22.336-2.56 38.4-22.976 35.968-45.696z" fill="currentColor"></path>
696
+ </svg>
697
+ `;
698
+
673
699
  const defaultConfig = {
674
700
  [CrepeFeature.CodeMirror]: {
675
701
  theme: themeOneDark.oneDark,
@@ -801,6 +827,8 @@ const zhCN = {
801
827
  "customMenu.colorPurple": "\u7D2B\u8272",
802
828
  "customMenu.colorGray": "\u7070\u8272",
803
829
  "customMenu.insertTable": "\u63D2\u5165\u652F\u6301\u5BCC\u6587\u672C\u7684\u8868\u683C",
830
+ "customMenu.export": "\u5BFC\u51FA",
831
+ "customMenu.import": "\u5BFC\u5165",
804
832
  "customMenu.fontDefault": "\u9ED8\u8BA4",
805
833
  "font.fangSong": "\u4EFF\u5B8B",
806
834
  "font.stFangsong": "\u534E\u6587\u4EFF\u5B8B",
@@ -948,6 +976,8 @@ const enUS = {
948
976
  "customMenu.colorPurple": "Purple",
949
977
  "customMenu.colorGray": "Gray",
950
978
  "customMenu.insertTable": "Insert Table",
979
+ "customMenu.export": "Export",
980
+ "customMenu.import": "Import",
951
981
  "customMenu.fontDefault": "Default",
952
982
  "font.fangSong": "FangSong",
953
983
  "font.stFangsong": "STFangsong",
@@ -3092,27 +3122,39 @@ const Menu = vue.defineComponent({
3092
3122
  let activeTextColor = null;
3093
3123
  let activeBgColor = null;
3094
3124
  if (node && node.nodeSize > 2) {
3095
- node.descendants((childNode) => {
3096
- if (childNode.isText) {
3097
- const tcType = textColorSchema.type(ctx);
3098
- const bcType = bgColorSchema.type(ctx);
3099
- if (!activeTextColor) {
3100
- const tcMark = childNode.marks.find((m) => m.type === tcType);
3101
- if (tcMark) activeTextColor = tcMark.attrs.color;
3102
- }
3103
- if (!activeBgColor) {
3104
- const bcMark = childNode.marks.find((m) => m.type === bcType);
3105
- if (bcMark) activeBgColor = bcMark.attrs.color;
3125
+ const schema = ctx.get(core.schemaCtx);
3126
+ const tcHasMark = schema.marks[textColorSchema.id];
3127
+ const bcHasMark = schema.marks[bgColorSchema.id];
3128
+ if (tcHasMark || bcHasMark) {
3129
+ node.descendants((childNode) => {
3130
+ if (childNode.isText) {
3131
+ if (tcHasMark && !activeTextColor) {
3132
+ const tcType = textColorSchema.type(ctx);
3133
+ const tcMark = childNode.marks.find(
3134
+ (m) => m.type === tcType
3135
+ );
3136
+ if (tcMark) activeTextColor = tcMark.attrs.color;
3137
+ }
3138
+ if (bcHasMark && !activeBgColor) {
3139
+ const bcType = bgColorSchema.type(ctx);
3140
+ const bcMark = childNode.marks.find(
3141
+ (m) => m.type === bcType
3142
+ );
3143
+ if (bcMark) activeBgColor = bcMark.attrs.color;
3144
+ }
3106
3145
  }
3107
- }
3108
- return false;
3109
- });
3146
+ return false;
3147
+ });
3148
+ }
3110
3149
  }
3111
3150
  const setBlockColor = (colorValue, isBg) => {
3112
3151
  if (pos === null || pos === void 0) return;
3113
3152
  const { tr } = view.state;
3114
3153
  const targetNode = tr.doc.nodeAt(pos);
3115
3154
  if (!targetNode) return;
3155
+ const schema = ctx.get(core.schemaCtx);
3156
+ const hasMark = isBg ? schema.marks[bgColorSchema.id] : schema.marks[textColorSchema.id];
3157
+ if (!hasMark) return;
3116
3158
  const markType = isBg ? bgColorSchema.type(ctx) : textColorSchema.type(ctx);
3117
3159
  const start = pos + 1;
3118
3160
  const end = pos + targetNode.nodeSize - 1;
@@ -3131,10 +3173,17 @@ const Menu = vue.defineComponent({
3131
3173
  const { tr } = view.state;
3132
3174
  const targetNode = tr.doc.nodeAt(pos);
3133
3175
  if (!targetNode) return;
3176
+ const schema = ctx.get(core.schemaCtx);
3177
+ const tcHasMark = schema.marks[textColorSchema.id];
3178
+ const bcHasMark = schema.marks[bgColorSchema.id];
3134
3179
  const start = pos + 1;
3135
3180
  const end = pos + targetNode.nodeSize - 1;
3136
- tr.removeMark(start, end, textColorSchema.type(ctx));
3137
- tr.removeMark(start, end, bgColorSchema.type(ctx));
3181
+ if (tcHasMark) {
3182
+ tr.removeMark(start, end, textColorSchema.type(ctx));
3183
+ }
3184
+ if (bcHasMark) {
3185
+ tr.removeMark(start, end, bgColorSchema.type(ctx));
3186
+ }
3138
3187
  view.dispatch(tr);
3139
3188
  showColorMenu.value = false;
3140
3189
  hide();
@@ -6165,6 +6214,10 @@ const Toolbar = vue.defineComponent({
6165
6214
  return { textColor: null, bgColor: null };
6166
6215
  const view = ctx.get(core.editorViewCtx);
6167
6216
  const { state } = view;
6217
+ const schema = ctx.get(core.schemaCtx);
6218
+ const tcHasMark = schema.marks[textColorSchema.id];
6219
+ const bcHasMark = schema.marks[bgColorSchema.id];
6220
+ if (!tcHasMark || !bcHasMark) return { textColor: null, bgColor: null };
6168
6221
  const tcType = textColorSchema.type(ctx);
6169
6222
  const bcType = bgColorSchema.type(ctx);
6170
6223
  const { $cursor, ranges } = state.selection;
@@ -6209,6 +6262,10 @@ const Toolbar = vue.defineComponent({
6209
6262
  const { state, dispatch } = view;
6210
6263
  const { tr } = state;
6211
6264
  const { from, to, empty } = state.selection;
6265
+ const schema = ctx.get(core.schemaCtx);
6266
+ const tcHasMark = schema.marks[textColorSchema.id];
6267
+ const bcHasMark = schema.marks[bgColorSchema.id];
6268
+ if (!tcHasMark || !bcHasMark) return;
6212
6269
  const textColorType = textColorSchema.type(ctx);
6213
6270
  const bgColorType = bgColorSchema.type(ctx);
6214
6271
  if (empty) {
@@ -6230,6 +6287,10 @@ const Toolbar = vue.defineComponent({
6230
6287
  return { fontFamily: null, fontSize: null };
6231
6288
  const view = ctx.get(core.editorViewCtx);
6232
6289
  const { state } = view;
6290
+ const schema = ctx.get(core.schemaCtx);
6291
+ const ffHasMark = schema.marks[fontFamilySchema.id];
6292
+ const fsHasMark = schema.marks[fontSizeSchema.id];
6293
+ if (!ffHasMark || !fsHasMark) return { fontFamily: null, fontSize: null };
6233
6294
  const ffType = fontFamilySchema.type(ctx);
6234
6295
  const fsType = fontSizeSchema.type(ctx);
6235
6296
  const { $cursor, ranges } = state.selection;
@@ -6637,6 +6698,7 @@ const Toolbar = vue.defineComponent({
6637
6698
  "toolbar-item",
6638
6699
  ctx && checkActive(item.active) && "active"
6639
6700
  ),
6701
+ "data-key": item.key,
6640
6702
  onPointerdown: (e) => {
6641
6703
  if (isTable) {
6642
6704
  e.preventDefault();
@@ -7473,11 +7535,12 @@ const Toolbar = vue.defineComponent({
7473
7535
  (() => {
7474
7536
  const cutoff = overflowVisibleCount.value;
7475
7537
  const items = [];
7476
- const renderIconButton = (iconHtml, title, isActive, onClick2, hasDropdown = false, onMouseEnter, onMouseLeave) => /* @__PURE__ */ vue.h(
7538
+ const renderIconButton = (iconHtml, title, isActive, onClick2, hasDropdown = false, onMouseEnter, onMouseLeave, key) => /* @__PURE__ */ vue.h(
7477
7539
  "button",
7478
7540
  {
7479
7541
  type: "button",
7480
7542
  class: clsx("toolbar-item", isActive && "active"),
7543
+ "data-key": key,
7481
7544
  title,
7482
7545
  onPointerdown: (e) => {
7483
7546
  e.preventDefault();
@@ -7599,7 +7662,8 @@ const Toolbar = vue.defineComponent({
7599
7662
  },
7600
7663
  isTable,
7601
7664
  isTable ? handleTableEnter : void 0,
7602
- isTable ? handleTableLeave : void 0
7665
+ isTable ? handleTableLeave : void 0,
7666
+ item.key
7603
7667
  )
7604
7668
  );
7605
7669
  }
@@ -7779,7 +7843,15 @@ const MenuBar = vue.defineComponent({
7779
7843
  { name: "\u6D45\u7D2B", value: "#F0E6FA" },
7780
7844
  { name: "\u6D45\u7C89", value: "#FDE8E9" }
7781
7845
  ];
7782
- const menuKeys = ["file", "edit", "view", "insert", "format"];
7846
+ const menuKeys = vue.computed(() => {
7847
+ var _a;
7848
+ const allKeys = ["file", "edit", "view", "insert", "format"];
7849
+ const itemsConfig = (_a = props.config) == null ? void 0 : _a.menuBarItems;
7850
+ if (!itemsConfig) return allKeys;
7851
+ return allKeys.filter(
7852
+ (key) => itemsConfig[key] !== false
7853
+ );
7854
+ });
7783
7855
  const hasSubmenu = (key) => key === "view";
7784
7856
  return () => {
7785
7857
  const state = viewState.value;
@@ -7868,7 +7940,7 @@ const MenuBar = vue.defineComponent({
7868
7940
  e.stopPropagation();
7869
7941
  }
7870
7942
  },
7871
- menuKeys.map((menuKey) => {
7943
+ menuKeys.value.map((menuKey) => {
7872
7944
  const isHovered = activeSubmenu.value === menuKey;
7873
7945
  const label = i18n(props.ctx, `menuBar.${menuKey}`) || menuKey;
7874
7946
  return /* @__PURE__ */ vue.h(
@@ -8407,70 +8479,159 @@ const FixedToolbarComponent = vue.defineComponent({
8407
8479
  hide: { type: Function, required: true },
8408
8480
  show: { type: Object, required: true },
8409
8481
  selection: { type: Object, required: true },
8410
- config: { type: Object, required: false }
8482
+ config: { type: Object, required: false },
8483
+ canUndo: { type: Object, required: true },
8484
+ canRedo: { type: Object, required: true }
8411
8485
  },
8412
8486
  setup(props) {
8413
8487
  const showShortcuts = vue.ref(false);
8414
- return () => /* @__PURE__ */ vue.h(
8415
- "div",
8416
- {
8417
- style: {
8418
- display: "flex",
8419
- alignItems: "center",
8420
- justifyContent: "center",
8421
- width: "100%",
8422
- gap: "0px"
8423
- }
8424
- },
8425
- /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
8426
- /* @__PURE__ */ vue.h(
8427
- "div",
8428
- {
8429
- style: {
8430
- width: "1px",
8431
- minWidth: "1px",
8432
- height: "20px",
8433
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8434
- }
8435
- }
8436
- ),
8437
- /* @__PURE__ */ vue.h(
8438
- Toolbar,
8439
- {
8440
- ctx: props.ctx,
8441
- hide: props.hide,
8442
- show: props.show,
8443
- selection: props.selection,
8444
- config: props.config,
8445
- isFixed: true
8446
- }
8447
- ),
8448
- /* @__PURE__ */ vue.h(
8488
+ vue.onMounted(() => {
8489
+ const handleShowShortcuts = () => {
8490
+ showShortcuts.value = true;
8491
+ };
8492
+ window.addEventListener("milkdown-show-shortcuts", handleShowShortcuts);
8493
+ vue.onUnmounted(() => {
8494
+ window.removeEventListener(
8495
+ "milkdown-show-shortcuts",
8496
+ handleShowShortcuts
8497
+ );
8498
+ });
8499
+ });
8500
+ return () => {
8501
+ var _a, _b, _c, _d;
8502
+ props.selection.value;
8503
+ const canUndo = (typeof props.canUndo === "boolean" ? props.canUndo : (_a = props.canUndo) == null ? void 0 : _a.value) || false;
8504
+ const canRedo = (typeof props.canRedo === "boolean" ? props.canRedo : (_b = props.canRedo) == null ? void 0 : _b.value) || false;
8505
+ return /* @__PURE__ */ vue.h(
8449
8506
  "div",
8450
8507
  {
8451
8508
  style: {
8452
- width: "1px",
8453
- minWidth: "1px",
8454
- height: "20px",
8455
- flexShrink: 0,
8456
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8457
- }
8458
- }
8459
- ),
8460
- /* @__PURE__ */ vue.h(
8461
- "button",
8462
- {
8463
- type: "button",
8464
- class: "toolbar-shortcut-btn",
8465
- title: i18n(props.ctx, "shortcuts.title"),
8466
- onClick: () => {
8467
- showShortcuts.value = true;
8509
+ display: "flex",
8510
+ alignItems: "center",
8511
+ justifyContent: "center",
8512
+ width: "100%",
8513
+ gap: "0px"
8468
8514
  }
8469
8515
  },
8470
- /* @__PURE__ */ vue.h(component.Icon, { icon: keyboardIcon })
8471
- ),
8472
- showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8473
- );
8516
+ ((_c = props.config) == null ? void 0 : _c.showMenuBar) !== false && [
8517
+ /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
8518
+ /* @__PURE__ */ vue.h(
8519
+ "div",
8520
+ {
8521
+ style: {
8522
+ width: "1px",
8523
+ minWidth: "1px",
8524
+ height: "20px",
8525
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8526
+ }
8527
+ }
8528
+ )
8529
+ ],
8530
+ ((_d = props.config) == null ? void 0 : _d.showHistory) !== false && [
8531
+ /* @__PURE__ */ vue.h(
8532
+ "button",
8533
+ {
8534
+ type: "button",
8535
+ class: ["toolbar-item", !canUndo && "disabled"],
8536
+ disabled: !canUndo,
8537
+ title: "\u64A4\u9500",
8538
+ onPointerdown: (e) => {
8539
+ e.preventDefault();
8540
+ e.stopPropagation();
8541
+ },
8542
+ onClick: (e) => {
8543
+ e.preventDefault();
8544
+ e.stopPropagation();
8545
+ if (canUndo) {
8546
+ props.ctx.get(core.commandsCtx).call("Undo");
8547
+ }
8548
+ },
8549
+ style: {
8550
+ display: "flex",
8551
+ alignItems: "center",
8552
+ justifyContent: "center",
8553
+ border: "none",
8554
+ background: "transparent",
8555
+ cursor: canUndo ? "pointer" : "default",
8556
+ padding: "6px",
8557
+ borderRadius: "4px",
8558
+ color: canUndo ? "#363b4c" : "#c0c4cc",
8559
+ "--toolbar-icon-color": canUndo ? "#363b4c" : "#c0c4cc"
8560
+ }
8561
+ },
8562
+ /* @__PURE__ */ vue.h(
8563
+ "span",
8564
+ {
8565
+ style: { display: "inline-flex", alignItems: "center" },
8566
+ innerHTML: undoIcon
8567
+ }
8568
+ )
8569
+ ),
8570
+ /* @__PURE__ */ vue.h(
8571
+ "button",
8572
+ {
8573
+ type: "button",
8574
+ class: ["toolbar-item", !canRedo && "disabled"],
8575
+ disabled: !canRedo,
8576
+ title: "\u6062\u590D",
8577
+ onPointerdown: (e) => {
8578
+ e.preventDefault();
8579
+ e.stopPropagation();
8580
+ },
8581
+ onClick: (e) => {
8582
+ e.preventDefault();
8583
+ e.stopPropagation();
8584
+ if (canRedo) {
8585
+ props.ctx.get(core.commandsCtx).call("Redo");
8586
+ }
8587
+ },
8588
+ style: {
8589
+ display: "flex",
8590
+ alignItems: "center",
8591
+ justifyContent: "center",
8592
+ border: "none",
8593
+ background: "transparent",
8594
+ cursor: canRedo ? "pointer" : "default",
8595
+ padding: "6px",
8596
+ borderRadius: "4px",
8597
+ color: canRedo ? "#363b4c" : "#c0c4cc",
8598
+ "--toolbar-icon-color": canRedo ? "#363b4c" : "#c0c4cc"
8599
+ }
8600
+ },
8601
+ /* @__PURE__ */ vue.h(
8602
+ "span",
8603
+ {
8604
+ style: { display: "inline-flex", alignItems: "center" },
8605
+ innerHTML: redoIcon
8606
+ }
8607
+ )
8608
+ ),
8609
+ /* @__PURE__ */ vue.h(
8610
+ "div",
8611
+ {
8612
+ style: {
8613
+ width: "1px",
8614
+ minWidth: "1px",
8615
+ height: "20px",
8616
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8617
+ }
8618
+ }
8619
+ )
8620
+ ],
8621
+ /* @__PURE__ */ vue.h(
8622
+ Toolbar,
8623
+ {
8624
+ ctx: props.ctx,
8625
+ hide: props.hide,
8626
+ show: props.show,
8627
+ selection: props.selection,
8628
+ config: props.config,
8629
+ isFixed: true
8630
+ }
8631
+ ),
8632
+ showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8633
+ );
8634
+ };
8474
8635
  }
8475
8636
  });
8476
8637
 
@@ -8896,6 +9057,65 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8896
9057
  }
8897
9058
  });
8898
9059
  }
9060
+ const documentGroup = builder.addGroup("document", "Document");
9061
+ if ((_config == null ? void 0 : _config.showExport) !== false) {
9062
+ documentGroup.addItem("export", {
9063
+ label: ctx ? i18n(ctx, "customMenu.export") || "\u5BFC\u51FA" : "\u5BFC\u51FA",
9064
+ icon: exportIcon,
9065
+ active: () => false,
9066
+ onRun: (ctx2) => {
9067
+ const markdown = utils.getMarkdown()(ctx2);
9068
+ if (_config == null ? void 0 : _config.onExport) {
9069
+ _config.onExport(markdown, ctx2);
9070
+ } else {
9071
+ const blob = new Blob([markdown], {
9072
+ type: "text/markdown;charset=utf-8;"
9073
+ });
9074
+ const url = URL.createObjectURL(blob);
9075
+ const link = document.createElement("a");
9076
+ link.href = url;
9077
+ link.download = "document.md";
9078
+ link.click();
9079
+ URL.revokeObjectURL(url);
9080
+ }
9081
+ }
9082
+ });
9083
+ }
9084
+ if ((_config == null ? void 0 : _config.showImport) !== false) {
9085
+ documentGroup.addItem("import", {
9086
+ label: ctx ? i18n(ctx, "customMenu.import") || "\u5BFC\u5165" : "\u5BFC\u5165",
9087
+ icon: importIcon,
9088
+ active: () => false,
9089
+ onRun: (ctx2) => {
9090
+ if (_config == null ? void 0 : _config.onImport) {
9091
+ _config.onImport((markdown) => utils$1.replaceAll(markdown)(ctx2), ctx2);
9092
+ } else {
9093
+ const input = document.createElement("input");
9094
+ input.type = "file";
9095
+ input.accept = ".md";
9096
+ input.onchange = (e) => {
9097
+ var _a;
9098
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
9099
+ if (!file) return;
9100
+ file.text().then((text) => {
9101
+ utils$1.replaceAll(text)(ctx2);
9102
+ }).catch((err) => {
9103
+ console.error("Failed to read file:", err);
9104
+ });
9105
+ };
9106
+ input.click();
9107
+ }
9108
+ }
9109
+ });
9110
+ }
9111
+ documentGroup.addItem("shortcuts", {
9112
+ label: ctx ? i18n(ctx, "shortcuts.title") : "Shortcuts",
9113
+ icon: keyboardIcon,
9114
+ active: () => false,
9115
+ onRun: () => {
9116
+ window.dispatchEvent(new CustomEvent("milkdown-show-shortcuts"));
9117
+ }
9118
+ });
8899
9119
  return builder.build();
8900
9120
  }
8901
9121
 
@@ -9205,6 +9425,11 @@ const OutlinePanel = vue.defineComponent({
9205
9425
  const activeId = vue.ref("");
9206
9426
  const collapsedIds = vue.ref(/* @__PURE__ */ new Set());
9207
9427
  let scrollLock = false;
9428
+ const clickedActiveId = vue.ref(null);
9429
+ const clearClickedActive = () => {
9430
+ if (scrollLock) return;
9431
+ clickedActiveId.value = null;
9432
+ };
9208
9433
  const hasChildren = (index) => {
9209
9434
  const current = items.value[index];
9210
9435
  if (!current) return false;
@@ -9259,6 +9484,10 @@ const OutlinePanel = vue.defineComponent({
9259
9484
  if (scrollLock) return;
9260
9485
  const view = props.ctx.get(core.editorViewCtx);
9261
9486
  if (!view || !view.dom) return;
9487
+ if (clickedActiveId.value) {
9488
+ activeId.value = clickedActiveId.value;
9489
+ return;
9490
+ }
9262
9491
  const headings = Array.from(
9263
9492
  view.dom.querySelectorAll("h1, h2, h3, h4, h5, h6")
9264
9493
  );
@@ -9266,14 +9495,39 @@ const OutlinePanel = vue.defineComponent({
9266
9495
  activeId.value = "";
9267
9496
  return;
9268
9497
  }
9269
- const scrollContainer = view.dom.parentElement;
9270
- if (!scrollContainer) return;
9271
- const toolbar = scrollContainer.querySelector(
9498
+ let scrollContainer = view.dom.parentElement;
9499
+ while (scrollContainer && scrollContainer !== document.body) {
9500
+ const style = window.getComputedStyle(scrollContainer);
9501
+ const overflowY = style.overflowY;
9502
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9503
+ break;
9504
+ }
9505
+ scrollContainer = scrollContainer.parentElement;
9506
+ }
9507
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9508
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9509
+ const rootNode = view.dom.getRootNode();
9510
+ let toolbar = rootNode.querySelector(
9272
9511
  ".milkdown-fixed-toolbar"
9273
9512
  );
9513
+ if (!toolbar) {
9514
+ toolbar = document.querySelector(
9515
+ ".milkdown-fixed-toolbar"
9516
+ );
9517
+ }
9274
9518
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9275
- const containerRect = scrollContainer.getBoundingClientRect();
9276
- const threshold = containerRect.top + toolbarHeight + 50;
9519
+ const containerRect = actualScrollContainer.getBoundingClientRect();
9520
+ const containerTop = isRootScroll ? 0 : Math.max(0, containerRect.top);
9521
+ let scrollTop = actualScrollContainer.scrollTop;
9522
+ let clientHeight = actualScrollContainer.clientHeight;
9523
+ let scrollHeight = actualScrollContainer.scrollHeight;
9524
+ if (isRootScroll) {
9525
+ scrollTop = window.scrollY || document.documentElement.scrollTop;
9526
+ clientHeight = window.innerHeight || document.documentElement.clientHeight;
9527
+ scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
9528
+ }
9529
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight - 15;
9530
+ const threshold = isAtBottom ? containerTop + clientHeight : containerTop + toolbarHeight + 50;
9277
9531
  let active = headings[0];
9278
9532
  for (const h2 of headings) {
9279
9533
  const rect = h2.getBoundingClientRect();
@@ -9283,43 +9537,120 @@ const OutlinePanel = vue.defineComponent({
9283
9537
  break;
9284
9538
  }
9285
9539
  }
9286
- activeId.value = (active == null ? void 0 : active.id) || "";
9540
+ const activeItem = items.value.find((item) => {
9541
+ try {
9542
+ const activePos = view.posAtDOM(active, 0);
9543
+ const isPosMatch = item.pos === activePos - 1;
9544
+ let isDepthMatch = false;
9545
+ const $pos = view.state.doc.resolve(activePos);
9546
+ for (let d = $pos.depth; d >= 0; d--) {
9547
+ if ($pos.node(d).type.name === "heading") {
9548
+ if (item.pos === $pos.before(d)) {
9549
+ isDepthMatch = true;
9550
+ break;
9551
+ }
9552
+ }
9553
+ }
9554
+ if (isPosMatch || isDepthMatch) {
9555
+ return true;
9556
+ }
9557
+ } catch (e) {
9558
+ }
9559
+ const dom = view.nodeDOM(item.pos);
9560
+ const domMatch = dom === active || dom instanceof HTMLElement && active && dom.contains(active);
9561
+ if (domMatch) {
9562
+ return true;
9563
+ }
9564
+ return false;
9565
+ });
9566
+ const newActiveId = activeItem ? activeItem.id : (active == null ? void 0 : active.id) || "";
9567
+ activeId.value = newActiveId;
9287
9568
  };
9288
- const scrollToHeading = (id) => {
9569
+ const scrollToHeading = (item) => {
9289
9570
  const view = props.ctx.get(core.editorViewCtx);
9290
9571
  if (!view) return;
9291
9572
  try {
9292
- const headingEl = view.dom.querySelector(
9293
- `[id="${id}"]`
9294
- );
9573
+ let headingEl = view.nodeDOM(item.pos);
9574
+ if (!headingEl) {
9575
+ try {
9576
+ const domAt = view.domAtPos(item.pos);
9577
+ let node = domAt.node;
9578
+ if (node.nodeType === Node.TEXT_NODE) {
9579
+ node = node.parentElement;
9580
+ }
9581
+ if (node instanceof HTMLElement) {
9582
+ headingEl = node.closest(
9583
+ "h1, h2, h3, h4, h5, h6"
9584
+ );
9585
+ if (!headingEl && domAt.offset < node.childNodes.length) {
9586
+ const child = node.childNodes[domAt.offset];
9587
+ if (child instanceof HTMLElement) {
9588
+ headingEl = child.closest("h1, h2, h3, h4, h5, h6") || child.querySelector(
9589
+ "h1, h2, h3, h4, h5, h6"
9590
+ );
9591
+ }
9592
+ }
9593
+ }
9594
+ } catch (e) {
9595
+ }
9596
+ }
9597
+ if (!headingEl) {
9598
+ headingEl = view.dom.querySelector(
9599
+ `[id="${item.id}"]`
9600
+ );
9601
+ }
9295
9602
  if (!headingEl) return;
9296
- const scrollContainer = view.dom.parentElement;
9297
- if (!scrollContainer) return;
9603
+ let scrollContainer = view.dom.parentElement;
9604
+ while (scrollContainer && scrollContainer !== document.body) {
9605
+ const style = window.getComputedStyle(scrollContainer);
9606
+ const overflowY = style.overflowY;
9607
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9608
+ break;
9609
+ }
9610
+ scrollContainer = scrollContainer.parentElement;
9611
+ }
9612
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9613
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9298
9614
  scrollLock = true;
9299
- const toolbar = scrollContainer.querySelector(
9615
+ const rootNode = view.dom.getRootNode();
9616
+ let toolbar = rootNode.querySelector(
9300
9617
  ".milkdown-fixed-toolbar"
9301
9618
  );
9619
+ if (!toolbar) {
9620
+ toolbar = document.querySelector(
9621
+ ".milkdown-fixed-toolbar"
9622
+ );
9623
+ }
9302
9624
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9303
- const containerRect = scrollContainer.getBoundingClientRect();
9625
+ const containerRectTop = isRootScroll ? 0 : actualScrollContainer.getBoundingClientRect().top;
9304
9626
  const headingRect = headingEl.getBoundingClientRect();
9305
- scrollContainer.scrollTo({
9306
- top: scrollContainer.scrollTop + headingRect.top - containerRect.top - toolbarHeight - 20,
9307
- behavior: "smooth"
9308
- });
9627
+ const targetTop = actualScrollContainer.scrollTop + headingRect.top - containerRectTop - toolbarHeight - 20;
9628
+ const scrollTarget = isRootScroll ? window : actualScrollContainer;
9309
9629
  let timer;
9310
9630
  const onScrollEnd = () => {
9311
9631
  clearTimeout(timer);
9312
9632
  timer = setTimeout(() => {
9313
9633
  scrollLock = false;
9314
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9634
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9315
9635
  checkActive();
9316
9636
  }, 150);
9317
9637
  };
9318
- scrollContainer.addEventListener("scroll", onScrollEnd);
9638
+ scrollTarget.addEventListener("scroll", onScrollEnd);
9319
9639
  setTimeout(() => {
9320
9640
  scrollLock = false;
9321
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9641
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9322
9642
  }, 2e3);
9643
+ if (isRootScroll) {
9644
+ window.scrollTo({
9645
+ top: targetTop,
9646
+ behavior: "smooth"
9647
+ });
9648
+ } else {
9649
+ actualScrollContainer.scrollTo({
9650
+ top: targetTop,
9651
+ behavior: "smooth"
9652
+ });
9653
+ }
9323
9654
  } catch (e) {
9324
9655
  scrollLock = false;
9325
9656
  updateOutline();
@@ -9330,6 +9661,27 @@ const OutlinePanel = vue.defineComponent({
9330
9661
  vue.onMounted(() => {
9331
9662
  updateOutline();
9332
9663
  checkActive();
9664
+ window.addEventListener("wheel", clearClickedActive, { passive: true });
9665
+ window.addEventListener("touchmove", clearClickedActive, {
9666
+ passive: true
9667
+ });
9668
+ window.addEventListener("pointerdown", clearClickedActive, {
9669
+ passive: true
9670
+ });
9671
+ const keyHandler = (e) => {
9672
+ if ([
9673
+ "ArrowUp",
9674
+ "ArrowDown",
9675
+ "PageUp",
9676
+ "PageDown",
9677
+ "Home",
9678
+ "End"
9679
+ ].includes(e.key)) {
9680
+ clearClickedActive();
9681
+ }
9682
+ };
9683
+ window.addEventListener("keydown", keyHandler, { passive: true });
9684
+ vue.onMounted._keyHandler = keyHandler;
9333
9685
  interval = setInterval(() => {
9334
9686
  if (viewState.value.outlineVisible) {
9335
9687
  updateOutline();
@@ -9346,6 +9698,13 @@ const OutlinePanel = vue.defineComponent({
9346
9698
  if (interval) clearInterval(interval);
9347
9699
  if (pollInterval) clearInterval(pollInterval);
9348
9700
  window.removeEventListener("scroll", checkActive, true);
9701
+ window.removeEventListener("wheel", clearClickedActive);
9702
+ window.removeEventListener("touchmove", clearClickedActive);
9703
+ window.removeEventListener("pointerdown", clearClickedActive);
9704
+ const keyHandler = vue.onMounted._keyHandler;
9705
+ if (keyHandler) {
9706
+ window.removeEventListener("keydown", keyHandler);
9707
+ }
9349
9708
  });
9350
9709
  let startX = 0;
9351
9710
  let startWidth = 0;
@@ -9473,7 +9832,8 @@ const OutlinePanel = vue.defineComponent({
9473
9832
  key: item.id,
9474
9833
  onClick: () => {
9475
9834
  activeId.value = item.id;
9476
- scrollToHeading(item.id);
9835
+ clickedActiveId.value = item.id;
9836
+ scrollToHeading(item);
9477
9837
  },
9478
9838
  style: {
9479
9839
  display: "flex",
@@ -9530,7 +9890,7 @@ const OutlinePanel = vue.defineComponent({
9530
9890
  e.currentTarget.style.backgroundColor = "transparent";
9531
9891
  }
9532
9892
  },
9533
- "\uFFFD?",
9893
+ "\u25BC",
9534
9894
  " "
9535
9895
  ),
9536
9896
  /* @__PURE__ */ vue.h(
@@ -9585,7 +9945,7 @@ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Ca
9585
9945
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9586
9946
  var __privateAdd$4 = (obj, member, value) => member.has(obj) ? __typeError$4("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
9587
9947
  var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
9588
- var _content$2, _app$2, _headerContent, _headerApp, _outlineContent, _outlineApp, _watcher, _selection$1, _show$1, _resizeObserver$1, _updateOutlineGeometry, _scrollContainers$1, _onDblClick, _view$1, _editorContainer;
9948
+ var _content$2, _app$2, _headerContent, _headerApp, _outlineContent, _outlineApp, _watcher, _selection$1, _show$1, _canUndo, _canRedo, _resizeObserver$1, _updateOutlineGeometry, _scrollContainers$1, _onDblClick, _view$1, _editorContainer;
9589
9949
  const fixedToolbarConfig = utils.$ctx(
9590
9950
  {},
9591
9951
  "fixedToolbarConfigCtx"
@@ -9602,6 +9962,8 @@ class FixedToolbarView {
9602
9962
  __privateAdd$4(this, _watcher);
9603
9963
  __privateAdd$4(this, _selection$1);
9604
9964
  __privateAdd$4(this, _show$1, vue.ref(true));
9965
+ __privateAdd$4(this, _canUndo, vue.ref(false));
9966
+ __privateAdd$4(this, _canRedo, vue.ref(false));
9605
9967
  __privateAdd$4(this, _resizeObserver$1);
9606
9968
  __privateAdd$4(this, _updateOutlineGeometry);
9607
9969
  __privateAdd$4(this, _scrollContainers$1, []);
@@ -9610,6 +9972,11 @@ class FixedToolbarView {
9610
9972
  __privateAdd$4(this, _editorContainer);
9611
9973
  this.update = (view) => {
9612
9974
  __privateGet$4(this, _selection$1).value = view.state.selection;
9975
+ try {
9976
+ __privateGet$4(this, _canUndo).value = history.undo(view.state);
9977
+ __privateGet$4(this, _canRedo).value = history.redo(view.state);
9978
+ } catch (e) {
9979
+ }
9613
9980
  };
9614
9981
  this.destroy = () => {
9615
9982
  if (__privateGet$4(this, _watcher)) __privateGet$4(this, _watcher).call(this);
@@ -9634,6 +10001,60 @@ class FixedToolbarView {
9634
10001
  };
9635
10002
  __privateSet$4(this, _view$1, view);
9636
10003
  const config = ctx.get(fixedToolbarConfig.key);
10004
+ const viewState = ctx.get(viewMenuStateCtx.key);
10005
+ if (config == null ? void 0 : config.useLocalStorage) {
10006
+ try {
10007
+ const stored = localStorage.getItem("jvs-milkdown-data");
10008
+ if (stored) {
10009
+ const parsed = JSON.parse(stored);
10010
+ if (parsed.outlineVisible !== void 0)
10011
+ viewState.outlineVisible = parsed.outlineVisible;
10012
+ if (parsed.outlinePosition !== void 0)
10013
+ viewState.outlinePosition = parsed.outlinePosition;
10014
+ if (parsed.outlineWidth !== void 0)
10015
+ viewState.outlineWidth = parsed.outlineWidth;
10016
+ if (parsed.documentBackground !== void 0)
10017
+ viewState.documentBackground = parsed.documentBackground;
10018
+ if (parsed.showTitle !== void 0)
10019
+ viewState.showTitle = parsed.showTitle;
10020
+ if (parsed.showCover !== void 0)
10021
+ viewState.showCover = parsed.showCover;
10022
+ if (parsed.coverUrl !== void 0)
10023
+ viewState.coverUrl = parsed.coverUrl;
10024
+ if (parsed.editorWidth !== void 0)
10025
+ viewState.editorWidth = parsed.editorWidth;
10026
+ }
10027
+ } catch (e) {
10028
+ console.error("Error loading view state from localStorage:", e);
10029
+ }
10030
+ vue.watch(
10031
+ viewState,
10032
+ (newState) => {
10033
+ try {
10034
+ const stored = localStorage.getItem("jvs-milkdown-data");
10035
+ let parsed = {};
10036
+ if (stored) {
10037
+ parsed = JSON.parse(stored);
10038
+ }
10039
+ const merged = {
10040
+ ...parsed,
10041
+ outlineVisible: newState.outlineVisible,
10042
+ outlinePosition: newState.outlinePosition,
10043
+ outlineWidth: newState.outlineWidth,
10044
+ documentBackground: newState.documentBackground,
10045
+ showTitle: newState.showTitle,
10046
+ showCover: newState.showCover,
10047
+ coverUrl: newState.coverUrl,
10048
+ editorWidth: newState.editorWidth
10049
+ };
10050
+ localStorage.setItem("jvs-milkdown-data", JSON.stringify(merged));
10051
+ } catch (e) {
10052
+ console.error("Error saving view state to localStorage:", e);
10053
+ }
10054
+ },
10055
+ { deep: true }
10056
+ );
10057
+ }
9637
10058
  const content = document.createElement("div");
9638
10059
  content.className = "milkdown-fixed-toolbar";
9639
10060
  __privateSet$4(this, _selection$1, vue.shallowRef(view.state.selection));
@@ -9644,7 +10065,9 @@ class FixedToolbarView {
9644
10065
  // No-op for fixed toolbar
9645
10066
  config,
9646
10067
  selection: __privateGet$4(this, _selection$1),
9647
- show: __privateGet$4(this, _show$1)
10068
+ show: __privateGet$4(this, _show$1),
10069
+ canUndo: __privateGet$4(this, _canUndo),
10070
+ canRedo: __privateGet$4(this, _canRedo)
9648
10071
  });
9649
10072
  app.mount(content);
9650
10073
  __privateSet$4(this, _content$2, content);
@@ -9701,9 +10124,9 @@ class FixedToolbarView {
9701
10124
  });
9702
10125
  view.dom.addEventListener("dblclick", __privateGet$4(this, _onDblClick));
9703
10126
  __privateGet$4(this, _content$2).style.transition = "margin 0.1s ease-out, width 0.1s ease-out";
9704
- const viewState = ctx.get(viewMenuStateCtx.key);
10127
+ const viewState2 = ctx.get(viewMenuStateCtx.key);
9705
10128
  if (config.outlinePosition) {
9706
- viewState.outlinePosition = config.outlinePosition;
10129
+ viewState2.outlinePosition = config.outlinePosition;
9707
10130
  }
9708
10131
  __privateSet$4(this, _updateOutlineGeometry, () => {
9709
10132
  const rootRect = root.getBoundingClientRect();
@@ -9712,7 +10135,7 @@ class FixedToolbarView {
9712
10135
  const toolbarRect = __privateGet$4(this, _content$2).getBoundingClientRect();
9713
10136
  outlineTop = Math.max(outlineTop, toolbarRect.bottom);
9714
10137
  }
9715
- if (viewState.showCover && __privateGet$4(this, _headerContent)) {
10138
+ if (viewState2.showCover && __privateGet$4(this, _headerContent)) {
9716
10139
  const coverEl = __privateGet$4(this, _headerContent).querySelector(
9717
10140
  ".milkdown-document-cover"
9718
10141
  );
@@ -9729,8 +10152,8 @@ class FixedToolbarView {
9729
10152
  }
9730
10153
  outlineContent.style.top = `${outlineTop}px`;
9731
10154
  outlineContent.style.height = `${height}px`;
9732
- if (viewState.outlineVisible) {
9733
- if (viewState.outlinePosition === "left") {
10155
+ if (viewState2.outlineVisible) {
10156
+ if (viewState2.outlinePosition === "left") {
9734
10157
  outlineContent.style.left = `${rootRect.left}px`;
9735
10158
  outlineContent.style.right = "auto";
9736
10159
  } else {
@@ -9780,16 +10203,16 @@ class FixedToolbarView {
9780
10203
  }
9781
10204
  __privateSet$4(this, _watcher, vue.watch(
9782
10205
  () => [
9783
- viewState.outlineVisible,
9784
- viewState.outlinePosition,
9785
- viewState.outlineWidth,
9786
- viewState.documentBackground,
9787
- viewState.showCover,
9788
- viewState.editorWidth
10206
+ viewState2.outlineVisible,
10207
+ viewState2.outlinePosition,
10208
+ viewState2.outlineWidth,
10209
+ viewState2.documentBackground,
10210
+ viewState2.showCover,
10211
+ viewState2.editorWidth
9789
10212
  ],
9790
10213
  () => {
9791
- if (viewState.documentBackground) {
9792
- root.style.backgroundColor = viewState.documentBackground;
10214
+ if (viewState2.documentBackground) {
10215
+ root.style.backgroundColor = viewState2.documentBackground;
9793
10216
  } else {
9794
10217
  root.style.backgroundColor = "";
9795
10218
  }
@@ -9799,20 +10222,20 @@ class FixedToolbarView {
9799
10222
  __privateGet$4(this, _content$2).style.marginLeft = "0";
9800
10223
  __privateGet$4(this, _content$2).style.marginRight = "0";
9801
10224
  if (__privateGet$4(this, _editorContainer)) {
9802
- if (viewState.outlineVisible) {
9803
- if (viewState.outlinePosition === "left") {
9804
- __privateGet$4(this, _editorContainer).style.paddingLeft = `${viewState.outlineWidth}px`;
10225
+ if (viewState2.outlineVisible) {
10226
+ if (viewState2.outlinePosition === "left") {
10227
+ __privateGet$4(this, _editorContainer).style.paddingLeft = `${viewState2.outlineWidth}px`;
9805
10228
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9806
10229
  } else {
9807
10230
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9808
- __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState.outlineWidth}px`;
10231
+ __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState2.outlineWidth}px`;
9809
10232
  }
9810
10233
  } else {
9811
10234
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9812
10235
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9813
10236
  }
9814
10237
  }
9815
- const maxWidth = editorWidthMap[viewState.editorWidth];
10238
+ const maxWidth = editorWidthMap[viewState2.editorWidth];
9816
10239
  const isFull = maxWidth === "none";
9817
10240
  const px = isFull ? "80px" : "0";
9818
10241
  __privateGet$4(this, _view$1).dom.style.maxWidth = maxWidth;
@@ -9820,7 +10243,7 @@ class FixedToolbarView {
9820
10243
  __privateGet$4(this, _view$1).dom.style.margin = isFull ? "0" : "0 auto";
9821
10244
  __privateGet$4(this, _view$1).dom.style.padding = `20px ${px} 36px`;
9822
10245
  if (__privateGet$4(this, _headerContent)) {
9823
- __privateGet$4(this, _headerContent).style.margin = isFull && !viewState.showCover ? "0 auto" : "0";
10246
+ __privateGet$4(this, _headerContent).style.margin = isFull && !viewState2.showCover ? "0 auto" : "0";
9824
10247
  __privateGet$4(this, _headerContent).style.padding = `0px`;
9825
10248
  }
9826
10249
  void vue.nextTick(() => {
@@ -9846,6 +10269,8 @@ _outlineApp = new WeakMap();
9846
10269
  _watcher = new WeakMap();
9847
10270
  _selection$1 = new WeakMap();
9848
10271
  _show$1 = new WeakMap();
10272
+ _canUndo = new WeakMap();
10273
+ _canRedo = new WeakMap();
9849
10274
  _resizeObserver$1 = new WeakMap();
9850
10275
  _updateOutlineGeometry = new WeakMap();
9851
10276
  _scrollContainers$1 = new WeakMap();
@@ -11041,9 +11466,9 @@ class LatexInlineTooltip {
11041
11466
  doc: innerDoc,
11042
11467
  plugins: [
11043
11468
  keymap.keymap({
11044
- "Mod-z": history.undo,
11045
- "Mod-Z": history.redo,
11046
- "Mod-y": history.redo,
11469
+ "Mod-z": history$1.undo,
11470
+ "Mod-Z": history$1.redo,
11471
+ "Mod-y": history$1.redo,
11047
11472
  Enter: () => {
11048
11473
  if (__privateGet$2(this, _debounceTimer)) {
11049
11474
  clearTimeout(__privateGet$2(this, _debounceTimer));
@@ -11701,7 +12126,7 @@ class CrepeBuilder {
11701
12126
  return nodes.filter((n) => n !== null);
11702
12127
  }
11703
12128
  }));
11704
- }).use(commonmark.commonmark).use(listener.listener).use(history$1.history).use(indent.indent).use(trailing.trailing).use(clipboard.clipboard).use(upload.upload).use(gfm.gfm));
12129
+ }).use(commonmark.commonmark).use(listener.listener).use(history$2.history).use(indent.indent).use(trailing.trailing).use(clipboard.clipboard).use(upload.upload).use(gfm.gfm));
11705
12130
  }
11706
12131
  /// Get the milkdown editor instance.
11707
12132
  get editor() {
@@ -11720,21 +12145,65 @@ class Crepe extends CrepeBuilder {
11720
12145
  /// The constructor of the crepe editor.
11721
12146
  /// You can pass configs to the editor to configure the editor.
11722
12147
  /// Calling the constructor will not create the editor, you need to call `create` to create the editor.
11723
- constructor({
11724
- features = {},
11725
- featureConfigs = {},
11726
- ...crepeBuilderConfig
11727
- } = {}) {
11728
- super(crepeBuilderConfig);
12148
+ constructor(config = {}) {
12149
+ var _a;
12150
+ const { features = {}, featureConfigs = {}, ...crepeBuilderConfig } = config;
11729
12151
  const finalConfigs = lodashEs.defaultsDeep(featureConfigs, defaultConfig);
12152
+ const fixedToolbarConfig = finalConfigs[CrepeFeature.FixedToolbar];
12153
+ if (fixedToolbarConfig == null ? void 0 : fixedToolbarConfig.useLocalStorage) {
12154
+ try {
12155
+ const stored = localStorage.getItem("jvs-milkdown-data");
12156
+ if (stored) {
12157
+ const parsed = JSON.parse(stored);
12158
+ const docId = fixedToolbarConfig.id || "default";
12159
+ if (parsed.content && parsed.content[docId] !== void 0) {
12160
+ const entry = parsed.content[docId];
12161
+ const defaultValue = typeof entry === "string" ? entry : (_a = entry == null ? void 0 : entry.markdown) != null ? _a : "";
12162
+ crepeBuilderConfig.defaultValue = defaultValue;
12163
+ }
12164
+ }
12165
+ } catch (e) {
12166
+ console.error("Error loading content from localStorage:", e);
12167
+ }
12168
+ }
12169
+ super(crepeBuilderConfig);
11730
12170
  const enabledFeatures = Object.entries({
11731
12171
  ...defaultFeatures,
11732
12172
  ...features
11733
12173
  }).filter(([, enabled]) => enabled).map(([feature]) => feature);
11734
12174
  enabledFeatures.forEach((feature) => {
11735
- const config = finalConfigs[feature];
11736
- loadFeature(feature, this.editor, config);
12175
+ const config2 = finalConfigs[feature];
12176
+ loadFeature(feature, this.editor, config2);
11737
12177
  });
12178
+ if (fixedToolbarConfig == null ? void 0 : fixedToolbarConfig.useLocalStorage) {
12179
+ this.on((listener) => {
12180
+ listener.markdownUpdated((_, markdown) => {
12181
+ try {
12182
+ const stored = localStorage.getItem("jvs-milkdown-data");
12183
+ let parsed = {};
12184
+ if (stored) {
12185
+ parsed = JSON.parse(stored);
12186
+ }
12187
+ if (!parsed.content) {
12188
+ parsed.content = {};
12189
+ }
12190
+ const html = this.editor.action(utils$1.getHTML());
12191
+ const docId = fixedToolbarConfig.id || "default";
12192
+ const currentEntry = parsed.content[docId];
12193
+ const hasChanged = !currentEntry || typeof currentEntry === "string" && currentEntry !== markdown || typeof currentEntry === "object" && (currentEntry.markdown !== markdown || currentEntry.html !== html);
12194
+ if (hasChanged) {
12195
+ parsed.content[docId] = {
12196
+ markdown,
12197
+ html
12198
+ };
12199
+ localStorage.setItem("jvs-milkdown-data", JSON.stringify(parsed));
12200
+ }
12201
+ } catch (e) {
12202
+ console.error("Error saving content to localStorage:", e);
12203
+ }
12204
+ });
12205
+ });
12206
+ }
11738
12207
  }
11739
12208
  }
11740
12209
  /// This is an alias for the `CrepeFeature` enum.