I am working on a feature that dynamically adjusts the row heights in proseMirror-tables base plugin, triggered during user interactions such as dragging to resize rows. However, I’ve encountered an issue where direct DOM manipulations to adjust the tr
height attributes seem to be immediately overwritten by ProseMirror’s rendering cycle.
The function triggers during a drag-to-resize action by the user. This function is inspired by another function for adjusting column widths, named updateColumnsOnResize
.Here’s how I have set it up:
function updateRowsOnResize(
node: Node, table: HTMLTableElement, cellMinHeight: number,
overrideRow?: number, overrideValue?: number
): void {
let totalHeight = 0;
const rows = table.rows;
const calculatedHeights: number[] = [];
for (let row = 0; row < node.childCount; row++) {
const rowNode = node.child(row);
const rowHeight = overrideRow === row ? overrideValue : rowNode.attrs.rowheight || cellMinHeight;
calculatedHeights[row] = rowHeight;
}
calculatedHeights.forEach((height, index) => {
if (rows[index] && rows[index].style.height !== `${height}px`) {
rows[index].style.height = `${height}px`;
}
});
totalHeight = calculatedHeights.reduce((acc, cur) => acc + cur, 0);
table.style.height = "";
table.style.minHeight = `${totalHeight}px`;
}
The schema configuration for table_row
includes a custom attribute for row height:
table_row: {
content: "(table_cell | table_header)*",
attrs: {
rowheight: { default: 25 }, // Add rowheight here
},
tableRole: "row",
parseDOM: [
{
tag: "tr",
getAttrs: (dom) => ({
rowheight: dom.getAttribute("data-rowheight") || null,
}),
},
],
toDOM(node) {
return [
"tr",
{
"data-rowheight": node.attrs.rowheight || null,
style: height: ${node.attrs.rowheight}px,
},
0,
];
},
}
Here’s a brief overview of my current implementation:
- Direct DOM Manipulation Approach: I initially tried to directly adjust the DOM
tr
height attributes. This was directly manipulating the style of thetr
elements upon user action, but the changes were not persistent, likely being overwritten by ProseMirror’s internal state.
- ProseMirror Transaction Approach: Shifting to a more ProseMirror-centric approach, I used
tr.setNodeMarkup
to create transactions that adjust the row heights based on user interactions. This approach successfully updates the row heights and the overall table height but at a noticeable performance cost.
function updateRowsOnTransaction(view: EditorView, rowIndex: number, newHeight: number): void {
const tr = view.state.tr;
const pos = ...; // position calculation logic here
const rowNode = view.state.doc.nodeAt(pos);
tr.setNodeMarkup(pos, null, {
...rowNode.attrs,
rowheight: newHeight,
});
view.dispatch(tr);
}
This approach works, but it seems to be performance-heavy.
I initially tried a more straightforward method by directly modifying the DOM properties to reduce the computational overhead. However, this method does not seem to work as expected.
Originally, I considered direct DOM manipulation to reduce computational overhead, as I did with columns, which was successful(prosemirror-tables’s code):
/**
* @public
*/
export function updateColumnsOnResize(
node: Node,
colgroup: HTMLTableColElement,
table: HTMLTableElement,
cellMinWidth: number,
overrideCol?: number,
overrideValue?: number
): void {
let totalWidth = 0;
let fixedWidth = true;
let nextDOM = colgroup.firstChild as HTMLElement;
const row = node.firstChild;
if (!row) return;
for (let i = 0, col = 0; i < row.childCount; i++) {
const { colspan, colwidth } = row.child(i).attrs as CellAttrs;
for (let j = 0; j < colspan; j++, col++) {
const hasWidth =
overrideCol == col ? overrideValue : colwidth && colwidth[j];
const cssWidth = hasWidth ? hasWidth + "px" : "";
totalWidth += hasWidth || cellMinWidth;
if (!hasWidth) fixedWidth = false;
if (!nextDOM) {
colgroup.appendChild(document.createElement("col")).style.width =
cssWidth;
} else {
if (nextDOM.style.width != cssWidth) nextDOM.style.width = cssWidth;
nextDOM = nextDOM.nextSibling as HTMLElement;
}
}
}
while (nextDOM) {
const after = nextDOM.nextSibling;
nextDOM.parentNode?.removeChild(nextDOM);
nextDOM = after as HTMLElement;
}
if (fixedWidth) {
table.style.width = totalWidth + "px";
table.style.minWidth = "";
} else {
table.style.width = "";
table.style.minWidth = totalWidth + "px";
}
}
Can anyone suggest a more efficient or proper way to handle dynamic row height adjustments in ProseMirror tables?