/** * Image Extension - Handle image display and paste */ import Image from '@tiptap/extension-image'; import { Plugin, PluginKey } from '@tiptap/pm/state'; import { MessageContentType } from '../../../../types/messageInput'; export function createImageExtension() { return Image.extend({ addOptions() { return { ...this.parent?.(), HTMLAttributes: { 'data-type': MessageContentType.IMAGE, }, }; }, addAttributes() { return { ...this.parent?.(), 'class': { default: 'message-image', parseHTML: (element) => { const type = element.getAttribute('data-type') || MessageContentType.IMAGE; return `message-${type}`; }, renderHTML: (attributes) => { const type = attributes['data-type'] || MessageContentType.IMAGE; return type ? { class: `message-${type}` } : {}; }, }, 'fileData': { default: null, parseHTML: element => element.getAttribute('file-data'), renderHTML: attributes => (attributes.fileData ? { 'file-data': attributes.fileData } : {}), }, 'data-type': { default: null, parseHTML: element => element.getAttribute('data-type'), renderHTML: attributes => (attributes['data-type'] ? { 'data-type': attributes['data-type'] } : {}), }, }; }, addProseMirrorPlugins() { return [ new Plugin({ key: new PluginKey('imagePaste'), props: { handlePaste: (view, event) => { const items = Array.from(event.clipboardData?.items || []); const images = items.filter(item => item.type.indexOf('image') === 0); if (images.length === 0) { return false; // Let default handler process } images.forEach((item) => { const file = item.getAsFile(); if (file) { const reader = new FileReader(); reader.onload = (readerEvent) => { const dataUrl = readerEvent.target?.result as string; const node = view.state.schema.nodes.image.create({ src: dataUrl, fileData: file, }); const transaction = view.state.tr.replaceSelectionWith(node); view.dispatch(transaction); }; reader.onerror = (error) => { console.error('[MessageInput]::Failed to read image file:', error); }; reader.onabort = () => { console.warn('[MessageInput]::Image file reading was aborted.'); }; reader.readAsDataURL(file); } }); return true; // Prevent default paste behavior }, }, }), ]; }, }).configure({ inline: true, }); }