import Document from '@tiptap/extension-document'; import Hystory from '@tiptap/extension-history'; import TextAlign from '@tiptap/extension-text-align'; import Gapcursor from '@tiptap/extension-gapcursor'; import Paragraph from '@tiptap/extension-paragraph'; import BulletList from '@tiptap/extension-bullet-list'; import OrderedList from '@tiptap/extension-ordered-list'; import ListItem from '@tiptap/extension-list-item'; import Text from '@tiptap/extension-text'; import Highlight from '@tiptap/extension-highlight'; import Underline from '@tiptap/extension-underline'; import Bold from '@tiptap/extension-bold'; import Italic from '@tiptap/extension-italic'; import Strike from '@tiptap/extension-strike'; import Mention from '@tiptap/extension-mention'; import Typography from '@tiptap/extension-typography'; import Heading from '@tiptap/extension-heading'; import { Editor, type EditorOptions, type JSONContent, type Extensions } from '@tiptap/core'; import { DocumentWithHeader, Title, Header, HeaderColumn } from './nodes'; import { createSuggestionMenu, type TagSchema } from './tags'; export function createEditor({ editorElement, content, tags, buttons, attributes, onChange }: { editorElement: Element; content?: JSONContent; tags: TagSchema[]; buttons: string[]; onChange(change: { editor: Editor }): void; attributes?: Record; }): Editor { const options = getEditorOptions( editorElement, tags, buttons, content, attributes ); const editor = new Editor(options); editor.on('transaction', onChange); return editor; } function getEditorOptions( element: Element, tags: TagSchema[], actions: string[], content?: JSONContent, attributes?: Record ): Partial { const extensions: Extensions = []; for (const action of actions) { switch (action) { case 'bold': extensions.push(Bold); break; case 'italic': extensions.push(Italic); break; case 'underline': extensions.push(Underline); break; case 'strike': extensions.push(Strike); break; case 'highlight': extensions.push(Highlight); break; case 'bulletList': extensions.push(BulletList); break; case 'orderedList': extensions.push(OrderedList); break; case 'title': extensions.push(Header, HeaderColumn, Title); break; } } if (actions.includes('bulletList') || actions.includes('orderedList')) { extensions.push(ListItem); } if (actions.includes('heading2') || actions.includes('heading3')) { extensions.push(Heading.configure({ levels: [2, 3] })); } if ( actions.includes('left') || actions.includes('center') || actions.includes('right') || actions.includes('justify') ) { extensions.push( TextAlign.configure({ types: actions.includes('title') ? ['headerColumn', 'title', 'heading', 'paragraph'] : ['heading', 'paragraph'] }) ); } if (tags.length > 0) { extensions.push( Mention.configure({ renderLabel({ node }) { return node.attrs.label; }, HTMLAttributes: { class: 'fr-tag fr-tag--sm' }, suggestion: createSuggestionMenu(tags, element) }) ); } return { element, content, editorProps: { attributes }, extensions: [ actions.includes('title') ? DocumentWithHeader : Document, Hystory, Typography, Gapcursor, Paragraph, Text, ...extensions ] }; }