@milkdown/preset-commonmark 6.5.4 → 7.0.0-next.1
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.
- package/lib/composed/commands.d.ts +3 -0
- package/lib/composed/commands.d.ts.map +1 -0
- package/lib/composed/index.d.ts +6 -0
- package/lib/composed/index.d.ts.map +1 -0
- package/lib/composed/inputrules.d.ts +3 -0
- package/lib/composed/inputrules.d.ts.map +1 -0
- package/lib/composed/keymap.d.ts +3 -0
- package/lib/composed/keymap.d.ts.map +1 -0
- package/lib/composed/plugins.d.ts +3 -0
- package/lib/composed/plugins.d.ts.map +1 -0
- package/lib/composed/schema.d.ts +3 -0
- package/lib/composed/schema.d.ts.map +1 -0
- package/lib/index.d.ts +4 -29
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +1099 -1386
- package/lib/index.es.js.map +1 -1
- package/lib/mark/emphasis.d.ts +5 -0
- package/lib/mark/emphasis.d.ts.map +1 -0
- package/lib/mark/index.d.ts +3 -4
- package/lib/mark/index.d.ts.map +1 -1
- package/lib/mark/inline-code.d.ts +5 -0
- package/lib/mark/inline-code.d.ts.map +1 -0
- package/lib/mark/link.d.ts +8 -10
- package/lib/mark/link.d.ts.map +1 -1
- package/lib/mark/strong.d.ts +4 -2
- package/lib/mark/strong.d.ts.map +1 -1
- package/lib/node/blockquote.d.ts +6 -2
- package/lib/node/blockquote.d.ts.map +1 -1
- package/lib/node/bullet-list.d.ts +5 -2
- package/lib/node/bullet-list.d.ts.map +1 -1
- package/lib/node/code-block.d.ts +10 -0
- package/lib/node/code-block.d.ts.map +1 -0
- package/lib/node/doc.d.ts +1 -1
- package/lib/node/doc.d.ts.map +1 -1
- package/lib/node/hardbreak.d.ts +4 -6
- package/lib/node/hardbreak.d.ts.map +1 -1
- package/lib/node/heading.d.ts +7 -12
- package/lib/node/heading.d.ts.map +1 -1
- package/lib/node/hr.d.ts +4 -2
- package/lib/node/hr.d.ts.map +1 -1
- package/lib/node/image.d.ts +10 -11
- package/lib/node/image.d.ts.map +1 -1
- package/lib/node/index.d.ts +6 -8
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/list-item.d.ts +6 -7
- package/lib/node/list-item.d.ts.map +1 -1
- package/lib/node/ordered-list.d.ts +5 -2
- package/lib/node/ordered-list.d.ts.map +1 -1
- package/lib/node/paragraph.d.ts +4 -2
- package/lib/node/paragraph.d.ts.map +1 -1
- package/lib/node/text.d.ts +1 -1
- package/lib/node/text.d.ts.map +1 -1
- package/lib/plugin/hardbreak-clear-mark-plugin.d.ts +2 -0
- package/lib/plugin/hardbreak-clear-mark-plugin.d.ts.map +1 -0
- package/lib/plugin/hardbreak-filter-plugin.d.ts +3 -0
- package/lib/plugin/hardbreak-filter-plugin.d.ts.map +1 -0
- package/lib/plugin/index.d.ts +9 -3
- package/lib/plugin/index.d.ts.map +1 -1
- package/lib/plugin/inline-nodes-cursor-plugin.d.ts +2 -0
- package/lib/plugin/inline-nodes-cursor-plugin.d.ts.map +1 -0
- package/lib/plugin/{inline-sync → inline-sync-plugin}/config.d.ts +2 -2
- package/lib/plugin/inline-sync-plugin/config.d.ts.map +1 -0
- package/lib/plugin/{inline-sync → inline-sync-plugin}/context.d.ts +1 -2
- package/lib/plugin/inline-sync-plugin/context.d.ts.map +1 -0
- package/lib/plugin/inline-sync-plugin/index.d.ts +3 -0
- package/lib/plugin/inline-sync-plugin/index.d.ts.map +1 -0
- package/lib/plugin/inline-sync-plugin/inline-sync-plugin.d.ts +2 -0
- package/lib/plugin/inline-sync-plugin/inline-sync-plugin.d.ts.map +1 -0
- package/lib/plugin/{inline-sync → inline-sync-plugin}/regexp.d.ts +0 -0
- package/lib/plugin/inline-sync-plugin/regexp.d.ts.map +1 -0
- package/lib/plugin/{inline-sync → inline-sync-plugin}/replacer.d.ts +1 -1
- package/lib/plugin/inline-sync-plugin/replacer.d.ts.map +1 -0
- package/lib/plugin/{inline-sync → inline-sync-plugin}/utils.d.ts +0 -0
- package/lib/plugin/inline-sync-plugin/utils.d.ts.map +1 -0
- package/lib/plugin/remark-add-order-in-list-plugin.d.ts +2 -0
- package/lib/plugin/remark-add-order-in-list-plugin.d.ts.map +1 -0
- package/lib/plugin/remark-inline-link-plugin.d.ts +2 -0
- package/lib/plugin/remark-inline-link-plugin.d.ts.map +1 -0
- package/lib/plugin/remark-line-break.d.ts +2 -0
- package/lib/plugin/remark-line-break.d.ts.map +1 -0
- package/lib/plugin/sync-heading-id-plugin.d.ts +2 -0
- package/lib/plugin/sync-heading-id-plugin.d.ts.map +1 -0
- package/lib/plugin/sync-list-order-plugin.d.ts +2 -0
- package/lib/plugin/sync-list-order-plugin.d.ts.map +1 -0
- package/package.json +9 -7
- package/src/composed/commands.ts +31 -0
- package/src/composed/index.ts +6 -0
- package/src/composed/inputrules.ts +13 -0
- package/src/composed/keymap.ts +20 -0
- package/src/composed/plugins.ts +23 -0
- package/src/composed/schema.ts +55 -0
- package/src/index.ts +6 -52
- package/src/mark/emphasis.ts +47 -0
- package/src/mark/index.ts +3 -10
- package/src/mark/inline-code.ts +70 -0
- package/src/mark/link.ts +96 -247
- package/src/mark/strong.ts +41 -36
- package/src/node/blockquote.ts +39 -33
- package/src/node/bullet-list.ts +62 -55
- package/src/node/code-block.ts +103 -0
- package/src/node/doc.ts +18 -22
- package/src/node/hardbreak.ts +68 -117
- package/src/node/heading.ts +175 -284
- package/src/node/hr.ts +57 -57
- package/src/node/image.ts +113 -209
- package/src/node/index.ts +6 -35
- package/src/node/list-item.ts +125 -141
- package/src/node/ordered-list.ts +70 -65
- package/src/node/paragraph.ts +54 -50
- package/src/node/text.ts +14 -16
- package/src/plugin/hardbreak-clear-mark-plugin.ts +45 -0
- package/src/plugin/hardbreak-filter-plugin.ts +33 -0
- package/src/plugin/index.ts +12 -14
- package/src/plugin/{inline-nodes-cursor.ts → inline-nodes-cursor-plugin.ts} +5 -8
- package/src/plugin/{inline-sync → inline-sync-plugin}/config.ts +18 -3
- package/src/plugin/{inline-sync → inline-sync-plugin}/context.ts +4 -6
- package/src/plugin/inline-sync-plugin/index.ts +4 -0
- package/src/plugin/{inline-sync/index.ts → inline-sync-plugin/inline-sync-plugin.ts} +14 -11
- package/src/plugin/{inline-sync → inline-sync-plugin}/regexp.ts +0 -0
- package/src/plugin/{inline-sync → inline-sync-plugin}/replacer.ts +3 -3
- package/src/plugin/{inline-sync → inline-sync-plugin}/utils.ts +0 -0
- package/src/plugin/remark-add-order-in-list-plugin.ts +16 -0
- package/src/plugin/remark-inline-link-plugin.ts +6 -0
- package/src/plugin/remark-line-break.ts +44 -0
- package/src/plugin/sync-heading-id-plugin.ts +55 -0
- package/src/plugin/sync-list-order-plugin.ts +57 -0
- package/lib/mark/code-inline.d.ts +0 -3
- package/lib/mark/code-inline.d.ts.map +0 -1
- package/lib/mark/em.d.ts +0 -3
- package/lib/mark/em.d.ts.map +0 -1
- package/lib/node/code-fence.d.ts +0 -7
- package/lib/node/code-fence.d.ts.map +0 -1
- package/lib/plugin/add-order-in-list.d.ts +0 -3
- package/lib/plugin/add-order-in-list.d.ts.map +0 -1
- package/lib/plugin/filter-html.d.ts +0 -3
- package/lib/plugin/filter-html.d.ts.map +0 -1
- package/lib/plugin/inline-nodes-cursor.d.ts +0 -7
- package/lib/plugin/inline-nodes-cursor.d.ts.map +0 -1
- package/lib/plugin/inline-sync/config.d.ts.map +0 -1
- package/lib/plugin/inline-sync/context.d.ts.map +0 -1
- package/lib/plugin/inline-sync/index.d.ts +0 -6
- package/lib/plugin/inline-sync/index.d.ts.map +0 -1
- package/lib/plugin/inline-sync/regexp.d.ts.map +0 -1
- package/lib/plugin/inline-sync/replacer.d.ts.map +0 -1
- package/lib/plugin/inline-sync/utils.d.ts.map +0 -1
- package/lib/supported-keys.d.ts +0 -23
- package/lib/supported-keys.d.ts.map +0 -1
- package/src/mark/code-inline.ts +0 -66
- package/src/mark/em.ts +0 -42
- package/src/node/code-fence.ts +0 -245
- package/src/plugin/add-order-in-list.ts +0 -19
- package/src/plugin/filter-html.ts +0 -43
- package/src/supported-keys.ts +0 -25
- package/src/types.d.ts +0 -5
package/src/node/ordered-list.ts
CHANGED
|
@@ -1,79 +1,84 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
2
|
+
import { commandsCtx } from '@milkdown/core'
|
|
3
3
|
import { expectDomTypeError } from '@milkdown/exception'
|
|
4
4
|
import { wrapIn } from '@milkdown/prose/commands'
|
|
5
5
|
import { wrappingInputRule } from '@milkdown/prose/inputrules'
|
|
6
|
-
import {
|
|
6
|
+
import { $command, $inputRule, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/// HTML attributes for ordered list node.
|
|
9
|
+
export const orderedListAttr = $nodeAttr('orderedList')
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
attrs: {
|
|
21
|
-
order: {
|
|
22
|
-
default: 1,
|
|
23
|
-
},
|
|
24
|
-
spread: {
|
|
25
|
-
default: false,
|
|
26
|
-
},
|
|
11
|
+
/// Schema for ordered list node.
|
|
12
|
+
export const orderedListSchema = $nodeSchema('ordered_list', ctx => ({
|
|
13
|
+
content: 'listItem+',
|
|
14
|
+
group: 'block',
|
|
15
|
+
attrs: {
|
|
16
|
+
order: {
|
|
17
|
+
default: 1,
|
|
18
|
+
},
|
|
19
|
+
spread: {
|
|
20
|
+
default: false,
|
|
27
21
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
},
|
|
23
|
+
parseDOM: [
|
|
24
|
+
{
|
|
25
|
+
tag: 'ol',
|
|
26
|
+
getAttrs: (dom) => {
|
|
27
|
+
if (!(dom instanceof HTMLElement))
|
|
28
|
+
throw expectDomTypeError(dom)
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
toDOM: node => [
|
|
43
|
-
'ol',
|
|
44
|
-
{
|
|
45
|
-
...(node.attrs.order === 1 ? {} : node.attrs.order),
|
|
46
|
-
'data-spread': node.attrs.spread,
|
|
47
|
-
'class': utils.getClassName(node.attrs, 'ordered-list'),
|
|
48
|
-
},
|
|
49
|
-
0,
|
|
50
|
-
],
|
|
51
|
-
parseMarkdown: {
|
|
52
|
-
match: ({ type, ordered }) => type === 'list' && !!ordered,
|
|
53
|
-
runner: (state, node, type) => {
|
|
54
|
-
const spread = node.spread != null ? `${node.spread}` : 'true'
|
|
55
|
-
state.openNode(type, { spread }).next(node.children).closeNode()
|
|
30
|
+
return {
|
|
31
|
+
spread: dom.dataset.spread,
|
|
32
|
+
order: dom.hasAttribute('start') ? Number(dom.getAttribute('start')) : 1,
|
|
33
|
+
}
|
|
56
34
|
},
|
|
57
35
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
36
|
+
],
|
|
37
|
+
toDOM: node => [
|
|
38
|
+
'ol',
|
|
39
|
+
{
|
|
40
|
+
...ctx.get(orderedListAttr.key)(node),
|
|
41
|
+
...(node.attrs.order === 1 ? {} : node.attrs.order),
|
|
42
|
+
'data-spread': node.attrs.spread,
|
|
65
43
|
},
|
|
66
|
-
|
|
67
|
-
inputRules: nodeType => [
|
|
68
|
-
wrappingInputRule(
|
|
69
|
-
/^(\d+)\.\s$/,
|
|
70
|
-
nodeType,
|
|
71
|
-
match => ({ order: Number(match[1]) }),
|
|
72
|
-
(match, node) => node.childCount + node.attrs.order === Number(match[1]),
|
|
73
|
-
),
|
|
44
|
+
0,
|
|
74
45
|
],
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
46
|
+
parseMarkdown: {
|
|
47
|
+
match: ({ type, ordered }) => type === 'list' && !!ordered,
|
|
48
|
+
runner: (state, node, type) => {
|
|
49
|
+
const spread = node.spread != null ? `${node.spread}` : 'true'
|
|
50
|
+
state.openNode(type, { spread }).next(node.children).closeNode()
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
toMarkdown: {
|
|
54
|
+
match: node => node.type.name === 'ordered_list',
|
|
55
|
+
runner: (state, node) => {
|
|
56
|
+
state.openNode('list', undefined, { ordered: true, start: 1, spread: node.attrs.spread === 'true' })
|
|
57
|
+
state.next(node.content)
|
|
58
|
+
state.closeNode()
|
|
59
|
+
},
|
|
78
60
|
},
|
|
79
61
|
}))
|
|
62
|
+
|
|
63
|
+
/// Input rule for wrapping a block in ordered list node.
|
|
64
|
+
export const wrapInOrderedListInputRule = $inputRule(() => wrappingInputRule(
|
|
65
|
+
/^\s*(\d+)\.\s$/,
|
|
66
|
+
orderedListSchema.type(),
|
|
67
|
+
match => ({ order: Number(match[1]) }),
|
|
68
|
+
(match, node) => node.childCount + node.attrs.order === Number(match[1]),
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
/// Command for wrapping a block in ordered list node.
|
|
72
|
+
export const wrapInOrderedListCommand = $command('WrapInOrderedList', () => () => wrapIn(orderedListSchema.type()))
|
|
73
|
+
|
|
74
|
+
/// Keymap for ordered list node.
|
|
75
|
+
/// - `Mod-Alt-7`: Wrap a block in ordered list.
|
|
76
|
+
export const orderedListKeymap = $useKeymap('orderedListKeymap', {
|
|
77
|
+
WrapInOrderedList: {
|
|
78
|
+
shortcuts: 'Mod-Alt-7',
|
|
79
|
+
command: (ctx) => {
|
|
80
|
+
const commands = ctx.get(commandsCtx)
|
|
81
|
+
return () => commands.call(wrapInOrderedListCommand.key)
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
})
|
package/src/node/paragraph.ts
CHANGED
|
@@ -1,62 +1,66 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
2
|
+
import { commandsCtx } from '@milkdown/core'
|
|
3
3
|
import { setBlockType } from '@milkdown/prose/commands'
|
|
4
4
|
import type { Node } from '@milkdown/prose/model'
|
|
5
5
|
import { Fragment } from '@milkdown/prose/model'
|
|
6
|
-
import {
|
|
6
|
+
import { $command, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/// HTML attributes for paragraph node.
|
|
9
|
+
export const paragraphAttr = $nodeAttr('paragraph')
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
/// Schema for paragraph node.
|
|
12
|
+
export const paragraphSchema = $nodeSchema('paragraph', ctx => ({
|
|
13
|
+
content: 'inline*',
|
|
14
|
+
group: 'block',
|
|
15
|
+
parseDOM: [{ tag: 'p' }],
|
|
16
|
+
toDOM: node => ['p', ctx.get(paragraphAttr.key)(node), 0],
|
|
17
|
+
parseMarkdown: {
|
|
18
|
+
match: node => node.type === 'paragraph',
|
|
19
|
+
runner: (state, node, type) => {
|
|
20
|
+
state.openNode(type)
|
|
21
|
+
if (node.children)
|
|
22
|
+
state.next(node.children)
|
|
11
23
|
|
|
12
|
-
|
|
24
|
+
else
|
|
25
|
+
state.addText((node.value || '') as string)
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
state.closeNode()
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
toMarkdown: {
|
|
31
|
+
match: node => node.type.name === 'paragraph',
|
|
32
|
+
runner: (state, node) => {
|
|
33
|
+
state.openNode('paragraph')
|
|
34
|
+
const lastIsHardbreak = node.childCount >= 1 && node.lastChild?.type.name === 'hardbreak'
|
|
35
|
+
if (lastIsHardbreak) {
|
|
36
|
+
const contentArr: Node[] = []
|
|
37
|
+
node.content.forEach((n, _, i) => {
|
|
38
|
+
if (i === node.childCount - 1)
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
contentArr.push(n)
|
|
42
|
+
})
|
|
43
|
+
state.next(Fragment.fromArray(contentArr))
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
state.next(node.content)
|
|
47
|
+
}
|
|
48
|
+
state.closeNode()
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}))
|
|
31
52
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
toMarkdown: {
|
|
36
|
-
match: node => node.type.name === 'paragraph',
|
|
37
|
-
runner: (state, node) => {
|
|
38
|
-
state.openNode('paragraph')
|
|
39
|
-
const lastIsHardbreak = node.childCount >= 1 && node.lastChild?.type.name === 'hardbreak'
|
|
40
|
-
if (lastIsHardbreak) {
|
|
41
|
-
const contentArr: Node[] = []
|
|
42
|
-
node.content.forEach((n, _, i) => {
|
|
43
|
-
if (i === node.childCount - 1)
|
|
44
|
-
return
|
|
53
|
+
/// This command can turn the selected block into paragraph.
|
|
54
|
+
export const turnIntoTextCommand = $command('TurnIntoText', () => () => setBlockType(paragraphSchema.type()))
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
commands: nodeType => [createCmd(TurnIntoText, () => setBlockType(nodeType))],
|
|
58
|
-
shortcuts: {
|
|
59
|
-
[SupportedKeys.Text]: createShortcut(TurnIntoText, 'Mod-Alt-0'),
|
|
56
|
+
/// Keymap for paragraph node.
|
|
57
|
+
/// - `<Mod-Alt-0>`: Turn the selected block into paragraph.
|
|
58
|
+
export const paragraphKeymap = $useKeymap('paragraphKeymap', {
|
|
59
|
+
TurnIntoText: {
|
|
60
|
+
shortcuts: 'Mod-Alt-0',
|
|
61
|
+
command: (ctx) => {
|
|
62
|
+
const commands = ctx.get(commandsCtx)
|
|
63
|
+
return () => commands.call(turnIntoTextCommand.key)
|
|
60
64
|
},
|
|
61
|
-
}
|
|
65
|
+
},
|
|
62
66
|
})
|
package/src/node/text.ts
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
2
|
+
import { $node } from '@milkdown/utils'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
state.addText(node.value as string)
|
|
12
|
-
},
|
|
4
|
+
/// The bottom-level node.
|
|
5
|
+
export const textSchema = $node('text', () => ({
|
|
6
|
+
group: 'inline',
|
|
7
|
+
parseMarkdown: {
|
|
8
|
+
match: ({ type }) => type === 'text',
|
|
9
|
+
runner: (state, node) => {
|
|
10
|
+
state.addText(node.value as string)
|
|
13
11
|
},
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
},
|
|
13
|
+
toMarkdown: {
|
|
14
|
+
match: node => node.type.name === 'text',
|
|
15
|
+
runner: (state, node) => {
|
|
16
|
+
state.addNode('text', undefined, node.text as string)
|
|
19
17
|
},
|
|
20
|
-
}
|
|
18
|
+
},
|
|
21
19
|
}))
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
|
+
import { AddMarkStep, ReplaceStep } from '@milkdown/prose/transform'
|
|
4
|
+
import { $prose } from '@milkdown/utils'
|
|
5
|
+
import { hardbreakSchema } from '../node/hardbreak'
|
|
6
|
+
|
|
7
|
+
/// This plugin is used to clear the marks around the hardbreak node.
|
|
8
|
+
export const hardbreakClearMarkPlugin = $prose(() => {
|
|
9
|
+
return new Plugin({
|
|
10
|
+
key: new PluginKey('MILKDOWN_HARDBREAK_MARKS'),
|
|
11
|
+
appendTransaction: (trs, _oldState, newState) => {
|
|
12
|
+
if (!trs.length)
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
const [tr] = trs
|
|
16
|
+
if (!tr)
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
const [step] = tr.steps
|
|
20
|
+
|
|
21
|
+
const isInsertHr = tr.getMeta('hardbreak')
|
|
22
|
+
if (isInsertHr) {
|
|
23
|
+
if (!(step instanceof ReplaceStep))
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
const { from } = step as unknown as { from: number }
|
|
27
|
+
return newState.tr.setNodeMarkup(from, hardbreakSchema.type(), undefined, [])
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isAddMarkStep = step instanceof AddMarkStep
|
|
31
|
+
if (isAddMarkStep) {
|
|
32
|
+
let _tr = newState.tr
|
|
33
|
+
const { from, to } = step as unknown as { from: number; to: number }
|
|
34
|
+
newState.doc.nodesBetween(from, to, (node, pos) => {
|
|
35
|
+
if (node.type === hardbreakSchema.type())
|
|
36
|
+
_tr = _tr.setNodeMarkup(pos, hardbreakSchema.type(), undefined, [])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return _tr
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return undefined
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
|
+
import { $ctx, $prose } from '@milkdown/utils'
|
|
4
|
+
|
|
5
|
+
/// This slice contains the nodes that within which the hardbreak will be ignored.
|
|
6
|
+
export const hardbreakFilterNodes = $ctx(['table', 'code_block'], 'hardbreakFilterNodes')
|
|
7
|
+
|
|
8
|
+
/// This plugin is used to filter the hardbreak node.
|
|
9
|
+
/// If the hardbreak is going to be inserted within a node that is in the `hardbreakFilterNodes`, ignore it.
|
|
10
|
+
export const hardbreakFilterPlugin = $prose((ctx) => {
|
|
11
|
+
const notIn = ctx.get(hardbreakFilterNodes.key)
|
|
12
|
+
return new Plugin({
|
|
13
|
+
key: new PluginKey('MILKDOWN_HARDBREAK_FILTER'),
|
|
14
|
+
filterTransaction: (tr, state) => {
|
|
15
|
+
const isInsertHr = tr.getMeta('hardbreak')
|
|
16
|
+
const [step] = tr.steps
|
|
17
|
+
if (isInsertHr && step) {
|
|
18
|
+
const { from } = step as unknown as { from: number }
|
|
19
|
+
const $from = state.doc.resolve(from)
|
|
20
|
+
let curDepth = $from.depth
|
|
21
|
+
let canApply = true
|
|
22
|
+
while (curDepth > 0) {
|
|
23
|
+
if (notIn.includes($from.node(curDepth).type.name))
|
|
24
|
+
canApply = false
|
|
25
|
+
|
|
26
|
+
curDepth--
|
|
27
|
+
}
|
|
28
|
+
return canApply
|
|
29
|
+
}
|
|
30
|
+
return true
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
})
|
package/src/plugin/index.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { createPlugin } from '@milkdown/utils'
|
|
3
|
-
import links from 'remark-inline-links'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
import { filterHTMLPlugin } from './filter-html'
|
|
7
|
-
import { getInlineNodesCursorPlugin } from './inline-nodes-cursor'
|
|
8
|
-
import { getInlineSyncPlugin, inlineSyncConfigCtx } from './inline-sync'
|
|
3
|
+
export * from './inline-sync-plugin'
|
|
9
4
|
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
export * from './remark-add-order-in-list-plugin'
|
|
6
|
+
export * from './remark-line-break'
|
|
7
|
+
export * from './remark-inline-link-plugin'
|
|
8
|
+
|
|
9
|
+
export * from './inline-nodes-cursor-plugin'
|
|
10
|
+
|
|
11
|
+
export * from './hardbreak-clear-mark-plugin'
|
|
12
|
+
export * from './hardbreak-filter-plugin'
|
|
13
|
+
|
|
14
|
+
export * from './sync-heading-id-plugin'
|
|
15
|
+
export * from './sync-list-order-plugin'
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
2
|
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
3
|
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
4
|
+
import { $prose } from '@milkdown/utils'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* This plugin is to solve the chrome 98 bug:
|
|
9
|
-
* https://discuss.prosemirror.net/t/cursor-jumps-at-the-end-of-line-when-it-betweens-two-inline-nodes/4641
|
|
10
|
-
*/
|
|
11
|
-
export const getInlineNodesCursorPlugin = (): Plugin => {
|
|
6
|
+
/// This plugin is to solve the [chrome 98 bug](https://discuss.prosemirror.net/t/cursor-jumps-at-the-end-of-line-when-it-betweens-two-inline-nodes/4641).
|
|
7
|
+
export const inlineNodesCursorPlugin = $prose(() => {
|
|
12
8
|
let lock = false
|
|
9
|
+
const inlineNodesCursorPluginKey = new PluginKey('MILKDOWN_INLINE_NODES_CURSOR')
|
|
13
10
|
const inlineNodesCursorPlugin: Plugin = new Plugin({
|
|
14
11
|
key: inlineNodesCursorPluginKey,
|
|
15
12
|
state: {
|
|
@@ -90,4 +87,4 @@ export const getInlineNodesCursorPlugin = (): Plugin => {
|
|
|
90
87
|
})
|
|
91
88
|
|
|
92
89
|
return inlineNodesCursorPlugin
|
|
93
|
-
}
|
|
90
|
+
})
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { Ctx } from '@milkdown/
|
|
3
|
-
import { createSlice } from '@milkdown/core'
|
|
2
|
+
import type { Ctx } from '@milkdown/ctx'
|
|
4
3
|
import type { Node, NodeType } from '@milkdown/prose/model'
|
|
5
4
|
import type { Transaction } from '@milkdown/prose/state'
|
|
5
|
+
import { $ctx } from '@milkdown/utils'
|
|
6
6
|
|
|
7
7
|
import { swap } from './utils'
|
|
8
8
|
|
|
9
|
+
/// @internal
|
|
9
10
|
export type ShouldSyncNode = (context: {
|
|
10
11
|
prevNode: Node
|
|
11
12
|
nextNode: Node
|
|
@@ -14,12 +15,14 @@ export type ShouldSyncNode = (context: {
|
|
|
14
15
|
text: string
|
|
15
16
|
}) => boolean
|
|
16
17
|
|
|
18
|
+
/// @internal
|
|
17
19
|
export interface SyncNodePlaceholder {
|
|
18
20
|
hole: string
|
|
19
21
|
punctuation: string
|
|
20
22
|
char: string
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
/// @internal
|
|
23
26
|
export interface InlineSyncConfig {
|
|
24
27
|
placeholderConfig: SyncNodePlaceholder
|
|
25
28
|
shouldSyncNode: ShouldSyncNode
|
|
@@ -27,6 +30,7 @@ export interface InlineSyncConfig {
|
|
|
27
30
|
movePlaceholder: (placeholderToMove: string, text: string) => string
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
/// @internal
|
|
30
34
|
export const defaultConfig: InlineSyncConfig = {
|
|
31
35
|
placeholderConfig: {
|
|
32
36
|
hole: '∅',
|
|
@@ -54,4 +58,15 @@ export const defaultConfig: InlineSyncConfig = {
|
|
|
54
58
|
},
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
/// A slice that contains the inline sync config.
|
|
62
|
+
/// You can set value to this slice to change the config.
|
|
63
|
+
///
|
|
64
|
+
/// ```typescript
|
|
65
|
+
/// ctx.update(inlineSyncConfigCtx, (prevCfg) => ({
|
|
66
|
+
/// ...prevCfg,
|
|
67
|
+
/// // your config
|
|
68
|
+
/// }));
|
|
69
|
+
/// ```
|
|
70
|
+
///
|
|
71
|
+
/// You can find the default config [here](https://github.com/Saul-Mirone/milkdown/blob/main/packages/preset-commonmark/src/plugin/inline-sync-plugin/config.ts).
|
|
72
|
+
export const inlineSyncConfig = $ctx<InlineSyncConfig, 'inlineSyncConfig'>(defaultConfig, 'inlineSyncConfig')
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { Ctx } from '@milkdown/
|
|
2
|
+
import type { Ctx } from '@milkdown/ctx'
|
|
3
3
|
import { parserCtx, serializerCtx } from '@milkdown/core'
|
|
4
4
|
import type { Node } from '@milkdown/prose/model'
|
|
5
5
|
import type { EditorState } from '@milkdown/prose/state'
|
|
6
6
|
import { pipe } from '@milkdown/utils'
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { inlineSyncConfig } from './config'
|
|
9
9
|
import { calculatePlaceholder, keepLink, replacePunctuation } from './utils'
|
|
10
10
|
|
|
11
|
-
export * from './config'
|
|
12
|
-
|
|
13
11
|
export interface InlineSyncContext {
|
|
14
12
|
text: string
|
|
15
13
|
prevNode: Node
|
|
@@ -35,7 +33,7 @@ const getMarkdown = (ctx: Ctx, state: EditorState, node: Node, globalNode: Node[
|
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
const addPlaceholder = (ctx: Ctx, markdown: string) => {
|
|
38
|
-
const config = ctx.get(
|
|
36
|
+
const config = ctx.get(inlineSyncConfig.key)
|
|
39
37
|
const holePlaceholder = config.placeholderConfig.hole
|
|
40
38
|
|
|
41
39
|
const [firstLine = '', ...rest] = markdown.split('\n\n')
|
|
@@ -65,7 +63,7 @@ const getNewNode = (ctx: Ctx, text: string) => {
|
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
const collectGlobalNodes = (ctx: Ctx, state: EditorState) => {
|
|
68
|
-
const { globalNodes } = ctx.get(
|
|
66
|
+
const { globalNodes } = ctx.get(inlineSyncConfig.key)
|
|
69
67
|
const nodes: Node[] = []
|
|
70
68
|
|
|
71
69
|
state.doc.descendants((node) => {
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { Ctx } from '@milkdown/
|
|
2
|
+
import type { Ctx } from '@milkdown/ctx'
|
|
3
3
|
import { editorViewCtx } from '@milkdown/core'
|
|
4
4
|
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
5
|
+
import { $prose } from '@milkdown/utils'
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { inlineSyncConfig } from './config'
|
|
7
8
|
import { getContextByState } from './context'
|
|
8
9
|
import { runReplacer } from './replacer'
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/// This plugin is used to sync the inline mark.
|
|
12
|
+
/// It will create and remove marks automatically according to the user input.
|
|
13
|
+
///
|
|
14
|
+
/// When users type something, the plugin will transform the line (for better performance) to real markdown AST by serializer
|
|
15
|
+
/// and render the AST to dom by parser, thus the input texts can be displayed correctly.
|
|
16
|
+
export const inlineSyncPlugin = $prose((ctx: Ctx) => {
|
|
14
17
|
let requestId: number | null = null
|
|
15
|
-
const
|
|
18
|
+
const inlineSyncPluginKey = new PluginKey('MILKDOWN_INLINE_SYNC')
|
|
19
|
+
|
|
20
|
+
return new Plugin<null>({
|
|
16
21
|
key: inlineSyncPluginKey,
|
|
17
22
|
state: {
|
|
18
23
|
init: () => {
|
|
@@ -41,7 +46,7 @@ export const getInlineSyncPlugin = (ctx: Ctx) => {
|
|
|
41
46
|
|
|
42
47
|
const { prevNode, nextNode, text } = context
|
|
43
48
|
|
|
44
|
-
const { shouldSyncNode } = ctx.get(
|
|
49
|
+
const { shouldSyncNode } = ctx.get(inlineSyncConfig.key)
|
|
45
50
|
|
|
46
51
|
if (!shouldSyncNode({ prevNode, nextNode, ctx, tr, text }))
|
|
47
52
|
return null
|
|
@@ -58,6 +63,4 @@ export const getInlineSyncPlugin = (ctx: Ctx) => {
|
|
|
58
63
|
},
|
|
59
64
|
},
|
|
60
65
|
})
|
|
61
|
-
|
|
62
|
-
return inlineSyncPlugin
|
|
63
|
-
}
|
|
66
|
+
})
|
|
File without changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import type { Ctx } from '@milkdown/
|
|
2
|
+
import type { Ctx } from '@milkdown/ctx'
|
|
3
3
|
import type { Attrs } from '@milkdown/prose/model'
|
|
4
4
|
import type { EditorState, PluginKey, Transaction } from '@milkdown/prose/state'
|
|
5
5
|
import { TextSelection } from '@milkdown/prose/state'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { inlineSyncConfig } from './config'
|
|
8
8
|
import { getContextByState } from './context'
|
|
9
9
|
import { calcOffset } from './utils'
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ export const runReplacer = (
|
|
|
15
15
|
dispatch: (tr: Transaction) => void,
|
|
16
16
|
attrs: Attrs,
|
|
17
17
|
) => {
|
|
18
|
-
const { placeholderConfig } = ctx.get(
|
|
18
|
+
const { placeholderConfig } = ctx.get(inlineSyncConfig.key)
|
|
19
19
|
const holePlaceholder = placeholderConfig.hole
|
|
20
20
|
// insert a placeholder to restore the selection
|
|
21
21
|
let tr = state.tr.setMeta(key, true).insertText(holePlaceholder, state.selection.from)
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { $remark } from '@milkdown/utils'
|
|
3
|
+
import type { Node, Parent } from 'unist'
|
|
4
|
+
import { visit } from 'unist-util-visit'
|
|
5
|
+
|
|
6
|
+
/// This plugin is used to add order in list for remark AST.
|
|
7
|
+
export const remarkAddOrderInListPlugin = $remark(() => () => (tree: Node) => {
|
|
8
|
+
visit(tree, 'list', (node: Parent & { ordered?: boolean; start?: number }) => {
|
|
9
|
+
if (node.ordered) {
|
|
10
|
+
const start = node.start ?? 1
|
|
11
|
+
node.children.forEach((child, index) => {
|
|
12
|
+
(child as Node & { label: number }).label = index + start
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
+
import { $remark } from '@milkdown/utils'
|
|
3
|
+
import remarkInlineLinks from 'remark-inline-links'
|
|
4
|
+
|
|
5
|
+
/// This plugin wraps [remark-inline-links](https://github.com/remarkjs/remark-inline-links).
|
|
6
|
+
export const remarkInlineLinkPlugin = $remark(() => remarkInlineLinks)
|