diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
index b6a683f022e..670e78ff850 100644
--- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
@@ -34,6 +34,7 @@ import {
insertSampleImage,
insertTable,
insertTableColumnBefore,
+ insertTableRowAbove,
insertTableRowBelow,
IS_COLLAB,
IS_LINUX,
@@ -4674,4 +4675,408 @@ test.describe.parallel('Tables', () => {
`,
);
});
+
+ test('Can insert multiple rows above the selection', async ({
+ page,
+ isCollab,
+ isPlainText,
+ }) => {
+ await initialize({isCollab, page});
+ test.skip(isPlainText);
+ test.skip(isCollab);
+
+ await focusEditor(page);
+
+ await insertTable(page, 5, 5);
+
+ await selectCellsFromTableCords(
+ page,
+ {x: 0, y: 1},
+ {x: 4, y: 3},
+ true,
+ false,
+ );
+
+ await insertTableRowAbove(page);
+
+ await assertHTML(
+ page,
+ html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ `,
+ );
+ });
+
+ test('Can insert multiple rows below the selection', async ({
+ page,
+ isCollab,
+ isPlainText,
+ }) => {
+ await initialize({isCollab, page});
+ test.skip(isPlainText);
+ test.skip(isCollab);
+
+ await focusEditor(page);
+
+ await insertTable(page, 5, 5);
+
+ await selectCellsFromTableCords(
+ page,
+ {x: 0, y: 1},
+ {x: 4, y: 3},
+ true,
+ false,
+ );
+
+ await insertTableRowBelow(page);
+
+ await assertHTML(
+ page,
+ html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ `,
+ );
+ });
});
diff --git a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx
index 2e17272cbf7..b5275c7cd22 100644
--- a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx
@@ -309,11 +309,13 @@ function TableActionMenu({
const insertTableRowAtSelection = useCallback(
(shouldInsertAfter: boolean) => {
editor.update(() => {
- $insertTableRow__EXPERIMENTAL(shouldInsertAfter);
+ for (let i = 0; i < selectionCounts.rows; i++) {
+ $insertTableRow__EXPERIMENTAL(shouldInsertAfter);
+ }
onClose();
});
},
- [editor, onClose],
+ [editor, onClose, selectionCounts.rows],
);
const insertTableColumnAtSelection = useCallback(
diff --git a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css
index 2e985c4dc8d..d7041331a52 100644
--- a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css
+++ b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css
@@ -213,6 +213,14 @@
padding: 6px 8px;
position: relative;
outline: none;
+ overflow: auto;
+}
+/*
+ A firefox workaround to allow scrolling of overflowing table cell
+ ref: https://bugzilla.mozilla.org/show_bug.cgi?id=1904159
+*/
+.PlaygroundEditorTheme__tableCell > * {
+ overflow: inherit;
}
.PlaygroundEditorTheme__tableCellResizer {
position: absolute;
diff --git a/packages/lexical-table/src/LexicalTableUtils.ts b/packages/lexical-table/src/LexicalTableUtils.ts
index 6c354285ec4..84e4ab3f5a7 100644
--- a/packages/lexical-table/src/LexicalTableUtils.ts
+++ b/packages/lexical-table/src/LexicalTableUtils.ts
@@ -258,20 +258,31 @@ export function $insertTableRow__EXPERIMENTAL(
$isRangeSelection(selection) || $isTableSelection(selection),
'Expected a RangeSelection or TableSelection',
);
+ const anchor = selection.anchor.getNode();
const focus = selection.focus.getNode();
+ const [anchorCell] = $getNodeTriplet(anchor);
const [focusCell, , grid] = $getNodeTriplet(focus);
- const [gridMap, focusCellMap] = $computeTableMap(grid, focusCell, focusCell);
+ const [gridMap, focusCellMap, anchorCellMap] = $computeTableMap(
+ grid,
+ focusCell,
+ anchorCell,
+ );
const columnCount = gridMap[0].length;
+ const {startRow: anchorStartRow} = anchorCellMap;
const {startRow: focusStartRow} = focusCellMap;
let insertedRow: TableRowNode | null = null;
if (insertAfter) {
- const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
- const focusEndRowMap = gridMap[focusEndRow];
+ const insertAfterEndRow =
+ Math.max(
+ focusStartRow + focusCell.__rowSpan,
+ anchorStartRow + anchorCell.__rowSpan,
+ ) - 1;
+ const insertAfterEndRowMap = gridMap[insertAfterEndRow];
const newRow = $createTableRowNode();
for (let i = 0; i < columnCount; i++) {
- const {cell, startRow} = focusEndRowMap[i];
- if (startRow + cell.__rowSpan - 1 <= focusEndRow) {
- const currentCell = focusEndRowMap[i].cell as TableCellNode;
+ const {cell, startRow} = insertAfterEndRowMap[i];
+ if (startRow + cell.__rowSpan - 1 <= insertAfterEndRow) {
+ const currentCell = insertAfterEndRowMap[i].cell as TableCellNode;
const currentCellHeaderState = currentCell.__headerState;
const headerState = getHeaderState(
@@ -286,20 +297,21 @@ export function $insertTableRow__EXPERIMENTAL(
cell.setRowSpan(cell.__rowSpan + 1);
}
}
- const focusEndRowNode = grid.getChildAtIndex(focusEndRow);
+ const insertAfterEndRowNode = grid.getChildAtIndex(insertAfterEndRow);
invariant(
- $isTableRowNode(focusEndRowNode),
- 'focusEndRow is not a TableRowNode',
+ $isTableRowNode(insertAfterEndRowNode),
+ 'insertAfterEndRow is not a TableRowNode',
);
- focusEndRowNode.insertAfter(newRow);
+ insertAfterEndRowNode.insertAfter(newRow);
insertedRow = newRow;
} else {
- const focusStartRowMap = gridMap[focusStartRow];
+ const insertBeforeStartRow = Math.min(focusStartRow, anchorStartRow);
+ const insertBeforeStartRowMap = gridMap[insertBeforeStartRow];
const newRow = $createTableRowNode();
for (let i = 0; i < columnCount; i++) {
- const {cell, startRow} = focusStartRowMap[i];
- if (startRow === focusStartRow) {
- const currentCell = focusStartRowMap[i].cell as TableCellNode;
+ const {cell, startRow} = insertBeforeStartRowMap[i];
+ if (startRow === insertBeforeStartRow) {
+ const currentCell = insertBeforeStartRowMap[i].cell as TableCellNode;
const currentCellHeaderState = currentCell.__headerState;
const headerState = getHeaderState(
@@ -314,12 +326,12 @@ export function $insertTableRow__EXPERIMENTAL(
cell.setRowSpan(cell.__rowSpan + 1);
}
}
- const focusStartRowNode = grid.getChildAtIndex(focusStartRow);
+ const insertBeforeStartRowNode = grid.getChildAtIndex(insertBeforeStartRow);
invariant(
- $isTableRowNode(focusStartRowNode),
- 'focusEndRow is not a TableRowNode',
+ $isTableRowNode(insertBeforeStartRowNode),
+ 'insertBeforeStartRow is not a TableRowNode',
);
- focusStartRowNode.insertBefore(newRow);
+ insertBeforeStartRowNode.insertBefore(newRow);
insertedRow = newRow;
}
return insertedRow;