import { type Editor, Extension } from '@tiptap/core'; import { Plugin, PluginKey } from '@tiptap/pm/state'; import type { FileError, FileValidationOptions } from '../../utils'; import { filterFiles } from '../../utils'; type FileHandlePluginOptions = { key?: PluginKey; editor: Editor; onPaste?: (editor: Editor, files: File[], pasteContent?: string) => void; onDrop?: (editor: Editor, files: File[], pos: number) => void; onValidationError?: (errors: FileError[]) => void; } & FileValidationOptions; const FileHandlePlugin = (options: FileHandlePluginOptions) => { const { key, editor, onPaste, onDrop, onValidationError, allowedMimeTypes, maxFileSize } = options; return new Plugin({ key: key || new PluginKey('fileHandler'), props: { handleDrop(view, event) { event.preventDefault(); event.stopPropagation(); const { dataTransfer } = event; if (!dataTransfer?.files.length) { return; } const pos = view.posAtCoords({ left: event.clientX, top: event.clientY, }); const [validFiles, errors] = filterFiles(Array.from(dataTransfer.files), { allowedMimeTypes, maxFileSize, allowBase64: options.allowBase64, }); if (errors.length > 0 && onValidationError) { onValidationError(errors); } if (validFiles.length > 0 && onDrop) { onDrop(editor, validFiles, pos?.pos ?? 0); } }, handlePaste(_, event) { event.preventDefault(); event.stopPropagation(); const { clipboardData } = event; if (!clipboardData?.files.length) { return; } const [validFiles, errors] = filterFiles(Array.from(clipboardData.files), { allowedMimeTypes, maxFileSize, allowBase64: options.allowBase64, }); const html = clipboardData.getData('text/html'); if (errors.length > 0 && onValidationError) { onValidationError(errors); } if (validFiles.length > 0 && onPaste) { onPaste(editor, validFiles, html); } }, }, }); }; export const FileHandler = Extension.create>({ name: 'fileHandler', addOptions() { return { allowBase64: false, allowedMimeTypes: [], maxFileSize: 0, }; }, addProseMirrorPlugins() { return [ FileHandlePlugin({ key: new PluginKey(this.name), editor: this.editor, ...this.options, }), ]; }, });