@tiptap/core 3.19.0 → 3.20.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.19.0",
4
+ "version": "3.20.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.19.0"
55
+ "@tiptap/pm": "^3.20.1"
56
56
  },
57
57
  "peerDependencies": {
58
- "@tiptap/pm": "^3.19.0"
58
+ "@tiptap/pm": "^3.20.1"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
package/src/Editor.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import type { MarkType, Node as ProseMirrorNode, NodeType, Schema } from '@tiptap/pm/model'
3
3
  import type { Plugin, PluginKey, Transaction } from '@tiptap/pm/state'
4
4
  import { EditorState } from '@tiptap/pm/state'
5
- import { EditorView } from '@tiptap/pm/view'
5
+ import { type DirectEditorProps, EditorView } from '@tiptap/pm/view'
6
6
 
7
7
  import { CommandManager } from './CommandManager.js'
8
8
  import { EventEmitter } from './EventEmitter.js'
@@ -300,7 +300,7 @@ export class Editor extends EventEmitter<EditorEvents> {
300
300
  }
301
301
 
302
302
  /**
303
- * Returns the editor state.
303
+ * Returns the editor view.
304
304
  */
305
305
  public get view(): EditorView {
306
306
  if (this.editorView) {
@@ -523,11 +523,15 @@ export class Editor extends EventEmitter<EditorEvents> {
523
523
  // If a user provided a custom `dispatchTransaction` through `editorProps`,
524
524
  // we use that as the base dispatch function.
525
525
  // Otherwise, we use Tiptap's internal `dispatchTransaction` method.
526
- const baseDispatch = (editorProps as any).dispatchTransaction || this.dispatchTransaction.bind(this)
526
+ const baseDispatch = (editorProps as DirectEditorProps).dispatchTransaction || this.dispatchTransaction.bind(this)
527
527
  const dispatch = enableExtensionDispatchTransaction
528
528
  ? this.extensionManager.dispatchTransaction(baseDispatch)
529
529
  : baseDispatch
530
530
 
531
+ // Compose transformPastedHTML from extensions and user-provided editorProps
532
+ const baseTransformPastedHTML = (editorProps as DirectEditorProps).transformPastedHTML
533
+ const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML)
534
+
531
535
  this.editorView = new EditorView(element, {
532
536
  ...editorProps,
533
537
  attributes: {
@@ -536,6 +540,7 @@ export class Editor extends EventEmitter<EditorEvents> {
536
540
  ...editorProps?.attributes,
537
541
  },
538
542
  dispatchTransaction: dispatch,
543
+ transformPastedHTML,
539
544
  state: this.editorState,
540
545
  markViews: this.extensionManager.markViews,
541
546
  nodeViews: this.extensionManager.nodeViews,
package/src/Extendable.ts CHANGED
@@ -213,6 +213,30 @@ export interface ExtendableConfig<
213
213
  parent: ParentConfig<Config>['addProseMirrorPlugins']
214
214
  }) => Plugin[]
215
215
 
216
+ /**
217
+ * This function transforms pasted HTML content before it's parsed.
218
+ * Extensions can use this to modify or clean up pasted HTML.
219
+ * The transformations are chained - each extension's transform receives
220
+ * the output from the previous extension's transform.
221
+ * @see https://tiptap.dev/docs/editor/guide/custom-extensions#transform-pasted-html
222
+ * @example
223
+ * transformPastedHTML(html) {
224
+ * // Remove all style attributes
225
+ * return html.replace(/style="[^"]*"/g, '')
226
+ * }
227
+ */
228
+ transformPastedHTML?: (
229
+ this: {
230
+ name: string
231
+ options: Options
232
+ storage: Storage
233
+ editor: Editor
234
+ type: PMType
235
+ parent: ParentConfig<Config>['transformPastedHTML']
236
+ },
237
+ html: string,
238
+ ) => string
239
+
216
240
  /**
217
241
  * This function adds additional extensions to the editor. This is useful for
218
242
  * building extension kits.
@@ -1,7 +1,7 @@
1
1
  import { keymap } from '@tiptap/pm/keymap'
2
2
  import type { Schema } from '@tiptap/pm/model'
3
3
  import type { Plugin, Transaction } from '@tiptap/pm/state'
4
- import type { MarkViewConstructor, NodeViewConstructor } from '@tiptap/pm/view'
4
+ import type { EditorView, MarkViewConstructor, NodeViewConstructor } from '@tiptap/pm/view'
5
5
 
6
6
  import type { Editor } from './Editor.js'
7
7
  import {
@@ -277,6 +277,47 @@ export class ExtensionManager {
277
277
  }, baseDispatch)
278
278
  }
279
279
 
280
+ /**
281
+ * Get the composed transformPastedHTML function from all extensions.
282
+ * @param baseTransform The base transform function (e.g. from the editor props)
283
+ * @returns A composed transform function that chains all extension transforms
284
+ */
285
+ transformPastedHTML(
286
+ baseTransform?: (html: string, view?: any) => string,
287
+ ): (html: string, view?: EditorView) => string {
288
+ const { editor } = this
289
+ const extensions = sortExtensions([...this.extensions])
290
+
291
+ return extensions.reduce(
292
+ (transform, extension) => {
293
+ const context = {
294
+ name: extension.name,
295
+ options: extension.options,
296
+ storage: this.editor.extensionStorage[extension.name as keyof Storage],
297
+ editor,
298
+ type: getSchemaTypeByName(extension.name, this.schema),
299
+ }
300
+
301
+ const extensionTransform = getExtensionField<AnyConfig['transformPastedHTML']>(
302
+ extension,
303
+ 'transformPastedHTML',
304
+ context,
305
+ )
306
+
307
+ if (!extensionTransform) {
308
+ return transform
309
+ }
310
+
311
+ return (html: string, view?: any) => {
312
+ // Chain the transforms: pass the result of the previous transform to the next
313
+ const transformedHtml = transform(html, view)
314
+ return extensionTransform.call(context, transformedHtml)
315
+ }
316
+ },
317
+ baseTransform || ((html: string) => html),
318
+ )
319
+ }
320
+
280
321
  get markViews(): Record<string, MarkViewConstructor> {
281
322
  const { editor } = this
282
323
  const { markExtensions } = splitExtensions(this.extensions)