From 9dc9735a745d834b954fb72dbba8c5e990fa8275 Mon Sep 17 00:00:00 2001 From: Dzmitry Tamashevich Date: Wed, 15 Nov 2023 16:49:11 +0300 Subject: [PATCH] add merge / unmerge --- apps/www/src/components/icons.tsx | 4 + .../src/lib/plate/demo/values/tableValue.tsx | 56 +++++++- .../default/plate-ui/table-element.tsx | 85 +++++++++--- .../useTableCellElementState.ts | 19 ++- .../TableElement/useTableElement.ts | 6 + packages/table/src/index.ts | 1 + packages/table/src/merge/index.ts | 6 + packages/table/src/merge/mergeTableCells.ts | 129 ++++++++++++++++++ packages/table/src/merge/unmergeTableCells.ts | 106 ++++++++++++++ .../table/src/queries/computeCellIndices.ts | 116 ++++++++++++++++ .../table/src/queries/findCellByIndexes.ts | 20 ++- packages/table/src/queries/getCellIdices.ts | 105 -------------- packages/table/src/queries/getIndices.ts | 5 +- .../table/src/queries/getIndicesWithSpans.ts | 14 +- .../table/src/queries/getTableGridByRange.ts | 27 ++-- packages/table/src/types.ts | 2 +- 16 files changed, 541 insertions(+), 160 deletions(-) create mode 100644 packages/table/src/merge/index.ts create mode 100644 packages/table/src/merge/mergeTableCells.ts create mode 100644 packages/table/src/merge/unmergeTableCells.ts create mode 100644 packages/table/src/queries/computeCellIndices.ts delete mode 100644 packages/table/src/queries/getCellIdices.ts diff --git a/apps/www/src/components/icons.tsx b/apps/www/src/components/icons.tsx index 793de4ff5d..bc3fb4ef83 100644 --- a/apps/www/src/components/icons.tsx +++ b/apps/www/src/components/icons.tsx @@ -15,6 +15,7 @@ import { ChevronsUpDown, ClipboardCheck, Code2, + Combine, Copy, DownloadCloud, ExternalLink, @@ -73,6 +74,7 @@ import { Trash, Twitter, Underline, + Ungroup, Unlink, WrapText, X, @@ -281,6 +283,8 @@ export const Icons = { codeblock: FileCode, color: Baseline, column: RectangleVertical, + combine: Combine, + ungroup: Ungroup, comment: MessageSquare, commentAdd: MessageSquarePlus, conflict: Unlink, diff --git a/apps/www/src/lib/plate/demo/values/tableValue.tsx b/apps/www/src/lib/plate/demo/values/tableValue.tsx index 0e79843495..09c5493cf3 100644 --- a/apps/www/src/lib/plate/demo/values/tableValue.tsx +++ b/apps/www/src/lib/plate/demo/values/tableValue.tsx @@ -158,6 +158,59 @@ export const createMergedCellsTable = (): any => ( ); +export const createAutoLayoutTable = (): any => ( + + + + + + Heading + + + + + Cell 1 + + + + + Cell 11 + + + + + Cell 2 + + + + + + Cell 3 + + {/* + Cell 77 + */} + + Cell 7 + + + + + + Cell 4 + + + {/* + Cell 5 + */} + + Cell 8 + + + + +); + export const tableValue: any = ( @@ -167,7 +220,8 @@ export const tableValue: any = ( to design structured layouts. {createMergedCellsTable()} - {createSpanningTable()} + {/* {createSpanningTable()} + {createAutoLayoutTable()} */} {/* {createTable()} */} {/* This table is an example of rendering a table spanning multiple columns: diff --git a/apps/www/src/registry/default/plate-ui/table-element.tsx b/apps/www/src/registry/default/plate-ui/table-element.tsx index 713679f69b..15e204fe50 100644 --- a/apps/www/src/registry/default/plate-ui/table-element.tsx +++ b/apps/www/src/registry/default/plate-ui/table-element.tsx @@ -3,6 +3,7 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; import { PopoverAnchor, PopoverContentProps } from '@radix-ui/react-popover'; import { isCollapsed, + isExpanded, PlateElement, PlateElementProps, useEditorState, @@ -10,7 +11,10 @@ import { useRemoveNodeButton, } from '@udecode/plate-common'; import { + getTableGridAbove, + mergeTableCells, TTableElement, + unmergeTableCells, useTableBordersDropdownMenuContentState, useTableElement, useTableElementState, @@ -114,7 +118,66 @@ const TableFloatingToolbar = React.forwardRef< const readOnly = useReadOnly(); const selected = useSelected(); const editor = useEditorState(); - const open = !readOnly && selected && isCollapsed(editor.selection); + // const open = !readOnly && selected && isCollapsed(editor.selection); + + const collapsed = !readOnly && selected && isCollapsed(editor.selection); + const expanded = !readOnly && selected && isExpanded(editor.selection); + const open = !readOnly && selected; + + const cellEntries = getTableGridAbove(editor, { format: 'cell' }); + + const canUnmerge = + collapsed && + cellEntries && + cellEntries.length === 1 && + ((cellEntries[0][0] as any)?.colSpan > 1 || + (cellEntries[0][0] as any)?.rowSpan > 1); + + const mergeContent = expanded && ( + + ); + + const unmergeButton = canUnmerge && ( + + ); + + const bordersContent = collapsed && ( + <> + + + + + + + + + + + + + ); return ( @@ -125,23 +188,9 @@ const TableFloatingToolbar = React.forwardRef< onOpenAutoFocus={(e) => e.preventDefault()} {...props} > - - - - - - - - - - - + {unmergeButton} + {mergeContent} + {bordersContent} ); diff --git a/packages/table/src/components/TableCellElement/useTableCellElementState.ts b/packages/table/src/components/TableCellElement/useTableCellElementState.ts index 875503e60a..cd7a24c125 100644 --- a/packages/table/src/components/TableCellElement/useTableCellElementState.ts +++ b/packages/table/src/components/TableCellElement/useTableCellElementState.ts @@ -7,7 +7,7 @@ import { import { useReadOnly } from 'slate-react'; import { ELEMENT_TABLE, ELEMENT_TR } from '../../createTablePlugin'; -import { getCellIndices } from '../../queries/getCellIdices'; +import { computeCellIndices } from '../../queries/computeCellIndices'; import { getColSpan } from '../../queries/getColSpan'; import { getRowSpan } from '../../queries/getRowSpan'; import { getTableColumnIndex, getTableRowIndex } from '../../queries/index'; @@ -67,19 +67,28 @@ export const useTableCellElementState = ({ let x: { col: number; row: number }; const fromWeakMap = _cellIndices.get(cellElement); + // const cellContent = cellElement.children.map((i) => { + // return (i.children as any)[0].text; + // }); + + // const spans = { + // colSpan: getColSpan(cellElement), + // rowSpan: getRowSpan(cellElement), + // }; + if (fromWeakMap) { x = fromWeakMap; - console.log('from weak map', x, 'cellElement', cellElement); + // console.log('cellContent', cellContent, x); } else { - const x1 = getCellIndices(editor, tableElement, cellElement); + const x1 = computeCellIndices(editor, tableElement, cellElement); if (x1) { x = x1; - console.log('computed', x, 'cellElement', cellElement); + // console.log('computed', x, 'cellContent', cellContent, 'spans', spans); } else { const defaultColIndex = getTableColumnIndex(editor, cellElement); const defaultRowIndex = getTableRowIndex(editor, cellElement); x = { col: defaultColIndex, row: defaultRowIndex }; - console.log('get default', x, 'cellElement', cellElement); + // console.log('get default', x, 'cellContent', cellContent); } } const colIndex = x.col; diff --git a/packages/table/src/components/TableElement/useTableElement.ts b/packages/table/src/components/TableElement/useTableElement.ts index e0d5b76765..0a84039921 100644 --- a/packages/table/src/components/TableElement/useTableElement.ts +++ b/packages/table/src/components/TableElement/useTableElement.ts @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import { collapseSelection, getPluginOptions, @@ -6,6 +7,7 @@ import { } from '@udecode/plate-common'; import { ELEMENT_TABLE } from '../../createTablePlugin'; +import { computeAllCellIndices } from '../../queries/computeCellIndices'; import { useTableStore } from '../../stores/tableStore'; import { TablePlugin, TTableElement } from '../../types'; import { useSelectedCells } from './useSelectedCells'; @@ -43,6 +45,10 @@ export const useTableElementState = ({ let colSizes = useTableColSizes(element); + useEffect(() => { + computeAllCellIndices(editor, element); + }, [editor, element]); + if (transformColSizes) { colSizes = transformColSizes(colSizes); } diff --git a/packages/table/src/index.ts b/packages/table/src/index.ts index 81ea22f4b0..8821555967 100644 --- a/packages/table/src/index.ts +++ b/packages/table/src/index.ts @@ -19,3 +19,4 @@ export * from './queries/index'; export * from './stores/index'; export * from './transforms/index'; export * from './utils/index'; +export * from './merge/index'; diff --git a/packages/table/src/merge/index.ts b/packages/table/src/merge/index.ts new file mode 100644 index 0000000000..9ec11f2d66 --- /dev/null +++ b/packages/table/src/merge/index.ts @@ -0,0 +1,6 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './mergeTableCells'; +export * from './unmergeTableCells'; diff --git a/packages/table/src/merge/mergeTableCells.ts b/packages/table/src/merge/mergeTableCells.ts new file mode 100644 index 0000000000..647fb3bb42 --- /dev/null +++ b/packages/table/src/merge/mergeTableCells.ts @@ -0,0 +1,129 @@ +import { + getBlockAbove, + getPluginOptions, + getPluginType, + insertElements, + PlateEditor, + removeNodes, + Value, + withoutNormalizing, +} from '@udecode/plate-common'; +import { cloneDeep } from 'lodash'; + +import { ELEMENT_TABLE } from '../createTablePlugin'; +import { getTableGridAbove } from '../queries'; +import { computeCellIndices } from '../queries/computeCellIndices'; +import { getColSpan } from '../queries/getColSpan'; +import { getRowSpan } from '../queries/getRowSpan'; +import { TablePlugin, TTableCellElement, TTableElement } from '../types'; +import { getEmptyCellNode } from '../utils'; + +/** + * Merges multiple selected cells into one. + */ +export const mergeTableCells = ( + editor: PlateEditor +) => { + withoutNormalizing(editor, () => { + const options = getPluginOptions(editor, ELEMENT_TABLE); + const tableEntry = getBlockAbove(editor, { + at: editor.selection?.anchor.path, + match: { type: getPluginType(editor, ELEMENT_TABLE) }, + })!; + + const cellEntries = getTableGridAbove(editor, { format: 'cell' }); + + // calculate the colSpan which is the number of horizontal cells that a cell should span. + let colSpan = 0; + for (const entry of cellEntries) { + const [data, path] = entry; + + // count only those cells that are in the first selected row. + if (path[1] === cellEntries[0][1][1]) { + const cellColSpan = getColSpan(data as TTableCellElement); + colSpan += cellColSpan; + } + } + + // calculate the rowSpan which is the number of vertical cells that a cell should span. + let rowSpan = 0; + const { col } = options._cellIndices.get( + cellEntries[0][0] as TTableCellElement + )!; + cellEntries.forEach((cE) => { + const cell = cE[0] as TTableCellElement; + const { col: curCol } = + options._cellIndices.get(cell) || + computeCellIndices(editor, tableEntry[0] as TTableElement, cell)!; + if (col === curCol) { + rowSpan += getRowSpan(cell); + } + }); + + // This will store the content of all cells we are merging + const contents = []; + for (const cellEntry of cellEntries) { + const [el] = cellEntry; + contents.push(...cloneDeep(el.children)); + } + + // Create a hash map where keys are col paths, + // and values are an array of all paths with that column + const cols: { [key: string]: number[][] } = {}; + + // A boolean to keep track if we have a header cell among the cells we are merging + let hasHeaderCell = false; + + cellEntries.forEach(([entry, path]) => { + if (!hasHeaderCell && entry.type === 'table_header_cell') { + hasHeaderCell = true; + } + if (cols[path[1]]) { + cols[path[1]].push(path); + } else { + cols[path[1]] = [path]; + } + }); + + // removes multiple cells with on same path. + // once cell removed, next cell in the row will settle down on that path + Object.values(cols).forEach((paths) => { + paths?.forEach(() => { + removeNodes(editor, { at: paths[0] }); + }); + }); + + // Create a new cell to replace the merged cells, with + // calculated colSpan and rowSpan attributes and combined content + const mergedCell = { + ...getEmptyCellNode(editor, { + header: cellEntries[0][0].type === 'th', + newCellChildren: contents, + }), + colSpan, + rowSpan, + }; + + // insert the new merged cell in place of the first cell in the selection + insertElements(editor, mergedCell, { at: cellEntries[0][1] }); + + // /** + // * Update cell indices in weak map + // */ + // const tableEntry = findNode(editor, { + // at: cellEntries[0][1], + // match: { type: getPluginType(editor, ELEMENT_TABLE) }, + // })!; // TODO: improve typing + // const cellEntry = findNode(editor, { + // at: cellEntries[0][1], + // match: { type: getCellTypes(editor) }, + // })!; // TODO: improve typing + + // const realTable = tableEntry[0] as TTableElement; + // const mC = cellEntry[0] as TTableCellElement; + // console.log('realTable', realTable, 'mC', mC); + + // computeCellIndices(editor, realTable, mC); + // console.log('should be computed'); + }); +}; diff --git a/packages/table/src/merge/unmergeTableCells.ts b/packages/table/src/merge/unmergeTableCells.ts new file mode 100644 index 0000000000..395ba1163d --- /dev/null +++ b/packages/table/src/merge/unmergeTableCells.ts @@ -0,0 +1,106 @@ +import { + findNode, + getPluginOptions, + getPluginType, + insertElements, + PlateEditor, + removeNodes, + TDescendant, + Value, + withoutNormalizing, +} from '@udecode/plate-common'; + +import { ELEMENT_TABLE, ELEMENT_TR } from '../createTablePlugin'; +import { getTableGridAbove } from '../queries'; +import { getColSpan } from '../queries/getColSpan'; +import { + TablePlugin, + TTableCellElement, + TTableElement, + TTableRowElement, +} from '../types'; +import { getEmptyCellNode } from '../utils'; + +export const unmergeTableCells = ( + editor: PlateEditor +) => { + withoutNormalizing(editor, () => { + const options = getPluginOptions(editor, ELEMENT_TABLE); + + const cellEntries = getTableGridAbove(editor, { format: 'cell' }); + const [[cellElem, path]] = cellEntries; + + // creating new object per iteration is essential here + const createEmptyCell = (children?: TDescendant[]) => { + return { + ...getEmptyCellNode(editor, { + header: cellElem.type === 'th', + newCellChildren: children, + }), + colSpan: 1, + rowSpan: 1, + }; + }; + + const tablePath = path.slice(0, -2); + + const cellPath = path.slice(-2); + const [rowPath, colPath] = cellPath; + const colSpan = cellElem.colSpan as number; + const rowSpan = cellElem.rowSpan as number; + + // Generate an array of column paths from the colspan + const colPaths: number[] = []; + for (let i = 0; i < colSpan; i++) { + colPaths.push(colPath + i); + } + + // Remove the original merged cell from the editor + removeNodes(editor, { at: path }); + + const { col } = options._cellIndices.get(cellElem as TTableCellElement)!; + + const getColPathForRow = (row: number) => { + let newColPath = 0; + + const rowEntry = findNode(editor, { + at: [...tablePath, row], + match: { type: getPluginType(editor, ELEMENT_TR) }, + })!; // TODO: improve typing + const rowEl = rowEntry[0] as TTableRowElement; + + for (const item of rowEl.children) { + const { col: c } = options._cellIndices.get(item as TTableCellElement)!; + if (c === col - 1) { + newColPath = rowEl.children.indexOf(item) + 1; + // console.log('found first', newColPath); + break; + } + if (col + getColSpan(cellElem as TTableCellElement) === c - 1) { + newColPath = rowEl.children.indexOf(item); + // console.log('found last', newColPath); + break; + } + } + + return newColPath; + }; + + // Generate an array of cell paths from the row and col spans and then insert empty cells at those paths + for (let i = 0; i < rowSpan; i++) { + const currentRowPath = rowPath + i; + const pathForNextRows = getColPathForRow(currentRowPath); + for (let j = 0; j < colPaths.length; j++) { + const currentColPath = i === 0 ? colPaths[j] : pathForNextRows; + + const pathForNewCell = [...tablePath, currentRowPath, currentColPath]; + const cellToInsert = + i === 0 && j === 0 + ? createEmptyCell(cellElem.children) + : createEmptyCell(); + + insertElements(editor, cellToInsert, { at: pathForNewCell }); + } + } + }); +}; diff --git a/packages/table/src/queries/computeCellIndices.ts b/packages/table/src/queries/computeCellIndices.ts new file mode 100644 index 0000000000..009912c2d5 --- /dev/null +++ b/packages/table/src/queries/computeCellIndices.ts @@ -0,0 +1,116 @@ +import { + findNodePath, + getPluginOptions, + PlateEditor, + Value, +} from '@udecode/plate-common'; + +import { ELEMENT_TABLE } from '../createTablePlugin'; +import { + TablePlugin, + TTableCellElement, + TTableElement, + TTableRowElement, +} from '../types'; + +export function computeCellIndices( + editor: PlateEditor, + tableEl: TTableElement, + cellEl: TTableCellElement +) { + const options = getPluginOptions(editor, ELEMENT_TABLE); + + const tableNodes = tableEl.children; + + let rowIndex = -1; + let colIndex = -1; + + for (let r = 0; r < tableNodes.length; r++) { + const row = tableNodes[r] as TTableRowElement; + + let cIndex = 0; + for (let c = 0; c < row.children.length; c++) { + const cell = row.children[c] as TTableCellElement; + if (cellEl === cell) { + colIndex = cIndex; + rowIndex = r; + break; + } + cIndex += cell.colSpan || 1; // consider 0 and undefined as 1 + } + } + + 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); + if (prevIndices) { + const { col: prevColIndex } = prevIndices; + if ( + // colIndex affects + prevColIndex <= colIndex && + // rowSpan affects + prevCell.rowSpan && + prevCell.rowSpan > 1 && + rowIndex - _rowIndex < prevCell.rowSpan + ) { + colIndex += prevCell.colSpan || 1; + } + } + }); + }); + + if (rowIndex === -1 || colIndex === -1) { + // console.log('Invalid cell location.'); + return null; + } + + const indices = { row: rowIndex, col: colIndex }; + const cellContent = cellEl.children?.map((i) => { + return (i.children as any)[0].text; + }); + // console.log('new cell location', cellContent, indices); + + options?._cellIndices?.set(cellEl, indices); + + return indices; +} + +export const computeAllCellIndices = ( + editor: PlateEditor, + tableNode: TTableElement +) => { + const options = getPluginOptions(editor, ELEMENT_TABLE); + + // Initialize an array to store the indices of each cell + const cellIndicesArray = []; + + // const tablePath = findNodePath(editor, tableNode)!; + + // Iterate through the table rows + for (let r = 0; r < tableNode.children.length; r++) { + const row = tableNode.children[r] as TTableRowElement; + const rowIndicesArray = []; + + // Iterate through the row cells + for (let c = 0; c < row.children.length; c++) { + const cell = row.children[c] as TTableCellElement; + + // Get cell indices and store them in the row's array + // const cellPath = [r, c]; + + const indices = computeCellIndices(editor, tableNode, cell); + if (indices) { + options._cellIndices.set(cell, indices); + } + rowIndicesArray.push(indices); + } + + // Push the rowIndicesArray to the cellIndicesArray + cellIndicesArray.push(rowIndicesArray); + // console.log('calculated array', cellIndicesArray); + } + + return cellIndicesArray; +}; diff --git a/packages/table/src/queries/findCellByIndexes.ts b/packages/table/src/queries/findCellByIndexes.ts index 150c724af0..09ba7f1aef 100644 --- a/packages/table/src/queries/findCellByIndexes.ts +++ b/packages/table/src/queries/findCellByIndexes.ts @@ -1,15 +1,19 @@ -import { Value } from '@udecode/plate-common'; +import { getPluginOptions, PlateEditor, Value } from '@udecode/plate-common'; +import { ELEMENT_TABLE } from '../createTablePlugin'; import { TablePlugin, TTableCellElement, TTableElement } from '../types'; +import { computeCellIndices } from './computeCellIndices'; import { getIndices } from './getIndices'; import { getIndicesWithSpans } from './getIndicesWithSpans'; -export const findCellByIndexes1 = ( - options: TablePlugin, +export const findCellByIndexes = ( + editor: PlateEditor, table: TTableElement, searchRowIndex: number, searchColIndex: number ) => { + const options = getPluginOptions(editor, ELEMENT_TABLE); + const allCells = table.children.flatMap( (current) => current.children ) as TTableCellElement[]; @@ -18,9 +22,13 @@ export const findCellByIndexes1 = ( const foundCell = allCells.find((cell) => { const cellElement = cell as TTableCellElement; - const { _startColIndex, _startRowIndex } = getIndices(options, cellElement); - const { _endRowIndex, _endColIndex } = getIndicesWithSpans( - options, + const indices = + getIndices(options, cellElement) || + computeCellIndices(editor, table, cellElement)!; + + const { col: _startColIndex, row: _startRowIndex } = indices; + const { row: _endRowIndex, col: _endColIndex } = getIndicesWithSpans( + indices, cellElement ); diff --git a/packages/table/src/queries/getCellIdices.ts b/packages/table/src/queries/getCellIdices.ts deleted file mode 100644 index e51356274b..0000000000 --- a/packages/table/src/queries/getCellIdices.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { getPluginOptions, PlateEditor } from '@udecode/plate-common'; - -import { ELEMENT_TABLE } from '../createTablePlugin'; -import { - TablePlugin, - TTableCellElement, - TTableElement, - TTableRowElement, -} from '../types'; - -export function getCellIndices( - editor: PlateEditor, - tableEl: TTableElement, - cellEl: TTableCellElement -) { - const options = getPluginOptions(editor, ELEMENT_TABLE); - - const tableNodes = tableEl.children; - - let rowIndex = -1; - let colIndex = -1; - - for (let r = 0; r < tableNodes.length; r++) { - const row = tableNodes[r] as TTableRowElement; - - let cIndex = 0; - for (let c = 0; c < row.children.length; c++) { - const cell = row.children[c] as TTableCellElement; - if (cellEl === cell) { - colIndex = cIndex; - rowIndex = r; - break; - } - cIndex += cell.colSpan || 1; // consider 0 and undefined as 1 - } - } - - 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); - if (prevIndices) { - const { col: prevColIndex } = prevIndices; - if ( - // colIndex affects - prevColIndex <= colIndex && - // rowSpan affects - prevCell.rowSpan && - prevCell.rowSpan > 1 && - rowIndex - _rowIndex < prevCell.rowSpan - ) { - colIndex += prevCell.colSpan || 1; - } - } - }); - }); - - if (rowIndex === -1 || colIndex === -1) { - console.log('Invalid cell location.'); - return null; - } - - const indices = { row: rowIndex, col: colIndex }; - - options?._cellIndices?.set(cellEl, indices); - - return indices; -} - -// const calculateCellIndexes = ( -// editor: PlateEditor, -// tableNode: TTableElement -// ) => { -// // Initialize an array to store the indices of each cell -// const cellIndicesArray = []; - -// const tablePath = findNodePath(editor, tableNode)!; - -// // Iterate through the table rows -// for (let r = 0; r < tableNode.children.length; r++) { -// const row = tableNode.children[r] as TTableRowElement; -// const rowIndicesArray = []; - -// // Iterate through the row cells -// for (let c = 0; c < row.children.length; c++) { -// const cell = row.children[c] as TTableCellElement; - -// // Get cell indices and store them in the row's array -// const cellPath = [r, c]; - -// const indices = getCellIndices(editor, tableNode, cell); -// if (indices) { -// cellIndices.set(cell, indices); -// } -// rowIndicesArray.push(indices); -// } - -// // Push the rowIndicesArray to the cellIndicesArray -// cellIndicesArray.push(rowIndicesArray); -// console.log('calculated array', cellIndicesArray); -// } - -// return cellIndicesArray; -// }; diff --git a/packages/table/src/queries/getIndices.ts b/packages/table/src/queries/getIndices.ts index c5b6a60bbb..e21a4998c7 100644 --- a/packages/table/src/queries/getIndices.ts +++ b/packages/table/src/queries/getIndices.ts @@ -6,8 +6,5 @@ export const getIndices = ( options: TablePlugin, startCell: TTableCellElement ) => { - const { col: _startColIndex, row: _startRowIndex } = - options._cellIndices.get(startCell)!; - - return { _startColIndex, _startRowIndex }; + return options._cellIndices.get(startCell); }; diff --git a/packages/table/src/queries/getIndicesWithSpans.ts b/packages/table/src/queries/getIndicesWithSpans.ts index c07cf73b62..ff69016c85 100644 --- a/packages/table/src/queries/getIndicesWithSpans.ts +++ b/packages/table/src/queries/getIndicesWithSpans.ts @@ -5,15 +5,11 @@ import { getColSpan } from './getColSpan'; import { getRowSpan } from './getRowSpan'; export const getIndicesWithSpans = ( - options: TablePlugin, + { col, row }: { col: number; row: number }, endCell: TTableCellElement ) => { - const { col: __endColIndex, row: __endRowIndex } = - options._cellIndices.get(endCell)!; - - // TODO: improve typing - const _endRowIndex = __endRowIndex + getRowSpan(endCell) - 1; - const _endColIndex = __endColIndex + getColSpan(endCell) - 1; - - return { _endRowIndex, _endColIndex }; + return { + row: row + getRowSpan(endCell) - 1, + col: col + getColSpan(endCell) - 1, + }; }; diff --git a/packages/table/src/queries/getTableGridByRange.ts b/packages/table/src/queries/getTableGridByRange.ts index a0f9fceb9a..4171cee1c4 100644 --- a/packages/table/src/queries/getTableGridByRange.ts +++ b/packages/table/src/queries/getTableGridByRange.ts @@ -19,7 +19,8 @@ import { } from '../types'; import { getCellTypes } from '../utils'; import { getEmptyTableNode } from '../utils/getEmptyTableNode'; -import { findCellByIndexes1 } from './findCellByIndexes'; +import { computeCellIndices } from './computeCellIndices'; +import { findCellByIndexes } from './findCellByIndexes'; import { getIndices } from './getIndices'; import { getIndicesWithSpans } from './getIndicesWithSpans'; @@ -75,8 +76,15 @@ export const getTableGridByRange = ( })!; // TODO: improve typing const realTable = tableEntry[0] as TTableElement; - const { _startColIndex, _startRowIndex } = getIndices(options, startCell); - const { _endRowIndex, _endColIndex } = getIndicesWithSpans(options, endCell); + const { col: _startColIndex, row: _startRowIndex } = + getIndices(options, startCell) || + computeCellIndices(editor, realTable, startCell)!; + + const { row: _endRowIndex, col: _endColIndex } = getIndicesWithSpans( + getIndices(options, endCell) || + computeCellIndices(editor, realTable, endCell)!, + endCell + ); const startRowIndex = Math.min(_startRowIndex, _endRowIndex); const endRowIndex = Math.max(_startRowIndex, _endRowIndex); @@ -93,25 +101,24 @@ export const getTableGridByRange = ( }); const cellEntries: TElementEntry[] = []; - const cellsSet = new Set(); + const cellsSet = new WeakSet(); let rowIndex = startRowIndex; let colIndex = startColIndex; while (true) { - const cell = findCellByIndexes1(options, realTable, rowIndex, colIndex); + const cell = findCellByIndexes(editor, realTable, rowIndex, colIndex); if (!cell) { break; } - const cellPath = findNodePath(editor, cell)!; - const path = cellPath.join(''); - if (!cellsSet.has(path)) { - cellsSet.add(path); + if (!cellsSet.has(cell)) { + cellsSet.add(cell); const rows = table.children[rowIndex - startRowIndex] .children as TElement[]; rows[colIndex - startColIndex] = cell; + const cellPath = findNodePath(editor, cell)!; cellEntries.push([cell, cellPath]); } @@ -143,7 +150,5 @@ export const getTableGridByRange = ( rowElement.children = filteredChildren; }); - console.log('return entries', [[table, tablePath]], cellEntries); - return [[table, tablePath]]; }; diff --git a/packages/table/src/types.ts b/packages/table/src/types.ts index 173462c7e5..02a3893dce 100644 --- a/packages/table/src/types.ts +++ b/packages/table/src/types.ts @@ -65,7 +65,7 @@ export interface TablePlugin { _cellIndices: TableStoreCellAttributes; } -export type TableStoreCellAttributes = Map< +export type TableStoreCellAttributes = WeakMap< TTableCellElement, { row: number; col: number } >;