import { mergeAttributes, Node } from '@tiptap/core'; import { Plugin } from '@tiptap/pm/state'; import { Decoration, DecorationSet } from '@tiptap/pm/view'; import { getCellsInColumn, isRowSelected, selectRow } from './utils.js'; export interface TableCellOptions { HTMLAttributes: Record; } export const TableCell = Node.create({ name: 'tableCell', content: 'block+', tableRole: 'cell', isolating: true, addOptions() { return { HTMLAttributes: {} }; }, parseHTML() { return [{ tag: 'td' }]; }, renderHTML({ HTMLAttributes }) { return ['td', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, addAttributes() { return { colspan: { default: 1, parseHTML: (element) => { const colspan = element.getAttribute('colspan'); const value = colspan ? parseInt(colspan, 10) : 1; return value; } }, rowspan: { default: 1, parseHTML: (element) => { const rowspan = element.getAttribute('rowspan'); const value = rowspan ? parseInt(rowspan, 10) : 1; return value; } }, colwidth: { default: null, parseHTML: (element) => { const colwidth = element.getAttribute('colwidth'); const value = colwidth ? [parseInt(colwidth, 10)] : null; return value; } }, style: { default: null } }; }, addProseMirrorPlugins() { const { isEditable } = this.editor; return [ new Plugin({ props: { decorations: (state) => { if (!isEditable) { return DecorationSet.empty; } const { doc, selection } = state; const decorations: Decoration[] = []; const cells = getCellsInColumn(0)(selection); if (cells) { cells.forEach(({ pos }: { pos: number }, index: number) => { decorations.push( Decoration.widget(pos + 1, () => { const rowSelected = isRowSelected(index)(selection); let className = 'grip-row'; if (rowSelected) { className += ' selected'; } if (index === 0) { className += ' first'; } if (index === cells.length - 1) { className += ' last'; } const grip = document.createElement('a'); grip.className = className; grip.addEventListener('mousedown', (event) => { event.preventDefault(); event.stopImmediatePropagation(); this.editor.view.dispatch(selectRow(index)(this.editor.state.tr)); }); return grip; }) ); }); } return DecorationSet.create(doc, decorations); } } }) ]; } });