@tiptap/core 3.10.7 → 3.11.0
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/dist/index.cjs +217 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -5
- package/dist/index.d.ts +116 -5
- package/dist/index.js +210 -72
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Editor.ts +5 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/resetAttributes.ts +20 -12
- package/src/commands/setTextDirection.ts +51 -0
- package/src/commands/unsetTextDirection.ts +51 -0
- package/src/commands/updateAttributes.ts +68 -58
- package/src/extensions/index.ts +1 -0
- package/src/extensions/textDirection.ts +86 -0
- package/src/helpers/getSchemaByResolvedExtensions.ts +2 -2
- package/src/types.ts +65 -2
- package/src/utilities/markdown/parseIndentedBlocks.ts +2 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/core",
|
|
3
3
|
"description": "headless rich text editor",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.11.0",
|
|
5
5
|
"homepage": "https://tiptap.dev",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"jsx-dev-runtime"
|
|
53
53
|
],
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@tiptap/pm": "^3.
|
|
55
|
+
"@tiptap/pm": "^3.11.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@tiptap/pm": "^3.
|
|
58
|
+
"@tiptap/pm": "^3.11.0"
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
package/src/Editor.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
Keymap,
|
|
18
18
|
Paste,
|
|
19
19
|
Tabindex,
|
|
20
|
+
TextDirection,
|
|
20
21
|
} from './extensions/index.js'
|
|
21
22
|
import { createDocument } from './helpers/createDocument.js'
|
|
22
23
|
import { getAttributes } from './helpers/getAttributes.js'
|
|
@@ -87,6 +88,7 @@ export class Editor extends EventEmitter<EditorEvents> {
|
|
|
87
88
|
extensions: [],
|
|
88
89
|
autofocus: false,
|
|
89
90
|
editable: true,
|
|
91
|
+
textDirection: undefined,
|
|
90
92
|
editorProps: {},
|
|
91
93
|
parseOptions: {},
|
|
92
94
|
coreExtensionOptions: {},
|
|
@@ -430,6 +432,9 @@ export class Editor extends EventEmitter<EditorEvents> {
|
|
|
430
432
|
Drop,
|
|
431
433
|
Paste,
|
|
432
434
|
Delete,
|
|
435
|
+
TextDirection.configure({
|
|
436
|
+
direction: this.options.textDirection,
|
|
437
|
+
}),
|
|
433
438
|
].filter(ext => {
|
|
434
439
|
if (typeof this.options.enableCoreExtensions === 'object') {
|
|
435
440
|
return (
|
package/src/commands/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ export * from './setMark.js'
|
|
|
39
39
|
export * from './setMeta.js'
|
|
40
40
|
export * from './setNode.js'
|
|
41
41
|
export * from './setNodeSelection.js'
|
|
42
|
+
export * from './setTextDirection.js'
|
|
42
43
|
export * from './setTextSelection.js'
|
|
43
44
|
export * from './sinkListItem.js'
|
|
44
45
|
export * from './splitBlock.js'
|
|
@@ -50,6 +51,7 @@ export * from './toggleWrap.js'
|
|
|
50
51
|
export * from './undoInputRule.js'
|
|
51
52
|
export * from './unsetAllMarks.js'
|
|
52
53
|
export * from './unsetMark.js'
|
|
54
|
+
export * from './unsetTextDirection.js'
|
|
53
55
|
export * from './updateAttributes.js'
|
|
54
56
|
export * from './wrapIn.js'
|
|
55
57
|
export * from './wrapInList.js'
|
|
@@ -43,23 +43,31 @@ export const resetAttributes: RawCommands['resetAttributes'] =
|
|
|
43
43
|
markType = getMarkType(typeOrName as MarkType, state.schema)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
let canReset = false
|
|
47
|
+
|
|
48
|
+
tr.selection.ranges.forEach(range => {
|
|
49
|
+
state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
|
|
50
|
+
if (nodeType && nodeType === node.type) {
|
|
51
|
+
canReset = true
|
|
52
|
+
|
|
53
|
+
if (dispatch) {
|
|
50
54
|
tr.setNodeMarkup(pos, undefined, deleteProps(node.attrs, attributes))
|
|
51
55
|
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (markType && node.marks.length) {
|
|
59
|
+
node.marks.forEach(mark => {
|
|
60
|
+
if (markType === mark.type) {
|
|
61
|
+
canReset = true
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
node.marks.forEach(mark => {
|
|
55
|
-
if (markType === mark.type) {
|
|
63
|
+
if (dispatch) {
|
|
56
64
|
tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)))
|
|
57
65
|
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}
|
|
61
69
|
})
|
|
62
|
-
}
|
|
70
|
+
})
|
|
63
71
|
|
|
64
|
-
return
|
|
72
|
+
return canReset
|
|
65
73
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Range, RawCommands } from '../types.js'
|
|
2
|
+
|
|
3
|
+
declare module '@tiptap/core' {
|
|
4
|
+
interface Commands<ReturnType> {
|
|
5
|
+
setTextDirection: {
|
|
6
|
+
/**
|
|
7
|
+
* Set the text direction for nodes.
|
|
8
|
+
* If no position is provided, it will use the current selection.
|
|
9
|
+
* @param direction The text direction to set ('ltr', 'rtl', or 'auto')
|
|
10
|
+
* @param position Optional position or range to apply the direction to
|
|
11
|
+
* @example editor.commands.setTextDirection('rtl')
|
|
12
|
+
* @example editor.commands.setTextDirection('ltr', { from: 0, to: 10 })
|
|
13
|
+
*/
|
|
14
|
+
setTextDirection: (direction: 'ltr' | 'rtl' | 'auto', position?: number | Range) => ReturnType
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const setTextDirection: RawCommands['setTextDirection'] =
|
|
20
|
+
(direction, position) =>
|
|
21
|
+
({ tr, state, dispatch }) => {
|
|
22
|
+
const { selection } = state
|
|
23
|
+
let from: number
|
|
24
|
+
let to: number
|
|
25
|
+
|
|
26
|
+
if (typeof position === 'number') {
|
|
27
|
+
from = position
|
|
28
|
+
to = position
|
|
29
|
+
} else if (position && 'from' in position && 'to' in position) {
|
|
30
|
+
from = position.from
|
|
31
|
+
to = position.to
|
|
32
|
+
} else {
|
|
33
|
+
from = selection.from
|
|
34
|
+
to = selection.to
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (dispatch) {
|
|
38
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
39
|
+
if (node.isText) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
tr.setNodeMarkup(pos, undefined, {
|
|
44
|
+
...node.attrs,
|
|
45
|
+
dir: direction,
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Range, RawCommands } from '../types.js'
|
|
2
|
+
|
|
3
|
+
declare module '@tiptap/core' {
|
|
4
|
+
interface Commands<ReturnType> {
|
|
5
|
+
unsetTextDirection: {
|
|
6
|
+
/**
|
|
7
|
+
* Remove the text direction attribute from nodes.
|
|
8
|
+
* If no position is provided, it will use the current selection.
|
|
9
|
+
* @param position Optional position or range to remove the direction from
|
|
10
|
+
* @example editor.commands.unsetTextDirection()
|
|
11
|
+
* @example editor.commands.unsetTextDirection({ from: 0, to: 10 })
|
|
12
|
+
*/
|
|
13
|
+
unsetTextDirection: (position?: number | Range) => ReturnType
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const unsetTextDirection: RawCommands['unsetTextDirection'] =
|
|
19
|
+
position =>
|
|
20
|
+
({ tr, state, dispatch }) => {
|
|
21
|
+
const { selection } = state
|
|
22
|
+
let from: number
|
|
23
|
+
let to: number
|
|
24
|
+
|
|
25
|
+
if (typeof position === 'number') {
|
|
26
|
+
from = position
|
|
27
|
+
to = position
|
|
28
|
+
} else if (position && 'from' in position && 'to' in position) {
|
|
29
|
+
from = position.from
|
|
30
|
+
to = position.to
|
|
31
|
+
} else {
|
|
32
|
+
from = selection.from
|
|
33
|
+
to = selection.to
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (dispatch) {
|
|
37
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
38
|
+
if (node.isText) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const newAttrs = { ...node.attrs }
|
|
43
|
+
|
|
44
|
+
delete newAttrs.dir
|
|
45
|
+
|
|
46
|
+
tr.setNodeMarkup(pos, undefined, newAttrs)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
@@ -53,45 +53,55 @@ export const updateAttributes: RawCommands['updateAttributes'] =
|
|
|
53
53
|
markType = getMarkType(typeOrName as MarkType, state.schema)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
let canUpdate = false
|
|
57
|
+
|
|
58
|
+
tr.selection.ranges.forEach((range: SelectionRange) => {
|
|
59
|
+
const from = range.$from.pos
|
|
60
|
+
const to = range.$to.pos
|
|
61
|
+
|
|
62
|
+
let lastPos: number | undefined
|
|
63
|
+
let lastNode: Node | undefined
|
|
64
|
+
let trimmedFrom: number
|
|
65
|
+
let trimmedTo: number
|
|
66
|
+
|
|
67
|
+
if (tr.selection.empty) {
|
|
68
|
+
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
69
|
+
if (nodeType && nodeType === node.type) {
|
|
70
|
+
canUpdate = true
|
|
71
|
+
trimmedFrom = Math.max(pos, from)
|
|
72
|
+
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
73
|
+
lastPos = pos
|
|
74
|
+
lastNode = node
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
} else {
|
|
78
|
+
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
79
|
+
if (pos < from && nodeType && nodeType === node.type) {
|
|
80
|
+
canUpdate = true
|
|
81
|
+
trimmedFrom = Math.max(pos, from)
|
|
82
|
+
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
83
|
+
lastPos = pos
|
|
84
|
+
lastNode = node
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (pos >= from && pos <= to) {
|
|
68
88
|
if (nodeType && nodeType === node.type) {
|
|
69
|
-
|
|
70
|
-
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
71
|
-
lastPos = pos
|
|
72
|
-
lastNode = node
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
} else {
|
|
76
|
-
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
|
|
77
|
-
if (pos < from && nodeType && nodeType === node.type) {
|
|
78
|
-
trimmedFrom = Math.max(pos, from)
|
|
79
|
-
trimmedTo = Math.min(pos + node.nodeSize, to)
|
|
80
|
-
lastPos = pos
|
|
81
|
-
lastNode = node
|
|
82
|
-
}
|
|
89
|
+
canUpdate = true
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
if (nodeType && nodeType === node.type) {
|
|
91
|
+
if (dispatch) {
|
|
86
92
|
tr.setNodeMarkup(pos, undefined, {
|
|
87
93
|
...node.attrs,
|
|
88
94
|
...attributes,
|
|
89
95
|
})
|
|
90
96
|
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (markType && node.marks.length) {
|
|
100
|
+
node.marks.forEach((mark: Mark) => {
|
|
101
|
+
if (markType === mark.type) {
|
|
102
|
+
canUpdate = true
|
|
91
103
|
|
|
92
|
-
|
|
93
|
-
node.marks.forEach((mark: Mark) => {
|
|
94
|
-
if (markType === mark.type) {
|
|
104
|
+
if (dispatch) {
|
|
95
105
|
const trimmedFrom2 = Math.max(pos, from)
|
|
96
106
|
const trimmedTo2 = Math.min(pos + node.nodeSize, to)
|
|
97
107
|
|
|
@@ -104,37 +114,37 @@ export const updateAttributes: RawCommands['updateAttributes'] =
|
|
|
104
114
|
}),
|
|
105
115
|
)
|
|
106
116
|
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
109
119
|
}
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (lastNode) {
|
|
125
|
+
if (lastPos !== undefined && dispatch) {
|
|
126
|
+
tr.setNodeMarkup(lastPos, undefined, {
|
|
127
|
+
...lastNode.attrs,
|
|
128
|
+
...attributes,
|
|
110
129
|
})
|
|
111
130
|
}
|
|
112
131
|
|
|
113
|
-
if (lastNode) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
trimmedTo,
|
|
127
|
-
markType.create({
|
|
128
|
-
...mark.attrs,
|
|
129
|
-
...attributes,
|
|
130
|
-
}),
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
}
|
|
132
|
+
if (markType && lastNode.marks.length) {
|
|
133
|
+
lastNode.marks.forEach((mark: Mark) => {
|
|
134
|
+
if (markType === mark.type && dispatch) {
|
|
135
|
+
tr.addMark(
|
|
136
|
+
trimmedFrom,
|
|
137
|
+
trimmedTo,
|
|
138
|
+
markType.create({
|
|
139
|
+
...mark.attrs,
|
|
140
|
+
...attributes,
|
|
141
|
+
}),
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
135
145
|
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
146
|
+
}
|
|
147
|
+
})
|
|
138
148
|
|
|
139
|
-
return
|
|
149
|
+
return canUpdate
|
|
140
150
|
}
|
package/src/extensions/index.ts
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
2
|
+
|
|
3
|
+
import { Extension } from '../Extension.js'
|
|
4
|
+
import { splitExtensions } from '../helpers/splitExtensions.js'
|
|
5
|
+
|
|
6
|
+
export interface TextDirectionOptions {
|
|
7
|
+
direction: 'ltr' | 'rtl' | 'auto' | undefined
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The TextDirection extension adds support for setting text direction (LTR/RTL/auto)
|
|
12
|
+
* on all nodes in the editor.
|
|
13
|
+
*
|
|
14
|
+
* This extension adds a global `dir` attribute to all node types, which can be used
|
|
15
|
+
* to control bidirectional text rendering. The direction can be set globally via
|
|
16
|
+
* editor options or per-node using commands.
|
|
17
|
+
*/
|
|
18
|
+
export const TextDirection = Extension.create<TextDirectionOptions>({
|
|
19
|
+
name: 'textDirection',
|
|
20
|
+
|
|
21
|
+
addOptions() {
|
|
22
|
+
return {
|
|
23
|
+
direction: undefined,
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
addGlobalAttributes() {
|
|
28
|
+
// Only add the dir attribute to nodes if text direction is configured
|
|
29
|
+
// This prevents null/undefined values from appearing in JSON exports
|
|
30
|
+
if (!this.options.direction) {
|
|
31
|
+
return []
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { nodeExtensions } = splitExtensions(this.extensions)
|
|
35
|
+
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
types: nodeExtensions.filter(extension => extension.name !== 'text').map(extension => extension.name),
|
|
39
|
+
attributes: {
|
|
40
|
+
dir: {
|
|
41
|
+
default: this.options.direction,
|
|
42
|
+
parseHTML: element => {
|
|
43
|
+
const dir = element.getAttribute('dir')
|
|
44
|
+
|
|
45
|
+
if (dir && (dir === 'ltr' || dir === 'rtl' || dir === 'auto')) {
|
|
46
|
+
return dir
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return this.options.direction
|
|
50
|
+
},
|
|
51
|
+
renderHTML: attributes => {
|
|
52
|
+
if (!attributes.dir) {
|
|
53
|
+
return {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
dir: attributes.dir,
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
addProseMirrorPlugins() {
|
|
67
|
+
return [
|
|
68
|
+
new Plugin({
|
|
69
|
+
key: new PluginKey('textDirection'),
|
|
70
|
+
props: {
|
|
71
|
+
attributes: (): { [name: string]: string } => {
|
|
72
|
+
const direction = this.options.direction
|
|
73
|
+
|
|
74
|
+
if (!direction) {
|
|
75
|
+
return {}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
dir: direction,
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
})
|
|
@@ -34,8 +34,8 @@ function buildAttributeSpec(
|
|
|
34
34
|
): [string, Record<string, any>] {
|
|
35
35
|
const spec: Record<string, any> = {}
|
|
36
36
|
|
|
37
|
-
// Only include 'default' if the attribute is not required and default is
|
|
38
|
-
if (!extensionAttribute?.attribute?.isRequired && extensionAttribute?.attribute
|
|
37
|
+
// Only include 'default' if the attribute is not required and default is set on the attribute
|
|
38
|
+
if (!extensionAttribute?.attribute?.isRequired && 'default' in (extensionAttribute?.attribute || {})) {
|
|
39
39
|
spec.default = extensionAttribute.attribute.default
|
|
40
40
|
}
|
|
41
41
|
|
package/src/types.ts
CHANGED
|
@@ -292,6 +292,14 @@ export interface EditorOptions {
|
|
|
292
292
|
* Whether the editor is editable
|
|
293
293
|
*/
|
|
294
294
|
editable: boolean
|
|
295
|
+
/**
|
|
296
|
+
* The default text direction for all content in the editor.
|
|
297
|
+
* When set to 'ltr' or 'rtl', all nodes will have the corresponding dir attribute.
|
|
298
|
+
* When set to 'auto', the dir attribute will be set based on content detection.
|
|
299
|
+
* When undefined, no dir attribute will be added.
|
|
300
|
+
* @default undefined
|
|
301
|
+
*/
|
|
302
|
+
textDirection?: 'ltr' | 'rtl' | 'auto'
|
|
295
303
|
/**
|
|
296
304
|
* The editor's props
|
|
297
305
|
*/
|
|
@@ -357,7 +365,8 @@ export interface EditorOptions {
|
|
|
357
365
|
| 'tabindex'
|
|
358
366
|
| 'drop'
|
|
359
367
|
| 'paste'
|
|
360
|
-
| 'delete'
|
|
368
|
+
| 'delete'
|
|
369
|
+
| 'textDirection',
|
|
361
370
|
false
|
|
362
371
|
>
|
|
363
372
|
>
|
|
@@ -442,17 +451,71 @@ export interface EditorOptions {
|
|
|
442
451
|
export type HTMLContent = string
|
|
443
452
|
|
|
444
453
|
/**
|
|
445
|
-
*
|
|
454
|
+
* A Tiptap JSON node or document. Tiptap JSON is the standard format for
|
|
455
|
+
* storing and manipulating Tiptap content. It is equivalent to the JSON
|
|
456
|
+
* representation of a Prosemirror node.
|
|
457
|
+
*
|
|
458
|
+
* Tiptap JSON documents are trees of nodes. The root node is usually of type
|
|
459
|
+
* `doc`. Nodes can have other nodes as children. Nodes can also have marks and
|
|
460
|
+
* attributes. Text nodes (nodes with type `text`) have a `text` property and no
|
|
461
|
+
* children.
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* const content: JSONContent = {
|
|
466
|
+
* type: 'doc',
|
|
467
|
+
* content: [
|
|
468
|
+
* {
|
|
469
|
+
* type: 'paragraph',
|
|
470
|
+
* content: [
|
|
471
|
+
* {
|
|
472
|
+
* type: 'text',
|
|
473
|
+
* text: 'Hello ',
|
|
474
|
+
* },
|
|
475
|
+
* {
|
|
476
|
+
* type: 'text',
|
|
477
|
+
* text: 'world',
|
|
478
|
+
* marks: [{ type: 'bold' }],
|
|
479
|
+
* },
|
|
480
|
+
* ],
|
|
481
|
+
* },
|
|
482
|
+
* ],
|
|
483
|
+
* }
|
|
484
|
+
* ```
|
|
446
485
|
*/
|
|
447
486
|
export type JSONContent = {
|
|
487
|
+
/**
|
|
488
|
+
* The type of the node
|
|
489
|
+
*/
|
|
448
490
|
type?: string
|
|
491
|
+
/**
|
|
492
|
+
* The attributes of the node. Attributes can have any JSON-serializable value.
|
|
493
|
+
*/
|
|
449
494
|
attrs?: Record<string, any> | undefined
|
|
495
|
+
/**
|
|
496
|
+
* The children of the node. A node can have other nodes as children.
|
|
497
|
+
*/
|
|
450
498
|
content?: JSONContent[]
|
|
499
|
+
/**
|
|
500
|
+
* A list of marks of the node. Inline nodes can have marks.
|
|
501
|
+
*/
|
|
451
502
|
marks?: {
|
|
503
|
+
/**
|
|
504
|
+
* The type of the mark
|
|
505
|
+
*/
|
|
452
506
|
type: string
|
|
507
|
+
/**
|
|
508
|
+
* The attributes of the mark. Attributes can have any JSON-serializable value.
|
|
509
|
+
*/
|
|
453
510
|
attrs?: Record<string, any>
|
|
454
511
|
[key: string]: any
|
|
455
512
|
}[]
|
|
513
|
+
/**
|
|
514
|
+
* The text content of the node. This property is only present on text nodes
|
|
515
|
+
* (i.e. nodes with `type: 'text'`).
|
|
516
|
+
*
|
|
517
|
+
* Text nodes cannot have children, but they can have marks.
|
|
518
|
+
*/
|
|
456
519
|
text?: string
|
|
457
520
|
[key: string]: any
|
|
458
521
|
}
|
|
@@ -103,6 +103,7 @@ export function parseIndentedBlocks(
|
|
|
103
103
|
break
|
|
104
104
|
} else if (currentLine.trim() === '') {
|
|
105
105
|
i += 1
|
|
106
|
+
totalRaw = `${totalRaw}${currentLine}\n`
|
|
106
107
|
continue
|
|
107
108
|
} else {
|
|
108
109
|
return undefined
|
|
@@ -188,6 +189,6 @@ export function parseIndentedBlocks(
|
|
|
188
189
|
|
|
189
190
|
return {
|
|
190
191
|
items,
|
|
191
|
-
raw: totalRaw
|
|
192
|
+
raw: totalRaw,
|
|
192
193
|
}
|
|
193
194
|
}
|