import '@tiptap/extension-text-style' import { Extension, Node } from '@tiptap/core' import Image from '@tiptap/extension-image' import { VueNodeViewRenderer } from '@tiptap/vue-3' import ImageResizeComponent from '../components/ImageResizeComponent.vue' import VideoPlayerComponent from '../components/VideoPlayerComponent.vue' declare module '@tiptap/core' { interface Commands { fontSize: { setFontSize: (size: string) => ReturnType unsetFontSize: () => ReturnType } } } export const FontSize = Extension.create({ name: 'fontSize', addOptions() { return { types: ['textStyle'], } }, addGlobalAttributes() { return [ { types: this.options.types, attributes: { fontSize: { default: null, parseHTML: element => element.style.fontSize.replace(/['"]+/g, ''), renderHTML: attributes => { if (!attributes.fontSize) { return {} } return { style: `font-size: ${attributes.fontSize}`, } }, }, }, }, ] }, addCommands() { return { setFontSize: fontSize => ({ chain }) => { return chain() .setMark('textStyle', { fontSize }) .run() }, unsetFontSize: () => ({ chain }) => { return chain() .setMark('textStyle', { fontSize: null }) .removeEmptyTextStyle() .run() }, } }, }) // ========== 自定义视频扩展 ========== export const CustomVideo = Node.create({ name: 'customVideo', group: 'block', atom: true, draggable: true, selectable: true, addAttributes() { return { src: { default: null }, width: { default: '100%' }, height: { default: 'auto' }, controls: { default: true }, } }, parseHTML() { return [ { tag: 'div[data-custom-video]', }, ] }, renderHTML({ HTMLAttributes }) { return ['div', { 'data-custom-video': '', ...HTMLAttributes }] }, addNodeView() { return VueNodeViewRenderer(VideoPlayerComponent) }, }) // ========== 自定义图片扩展(支持缩放) ========== export const ResizableImage = Image.extend({ name: 'resizableImage', addAttributes() { return { ...this.parent?.(), width: { default: null }, height: { default: null }, style: { default: null }, } }, addNodeView() { return VueNodeViewRenderer(ImageResizeComponent) }, })