import { Plugin } from 'prosemirror-state'; import { Node as PMNode } from 'prosemirror-model'; import { tableEditing, columnResizing, TableView } from 'prosemirror-tables'; import { tableStyles } from '../schema'; /** TableView that also puts the author's class/id and fidelity table styles on the inner ``. */ class HtmlAttrTableView extends TableView { constructor(node: PMNode, defaultCellMinWidth: number) { super(node, defaultCellMinWidth); this.applyHtmlAttrs(node); } private applyHtmlAttrs(node: PMNode): void { const htmlClass = node.attrs.htmlClass as string | null; const htmlId = node.attrs.htmlId as string | null; this.table.className = htmlClass ?? ''; if (htmlId) this.table.id = htmlId; else this.table.removeAttribute('id'); // Email-fidelity attrs (width, max-width, background, border, centring). // Width is only overridden when set, so column-resize sizing still applies. const style = this.table.style; // tableStyles() entries can hold several declarations ('color: x; font-family: y' // for the table text style or an allowedStyles extension), so flatten them first. const decls = tableStyles(node.attrs) .flatMap(entry => entry.split(';')) .map(decl => decl.trim()) .filter(decl => decl.includes(':')); for (const prop of [ 'max-width', 'background-color', 'border', 'margin-left', 'margin-right', 'color', 'font-family', 'font-size', 'font-weight', 'line-height', ]) { style.removeProperty(prop); } // Clear any per-app extension properties first so a value that changed (or an // entry that was removed) doesn't linger from the previous application. for (const decl of decls) style.removeProperty(decl.slice(0, decl.indexOf(':')).trim()); for (const decl of decls) { const idx = decl.indexOf(':'); style.setProperty(decl.slice(0, idx).trim(), decl.slice(idx + 1).trim()); } // A layout table with no width of its own (an email button) shrinks to fit // under email-fidelity; the host CSS keys off this hook. this.table.toggleAttribute('data-autowidth', Boolean(node.attrs.layout && !node.attrs.width)); // Lets the host CSS drop column resizing's min-width on layout tables. this.table.toggleAttribute('data-layout-table', Boolean(node.attrs.layout)); } update(node: PMNode): boolean { const updated = super.update(node); if (updated) this.applyHtmlAttrs(node); return updated; } } /** * prosemirror-tables wiring: cell selections, fix-tables normalization, and * draggable column resizing (widths persist as `data-colwidth`). The CSS * these plugins rely on (.selectedCell, .column-resize-handle, .resize-cursor) * is inlined in nile-wysiwyg-editor.css.ts. */ export function tablePlugins(): Plugin[] { return [ columnResizing({ View: HtmlAttrTableView }), tableEditing({ allowTableNodeSelection: true }), ]; }