@tiptap/static-renderer 3.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/README.md +18 -0
- package/dist/index.cjs +62 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +52 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/json/html-string/index.cjs +100 -0
- package/dist/json/html-string/index.cjs.map +1 -0
- package/dist/json/html-string/index.d.cts +205 -0
- package/dist/json/html-string/index.d.ts +205 -0
- package/dist/json/html-string/index.js +72 -0
- package/dist/json/html-string/index.js.map +1 -0
- package/dist/json/react/index.cjs +2306 -0
- package/dist/json/react/index.cjs.map +1 -0
- package/dist/json/react/index.d.cts +207 -0
- package/dist/json/react/index.d.ts +207 -0
- package/dist/json/react/index.js +2291 -0
- package/dist/json/react/index.js.map +1 -0
- package/dist/json/renderer.cjs +89 -0
- package/dist/json/renderer.cjs.map +1 -0
- package/dist/json/renderer.d.cts +182 -0
- package/dist/json/renderer.d.ts +182 -0
- package/dist/json/renderer.js +64 -0
- package/dist/json/renderer.js.map +1 -0
- package/dist/pm/html-string/index.cjs +359 -0
- package/dist/pm/html-string/index.cjs.map +1 -0
- package/dist/pm/html-string/index.d.cts +192 -0
- package/dist/pm/html-string/index.d.ts +192 -0
- package/dist/pm/html-string/index.js +332 -0
- package/dist/pm/html-string/index.js.map +1 -0
- package/dist/pm/react/index.cjs +2588 -0
- package/dist/pm/react/index.cjs.map +1 -0
- package/dist/pm/react/index.d.cts +181 -0
- package/dist/pm/react/index.d.ts +181 -0
- package/dist/pm/react/index.js +2576 -0
- package/dist/pm/react/index.js.map +1 -0
- package/package.json +82 -0
- package/src/helpers.example.ts +35 -0
- package/src/helpers.ts +65 -0
- package/src/index.ts +2 -0
- package/src/json/html-string/index.ts +2 -0
- package/src/json/html-string/string.example.ts +46 -0
- package/src/json/html-string/string.ts +22 -0
- package/src/json/react/index.ts +2 -0
- package/src/json/react/react.example.ts +45 -0
- package/src/json/react/react.tsx +35 -0
- package/src/json/renderer.ts +242 -0
- package/src/pm/extensionRenderer.ts +230 -0
- package/src/pm/html-string/html-string.example.ts +225 -0
- package/src/pm/html-string/html-string.ts +121 -0
- package/src/pm/html-string/index.ts +2 -0
- package/src/pm/markdown/markdown.example.ts +296 -0
- package/src/pm/react/index.ts +2 -0
- package/src/pm/react/react.example.tsx +306 -0
- package/src/pm/react/react.tsx +133 -0
- package/src/types.ts +57 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import StarterKit from '@tiptap/starter-kit'
|
|
2
|
+
|
|
3
|
+
import { renderToHTMLString, serializeAttrsToHTMLString, serializeChildrenToHTMLString } from './html-string.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This example demonstrates how to render a Prosemirror Node (or JSON Content) to an HTML string.
|
|
7
|
+
* It will use your extensions to render the content based on each Node's/Mark's `renderHTML` method.
|
|
8
|
+
* This can be useful if you want to render content to HTML without having an actual editor instance.
|
|
9
|
+
*
|
|
10
|
+
* You have complete control over the rendering process. And can replace how each Node/Mark is rendered.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line no-console
|
|
14
|
+
console.log(
|
|
15
|
+
renderToHTMLString({
|
|
16
|
+
extensions: [StarterKit],
|
|
17
|
+
options: {
|
|
18
|
+
nodeMapping: {
|
|
19
|
+
heading({ node, children }) {
|
|
20
|
+
const level = node.attrs.level
|
|
21
|
+
|
|
22
|
+
return `<h${level}${serializeAttrsToHTMLString(node.attrs)}>THIS IS AN EXAMPLE OF CUSTOM HTML STRING RENDERING${serializeChildrenToHTMLString(children)}</h${level}>`
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
markMapping: {},
|
|
26
|
+
},
|
|
27
|
+
content:
|
|
28
|
+
{
|
|
29
|
+
type: 'doc',
|
|
30
|
+
from: 0,
|
|
31
|
+
to: 574,
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: 'heading',
|
|
35
|
+
from: 0,
|
|
36
|
+
to: 11,
|
|
37
|
+
attrs: {
|
|
38
|
+
level: 2,
|
|
39
|
+
},
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
from: 1,
|
|
44
|
+
to: 10,
|
|
45
|
+
text: 'Hi there,',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'paragraph',
|
|
51
|
+
from: 11,
|
|
52
|
+
to: 169,
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: 'text',
|
|
56
|
+
from: 12,
|
|
57
|
+
to: 22,
|
|
58
|
+
text: 'this is a ',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
from: 22,
|
|
63
|
+
to: 27,
|
|
64
|
+
marks: [
|
|
65
|
+
{
|
|
66
|
+
type: 'italic',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
text: 'basic',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'text',
|
|
73
|
+
from: 27,
|
|
74
|
+
to: 39,
|
|
75
|
+
text: ' example of ',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
from: 39,
|
|
80
|
+
to: 45,
|
|
81
|
+
marks: [
|
|
82
|
+
{
|
|
83
|
+
type: 'bold',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
text: 'Tiptap',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'text',
|
|
90
|
+
from: 45,
|
|
91
|
+
to: 168,
|
|
92
|
+
text: '. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:',
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'bulletList',
|
|
98
|
+
from: 169,
|
|
99
|
+
to: 230,
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: 'listItem',
|
|
103
|
+
from: 170,
|
|
104
|
+
to: 205,
|
|
105
|
+
attrs: {
|
|
106
|
+
color: '',
|
|
107
|
+
},
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'paragraph',
|
|
111
|
+
from: 171,
|
|
112
|
+
to: 204,
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: 'text',
|
|
116
|
+
from: 172,
|
|
117
|
+
to: 203,
|
|
118
|
+
text: 'That’s a bullet list with one …',
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
type: 'listItem',
|
|
126
|
+
from: 205,
|
|
127
|
+
to: 229,
|
|
128
|
+
attrs: {
|
|
129
|
+
color: '',
|
|
130
|
+
},
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: 'paragraph',
|
|
134
|
+
from: 206,
|
|
135
|
+
to: 228,
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: 'text',
|
|
139
|
+
from: 207,
|
|
140
|
+
to: 227,
|
|
141
|
+
text: '… or two list items.',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'paragraph',
|
|
151
|
+
from: 230,
|
|
152
|
+
to: 326,
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: 'text',
|
|
156
|
+
from: 231,
|
|
157
|
+
to: 325,
|
|
158
|
+
text: 'Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:',
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'codeBlock',
|
|
164
|
+
from: 326,
|
|
165
|
+
to: 353,
|
|
166
|
+
attrs: {
|
|
167
|
+
language: 'css',
|
|
168
|
+
},
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: 'text',
|
|
172
|
+
from: 327,
|
|
173
|
+
to: 352,
|
|
174
|
+
text: 'body {\n display: none;\n}',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
type: 'paragraph',
|
|
180
|
+
from: 353,
|
|
181
|
+
to: 522,
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: 'text',
|
|
185
|
+
from: 354,
|
|
186
|
+
to: 521,
|
|
187
|
+
text: 'I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.',
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: 'blockquote',
|
|
193
|
+
from: 522,
|
|
194
|
+
to: 572,
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: 'paragraph',
|
|
198
|
+
from: 523,
|
|
199
|
+
to: 571,
|
|
200
|
+
content: [
|
|
201
|
+
{
|
|
202
|
+
type: 'text',
|
|
203
|
+
from: 524,
|
|
204
|
+
to: 564,
|
|
205
|
+
text: 'Wow, that’s amazing. Good work, boy! 👏 ',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
type: 'hardBreak',
|
|
209
|
+
from: 564,
|
|
210
|
+
to: 565,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
type: 'text',
|
|
214
|
+
from: 565,
|
|
215
|
+
to: 570,
|
|
216
|
+
text: '— Mom',
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
}),
|
|
225
|
+
)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { Extensions, JSONContent } from '@tiptap/core'
|
|
3
|
+
import type { DOMOutputSpec, Mark, Node } from '@tiptap/pm/model'
|
|
4
|
+
|
|
5
|
+
import { renderJSONContentToString } from '../../json/html-string/string.js'
|
|
6
|
+
import { TiptapStaticRendererOptions } from '../../json/renderer.js'
|
|
7
|
+
import type { DOMOutputSpecArray } from '../../types.js'
|
|
8
|
+
import { renderToElement } from '../extensionRenderer.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Serialize the attributes of a node or mark to a string
|
|
12
|
+
* @param attrs The attributes to serialize
|
|
13
|
+
* @returns The serialized attributes as a string
|
|
14
|
+
*/
|
|
15
|
+
export function serializeAttrsToHTMLString(attrs: Record<string, any>): string {
|
|
16
|
+
const output = Object.entries(attrs)
|
|
17
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
18
|
+
.join(' ')
|
|
19
|
+
|
|
20
|
+
return output ? ` ${output}` : ''
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Serialize the children of a node or mark to a string
|
|
25
|
+
* @param children The children to serialize
|
|
26
|
+
* @returns The serialized children as a string
|
|
27
|
+
*/
|
|
28
|
+
export function serializeChildrenToHTMLString(children?: string | string[]): string {
|
|
29
|
+
return ([] as string[])
|
|
30
|
+
.concat(children || '')
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.join('')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Take a DOMOutputSpec and return a function that can render it to a string
|
|
37
|
+
* @param content The DOMOutputSpec to convert to a string
|
|
38
|
+
* @returns A function that can render the DOMOutputSpec to a string
|
|
39
|
+
*/
|
|
40
|
+
export function domOutputSpecToHTMLString(
|
|
41
|
+
content: DOMOutputSpec,
|
|
42
|
+
): (children?: string | string[]) => string {
|
|
43
|
+
if (typeof content === 'string') {
|
|
44
|
+
return () => content
|
|
45
|
+
}
|
|
46
|
+
if (typeof content === 'object' && 'length' in content) {
|
|
47
|
+
const [tag, attrs, children, ...rest] = content as DOMOutputSpecArray
|
|
48
|
+
|
|
49
|
+
if (attrs === undefined) {
|
|
50
|
+
return () => `<${tag}/>`
|
|
51
|
+
}
|
|
52
|
+
if (attrs === 0) {
|
|
53
|
+
return child => `<${tag}>${serializeChildrenToHTMLString(child)}</${tag}>`
|
|
54
|
+
}
|
|
55
|
+
if (typeof attrs === 'object') {
|
|
56
|
+
if (Array.isArray(attrs)) {
|
|
57
|
+
if (children === undefined) {
|
|
58
|
+
return child => `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`
|
|
59
|
+
}
|
|
60
|
+
if (children === 0) {
|
|
61
|
+
return child => `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}</${tag}>`
|
|
62
|
+
}
|
|
63
|
+
return child => `<${tag}>${domOutputSpecToHTMLString(attrs as DOMOutputSpecArray)(child)}${[children]
|
|
64
|
+
.concat(rest)
|
|
65
|
+
.map(a => domOutputSpecToHTMLString(a)(child))}</${tag}>`
|
|
66
|
+
}
|
|
67
|
+
if (children === undefined) {
|
|
68
|
+
return () => `<${tag}${serializeAttrsToHTMLString(attrs)}/>`
|
|
69
|
+
}
|
|
70
|
+
if (children === 0) {
|
|
71
|
+
return child => `<${tag}${serializeAttrsToHTMLString(attrs)}>${serializeChildrenToHTMLString(
|
|
72
|
+
child,
|
|
73
|
+
)}</${tag}>`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return child => `<${tag}${serializeAttrsToHTMLString(attrs)}>${[children]
|
|
77
|
+
.concat(rest)
|
|
78
|
+
.map(a => domOutputSpecToHTMLString(a)(child))
|
|
79
|
+
.join('')}</${tag}>`
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// TODO support DOM elements? How to handle them?
|
|
84
|
+
throw new Error(
|
|
85
|
+
'[tiptap error]: Unsupported DomOutputSpec type, check the `renderHTML` method output',
|
|
86
|
+
{
|
|
87
|
+
cause: content,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* This function will statically render a Prosemirror Node to HTML using the provided extensions and options
|
|
94
|
+
* @param content The content to render to HTML
|
|
95
|
+
* @param extensions The extensions to use for rendering
|
|
96
|
+
* @param options The options to use for rendering
|
|
97
|
+
* @returns The rendered HTML string
|
|
98
|
+
*/
|
|
99
|
+
export function renderToHTMLString({
|
|
100
|
+
content,
|
|
101
|
+
extensions,
|
|
102
|
+
options,
|
|
103
|
+
}: {
|
|
104
|
+
content: Node | JSONContent;
|
|
105
|
+
extensions: Extensions;
|
|
106
|
+
options?: Partial<TiptapStaticRendererOptions<string, Mark, Node>>;
|
|
107
|
+
}): string {
|
|
108
|
+
return renderToElement<string>({
|
|
109
|
+
renderer: renderJSONContentToString,
|
|
110
|
+
domOutputSpecToElement: domOutputSpecToHTMLString,
|
|
111
|
+
mapDefinedTypes: {
|
|
112
|
+
// Map a doc node to concatenated children
|
|
113
|
+
doc: ({ children }) => serializeChildrenToHTMLString(children),
|
|
114
|
+
// Map a text node to its text content
|
|
115
|
+
text: ({ node }) => node.text ?? '',
|
|
116
|
+
},
|
|
117
|
+
content,
|
|
118
|
+
extensions,
|
|
119
|
+
options,
|
|
120
|
+
})
|
|
121
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { JSONContent } from '@tiptap/core'
|
|
2
|
+
import StarterKit from '@tiptap/starter-kit'
|
|
3
|
+
|
|
4
|
+
import { renderToHTMLString, serializeChildrenToHTMLString } from '../html-string/html-string.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This code is just to show the flexibility of this renderer. We can potentially render content to any format we want.
|
|
8
|
+
* This is a simple example of how we can render content to markdown. This is not a full implementation of a markdown renderer.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const renderToMarkdown = ({ content }: { content: JSONContent | Node }) => renderToHTMLString({
|
|
12
|
+
content,
|
|
13
|
+
extensions: [StarterKit],
|
|
14
|
+
options: {
|
|
15
|
+
nodeMapping: {
|
|
16
|
+
bulletList({ children }) {
|
|
17
|
+
return `\n${serializeChildrenToHTMLString(children)}`
|
|
18
|
+
},
|
|
19
|
+
orderedList({ children }) {
|
|
20
|
+
return `\n${serializeChildrenToHTMLString(children)}`
|
|
21
|
+
},
|
|
22
|
+
listItem({ node, children, parent }) {
|
|
23
|
+
if (parent?.type.name === 'bulletList') {
|
|
24
|
+
return `- ${serializeChildrenToHTMLString(children).trim()}\n`
|
|
25
|
+
}
|
|
26
|
+
if (parent?.type.name === 'orderedList') {
|
|
27
|
+
let number = parent.attrs.start || 1
|
|
28
|
+
|
|
29
|
+
parent.forEach((parentChild, _offset, index) => {
|
|
30
|
+
if (node === parentChild) {
|
|
31
|
+
number = index + 1
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return `${number}. ${serializeChildrenToHTMLString(children).trim()}\n`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return serializeChildrenToHTMLString(children)
|
|
39
|
+
},
|
|
40
|
+
paragraph({ children }) {
|
|
41
|
+
return `\n${serializeChildrenToHTMLString(children)}\n`
|
|
42
|
+
},
|
|
43
|
+
heading({ node, children }) {
|
|
44
|
+
const level = node.attrs.level as number
|
|
45
|
+
|
|
46
|
+
return `${new Array(level).fill('#').join('')} ${children}\n`
|
|
47
|
+
},
|
|
48
|
+
codeBlock({ node, children }) {
|
|
49
|
+
return `\n\`\`\`${node.attrs.language}\n${serializeChildrenToHTMLString(
|
|
50
|
+
children,
|
|
51
|
+
)}\n\`\`\`\n`
|
|
52
|
+
},
|
|
53
|
+
blockquote({ children }) {
|
|
54
|
+
return `\n${serializeChildrenToHTMLString(children)
|
|
55
|
+
.trim()
|
|
56
|
+
.split('\n')
|
|
57
|
+
.map(a => `> ${a}`)
|
|
58
|
+
.join('\n')}`
|
|
59
|
+
},
|
|
60
|
+
image({ node }) {
|
|
61
|
+
return ``
|
|
62
|
+
},
|
|
63
|
+
hardBreak() {
|
|
64
|
+
return '\n'
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
markMapping: {
|
|
68
|
+
bold({ children }) {
|
|
69
|
+
return `**${serializeChildrenToHTMLString(children)}**`
|
|
70
|
+
},
|
|
71
|
+
italic({ children, node }) {
|
|
72
|
+
let isBoldToo = false
|
|
73
|
+
|
|
74
|
+
// Check if the node being wrapped also has a bold mark, if so, we need to use the bold markdown syntax
|
|
75
|
+
if (node?.marks.some(m => m.type.name === 'bold')) {
|
|
76
|
+
isBoldToo = true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isBoldToo) {
|
|
80
|
+
// If the content is bold, just wrap the bold content in italic markdown syntax with another set of asterisks
|
|
81
|
+
return `*${serializeChildrenToHTMLString(children)}*`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return `_${serializeChildrenToHTMLString(children)}_`
|
|
85
|
+
},
|
|
86
|
+
code({ children }) {
|
|
87
|
+
return `\`${serializeChildrenToHTMLString(children)}\``
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.log(
|
|
95
|
+
renderToMarkdown({
|
|
96
|
+
content: {
|
|
97
|
+
type: 'doc',
|
|
98
|
+
from: 0,
|
|
99
|
+
to: 574,
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: 'heading',
|
|
103
|
+
from: 0,
|
|
104
|
+
to: 11,
|
|
105
|
+
attrs: {
|
|
106
|
+
level: 2,
|
|
107
|
+
},
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
from: 1,
|
|
112
|
+
to: 10,
|
|
113
|
+
text: 'Hi there,',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: 'paragraph',
|
|
119
|
+
from: 11,
|
|
120
|
+
to: 169,
|
|
121
|
+
content: [
|
|
122
|
+
{
|
|
123
|
+
type: 'text',
|
|
124
|
+
from: 12,
|
|
125
|
+
to: 22,
|
|
126
|
+
text: 'this is a ',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'text',
|
|
130
|
+
from: 22,
|
|
131
|
+
to: 27,
|
|
132
|
+
marks: [
|
|
133
|
+
{
|
|
134
|
+
type: 'italic',
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
text: 'basic',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'text',
|
|
141
|
+
from: 27,
|
|
142
|
+
to: 39,
|
|
143
|
+
text: ' example of ',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'text',
|
|
147
|
+
from: 39,
|
|
148
|
+
to: 45,
|
|
149
|
+
marks: [
|
|
150
|
+
{
|
|
151
|
+
type: 'bold',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'italic',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
text: 'Tiptap',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
type: 'text',
|
|
161
|
+
from: 45,
|
|
162
|
+
to: 168,
|
|
163
|
+
text: '. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:',
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'bulletList',
|
|
169
|
+
from: 169,
|
|
170
|
+
to: 230,
|
|
171
|
+
content: [
|
|
172
|
+
{
|
|
173
|
+
type: 'listItem',
|
|
174
|
+
from: 170,
|
|
175
|
+
to: 205,
|
|
176
|
+
attrs: {
|
|
177
|
+
color: '',
|
|
178
|
+
},
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: 'paragraph',
|
|
182
|
+
from: 171,
|
|
183
|
+
to: 204,
|
|
184
|
+
content: [
|
|
185
|
+
{
|
|
186
|
+
type: 'text',
|
|
187
|
+
from: 172,
|
|
188
|
+
to: 203,
|
|
189
|
+
text: 'That’s a bullet list with one …',
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: 'listItem',
|
|
197
|
+
from: 205,
|
|
198
|
+
to: 229,
|
|
199
|
+
attrs: {
|
|
200
|
+
color: '',
|
|
201
|
+
},
|
|
202
|
+
content: [
|
|
203
|
+
{
|
|
204
|
+
type: 'paragraph',
|
|
205
|
+
from: 206,
|
|
206
|
+
to: 228,
|
|
207
|
+
content: [
|
|
208
|
+
{
|
|
209
|
+
type: 'text',
|
|
210
|
+
from: 207,
|
|
211
|
+
to: 227,
|
|
212
|
+
text: '… or two list items.',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
type: 'paragraph',
|
|
222
|
+
from: 230,
|
|
223
|
+
to: 326,
|
|
224
|
+
content: [
|
|
225
|
+
{
|
|
226
|
+
type: 'text',
|
|
227
|
+
from: 231,
|
|
228
|
+
to: 325,
|
|
229
|
+
text: 'Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
type: 'codeBlock',
|
|
235
|
+
from: 326,
|
|
236
|
+
to: 353,
|
|
237
|
+
attrs: {
|
|
238
|
+
language: 'css',
|
|
239
|
+
},
|
|
240
|
+
content: [
|
|
241
|
+
{
|
|
242
|
+
type: 'text',
|
|
243
|
+
from: 327,
|
|
244
|
+
to: 352,
|
|
245
|
+
text: 'body {\n display: none;\n}',
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
type: 'paragraph',
|
|
251
|
+
from: 353,
|
|
252
|
+
to: 522,
|
|
253
|
+
content: [
|
|
254
|
+
{
|
|
255
|
+
type: 'text',
|
|
256
|
+
from: 354,
|
|
257
|
+
to: 521,
|
|
258
|
+
text: 'I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.',
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
type: 'blockquote',
|
|
264
|
+
from: 522,
|
|
265
|
+
to: 572,
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: 'paragraph',
|
|
269
|
+
from: 523,
|
|
270
|
+
to: 571,
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: 'text',
|
|
274
|
+
from: 524,
|
|
275
|
+
to: 564,
|
|
276
|
+
text: 'Wow, that’s amazing. Good work, boy! 👏 ',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
type: 'hardBreak',
|
|
280
|
+
from: 564,
|
|
281
|
+
to: 565,
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
type: 'text',
|
|
285
|
+
from: 565,
|
|
286
|
+
to: 570,
|
|
287
|
+
text: '— Mom',
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
}),
|
|
296
|
+
)
|