@jvs-milkdown/crepe 1.2.17 → 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 (89) 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 +4 -0
  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 +9 -2
  24. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  25. package/lib/cjs/index.js +394 -96
  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 +4 -0
  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 +9 -2
  50. package/lib/esm/feature/toolbar/index.js.map +1 -1
  51. package/lib/esm/index.js +393 -95
  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/fixed-toolbar/component.d.ts +2 -0
  60. package/lib/types/feature/fixed-toolbar/component.d.ts.map +1 -1
  61. package/lib/types/feature/fixed-toolbar/config.d.ts.map +1 -1
  62. package/lib/types/feature/fixed-toolbar/index.d.ts +16 -0
  63. package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
  64. package/lib/types/feature/fixed-toolbar/menu-bar.d.ts.map +1 -1
  65. package/lib/types/feature/toolbar/component.d.ts.map +1 -1
  66. package/lib/types/icons/export.d.ts +2 -0
  67. package/lib/types/icons/export.d.ts.map +1 -0
  68. package/lib/types/icons/import.d.ts +2 -0
  69. package/lib/types/icons/import.d.ts.map +1 -0
  70. package/lib/types/icons/index.d.ts +4 -0
  71. package/lib/types/icons/index.d.ts.map +1 -1
  72. package/lib/types/icons/redo.d.ts +2 -0
  73. package/lib/types/icons/redo.d.ts.map +1 -0
  74. package/lib/types/icons/undo.d.ts +2 -0
  75. package/lib/types/icons/undo.d.ts.map +1 -0
  76. package/package.json +4 -4
  77. package/src/core/crepe.ts +60 -7
  78. package/src/core/locale.ts +4 -0
  79. package/src/feature/fixed-toolbar/component.tsx +155 -51
  80. package/src/feature/fixed-toolbar/config.ts +70 -2
  81. package/src/feature/fixed-toolbar/index.ts +86 -1
  82. package/src/feature/fixed-toolbar/menu-bar.tsx +18 -3
  83. package/src/feature/toolbar/component.tsx +6 -2
  84. package/src/icons/export.ts +5 -0
  85. package/src/icons/import.ts +6 -0
  86. package/src/icons/index.ts +4 -0
  87. package/src/icons/redo.ts +5 -0
  88. package/src/icons/undo.ts +5 -0
  89. 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",
