@jvs-milkdown/crepe 1.2.16 → 1.2.17

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.
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../../src/feature/block-edit/menu/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAYhD,OAAO,EAOL,KAAK,GAAG,EAGT,MAAM,KAAK,CAAA;AAEZ,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,IAAI,CAAA;AAwBhD,KAAK,SAAS,GAAG;IACf,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAClB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACnB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,MAAM,CAAC,EAAE,sBAAsB,CAAA;IAC/B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,IAAI,oWA4vCf,CAAA"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../../src/feature/block-edit/menu/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAYhD,OAAO,EAOL,KAAK,GAAG,EAGT,MAAM,KAAK,CAAA;AAEZ,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,IAAI,CAAA;AAwBhD,KAAK,SAAS,GAAG;IACf,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAClB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACnB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,MAAM,CAAC,EAAE,sBAAsB,CAAA;IAC/B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,IAAI,oWAoxCf,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"outline-panel.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/outline-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAgBhD,eAAO,MAAM,YAAY;;cAEE,MAAM,GAAG;;;;;cAAT,MAAM,GAAG;;;+GA+clC,CAAA"}
1
+ {"version":3,"file":"outline-panel.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/outline-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAgBhD,eAAO,MAAM,YAAY;;cAEE,MAAM,GAAG;;;;;cAAT,MAAM,GAAG;;;+GA0oBlC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../src/feature/toolbar/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAehD,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,+BAA+B,CAAA;AAUtC,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,UAAU,EAQhB,MAAM,KAAK,CAAA;AAEZ,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,GAAG,CAAA;AAmG7C,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAClB,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAeD,eAAO,MAAM,OAAO,0WAy9ElB,CAAA"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../../src/feature/toolbar/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAgBhD,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,+BAA+B,CAAA;AAUtC,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,UAAU,EAQhB,MAAM,KAAK,CAAA;AAEZ,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,GAAG,CAAA;AAmG7C,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAClB,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAeD,eAAO,MAAM,OAAO,0WA2+ElB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jvs-milkdown/crepe",
3
- "version": "1.2.16",
3
+ "version": "1.2.17",
4
4
  "keywords": [
5
5
  "crepe",
6
6
  "editor",
@@ -107,9 +107,9 @@
107
107
  "@codemirror/theme-one-dark": "^6.1.2",
108
108
  "@codemirror/view": "^6.26.0",
109
109
  "@floating-ui/dom": "^1.7.6",
110
- "@jvs-milkdown/kit": "^1.2.16",
111
- "@jvs-milkdown/prose": "^1.2.16",
112
- "@jvs-milkdown/utils": "^1.2.16",
110
+ "@jvs-milkdown/kit": "^1.2.17",
111
+ "@jvs-milkdown/prose": "^1.2.17",
112
+ "@jvs-milkdown/utils": "^1.2.17",
113
113
  "@types/lodash-es": "^4.17.12",
114
114
  "clsx": "^2.0.0",
115
115
  "codemirror": "^6.0.1",
@@ -1,7 +1,7 @@
1
1
  import type { Ctx } from '@jvs-milkdown/kit/ctx'
2
2
 
3
3
  import { Icon } from '@jvs-milkdown/kit/component'
4
- import { editorViewCtx, commandsCtx } from '@jvs-milkdown/kit/core'
4
+ import { editorViewCtx, commandsCtx, schemaCtx } from '@jvs-milkdown/kit/core'
5
5
  import {
6
6
  clearTextInCurrentBlockCommand,
7
7
  addBlockTypeCommand,
@@ -729,21 +729,31 @@ export const Menu = defineComponent<MenuProps>({
729
729
  let activeBgColor: string | null = null
730
730
 
731
731
  if (node && node.nodeSize > 2) {
732
- node.descendants((childNode: any) => {
733
- if (childNode.isText) {
734
- const tcType = textColorSchema.type(ctx)
735
- const bcType = bgColorSchema.type(ctx)
736
- if (!activeTextColor) {
737
- const tcMark = childNode.marks.find((m: any) => m.type === tcType)
738
- if (tcMark) activeTextColor = tcMark.attrs.color
739
- }
740
- if (!activeBgColor) {
741
- const bcMark = childNode.marks.find((m: any) => m.type === bcType)
742
- if (bcMark) activeBgColor = bcMark.attrs.color
732
+ const schema = ctx.get(schemaCtx)
733
+ const tcHasMark = schema.marks[textColorSchema.id]
734
+ const bcHasMark = schema.marks[bgColorSchema.id]
735
+
736
+ if (tcHasMark || bcHasMark) {
737
+ node.descendants((childNode: any) => {
738
+ if (childNode.isText) {
739
+ if (tcHasMark && !activeTextColor) {
740
+ const tcType = textColorSchema.type(ctx)
741
+ const tcMark = childNode.marks.find(
742
+ (m: any) => m.type === tcType
743
+ )
744
+ if (tcMark) activeTextColor = tcMark.attrs.color
745
+ }
746
+ if (bcHasMark && !activeBgColor) {
747
+ const bcType = bgColorSchema.type(ctx)
748
+ const bcMark = childNode.marks.find(
749
+ (m: any) => m.type === bcType
750
+ )
751
+ if (bcMark) activeBgColor = bcMark.attrs.color
752
+ }
743
753
  }
744
- }
745
- return false
746
- })
754
+ return false
755
+ })
756
+ }
747
757
  }
748
758
 
749
759
  const setBlockColor = (colorValue: string | null, isBg: boolean) => {
@@ -752,6 +762,12 @@ export const Menu = defineComponent<MenuProps>({
752
762
  const targetNode = tr.doc.nodeAt(pos)
753
763
  if (!targetNode) return
754
764
 
765
+ const schema = ctx.get(schemaCtx)
766
+ const hasMark = isBg
767
+ ? schema.marks[bgColorSchema.id]
768
+ : schema.marks[textColorSchema.id]
769
+ if (!hasMark) return
770
+
755
771
  const markType = isBg
756
772
  ? bgColorSchema.type(ctx)
757
773
  : textColorSchema.type(ctx)
@@ -779,11 +795,19 @@ export const Menu = defineComponent<MenuProps>({
779
795
  const targetNode = tr.doc.nodeAt(pos)
780
796
  if (!targetNode) return
781
797
 
798
+ const schema = ctx.get(schemaCtx)
799
+ const tcHasMark = schema.marks[textColorSchema.id]
800
+ const bcHasMark = schema.marks[bgColorSchema.id]
801
+
782
802
  const start = pos + 1
783
803
  const end = pos + targetNode.nodeSize - 1
784
804
 
785
- tr.removeMark(start, end, textColorSchema.type(ctx))
786
- tr.removeMark(start, end, bgColorSchema.type(ctx))
805
+ if (tcHasMark) {
806
+ tr.removeMark(start, end, textColorSchema.type(ctx))
807
+ }
808
+ if (bcHasMark) {
809
+ tr.removeMark(start, end, bgColorSchema.type(ctx))
810
+ }
787
811
 
788
812
  view.dispatch(tr)
789
813
  showColorMenu.value = false
@@ -25,6 +25,12 @@ export const OutlinePanel = defineComponent({
25
25
  const activeId = ref<string>('')
26
26
  const collapsedIds = ref<Set<string>>(new Set())
27
27
  let scrollLock = false
28
+ const clickedActiveId = ref<string | null>(null)
29
+
30
+ const clearClickedActive = () => {
31
+ if (scrollLock) return
32
+ clickedActiveId.value = null
33
+ }
28
34
 
29
35
  const hasChildren = (index: number) => {
30
36
  const current = items.value[index]
@@ -97,6 +103,11 @@ export const OutlinePanel = defineComponent({
97
103
  const view = props.ctx.get(editorViewCtx)
98
104
  if (!view || !view.dom) return
99
105
 
106
+ if (clickedActiveId.value) {
107
+ activeId.value = clickedActiveId.value
108
+ return
109
+ }
110
+
100
111
  const headings = Array.from(
101
112
  view.dom.querySelectorAll('h1, h2, h3, h4, h5, h6')
102
113
  )
@@ -105,19 +116,61 @@ export const OutlinePanel = defineComponent({
105
116
  return
106
117
  }
107
118
 
108
- // Use the scroll container's visible area, not the editor element
109
- // (editor top goes negative when scrolled, breaking threshold calculation)
110
- const scrollContainer = view.dom.parentElement
111
- if (!scrollContainer) return
119
+ // Find the actual scroll container
120
+ let scrollContainer: HTMLElement | null = view.dom.parentElement
121
+ while (scrollContainer && scrollContainer !== document.body) {
122
+ const style = window.getComputedStyle(scrollContainer)
123
+ const overflowY = style.overflowY
124
+ if (
125
+ (overflowY === 'auto' || overflowY === 'scroll') &&
126
+ scrollContainer.scrollHeight > scrollContainer.clientHeight
127
+ ) {
128
+ break
129
+ }
130
+ scrollContainer = scrollContainer.parentElement
131
+ }
112
132
 
113
- const toolbar = scrollContainer.querySelector(
133
+ const isRootScroll =
134
+ !scrollContainer ||
135
+ scrollContainer === document.body ||
136
+ scrollContainer === document.documentElement
137
+ const actualScrollContainer = isRootScroll
138
+ ? ((document.scrollingElement ||
139
+ document.documentElement ||
140
+ document.body) as HTMLElement)
141
+ : scrollContainer!
142
+
143
+ const rootNode = view.dom.getRootNode() as Document | ShadowRoot
144
+ let toolbar = rootNode.querySelector(
114
145
  '.milkdown-fixed-toolbar'
115
146
  ) as HTMLElement | null
147
+ if (!toolbar) {
148
+ toolbar = document.querySelector(
149
+ '.milkdown-fixed-toolbar'
150
+ ) as HTMLElement | null
151
+ }
116
152
  const toolbarHeight = toolbar?.offsetHeight || 0
117
- const containerRect = scrollContainer.getBoundingClientRect()
118
- // 50px buffer: tight enough to exclude the next heading
119
- // (min gap between consecutive headings ~44px for h5/h6)
120
- const threshold = containerRect.top + toolbarHeight + 50
153
+ const containerRect = actualScrollContainer.getBoundingClientRect()
154
+ // Use Math.max(0, containerRect.top) because when container scrolls off-screen,
155
+ // its visual top boundary is the top of the viewport (0)
156
+ const containerTop = isRootScroll ? 0 : Math.max(0, containerRect.top)
157
+
158
+ let scrollTop = actualScrollContainer.scrollTop
159
+ let clientHeight = actualScrollContainer.clientHeight
160
+ let scrollHeight = actualScrollContainer.scrollHeight
161
+
162
+ if (isRootScroll) {
163
+ scrollTop = window.scrollY || document.documentElement.scrollTop
164
+ clientHeight =
165
+ window.innerHeight || document.documentElement.clientHeight
166
+ scrollHeight =
167
+ document.documentElement.scrollHeight || document.body.scrollHeight
168
+ }
169
+
170
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight - 15
171
+ const threshold = isAtBottom
172
+ ? containerTop + clientHeight
173
+ : containerTop + toolbarHeight + 50
121
174
 
122
175
  let active = headings[0]
123
176
  for (const h of headings as HTMLElement[]) {
@@ -128,57 +181,158 @@ export const OutlinePanel = defineComponent({
128
181
  break
129
182
  }
130
183
  }
131
- activeId.value = (active as any)?.id || ''
184
+
185
+ // Compare DOM node references directly to identify active outline item without relying on ID
186
+ const activeItem = items.value.find((item) => {
187
+ try {
188
+ const activePos = view.posAtDOM(active, 0)
189
+ const isPosMatch = item.pos === activePos - 1
190
+
191
+ let isDepthMatch = false
192
+ const $pos = view.state.doc.resolve(activePos)
193
+ for (let d = $pos.depth; d >= 0; d--) {
194
+ if ($pos.node(d).type.name === 'heading') {
195
+ if (item.pos === $pos.before(d)) {
196
+ isDepthMatch = true
197
+ break
198
+ }
199
+ }
200
+ }
201
+
202
+ if (isPosMatch || isDepthMatch) {
203
+ return true
204
+ }
205
+ } catch (e) {
206
+ // Silent catch
207
+ }
208
+
209
+ const dom = view.nodeDOM(item.pos)
210
+ const domMatch =
211
+ dom === active ||
212
+ (dom instanceof HTMLElement && active && dom.contains(active as Node))
213
+ if (domMatch) {
214
+ return true
215
+ }
216
+ return false
217
+ })
218
+
219
+ const newActiveId = activeItem ? activeItem.id : (active as any)?.id || ''
220
+ activeId.value = newActiveId
132
221
  }
133
222
 
134
- const scrollToHeading = (id: string) => {
223
+ const scrollToHeading = (item: OutlineItem) => {
135
224
  const view = props.ctx.get(editorViewCtx)
136
225
  if (!view) return
137
226
 
138
227
  try {
139
- const headingEl = view.dom.querySelector(
140
- `[id="${id}"]`
141
- ) as HTMLElement | null
228
+ let headingEl = view.nodeDOM(item.pos) as HTMLElement | null
229
+ if (!headingEl) {
230
+ try {
231
+ const domAt = view.domAtPos(item.pos)
232
+ let node = domAt.node
233
+ if (node.nodeType === Node.TEXT_NODE) {
234
+ node = node.parentElement!
235
+ }
236
+ if (node instanceof HTMLElement) {
237
+ headingEl = node.closest(
238
+ 'h1, h2, h3, h4, h5, h6'
239
+ ) as HTMLElement | null
240
+ if (!headingEl && domAt.offset < node.childNodes.length) {
241
+ const child = node.childNodes[domAt.offset]
242
+ if (child instanceof HTMLElement) {
243
+ headingEl = (child.closest('h1, h2, h3, h4, h5, h6') ||
244
+ child.querySelector(
245
+ 'h1, h2, h3, h4, h5, h6'
246
+ )) as HTMLElement | null
247
+ }
248
+ }
249
+ }
250
+ } catch {}
251
+ }
252
+ if (!headingEl) {
253
+ headingEl = view.dom.querySelector(
254
+ `[id="${item.id}"]`
255
+ ) as HTMLElement | null
256
+ }
142
257
  if (!headingEl) return
143
258
 
144
- const scrollContainer = view.dom.parentElement
145
- if (!scrollContainer) return
259
+ // Find the actual scroll container
260
+ let scrollContainer: HTMLElement | null = view.dom.parentElement
261
+ while (scrollContainer && scrollContainer !== document.body) {
262
+ const style = window.getComputedStyle(scrollContainer)
263
+ const overflowY = style.overflowY
264
+ if (
265
+ (overflowY === 'auto' || overflowY === 'scroll') &&
266
+ scrollContainer.scrollHeight > scrollContainer.clientHeight
267
+ ) {
268
+ break
269
+ }
270
+ scrollContainer = scrollContainer.parentElement
271
+ }
272
+
273
+ const isRootScroll =
274
+ !scrollContainer ||
275
+ scrollContainer === document.body ||
276
+ scrollContainer === document.documentElement
277
+ const actualScrollContainer = isRootScroll
278
+ ? ((document.scrollingElement ||
279
+ document.documentElement ||
280
+ document.body) as HTMLElement)
281
+ : scrollContainer!
146
282
 
147
283
  scrollLock = true
148
284
 
149
- const toolbar = scrollContainer.querySelector(
285
+ const rootNode = view.dom.getRootNode() as Document | ShadowRoot
286
+ let toolbar = rootNode.querySelector(
150
287
  '.milkdown-fixed-toolbar'
151
288
  ) as HTMLElement | null
289
+ if (!toolbar) {
290
+ toolbar = document.querySelector(
291
+ '.milkdown-fixed-toolbar'
292
+ ) as HTMLElement | null
293
+ }
152
294
  const toolbarHeight = toolbar?.offsetHeight || 0
153
- const containerRect = scrollContainer.getBoundingClientRect()
295
+ const containerRectTop = isRootScroll
296
+ ? 0
297
+ : actualScrollContainer.getBoundingClientRect().top
154
298
  const headingRect = headingEl.getBoundingClientRect()
155
299
 
156
- scrollContainer.scrollTo({
157
- top:
158
- scrollContainer.scrollTop +
159
- headingRect.top -
160
- containerRect.top -
161
- toolbarHeight -
162
- 20,
163
- behavior: 'smooth',
164
- })
300
+ const targetTop =
301
+ actualScrollContainer.scrollTop +
302
+ headingRect.top -
303
+ containerRectTop -
304
+ toolbarHeight -
305
+ 20
165
306
 
307
+ const scrollTarget = isRootScroll ? window : actualScrollContainer
166
308
  let timer: ReturnType<typeof setTimeout>
167
309
  const onScrollEnd = () => {
168
310
  clearTimeout(timer)
169
311
  timer = setTimeout(() => {
170
312
  scrollLock = false
171
- scrollContainer.removeEventListener('scroll', onScrollEnd)
313
+ scrollTarget.removeEventListener('scroll', onScrollEnd)
172
314
  checkActive()
173
315
  }, 150)
174
316
  }
175
- scrollContainer.addEventListener('scroll', onScrollEnd)
317
+ scrollTarget.addEventListener('scroll', onScrollEnd)
176
318
 
177
319
  // Safety timeout in case scroll events are not fired
178
320
  setTimeout(() => {
179
321
  scrollLock = false
180
- scrollContainer.removeEventListener('scroll', onScrollEnd)
322
+ scrollTarget.removeEventListener('scroll', onScrollEnd)
181
323
  }, 2000)
324
+
325
+ if (isRootScroll) {
326
+ window.scrollTo({
327
+ top: targetTop,
328
+ behavior: 'smooth',
329
+ })
330
+ } else {
331
+ actualScrollContainer.scrollTo({
332
+ top: targetTop,
333
+ behavior: 'smooth',
334
+ })
335
+ }
182
336
  } catch {
183
337
  scrollLock = false
184
338
  updateOutline()
@@ -192,6 +346,31 @@ export const OutlinePanel = defineComponent({
192
346
  onMounted(() => {
193
347
  updateOutline()
194
348
  checkActive()
349
+
350
+ window.addEventListener('wheel', clearClickedActive, { passive: true })
351
+ window.addEventListener('touchmove', clearClickedActive, {
352
+ passive: true,
353
+ })
354
+ window.addEventListener('pointerdown', clearClickedActive, {
355
+ passive: true,
356
+ })
357
+ const keyHandler = (e: KeyboardEvent) => {
358
+ if (
359
+ [
360
+ 'ArrowUp',
361
+ 'ArrowDown',
362
+ 'PageUp',
363
+ 'PageDown',
364
+ 'Home',
365
+ 'End',
366
+ ].includes(e.key)
367
+ ) {
368
+ clearClickedActive()
369
+ }
370
+ }
371
+ window.addEventListener('keydown', keyHandler, { passive: true })
372
+ ;(onMounted as any)._keyHandler = keyHandler
373
+
195
374
  interval = setInterval(() => {
196
375
  if (viewState.value.outlineVisible) {
197
376
  updateOutline()
@@ -212,6 +391,13 @@ export const OutlinePanel = defineComponent({
212
391
  if (interval) clearInterval(interval)
213
392
  if (pollInterval) clearInterval(pollInterval)
214
393
  window.removeEventListener('scroll', checkActive, true)
394
+ window.removeEventListener('wheel', clearClickedActive)
395
+ window.removeEventListener('touchmove', clearClickedActive)
396
+ window.removeEventListener('pointerdown', clearClickedActive)
397
+ const keyHandler = (onMounted as any)._keyHandler
398
+ if (keyHandler) {
399
+ window.removeEventListener('keydown', keyHandler)
400
+ }
215
401
  })
216
402
 
217
403
  // Drag to resize logic
@@ -359,7 +545,8 @@ export const OutlinePanel = defineComponent({
359
545
  key={item.id}
360
546
  onClick={() => {
361
547
  activeId.value = item.id
362
- scrollToHeading(item.id)
548
+ clickedActiveId.value = item.id
549
+ scrollToHeading(item)
363
550
  }}
364
551
  style={{
365
552
  display: 'flex',
@@ -429,7 +616,7 @@ export const OutlinePanel = defineComponent({
429
616
  'transparent'
430
617
  }}
431
618
  >
432
- �?{' '}
619
+ {'\u25BC'}{' '}
433
620
  </span>
434
621
  {/* Text - click to scroll */}
435
622
  <span
@@ -7,6 +7,7 @@ import {
7
7
  EditorStatus,
8
8
  editorViewCtx,
9
9
  commandsCtx,
10
+ schemaCtx,
10
11
  } from '@jvs-milkdown/kit/core'
11
12
  import {
12
13
  addBlockTypeCommand,
@@ -1094,6 +1095,12 @@ export const Toolbar = defineComponent<ToolbarProps>({
1094
1095
 
1095
1096
  const view = ctx.get(editorViewCtx)
1096
1097
  const { state } = view
1098
+ const schema = ctx.get(schemaCtx)
1099
+
1100
+ const tcHasMark = schema.marks[textColorSchema.id]
1101
+ const bcHasMark = schema.marks[bgColorSchema.id]
1102
+
1103
+ if (!tcHasMark || !bcHasMark) return { textColor: null, bgColor: null }
1097
1104
 
1098
1105
  const tcType = textColorSchema.type(ctx)
1099
1106
  const bcType = bgColorSchema.type(ctx)
@@ -1147,6 +1154,12 @@ export const Toolbar = defineComponent<ToolbarProps>({
1147
1154
  const { state, dispatch } = view
1148
1155
  const { tr } = state
1149
1156
  const { from, to, empty } = state.selection
1157
+ const schema = ctx.get(schemaCtx)
1158
+
1159
+ const tcHasMark = schema.marks[textColorSchema.id]
1160
+ const bcHasMark = schema.marks[bgColorSchema.id]
1161
+
1162
+ if (!tcHasMark || !bcHasMark) return
1150
1163
 
1151
1164
  const textColorType = textColorSchema.type(ctx)
1152
1165
  const bgColorType = bgColorSchema.type(ctx)
@@ -1173,6 +1186,12 @@ export const Toolbar = defineComponent<ToolbarProps>({
1173
1186
 
1174
1187
  const view = ctx.get(editorViewCtx)
1175
1188
  const { state } = view
1189
+ const schema = ctx.get(schemaCtx)
1190
+
1191
+ const ffHasMark = schema.marks[fontFamilySchema.id]
1192
+ const fsHasMark = schema.marks[fontSizeSchema.id]
1193
+
1194
+ if (!ffHasMark || !fsHasMark) return { fontFamily: null, fontSize: null }
1176
1195
 
1177
1196
  const ffType = fontFamilySchema.type(ctx)
1178
1197
  const fsType = fontSizeSchema.type(ctx)