@jvs-milkdown/crepe 1.2.17 → 1.2.20

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 +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 +56 -22
  24. package/lib/cjs/feature/toolbar/index.js.map +1 -1
  25. package/lib/cjs/index.js +533 -151
  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 +56 -22
  50. package/lib/esm/feature/toolbar/index.js.map +1 -1
  51. package/lib/esm/index.js +700 -318
  52. package/lib/esm/index.js.map +1 -1
  53. package/lib/theme/common/toolbar.css +9 -0
  54. package/lib/tsconfig.tsbuildinfo +1 -1
  55. package/lib/types/core/crepe.d.ts +2 -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/lib/types/utils/fixed-toolbar-popup-state.d.ts +1 -0
  77. package/lib/types/utils/fixed-toolbar-popup-state.d.ts.map +1 -1
  78. package/package.json +116 -62
  79. package/src/core/crepe.ts +122 -7
  80. package/src/core/locale.ts +4 -0
  81. package/src/feature/fixed-toolbar/component.tsx +154 -53
  82. package/src/feature/fixed-toolbar/config.ts +70 -2
  83. package/src/feature/fixed-toolbar/index.ts +85 -0
  84. package/src/feature/fixed-toolbar/menu-bar.tsx +17 -3
  85. package/src/feature/toolbar/component.tsx +61 -23
  86. package/src/icons/export.ts +5 -0
  87. package/src/icons/import.ts +6 -0
  88. package/src/icons/index.ts +4 -0
  89. package/src/icons/redo.ts +5 -0
  90. package/src/icons/undo.ts +5 -0
  91. package/src/theme/common/toolbar.css +19 -0
  92. package/src/utils/fixed-toolbar-popup-state.ts +5 -0
  93. package/LICENSE +0 -21
@@ -1,14 +1,20 @@
1
1
  import type { Ctx } from '@jvs-milkdown/kit/ctx'
2
2
  import type { Selection } from '@jvs-milkdown/kit/prose/state'
3
3
 
4
- import { Icon } from '@jvs-milkdown/kit/component'
4
+ import { commandsCtx } from '@jvs-milkdown/kit/core'
5
5
  // @ts-ignore
6
- import { defineComponent, type ShallowRef, type Ref, ref, h } from 'vue'
6
+ import {
7
+ defineComponent,
8
+ type ShallowRef,
9
+ type Ref,
10
+ ref,
11
+ onMounted,
12
+ onUnmounted,
13
+ } from 'vue'
7
14
 
8
15
  import type { FixedToolbarFeatureConfig } from '.'
9
16
 
10
- import { i18n } from '../../core/locale'
11
- import { keyboardIcon } from '../../icons'
17
+ import { undoIcon, redoIcon } from '../../icons'
12
18
  import { Toolbar } from '../toolbar/component'
13
19
  import { MenuBar } from './menu-bar'
14
20
  import { ShortcutHelpModal } from './shortcut-help-modal'
@@ -19,6 +25,8 @@ type FixedToolbarProps = {
19
25
  show: Ref<boolean>
20
26
  selection: ShallowRef<Selection>
21
27
  config?: FixedToolbarFeatureConfig
28
+ canUndo: Ref<boolean>
29
+ canRedo: Ref<boolean>
22
30
  }
23
31
 
