@milkdown/preset-commonmark
Version:
The commonmark preset of [milkdown](https://milkdown.dev/).
142 lines (127 loc) • 3.57 kB
text/typescript
import { commandsCtx } from '@milkdown/core'
import { expectDomTypeError } from '@milkdown/exception'
import { wrapIn } from '@milkdown/prose/commands'
import { wrappingInputRule } from '@milkdown/prose/inputrules'
import {
$command,
$inputRule,
$nodeAttr,
$nodeSchema,
$useKeymap,
} from '@milkdown/utils'
import { withMeta } from '../__internal__'
/// HTML attributes for ordered list node.
export const orderedListAttr = $nodeAttr('orderedList')
withMeta(orderedListAttr, {
displayName: 'Attr<orderedList>',
group: 'OrderedList',
})
/// Schema for ordered list node.
export const orderedListSchema = $nodeSchema('ordered_list', (ctx) => ({
content: 'listItem+',
group: 'block',
attrs: {
order: {
default: 1,
validate: 'number',
},
spread: {
default: false,
validate: 'boolean',
},
},
parseDOM: [
{
tag: 'ol',
getAttrs: (dom) => {
if (!(dom instanceof HTMLElement)) throw expectDomTypeError(dom)
return {
spread: dom.dataset.spread,
order: dom.hasAttribute('start')
? Number(dom.getAttribute('start'))
: 1,
}
},
},
],
toDOM: (node) => [
'ol',
{
...ctx.get(orderedListAttr.key)(node),
...(node.attrs.order === 1 ? {} : { start: node.attrs.order }),
'data-spread': node.attrs.spread,
},
0,
],
parseMarkdown: {
match: ({ type, ordered }) => type === 'list' && !!ordered,
runner: (state, node, type) => {
const spread = node.spread != null ? `${node.spread}` : 'true'
state
.openNode(type, { spread, order: node.start ?? 1 })
.next(node.children)
.closeNode()
},
},
toMarkdown: {
match: (node) => node.type.name === 'ordered_list',
runner: (state, node) => {
state.openNode('list', undefined, {
ordered: true,
start: node.attrs.order ?? 1,
spread: node.attrs.spread === 'true',
})
state.next(node.content)
state.closeNode()
},
},
}))
withMeta(orderedListSchema.node, {
displayName: 'NodeSchema<orderedList>',
group: 'OrderedList',
})
withMeta(orderedListSchema.ctx, {
displayName: 'NodeSchemaCtx<orderedList>',
group: 'OrderedList',
})
/// Input rule for wrapping a block in ordered list node.
export const wrapInOrderedListInputRule = $inputRule((ctx) =>
wrappingInputRule(
/^\s*(\d+)\.\s$/,
orderedListSchema.type(ctx),
(match) => ({ order: Number(match[1]) }),
(match, node) => node.childCount + node.attrs.order === Number(match[1])
)
)
withMeta(wrapInOrderedListInputRule, {
displayName: 'InputRule<wrapInOrderedListInputRule>',
group: 'OrderedList',
})
/// Command for wrapping a block in ordered list node.
export const wrapInOrderedListCommand = $command(
'WrapInOrderedList',
(ctx) => () => wrapIn(orderedListSchema.type(ctx))
)
withMeta(wrapInOrderedListCommand, {
displayName: 'Command<wrapInOrderedListCommand>',
group: 'OrderedList',
})
/// Keymap for ordered list node.
/// - `Mod-Alt-7`: Wrap a block in ordered list.
export const orderedListKeymap = $useKeymap('orderedListKeymap', {
WrapInOrderedList: {
shortcuts: 'Mod-Alt-7',
command: (ctx) => {
const commands = ctx.get(commandsCtx)
return () => commands.call(wrapInOrderedListCommand.key)
},
},
})
withMeta(orderedListKeymap.ctx, {
displayName: 'KeymapCtx<orderedList>',
group: 'OrderedList',
})
withMeta(orderedListKeymap.shortcuts, {
displayName: 'Keymap<orderedList>',
group: 'OrderedList',
})