diff --git a/packages/ui/src/RichEditor/TableCellMenu.tsx b/packages/ui/src/RichEditor/TableCellMenu.tsx
index aeb542616..f02da49f4 100644
--- a/packages/ui/src/RichEditor/TableCellMenu.tsx
+++ b/packages/ui/src/RichEditor/TableCellMenu.tsx
@@ -235,70 +235,33 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
setMenuOpen(false);
};
- const hasSpannedCell = (): boolean => {
- const { selection } = editor.state;
-
- if (selection instanceof CellSelection) {
- let found = false;
- selection.forEachCell((node) => {
- if (node.attrs.colspan > 1 || node.attrs.rowspan > 1) {
- found = true;
- }
- });
- return found;
- }
-
- const $pos = editor.state.doc.resolve(selection.from);
- const cell = cellAround($pos);
- if (!cell) return false;
- const cellNode = editor.state.doc.nodeAt(cell.pos);
- if (!cellNode) return false;
- return cellNode.attrs.colspan > 1 || cellNode.attrs.rowspan > 1;
- };
-
const handleSplitCell = () => {
editor.chain().focus().splitCell().run();
setMenuOpen(false);
};
const handleClearContents = () => {
- const { state, dispatch } = editor.view;
- const { selection, schema } = state;
- const { tr } = state;
- let cursorTarget: number | null = null;
+ const { state } = editor.view;
- if (selection instanceof CellSelection) {
- selection.forEachCell((node, pos) => {
- const start = pos + 1;
- const end = pos + node.nodeSize - 1;
- if (cursorTarget === null) {
- cursorTarget = tr.mapping.map(start) + 1;
- }
- tr.replaceWith(
- tr.mapping.map(start),
- tr.mapping.map(end),
- schema.nodes.paragraph.create(),
- );
- });
+ if (state.selection instanceof CellSelection) {
+ editor.commands.deleteSelection();
} else {
- const $pos = state.doc.resolve(selection.from);
+ const { dispatch } = editor.view;
+ const { tr, schema } = state;
+ const $pos = state.doc.resolve(state.selection.from);
const cell = cellAround($pos);
if (cell) {
const cellNode = state.doc.nodeAt(cell.pos);
if (cellNode) {
const start = cell.pos + 1;
const end = cell.pos + cellNode.nodeSize - 1;
- cursorTarget = start + 1;
tr.replaceWith(start, end, schema.nodes.paragraph.create());
+ tr.setSelection(TextSelection.create(tr.doc, start + 1));
+ dispatch(tr);
}
}
}
- if (cursorTarget !== null) {
- tr.setSelection(TextSelection.create(tr.doc, cursorTarget));
- }
-
- dispatch(tr);
setMenuOpen(false);
};
@@ -340,11 +303,13 @@ export function TableCellMenu({ editor }: TableCellMenuProps) {
onMouseDown={e => e.preventDefault()}
className={menu()}
>
-
-
- Merge cells
-
- {hasSpannedCell() && (
+ {editor.can().mergeCells() && (
+
+
+ Merge cells
+
+ )}
+ {editor.can().splitCell() && (
Split cells
diff --git a/packages/ui/src/RichEditor/TableColumnMenu.tsx b/packages/ui/src/RichEditor/TableColumnMenu.tsx
index 6112a46a5..ad79d816d 100644
--- a/packages/ui/src/RichEditor/TableColumnMenu.tsx
+++ b/packages/ui/src/RichEditor/TableColumnMenu.tsx
@@ -450,19 +450,17 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
if (!table) return;
const map = TableMap.get(table);
- const { tr, schema } = editor.state;
- const targetType = isHeaderColumn()
- ? schema.nodes.tableCell
- : schema.nodes.tableHeader;
+ const cellPos = map.positionAt(0, 0, table) + tableStart;
- for (let row = 0; row < map.height; row++) {
- const cellPos = map.map[row * map.width] + tableStart;
- const cellNode = editor.state.doc.nodeAt(cellPos);
- if (!cellNode) continue;
- tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
- }
-
- editor.view.dispatch(tr);
+ editor
+ .chain()
+ .focus()
+ .command(({ tr }) => {
+ tr.setSelection(TextSelection.create(tr.doc, cellPos + 1));
+ return true;
+ })
+ .toggleHeaderColumn()
+ .run();
} catch {
// table may have changed
}
@@ -503,26 +501,26 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
const { colIndex, tableStart } = currentCol;
try {
- const tableNodePos = tableStart - 1;
- const table = editor.state.doc.nodeAt(tableNodePos);
+ const table = editor.state.doc.nodeAt(tableStart - 1);
if (!table) return;
- const rows: PMNode[] = [];
- table.forEach((row) => {
- const cells: PMNode[] = [];
- row.forEach((cell, _offset, i) => {
- cells.push(cell);
- if (i === colIndex) {
- cells.push(cell.copy(cell.content));
- }
- });
- rows.push(row.type.create(row.attrs, cells));
- });
+ const map = TableMap.get(table);
- const newTable = table.type.create(table.attrs, rows);
- const { tr } = editor.state;
- tr.replaceWith(tableNodePos, tableNodePos + table.nodeSize, newTable);
- editor.view.dispatch(tr);
+ editor
+ .chain()
+ .focus()
+ .command(({ tr }) => {
+ for (let row = map.height - 1; row >= 0; row--) {
+ const cellOffset = map.map[row * map.width + colIndex];
+ const cell = table.nodeAt(cellOffset);
+ if (!cell) continue;
+
+ const insertPos = cellOffset + tableStart + cell.nodeSize;
+ tr.insert(insertPos, cell);
+ }
+ return true;
+ })
+ .run();
} catch {
// table may have changed
}
@@ -593,25 +591,17 @@ export function TableColumnMenu({ editor }: TableColumnMenuProps) {
if (!table) return;
const map = TableMap.get(table);
- const { tr } = editor.state;
- const { schema } = editor.state;
+ const firstCellPos = map.map[colIndex] + tableStart;
+ const lastCellPos
+ = map.map[(map.height - 1) * map.width + colIndex] + tableStart;
- for (let row = 0; row < map.height; row++) {
- const cellPos = map.map[row * map.width + colIndex] + tableStart;
- const cellNode = editor.state.doc.nodeAt(cellPos);
- if (!cellNode) continue;
+ const $anchor = editor.state.doc.resolve(firstCellPos);
+ const $head = editor.state.doc.resolve(lastCellPos);
- const start = cellPos + 1;
- const end = cellPos + cellNode.nodeSize - 1;
-
- tr.replaceWith(
- tr.mapping.map(start),
- tr.mapping.map(end),
- schema.nodes.paragraph.create(),
- );
- }
-
- editor.view.dispatch(tr);
+ editor.view.dispatch(
+ editor.state.tr.setSelection(new CellSelection($anchor, $head)),
+ );
+ editor.commands.deleteSelection();
} catch {
// table may have changed
}
diff --git a/packages/ui/src/RichEditor/TableRowMenu.tsx b/packages/ui/src/RichEditor/TableRowMenu.tsx
index d61e9e3a5..357abd235 100644
--- a/packages/ui/src/RichEditor/TableRowMenu.tsx
+++ b/packages/ui/src/RichEditor/TableRowMenu.tsx
@@ -446,19 +446,17 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
if (!table) return;
const map = TableMap.get(table);
- const { tr, schema } = editor.state;
- const targetType = isHeaderRow()
- ? schema.nodes.tableCell
- : schema.nodes.tableHeader;
+ const cellPos = map.positionAt(0, 0, table) + tableStart;
- for (let col = 0; col < map.width; col++) {
- const cellPos = map.map[col] + tableStart;
- const cellNode = editor.state.doc.nodeAt(cellPos);
- if (!cellNode) continue;
- tr.setNodeMarkup(cellPos, targetType, cellNode.attrs);
- }
-
- editor.view.dispatch(tr);
+ editor
+ .chain()
+ .focus()
+ .command(({ tr }) => {
+ tr.setSelection(TextSelection.create(tr.doc, cellPos + 1));
+ return true;
+ })
+ .toggleHeaderRow()
+ .run();
} catch {
// table may have changed
}
@@ -499,22 +497,24 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
const { rowIndex, tableStart } = currentRow;
try {
- const tableNodePos = tableStart - 1;
- const table = editor.state.doc.nodeAt(tableNodePos);
+ const table = editor.state.doc.nodeAt(tableStart - 1);
if (!table) return;
- const rows: PMNode[] = [];
- table.forEach((row, _offset, i) => {
- rows.push(row);
- if (i === rowIndex) {
- rows.push(row.copy(row.content));
- }
- });
+ const rowNode = table.child(rowIndex);
- const newTable = table.type.create(table.attrs, rows);
- const { tr } = editor.state;
- tr.replaceWith(tableNodePos, tableNodePos + table.nodeSize, newTable);
- editor.view.dispatch(tr);
+ let insertPos = tableStart;
+ for (let i = 0; i <= rowIndex; i++) {
+ insertPos += table.child(i).nodeSize;
+ }
+
+ editor
+ .chain()
+ .focus()
+ .command(({ tr }) => {
+ tr.insert(insertPos, rowNode);
+ return true;
+ })
+ .run();
} catch {
// table may have changed
}
@@ -585,25 +585,17 @@ export function TableRowMenu({ editor }: TableRowMenuProps) {
if (!table) return;
const map = TableMap.get(table);
- const { tr } = editor.state;
- const { schema } = editor.state;
+ const firstCellPos = map.map[rowIndex * map.width] + tableStart;
+ const lastCellPos
+ = map.map[rowIndex * map.width + (map.width - 1)] + tableStart;
- for (let col = 0; col < map.width; col++) {
- const cellPos = map.map[rowIndex * map.width + col] + tableStart;
- const cellNode = editor.state.doc.nodeAt(cellPos);
- if (!cellNode) continue;
+ const $anchor = editor.state.doc.resolve(firstCellPos);
+ const $head = editor.state.doc.resolve(lastCellPos);
- const start = cellPos + 1;
- const end = cellPos + cellNode.nodeSize - 1;
-
- tr.replaceWith(
- tr.mapping.map(start),
- tr.mapping.map(end),
- schema.nodes.paragraph.create(),
- );
- }
-
- editor.view.dispatch(tr);
+ editor.view.dispatch(
+ editor.state.tr.setSelection(new CellSelection($anchor, $head)),
+ );
+ editor.commands.deleteSelection();
} catch {
// table may have changed
}