@milkdown/preset-commonmark 6.5.2 → 6.5.3
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/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +228 -219
- package/lib/index.es.js.map +1 -1
- package/lib/mark/code-inline.d.ts +1 -1
- package/lib/mark/code-inline.d.ts.map +1 -1
- package/lib/mark/em.d.ts +1 -1
- package/lib/mark/em.d.ts.map +1 -1
- package/lib/mark/index.d.ts.map +1 -1
- package/lib/mark/link.d.ts +4 -3
- package/lib/mark/link.d.ts.map +1 -1
- package/lib/mark/strong.d.ts +1 -1
- package/lib/mark/strong.d.ts.map +1 -1
- package/lib/node/blockquote.d.ts +1 -1
- package/lib/node/blockquote.d.ts.map +1 -1
- package/lib/node/bullet-list.d.ts +1 -1
- package/lib/node/bullet-list.d.ts.map +1 -1
- package/lib/node/code-fence.d.ts.map +1 -1
- package/lib/node/doc.d.ts +1 -1
- package/lib/node/doc.d.ts.map +1 -1
- package/lib/node/hardbreak.d.ts.map +1 -1
- package/lib/node/heading.d.ts +2 -2
- package/lib/node/heading.d.ts.map +1 -1
- package/lib/node/hr.d.ts +1 -1
- package/lib/node/hr.d.ts.map +1 -1
- package/lib/node/image.d.ts +2 -2
- package/lib/node/image.d.ts.map +1 -1
- package/lib/node/index.d.ts +1 -1
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/list-item.d.ts +2 -2
- package/lib/node/list-item.d.ts.map +1 -1
- package/lib/node/ordered-list.d.ts +1 -1
- package/lib/node/ordered-list.d.ts.map +1 -1
- package/lib/node/paragraph.d.ts +1 -1
- 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/add-order-in-list.d.ts +1 -1
- package/lib/plugin/add-order-in-list.d.ts.map +1 -1
- package/lib/plugin/filter-html.d.ts +1 -1
- package/lib/plugin/filter-html.d.ts.map +1 -1
- package/lib/plugin/index.d.ts +1 -1
- package/lib/plugin/index.d.ts.map +1 -1
- package/lib/plugin/inline-nodes-cursor.d.ts.map +1 -1
- package/lib/plugin/inline-sync/config.d.ts +8 -8
- package/lib/plugin/inline-sync/config.d.ts.map +1 -1
- package/lib/plugin/inline-sync/context.d.ts +5 -5
- package/lib/plugin/inline-sync/context.d.ts.map +1 -1
- package/lib/plugin/inline-sync/index.d.ts +1 -1
- package/lib/plugin/inline-sync/index.d.ts.map +1 -1
- package/lib/plugin/inline-sync/regexp.d.ts.map +1 -1
- package/lib/plugin/inline-sync/replacer.d.ts +3 -3
- package/lib/plugin/inline-sync/replacer.d.ts.map +1 -1
- package/lib/plugin/inline-sync/utils.d.ts +2 -2
- package/lib/plugin/inline-sync/utils.d.ts.map +1 -1
- package/lib/supported-keys.d.ts +1 -1
- package/lib/supported-keys.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/index.ts +52 -52
- package/src/mark/code-inline.ts +56 -55
- package/src/mark/em.ts +36 -36
- package/src/mark/index.ts +9 -9
- package/src/mark/link.ts +250 -223
- package/src/mark/strong.ts +37 -37
- package/src/node/blockquote.ts +35 -35
- package/src/node/bullet-list.ts +65 -65
- package/src/node/code-fence.ts +236 -229
- package/src/node/doc.ts +21 -21
- package/src/node/hardbreak.ts +108 -107
- package/src/node/heading.ts +275 -272
- package/src/node/hr.ts +55 -55
- package/src/node/image.ts +216 -210
- package/src/node/index.ts +38 -38
- package/src/node/list-item.ts +139 -140
- package/src/node/ordered-list.ts +71 -71
- package/src/node/paragraph.ts +55 -53
- package/src/node/text.ts +18 -18
- package/src/plugin/add-order-in-list.ts +15 -15
- package/src/plugin/filter-html.ts +31 -33
- package/src/plugin/index.ts +13 -13
- package/src/plugin/inline-nodes-cursor.ts +78 -79
- package/src/plugin/inline-sync/config.ts +46 -45
- package/src/plugin/inline-sync/context.ts +88 -83
- package/src/plugin/inline-sync/index.ts +46 -42
- package/src/plugin/inline-sync/regexp.ts +2 -2
- package/src/plugin/inline-sync/replacer.ts +33 -31
- package/src/plugin/inline-sync/utils.ts +53 -55
- package/src/supported-keys.ts +22 -21
|
@@ -1,45 +1,43 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { Literal, Node, Parent } from 'unist'
|
|
2
|
+
import type { Literal, Node, Parent } from 'unist'
|
|
3
3
|
|
|
4
|
-
const isParent = (node: Node): node is Parent => !!(node as Parent).children
|
|
5
|
-
const isHTML = (node: Node): node is Literal<string> => node.type === 'html'
|
|
4
|
+
const isParent = (node: Node): node is Parent => !!(node as Parent).children
|
|
5
|
+
const isHTML = (node: Node): node is Literal<string> => node.type === 'html'
|
|
6
6
|
|
|
7
7
|
function flatMapWithDepth(ast: Node, fn: (node: Node, index: number, parent: Node | null) => Node[]) {
|
|
8
|
-
|
|
8
|
+
return transform(ast, 0, null)[0]
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
10
|
+
function transform(node: Node, index: number, parent: Node | null) {
|
|
11
|
+
if (isParent(node)) {
|
|
12
|
+
const out = []
|
|
13
|
+
for (let i = 0, n = node.children.length; i < n; i++) {
|
|
14
|
+
const nthChild = node.children[i]
|
|
15
|
+
if (nthChild) {
|
|
16
|
+
const xs = transform(nthChild, i, node)
|
|
17
|
+
if (xs) {
|
|
18
|
+
for (let j = 0, m = xs.length; j < m; j++) {
|
|
19
|
+
const item = xs[j]
|
|
20
|
+
if (item)
|
|
21
|
+
out.push(item)
|
|
26
22
|
}
|
|
27
|
-
|
|
23
|
+
}
|
|
28
24
|
}
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
}
|
|
26
|
+
node.children = out
|
|
31
27
|
}
|
|
28
|
+
|
|
29
|
+
return fn(node, index, parent)
|
|
30
|
+
}
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
export const filterHTMLPlugin = () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
34
|
+
function transformer(tree: Node) {
|
|
35
|
+
flatMapWithDepth(tree, (node) => {
|
|
36
|
+
if (!isHTML(node))
|
|
37
|
+
return [node]
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
39
|
+
return []
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
return transformer
|
|
43
|
+
}
|
package/src/plugin/index.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { createPlugin } from '@milkdown/utils'
|
|
3
|
-
import links from 'remark-inline-links'
|
|
2
|
+
import { createPlugin } from '@milkdown/utils'
|
|
3
|
+
import links from 'remark-inline-links'
|
|
4
4
|
|
|
5
|
-
import { addOrderInList } from './add-order-in-list'
|
|
6
|
-
import { filterHTMLPlugin } from './filter-html'
|
|
7
|
-
import { getInlineNodesCursorPlugin } from './inline-nodes-cursor'
|
|
8
|
-
import { getInlineSyncPlugin, inlineSyncConfigCtx } from './inline-sync'
|
|
5
|
+
import { addOrderInList } from './add-order-in-list'
|
|
6
|
+
import { filterHTMLPlugin } from './filter-html'
|
|
7
|
+
import { getInlineNodesCursorPlugin } from './inline-nodes-cursor'
|
|
8
|
+
import { getInlineSyncPlugin, inlineSyncConfigCtx } from './inline-sync'
|
|
9
9
|
|
|
10
|
-
export { inlineSyncConfigCtx }
|
|
10
|
+
export { inlineSyncConfigCtx }
|
|
11
11
|
export const commonmarkPlugins = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
]
|
|
12
|
+
createPlugin(() => ({
|
|
13
|
+
injectSlices: [inlineSyncConfigCtx],
|
|
14
|
+
prosePlugins: (_, ctx) => [getInlineNodesCursorPlugin(), getInlineSyncPlugin(ctx)],
|
|
15
|
+
remarkPlugins: () => [links, filterHTMLPlugin, addOrderInList],
|
|
16
|
+
}))(),
|
|
17
|
+
]
|
|
@@ -1,94 +1,93 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
|
-
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
2
|
+
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
3
|
+
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
4
4
|
|
|
5
|
-
const inlineNodesCursorPluginKey = new PluginKey('MILKDOWN_INLINE_NODES_CURSOR')
|
|
5
|
+
const inlineNodesCursorPluginKey = new PluginKey('MILKDOWN_INLINE_NODES_CURSOR')
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* This plugin is to solve the chrome 98 bug:
|
|
9
9
|
* https://discuss.prosemirror.net/t/cursor-jumps-at-the-end-of-line-when-it-betweens-two-inline-nodes/4641
|
|
10
10
|
*/
|
|
11
11
|
export const getInlineNodesCursorPlugin = (): Plugin => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
const pos = tr.selection.$from;
|
|
24
|
-
const left = pos.nodeBefore;
|
|
25
|
-
const right = pos.nodeAfter;
|
|
26
|
-
if (left && right && left.isInline && !left.isText && right.isInline && !right.isText) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
12
|
+
let lock = false
|
|
13
|
+
const inlineNodesCursorPlugin: Plugin = new Plugin({
|
|
14
|
+
key: inlineNodesCursorPluginKey,
|
|
15
|
+
state: {
|
|
16
|
+
init() {
|
|
17
|
+
return false
|
|
18
|
+
},
|
|
19
|
+
apply(tr) {
|
|
20
|
+
if (!tr.selection.empty)
|
|
21
|
+
return false
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
const pos = tr.selection.$from
|
|
24
|
+
const left = pos.nodeBefore
|
|
25
|
+
const right = pos.nodeAfter
|
|
26
|
+
if (left && right && left.isInline && !left.isText && right.isInline && !right.isText)
|
|
27
|
+
return true
|
|
28
|
+
|
|
29
|
+
return false
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
props: {
|
|
33
|
+
handleDOMEvents: {
|
|
34
|
+
compositionend: (view, e) => {
|
|
35
|
+
if (lock) {
|
|
36
|
+
lock = false
|
|
37
|
+
requestAnimationFrame(() => {
|
|
38
|
+
const active = inlineNodesCursorPlugin.getState(view.state)
|
|
39
|
+
if (active) {
|
|
40
|
+
const from = view.state.selection.from
|
|
41
|
+
e.preventDefault()
|
|
42
|
+
view.dispatch(view.state.tr.insertText(e.data || '', from))
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return true
|
|
47
|
+
}
|
|
48
|
+
return false
|
|
32
49
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
lock = false;
|
|
38
|
-
requestAnimationFrame(() => {
|
|
39
|
-
const active = inlineNodesCursorPlugin.getState(view.state);
|
|
40
|
-
if (active) {
|
|
41
|
-
const from = view.state.selection.from;
|
|
42
|
-
e.preventDefault();
|
|
43
|
-
view.dispatch(view.state.tr.insertText(e.data || '', from));
|
|
44
|
-
}
|
|
45
|
-
});
|
|
50
|
+
compositionstart: (view) => {
|
|
51
|
+
const active = inlineNodesCursorPlugin.getState(view.state)
|
|
52
|
+
if (active)
|
|
53
|
+
lock = true
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
return false;
|
|
57
|
-
},
|
|
58
|
-
beforeinput: (view, e) => {
|
|
59
|
-
const active = inlineNodesCursorPlugin.getState(view.state);
|
|
60
|
-
if (active && e instanceof InputEvent && e.data && !lock) {
|
|
61
|
-
const from = view.state.selection.from;
|
|
62
|
-
e.preventDefault();
|
|
63
|
-
view.dispatch(view.state.tr.insertText(e.data || '', from));
|
|
55
|
+
return false
|
|
56
|
+
},
|
|
57
|
+
beforeinput: (view, e) => {
|
|
58
|
+
const active = inlineNodesCursorPlugin.getState(view.state)
|
|
59
|
+
if (active && e instanceof InputEvent && e.data && !lock) {
|
|
60
|
+
const from = view.state.selection.from
|
|
61
|
+
e.preventDefault()
|
|
62
|
+
view.dispatch(view.state.tr.insertText(e.data || '', from))
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
decorations(state) {
|
|
72
|
-
const active = inlineNodesCursorPlugin.getState(state);
|
|
73
|
-
if (active) {
|
|
74
|
-
const pos = state.selection.$from;
|
|
75
|
-
const position = pos.pos;
|
|
76
|
-
const left = document.createElement('span');
|
|
77
|
-
const leftDec = Decoration.widget(position, left, {
|
|
78
|
-
side: -1,
|
|
79
|
-
});
|
|
80
|
-
const right = document.createElement('span');
|
|
81
|
-
const rightDec = Decoration.widget(position, right);
|
|
82
|
-
setTimeout(() => {
|
|
83
|
-
left.contentEditable = 'true';
|
|
84
|
-
right.contentEditable = 'true';
|
|
85
|
-
});
|
|
86
|
-
return DecorationSet.create(state.doc, [leftDec, rightDec]);
|
|
87
|
-
}
|
|
88
|
-
return DecorationSet.empty;
|
|
89
|
-
},
|
|
67
|
+
return false
|
|
90
68
|
},
|
|
91
|
-
|
|
69
|
+
},
|
|
70
|
+
decorations(state) {
|
|
71
|
+
const active = inlineNodesCursorPlugin.getState(state)
|
|
72
|
+
if (active) {
|
|
73
|
+
const pos = state.selection.$from
|
|
74
|
+
const position = pos.pos
|
|
75
|
+
const left = document.createElement('span')
|
|
76
|
+
const leftDec = Decoration.widget(position, left, {
|
|
77
|
+
side: -1,
|
|
78
|
+
})
|
|
79
|
+
const right = document.createElement('span')
|
|
80
|
+
const rightDec = Decoration.widget(position, right)
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
left.contentEditable = 'true'
|
|
83
|
+
right.contentEditable = 'true'
|
|
84
|
+
})
|
|
85
|
+
return DecorationSet.create(state.doc, [leftDec, rightDec])
|
|
86
|
+
}
|
|
87
|
+
return DecorationSet.empty
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
})
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
}
|
|
92
|
+
return inlineNodesCursorPlugin
|
|
93
|
+
}
|
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import type { Ctx } from '@milkdown/core'
|
|
3
|
+
import { createSlice } from '@milkdown/core'
|
|
4
|
+
import type { Node, NodeType } from '@milkdown/prose/model'
|
|
5
|
+
import type { Transaction } from '@milkdown/prose/state'
|
|
5
6
|
|
|
6
|
-
import { swap } from './utils'
|
|
7
|
+
import { swap } from './utils'
|
|
7
8
|
|
|
8
9
|
export type ShouldSyncNode = (context: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}) => boolean
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
10
|
+
prevNode: Node
|
|
11
|
+
nextNode: Node
|
|
12
|
+
ctx: Ctx
|
|
13
|
+
tr: Transaction
|
|
14
|
+
text: string
|
|
15
|
+
}) => boolean
|
|
16
|
+
|
|
17
|
+
export interface SyncNodePlaceholder {
|
|
18
|
+
hole: string
|
|
19
|
+
punctuation: string
|
|
20
|
+
char: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface InlineSyncConfig {
|
|
24
|
+
placeholderConfig: SyncNodePlaceholder
|
|
25
|
+
shouldSyncNode: ShouldSyncNode
|
|
26
|
+
globalNodes: Array<NodeType | string>
|
|
27
|
+
movePlaceholder: (placeholderToMove: string, text: string) => string
|
|
28
|
+
}
|
|
28
29
|
|
|
29
30
|
export const defaultConfig: InlineSyncConfig = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
nextNode
|
|
31
|
+
placeholderConfig: {
|
|
32
|
+
hole: '∅',
|
|
33
|
+
punctuation: '⁂',
|
|
34
|
+
char: '∴',
|
|
35
|
+
},
|
|
36
|
+
globalNodes: ['footnote_definition'],
|
|
37
|
+
shouldSyncNode: ({ prevNode, nextNode }) =>
|
|
38
|
+
prevNode.inlineContent
|
|
39
|
+
&& nextNode
|
|
39
40
|
// if node type changes, do not sync
|
|
40
|
-
prevNode.type === nextNode.type
|
|
41
|
+
&& prevNode.type === nextNode.type
|
|
41
42
|
// if two node fully equal, we don't modify them
|
|
42
|
-
!prevNode.eq(nextNode),
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
&& !prevNode.eq(nextNode),
|
|
44
|
+
movePlaceholder: (placeholderToMove: string, text: string) => {
|
|
45
|
+
const symbolsNeedToMove = ['*', '_']
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
let index = text.indexOf(placeholderToMove)
|
|
48
|
+
while (symbolsNeedToMove.includes(text[index - 1] || '') && symbolsNeedToMove.includes(text[index + 1] || '')) {
|
|
49
|
+
text = swap(text, index, index + 1)
|
|
50
|
+
index = index + 1
|
|
51
|
+
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
53
|
+
return text
|
|
54
|
+
},
|
|
55
|
+
}
|
|
55
56
|
|
|
56
|
-
export const inlineSyncConfigCtx = createSlice<InlineSyncConfig, 'inlineSyncConfig'>(defaultConfig, 'inlineSyncConfig')
|
|
57
|
+
export const inlineSyncConfigCtx = createSlice<InlineSyncConfig, 'inlineSyncConfig'>(defaultConfig, 'inlineSyncConfig')
|
|
@@ -1,115 +1,120 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import { Ctx
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import type { Ctx } from '@milkdown/core'
|
|
3
|
+
import { parserCtx, serializerCtx } from '@milkdown/core'
|
|
4
|
+
import type { Node } from '@milkdown/prose/model'
|
|
5
|
+
import type { EditorState } from '@milkdown/prose/state'
|
|
6
|
+
import { pipe } from '@milkdown/utils'
|
|
6
7
|
|
|
7
|
-
import { inlineSyncConfigCtx } from './config'
|
|
8
|
-
import { calculatePlaceholder, keepLink, replacePunctuation } from './utils'
|
|
8
|
+
import { inlineSyncConfigCtx } from './config'
|
|
9
|
+
import { calculatePlaceholder, keepLink, replacePunctuation } from './utils'
|
|
9
10
|
|
|
10
|
-
export * from './config'
|
|
11
|
+
export * from './config'
|
|
11
12
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
13
|
+
export interface InlineSyncContext {
|
|
14
|
+
text: string
|
|
15
|
+
prevNode: Node
|
|
16
|
+
nextNode: Node
|
|
17
|
+
placeholder: string
|
|
18
|
+
}
|
|
18
19
|
|
|
19
20
|
const getNodeFromSelection = (state: EditorState) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const { selection } = state
|
|
22
|
+
const { $from } = selection
|
|
23
|
+
const node = $from.node()
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
}
|
|
25
|
+
return node
|
|
26
|
+
}
|
|
26
27
|
|
|
27
28
|
const getMarkdown = (ctx: Ctx, state: EditorState, node: Node, globalNode: Node[]) => {
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const serializer = ctx.get(serializerCtx)
|
|
30
|
+
const doc = state.schema.topNodeType.create(undefined, [node, ...globalNode])
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
const markdown = serializer(doc)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
}
|
|
34
|
+
return markdown
|
|
35
|
+
}
|
|
35
36
|
|
|
36
37
|
const addPlaceholder = (ctx: Ctx, markdown: string) => {
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
const config = ctx.get(inlineSyncConfigCtx)
|
|
39
|
+
const holePlaceholder = config.placeholderConfig.hole
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
const [firstLine = '', ...rest] = markdown.split('\n\n')
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
const movePlaceholder = (text: string) => config.movePlaceholder(holePlaceholder, text)
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const handleText = pipe(replacePunctuation(holePlaceholder), movePlaceholder, keepLink)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
let text = handleText(firstLine)
|
|
48
|
+
const placeholder = calculatePlaceholder(config.placeholderConfig)(text)
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
text = text.replace(holePlaceholder, placeholder)
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
text = [text, ...rest].join('\n\n')
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
}
|
|
54
|
+
return [text, placeholder] as [markdown: string, placeholder: string]
|
|
55
|
+
}
|
|
55
56
|
|
|
56
57
|
const getNewNode = (ctx: Ctx, text: string) => {
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
const parser = ctx.get(parserCtx)
|
|
59
|
+
const parsed = parser(text)
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
if (!parsed)
|
|
62
|
+
return null
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
+
return parsed.firstChild
|
|
65
|
+
}
|
|
64
66
|
|
|
65
67
|
const collectGlobalNodes = (ctx: Ctx, state: EditorState) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
const { globalNodes } = ctx.get(inlineSyncConfigCtx)
|
|
69
|
+
const nodes: Node[] = []
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
state.doc.descendants((node) => {
|
|
72
|
+
if (globalNodes.includes(node.type.name) || globalNodes.includes(node.type)) {
|
|
73
|
+
nodes.push(node)
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return undefined
|
|
78
|
+
})
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
}
|
|
80
|
+
return nodes
|
|
81
|
+
}
|
|
79
82
|
|
|
80
|
-
const removeGlobalFromText = (text: string) => text.split('\n\n')[0] || ''
|
|
83
|
+
const removeGlobalFromText = (text: string) => text.split('\n\n')[0] || ''
|
|
81
84
|
|
|
82
85
|
export const getContextByState = (ctx: Ctx, state: EditorState): InlineSyncContext | null => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
} catch {
|
|
113
|
-
return null;
|
|
86
|
+
try {
|
|
87
|
+
const globalNode = collectGlobalNodes(ctx, state)
|
|
88
|
+
const node = getNodeFromSelection(state)
|
|
89
|
+
|
|
90
|
+
const markdown = getMarkdown(ctx, state, node, globalNode)
|
|
91
|
+
const [text, placeholder] = addPlaceholder(ctx, markdown)
|
|
92
|
+
|
|
93
|
+
const newNode = getNewNode(ctx, text)
|
|
94
|
+
|
|
95
|
+
if (!newNode || node.type !== newNode.type)
|
|
96
|
+
return null
|
|
97
|
+
|
|
98
|
+
// @ts-expect-error hijack the node attribute
|
|
99
|
+
newNode.attrs = { ...node.attrs }
|
|
100
|
+
|
|
101
|
+
newNode.descendants((node) => {
|
|
102
|
+
const marks = node.marks
|
|
103
|
+
const link = marks.find(mark => mark.type.name === 'link')
|
|
104
|
+
if (link && node.text?.includes(placeholder) && link.attrs.href.includes(placeholder)) {
|
|
105
|
+
// @ts-expect-error hijack the mark attribute
|
|
106
|
+
link.attrs.href = link.attrs.href.replace(placeholder, '')
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
text: removeGlobalFromText(text),
|
|
112
|
+
prevNode: node,
|
|
113
|
+
nextNode: newNode,
|
|
114
|
+
placeholder,
|
|
114
115
|
}
|
|
115
|
-
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null
|
|
119
|
+
}
|
|
120
|
+
}
|