@milkdown/preset-commonmark 7.4.0 → 7.5.8
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/__internal__/serialize-text.d.ts.map +1 -1
- package/lib/__internal__/with-meta.d.ts.map +1 -1
- package/lib/composed/commands.d.ts.map +1 -1
- package/lib/composed/inputrules.d.ts.map +1 -1
- package/lib/composed/keymap.d.ts.map +1 -1
- package/lib/composed/schema.d.ts.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +544 -400
- package/lib/index.es.js.map +1 -1
- package/lib/mark/emphasis.d.ts.map +1 -1
- package/lib/mark/inline-code.d.ts.map +1 -1
- package/lib/mark/link.d.ts.map +1 -1
- package/lib/mark/strong.d.ts.map +1 -1
- package/lib/node/blockquote.d.ts.map +1 -1
- package/lib/node/bullet-list.d.ts.map +1 -1
- package/lib/node/code-block.d.ts.map +1 -1
- package/lib/node/hardbreak.d.ts.map +1 -1
- package/lib/node/heading.d.ts.map +1 -1
- package/lib/node/hr.d.ts.map +1 -1
- package/lib/node/html.d.ts.map +1 -1
- package/lib/node/image.d.ts.map +1 -1
- package/lib/node/list-item.d.ts.map +1 -1
- package/lib/node/ordered-list.d.ts.map +1 -1
- package/lib/node/paragraph.d.ts.map +1 -1
- package/lib/plugin/hardbreak-clear-mark-plugin.d.ts.map +1 -1
- package/lib/plugin/hardbreak-filter-plugin.d.ts.map +1 -1
- package/lib/plugin/inline-nodes-cursor-plugin.d.ts.map +1 -1
- package/lib/plugin/remark-add-order-in-list-plugin.d.ts.map +1 -1
- package/lib/plugin/remark-html-transformer.d.ts.map +1 -1
- package/lib/plugin/remark-inline-link-plugin.d.ts.map +1 -1
- package/lib/plugin/remark-line-break.d.ts.map +1 -1
- package/lib/plugin/remark-marker-plugin.d.ts.map +1 -1
- package/lib/plugin/sync-heading-id-plugin.d.ts.map +1 -1
- package/lib/plugin/sync-list-order-plugin.d.ts.map +1 -1
- package/package.json +10 -16
- package/src/__internal__/serialize-text.ts +3 -4
- package/src/__internal__/with-meta.ts +4 -1
- package/src/composed/commands.ts +7 -1
- package/src/composed/inputrules.ts +14 -2
- package/src/composed/keymap.ts +10 -1
- package/src/composed/schema.ts +10 -1
- package/src/index.ts +16 -2
- package/src/mark/emphasis.ts +19 -9
- package/src/mark/inline-code.ts +40 -30
- package/src/mark/link.ts +55 -45
- package/src/mark/strong.ts +13 -7
- package/src/node/blockquote.ts +34 -20
- package/src/node/bullet-list.ts +20 -7
- package/src/node/code-block.ts +43 -18
- package/src/node/doc.ts +1 -1
- package/src/node/hardbreak.ts +50 -28
- package/src/node/heading.ts +44 -27
- package/src/node/hr.ts +27 -28
- package/src/node/html.ts +10 -8
- package/src/node/image.ts +57 -43
- package/src/node/list-item.ts +35 -18
- package/src/node/ordered-list.ts +31 -15
- package/src/node/paragraph.ts +10 -10
- package/src/node/text.ts +1 -1
- package/src/plugin/hardbreak-clear-mark-plugin.ts +16 -9
- package/src/plugin/hardbreak-filter-plugin.ts +5 -3
- package/src/plugin/inline-nodes-cursor-plugin.ts +13 -6
- package/src/plugin/remark-add-order-in-list-plugin.ts +13 -10
- package/src/plugin/remark-html-transformer.ts +24 -17
- package/src/plugin/remark-inline-link-plugin.ts +4 -1
- package/src/plugin/remark-line-break.ts +39 -26
- package/src/plugin/remark-marker-plugin.ts +14 -7
- package/src/plugin/sync-heading-id-plugin.ts +13 -8
- package/src/plugin/sync-list-order-plugin.ts +12 -11
package/src/node/heading.ts
CHANGED
|
@@ -3,7 +3,14 @@ import { expectDomTypeError } from '@milkdown/exception'
|
|
|
3
3
|
import { setBlockType } from '@milkdown/prose/commands'
|
|
4
4
|
import { textblockTypeInputRule } from '@milkdown/prose/inputrules'
|
|
5
5
|
import type { Node } from '@milkdown/prose/model'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
$command,
|
|
8
|
+
$ctx,
|
|
9
|
+
$inputRule,
|
|
10
|
+
$nodeAttr,
|
|
11
|
+
$nodeSchema,
|
|
12
|
+
$useKeymap,
|
|
13
|
+
} from '@milkdown/utils'
|
|
7
14
|
import slugify from '@sindresorhus/slugify'
|
|
8
15
|
import { serializeText, withMeta } from '../__internal__'
|
|
9
16
|
import { paragraphSchema } from './paragraph'
|
|
@@ -18,7 +25,10 @@ function defaultHeadingIdGenerator(node: Node) {
|
|
|
18
25
|
|
|
19
26
|
/// This is a slice contains a function to generate heading id.
|
|
20
27
|
/// You can configure it to generate id in your own way.
|
|
21
|
-
export const headingIdGenerator = $ctx(
|
|
28
|
+
export const headingIdGenerator = $ctx(
|
|
29
|
+
defaultHeadingIdGenerator,
|
|
30
|
+
'headingIdGenerator'
|
|
31
|
+
)
|
|
22
32
|
|
|
23
33
|
withMeta(headingIdGenerator, {
|
|
24
34
|
displayName: 'Ctx<HeadingIdGenerator>',
|
|
@@ -48,11 +58,10 @@ export const headingSchema = $nodeSchema('heading', (ctx) => {
|
|
|
48
58
|
default: 1,
|
|
49
59
|
},
|
|
50
60
|
},
|
|
51
|
-
parseDOM: headingIndex.map(x => ({
|
|
61
|
+
parseDOM: headingIndex.map((x) => ({
|
|
52
62
|
tag: `h${x}`,
|
|
53
63
|
getAttrs: (node) => {
|
|
54
|
-
if (!(node instanceof HTMLElement))
|
|
55
|
-
throw expectDomTypeError(node)
|
|
64
|
+
if (!(node instanceof HTMLElement)) throw expectDomTypeError(node)
|
|
56
65
|
|
|
57
66
|
return { level: x, id: node.id }
|
|
58
67
|
},
|
|
@@ -77,7 +86,7 @@ export const headingSchema = $nodeSchema('heading', (ctx) => {
|
|
|
77
86
|
},
|
|
78
87
|
},
|
|
79
88
|
toMarkdown: {
|
|
80
|
-
match: node => node.type.name === 'heading',
|
|
89
|
+
match: (node) => node.type.name === 'heading',
|
|
81
90
|
runner: (state, node) => {
|
|
82
91
|
state.openNode('heading', undefined, { depth: node.attrs.level })
|
|
83
92
|
serializeText(state, node)
|
|
@@ -100,21 +109,24 @@ withMeta(headingSchema.ctx, {
|
|
|
100
109
|
/// This input rule can turn the selected block into heading.
|
|
101
110
|
/// You can input numbers of `#` and a `space` to create heading.
|
|
102
111
|
export const wrapInHeadingInputRule = $inputRule((ctx) => {
|
|
103
|
-
return textblockTypeInputRule(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
return textblockTypeInputRule(
|
|
113
|
+
/^(?<hashes>#+)\s$/,
|
|
114
|
+
headingSchema.type(ctx),
|
|
115
|
+
(match) => {
|
|
116
|
+
const x = match.groups?.hashes?.length || 0
|
|
117
|
+
|
|
118
|
+
const view = ctx.get(editorViewCtx)
|
|
119
|
+
const { $from } = view.state.selection
|
|
120
|
+
const node = $from.node()
|
|
121
|
+
if (node.type.name === 'heading') {
|
|
122
|
+
let level = Number(node.attrs.level) + Number(x)
|
|
123
|
+
if (level > 6) level = 6
|
|
124
|
+
|
|
125
|
+
return { level }
|
|
126
|
+
}
|
|
127
|
+
return { level: x }
|
|
115
128
|
}
|
|
116
|
-
|
|
117
|
-
})
|
|
129
|
+
)
|
|
118
130
|
})
|
|
119
131
|
|
|
120
132
|
withMeta(wrapInHeadingInputRule, {
|
|
@@ -129,8 +141,7 @@ export const wrapInHeadingCommand = $command('WrapInHeading', (ctx) => {
|
|
|
129
141
|
return (level?: number) => {
|
|
130
142
|
level ??= 1
|
|
131
143
|
|
|
132
|
-
if (level < 1)
|
|
133
|
-
return setBlockType(paragraphSchema.type(ctx))
|
|
144
|
+
if (level < 1) return setBlockType(paragraphSchema.type(ctx))
|
|
134
145
|
|
|
135
146
|
return setBlockType(headingSchema.type(ctx), { level })
|
|
136
147
|
}
|
|
@@ -144,11 +155,16 @@ withMeta(wrapInHeadingCommand, {
|
|
|
144
155
|
/// This command can downgrade the selected heading.
|
|
145
156
|
/// For example, if you have a `h2` element, and you call this command, you will get a `h1` element.
|
|
146
157
|
/// If the element is already a `h1` element, it will turn it into a `p` element.
|
|
147
|
-
export const downgradeHeadingCommand = $command(
|
|
148
|
-
|
|
158
|
+
export const downgradeHeadingCommand = $command(
|
|
159
|
+
'DowngradeHeading',
|
|
160
|
+
(ctx) => () => (state, dispatch, view) => {
|
|
149
161
|
const { $from } = state.selection
|
|
150
162
|
const node = $from.node()
|
|
151
|
-
if (
|
|
163
|
+
if (
|
|
164
|
+
node.type !== headingSchema.type(ctx) ||
|
|
165
|
+
!state.selection.empty ||
|
|
166
|
+
$from.parentOffset !== 0
|
|
167
|
+
)
|
|
152
168
|
return false
|
|
153
169
|
|
|
154
170
|
const level = node.attrs.level - 1
|
|
@@ -159,10 +175,11 @@ export const downgradeHeadingCommand = $command('DowngradeHeading', ctx => () =>
|
|
|
159
175
|
state.tr.setNodeMarkup(state.selection.$from.before(), undefined, {
|
|
160
176
|
...node.attrs,
|
|
161
177
|
level,
|
|
162
|
-
})
|
|
178
|
+
})
|
|
163
179
|
)
|
|
164
180
|
return true
|
|
165
|
-
}
|
|
181
|
+
}
|
|
182
|
+
)
|
|
166
183
|
|
|
167
184
|
withMeta(downgradeHeadingCommand, {
|
|
168
185
|
displayName: 'Command<downgradeHeadingCommand>',
|
package/src/node/hr.ts
CHANGED
|
@@ -13,10 +13,10 @@ withMeta(hrAttr, {
|
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
/// Hr node schema.
|
|
16
|
-
export const hrSchema = $nodeSchema('hr', ctx => ({
|
|
16
|
+
export const hrSchema = $nodeSchema('hr', (ctx) => ({
|
|
17
17
|
group: 'block',
|
|
18
18
|
parseDOM: [{ tag: 'hr' }],
|
|
19
|
-
toDOM: node => ['hr', ctx.get(hrAttr.key)(node)],
|
|
19
|
+
toDOM: (node) => ['hr', ctx.get(hrAttr.key)(node)],
|
|
20
20
|
parseMarkdown: {
|
|
21
21
|
match: ({ type }) => type === 'thematicBreak',
|
|
22
22
|
runner: (state, _, type) => {
|
|
@@ -24,7 +24,7 @@ export const hrSchema = $nodeSchema('hr', ctx => ({
|
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
toMarkdown: {
|
|
27
|
-
match: node => node.type.name === 'hr',
|
|
27
|
+
match: (node) => node.type.name === 'hr',
|
|
28
28
|
runner: (state) => {
|
|
29
29
|
state.addNode('thematicBreak')
|
|
30
30
|
},
|
|
@@ -43,17 +43,16 @@ withMeta(hrSchema.ctx, {
|
|
|
43
43
|
|
|
44
44
|
/// Input rule to insert a hr.
|
|
45
45
|
/// For example, `---` will be converted to a hr.
|
|
46
|
-
export const insertHrInputRule = $inputRule(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
export const insertHrInputRule = $inputRule(
|
|
47
|
+
(ctx) =>
|
|
48
|
+
new InputRule(/^(?:---|___\s|\*\*\*\s)$/, (state, match, start, end) => {
|
|
49
|
+
const { tr } = state
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
tr.replaceWith(start - 1, end, hrSchema.type(ctx).create())
|
|
51
|
+
if (match[0]) tr.replaceWith(start - 1, end, hrSchema.type(ctx).create())
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
53
|
+
return tr
|
|
54
|
+
})
|
|
55
|
+
)
|
|
57
56
|
|
|
58
57
|
withMeta(insertHrInputRule, {
|
|
59
58
|
displayName: 'InputRule<insertHrInputRule>',
|
|
@@ -61,25 +60,25 @@ withMeta(insertHrInputRule, {
|
|
|
61
60
|
})
|
|
62
61
|
|
|
63
62
|
/// Command to insert a hr.
|
|
64
|
-
export const insertHrCommand = $command(
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
export const insertHrCommand = $command(
|
|
64
|
+
'InsertHr',
|
|
65
|
+
(ctx) => () => (state, dispatch) => {
|
|
66
|
+
if (!dispatch) return true
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return true
|
|
68
|
+
const paragraph = paragraphSchema.node.type(ctx).create()
|
|
69
|
+
const { tr, selection } = state
|
|
70
|
+
const { from } = selection
|
|
71
|
+
const node = hrSchema.type(ctx).create()
|
|
72
|
+
if (!node) return true
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return true
|
|
74
|
+
const _tr = tr.replaceSelectionWith(node).insert(from, paragraph)
|
|
75
|
+
const sel = Selection.findFrom(_tr.doc.resolve(from), 1, true)
|
|
76
|
+
if (!sel) return true
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
78
|
+
dispatch(_tr.setSelection(sel).scrollIntoView())
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
)
|
|
83
82
|
|
|
84
83
|
withMeta(insertHrCommand, {
|
|
85
84
|
displayName: 'Command<insertHrCommand>',
|
package/src/node/html.ts
CHANGED
|
@@ -28,14 +28,16 @@ export const htmlSchema = $nodeSchema('html', (ctx) => {
|
|
|
28
28
|
span.textContent = node.attrs.value
|
|
29
29
|
return ['span', attr, node.attrs.value]
|
|
30
30
|
},
|
|
31
|
-
parseDOM: [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
parseDOM: [
|
|
32
|
+
{
|
|
33
|
+
tag: 'span[data-type="html"]',
|
|
34
|
+
getAttrs: (dom) => {
|
|
35
|
+
return {
|
|
36
|
+
value: dom.dataset.value ?? '',
|
|
37
|
+
}
|
|
38
|
+
},
|
|
37
39
|
},
|
|
38
|
-
|
|
40
|
+
],
|
|
39
41
|
parseMarkdown: {
|
|
40
42
|
match: ({ type }) => Boolean(type === 'html'),
|
|
41
43
|
runner: (state, node, type) => {
|
|
@@ -43,7 +45,7 @@ export const htmlSchema = $nodeSchema('html', (ctx) => {
|
|
|
43
45
|
},
|
|
44
46
|
},
|
|
45
47
|
toMarkdown: {
|
|
46
|
-
match: node => node.type.name === 'html',
|
|
48
|
+
match: (node) => node.type.name === 'html',
|
|
47
49
|
runner: (state, node) => {
|
|
48
50
|
state.addNode('html', undefined, node.attrs.value)
|
|
49
51
|
},
|
package/src/node/image.ts
CHANGED
|
@@ -32,8 +32,7 @@ export const imageSchema = $nodeSchema('image', (ctx) => {
|
|
|
32
32
|
{
|
|
33
33
|
tag: 'img[src]',
|
|
34
34
|
getAttrs: (dom) => {
|
|
35
|
-
if (!(dom instanceof HTMLElement))
|
|
36
|
-
throw expectDomTypeError(dom)
|
|
35
|
+
if (!(dom instanceof HTMLElement)) throw expectDomTypeError(dom)
|
|
37
36
|
|
|
38
37
|
return {
|
|
39
38
|
src: dom.getAttribute('src') || '',
|
|
@@ -60,7 +59,7 @@ export const imageSchema = $nodeSchema('image', (ctx) => {
|
|
|
60
59
|
},
|
|
61
60
|
},
|
|
62
61
|
toMarkdown: {
|
|
63
|
-
match: node => node.type.name === 'image',
|
|
62
|
+
match: (node) => node.type.name === 'image',
|
|
64
63
|
runner: (state, node) => {
|
|
65
64
|
state.addNode('image', undefined, undefined, {
|
|
66
65
|
title: node.attrs.title,
|
|
@@ -91,20 +90,22 @@ export interface UpdateImageCommandPayload {
|
|
|
91
90
|
|
|
92
91
|
/// This command will insert a image node.
|
|
93
92
|
/// You can pass a payload to set `src`, `alt` and `title` for the image node.
|
|
94
|
-
export const insertImageCommand = $command(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
export const insertImageCommand = $command(
|
|
94
|
+
'InsertImage',
|
|
95
|
+
(ctx) =>
|
|
96
|
+
(payload: UpdateImageCommandPayload = {}) =>
|
|
97
|
+
(state, dispatch) => {
|
|
98
|
+
if (!dispatch) return true
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
const { src = '', alt = '', title = '' } = payload
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return true
|
|
102
|
+
const node = imageSchema.type(ctx).create({ src, alt, title })
|
|
103
|
+
if (!node) return true
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
dispatch(state.tr.replaceSelectionWith(node).scrollIntoView())
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
)
|
|
108
109
|
|
|
109
110
|
withMeta(insertImageCommand, {
|
|
110
111
|
displayName: 'Command<insertImageCommand>',
|
|
@@ -113,25 +114,31 @@ withMeta(insertImageCommand, {
|
|
|
113
114
|
|
|
114
115
|
/// This command will update the selected image node.
|
|
115
116
|
/// You can pass a payload to update `src`, `alt` and `title` for the image node.
|
|
116
|
-
export const updateImageCommand = $command(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
export const updateImageCommand = $command(
|
|
118
|
+
'UpdateImage',
|
|
119
|
+
(ctx) =>
|
|
120
|
+
(payload: UpdateImageCommandPayload = {}) =>
|
|
121
|
+
(state, dispatch) => {
|
|
122
|
+
const nodeWithPos = findSelectedNodeOfType(
|
|
123
|
+
state.selection,
|
|
124
|
+
imageSchema.type(ctx)
|
|
125
|
+
)
|
|
126
|
+
if (!nodeWithPos) return false
|
|
127
|
+
|
|
128
|
+
const { node, pos } = nodeWithPos
|
|
129
|
+
|
|
130
|
+
const newAttrs = { ...node.attrs }
|
|
131
|
+
const { src, alt, title } = payload
|
|
132
|
+
if (src !== undefined) newAttrs.src = src
|
|
133
|
+
if (alt !== undefined) newAttrs.alt = alt
|
|
134
|
+
if (title !== undefined) newAttrs.title = title
|
|
135
|
+
|
|
136
|
+
dispatch?.(
|
|
137
|
+
state.tr.setNodeMarkup(pos, undefined, newAttrs).scrollIntoView()
|
|
138
|
+
)
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
)
|
|
135
142
|
|
|
136
143
|
withMeta(updateImageCommand, {
|
|
137
144
|
displayName: 'Command<updateImageCommand>',
|
|
@@ -141,16 +148,23 @@ withMeta(updateImageCommand, {
|
|
|
141
148
|
/// This input rule will insert a image node.
|
|
142
149
|
/// You can input `` to insert a image node.
|
|
143
150
|
/// The `title` is optional.
|
|
144
|
-
export const insertImageInputRule = $inputRule(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
export const insertImageInputRule = $inputRule(
|
|
152
|
+
(ctx) =>
|
|
153
|
+
new InputRule(
|
|
154
|
+
/!\[(?<alt>.*?)]\((?<filename>.*?)\s*(?="|\))"?(?<title>[^"]+)?"?\)/,
|
|
155
|
+
(state, match, start, end) => {
|
|
156
|
+
const [matched, alt, src = '', title] = match
|
|
157
|
+
if (matched)
|
|
158
|
+
return state.tr.replaceWith(
|
|
159
|
+
start,
|
|
160
|
+
end,
|
|
161
|
+
imageSchema.type(ctx).create({ src, alt, title })
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return null
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
)
|
|
154
168
|
|
|
155
169
|
withMeta(insertImageInputRule, {
|
|
156
170
|
displayName: 'InputRule<insertImageInputRule>',
|
package/src/node/list-item.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { commandsCtx } from '@milkdown/core'
|
|
2
2
|
import { expectDomTypeError } from '@milkdown/exception'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
liftListItem,
|
|
5
|
+
sinkListItem,
|
|
6
|
+
splitListItem,
|
|
7
|
+
} from '@milkdown/prose/schema-list'
|
|
4
8
|
import { $command, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
|
|
5
9
|
import { type Command, TextSelection } from '@milkdown/prose/state'
|
|
6
10
|
import type { Ctx } from '@milkdown/ctx'
|
|
@@ -15,7 +19,7 @@ withMeta(listItemAttr, {
|
|
|
15
19
|
})
|
|
16
20
|
|
|
17
21
|
/// Schema for list item node.
|
|
18
|
-
export const listItemSchema = $nodeSchema('list_item', ctx => ({
|
|
22
|
+
export const listItemSchema = $nodeSchema('list_item', (ctx) => ({
|
|
19
23
|
group: 'listItem',
|
|
20
24
|
content: '(paragraph|blockquote) block*',
|
|
21
25
|
attrs: {
|
|
@@ -34,8 +38,7 @@ export const listItemSchema = $nodeSchema('list_item', ctx => ({
|
|
|
34
38
|
{
|
|
35
39
|
tag: 'li',
|
|
36
40
|
getAttrs: (dom) => {
|
|
37
|
-
if (!(dom instanceof HTMLElement))
|
|
38
|
-
throw expectDomTypeError(dom)
|
|
41
|
+
if (!(dom instanceof HTMLElement)) throw expectDomTypeError(dom)
|
|
39
42
|
|
|
40
43
|
return {
|
|
41
44
|
label: dom.dataset.label,
|
|
@@ -45,7 +48,7 @@ export const listItemSchema = $nodeSchema('list_item', ctx => ({
|
|
|
45
48
|
},
|
|
46
49
|
},
|
|
47
50
|
],
|
|
48
|
-
toDOM: node => [
|
|
51
|
+
toDOM: (node) => [
|
|
49
52
|
'li',
|
|
50
53
|
{
|
|
51
54
|
...ctx.get(listItemAttr.key)(node),
|
|
@@ -67,9 +70,11 @@ export const listItemSchema = $nodeSchema('list_item', ctx => ({
|
|
|
67
70
|
},
|
|
68
71
|
},
|
|
69
72
|
toMarkdown: {
|
|
70
|
-
match: node => node.type.name === 'list_item',
|
|
73
|
+
match: (node) => node.type.name === 'list_item',
|
|
71
74
|
runner: (state, node) => {
|
|
72
|
-
state.openNode('listItem', undefined, {
|
|
75
|
+
state.openNode('listItem', undefined, {
|
|
76
|
+
spread: node.attrs.spread === 'true',
|
|
77
|
+
})
|
|
73
78
|
state.next(node.content)
|
|
74
79
|
state.closeNode()
|
|
75
80
|
},
|
|
@@ -98,7 +103,10 @@ withMeta(listItemSchema.ctx, {
|
|
|
98
103
|
/// * List item 1
|
|
99
104
|
/// * List item 2
|
|
100
105
|
/// ```
|
|
101
|
-
export const sinkListItemCommand = $command(
|
|
106
|
+
export const sinkListItemCommand = $command(
|
|
107
|
+
'SinkListItem',
|
|
108
|
+
(ctx) => () => sinkListItem(listItemSchema.type(ctx))
|
|
109
|
+
)
|
|
102
110
|
|
|
103
111
|
withMeta(sinkListItemCommand, {
|
|
104
112
|
displayName: 'Command<sinkListItemCommand>',
|
|
@@ -117,7 +125,10 @@ withMeta(sinkListItemCommand, {
|
|
|
117
125
|
/// * List item 1
|
|
118
126
|
/// * List item 2
|
|
119
127
|
/// ```
|
|
120
|
-
export const liftListItemCommand = $command(
|
|
128
|
+
export const liftListItemCommand = $command(
|
|
129
|
+
'LiftListItem',
|
|
130
|
+
(ctx) => () => liftListItem(listItemSchema.type(ctx))
|
|
131
|
+
)
|
|
121
132
|
|
|
122
133
|
withMeta(liftListItemCommand, {
|
|
123
134
|
displayName: 'Command<liftListItemCommand>',
|
|
@@ -137,7 +148,10 @@ withMeta(liftListItemCommand, {
|
|
|
137
148
|
/// * List item 2
|
|
138
149
|
/// * <- cursor here
|
|
139
150
|
/// ```
|
|
140
|
-
export const splitListItemCommand = $command(
|
|
151
|
+
export const splitListItemCommand = $command(
|
|
152
|
+
'SplitListItem',
|
|
153
|
+
(ctx) => () => splitListItem(listItemSchema.type(ctx))
|
|
154
|
+
)
|
|
141
155
|
|
|
142
156
|
withMeta(splitListItemCommand, {
|
|
143
157
|
displayName: 'Command<splitListItemCommand>',
|
|
@@ -147,24 +161,24 @@ withMeta(splitListItemCommand, {
|
|
|
147
161
|
function liftFirstListItem(ctx: Ctx): Command {
|
|
148
162
|
return (state, dispatch, view) => {
|
|
149
163
|
const { selection } = state
|
|
150
|
-
if (!(selection instanceof TextSelection))
|
|
151
|
-
return false
|
|
164
|
+
if (!(selection instanceof TextSelection)) return false
|
|
152
165
|
|
|
153
166
|
const { empty, $from } = selection
|
|
154
167
|
|
|
155
168
|
// selection should be empty and at the start of the node
|
|
156
|
-
if (!empty || $from.parentOffset !== 0)
|
|
157
|
-
return false
|
|
169
|
+
if (!empty || $from.parentOffset !== 0) return false
|
|
158
170
|
|
|
159
171
|
const parentItem = $from.node(-1)
|
|
160
172
|
// selection should be in list item and list item should be the first child of the list
|
|
161
|
-
if (
|
|
173
|
+
if (
|
|
174
|
+
parentItem.type !== listItemSchema.type(ctx) ||
|
|
175
|
+
parentItem.firstChild !== $from.node()
|
|
176
|
+
)
|
|
162
177
|
return false
|
|
163
178
|
|
|
164
179
|
const list = $from.node(-2)
|
|
165
180
|
// list should have only one list item
|
|
166
|
-
if (list.childCount > 1)
|
|
167
|
-
return false
|
|
181
|
+
if (list.childCount > 1) return false
|
|
168
182
|
|
|
169
183
|
return liftListItem(listItemSchema.type(ctx))(state, dispatch, view)
|
|
170
184
|
}
|
|
@@ -176,7 +190,10 @@ function liftFirstListItem(ctx: Ctx): Command {
|
|
|
176
190
|
/// - List item is the only child of the list.
|
|
177
191
|
///
|
|
178
192
|
/// Most of the time, you shouldn't use this command directly.
|
|
179
|
-
export const liftFirstListItemCommand = $command(
|
|
193
|
+
export const liftFirstListItemCommand = $command(
|
|
194
|
+
'LiftFirstListItem',
|
|
195
|
+
(ctx) => () => liftFirstListItem(ctx)
|
|
196
|
+
)
|
|
180
197
|
|
|
181
198
|
withMeta(liftFirstListItemCommand, {
|
|
182
199
|
displayName: 'Command<liftFirstListItemCommand>',
|
package/src/node/ordered-list.ts
CHANGED
|
@@ -2,7 +2,13 @@ import { commandsCtx } from '@milkdown/core'
|
|
|
2
2
|
import { expectDomTypeError } from '@milkdown/exception'
|
|
3
3
|
import { wrapIn } from '@milkdown/prose/commands'
|
|
4
4
|
import { wrappingInputRule } from '@milkdown/prose/inputrules'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
$command,
|
|
7
|
+
$inputRule,
|
|
8
|
+
$nodeAttr,
|
|
9
|
+
$nodeSchema,
|
|
10
|
+
$useKeymap,
|
|
11
|
+
} from '@milkdown/utils'
|
|
6
12
|
import { withMeta } from '../__internal__'
|
|
7
13
|
|
|
8
14
|
/// HTML attributes for ordered list node.
|
|
@@ -14,7 +20,7 @@ withMeta(orderedListAttr, {
|
|
|
14
20
|
})
|
|
15
21
|
|
|
16
22
|
/// Schema for ordered list node.
|
|
17
|
-
export const orderedListSchema = $nodeSchema('ordered_list', ctx => ({
|
|
23
|
+
export const orderedListSchema = $nodeSchema('ordered_list', (ctx) => ({
|
|
18
24
|
content: 'listItem+',
|
|
19
25
|
group: 'block',
|
|
20
26
|
attrs: {
|
|
@@ -29,17 +35,18 @@ export const orderedListSchema = $nodeSchema('ordered_list', ctx => ({
|
|
|
29
35
|
{
|
|
30
36
|
tag: 'ol',
|
|
31
37
|
getAttrs: (dom) => {
|
|
32
|
-
if (!(dom instanceof HTMLElement))
|
|
33
|
-
throw expectDomTypeError(dom)
|
|
38
|
+
if (!(dom instanceof HTMLElement)) throw expectDomTypeError(dom)
|
|
34
39
|
|
|
35
40
|
return {
|
|
36
41
|
spread: dom.dataset.spread,
|
|
37
|
-
order: dom.hasAttribute('start')
|
|
42
|
+
order: dom.hasAttribute('start')
|
|
43
|
+
? Number(dom.getAttribute('start'))
|
|
44
|
+
: 1,
|
|
38
45
|
}
|
|
39
46
|
},
|
|
40
47
|
},
|
|
41
48
|
],
|
|
42
|
-
toDOM: node => [
|
|
49
|
+
toDOM: (node) => [
|
|
43
50
|
'ol',
|
|
44
51
|
{
|
|
45
52
|
...ctx.get(orderedListAttr.key)(node),
|
|
@@ -56,9 +63,13 @@ export const orderedListSchema = $nodeSchema('ordered_list', ctx => ({
|
|
|
56
63
|
},
|
|
57
64
|
},
|
|
58
65
|
toMarkdown: {
|
|
59
|
-
match: node => node.type.name === 'ordered_list',
|
|
66
|
+
match: (node) => node.type.name === 'ordered_list',
|
|
60
67
|
runner: (state, node) => {
|
|
61
|
-
state.openNode('list', undefined, {
|
|
68
|
+
state.openNode('list', undefined, {
|
|
69
|
+
ordered: true,
|
|
70
|
+
start: 1,
|
|
71
|
+
spread: node.attrs.spread === 'true',
|
|
72
|
+
})
|
|
62
73
|
state.next(node.content)
|
|
63
74
|
state.closeNode()
|
|
64
75
|
},
|
|
@@ -76,12 +87,14 @@ withMeta(orderedListSchema.ctx, {
|
|
|
76
87
|
})
|
|
77
88
|
|
|
78
89
|
/// Input rule for wrapping a block in ordered list node.
|
|
79
|
-
export const wrapInOrderedListInputRule = $inputRule(ctx =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
))
|
|
90
|
+
export const wrapInOrderedListInputRule = $inputRule((ctx) =>
|
|
91
|
+
wrappingInputRule(
|
|
92
|
+
/^\s*(\d+)\.\s$/,
|
|
93
|
+
orderedListSchema.type(ctx),
|
|
94
|
+
(match) => ({ order: Number(match[1]) }),
|
|
95
|
+
(match, node) => node.childCount + node.attrs.order === Number(match[1])
|
|
96
|
+
)
|
|
97
|
+
)
|
|
85
98
|
|
|
86
99
|
withMeta(wrapInOrderedListInputRule, {
|
|
87
100
|
displayName: 'InputRule<wrapInOrderedListInputRule>',
|
|
@@ -89,7 +102,10 @@ withMeta(wrapInOrderedListInputRule, {
|
|
|
89
102
|
})
|
|
90
103
|
|
|
91
104
|
/// Command for wrapping a block in ordered list node.
|
|
92
|
-
export const wrapInOrderedListCommand = $command(
|
|
105
|
+
export const wrapInOrderedListCommand = $command(
|
|
106
|
+
'WrapInOrderedList',
|
|
107
|
+
(ctx) => () => wrapIn(orderedListSchema.type(ctx))
|
|
108
|
+
)
|
|
93
109
|
|
|
94
110
|
withMeta(wrapInOrderedListCommand, {
|
|
95
111
|
displayName: 'Command<wrapInOrderedListCommand>',
|
package/src/node/paragraph.ts
CHANGED
|
@@ -12,26 +12,23 @@ withMeta(paragraphAttr, {
|
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
/// Schema for paragraph node.
|
|
15
|
-
export const paragraphSchema = $nodeSchema('paragraph', ctx => ({
|
|
15
|
+
export const paragraphSchema = $nodeSchema('paragraph', (ctx) => ({
|
|
16
16
|
content: 'inline*',
|
|
17
17
|
group: 'block',
|
|
18
18
|
parseDOM: [{ tag: 'p' }],
|
|
19
|
-
toDOM: node => ['p', ctx.get(paragraphAttr.key)(node), 0],
|
|
19
|
+
toDOM: (node) => ['p', ctx.get(paragraphAttr.key)(node), 0],
|
|
20
20
|
parseMarkdown: {
|
|
21
|
-
match: node => node.type === 'paragraph',
|
|
21
|
+
match: (node) => node.type === 'paragraph',
|
|
22
22
|
runner: (state, node, type) => {
|
|
23
23
|
state.openNode(type)
|
|
24
|
-
if (node.children)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
state.addText((node.value || '') as string)
|
|
24
|
+
if (node.children) state.next(node.children)
|
|
25
|
+
else state.addText((node.value || '') as string)
|
|
29
26
|
|
|
30
27
|
state.closeNode()
|
|
31
28
|
},
|
|
32
29
|
},
|
|
33
30
|
toMarkdown: {
|
|
34
|
-
match: node => node.type.name === 'paragraph',
|
|
31
|
+
match: (node) => node.type.name === 'paragraph',
|
|
35
32
|
runner: (state, node) => {
|
|
36
33
|
state.openNode('paragraph')
|
|
37
34
|
serializeText(state, node)
|
|
@@ -50,7 +47,10 @@ withMeta(paragraphSchema.ctx, {
|
|
|
50
47
|
})
|
|
51
48
|
|
|
52
49
|
/// This command can turn the selected block into paragraph.
|
|
53
|
-
export const turnIntoTextCommand = $command(
|
|
50
|
+
export const turnIntoTextCommand = $command(
|
|
51
|
+
'TurnIntoText',
|
|
52
|
+
(ctx) => () => setBlockType(paragraphSchema.type(ctx))
|
|
53
|
+
)
|
|
54
54
|
|
|
55
55
|
withMeta(turnIntoTextCommand, {
|
|
56
56
|
displayName: 'Command<turnIntoTextCommand>',
|
package/src/node/text.ts
CHANGED
|
@@ -11,7 +11,7 @@ export const textSchema = $node('text', () => ({
|
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
toMarkdown: {
|
|
14
|
-
match: node => node.type.name === 'text',
|
|
14
|
+
match: (node) => node.type.name === 'text',
|
|
15
15
|
runner: (state, node) => {
|
|
16
16
|
state.addNode('text', undefined, node.text as string)
|
|
17
17
|
},
|