-
-
Notifications
You must be signed in to change notification settings - Fork 432
/
Copy pathsync-heading-id-plugin.ts
61 lines (50 loc) · 1.53 KB
/
sync-heading-id-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* Copyright 2021, Milkdown by Mirone. */
import { Plugin, PluginKey } from '@milkdown/prose/state'
import type { EditorView } from '@milkdown/prose/view'
import { $prose } from '@milkdown/utils'
import { headingIdGenerator, headingSchema } from '../node/heading'
import { withMeta } from '../__internal__'
/// This plugin is used to sync the heading id when the heading content changes.
/// It will use the `headingIdGenerator` to generate the id.
export const syncHeadingIdPlugin = $prose((ctx) => {
const headingIdPluginKey = new PluginKey('MILKDOWN_HEADING_ID')
const updateId = (view: EditorView) => {
if (view.composing)
return
const getId = ctx.get(headingIdGenerator.key)
const tr = view.state.tr.setMeta('addToHistory', false)
let found = false
view.state.doc.descendants((node, pos) => {
if (node.type === headingSchema.type(ctx)) {
if (node.textContent.trim().length === 0)
return
const attrs = node.attrs
const id = getId(node)
if (attrs.id !== id) {
found = true
tr.setMeta(headingIdPluginKey, true).setNodeMarkup(pos, undefined, {
...attrs,
id,
})
}
}
})
if (found)
view.dispatch(tr)
}
return new Plugin({
key: headingIdPluginKey,
view: (view) => {
updateId(view)
return {
update: (view) => {
updateId(view)
},
}
},
})
})
withMeta(syncHeadingIdPlugin, {
displayName: 'Prose<syncHeadingIdPlugin>',
group: 'Prose',
})