24
32
  export const FixedToolbarComponent = defineComponent<FixedToolbarProps>({
@@ -28,62 +36,155 @@ export const FixedToolbarComponent = defineComponent<FixedToolbarProps>({
28
36
  show: { type: Object, required: true },
29
37
  selection: { type: Object, required: true },
30
38
  config: { type: Object, required: false },
39
+ canUndo: { type: Object, required: true },
40
+ canRedo: { type: Object, required: true },
31
41
  },
32
42
  setup(props: any) {
33
43
  const showShortcuts = ref(false)
34
44
 
35
- return () => (
36
- <div
37
- style={{
38
- display: 'flex',
39
- alignItems: 'center',
40
- justifyContent: 'center',
41
- width: '100%',
42
- gap: '0px',
43
- }}
44
- >
45
- <MenuBar ctx={props.ctx} config={props.config} />
46
- <div
47
- style={{
48
- width: '1px',
49
- minWidth: '1px',
50
- height: '20px',
51
- backgroundColor:
52
- 'var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))',
53
- }}
54
- />
55
- <Toolbar
56
- ctx={props.ctx}
57
- hide={props.hide}
58
- show={props.show}
59
- selection={props.selection}
60
- config={props.config as any}
61
- isFixed={true}
62
- />
45
+ onMounted(() => {
46
+ const handleShowShortcuts = () => {
47
+ showShortcuts.value = true
48
+ }
49
+ window.addEventListener('milkdown-show-shortcuts', handleShowShortcuts)
50
+ onUnmounted(() => {
51
+ window.removeEventListener(
52
+ 'milkdown-show-shortcuts',
53
+ handleShowShortcuts
54
+ )
55
+ })
56
+ })
57
+
58
+ return () => {
59
+ // Access selection.value to register reactivity dependency for Vue on editor transactions
60
+ const _selection = props.selection.value
61
+ void _selection
62
+
63
+ const canUndo =
64
+ (typeof props.canUndo === 'boolean'
65
+ ? props.canUndo
66
+ : props.canUndo?.value) || false
67
+ const canRedo =
68
+ (typeof props.canRedo === 'boolean'
69
+ ? props.canRedo
70
+ : props.canRedo?.value) || false
71
+
72
+ return (
63
73
  <div
64
74
  style={{
65
- width: '1px',
66
- minWidth: '1px',
67
- height: '20px',
68
- flexShrink: 0,
69
- backgroundColor:
70
- 'var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))',
71
- }}
72
- />
73
- <button
74
- type="button"
75
- class="toolbar-shortcut-btn"
76
- title={i18n(props.ctx, 'shortcuts.title')}
77
- onClick={() => {
78
- showShortcuts.value = true
75
+ display: 'flex',
76
+ alignItems: 'center',
77
+ justifyContent: 'center',
78
+ width: '100%',
79
+ gap: '0px',
80
+ minWidth: '0',
81
+ overflow: 'hidden',
79
82
  }}
80
83
  >
81
- <Icon icon={keyboardIcon} />
82
- </button>
83
- {showShortcuts.value && (
84
- <ShortcutHelpModal ctx={props.ctx} visible={showShortcuts} />
85
- )}
86
- </div>
87
- )
84
+ {props.config?.showMenuBar !== false && [
85
+ <MenuBar ctx={props.ctx} config={props.config} />,
86
+ <div
87
+ style={{
88
+ width: '1px',
89
+ minWidth: '1px',
90
+ height: '20px',
91
+ backgroundColor:
92
+ 'var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))',
93
+ }}
94
+ />,
95
+ ]}
96
+ {props.config?.showHistory !== false && [
97
+ <button
98
+ type="button"
99
+ class={['toolbar-item', !canUndo && 'disabled']}
100
+ disabled={!canUndo}
101
+ title="撤销"
102
+ onPointerdown={(e: PointerEvent) => {
103
+ e.preventDefault()
104
+ e.stopPropagation()
105
+ }}
106
+ onClick={(e: MouseEvent) => {
107
+ e.preventDefault()
108
+ e.stopPropagation()
109
+ if (canUndo) {
110
+ props.ctx.get(commandsCtx).call('Undo')
111
+ }
112
+ }}
113
+ style={{
114
+ display: 'flex',
115
+ alignItems: 'center',
116
+ justifyContent: 'center',
117
+ border: 'none',
118
+ background: 'transparent',
119
+ cursor: canUndo ? 'pointer' : 'default',
120
+ padding: '6px',
121
+ borderRadius: '4px',
122
+ color: canUndo ? '#363b4c' : '#c0c4cc',
123
+ '--toolbar-icon-color': canUndo ? '#363b4c' : '#c0c4cc',
124
+ }}
125
+ >
126
+ <span
127
+ style={{ display: 'inline-flex', alignItems: 'center' }}
128
+ innerHTML={undoIcon}
129
+ />
130
+ </button>,
131
+ <button
132
+ type="button"
133
+ class={['toolbar-item', !canRedo && 'disabled']}
134
+ disabled={!canRedo}
135
+ title="恢复"
136
+ onPointerdown={(e: PointerEvent) => {
137
+ e.preventDefault()
138
+ e.stopPropagation()
139
+ }}
140
+ onClick={(e: MouseEvent) => {
141
+ e.preventDefault()
142
+ e.stopPropagation()
143
+ if (canRedo) {
144
+ props.ctx.get(commandsCtx).call('Redo')
145
+ }
146
+ }}
147
+ style={{
148
+ display: 'flex',
149
+ alignItems: 'center',
150
+ justifyContent: 'center',
151
+ border: 'none',
152
+ background: 'transparent',
153
+ cursor: canRedo ? 'pointer' : 'default',
154
+ padding: '6px',
155
+ borderRadius: '4px',
156
+ color: canRedo ? '#363b4c' : '#c0c4cc',
157
+ '--toolbar-icon-color': canRedo ? '#363b4c' : '#c0c4cc',
158
+ }}
159
+ >
160
+ <span
161
+ style={{ display: 'inline-flex', alignItems: 'center' }}
162
+ innerHTML={redoIcon}
163
+ />
164
+ </button>,
165
+ <div
166
+ style={{
167
+ width: '1px',
168
+ minWidth: '1px',
169
+ height: '20px',
170
+ backgroundColor:
171
+ 'var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%))',
172
+ }}
173
+ />,
174
+ ]}
175
+ <Toolbar
176
+ ctx={props.ctx}
177
+ hide={props.hide}
178
+ show={props.show}
179
+ selection={props.selection}
180
+ config={props.config as any}
181
+ isFixed={true}
182
+ />
183
+ {showShortcuts.value && (
184
+ <ShortcutHelpModal ctx={props.ctx} visible={showShortcuts} />
185
+ )}
186
+ </div>
187
+ )
188
+ }
88
189
  },
89
190
  })
@@ -29,6 +29,8 @@ import { createTable } from '@jvs-milkdown/kit/preset/gfm'
29
29
  import { findNodeInSelection } from '@jvs-milkdown/kit/prose'
30
30
  import { lift } from '@jvs-milkdown/kit/prose/commands'
31
31
  import { wrapInList } from '@jvs-milkdown/kit/prose/schema-list'
32
+ import { getMarkdown } from '@jvs-milkdown/kit/utils'
33
+ import { replaceAll } from '@jvs-milkdown/utils'
32
34
 
33
35
  import type { GroupBuilder } from '../../utils'
34
36
  import type { ToolbarItem } from '../toolbar/config'
@@ -50,6 +52,9 @@ import {
50
52
  highLineCodeIcon,
51
53
  linCodeIcon,
52
54
  linkIcon,
55
+ exportIcon,
56
+ importIcon,
57
+ keyboardIcon,
53
58
  } from '../../icons'
54
59
  import { attachmentSchema } from '../attachment/schema'
55
60
  import { CrepeFeature } from '../index'
@@ -472,7 +477,6 @@ export function buildDefaultFixedToolbar(
472
477
  },
473
478
  })