@@ -6668,6 +6698,7 @@ const Toolbar = vue.defineComponent({
6668
6698
  "toolbar-item",
6669
6699
  ctx && checkActive(item.active) && "active"
6670
6700
  ),
6701
+ "data-key": item.key,
6671
6702
  onPointerdown: (e) => {
6672
6703
  if (isTable) {
6673
6704
  e.preventDefault();
@@ -7504,11 +7535,12 @@ const Toolbar = vue.defineComponent({
7504
7535
  (() => {
7505
7536
  const cutoff = overflowVisibleCount.value;
7506
7537
  const items = [];
7507
- 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(
7508
7539
  "button",
7509
7540
  {
7510
7541
  type: "button",
7511
7542
  class: clsx("toolbar-item", isActive && "active"),
7543
+ "data-key": key,
7512
7544
  title,
7513
7545
  onPointerdown: (e) => {
7514
7546
  e.preventDefault();
@@ -7630,7 +7662,8 @@ const Toolbar = vue.defineComponent({
7630
7662
  },
7631
7663
  isTable,
7632
7664
  isTable ? handleTableEnter : void 0,
7633
- isTable ? handleTableLeave : void 0
7665
+ isTable ? handleTableLeave : void 0,
7666
+ item.key
7634
7667
  )
7635
7668
  );
7636
7669
  }
@@ -7810,7 +7843,15 @@ const MenuBar = vue.defineComponent({
7810
7843
  { name: "\u6D45\u7D2B", value: "#F0E6FA" },
7811
7844
  { name: "\u6D45\u7C89", value: "#FDE8E9" }
7812
7845
  ];
7813
- 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
+ });
7814
7855
  const hasSubmenu = (key) => key === "view";
7815
7856
  return () => {
7816
7857
  const state = viewState.value;
@@ -7899,7 +7940,7 @@ const MenuBar = vue.defineComponent({
7899
7940
  e.stopPropagation();
7900
7941
  }
7901
7942
  },
7902
- menuKeys.map((menuKey) => {
7943
+ menuKeys.value.map((menuKey) => {
7903
7944
  const isHovered = activeSubmenu.value === menuKey;
7904
7945
  const label = i18n(props.ctx, `menuBar.${menuKey}`) || menuKey;
7905
7946
  return /* @__PURE__ */ vue.h(
@@ -8438,70 +8479,159 @@ const FixedToolbarComponent = vue.defineComponent({
8438
8479
  hide: { type: Function, required: true },
8439
8480
  show: { type: Object, required: true },
8440
8481
  selection: { type: Object, required: true },
8441
- config: { type: Object, required: false }
8482
+ config: { type: Object, required: false },
8483
+ canUndo: { type: Object, required: true },
8484
+ canRedo: { type: Object, required: true }
8442
8485
  },
8443
8486
  setup(props) {
8444
8487
  const showShortcuts = vue.ref(false);
8445
- return () => /* @__PURE__ */ vue.h(
8446
- "div",
8447
- {
8448
- style: {
8449
- display: "flex",
8450
- alignItems: "center",
8451
- justifyContent: "center",
8452
- width: "100%",
8453
- gap: "0px"
8454
- }
8455
- },
8456
- /* @__PURE__ */ vue.h(MenuBar, { ctx: props.ctx, config: props.config }),
8457
- /* @__PURE__ */ vue.h(
8458
- "div",
8459
- {
8460
- style: {
8461
- width: "1px",
8462
- minWidth: "1px",
8463
- height: "20px",
8464
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8465
- }
8466
- }
8467
- ),
8468
- /* @__PURE__ */ vue.h(
8469
- Toolbar,
8470
- {
8471
- ctx: props.ctx,
8472
- hide: props.hide,
8473
- show: props.show,
8474
- selection: props.selection,
8475
- config: props.config,
8476
- isFixed: true
8477
- }
8478
- ),
8479
- /* @__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(
8480
8506
  "div",
8481
8507
  {
8482
8508
  style: {
8483
- width: "1px",
8484
- minWidth: "1px",
8485
- height: "20px",
8486
- flexShrink: 0,
8487
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8488
- }
8489
- }
8490
- ),
8491
- /* @__PURE__ */ vue.h(
8492
- "button",
8493
- {
8494
- type: "button",
8495
- class: "toolbar-shortcut-btn",
8496
- title: i18n(props.ctx, "shortcuts.title"),
8497
- onClick: () => {
8498
- showShortcuts.value = true;
8509
+ display: "flex",
8510
+ alignItems: "center",
8511
+ justifyContent: "center",
8512
+ width: "100%",
8513
+ gap: "0px"
8499
8514
  }
8500
8515
  },
8501
- /* @__PURE__ */ vue.h(component.Icon, { icon: keyboardIcon })
8502
- ),
8503
- showShortcuts.value && /* @__PURE__ */ vue.h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8504
- );
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
+ };
8505
8635
  }
8506
8636
  });
8507
8637
 
@@ -8927,6 +9057,65 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8927
9057
  }
8928
9058
  });
8929
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
+ });
8930
9119
  return builder.build();
8931
9120
  }
8932
9121
 
@@ -9756,7 +9945,7 @@ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Ca
9756
9945
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9757
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);
9758
9947
  var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
9759
- 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;
9760
9949
  const fixedToolbarConfig = utils.$ctx(
9761
9950
  {},
9762
9951
  "fixedToolbarConfigCtx"
@@ -9773,6 +9962,8 @@ class FixedToolbarView {
9773
9962
  __privateAdd$4(this, _watcher);
9774
9963
  __privateAdd$4(this, _selection$1);
9775
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));
9776
9967
  __privateAdd$4(this, _resizeObserver$1);
9777
9968
  __privateAdd$4(this, _updateOutlineGeometry);
9778
9969
  __privateAdd$4(this, _scrollContainers$1, []);
@@ -9781,6 +9972,11 @@ class FixedToolbarView {
9781
9972
  __privateAdd$4(this, _editorContainer);
9782
9973
  this.update = (view) => {
9783
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
+ }
9784
9980
  };
9785
9981
  this.destroy = () => {
9786
9982
  if (__privateGet$4(this, _watcher)) __privateGet$4(this, _watcher).call(this);
@@ -9805,6 +10001,60 @@ class FixedToolbarView {
9805
10001
  };
9806
10002
  __privateSet$4(this, _view$1, view);
9807
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
+ }
9808
10058
  const content = document.createElement("div");
9809
10059
  content.className = "milkdown-fixed-toolbar";
9810
10060
  __privateSet$4(this, _selection$1, vue.shallowRef(view.state.selection));
@@ -9815,7 +10065,9 @@ class FixedToolbarView {
9815
10065
  // No-op for fixed toolbar
9816
10066
  config,
9817
10067
  selection: __privateGet$4(this, _selection$1),
9818
- 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)
9819
10071
  });
9820
10072
  app.mount(content);
9821
10073
  __privateSet$4(this, _content$2, content);
@@ -9872,9 +10124,9 @@ class FixedToolbarView {
9872
10124
  });
9873
10125
  view.dom.addEventListener("dblclick", __privateGet$4(this, _onDblClick));
9874
10126
  __privateGet$4(this, _content$2).style.transition = "margin 0.1s ease-out, width 0.1s ease-out";
9875
- const viewState = ctx.get(viewMenuStateCtx.key);
10127
+ const viewState2 = ctx.get(viewMenuStateCtx.key);
9876
10128
  if (config.outlinePosition) {
9877
- viewState.outlinePosition = config.outlinePosition;
10129
+ viewState2.outlinePosition = config.outlinePosition;
9878
10130
  }
9879
10131
  __privateSet$4(this, _updateOutlineGeometry, () => {
9880
10132
  const rootRect = root.getBoundingClientRect();
@@ -9883,7 +10135,7 @@ class FixedToolbarView {
9883
10135
  const toolbarRect = __privateGet$4(this, _content$2).getBoundingClientRect();
9884
10136
  outlineTop = Math.max(outlineTop, toolbarRect.bottom);
9885
10137
  }
9886
- if (viewState.showCover && __privateGet$4(this, _headerContent)) {
10138
+ if (viewState2.showCover && __privateGet$4(this, _headerContent)) {
9887
10139
  const coverEl = __privateGet$4(this, _headerContent).querySelector(
9888
10140
  ".milkdown-document-cover"
9889
10141
  );
@@ -9900,8 +10152,8 @@ class FixedToolbarView {
9900
10152
  }
9901
10153
  outlineContent.style.top = `${outlineTop}px`;
9902
10154
  outlineContent.style.height = `${height}px`;
9903
- if (viewState.outlineVisible) {
9904
- if (viewState.outlinePosition === "left") {
10155
+ if (viewState2.outlineVisible) {
10156
+ if (viewState2.outlinePosition === "left") {
9905
10157
  outlineContent.style.left = `${rootRect.left}px`;
9906
10158
  outlineContent.style.right = "auto";
9907
10159
  } else {
@@ -9951,16 +10203,16 @@ class FixedToolbarView {
9951
10203
  }
9952
10204
  __privateSet$4(this, _watcher, vue.watch(
9953
10205
  () => [
9954
- viewState.outlineVisible,
9955
- viewState.outlinePosition,
9956
- viewState.outlineWidth,
9957
- viewState.documentBackground,
9958
- viewState.showCover,
9959
- viewState.editorWidth
10206
+ viewState2.outlineVisible,
10207
+ viewState2.outlinePosition,
10208
+ viewState2.outlineWidth,
10209
+ viewState2.documentBackground,
10210
+ viewState2.showCover,
10211
+ viewState2.editorWidth
9960
10212
  ],
9961
10213
  () => {
9962
- if (viewState.documentBackground) {
9963
- root.style.backgroundColor = viewState.documentBackground;
10214
+ if (viewState2.documentBackground) {
10215
+ root.style.backgroundColor = viewState2.documentBackground;
9964
10216
  } else {
9965
10217
  root.style.backgroundColor = "";
9966
10218
  }
@@ -9970,20 +10222,20 @@ class FixedToolbarView {
9970
10222
  __privateGet$4(this, _content$2).style.marginLeft = "0";
9971
10223
  __privateGet$4(this, _content$2).style.marginRight = "0";
9972
10224
  if (__privateGet$4(this, _editorContainer)) {
9973
- if (viewState.outlineVisible) {
9974
- if (viewState.outlinePosition === "left") {
9975
- __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`;
9976
10228
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9977
10229
  } else {
9978
10230
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9979
- __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState.outlineWidth}px`;
10231
+ __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState2.outlineWidth}px`;
9980
10232
  }
9981
10233
  } else {
9982
10234
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9983
10235
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9984
10236
  }
9985
10237
  }
9986
- const maxWidth = editorWidthMap[viewState.editorWidth];
10238
+ const maxWidth = editorWidthMap[viewState2.editorWidth];
9987
10239
  const isFull = maxWidth === "none";
9988
10240
  const px = isFull ? "80px" : "0";
9989
10241
  __privateGet$4(this, _view$1).dom.style.maxWidth = maxWidth;
@@ -9991,7 +10243,7 @@ class FixedToolbarView {
9991
10243
  __privateGet$4(this, _view$1).dom.style.margin = isFull ? "0" : "0 auto";
9992
10244
  __privateGet$4(this, _view$1).dom.style.padding = `20px ${px} 36px`;
9993
10245
  if (__privateGet$4(this, _headerContent)) {
9994
- __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";
9995
10247
  __privateGet$4(this, _headerContent).style.padding = `0px`;
9996
10248
  }
9997
10249
  void vue.nextTick(() => {
@@ -10017,6 +10269,8 @@ _outlineApp = new WeakMap();
10017
10269
  _watcher = new WeakMap();
10018
10270
  _selection$1 = new WeakMap();
10019
10271
  _show$1 = new WeakMap();
10272
+ _canUndo = new WeakMap();
10273
+ _canRedo = new WeakMap();
10020
10274
  _resizeObserver$1 = new WeakMap();
10021
10275
  _updateOutlineGeometry = new WeakMap();
10022
10276
  _scrollContainers$1 = new WeakMap();
@@ -11212,9 +11466,9 @@ class LatexInlineTooltip {
11212
11466
  doc: innerDoc,
11213
11467
  plugins: [
11214
11468
  keymap.keymap({
11215
- "Mod-z": history.undo,
11216
- "Mod-Z": history.redo,
11217
- "Mod-y": history.redo,
11469
+ "Mod-z": history$1.undo,
11470
+ "Mod-Z": history$1.redo,
11471
+ "Mod-y": history$1.redo,
11218
11472
  Enter: () => {
11219
11473
  if (__privateGet$2(this, _debounceTimer)) {
11220
11474
  clearTimeout(__privateGet$2(this, _debounceTimer));
@@ -11872,7 +12126,7 @@ class CrepeBuilder {
11872
12126
  return nodes.filter((n) => n !== null);
11873
12127
  }
11874
12128
  }));
11875
- }).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));
11876
12130
  }
11877
12131
  /// Get the milkdown editor instance.
11878
12132
  get editor() {
@@ -11891,21 +12145,65 @@ class Crepe extends CrepeBuilder {
11891
12145
  /// The constructor of the crepe editor.
11892
12146
  /// You can pass configs to the editor to configure the editor.
11893
12147
  /// Calling the constructor will not create the editor, you need to call `create` to create the editor.
11894
- constructor({
11895
- features = {},
11896
- featureConfigs = {},
11897
- ...crepeBuilderConfig
11898
- } = {}) {
11899
- super(crepeBuilderConfig);
12148
+ constructor(config = {}) {
12149
+ var _a;
12150
+ const { features = {}, featureConfigs = {}, ...crepeBuilderConfig } = config;
11900
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);
11901
12170
  const enabledFeatures = Object.entries({
11902
12171
  ...defaultFeatures,
11903
12172
  ...features
11904
12173
  }).filter(([, enabled]) => enabled).map(([feature]) => feature);
11905
12174
  enabledFeatures.forEach((feature) => {
11906
- const config = finalConfigs[feature];
11907
- loadFeature(feature, this.editor, config);
12175
+ const config2 = finalConfigs[feature];
12176
+ loadFeature(feature, this.editor, config2);
11908
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
+ }
11909
12207
  }
11910
12208
  }
11911
12209
  /// This is an alias for the `CrepeFeature` enum.