@tiptap/core 3.1.0 → 3.2.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/core",
3
3
  "description": "headless rich text editor",
4
- "version": "3.1.0",
4
+ "version": "3.2.1",
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.1.0"
55
+ "@tiptap/pm": "^3.2.1"
56
56
  },
57
57
  "peerDependencies": {
58
- "@tiptap/pm": "^3.1.0"
58
+ "@tiptap/pm": "^3.2.1"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
package/src/Editor.ts CHANGED
@@ -182,7 +182,20 @@ export class Editor extends EventEmitter<EditorEvents> {
182
182
  }
183
183
  this.editorView = null
184
184
  this.isInitialized = false
185
- this.css?.remove()
185
+
186
+ // Safely remove CSS element with fallback for test environments
187
+ if (this.css) {
188
+ try {
189
+ if (typeof this.css.remove === 'function') {
190
+ this.css.remove()
191
+ } else if (this.css.parentNode) {
192
+ this.css.parentNode.removeChild(this.css)
193
+ }
194
+ } catch (error) {
195
+ // Silently handle any unexpected DOM removal errors in test environments
196
+ console.warn('Failed to remove CSS element:', error)
197
+ }
198
+ }
186
199
  this.css = null
187
200
  }
188
201
 
package/src/NodeView.ts CHANGED
@@ -100,7 +100,47 @@ export class NodeView<
100
100
 
101
101
  const clonedNode = this.dom.cloneNode(true) as HTMLElement
102
102
 
103
- event.dataTransfer?.setDragImage(clonedNode, x, y)
103
+ // Preserve the visual size of the original when using the clone as
104
+ // the drag image.
105
+ try {
106
+ const domBox = this.dom.getBoundingClientRect()
107
+ clonedNode.style.width = `${Math.round(domBox.width)}px`
108
+ clonedNode.style.height = `${Math.round(domBox.height)}px`
109
+ clonedNode.style.boxSizing = 'border-box'
110
+ // Ensure the clone doesn't capture pointer events while offscreen
111
+ clonedNode.style.pointerEvents = 'none'
112
+ } catch {
113
+ // ignore measurement errors (e.g. if element not in DOM)
114
+ }
115
+
116
+ // Some browsers (notably Safari) require the element passed to
117
+ // setDragImage to be present in the DOM. Using a detached node can
118
+ // cause the drag to immediately end.
119
+ let dragImageWrapper: HTMLElement | null = null
120
+
121
+ try {
122
+ dragImageWrapper = document.createElement('div')
123
+ dragImageWrapper.style.position = 'absolute'
124
+ dragImageWrapper.style.top = '-9999px'
125
+ dragImageWrapper.style.left = '-9999px'
126
+ dragImageWrapper.style.pointerEvents = 'none'
127
+ dragImageWrapper.appendChild(clonedNode)
128
+ document.body.appendChild(dragImageWrapper)
129
+
130
+ event.dataTransfer?.setDragImage(clonedNode, x, y)
131
+ } finally {
132
+ // Remove the wrapper on the next tick so the browser can use the
133
+ // element as the drag image. A 0ms timeout is enough in practice.
134
+ if (dragImageWrapper) {
135
+ setTimeout(() => {
136
+ try {
137
+ dragImageWrapper?.remove()
138
+ } catch {
139
+ // ignore removal errors
140
+ }
141
+ }, 0)
142
+ }
143
+ }
104
144
 
105
145
  const pos = this.getPos()
106
146