@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
@@ -3,7 +3,8 @@ import type { PluginView, Selection } from '@jvs-milkdown/kit/prose/state'
3
3
  import type { EditorView } from '@jvs-milkdown/kit/prose/view'
4
4
 
5
5
  import { Plugin, PluginKey, TextSelection } from '@jvs-milkdown/kit/prose/state'
6
- import { $ctx, $prose } from '@jvs-milkdown/kit/utils'
6
+ import { $ctx, $prose, getMarkdown } 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,15 @@ 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
+ h,
12
+ watch,
13
+ } from 'vue'
6
14
 
7
15
  import type { FixedToolbarConfig } from './index'
8
16
 
@@ -143,7 +151,14 @@ export const MenuBar = defineComponent({
143
151
  { name: '浅粉', value: '#FDE8E9' },
144
152
  ]
145
153
 
146
- const menuKeys = ['file', 'edit', 'view', 'insert', 'format']
154
+ const menuKeys = computed(() => {
155
+ const allKeys = ['file', 'edit', 'view', 'insert', 'format']
156
+ const itemsConfig = props.config?.menuBarItems
157
+ if (!itemsConfig) return allKeys
158
+ return allKeys.filter(
159
+ (key) => itemsConfig[key as keyof typeof itemsConfig] !== false
160
+ )
161
+ })
147
162
  const hasSubmenu = (key: string) => key === 'view'
148
163
 
149
164
  return () => {
@@ -232,7 +247,7 @@ export const MenuBar = defineComponent({
232
247
  e.stopPropagation()
233
248
  }}
234
249
  >
235
- {menuKeys.map((menuKey) => {
250
+ {menuKeys.value.map((menuKey) => {
236
251
  const isHovered = activeSubmenu.value === menuKey
237
252
  const label =
238
253
  i18n(props.ctx, `menuBar.${menuKey}` as any) || menuKey
@@ -1631,6 +1631,7 @@ export const Toolbar = defineComponent<ToolbarProps>({
1631
1631
  'toolbar-item',
1632
1632
  ctx && checkActive(item.active) && 'active'
1633
1633
  )}
1634
+ data-key={item.key}
1634
1635
  onPointerdown={(e: PointerEvent) => {
1635
1636
  if (isTable) {
1636
1637
  e.preventDefault()
@@ -2547,11 +2548,13 @@ export const Toolbar = defineComponent<ToolbarProps>({
2547
2548
  onClick: ((e: MouseEvent) => void) | undefined,
2548
2549
  hasDropdown = false,
2549
2550
  onMouseEnter?: (e: MouseEvent) => void,
2550
- onMouseLeave?: (e: MouseEvent) => void
2551
+ onMouseLeave?: (e: MouseEvent) => void,
2552
+ key?: string
2551
2553
  ) => (
2552
2554
  <button
2553
2555
  type="button"
2554
2556
  class={clsx('toolbar-item', isActive && 'active')}
2557
+ data-key={key}
2555
2558
  title={title}
2556
2559
  onPointerdown={(e: PointerEvent) => {
2557
2560
  e.preventDefault()
@@ -2686,7 +2689,8 @@ export const Toolbar = defineComponent<ToolbarProps>({
2686
2689
  },
2687
2690
  isTable,
2688
2691
  isTable ? handleTableEnter : undefined,
2689
- isTable ? handleTableLeave : undefined
2692
+ isTable ? handleTableLeave : undefined,
2693
+ item.key
2690
2694
  )
2691
2695
  )
2692
2696
  }
@@ -0,0 +1,5 @@
1
+ export const exportIcon = `
2
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
3
+ <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>
4
+ </svg>
5
+ `
@@ -0,0 +1,6 @@
1
+ export const importIcon = `
2
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
3
+ <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>
4
+ <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>
5
+ </svg>
6
+ `
@@ -53,3 +53,7 @@ export * from './word-wrap'
53
53
  export * from './crop'
54
54
  export * from './border'
55
55
  export * from './format-painter'
56
+ export * from './undo'
57
+ export * from './redo'
58
+ export * from './export'
59
+ export * from './import'
@@ -0,0 +1,5 @@
1
+ export const redoIcon = `
2
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
3
+ <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>
4
+ </svg>
5
+ `
@@ -0,0 +1,5 @@
1
+ export const undoIcon = `
2
+ <svg viewBox="0 0 1024 1024" version="1.1" width="20" height="20">
3
+ <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>
4
+ </svg>
5
+ `
@@ -73,6 +73,14 @@
73
73
  fill: var(--crepe-color-primary);
74
74
  }
75
75
  }
76
+
77
+ &[data-key='export'],
78
+ &[data-key='import'],
79
+ &[data-key='shortcuts'] {
80
+ svg {
81
+ --toolbar-icon-color: #363b4c;
82
+ }
83
+ }
76
84
  }
77
85
  }
78
86
 
@@ -164,6 +172,14 @@
164
172
  fill: var(--crepe-color-primary);
165
173
  }
166
174
  }
175
+
176
+ &[data-key='export'],
177
+ &[data-key='import'],
178
+ &[data-key='shortcuts'] {
179
+ svg {
180
+ --toolbar-icon-color: #363b4c;
181
+ }
182
+ }
167
183
  }
168
184
  }
169
185
  }