UNPKG

@milkdown/preset-commonmark

Version:

The commonmark preset of [milkdown](https://milkdown.dev/).

92 lines (80 loc) 2.74 kB
import type { EditorView } from '@milkdown/prose/view' import { Plugin, PluginKey } from '@milkdown/prose/state' import { $prose } from '@milkdown/utils' import { withMeta } from '../__internal__' import { bulletListSchema } from '../node' import { listItemSchema } from '../node/list-item' import { orderedListSchema } from '../node/ordered-list' /// This plugin is used to keep the label of list item up to date in ordered list. export const syncListOrderPlugin = $prose((ctx) => { const syncOrderLabel = (view: EditorView) => { if (view.composing || !view.editable) return const orderedListType = orderedListSchema.type(ctx) const bulletListType = bulletListSchema.type(ctx) const listItemType = listItemSchema.type(ctx) const state = view.state const handleNodeItem = ( attrs: Record<string, any>, index: number ): boolean => { let changed = false const expectedLabel = `${index + 1}.` if (attrs.label !== expectedLabel) { attrs.label = expectedLabel changed = true } return changed } let tr = state.tr let needDispatch = false state.doc.descendants((node, pos, parent, index) => { if (node.type === bulletListType) { const base = node.maybeChild(0) if (base?.type === listItemType && base.attrs.listType === 'ordered') { needDispatch = true tr.setNodeMarkup(pos, orderedListType, { spread: 'true' }) node.descendants((child, pos, _parent, index) => { if (child.type === listItemType) { const attrs = { ...child.attrs } const changed = handleNodeItem(attrs, index) if (changed) tr = tr.setNodeMarkup(pos, undefined, attrs) } return false }) } } else if ( node.type === listItemType && parent?.type === orderedListType ) { const attrs = { ...node.attrs } let changed = false if (attrs.listType !== 'ordered') { attrs.listType = 'ordered' changed = true } const base = parent?.maybeChild(0) if (base) changed = handleNodeItem(attrs, index) if (changed) { tr = tr.setNodeMarkup(pos, undefined, attrs) needDispatch = true } } }) if (needDispatch) view.dispatch(tr.setMeta('addToHistory', false)) } return new Plugin({ key: new PluginKey('MILKDOWN_KEEP_LIST_ORDER'), view: (view) => { syncOrderLabel(view) return { update: (view) => { syncOrderLabel(view) }, } }, }) }) withMeta(syncListOrderPlugin, { displayName: 'Prose<syncListOrderPlugin>', group: 'Prose', })