474
479
 
475
-
476
480
  if (isAttachmentEnabled) {
477
481
  blockGroup.addItem('attachment', {
478
482
  label: ctx ? i18n(ctx, 'menu.item.attachment') : 'Video or File',
@@ -532,7 +536,6 @@ export function buildDefaultFixedToolbar(
532
536
  },
533
537
  })
534
538
 
535
-
536
539
  if (isLatexEnabled) {
537
540
  blockGroup.addItem('math-block', {
538
541
  label: ctx ? i18n(ctx, 'menu.item.math') : 'Math Block',
@@ -552,5 +555,70 @@ export function buildDefaultFixedToolbar(
552
555
  })
553
556
  }
554
557
 
558
+ const documentGroup = builder.addGroup('document', 'Document')
559
+
560
+ if (_config?.showExport !== false) {
561
+ documentGroup.addItem('export', {
562
+ label: ctx ? i18n(ctx, 'customMenu.export' as any) || '导出' : '导出',
563
+ icon: exportIcon,
564
+ active: () => false,
565
+ onRun: (ctx) => {
566
+ const markdown = getMarkdown()(ctx)
567
+ if (_config?.onExport) {
568
+ _config.onExport(markdown, ctx)
569
+ } else {
570
+ const blob = new Blob([markdown], {
571
+ type: 'text/markdown;charset=utf-8;',
572
+ })
573
+ const url = URL.createObjectURL(blob)
574
+ const link = document.createElement('a')
575
+ link.href = url
576
+ link.download = 'document.md'
577
+ link.click()
578
+ URL.revokeObjectURL(url)
579
+ }
580
+ },
581
+ })
582
+ }
583
+
584
+ if (_config?.showImport !== false) {
585
+ documentGroup.addItem('import', {
586
+ label: ctx ? i18n(ctx, 'customMenu.import' as any) || '导入' : '导入',
587
+ icon: importIcon,
588
+ active: () => false,
589
+ onRun: (ctx) => {
590
+ if (_config?.onImport) {
591
+ _config.onImport((markdown) => replaceAll(markdown)(ctx), ctx)
592
+ } else {
593
+ const input = document.createElement('input')
594
+ input.type = 'file'
595
+ input.accept = '.md'
596
+ input.onchange = (e) => {
597
+ const file = (e.target as HTMLInputElement).files?.[0]
598
+ if (!file) return
599
+ file
600
+ .text()
601
+ .then((text) => {
602
+ replaceAll(text)(ctx)
603
+ })
604
+ .catch((err) => {
605
+ console.error('Failed to read file:', err)
606
+ })
607
+ }
608
+ input.click()
609
+ }
610
+ },
611
+ })
612
+ }
613
+
614
+ documentGroup.addItem('shortcuts', {
615
+ label: ctx ? i18n(ctx, 'shortcuts.title') : 'Shortcuts',
616
+ icon: keyboardIcon,
617
+ active: () => false,
618
+ onRun: () => {
619
+ window.dispatchEvent(new CustomEvent('milkdown-show-shortcuts'))
620
+ },
621
+ })
622
+
555
623
  return builder.build()
556
624
  }
@@ -4,6 +4,7 @@ import type { EditorView } from '@jvs-milkdown/kit/prose/view'
4
4
 
5
5
  import { Plugin, PluginKey, TextSelection } from '@jvs-milkdown/kit/prose/state'
6
6
  import { $ctx, $prose } from '@jvs-milkdown/kit/utils'
7
+ import { undo, redo } from '@jvs-milkdown/prose/history'
7
8
  // @ts-ignore
8
9
  import {
9
10
  createApp,
@@ -44,6 +45,21 @@ export interface FixedToolbarConfig {
44
45
  outlinePosition?: 'left' | 'right'
45
46
  onUploadCover?: (file: File) => Promise<string>
46
47
  defaultCoverImages?: string[]
48
+ showMenuBar?: boolean
49
+ menuBarItems?: {
50
+ file?: boolean
51
+ edit?: boolean
52
+ view?: boolean
53
+ insert?: boolean
54
+ format?: boolean
55
+ }
56
+ showHistory?: boolean
57
+ showExport?: boolean
58
+ onExport?: (markdown: string, ctx: Ctx) => void
59
+ showImport?: boolean
60
+ onImport?: (replaceContent: (markdown: string) => void, ctx: Ctx) => void
61
+ useLocalStorage?: boolean
62
+ id?: string
47
63
  }
48
64
 
49
65
  export type FixedToolbarFeatureConfig = Partial<FixedToolbarConfig>
@@ -65,6 +81,8 @@ class FixedToolbarView implements PluginView {
65
81
  #watcher?: WatchStopHandle
66
82
  #selection: ShallowRef<Selection>
67
83
  #show = ref(true)
84
+ #canUndo = ref(false)
85
+ #canRedo = ref(false)
68
86
  #resizeObserver?: ResizeObserver
69
87
  #updateOutlineGeometry?: () => void
70
88
  #scrollContainers: Element[] = []
@@ -75,6 +93,65 @@ class FixedToolbarView implements PluginView {
75
93
  constructor(ctx: Ctx, view: EditorView) {
76
94
  this.#view = view
77
95
  const config = ctx.get(fixedToolbarConfig.key)
96
+ const viewState = ctx.get(viewMenuStateCtx.key)
97
+
98
+ // Load initial view menu state from localStorage if useLocalStorage is enabled
99
+ if (config?.useLocalStorage) {
100
+ try {
101
+ const stored = localStorage.getItem('jvs-milkdown-data')
102
+ if (stored) {
103
+ const parsed = JSON.parse(stored)
104
+ if (parsed.outlineVisible !== undefined)
105
+ viewState.outlineVisible = parsed.outlineVisible
106
+ if (parsed.outlinePosition !== undefined)
107
+ viewState.outlinePosition = parsed.outlinePosition
108
+ if (parsed.outlineWidth !== undefined)
109
+ viewState.outlineWidth = parsed.outlineWidth
110
+ if (parsed.documentBackground !== undefined)
111
+ viewState.documentBackground = parsed.documentBackground
112
+ if (parsed.showTitle !== undefined)
113
+ viewState.showTitle = parsed.showTitle
114
+ if (parsed.showCover !== undefined)
115
+ viewState.showCover = parsed.showCover
116
+ if (parsed.coverUrl !== undefined)
117
+ viewState.coverUrl = parsed.coverUrl
118
+ if (parsed.editorWidth !== undefined)
119
+ viewState.editorWidth = parsed.editorWidth
120
+ }
121
+ } catch (e) {
122
+ console.error('Error loading view state from localStorage:', e)
123
+ }
124
+
125
+ // Automatically watch and persist view state changes to localStorage
126
+ watch(
127
+ viewState,
128
+ (newState) => {
129
+ try {
130
+ const stored = localStorage.getItem('jvs-milkdown-data')
131
+ let parsed = {}
132
+ if (stored) {
133
+ parsed = JSON.parse(stored)
134
+ }
135
+ const merged = {
136
+ ...parsed,
137
+ outlineVisible: newState.outlineVisible,
138
+ outlinePosition: newState.outlinePosition,
139
+ outlineWidth: newState.outlineWidth,
140
+ documentBackground: newState.documentBackground,
141
+ showTitle: newState.showTitle,
142
+ showCover: newState.showCover,
143
+ coverUrl: newState.coverUrl,
144
+ editorWidth: newState.editorWidth,
145
+ }
146
+ localStorage.setItem('jvs-milkdown-data', JSON.stringify(merged))
147
+ } catch (e) {
148
+ console.error('Error saving view state to localStorage:', e)
149
+ }
150
+ },
151
+ { deep: true }
152
+ )
153
+ }
154
+
78
155
  const content = document.createElement('div')
79
156
  content.className = 'milkdown-fixed-toolbar'
80
157
  this.#selection = shallowRef(view.state.selection)
@@ -85,6 +162,8 @@ class FixedToolbarView implements PluginView {
85
162
  config,
86
163
  selection: this.#selection,
87
164
  show: this.#show,
165
+ canUndo: this.#canUndo,
166
+ canRedo: this.#canRedo,
88
167
  })
89
168
  app.mount(content)
90
169
  this.#content = content
@@ -317,6 +396,12 @@ class FixedToolbarView implements PluginView {
317
396
 
318
397
  update = (view: EditorView) => {
319
398
  this.#selection.value = view.state.selection
399
+ try {
400
+ this.#canUndo.value = undo(view.state)
401
+ this.#canRedo.value = redo(view.state)
402
+ } catch (e) {
403
+ // Ignore initialization errors
404
+ }
320
405
  }
321
406
 
322
407
  destroy = () => {
@@ -2,7 +2,14 @@ import type { Ctx } from '@jvs-milkdown/kit/ctx'
2
2
 
3
3
  import { Icon } from '@jvs-milkdown/kit/component'
4
4
  // @ts-ignore
5
- import { defineComponent, ref, onUnmounted, computed, onMounted, h, watch } from 'vue'
5
+ import {
6
+ defineComponent,
7
+ ref,
8
+ onUnmounted,
9
+ computed,
10
+ onMounted,
11
+ watch,
12
+ } from 'vue'
6
13
 
7
14
  import type { FixedToolbarConfig } from './index'
8
15
 
@@ -143,7 +150,14 @@ export const MenuBar = defineComponent({
143
150
  { name: '浅粉', value: '#FDE8E9' },
144
151
  ]
145
152
 
146
- const menuKeys = ['file', 'edit', 'view', 'insert', 'format']
153
+ const menuKeys = computed(() => {
154
+ const allKeys = ['file', 'edit', 'view', 'insert', 'format']
155
+ const itemsConfig = props.config?.menuBarItems
156
+ if (!itemsConfig) return allKeys
157
+ return allKeys.filter(
158
+ (key) => itemsConfig[key as keyof typeof itemsConfig] !== false
159
+ )
160
+ })
147
161
  const hasSubmenu = (key: string) => key === 'view'
148
162
 
149
163
  return () => {
@@ -232,7 +246,7 @@ export const MenuBar = defineComponent({
232
246
  e.stopPropagation()
233
247
  }}
234
248
  >
235
- {menuKeys.map((menuKey) => {
249
+ {menuKeys.value.map((menuKey) => {
236
250
  const isHovered = activeSubmenu.value === menuKey
237
251
  const label =
238
252
  i18n(props.ctx, `menuBar.${menuKey}` as any) || menuKey