Skip to content

Commit

Permalink
Merge pull request #3552 from udecode/fix/table-unmerge
Browse files Browse the repository at this point in the history
Fix unmerge, compute cell indices, delete row / column, add row / column
  • Loading branch information
zbeyens authored Sep 20, 2024
2 parents 1c19117 + 44544cd commit 2ab6b6b
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 164 deletions.
7 changes: 7 additions & 0 deletions .changeset/ninety-badgers-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@udecode/plate-table": patch
---

Fix unmerge & compute cell indices

Remove computeAllCellIndices, use computeCellIndices instead
92 changes: 26 additions & 66 deletions packages/table/src/lib/merge/computeCellIndices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,88 +12,48 @@ import { getRowSpan } from '../queries/getRowSpan';

export function computeCellIndices(
editor: SlateEditor,
tableEl: TTableElement,
cellEl: TTableCellElement
tableNode: TTableElement,
cellNode?: TTableCellElement
) {
const options = editor.getOptions(BaseTablePlugin);

const tableNodes = tableEl.children;
const skipCells: boolean[][] = [];
let targetIndices: { col: number; row: number } | undefined;

let rowIndex = -1;
let colIndex = -1;
for (let rowIndex = 0; rowIndex < tableNode.children.length; rowIndex++) {
const row = tableNode.children[rowIndex] as TTableRowElement;
let colIndex = 0;

for (let r = 0; r < tableNodes.length; r++) {
const row = tableNodes[r] as TTableRowElement;

let cIndex = 0;
for (const cellElement of row.children as TTableCellElement[]) {
while (skipCells[rowIndex]?.[colIndex]) {
colIndex++;
}

for (const item of row.children) {
const cell = item as TTableCellElement;
const currentIndices = { col: colIndex, row: rowIndex };
options._cellIndices?.set(cellElement, currentIndices);

if (cellEl === cell) {
colIndex = cIndex;
rowIndex = r;
if (cellElement === cellNode) {
targetIndices = currentIndices;

break;
}

cIndex += getColSpan(cell);
}
}

tableNodes.slice(0, rowIndex).forEach((pR, _rowIndex) => {
const prevRow = pR as TTableRowElement;
prevRow.children.forEach((pC) => {
const prevCell = pC as TTableCellElement;
const prevIndices = options?._cellIndices?.get(prevCell);
const _rowSpan = getRowSpan(prevCell);
const colSpan = getColSpan(cellElement);
const rowSpan = getRowSpan(cellElement);

if (prevIndices) {
const { col: prevColIndex } = prevIndices;
for (let r = 0; r < rowSpan; r++) {
skipCells[rowIndex + r] = skipCells[rowIndex + r] || [];

if (
// colIndex affects
prevColIndex <= colIndex &&
// rowSpan affects
_rowSpan &&
_rowSpan > 1 &&
rowIndex - _rowIndex < _rowSpan
) {
colIndex += getColSpan(prevCell);
for (let c = 0; c < colSpan; c++) {
skipCells[rowIndex + r][colIndex + c] = true;
}
}
});
});

if (rowIndex === -1 || colIndex === -1) {
return null;
}
colIndex += colSpan;
}

const indices = { col: colIndex, row: rowIndex };
options?._cellIndices?.set(cellEl, indices);
if (targetIndices) break;
}

return indices;
return targetIndices;
}

export const computeAllCellIndices = (
editor: SlateEditor,
tableNode: TTableElement
) => {
const options = editor.getOptions(BaseTablePlugin);

// Iterate through the table rows
for (const tableChild of tableNode.children) {
const row = tableChild as TTableRowElement;

// Iterate through the row cells
for (const rowChild of row.children) {
const cell = rowChild as TTableCellElement;

const indices = computeCellIndices(editor, tableNode, cell);

if (indices) {
options._cellIndices?.set(cell, indices);
}
}
}
};
14 changes: 9 additions & 5 deletions packages/table/src/lib/merge/insertTableColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
withoutNormalizing,
} from '@udecode/plate-common';
import { getEditorPlugin } from '@udecode/plate-common';
import cloneDeep from 'lodash/cloneDeep';
import { Path } from 'slate';

import type {
Expand Down Expand Up @@ -131,12 +132,15 @@ export const insertTableMergeColumn = (
const endCurI = curColIndex + curColSpan - 1;

if (endCurI >= nextColIndex && !firstCol) {
const colSpan = curColSpan + 1;
const newCell = cloneDeep({ ...curCell, colSpan });

if (newCell.attributes?.colspan) {
newCell.attributes.colspan = colSpan.toString();
}

// make wider
setNodes<TTableCellElement>(
editor,
{ ...curCell, colSpan: curColSpan + 1 },
{ at: currentCellPath }
);
setNodes<TTableCellElement>(editor, newCell, { at: currentCellPath });
} else {
// add new
const curRowPath = currentCellPath.slice(0, -1);
Expand Down
14 changes: 9 additions & 5 deletions packages/table/src/lib/merge/insertTableRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
setNodes,
withoutNormalizing,
} from '@udecode/plate-common';
import cloneDeep from 'lodash/cloneDeep';
import { Path } from 'slate';

import type {
Expand Down Expand Up @@ -134,12 +135,15 @@ export const insertTableMergeRow = (
const endCurI = curRowIndex + curRowSpan - 1;

if (endCurI >= nextRowIndex && !firstRow) {
const rowSpan = curRowSpan + 1;
const newCell = cloneDeep({ ...curCell, rowSpan });

if (newCell.attributes?.rowspan) {
newCell.attributes.rowspan = rowSpan.toString();
}

// make higher
setNodes<TTableCellElement>(
editor,
{ ...curCell, rowSpan: curRowSpan + 1 },
{ at: currentCellPath }
);
setNodes<TTableCellElement>(editor, newCell, { at: currentCellPath });
} else {
// add new
const row = getParentNode(editor, currentCellPath)!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { collapseSelection } from '@udecode/plate-common';
import { useEditorRef, useElement } from '@udecode/plate-common/react';

import { type TTableElement, computeAllCellIndices } from '../../../lib';
import { type TTableElement, computeCellIndices } from '../../../lib';
import { TablePlugin } from '../../TablePlugin';
import { useTableStore } from '../../stores';
import { useSelectedCells } from './useSelectedCells';
Expand Down Expand Up @@ -39,7 +39,7 @@ export const useTableElementState = ({

React.useEffect(() => {
if (enableMerging) {
computeAllCellIndices(editor, element);
computeCellIndices(editor, element);
}
}, [editor, element, enableMerging]);

Expand Down
13 changes: 8 additions & 5 deletions packages/table/src/react/merge/deleteColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
someNode,
withoutNormalizing,
} from '@udecode/plate-common';
import cloneDeep from 'lodash/cloneDeep';

import {
type TTableCellElement,
Expand Down Expand Up @@ -125,12 +126,14 @@ export const deleteTableMergeColumn = (editor: SlateEditor) => {
endingColIndex
);
const colsNumberAffected = curCellEndingColIndex - deletingColIndex + 1;
const colSpan = curColSpan - colsNumberAffected;
const newCell = cloneDeep({ ...curCell, colSpan });

setNodes<TTableCellElement>(
editor,
{ ...curCell, colSpan: curColSpan - colsNumberAffected },
{ at: curCellPath }
);
if (newCell.attributes?.colspan) {
newCell.attributes.colspan = colSpan.toString();
}

setNodes<TTableCellElement>(editor, newCell, { at: curCellPath });
});

const trEntry = getAboveNode(editor, {
Expand Down
65 changes: 45 additions & 20 deletions packages/table/src/react/merge/deleteRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
someNode,
} from '@udecode/plate-common';
import { findNodePath } from '@udecode/plate-common/react';
import cloneDeep from 'lodash/cloneDeep';

import {
type TTableCellElement,
Expand Down Expand Up @@ -110,12 +111,10 @@ export const deleteTableMergeRow = (editor: SlateEditor) => {
return;
}
if (nextRow) {
moveToNextRowCells.forEach((cur, index) => {
const curRowCell = cur as TTableCellElement;
const { col: curRowCellColIndex } = getCellIndices(
cellIndices!,
curRowCell
)!;
for (let index = 0; index < moveToNextRowCells.length; index++) {
const curRowCell = moveToNextRowCells[index] as TTableCellElement;
const { col: curRowCellColIndex, row: curRowCellRowIndex } =
getCellIndices(cellIndices!, curRowCell)!;
const curRowCellRowSpan = getRowSpan(curRowCell);

// search for anchor cell where to place current cell
Expand All @@ -126,6 +125,28 @@ export const deleteTableMergeRow = (editor: SlateEditor) => {
return curColIndex >= curRowCellColIndex;
});

if (startingCellIndex === -1) {
const startingCell = nextRow.children.at(-1) as TTableCellElement;
const startingCellPath = findNodePath(editor, startingCell)!;
const tablePath = startingCellPath.slice(0, -2);
const colPath = startingCellPath.at(-1)! + index + 1;
const nextRowStartCellPath = [...tablePath, nextRowIndex, colPath];

const rowsNumberAffected = endingRowIndex - curRowCellRowIndex + 1;
const rowSpan = curRowCellRowSpan - rowsNumberAffected;
const newCell = cloneDeep({ ...curRowCell, rowSpan });

if (newCell.attributes?.rowspan) {
newCell.attributes.rowspan = rowSpan.toString();
}

insertElements(editor, newCell, {
at: nextRowStartCellPath,
});

continue;
}

const startingCell = nextRow.children[
startingCellIndex
] as TTableCellElement;
Expand All @@ -152,16 +173,18 @@ export const deleteTableMergeRow = (editor: SlateEditor) => {
colPath + incrementBy,
];

const rowsNumberAffected = endingRowIndex - curRowCellColIndex + 1;
const rowsNumberAffected = endingRowIndex - curRowCellRowIndex + 1;
const rowSpan = curRowCellRowSpan - rowsNumberAffected;
const newCell = cloneDeep({ ...curRowCell, rowSpan });

// TODO: consider make deep clone here
// making cell smaller and moving it to next row
const newCell = {
...curRowCell,
rowSpan: curRowCellRowSpan - rowsNumberAffected,
};
insertElements(editor, newCell, { at: nextRowStartCellPath });
});
if (newCell.attributes?.rowspan) {
newCell.attributes.rowspan = rowSpan.toString();
}

insertElements(editor, newCell, {
at: nextRowStartCellPath,
});
}
}

squizeRowSpanCells.forEach((cur) => {
Expand All @@ -179,12 +202,14 @@ export const deleteTableMergeRow = (editor: SlateEditor) => {
endingRowIndex
);
const rowsNumberAffected = curCellEndingRowIndex - deletingRowIndex + 1;
const rowSpan = curRowCellRowSpan - rowsNumberAffected;
const newCell = cloneDeep({ ...curRowCell, rowSpan });

setNodes<TTableCellElement>(
editor,
{ ...curRowCell, rowSpan: curRowCellRowSpan - rowsNumberAffected },
{ at: curCellPath }
);
if (newCell.attributes?.rowspan) {
newCell.attributes.rowspan = rowSpan.toString();
}

setNodes<TTableCellElement>(editor, newCell, { at: curCellPath });
});

const rowToDelete = table.children[deletingRowIndex] as TTableRowElement;
Expand Down
Loading

0 comments on commit 2ab6b6b

Please sign in to comment.