@tiptap/core 2.5.0-beta.4 → 2.5.0-beta.5

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/core",
3
3
  "description": "headless rich text editor",
4
- "version": "2.5.0-beta.4",
4
+ "version": "2.5.0-beta.5",
5
5
  "homepage": "https://tiptap.dev",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -32,7 +32,7 @@
32
32
  "dist"
33
33
  ],
34
34
  "devDependencies": {
35
- "@tiptap/pm": "^2.5.0-beta.4"
35
+ "@tiptap/pm": "^2.5.0-beta.5"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@tiptap/pm": "^2.0.0"
@@ -84,11 +84,6 @@ export const insertContentAt: RawCommands['insertContentAt'] = (position, value,
84
84
  return false
85
85
  }
86
86
 
87
- // don’t dispatch an empty fragment because this can lead to strange errors
88
- if (content.toString() === '<>') {
89
- return true
90
- }
91
-
92
87
  let { from, to } = typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to }
93
88
 
94
89
  let isOnlyTextContent = true
@@ -1,4 +1,4 @@
1
- import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'
1
+ import { ParseOptions } from '@tiptap/pm/model'
2
2
 
3
3
  import { createDocument } from '../helpers/createDocument.js'
4
4
  import { Content, RawCommands } from '../types.js'
@@ -44,22 +44,34 @@ declare module '@tiptap/core' {
44
44
  }
45
45
  }
46
46
 
47
- export const setContent: RawCommands['setContent'] = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ tr, editor, dispatch }) => {
47
+ export const setContent: RawCommands['setContent'] = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({
48
+ editor, tr, dispatch, commands,
49
+ }) => {
48
50
  const { doc } = tr
49
51
 
50
- let document: Fragment | ProseMirrorNode
51
-
52
- try {
53
- document = createDocument(content, editor.schema, parseOptions, {
52
+ // This is to keep backward compatibility with the previous behavior
53
+ // TODO remove this in the next major version
54
+ if (parseOptions.preserveWhitespace !== 'full') {
55
+ const document = createDocument(content, editor.schema, parseOptions, {
54
56
  errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
55
57
  })
56
- } catch (e) {
57
- return false
58
+
59
+ if (dispatch) {
60
+ tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate)
61
+ }
62
+ return true
58
63
  }
59
64
 
60
65
  if (dispatch) {
61
- tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate)
66
+ tr.setMeta('preventUpdate', !emitUpdate)
62
67
  }
63
68
 
64
- return true
69
+ return commands.insertContentAt(
70
+ { from: 0, to: doc.content.size },
71
+ content,
72
+ {
73
+ parseOptions,
74
+ errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
75
+ },
76
+ )
65
77
  }
@@ -1,7 +1,4 @@
1
- import {
2
- Mark, MarkType, Node, NodeType,
3
- } from '@tiptap/pm/model'
4
- import { SelectionRange } from '@tiptap/pm/state'
1
+ import { MarkType, NodeType } from '@tiptap/pm/model'
5
2
 
6
3
  import { getMarkType } from '../helpers/getMarkType.js'
7
4
  import { getNodeType } from '../helpers/getNodeType.js'
@@ -54,49 +51,37 @@ export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, at
54
51
  }
55
52
 
56
53
  if (dispatch) {
57
- let lastPos: number | undefined
58
- let lastNode: Node | undefined
59
- let trimmedFrom: number
60
- let trimmedTo: number
61
-
62
- tr.selection.ranges.forEach((range: SelectionRange) => {
54
+ tr.selection.ranges.forEach(range => {
63
55
  const from = range.$from.pos
64
56
  const to = range.$to.pos
65
57
 
66
- state.doc.nodesBetween(from, to, (node: Node, pos: number) => {
58
+ state.doc.nodesBetween(from, to, (node, pos) => {
67
59
  if (nodeType && nodeType === node.type) {
68
- trimmedFrom = Math.max(pos, from)
69
- trimmedTo = Math.min(pos + node.nodeSize, to)
70
- lastPos = pos
71
- lastNode = node
60
+ tr.setNodeMarkup(pos, undefined, {
61
+ ...node.attrs,
62
+ ...attributes,
63
+ })
72
64
  }
73
- })
74
- })
75
-
76
- if (lastNode) {
77
65
 
78
- if (lastPos !== undefined) {
79
- tr.setNodeMarkup(lastPos, undefined, {
80
- ...lastNode.attrs,
81
- ...attributes,
82
- })
83
- }
66
+ if (markType && node.marks.length) {
67
+ node.marks.forEach(mark => {
68
+ if (markType === mark.type) {
69
+ const trimmedFrom = Math.max(pos, from)
70
+ const trimmedTo = Math.min(pos + node.nodeSize, to)
84
71
 
85
- if (markType && lastNode.marks.length) {
86
- lastNode.marks.forEach((mark: Mark) => {
87
- if (markType === mark.type) {
88
- tr.addMark(
89
- trimmedFrom,
90
- trimmedTo,
91
- markType.create({
92
- ...mark.attrs,
93
- ...attributes,
94
- }),
95
- )
96
- }
97
- })
98
- }
99
- }
72
+ tr.addMark(
73
+ trimmedFrom,
74
+ trimmedTo,
75
+ markType.create({
76
+ ...mark.attrs,
77
+ ...attributes,
78
+ }),
79
+ )
80
+ }
81
+ })
82
+ }
83
+ })
84
+ })
100
85
  }
101
86
 
102
87
  return true
@@ -60,6 +60,7 @@ export function createNodeFromContent(
60
60
  if (isTextContent) {
61
61
  let schemaToUse = schema
62
62
  let hasInvalidContent = false
63
+ let invalidContent = ''
63
64
 
64
65
  // Only ever check for invalid content if we're supposed to throw an error
65
66
  if (options.errorOnInvalidContent) {
@@ -75,9 +76,11 @@ export function createNodeFromContent(
75
76
  parseDOM: [
76
77
  {
77
78
  tag: '*',
78
- getAttrs: () => {
79
+ getAttrs: e => {
79
80
  // If this is ever called, we know that the content has something that we don't know how to handle in the schema
80
81
  hasInvalidContent = true
82
+ // Try to stringify the element for a more helpful error message
83
+ invalidContent = typeof e === 'string' ? e : e.outerHTML
81
84
  return null
82
85
  },
83
86
  },
@@ -94,7 +97,7 @@ export function createNodeFromContent(
94
97
  : parser.parse(elementFromString(content), options.parseOptions)
95
98
 
96
99
  if (options.errorOnInvalidContent && hasInvalidContent) {
97
- throw new Error('[tiptap error]: Invalid HTML content')
100
+ throw new Error('[tiptap error]: Invalid HTML content', { cause: new Error(`Invalid element found: ${invalidContent}`) })
98
101
  }
99
102
 
100
103
  return response