@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/esm/index.js CHANGED
@@ -1,12 +1,13 @@
1
+ import { replaceAll, $prose as $prose$1, getHTML } from '@jvs-milkdown/utils';
1
2
  import { defaultsDeep } from 'lodash-es';
2
3
  import { languages } from '@codemirror/language-data';
3
4
  import { oneDark } from '@codemirror/theme-one-dark';
4
5
  import { createSlice } from '@jvs-milkdown/kit/ctx';
5
- import { $ctx, $nodeSchema, $view, $remark, $markAttr, $markSchema, $command, $prose, $useKeymap, $inputRule, getMarkdown } from '@jvs-milkdown/kit/utils';
6
+ import { $ctx, $nodeSchema, $view, $remark, $markAttr, $markSchema, $command, $prose, $useKeymap, getMarkdown, $inputRule } from '@jvs-milkdown/kit/utils';
6
7
  import { defineComponent, shallowRef, ref, computed, h, createApp, watchEffect, watch, onUnmounted, Fragment, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue';
7
8
  import { Icon } from '@jvs-milkdown/kit/component';
8
9
  import { blockConfig, block, BlockProvider } from '@jvs-milkdown/kit/plugin/block';
9
- import { commandsCtx, editorViewCtx, editorCtx, EditorStatus, schemaCtx, parserCtx, editorViewOptionsCtx, Editor, rootCtx, defaultValueCtx } from '@jvs-milkdown/kit/core';
10
+ import { commandsCtx, editorViewCtx, schemaCtx, editorCtx, EditorStatus, parserCtx, editorViewOptionsCtx, Editor, rootCtx, defaultValueCtx } from '@jvs-milkdown/kit/core';
10
11
  import { findNodeInSelection, findParent, nodeRule } from '@jvs-milkdown/kit/prose';
11
12
  import { NodeSelection, TextSelection, Plugin, PluginKey, EditorState, AllSelection } from '@jvs-milkdown/kit/prose/state';
12
13
  import { computePosition, flip, shift, offset } from '@floating-ui/dom';
@@ -25,16 +26,16 @@ import { basicSetup } from 'codemirror';
25
26
  import { dropIndicatorConfig, cursor as cursor$1 } from '@jvs-milkdown/kit/plugin/cursor';
26
27
  import { createVirtualCursor } from 'prosemirror-virtual-cursor';
27
28
  import { diffBlockConfig, diffBlock } from '@jvs-milkdown/kit/component/diff-block';
29
+ import { undo, redo } from '@jvs-milkdown/prose/history';
28
30
  import { Decoration, DecorationSet, EditorView } from '@jvs-milkdown/kit/prose/view';
29
31
  import { mergeCells, splitCell, CellSelection, selectedRect, splitCellWithType } from '@jvs-milkdown/kit/prose/tables';
30
32
  import clsx from 'clsx';
31
33
  import { toggleLinkCommand, configureLinkTooltip, linkTooltipConfig, linkTooltipPlugin } from '@jvs-milkdown/kit/component/link-tooltip';
32
34
  import { inlineImageConfig, imageInlineComponent } from '@jvs-milkdown/kit/component/image-inline';
33
35
  import { Plugin as Plugin$1 } from '@jvs-milkdown/prose/state';
34
- import { $prose as $prose$1 } from '@jvs-milkdown/utils';
35
36
  import * as Diff from 'diff';
36
37
  import { tooltipFactory, TooltipProvider } from '@jvs-milkdown/kit/plugin/tooltip';
37
- import { redo, undo } from '@jvs-milkdown/kit/prose/history';
38
+ import { redo as redo$1, undo as undo$1 } from '@jvs-milkdown/kit/prose/history';
38
39
  import { keymap as keymap$1 } from '@jvs-milkdown/kit/prose/keymap';
39
40
  import { Schema } from '@jvs-milkdown/kit/prose/model';
40
41
  import { textblockTypeInputRule } from '@jvs-milkdown/kit/prose/inputrules';
@@ -649,6 +650,31 @@ const formatPainterIcon = `
649
650
  </svg>
650
651
  `;
651
652
 
653
+ const undoIcon = `
654
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
655
+ <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>
656
+ </svg>
657
+ `;
658
+
659
+ const redoIcon = `
660
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
661
+ <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>
662
+ </svg>
663
+ `;
664
+
665
+ const exportIcon = `
666
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
667
+ <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>
668
+ </svg>
669
+ `;
670
+
671
+ const importIcon = `
672
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
673
+ <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>
674
+ <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>
675
+ </svg>
676
+ `;
677
+
652
678
  const defaultConfig = {
653
679
  [CrepeFeature.CodeMirror]: {
654
680
  theme: oneDark,
@@ -780,6 +806,8 @@ const zhCN = {
780
806
  "customMenu.colorPurple": "\u7D2B\u8272",
781
807
  "customMenu.colorGray": "\u7070\u8272",
782
808
  "customMenu.insertTable": "\u63D2\u5165\u652F\u6301\u5BCC\u6587\u672C\u7684\u8868\u683C",
809
+ "customMenu.export": "\u5BFC\u51FA",
810
+ "customMenu.import": "\u5BFC\u5165",
783
811
  "customMenu.fontDefault": "\u9ED8\u8BA4",
784
812
  "font.fangSong": "\u4EFF\u5B8B",
785
813
  "font.stFangsong": "\u534E\u6587\u4EFF\u5B8B",
@@ -927,6 +955,8 @@ const enUS = {
927
955
  "customMenu.colorPurple": "Purple",
928
956
  "customMenu.colorGray": "Gray",
929
957
  "customMenu.insertTable": "Insert Table",
958
+ "customMenu.export": "Export",
959
+ "customMenu.import": "Import",
930
960
  "customMenu.fontDefault": "Default",
931
961
  "font.fangSong": "FangSong",
932
962
  "font.stFangsong": "STFangsong",
@@ -3071,27 +3101,39 @@ const Menu = defineComponent({
3071
3101
  let activeTextColor = null;
3072
3102
  let activeBgColor = null;
3073
3103
  if (node && node.nodeSize > 2) {
3074
- node.descendants((childNode) => {
3075
- if (childNode.isText) {
3076
- const tcType = textColorSchema.type(ctx);
3077
- const bcType = bgColorSchema.type(ctx);
3078
- if (!activeTextColor) {
3079
- const tcMark = childNode.marks.find((m) => m.type === tcType);
3080
- if (tcMark) activeTextColor = tcMark.attrs.color;
3081
- }
3082
- if (!activeBgColor) {
3083
- const bcMark = childNode.marks.find((m) => m.type === bcType);
3084
- if (bcMark) activeBgColor = bcMark.attrs.color;
3104
+ const schema = ctx.get(schemaCtx);
3105
+ const tcHasMark = schema.marks[textColorSchema.id];
3106
+ const bcHasMark = schema.marks[bgColorSchema.id];
3107
+ if (tcHasMark || bcHasMark) {
3108
+ node.descendants((childNode) => {
3109
+ if (childNode.isText) {
3110
+ if (tcHasMark && !activeTextColor) {
3111
+ const tcType = textColorSchema.type(ctx);
3112
+ const tcMark = childNode.marks.find(
3113
+ (m) => m.type === tcType
3114
+ );
3115
+ if (tcMark) activeTextColor = tcMark.attrs.color;
3116
+ }
3117
+ if (bcHasMark && !activeBgColor) {
3118
+ const bcType = bgColorSchema.type(ctx);
3119
+ const bcMark = childNode.marks.find(
3120
+ (m) => m.type === bcType
3121
+ );
3122
+ if (bcMark) activeBgColor = bcMark.attrs.color;
3123
+ }
3085
3124
  }
3086
- }
3087
- return false;
3088
- });
3125
+ return false;
3126
+ });
3127
+ }
3089
3128
  }
3090
3129
  const setBlockColor = (colorValue, isBg) => {
3091
3130
  if (pos === null || pos === void 0) return;
3092
3131
  const { tr } = view.state;
3093
3132
  const targetNode = tr.doc.nodeAt(pos);
3094
3133
  if (!targetNode) return;
3134
+ const schema = ctx.get(schemaCtx);
3135
+ const hasMark = isBg ? schema.marks[bgColorSchema.id] : schema.marks[textColorSchema.id];
3136
+ if (!hasMark) return;
3095
3137
  const markType = isBg ? bgColorSchema.type(ctx) : textColorSchema.type(ctx);
3096
3138
  const start = pos + 1;
3097
3139
  const end = pos + targetNode.nodeSize - 1;
@@ -3110,10 +3152,17 @@ const Menu = defineComponent({
3110
3152
  const { tr } = view.state;
3111
3153
  const targetNode = tr.doc.nodeAt(pos);
3112
3154
  if (!targetNode) return;
3155
+ const schema = ctx.get(schemaCtx);
3156
+ const tcHasMark = schema.marks[textColorSchema.id];
3157
+ const bcHasMark = schema.marks[bgColorSchema.id];
3113
3158
  const start = pos + 1;
3114
3159
  const end = pos + targetNode.nodeSize - 1;
3115
- tr.removeMark(start, end, textColorSchema.type(ctx));
3116
- tr.removeMark(start, end, bgColorSchema.type(ctx));
3160
+ if (tcHasMark) {
3161
+ tr.removeMark(start, end, textColorSchema.type(ctx));
3162
+ }
3163
+ if (bcHasMark) {
3164
+ tr.removeMark(start, end, bgColorSchema.type(ctx));
3165
+ }
3117
3166
  view.dispatch(tr);
3118
3167
  showColorMenu.value = false;
3119
3168
  hide();
@@ -6144,6 +6193,10 @@ const Toolbar = defineComponent({
6144
6193
  return { textColor: null, bgColor: null };
6145
6194
  const view = ctx.get(editorViewCtx);
6146
6195
  const { state } = view;
6196
+ const schema = ctx.get(schemaCtx);
6197
+ const tcHasMark = schema.marks[textColorSchema.id];
6198
+ const bcHasMark = schema.marks[bgColorSchema.id];
6199
+ if (!tcHasMark || !bcHasMark) return { textColor: null, bgColor: null };
6147
6200
  const tcType = textColorSchema.type(ctx);
6148
6201
  const bcType = bgColorSchema.type(ctx);
6149
6202
  const { $cursor, ranges } = state.selection;
@@ -6188,6 +6241,10 @@ const Toolbar = defineComponent({
6188
6241
  const { state, dispatch } = view;
6189
6242
  const { tr } = state;
6190
6243
  const { from, to, empty } = state.selection;
6244
+ const schema = ctx.get(schemaCtx);
6245
+ const tcHasMark = schema.marks[textColorSchema.id];
6246
+ const bcHasMark = schema.marks[bgColorSchema.id];
6247
+ if (!tcHasMark || !bcHasMark) return;
6191
6248
  const textColorType = textColorSchema.type(ctx);
6192
6249
  const bgColorType = bgColorSchema.type(ctx);
6193
6250
  if (empty) {
@@ -6209,6 +6266,10 @@ const Toolbar = defineComponent({
6209
6266
  return { fontFamily: null, fontSize: null };
6210
6267
  const view = ctx.get(editorViewCtx);
6211
6268
  const { state } = view;
6269
+ const schema = ctx.get(schemaCtx);
6270
+ const ffHasMark = schema.marks[fontFamilySchema.id];
6271
+ const fsHasMark = schema.marks[fontSizeSchema.id];
6272
+ if (!ffHasMark || !fsHasMark) return { fontFamily: null, fontSize: null };
6212
6273
  const ffType = fontFamilySchema.type(ctx);
6213
6274
  const fsType = fontSizeSchema.type(ctx);
6214
6275
  const { $cursor, ranges } = state.selection;
@@ -6616,6 +6677,7 @@ const Toolbar = defineComponent({
6616
6677
  "toolbar-item",
6617
6678
  ctx && checkActive(item.active) && "active"
6618
6679
  ),
6680
+ "data-key": item.key,
6619
6681
  onPointerdown: (e) => {
6620
6682
  if (isTable) {
6621
6683
  e.preventDefault();
@@ -7452,11 +7514,12 @@ const Toolbar = defineComponent({
7452
7514
  (() => {
7453
7515
  const cutoff = overflowVisibleCount.value;
7454
7516
  const items = [];
7455
- const renderIconButton = (iconHtml, title, isActive, onClick2, hasDropdown = false, onMouseEnter, onMouseLeave) => /* @__PURE__ */ h(
7517
+ const renderIconButton = (iconHtml, title, isActive, onClick2, hasDropdown = false, onMouseEnter, onMouseLeave, key) => /* @__PURE__ */ h(
7456
7518
  "button",
7457
7519
  {
7458
7520
  type: "button",
7459
7521
  class: clsx("toolbar-item", isActive && "active"),
7522
+ "data-key": key,
7460
7523
  title,
7461
7524
  onPointerdown: (e) => {
7462
7525
  e.preventDefault();
@@ -7578,7 +7641,8 @@ const Toolbar = defineComponent({
7578
7641
  },
7579
7642
  isTable,
7580
7643
  isTable ? handleTableEnter : void 0,
7581
- isTable ? handleTableLeave : void 0
7644
+ isTable ? handleTableLeave : void 0,
7645
+ item.key
7582
7646
  )
7583
7647
  );
7584
7648
  }
@@ -7758,7 +7822,15 @@ const MenuBar = defineComponent({
7758
7822
  { name: "\u6D45\u7D2B", value: "#F0E6FA" },
7759
7823
  { name: "\u6D45\u7C89", value: "#FDE8E9" }
7760
7824
  ];
7761
- const menuKeys = ["file", "edit", "view", "insert", "format"];
7825
+ const menuKeys = computed(() => {
7826
+ var _a;
7827
+ const allKeys = ["file", "edit", "view", "insert", "format"];
7828
+ const itemsConfig = (_a = props.config) == null ? void 0 : _a.menuBarItems;
7829
+ if (!itemsConfig) return allKeys;
7830
+ return allKeys.filter(
7831
+ (key) => itemsConfig[key] !== false
7832
+ );
7833
+ });
7762
7834
  const hasSubmenu = (key) => key === "view";
7763
7835
  return () => {
7764
7836
  const state = viewState.value;
@@ -7847,7 +7919,7 @@ const MenuBar = defineComponent({
7847
7919
  e.stopPropagation();
7848
7920
  }
7849
7921
  },
7850
- menuKeys.map((menuKey) => {
7922
+ menuKeys.value.map((menuKey) => {
7851
7923
  const isHovered = activeSubmenu.value === menuKey;
7852
7924
  const label = i18n(props.ctx, `menuBar.${menuKey}`) || menuKey;
7853
7925
  return /* @__PURE__ */ h(
@@ -8386,70 +8458,159 @@ const FixedToolbarComponent = defineComponent({
8386
8458
  hide: { type: Function, required: true },
8387
8459
  show: { type: Object, required: true },
8388
8460
  selection: { type: Object, required: true },
8389
- config: { type: Object, required: false }
8461
+ config: { type: Object, required: false },
8462
+ canUndo: { type: Object, required: true },
8463
+ canRedo: { type: Object, required: true }
8390
8464
  },
8391
8465
  setup(props) {
8392
8466
  const showShortcuts = ref(false);
8393
- return () => /* @__PURE__ */ h(
8394
- "div",
8395
- {
8396
- style: {
8397
- display: "flex",
8398
- alignItems: "center",
8399
- justifyContent: "center",
8400
- width: "100%",
8401
- gap: "0px"
8402
- }
8403
- },
8404
- /* @__PURE__ */ h(MenuBar, { ctx: props.ctx, config: props.config }),
8405
- /* @__PURE__ */ h(
8406
- "div",
8407
- {
8408
- style: {
8409
- width: "1px",
8410
- minWidth: "1px",
8411
- height: "20px",
8412
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8413
- }
8414
- }
8415
- ),
8416
- /* @__PURE__ */ h(
8417
- Toolbar,
8418
- {
8419
- ctx: props.ctx,
8420
- hide: props.hide,
8421
- show: props.show,
8422
- selection: props.selection,
8423
- config: props.config,
8424
- isFixed: true
8425
- }
8426
- ),
8427
- /* @__PURE__ */ h(
8467
+ onMounted(() => {
8468
+ const handleShowShortcuts = () => {
8469
+ showShortcuts.value = true;
8470
+ };
8471
+ window.addEventListener("milkdown-show-shortcuts", handleShowShortcuts);
8472
+ onUnmounted(() => {
8473
+ window.removeEventListener(
8474
+ "milkdown-show-shortcuts",
8475
+ handleShowShortcuts
8476
+ );
8477
+ });
8478
+ });
8479
+ return () => {
8480
+ var _a, _b, _c, _d;
8481
+ props.selection.value;
8482
+ const canUndo = (typeof props.canUndo === "boolean" ? props.canUndo : (_a = props.canUndo) == null ? void 0 : _a.value) || false;
8483
+ const canRedo = (typeof props.canRedo === "boolean" ? props.canRedo : (_b = props.canRedo) == null ? void 0 : _b.value) || false;
8484
+ return /* @__PURE__ */ h(
8428
8485
  "div",
8429
8486
  {
8430
8487
  style: {
8431
- width: "1px",
8432
- minWidth: "1px",
8433
- height: "20px",
8434
- flexShrink: 0,
8435
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8436
- }
8437
- }
8438
- ),
8439
- /* @__PURE__ */ h(
8440
- "button",
8441
- {
8442
- type: "button",
8443
- class: "toolbar-shortcut-btn",
8444
- title: i18n(props.ctx, "shortcuts.title"),
8445
- onClick: () => {
8446
- showShortcuts.value = true;
8488
+ display: "flex",
8489
+ alignItems: "center",
8490
+ justifyContent: "center",
8491
+ width: "100%",
8492
+ gap: "0px"
8447
8493
  }
8448
8494
  },
8449
- /* @__PURE__ */ h(Icon, { icon: keyboardIcon })
8450
- ),
8451
- showShortcuts.value && /* @__PURE__ */ h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8452
- );
8495
+ ((_c = props.config) == null ? void 0 : _c.showMenuBar) !== false && [
8496
+ /* @__PURE__ */ h(MenuBar, { ctx: props.ctx, config: props.config }),
8497
+ /* @__PURE__ */ h(
8498
+ "div",
8499
+ {
8500
+ style: {
8501
+ width: "1px",
8502
+ minWidth: "1px",
8503
+ height: "20px",
8504
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8505
+ }
8506
+ }
8507
+ )
8508
+ ],
8509
+ ((_d = props.config) == null ? void 0 : _d.showHistory) !== false && [
8510
+ /* @__PURE__ */ h(
8511
+ "button",
8512
+ {
8513
+ type: "button",
8514
+ class: ["toolbar-item", !canUndo && "disabled"],
8515
+ disabled: !canUndo,
8516
+ title: "\u64A4\u9500",
8517
+ onPointerdown: (e) => {
8518
+ e.preventDefault();
8519
+ e.stopPropagation();
8520
+ },
8521
+ onClick: (e) => {
8522
+ e.preventDefault();
8523
+ e.stopPropagation();
8524
+ if (canUndo) {
8525
+ props.ctx.get(commandsCtx).call("Undo");
8526
+ }
8527
+ },
8528
+ style: {
8529
+ display: "flex",
8530
+ alignItems: "center",
8531
+ justifyContent: "center",
8532
+ border: "none",
8533
+ background: "transparent",
8534
+ cursor: canUndo ? "pointer" : "default",
8535
+ padding: "6px",
8536
+ borderRadius: "4px",
8537
+ color: canUndo ? "#363b4c" : "#c0c4cc",
8538
+ "--toolbar-icon-color": canUndo ? "#363b4c" : "#c0c4cc"
8539
+ }
8540
+ },
8541
+ /* @__PURE__ */ h(
8542
+ "span",
8543
+ {
8544
+ style: { display: "inline-flex", alignItems: "center" },
8545
+ innerHTML: undoIcon
8546
+ }
8547
+ )
8548
+ ),
8549
+ /* @__PURE__ */ h(
8550
+ "button",
8551
+ {
8552
+ type: "button",
8553
+ class: ["toolbar-item", !canRedo && "disabled"],
8554
+ disabled: !canRedo,
8555
+ title: "\u6062\u590D",
8556
+ onPointerdown: (e) => {
8557
+ e.preventDefault();
8558
+ e.stopPropagation();
8559
+ },
8560
+ onClick: (e) => {
8561
+ e.preventDefault();
8562
+ e.stopPropagation();
8563
+ if (canRedo) {
8564
+ props.ctx.get(commandsCtx).call("Redo");
8565
+ }
8566
+ },
8567
+ style: {
8568
+ display: "flex",
8569
+ alignItems: "center",
8570
+ justifyContent: "center",
8571
+ border: "none",
8572
+ background: "transparent",
8573
+ cursor: canRedo ? "pointer" : "default",
8574
+ padding: "6px",
8575
+ borderRadius: "4px",
8576
+ color: canRedo ? "#363b4c" : "#c0c4cc",
8577
+ "--toolbar-icon-color": canRedo ? "#363b4c" : "#c0c4cc"
8578
+ }
8579
+ },
8580
+ /* @__PURE__ */ h(
8581
+ "span",
8582
+ {
8583
+ style: { display: "inline-flex", alignItems: "center" },
8584
+ innerHTML: redoIcon
8585
+ }
8586
+ )
8587
+ ),
8588
+ /* @__PURE__ */ h(
8589
+ "div",
8590
+ {
8591
+ style: {
8592
+ width: "1px",
8593
+ minWidth: "1px",
8594
+ height: "20px",
8595
+ backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8596
+ }
8597
+ }
8598
+ )
8599
+ ],
8600
+ /* @__PURE__ */ h(
8601
+ Toolbar,
8602
+ {
8603
+ ctx: props.ctx,
8604
+ hide: props.hide,
8605
+ show: props.show,
8606
+ selection: props.selection,
8607
+ config: props.config,
8608
+ isFixed: true
8609
+ }
8610
+ ),
8611
+ showShortcuts.value && /* @__PURE__ */ h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8612
+ );
8613
+ };
8453
8614
  }
8454
8615
  });
8455
8616
 
@@ -8875,6 +9036,65 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8875
9036
  }
8876
9037
  });
8877
9038
  }
9039
+ const documentGroup = builder.addGroup("document", "Document");
9040
+ if ((_config == null ? void 0 : _config.showExport) !== false) {
9041
+ documentGroup.addItem("export", {
9042
+ label: ctx ? i18n(ctx, "customMenu.export") || "\u5BFC\u51FA" : "\u5BFC\u51FA",
9043
+ icon: exportIcon,
9044
+ active: () => false,
9045
+ onRun: (ctx2) => {
9046
+ const markdown = getMarkdown()(ctx2);
9047
+ if (_config == null ? void 0 : _config.onExport) {
9048
+ _config.onExport(markdown, ctx2);
9049
+ } else {
9050
+ const blob = new Blob([markdown], {
9051
+ type: "text/markdown;charset=utf-8;"
9052
+ });
9053
+ const url = URL.createObjectURL(blob);
9054
+ const link = document.createElement("a");
9055
+ link.href = url;
9056
+ link.download = "document.md";
9057
+ link.click();
9058
+ URL.revokeObjectURL(url);
9059
+ }
9060
+ }
9061
+ });
9062
+ }
9063
+ if ((_config == null ? void 0 : _config.showImport) !== false) {
9064
+ documentGroup.addItem("import", {
9065
+ label: ctx ? i18n(ctx, "customMenu.import") || "\u5BFC\u5165" : "\u5BFC\u5165",
9066
+ icon: importIcon,
9067
+ active: () => false,
9068
+ onRun: (ctx2) => {
9069
+ if (_config == null ? void 0 : _config.onImport) {
9070
+ _config.onImport((markdown) => replaceAll(markdown)(ctx2), ctx2);
9071
+ } else {
9072
+ const input = document.createElement("input");
9073
+ input.type = "file";
9074
+ input.accept = ".md";
9075
+ input.onchange = (e) => {
9076
+ var _a;
9077
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
9078
+ if (!file) return;
9079
+ file.text().then((text) => {
9080
+ replaceAll(text)(ctx2);
9081
+ }).catch((err) => {
9082
+ console.error("Failed to read file:", err);
9083
+ });
9084
+ };
9085
+ input.click();
9086
+ }
9087
+ }
9088
+ });
9089
+ }
9090
+ documentGroup.addItem("shortcuts", {
9091
+ label: ctx ? i18n(ctx, "shortcuts.title") : "Shortcuts",
9092
+ icon: keyboardIcon,
9093
+ active: () => false,
9094
+ onRun: () => {
9095
+ window.dispatchEvent(new CustomEvent("milkdown-show-shortcuts"));
9096
+ }
9097
+ });
8878
9098
  return builder.build();
8879
9099
  }
8880
9100
 
@@ -9184,6 +9404,11 @@ const OutlinePanel = defineComponent({
9184
9404
  const activeId = ref("");
9185
9405
  const collapsedIds = ref(/* @__PURE__ */ new Set());
9186
9406
  let scrollLock = false;
9407
+ const clickedActiveId = ref(null);
9408
+ const clearClickedActive = () => {
9409
+ if (scrollLock) return;
9410
+ clickedActiveId.value = null;
9411
+ };
9187
9412
  const hasChildren = (index) => {
9188
9413
  const current = items.value[index];
9189
9414
  if (!current) return false;
@@ -9238,6 +9463,10 @@ const OutlinePanel = defineComponent({
9238
9463
  if (scrollLock) return;
9239
9464
  const view = props.ctx.get(editorViewCtx);
9240
9465
  if (!view || !view.dom) return;
9466
+ if (clickedActiveId.value) {
9467
+ activeId.value = clickedActiveId.value;
9468
+ return;
9469
+ }
9241
9470
  const headings = Array.from(
9242
9471
  view.dom.querySelectorAll("h1, h2, h3, h4, h5, h6")
9243
9472
  );
@@ -9245,14 +9474,39 @@ const OutlinePanel = defineComponent({
9245
9474
  activeId.value = "";
9246
9475
  return;
9247
9476
  }
9248
- const scrollContainer = view.dom.parentElement;
9249
- if (!scrollContainer) return;
9250
- const toolbar = scrollContainer.querySelector(
9477
+ let scrollContainer = view.dom.parentElement;
9478
+ while (scrollContainer && scrollContainer !== document.body) {
9479
+ const style = window.getComputedStyle(scrollContainer);
9480
+ const overflowY = style.overflowY;
9481
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9482
+ break;
9483
+ }
9484
+ scrollContainer = scrollContainer.parentElement;
9485
+ }
9486
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9487
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9488
+ const rootNode = view.dom.getRootNode();
9489
+ let toolbar = rootNode.querySelector(
9251
9490
  ".milkdown-fixed-toolbar"
9252
9491
  );
9492
+ if (!toolbar) {
9493
+ toolbar = document.querySelector(
9494
+ ".milkdown-fixed-toolbar"
9495
+ );
9496
+ }
9253
9497
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9254
- const containerRect = scrollContainer.getBoundingClientRect();
9255
- const threshold = containerRect.top + toolbarHeight + 50;
9498
+ const containerRect = actualScrollContainer.getBoundingClientRect();
9499
+ const containerTop = isRootScroll ? 0 : Math.max(0, containerRect.top);
9500
+ let scrollTop = actualScrollContainer.scrollTop;
9501
+ let clientHeight = actualScrollContainer.clientHeight;
9502
+ let scrollHeight = actualScrollContainer.scrollHeight;
9503
+ if (isRootScroll) {
9504
+ scrollTop = window.scrollY || document.documentElement.scrollTop;
9505
+ clientHeight = window.innerHeight || document.documentElement.clientHeight;
9506
+ scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
9507
+ }
9508
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight - 15;
9509
+ const threshold = isAtBottom ? containerTop + clientHeight : containerTop + toolbarHeight + 50;
9256
9510
  let active = headings[0];
9257
9511
  for (const h2 of headings) {
9258
9512
  const rect = h2.getBoundingClientRect();
@@ -9262,43 +9516,120 @@ const OutlinePanel = defineComponent({
9262
9516
  break;
9263
9517
  }
9264
9518
  }
9265
- activeId.value = (active == null ? void 0 : active.id) || "";
9519
+ const activeItem = items.value.find((item) => {
9520
+ try {
9521
+ const activePos = view.posAtDOM(active, 0);
9522
+ const isPosMatch = item.pos === activePos - 1;
9523
+ let isDepthMatch = false;
9524
+ const $pos = view.state.doc.resolve(activePos);
9525
+ for (let d = $pos.depth; d >= 0; d--) {
9526
+ if ($pos.node(d).type.name === "heading") {
9527
+ if (item.pos === $pos.before(d)) {
9528
+ isDepthMatch = true;
9529
+ break;
9530
+ }
9531
+ }
9532
+ }
9533
+ if (isPosMatch || isDepthMatch) {
9534
+ return true;
9535
+ }
9536
+ } catch (e) {
9537
+ }
9538
+ const dom = view.nodeDOM(item.pos);
9539
+ const domMatch = dom === active || dom instanceof HTMLElement && active && dom.contains(active);
9540
+ if (domMatch) {
9541
+ return true;
9542
+ }
9543
+ return false;
9544
+ });
9545
+ const newActiveId = activeItem ? activeItem.id : (active == null ? void 0 : active.id) || "";
9546
+ activeId.value = newActiveId;
9266
9547
  };
9267
- const scrollToHeading = (id) => {
9548
+ const scrollToHeading = (item) => {
9268
9549
  const view = props.ctx.get(editorViewCtx);
9269
9550
  if (!view) return;
9270
9551
  try {
9271
- const headingEl = view.dom.querySelector(
9272
- `[id="${id}"]`
9273
- );
9552
+ let headingEl = view.nodeDOM(item.pos);
9553
+ if (!headingEl) {
9554
+ try {
9555
+ const domAt = view.domAtPos(item.pos);
9556
+ let node = domAt.node;
9557
+ if (node.nodeType === Node.TEXT_NODE) {
9558
+ node = node.parentElement;
9559
+ }
9560
+ if (node instanceof HTMLElement) {
9561
+ headingEl = node.closest(
9562
+ "h1, h2, h3, h4, h5, h6"
9563
+ );
9564
+ if (!headingEl && domAt.offset < node.childNodes.length) {
9565
+ const child = node.childNodes[domAt.offset];
9566
+ if (child instanceof HTMLElement) {
9567
+ headingEl = child.closest("h1, h2, h3, h4, h5, h6") || child.querySelector(
9568
+ "h1, h2, h3, h4, h5, h6"
9569
+ );
9570
+ }
9571
+ }
9572
+ }
9573
+ } catch (e) {
9574
+ }
9575
+ }
9576
+ if (!headingEl) {
9577
+ headingEl = view.dom.querySelector(
9578
+ `[id="${item.id}"]`
9579
+ );
9580
+ }
9274
9581
  if (!headingEl) return;
9275
- const scrollContainer = view.dom.parentElement;
9276
- if (!scrollContainer) return;
9582
+ let scrollContainer = view.dom.parentElement;
9583
+ while (scrollContainer && scrollContainer !== document.body) {
9584
+ const style = window.getComputedStyle(scrollContainer);
9585
+ const overflowY = style.overflowY;
9586
+ if ((overflowY === "auto" || overflowY === "scroll") && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
9587
+ break;
9588
+ }
9589
+ scrollContainer = scrollContainer.parentElement;
9590
+ }
9591
+ const isRootScroll = !scrollContainer || scrollContainer === document.body || scrollContainer === document.documentElement;
9592
+ const actualScrollContainer = isRootScroll ? document.scrollingElement || document.documentElement || document.body : scrollContainer;
9277
9593
  scrollLock = true;
9278
- const toolbar = scrollContainer.querySelector(
9594
+ const rootNode = view.dom.getRootNode();
9595
+ let toolbar = rootNode.querySelector(
9279
9596
  ".milkdown-fixed-toolbar"
9280
9597
  );
9598
+ if (!toolbar) {
9599
+ toolbar = document.querySelector(
9600
+ ".milkdown-fixed-toolbar"
9601
+ );
9602
+ }
9281
9603
  const toolbarHeight = (toolbar == null ? void 0 : toolbar.offsetHeight) || 0;
9282
- const containerRect = scrollContainer.getBoundingClientRect();
9604
+ const containerRectTop = isRootScroll ? 0 : actualScrollContainer.getBoundingClientRect().top;
9283
9605
  const headingRect = headingEl.getBoundingClientRect();
9284
- scrollContainer.scrollTo({
9285
- top: scrollContainer.scrollTop + headingRect.top - containerRect.top - toolbarHeight - 20,
9286
- behavior: "smooth"
9287
- });
9606
+ const targetTop = actualScrollContainer.scrollTop + headingRect.top - containerRectTop - toolbarHeight - 20;
9607
+ const scrollTarget = isRootScroll ? window : actualScrollContainer;
9288
9608
  let timer;
9289
9609
  const onScrollEnd = () => {
9290
9610
  clearTimeout(timer);
9291
9611
  timer = setTimeout(() => {
9292
9612
  scrollLock = false;
9293
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9613
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9294
9614
  checkActive();
9295
9615
  }, 150);
9296
9616
  };
9297
- scrollContainer.addEventListener("scroll", onScrollEnd);
9617
+ scrollTarget.addEventListener("scroll", onScrollEnd);
9298
9618
  setTimeout(() => {
9299
9619
  scrollLock = false;
9300
- scrollContainer.removeEventListener("scroll", onScrollEnd);
9620
+ scrollTarget.removeEventListener("scroll", onScrollEnd);
9301
9621
  }, 2e3);
9622
+ if (isRootScroll) {
9623
+ window.scrollTo({
9624
+ top: targetTop,
9625
+ behavior: "smooth"
9626
+ });
9627
+ } else {
9628
+ actualScrollContainer.scrollTo({
9629
+ top: targetTop,
9630
+ behavior: "smooth"
9631
+ });
9632
+ }
9302
9633
  } catch (e) {
9303
9634
  scrollLock = false;
9304
9635
  updateOutline();
@@ -9309,6 +9640,27 @@ const OutlinePanel = defineComponent({
9309
9640
  onMounted(() => {
9310
9641
  updateOutline();
9311
9642
  checkActive();
9643
+ window.addEventListener("wheel", clearClickedActive, { passive: true });
9644
+ window.addEventListener("touchmove", clearClickedActive, {
9645
+ passive: true
9646
+ });
9647
+ window.addEventListener("pointerdown", clearClickedActive, {
9648
+ passive: true
9649
+ });
9650
+ const keyHandler = (e) => {
9651
+ if ([
9652
+ "ArrowUp",
9653
+ "ArrowDown",
9654
+ "PageUp",
9655
+ "PageDown",
9656
+ "Home",
9657
+ "End"
9658
+ ].includes(e.key)) {
9659
+ clearClickedActive();
9660
+ }
9661
+ };
9662
+ window.addEventListener("keydown", keyHandler, { passive: true });
9663
+ onMounted._keyHandler = keyHandler;
9312
9664
  interval = setInterval(() => {
9313
9665
  if (viewState.value.outlineVisible) {
9314
9666
  updateOutline();
@@ -9325,6 +9677,13 @@ const OutlinePanel = defineComponent({
9325
9677
  if (interval) clearInterval(interval);
9326
9678
  if (pollInterval) clearInterval(pollInterval);
9327
9679
  window.removeEventListener("scroll", checkActive, true);
9680
+ window.removeEventListener("wheel", clearClickedActive);
9681
+ window.removeEventListener("touchmove", clearClickedActive);
9682
+ window.removeEventListener("pointerdown", clearClickedActive);
9683
+ const keyHandler = onMounted._keyHandler;
9684
+ if (keyHandler) {
9685
+ window.removeEventListener("keydown", keyHandler);
9686
+ }
9328
9687
  });
9329
9688
  let startX = 0;
9330
9689
  let startWidth = 0;
@@ -9452,7 +9811,8 @@ const OutlinePanel = defineComponent({
9452
9811
  key: item.id,
9453
9812
  onClick: () => {
9454
9813
  activeId.value = item.id;
9455
- scrollToHeading(item.id);
9814
+ clickedActiveId.value = item.id;
9815
+ scrollToHeading(item);
9456
9816
  },
9457
9817
  style: {
9458
9818
  display: "flex",
@@ -9509,7 +9869,7 @@ const OutlinePanel = defineComponent({
9509
9869
  e.currentTarget.style.backgroundColor = "transparent";
9510
9870
  }
9511
9871
  },
9512
- "\uFFFD?",
9872
+ "\u25BC",
9513
9873
  " "
9514
9874
  ),
9515
9875
  /* @__PURE__ */ h(
@@ -9564,7 +9924,7 @@ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Ca
9564
9924
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9565
9925
  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);
9566
9926
  var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
9567
- var _content$2, _app$2, _headerContent, _headerApp, _outlineContent, _outlineApp, _watcher, _selection$1, _show$1, _resizeObserver$1, _updateOutlineGeometry, _scrollContainers$1, _onDblClick, _view$1, _editorContainer;
9927
+ 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;
9568
9928
  const fixedToolbarConfig = $ctx(
9569
9929
  {},
9570
9930
  "fixedToolbarConfigCtx"
@@ -9581,6 +9941,8 @@ class FixedToolbarView {
9581
9941
  __privateAdd$4(this, _watcher);
9582
9942
  __privateAdd$4(this, _selection$1);
9583
9943
  __privateAdd$4(this, _show$1, ref(true));
9944
+ __privateAdd$4(this, _canUndo, ref(false));
9945
+ __privateAdd$4(this, _canRedo, ref(false));
9584
9946
  __privateAdd$4(this, _resizeObserver$1);
9585
9947
  __privateAdd$4(this, _updateOutlineGeometry);
9586
9948
  __privateAdd$4(this, _scrollContainers$1, []);
@@ -9589,6 +9951,11 @@ class FixedToolbarView {
9589
9951
  __privateAdd$4(this, _editorContainer);
9590
9952
  this.update = (view) => {
9591
9953
  __privateGet$4(this, _selection$1).value = view.state.selection;
9954
+ try {
9955
+ __privateGet$4(this, _canUndo).value = undo(view.state);
9956
+ __privateGet$4(this, _canRedo).value = redo(view.state);
9957
+ } catch (e) {
9958
+ }
9592
9959
  };
9593
9960
  this.destroy = () => {
9594
9961
  if (__privateGet$4(this, _watcher)) __privateGet$4(this, _watcher).call(this);
@@ -9613,6 +9980,60 @@ class FixedToolbarView {
9613
9980
  };
9614
9981
  __privateSet$4(this, _view$1, view);
9615
9982
  const config = ctx.get(fixedToolbarConfig.key);
9983
+ const viewState = ctx.get(viewMenuStateCtx.key);
9984
+ if (config == null ? void 0 : config.useLocalStorage) {
9985
+ try {
9986
+ const stored = localStorage.getItem("jvs-milkdown-data");
9987
+ if (stored) {
9988
+ const parsed = JSON.parse(stored);
9989
+ if (parsed.outlineVisible !== void 0)
9990
+ viewState.outlineVisible = parsed.outlineVisible;
9991
+ if (parsed.outlinePosition !== void 0)
9992
+ viewState.outlinePosition = parsed.outlinePosition;
9993
+ if (parsed.outlineWidth !== void 0)
9994
+ viewState.outlineWidth = parsed.outlineWidth;
9995
+ if (parsed.documentBackground !== void 0)
9996
+ viewState.documentBackground = parsed.documentBackground;
9997
+ if (parsed.showTitle !== void 0)
9998
+ viewState.showTitle = parsed.showTitle;
9999
+ if (parsed.showCover !== void 0)
10000
+ viewState.showCover = parsed.showCover;
10001
+ if (parsed.coverUrl !== void 0)
10002
+ viewState.coverUrl = parsed.coverUrl;
10003
+ if (parsed.editorWidth !== void 0)
10004
+ viewState.editorWidth = parsed.editorWidth;
10005
+ }
10006
+ } catch (e) {
10007
+ console.error("Error loading view state from localStorage:", e);
10008
+ }
10009
+ watch(
10010
+ viewState,
10011
+ (newState) => {
10012
+ try {
10013
+ const stored = localStorage.getItem("jvs-milkdown-data");
10014
+ let parsed = {};
10015
+ if (stored) {
10016
+ parsed = JSON.parse(stored);
10017
+ }
10018
+ const merged = {
10019
+ ...parsed,
10020
+ outlineVisible: newState.outlineVisible,
10021
+ outlinePosition: newState.outlinePosition,
10022
+ outlineWidth: newState.outlineWidth,
10023
+ documentBackground: newState.documentBackground,
10024
+ showTitle: newState.showTitle,
10025
+ showCover: newState.showCover,
10026
+ coverUrl: newState.coverUrl,
10027
+ editorWidth: newState.editorWidth
10028
+ };
10029
+ localStorage.setItem("jvs-milkdown-data", JSON.stringify(merged));
10030
+ } catch (e) {
10031
+ console.error("Error saving view state to localStorage:", e);
10032
+ }
10033
+ },
10034
+ { deep: true }
10035
+ );
10036
+ }
9616
10037
  const content = document.createElement("div");
9617
10038
  content.className = "milkdown-fixed-toolbar";
9618
10039
  __privateSet$4(this, _selection$1, shallowRef(view.state.selection));
@@ -9623,7 +10044,9 @@ class FixedToolbarView {
9623
10044
  // No-op for fixed toolbar
9624
10045
  config,
9625
10046
  selection: __privateGet$4(this, _selection$1),
9626
- show: __privateGet$4(this, _show$1)
10047
+ show: __privateGet$4(this, _show$1),
10048
+ canUndo: __privateGet$4(this, _canUndo),
10049
+ canRedo: __privateGet$4(this, _canRedo)
9627
10050
  });
9628
10051
  app.mount(content);
9629
10052
  __privateSet$4(this, _content$2, content);
@@ -9680,9 +10103,9 @@ class FixedToolbarView {
9680
10103
  });
9681
10104
  view.dom.addEventListener("dblclick", __privateGet$4(this, _onDblClick));
9682
10105
  __privateGet$4(this, _content$2).style.transition = "margin 0.1s ease-out, width 0.1s ease-out";
9683
- const viewState = ctx.get(viewMenuStateCtx.key);
10106
+ const viewState2 = ctx.get(viewMenuStateCtx.key);
9684
10107
  if (config.outlinePosition) {
9685
- viewState.outlinePosition = config.outlinePosition;
10108
+ viewState2.outlinePosition = config.outlinePosition;
9686
10109
  }
9687
10110
  __privateSet$4(this, _updateOutlineGeometry, () => {
9688
10111
  const rootRect = root.getBoundingClientRect();
@@ -9691,7 +10114,7 @@ class FixedToolbarView {
9691
10114
  const toolbarRect = __privateGet$4(this, _content$2).getBoundingClientRect();
9692
10115
  outlineTop = Math.max(outlineTop, toolbarRect.bottom);
9693
10116
  }
9694
- if (viewState.showCover && __privateGet$4(this, _headerContent)) {
10117
+ if (viewState2.showCover && __privateGet$4(this, _headerContent)) {
9695
10118
  const coverEl = __privateGet$4(this, _headerContent).querySelector(
9696
10119
  ".milkdown-document-cover"
9697
10120
  );
@@ -9708,8 +10131,8 @@ class FixedToolbarView {
9708
10131
  }
9709
10132
  outlineContent.style.top = `${outlineTop}px`;
9710
10133
  outlineContent.style.height = `${height}px`;
9711
- if (viewState.outlineVisible) {
9712
- if (viewState.outlinePosition === "left") {
10134
+ if (viewState2.outlineVisible) {
10135
+ if (viewState2.outlinePosition === "left") {
9713
10136
  outlineContent.style.left = `${rootRect.left}px`;
9714
10137
  outlineContent.style.right = "auto";
9715
10138
  } else {
@@ -9759,16 +10182,16 @@ class FixedToolbarView {
9759
10182
  }
9760
10183
  __privateSet$4(this, _watcher, watch(
9761
10184
  () => [
9762
- viewState.outlineVisible,
9763
- viewState.outlinePosition,
9764
- viewState.outlineWidth,
9765
- viewState.documentBackground,
9766
- viewState.showCover,
9767
- viewState.editorWidth
10185
+ viewState2.outlineVisible,
10186
+ viewState2.outlinePosition,
10187
+ viewState2.outlineWidth,
10188
+ viewState2.documentBackground,
10189
+ viewState2.showCover,
10190
+ viewState2.editorWidth
9768
10191
  ],
9769
10192
  () => {
9770
- if (viewState.documentBackground) {
9771
- root.style.backgroundColor = viewState.documentBackground;
10193
+ if (viewState2.documentBackground) {
10194
+ root.style.backgroundColor = viewState2.documentBackground;
9772
10195
  } else {
9773
10196
  root.style.backgroundColor = "";
9774
10197
  }
@@ -9778,20 +10201,20 @@ class FixedToolbarView {
9778
10201
  __privateGet$4(this, _content$2).style.marginLeft = "0";
9779
10202
  __privateGet$4(this, _content$2).style.marginRight = "0";
9780
10203
  if (__privateGet$4(this, _editorContainer)) {
9781
- if (viewState.outlineVisible) {
9782
- if (viewState.outlinePosition === "left") {
9783
- __privateGet$4(this, _editorContainer).style.paddingLeft = `${viewState.outlineWidth}px`;
10204
+ if (viewState2.outlineVisible) {
10205
+ if (viewState2.outlinePosition === "left") {
10206
+ __privateGet$4(this, _editorContainer).style.paddingLeft = `${viewState2.outlineWidth}px`;
9784
10207
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9785
10208
  } else {
9786
10209
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9787
- __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState.outlineWidth}px`;
10210
+ __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState2.outlineWidth}px`;
9788
10211
  }
9789
10212
  } else {
9790
10213
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9791
10214
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9792
10215
  }
9793
10216
  }
9794
- const maxWidth = editorWidthMap[viewState.editorWidth];
10217
+ const maxWidth = editorWidthMap[viewState2.editorWidth];
9795
10218
  const isFull = maxWidth === "none";
9796
10219
  const px = isFull ? "80px" : "0";
9797
10220
  __privateGet$4(this, _view$1).dom.style.maxWidth = maxWidth;
@@ -9799,7 +10222,7 @@ class FixedToolbarView {
9799
10222
  __privateGet$4(this, _view$1).dom.style.margin = isFull ? "0" : "0 auto";
9800
10223
  __privateGet$4(this, _view$1).dom.style.padding = `20px ${px} 36px`;
9801
10224
  if (__privateGet$4(this, _headerContent)) {
9802
- __privateGet$4(this, _headerContent).style.margin = isFull && !viewState.showCover ? "0 auto" : "0";
10225
+ __privateGet$4(this, _headerContent).style.margin = isFull && !viewState2.showCover ? "0 auto" : "0";
9803
10226
  __privateGet$4(this, _headerContent).style.padding = `0px`;
9804
10227
  }
9805
10228
  void nextTick(() => {
@@ -9825,6 +10248,8 @@ _outlineApp = new WeakMap();
9825
10248
  _watcher = new WeakMap();
9826
10249
  _selection$1 = new WeakMap();
9827
10250
  _show$1 = new WeakMap();
10251
+ _canUndo = new WeakMap();
10252
+ _canRedo = new WeakMap();
9828
10253
  _resizeObserver$1 = new WeakMap();
9829
10254
  _updateOutlineGeometry = new WeakMap();
9830
10255
  _scrollContainers$1 = new WeakMap();
@@ -11020,9 +11445,9 @@ class LatexInlineTooltip {
11020
11445
  doc: innerDoc,
11021
11446
  plugins: [
11022
11447
  keymap$1({
11023
- "Mod-z": undo,
11024
- "Mod-Z": redo,
11025
- "Mod-y": redo,
11448
+ "Mod-z": undo$1,
11449
+ "Mod-Z": redo$1,
11450
+ "Mod-y": redo$1,
11026
11451
  Enter: () => {
11027
11452
  if (__privateGet$2(this, _debounceTimer)) {
11028
11453
  clearTimeout(__privateGet$2(this, _debounceTimer));
@@ -11699,21 +12124,65 @@ class Crepe extends CrepeBuilder {
11699
12124
  /// The constructor of the crepe editor.
11700
12125
  /// You can pass configs to the editor to configure the editor.
11701
12126
  /// Calling the constructor will not create the editor, you need to call `create` to create the editor.
11702
- constructor({
11703
- features = {},
11704
- featureConfigs = {},
11705
- ...crepeBuilderConfig
11706
- } = {}) {
11707
- super(crepeBuilderConfig);
12127
+ constructor(config = {}) {
12128
+ var _a;
12129
+ const { features = {}, featureConfigs = {}, ...crepeBuilderConfig } = config;
11708
12130
  const finalConfigs = defaultsDeep(featureConfigs, defaultConfig);
12131
+ const fixedToolbarConfig = finalConfigs[CrepeFeature.FixedToolbar];
12132
+ if (fixedToolbarConfig == null ? void 0 : fixedToolbarConfig.useLocalStorage) {
12133
+ try {
12134
+ const stored = localStorage.getItem("jvs-milkdown-data");
12135
+ if (stored) {
12136
+ const parsed = JSON.parse(stored);
12137
+ const docId = fixedToolbarConfig.id || "default";
12138
+ if (parsed.content && parsed.content[docId] !== void 0) {
12139
+ const entry = parsed.content[docId];
12140
+ const defaultValue = typeof entry === "string" ? entry : (_a = entry == null ? void 0 : entry.markdown) != null ? _a : "";
12141
+ crepeBuilderConfig.defaultValue = defaultValue;
12142
+ }
12143
+ }
12144
+ } catch (e) {
12145
+ console.error("Error loading content from localStorage:", e);
12146
+ }
12147
+ }
12148
+ super(crepeBuilderConfig);
11709
12149
  const enabledFeatures = Object.entries({
11710
12150
  ...defaultFeatures,
11711
12151
  ...features
11712
12152
  }).filter(([, enabled]) => enabled).map(([feature]) => feature);
11713
12153
  enabledFeatures.forEach((feature) => {
11714
- const config = finalConfigs[feature];
11715
- loadFeature(feature, this.editor, config);
12154
+ const config2 = finalConfigs[feature];
12155
+ loadFeature(feature, this.editor, config2);
11716
12156
  });
12157
+ if (fixedToolbarConfig == null ? void 0 : fixedToolbarConfig.useLocalStorage) {
12158
+ this.on((listener) => {
12159
+ listener.markdownUpdated((_, markdown) => {
12160
+ try {
12161
+ const stored = localStorage.getItem("jvs-milkdown-data");
12162
+ let parsed = {};
12163
+ if (stored) {
12164
+ parsed = JSON.parse(stored);
12165
+ }
12166
+ if (!parsed.content) {
12167
+ parsed.content = {};
12168
+ }
12169
+ const html = this.editor.action(getHTML());
12170
+ const docId = fixedToolbarConfig.id || "default";
12171
+ const currentEntry = parsed.content[docId];
12172
+ const hasChanged = !currentEntry || typeof currentEntry === "string" && currentEntry !== markdown || typeof currentEntry === "object" && (currentEntry.markdown !== markdown || currentEntry.html !== html);
12173
+ if (hasChanged) {
12174
+ parsed.content[docId] = {
12175
+ markdown,
12176
+ html
12177
+ };
12178
+ localStorage.setItem("jvs-milkdown-data", JSON.stringify(parsed));
12179
+ }
12180
+ } catch (e) {
12181
+ console.error("Error saving content to localStorage:", e);
12182
+ }
12183
+ });
12184
+ });
12185
+ }
11717
12186
  }
11718
12187
  }
11719
12188
  /// This is an alias for the `CrepeFeature` enum.