@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/esm/index.js CHANGED
@@ -1,8 +1,9 @@
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';
@@ -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",
@@ -6647,6 +6677,7 @@ const Toolbar = defineComponent({
6647
6677
  "toolbar-item",
6648
6678
  ctx && checkActive(item.active) && "active"
6649
6679
  ),
6680
+ "data-key": item.key,
6650
6681
  onPointerdown: (e) => {
6651
6682
  if (isTable) {
6652
6683
  e.preventDefault();
@@ -7483,11 +7514,12 @@ const Toolbar = defineComponent({
7483
7514
  (() => {
7484
7515
  const cutoff = overflowVisibleCount.value;
7485
7516
  const items = [];
7486
- 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(
7487
7518
  "button",
7488
7519
  {
7489
7520
  type: "button",
7490
7521
  class: clsx("toolbar-item", isActive && "active"),
7522
+ "data-key": key,
7491
7523
  title,
7492
7524
  onPointerdown: (e) => {
7493
7525
  e.preventDefault();
@@ -7609,7 +7641,8 @@ const Toolbar = defineComponent({
7609
7641
  },
7610
7642
  isTable,
7611
7643
  isTable ? handleTableEnter : void 0,
7612
- isTable ? handleTableLeave : void 0
7644
+ isTable ? handleTableLeave : void 0,
7645
+ item.key
7613
7646
  )
7614
7647
  );
7615
7648
  }
@@ -7789,7 +7822,15 @@ const MenuBar = defineComponent({
7789
7822
  { name: "\u6D45\u7D2B", value: "#F0E6FA" },
7790
7823
  { name: "\u6D45\u7C89", value: "#FDE8E9" }
7791
7824
  ];
7792
- 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
+ });
7793
7834
  const hasSubmenu = (key) => key === "view";
7794
7835
  return () => {
7795
7836
  const state = viewState.value;
@@ -7878,7 +7919,7 @@ const MenuBar = defineComponent({
7878
7919
  e.stopPropagation();
7879
7920
  }
7880
7921
  },
7881
- menuKeys.map((menuKey) => {
7922
+ menuKeys.value.map((menuKey) => {
7882
7923
  const isHovered = activeSubmenu.value === menuKey;
7883
7924
  const label = i18n(props.ctx, `menuBar.${menuKey}`) || menuKey;
7884
7925
  return /* @__PURE__ */ h(
@@ -8417,70 +8458,159 @@ const FixedToolbarComponent = defineComponent({
8417
8458
  hide: { type: Function, required: true },
8418
8459
  show: { type: Object, required: true },
8419
8460
  selection: { type: Object, required: true },
8420
- config: { type: Object, required: false }
8461
+ config: { type: Object, required: false },
8462
+ canUndo: { type: Object, required: true },
8463
+ canRedo: { type: Object, required: true }
8421
8464
  },
8422
8465
  setup(props) {
8423
8466
  const showShortcuts = ref(false);
8424
- return () => /* @__PURE__ */ h(
8425
- "div",
8426
- {
8427
- style: {
8428
- display: "flex",
8429
- alignItems: "center",
8430
- justifyContent: "center",
8431
- width: "100%",
8432
- gap: "0px"
8433
- }
8434
- },
8435
- /* @__PURE__ */ h(MenuBar, { ctx: props.ctx, config: props.config }),
8436
- /* @__PURE__ */ h(
8437
- "div",
8438
- {
8439
- style: {
8440
- width: "1px",
8441
- minWidth: "1px",
8442
- height: "20px",
8443
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8444
- }
8445
- }
8446
- ),
8447
- /* @__PURE__ */ h(
8448
- Toolbar,
8449
- {
8450
- ctx: props.ctx,
8451
- hide: props.hide,
8452
- show: props.show,
8453
- selection: props.selection,
8454
- config: props.config,
8455
- isFixed: true
8456
- }
8457
- ),
8458
- /* @__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(
8459
8485
  "div",
8460
8486
  {
8461
8487
  style: {
8462
- width: "1px",
8463
- minWidth: "1px",
8464
- height: "20px",
8465
- flexShrink: 0,
8466
- backgroundColor: "var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))"
8467
- }
8468
- }
8469
- ),
8470
- /* @__PURE__ */ h(
8471
- "button",
8472
- {
8473
- type: "button",
8474
- class: "toolbar-shortcut-btn",
8475
- title: i18n(props.ctx, "shortcuts.title"),
8476
- onClick: () => {
8477
- showShortcuts.value = true;
8488
+ display: "flex",
8489
+ alignItems: "center",
8490
+ justifyContent: "center",
8491
+ width: "100%",
8492
+ gap: "0px"
8478
8493
  }
8479
8494
  },
8480
- /* @__PURE__ */ h(Icon, { icon: keyboardIcon })
8481
- ),
8482
- showShortcuts.value && /* @__PURE__ */ h(ShortcutHelpModal, { ctx: props.ctx, visible: showShortcuts })
8483
- );
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
+ };
8484
8614
  }
8485
8615
  });
8486
8616
 
@@ -8906,6 +9036,65 @@ function buildDefaultFixedToolbar(builder, _config, ctx) {
8906
9036
  }
8907
9037
  });
8908
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
+ });
8909
9098
  return builder.build();
8910
9099
  }
8911
9100
 
@@ -9735,7 +9924,7 @@ var __accessCheck$4 = (obj, member, msg) => member.has(obj) || __typeError$4("Ca
9735
9924
  var __privateGet$4 = (obj, member, getter) => (__accessCheck$4(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9736
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);
9737
9926
  var __privateSet$4 = (obj, member, value, setter) => (__accessCheck$4(obj, member, "write to private field"), member.set(obj, value), value);
9738
- 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;
9739
9928
  const fixedToolbarConfig = $ctx(
9740
9929
  {},
9741
9930
  "fixedToolbarConfigCtx"
@@ -9752,6 +9941,8 @@ class FixedToolbarView {
9752
9941
  __privateAdd$4(this, _watcher);
9753
9942
  __privateAdd$4(this, _selection$1);
9754
9943
  __privateAdd$4(this, _show$1, ref(true));
9944
+ __privateAdd$4(this, _canUndo, ref(false));
9945
+ __privateAdd$4(this, _canRedo, ref(false));
9755
9946
  __privateAdd$4(this, _resizeObserver$1);
9756
9947
  __privateAdd$4(this, _updateOutlineGeometry);
9757
9948
  __privateAdd$4(this, _scrollContainers$1, []);
@@ -9760,6 +9951,11 @@ class FixedToolbarView {
9760
9951
  __privateAdd$4(this, _editorContainer);
9761
9952
  this.update = (view) => {
9762
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
+ }
9763
9959
  };
9764
9960
  this.destroy = () => {
9765
9961
  if (__privateGet$4(this, _watcher)) __privateGet$4(this, _watcher).call(this);
@@ -9784,6 +9980,60 @@ class FixedToolbarView {
9784
9980
  };
9785
9981
  __privateSet$4(this, _view$1, view);
9786
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
+ }
9787
10037
  const content = document.createElement("div");
9788
10038
  content.className = "milkdown-fixed-toolbar";
9789
10039
  __privateSet$4(this, _selection$1, shallowRef(view.state.selection));
@@ -9794,7 +10044,9 @@ class FixedToolbarView {
9794
10044
  // No-op for fixed toolbar
9795
10045
  config,
9796
10046
  selection: __privateGet$4(this, _selection$1),
9797
- 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)
9798
10050
  });
9799
10051
  app.mount(content);
9800
10052
  __privateSet$4(this, _content$2, content);
@@ -9851,9 +10103,9 @@ class FixedToolbarView {
9851
10103
  });
9852
10104
  view.dom.addEventListener("dblclick", __privateGet$4(this, _onDblClick));
9853
10105
  __privateGet$4(this, _content$2).style.transition = "margin 0.1s ease-out, width 0.1s ease-out";
9854
- const viewState = ctx.get(viewMenuStateCtx.key);
10106
+ const viewState2 = ctx.get(viewMenuStateCtx.key);
9855
10107
  if (config.outlinePosition) {
9856
- viewState.outlinePosition = config.outlinePosition;
10108
+ viewState2.outlinePosition = config.outlinePosition;
9857
10109
  }
9858
10110
  __privateSet$4(this, _updateOutlineGeometry, () => {
9859
10111
  const rootRect = root.getBoundingClientRect();
@@ -9862,7 +10114,7 @@ class FixedToolbarView {
9862
10114
  const toolbarRect = __privateGet$4(this, _content$2).getBoundingClientRect();
9863
10115
  outlineTop = Math.max(outlineTop, toolbarRect.bottom);
9864
10116
  }
9865
- if (viewState.showCover && __privateGet$4(this, _headerContent)) {
10117
+ if (viewState2.showCover && __privateGet$4(this, _headerContent)) {
9866
10118
  const coverEl = __privateGet$4(this, _headerContent).querySelector(
9867
10119
  ".milkdown-document-cover"
9868
10120
  );
@@ -9879,8 +10131,8 @@ class FixedToolbarView {
9879
10131
  }
9880
10132
  outlineContent.style.top = `${outlineTop}px`;
9881
10133
  outlineContent.style.height = `${height}px`;
9882
- if (viewState.outlineVisible) {
9883
- if (viewState.outlinePosition === "left") {
10134
+ if (viewState2.outlineVisible) {
10135
+ if (viewState2.outlinePosition === "left") {
9884
10136
  outlineContent.style.left = `${rootRect.left}px`;
9885
10137
  outlineContent.style.right = "auto";
9886
10138
  } else {
@@ -9930,16 +10182,16 @@ class FixedToolbarView {
9930
10182
  }
9931
10183
  __privateSet$4(this, _watcher, watch(
9932
10184
  () => [
9933
- viewState.outlineVisible,
9934
- viewState.outlinePosition,
9935
- viewState.outlineWidth,
9936
- viewState.documentBackground,
9937
- viewState.showCover,
9938
- viewState.editorWidth
10185
+ viewState2.outlineVisible,
10186
+ viewState2.outlinePosition,
10187
+ viewState2.outlineWidth,
10188
+ viewState2.documentBackground,
10189
+ viewState2.showCover,
10190
+ viewState2.editorWidth
9939
10191
  ],
9940
10192
  () => {
9941
- if (viewState.documentBackground) {
9942
- root.style.backgroundColor = viewState.documentBackground;
10193
+ if (viewState2.documentBackground) {
10194
+ root.style.backgroundColor = viewState2.documentBackground;
9943
10195
  } else {
9944
10196
  root.style.backgroundColor = "";
9945
10197
  }
@@ -9949,20 +10201,20 @@ class FixedToolbarView {
9949
10201
  __privateGet$4(this, _content$2).style.marginLeft = "0";
9950
10202
  __privateGet$4(this, _content$2).style.marginRight = "0";
9951
10203
  if (__privateGet$4(this, _editorContainer)) {
9952
- if (viewState.outlineVisible) {
9953
- if (viewState.outlinePosition === "left") {
9954
- __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`;
9955
10207
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9956
10208
  } else {
9957
10209
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9958
- __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState.outlineWidth}px`;
10210
+ __privateGet$4(this, _editorContainer).style.paddingRight = `${viewState2.outlineWidth}px`;
9959
10211
  }
9960
10212
  } else {
9961
10213
  __privateGet$4(this, _editorContainer).style.paddingLeft = "0";
9962
10214
  __privateGet$4(this, _editorContainer).style.paddingRight = "0";
9963
10215
  }
9964
10216
  }
9965
- const maxWidth = editorWidthMap[viewState.editorWidth];
10217
+ const maxWidth = editorWidthMap[viewState2.editorWidth];
9966
10218
  const isFull = maxWidth === "none";
9967
10219
  const px = isFull ? "80px" : "0";
9968
10220
  __privateGet$4(this, _view$1).dom.style.maxWidth = maxWidth;
@@ -9970,7 +10222,7 @@ class FixedToolbarView {
9970
10222
  __privateGet$4(this, _view$1).dom.style.margin = isFull ? "0" : "0 auto";
9971
10223
  __privateGet$4(this, _view$1).dom.style.padding = `20px ${px} 36px`;
9972
10224
  if (__privateGet$4(this, _headerContent)) {
9973
- __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";
9974
10226
  __privateGet$4(this, _headerContent).style.padding = `0px`;
9975
10227
  }
9976
10228
  void nextTick(() => {
@@ -9996,6 +10248,8 @@ _outlineApp = new WeakMap();
9996
10248
  _watcher = new WeakMap();
9997
10249
  _selection$1 = new WeakMap();
9998
10250
  _show$1 = new WeakMap();
10251
+ _canUndo = new WeakMap();
10252
+ _canRedo = new WeakMap();
9999
10253
  _resizeObserver$1 = new WeakMap();
10000
10254
  _updateOutlineGeometry = new WeakMap();
10001
10255
  _scrollContainers$1 = new WeakMap();
@@ -11191,9 +11445,9 @@ class LatexInlineTooltip {
11191
11445
  doc: innerDoc,
11192
11446
  plugins: [
11193
11447
  keymap$1({
11194
- "Mod-z": undo,
11195
- "Mod-Z": redo,
11196
- "Mod-y": redo,
11448
+ "Mod-z": undo$1,
11449
+ "Mod-Z": redo$1,
11450
+ "Mod-y": redo$1,
11197
11451
  Enter: () => {
11198
11452
  if (__privateGet$2(this, _debounceTimer)) {
11199
11453
  clearTimeout(__privateGet$2(this, _debounceTimer));
@@ -11870,21 +12124,65 @@ class Crepe extends CrepeBuilder {
11870
12124
  /// The constructor of the crepe editor.
11871
12125
  /// You can pass configs to the editor to configure the editor.
11872
12126
  /// Calling the constructor will not create the editor, you need to call `create` to create the editor.
11873
- constructor({
11874
- features = {},
11875
- featureConfigs = {},
11876
- ...crepeBuilderConfig
11877
- } = {}) {
11878
- super(crepeBuilderConfig);
12127
+ constructor(config = {}) {
12128
+ var _a;
12129
+ const { features = {}, featureConfigs = {}, ...crepeBuilderConfig } = config;
11879
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);
11880
12149
  const enabledFeatures = Object.entries({
11881
12150
  ...defaultFeatures,
11882
12151
  ...features
11883
12152
  }).filter(([, enabled]) => enabled).map(([feature]) => feature);
11884
12153
  enabledFeatures.forEach((feature) => {
11885
- const config = finalConfigs[feature];
11886
- loadFeature(feature, this.editor, config);
12154
+ const config2 = finalConfigs[feature];
12155
+ loadFeature(feature, this.editor, config2);
11887
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
+ }
11888
12186
  }
11889
12187
  }
11890
12188
  /// This is an alias for the `CrepeFeature` enum.