@tiptap/static-renderer 3.0.0-next.1 → 3.0.0-next.4

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.
Files changed (60) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +1 -1
  3. package/dist/index.cjs +573 -6
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +307 -32
  6. package/dist/index.d.ts +307 -32
  7. package/dist/index.js +552 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/json/html-string/index.cjs +16 -5
  10. package/dist/json/html-string/index.cjs.map +1 -1
  11. package/dist/json/html-string/index.d.cts +18 -22
  12. package/dist/json/html-string/index.d.ts +18 -22
  13. package/dist/json/html-string/index.js +10 -1
  14. package/dist/json/html-string/index.js.map +1 -1
  15. package/dist/json/react/index.cjs +12 -2201
  16. package/dist/json/react/index.cjs.map +1 -1
  17. package/dist/json/react/index.d.cts +5 -22
  18. package/dist/json/react/index.d.ts +5 -22
  19. package/dist/json/react/index.js +9 -2221
  20. package/dist/json/react/index.js.map +1 -1
  21. package/dist/json/renderer.cjs.map +1 -1
  22. package/dist/json/renderer.d.cts +5 -21
  23. package/dist/json/renderer.d.ts +5 -21
  24. package/dist/json/renderer.js.map +1 -1
  25. package/dist/pm/html-string/index.cjs +22 -37
  26. package/dist/pm/html-string/index.cjs.map +1 -1
  27. package/dist/pm/html-string/index.d.cts +7 -24
  28. package/dist/pm/html-string/index.d.ts +7 -24
  29. package/dist/pm/html-string/index.js +19 -34
  30. package/dist/pm/html-string/index.js.map +1 -1
  31. package/dist/pm/markdown/index.cjs +473 -0
  32. package/dist/pm/markdown/index.cjs.map +1 -0
  33. package/dist/pm/markdown/index.d.cts +153 -0
  34. package/dist/pm/markdown/index.d.ts +153 -0
  35. package/dist/pm/markdown/index.js +449 -0
  36. package/dist/pm/markdown/index.js.map +1 -0
  37. package/dist/pm/react/index.cjs +41 -2230
  38. package/dist/pm/react/index.cjs.map +1 -1
  39. package/dist/pm/react/index.d.cts +5 -23
  40. package/dist/pm/react/index.d.ts +5 -23
  41. package/dist/pm/react/index.js +47 -2259
  42. package/dist/pm/react/index.js.map +1 -1
  43. package/package.json +27 -8
  44. package/src/helpers.ts +5 -16
  45. package/src/index.ts +5 -1
  46. package/src/json/html-string/string.ts +39 -13
  47. package/src/json/react/react.tsx +12 -15
  48. package/src/json/renderer.ts +50 -51
  49. package/src/pm/extensionRenderer.ts +16 -34
  50. package/src/pm/html-string/html-string.ts +29 -45
  51. package/src/pm/markdown/index.ts +2 -0
  52. package/src/pm/markdown/markdown.ts +142 -0
  53. package/src/pm/react/react.tsx +49 -30
  54. package/src/helpers.example.ts +0 -35
  55. package/src/json/html-string/string.example.ts +0 -46
  56. package/src/json/react/react.example.ts +0 -45
  57. package/src/pm/html-string/html-string.example.ts +0 -225
  58. package/src/pm/markdown/markdown.example.ts +0 -296
  59. package/src/pm/react/react.example.tsx +0 -306
  60. package/src/types.ts +0 -57
@@ -1,296 +0,0 @@
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 `![${node.attrs.alt}](${node.attrs.src})`
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
- )
@@ -1,306 +0,0 @@
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))
package/src/types.ts DELETED
@@ -1,57 +0,0 @@
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];