@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,306 @@
|
|
|
1
|
+
/* eslint-disable no-plusplus */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Node,
|
|
6
|
+
NodeViewContent,
|
|
7
|
+
ReactNodeViewContentProvider,
|
|
8
|
+
ReactNodeViewRenderer,
|
|
9
|
+
} from '@tiptap/react'
|
|
10
|
+
import StarterKit from '@tiptap/starter-kit'
|
|
11
|
+
import React from 'react'
|
|
12
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
13
|
+
|
|
14
|
+
import { renderToReactElement } from './react.jsx'
|
|
15
|
+
|
|
16
|
+
// This component does not have a NodeViewContent, so it does not render it's children's rich text content
|
|
17
|
+
function MyCustomComponentWithoutContent() {
|
|
18
|
+
const [count, setCount] = React.useState(200)
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className='custom-component-without-content' onClick={() => setCount(a => a + 1)}>
|
|
22
|
+
{count} This is a react component!
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// This component does have a NodeViewContent, so it will render it's children's rich text content
|
|
28
|
+
function MyCustomComponentWithContent() {
|
|
29
|
+
return (
|
|
30
|
+
<div className='custom-component-with-content'>
|
|
31
|
+
Custom component with content in React!
|
|
32
|
+
<NodeViewContent />
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* This example demonstrates how to render a Prosemirror Node (or JSON Content) to a React Element.
|
|
39
|
+
* It will use your extensions to render the content based on each Node's/Mark's `renderHTML` method.
|
|
40
|
+
* This can be useful if you want to render content to React without having an actual editor instance.
|
|
41
|
+
*
|
|
42
|
+
* You have complete control over the rendering process. And can replace how each Node/Mark is rendered.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
const CustomNodeExtensionWithContent = Node.create({
|
|
46
|
+
name: 'customNodeExtensionWithContent',
|
|
47
|
+
content: 'text*',
|
|
48
|
+
group: 'block',
|
|
49
|
+
renderHTML() {
|
|
50
|
+
return ['div', { class: 'my-custom-component-with-content' }, 0] as const
|
|
51
|
+
},
|
|
52
|
+
addNodeView() {
|
|
53
|
+
return ReactNodeViewRenderer(MyCustomComponentWithContent)
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const CustomNodeExtensionWithoutContent = Node.create({
|
|
58
|
+
name: 'customNodeExtensionWithoutContent',
|
|
59
|
+
atom: true,
|
|
60
|
+
renderHTML() {
|
|
61
|
+
return ['div', { class: 'my-custom-component-without-content' }] as const
|
|
62
|
+
},
|
|
63
|
+
addNodeView() {
|
|
64
|
+
return ReactNodeViewRenderer(MyCustomComponentWithoutContent)
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const Element = renderToReactElement({
|
|
69
|
+
extensions: [StarterKit, CustomNodeExtensionWithContent, CustomNodeExtensionWithoutContent],
|
|
70
|
+
options: {
|
|
71
|
+
nodeMapping: {
|
|
72
|
+
// You can replace the rendering of a node with a custom react component
|
|
73
|
+
heading({ node, children }) {
|
|
74
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
75
|
+
const [count, setCount] = React.useState(100)
|
|
76
|
+
|
|
77
|
+
return <h1 {...node.attrs} onClick={() => setCount(100)}>Can you use React hooks? {count}% {children}</h1>
|
|
78
|
+
},
|
|
79
|
+
// Node views are not supported in the static renderer, so you need to supply the custom component yourself
|
|
80
|
+
customNodeExtensionWithContent({ children }) {
|
|
81
|
+
return (
|
|
82
|
+
<ReactNodeViewContentProvider content={children}>
|
|
83
|
+
<MyCustomComponentWithContent />
|
|
84
|
+
</ReactNodeViewContentProvider>
|
|
85
|
+
)
|
|
86
|
+
},
|
|
87
|
+
customNodeExtensionWithoutContent() {
|
|
88
|
+
return <MyCustomComponentWithoutContent />
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
markMapping: {},
|
|
92
|
+
},
|
|
93
|
+
content: {
|
|
94
|
+
type: 'doc',
|
|
95
|
+
from: 0,
|
|
96
|
+
to: 574,
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: 'heading',
|
|
100
|
+
from: 0,
|
|
101
|
+
to: 11,
|
|
102
|
+
attrs: {
|
|
103
|
+
level: 2,
|
|
104
|
+
},
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: 'text',
|
|
108
|
+
from: 1,
|
|
109
|
+
to: 10,
|
|
110
|
+
text: 'Hi there,',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
// This is a custom node extension with content
|
|
115
|
+
{
|
|
116
|
+
type: 'customNodeExtensionWithContent',
|
|
117
|
+
content: [
|
|
118
|
+
{
|
|
119
|
+
type: 'text',
|
|
120
|
+
text: 'MY CUSTOM COMPONENT CONTENT!!!',
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
// This is a custom node extension without content
|
|
125
|
+
{
|
|
126
|
+
type: 'customNodeExtensionWithoutContent',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'paragraph',
|
|
130
|
+
from: 11,
|
|
131
|
+
to: 169,
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: 'text',
|
|
135
|
+
from: 12,
|
|
136
|
+
to: 22,
|
|
137
|
+
text: 'this is a ',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
type: 'text',
|
|
141
|
+
from: 22,
|
|
142
|
+
to: 27,
|
|
143
|
+
marks: [
|
|
144
|
+
{
|
|
145
|
+
type: 'italic',
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
text: 'basic',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
type: 'text',
|
|
152
|
+
from: 27,
|
|
153
|
+
to: 39,
|
|
154
|
+
text: ' example of ',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
type: 'text',
|
|
158
|
+
from: 39,
|
|
159
|
+
to: 45,
|
|
160
|
+
marks: [
|
|
161
|
+
{
|
|
162
|
+
type: 'bold',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
text: 'Tiptap',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'text',
|
|
169
|
+
from: 45,
|
|
170
|
+
to: 168,
|
|
171
|
+
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:',
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
type: 'bulletList',
|
|
177
|
+
from: 169,
|
|
178
|
+
to: 230,
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: 'listItem',
|
|
182
|
+
from: 170,
|
|
183
|
+
to: 205,
|
|
184
|
+
attrs: {
|
|
185
|
+
color: '',
|
|
186
|
+
},
|
|
187
|
+
content: [
|
|
188
|
+
{
|
|
189
|
+
type: 'paragraph',
|
|
190
|
+
from: 171,
|
|
191
|
+
to: 204,
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: 'text',
|
|
195
|
+
from: 172,
|
|
196
|
+
to: 203,
|
|
197
|
+
text: 'That’s a bullet list with one …',
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: 'listItem',
|
|
205
|
+
from: 205,
|
|
206
|
+
to: 229,
|
|
207
|
+
attrs: {
|
|
208
|
+
color: '',
|
|
209
|
+
},
|
|
210
|
+
content: [
|
|
211
|
+
{
|
|
212
|
+
type: 'paragraph',
|
|
213
|
+
from: 206,
|
|
214
|
+
to: 228,
|
|
215
|
+
content: [
|
|
216
|
+
{
|
|
217
|
+
type: 'text',
|
|
218
|
+
from: 207,
|
|
219
|
+
to: 227,
|
|
220
|
+
text: '… or two list items.',
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: 'paragraph',
|
|
230
|
+
from: 230,
|
|
231
|
+
to: 326,
|
|
232
|
+
content: [
|
|
233
|
+
{
|
|
234
|
+
type: 'text',
|
|
235
|
+
from: 231,
|
|
236
|
+
to: 325,
|
|
237
|
+
text: 'Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:',
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
type: 'codeBlock',
|
|
243
|
+
from: 326,
|
|
244
|
+
to: 353,
|
|
245
|
+
attrs: {
|
|
246
|
+
language: 'css',
|
|
247
|
+
},
|
|
248
|
+
content: [
|
|
249
|
+
{
|
|
250
|
+
type: 'text',
|
|
251
|
+
from: 327,
|
|
252
|
+
to: 352,
|
|
253
|
+
text: 'body {\n display: none;\n}',
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
type: 'paragraph',
|
|
259
|
+
from: 353,
|
|
260
|
+
to: 522,
|
|
261
|
+
content: [
|
|
262
|
+
{
|
|
263
|
+
type: 'text',
|
|
264
|
+
from: 354,
|
|
265
|
+
to: 521,
|
|
266
|
+
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.',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
type: 'blockquote',
|
|
272
|
+
from: 522,
|
|
273
|
+
to: 572,
|
|
274
|
+
content: [
|
|
275
|
+
{
|
|
276
|
+
type: 'paragraph',
|
|
277
|
+
from: 523,
|
|
278
|
+
to: 571,
|
|
279
|
+
content: [
|
|
280
|
+
{
|
|
281
|
+
type: 'text',
|
|
282
|
+
from: 524,
|
|
283
|
+
to: 564,
|
|
284
|
+
text: 'Wow, that’s amazing. Good work, boy! 👏 ',
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
type: 'hardBreak',
|
|
288
|
+
from: 564,
|
|
289
|
+
to: 565,
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
type: 'text',
|
|
293
|
+
from: 565,
|
|
294
|
+
to: 570,
|
|
295
|
+
text: '— Mom',
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
// eslint-disable-next-line no-console
|
|
306
|
+
console.log(renderToStaticMarkup(Element))
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* eslint-disable no-plusplus, @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { Extensions, JSONContent } from '@tiptap/core'
|
|
3
|
+
import type { DOMOutputSpec, Mark, Node } from '@tiptap/pm/model'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
import { renderJSONContentToReactElement } from '../../json/react/react.js'
|
|
7
|
+
import { TiptapStaticRendererOptions } from '../../json/renderer.js'
|
|
8
|
+
import type { DOMOutputSpecArray } from '../../types.js'
|
|
9
|
+
import { renderToElement } from '../extensionRenderer.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This function maps the attributes of a node or mark to HTML attributes
|
|
13
|
+
* @param attrs The attributes to map
|
|
14
|
+
* @param key The key to use for the React element
|
|
15
|
+
* @returns The mapped HTML attributes as an object
|
|
16
|
+
*/
|
|
17
|
+
function mapAttrsToHTMLAttributes(attrs?: Record<string, any>, key?: string): Record<string, any> {
|
|
18
|
+
if (!attrs) {
|
|
19
|
+
return { key }
|
|
20
|
+
}
|
|
21
|
+
return Object.entries(attrs).reduce(
|
|
22
|
+
(acc, [name, value]) => {
|
|
23
|
+
if (name === 'class') {
|
|
24
|
+
return Object.assign(acc, { className: value })
|
|
25
|
+
}
|
|
26
|
+
return Object.assign(acc, { [name]: value })
|
|
27
|
+
},
|
|
28
|
+
{ key },
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Take a DOMOutputSpec and return a function that can render it to a React element
|
|
34
|
+
* @param content The DOMOutputSpec to convert to a React element
|
|
35
|
+
* @returns A function that can render the DOMOutputSpec to a React element
|
|
36
|
+
*/
|
|
37
|
+
export function domOutputSpecToReactElement(
|
|
38
|
+
content: DOMOutputSpec,
|
|
39
|
+
key = 0,
|
|
40
|
+
): (children?: React.ReactNode) => React.ReactNode {
|
|
41
|
+
if (typeof content === 'string') {
|
|
42
|
+
return () => content
|
|
43
|
+
}
|
|
44
|
+
if (typeof content === 'object' && 'length' in content) {
|
|
45
|
+
const [tag, attrs, children, ...rest] = content as DOMOutputSpecArray
|
|
46
|
+
|
|
47
|
+
if (attrs === undefined) {
|
|
48
|
+
return () => React.createElement(tag, mapAttrsToHTMLAttributes(undefined, key.toString()))
|
|
49
|
+
}
|
|
50
|
+
if (attrs === 0) {
|
|
51
|
+
return child => React.createElement(tag, mapAttrsToHTMLAttributes(undefined, key.toString()), child)
|
|
52
|
+
}
|
|
53
|
+
if (typeof attrs === 'object') {
|
|
54
|
+
if (Array.isArray(attrs)) {
|
|
55
|
+
if (children === undefined) {
|
|
56
|
+
return child => React.createElement(
|
|
57
|
+
tag,
|
|
58
|
+
mapAttrsToHTMLAttributes(undefined, key.toString()),
|
|
59
|
+
domOutputSpecToReactElement(attrs as DOMOutputSpecArray, key++)(child),
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
if (children === 0) {
|
|
63
|
+
return child => React.createElement(
|
|
64
|
+
tag,
|
|
65
|
+
mapAttrsToHTMLAttributes(undefined, key.toString()),
|
|
66
|
+
domOutputSpecToReactElement(attrs as DOMOutputSpecArray, key++)(child),
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
return child => React.createElement(
|
|
70
|
+
tag,
|
|
71
|
+
mapAttrsToHTMLAttributes(undefined, key.toString()),
|
|
72
|
+
domOutputSpecToReactElement(attrs as DOMOutputSpecArray)(child),
|
|
73
|
+
[children]
|
|
74
|
+
.concat(rest)
|
|
75
|
+
.map(outputSpec => domOutputSpecToReactElement(outputSpec, key++)(child)),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
if (children === undefined) {
|
|
79
|
+
return () => React.createElement(tag, mapAttrsToHTMLAttributes(attrs, key.toString()))
|
|
80
|
+
}
|
|
81
|
+
if (children === 0) {
|
|
82
|
+
return child => React.createElement(tag, mapAttrsToHTMLAttributes(attrs, key.toString()), child)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return child => React.createElement(
|
|
86
|
+
tag,
|
|
87
|
+
mapAttrsToHTMLAttributes(attrs, key.toString()),
|
|
88
|
+
[children]
|
|
89
|
+
.concat(rest)
|
|
90
|
+
.map(outputSpec => domOutputSpecToReactElement(outputSpec, key++)(child)),
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// TODO support DOM elements? How to handle them?
|
|
96
|
+
throw new Error(
|
|
97
|
+
'[tiptap error]: Unsupported DomOutputSpec type, check the `renderHTML` method output',
|
|
98
|
+
{
|
|
99
|
+
cause: content,
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* This function will statically render a Prosemirror Node to a React component using the given extensions
|
|
106
|
+
* @param content The content to render to a React component
|
|
107
|
+
* @param extensions The extensions to use for rendering
|
|
108
|
+
* @param options The options to use for rendering
|
|
109
|
+
* @returns The React element that represents the rendered content
|
|
110
|
+
*/
|
|
111
|
+
export function renderToReactElement({
|
|
112
|
+
content,
|
|
113
|
+
extensions,
|
|
114
|
+
options,
|
|
115
|
+
}: {
|
|
116
|
+
content: Node | JSONContent;
|
|
117
|
+
extensions: Extensions;
|
|
118
|
+
options?: Partial<TiptapStaticRendererOptions<React.ReactNode, Mark, Node>>;
|
|
119
|
+
}): React.ReactNode {
|
|
120
|
+
return renderToElement<React.ReactNode>({
|
|
121
|
+
renderer: renderJSONContentToReactElement,
|
|
122
|
+
domOutputSpecToElement: domOutputSpecToReactElement,
|
|
123
|
+
mapDefinedTypes: {
|
|
124
|
+
// Map a doc node to concatenated children
|
|
125
|
+
doc: ({ children }) => <>{children}</>,
|
|
126
|
+
// Map a text node to its text content
|
|
127
|
+
text: ({ node }) => node.text ?? '',
|
|
128
|
+
},
|
|
129
|
+
content,
|
|
130
|
+
extensions,
|
|
131
|
+
options,
|
|
132
|
+
})
|
|
133
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A mark type is either a JSON representation of a mark or a Prosemirror mark instance
|
|
5
|
+
*/
|
|
6
|
+
export type MarkType<
|
|
7
|
+
Type extends string = any,
|
|
8
|
+
Attributes extends undefined | Record<string, any> = any,
|
|
9
|
+
> = {
|
|
10
|
+
type: Type;
|
|
11
|
+
attrs: Attributes;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A node type is either a JSON representation of a node or a Prosemirror node instance
|
|
16
|
+
*/
|
|
17
|
+
export type NodeType<
|
|
18
|
+
Type extends string = any,
|
|
19
|
+
Attributes extends undefined | Record<string, any> = any,
|
|
20
|
+
NodeMarkType extends MarkType = any,
|
|
21
|
+
Content extends NodeType[] = any,
|
|
22
|
+
> = {
|
|
23
|
+
type: Type;
|
|
24
|
+
attrs: Attributes;
|
|
25
|
+
content?: Content;
|
|
26
|
+
marks?: NodeMarkType[];
|
|
27
|
+
text?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A node type is either a JSON representation of a doc node or a Prosemirror doc node instance
|
|
32
|
+
*/
|
|
33
|
+
export type DocumentType<
|
|
34
|
+
TNodeAttributes extends Record<string, any> = Record<string, any>,
|
|
35
|
+
TContentType extends NodeType[] = NodeType[],
|
|
36
|
+
> = NodeType<'doc', TNodeAttributes, never, TContentType>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A node type is either a JSON representation of a text node or a Prosemirror text node instance
|
|
40
|
+
*/
|
|
41
|
+
export type TextType<TMarkType extends MarkType = MarkType> = {
|
|
42
|
+
type: 'text';
|
|
43
|
+
text: string;
|
|
44
|
+
marks: TMarkType[];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Describes the output of a `renderHTML` function in prosemirror
|
|
49
|
+
* @see https://prosemirror.net/docs/ref/#model.DOMOutputSpec
|
|
50
|
+
*/
|
|
51
|
+
export type DOMOutputSpecArray =
|
|
52
|
+
| [string]
|
|
53
|
+
| [string, Record<string, any>]
|
|
54
|
+
| [string, 0]
|
|
55
|
+
| [string, Record<string, any>, 0]
|
|
56
|
+
| [string, Record<string, any>, DOMOutputSpecArray | 0]
|
|
57
|
+
| [string, DOMOutputSpecArray];
|