Move Grid to @lexical/table (#5528)

This commit is contained in:
Gerard Rovira
2024-01-24 14:14:58 +00:00
committed by GitHub
parent e4fe60267c
commit 1154413a2c
19 changed files with 363 additions and 398 deletions

View File

@ -6,28 +6,27 @@
*
*/
import type {
DEPRECATED_GridCellNode,
ElementNode,
LexicalEditor,
} from 'lexical';
import type {ElementNode, LexicalEditor} from 'lexical';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import useLexicalEditable from '@lexical/react/useLexicalEditable';
import {
$deleteTableColumn__EXPERIMENTAL,
$deleteTableRow__EXPERIMENTAL,
$getNodeTriplet,
$getTableCellNodeFromLexicalNode,
$getTableColumnIndexFromTableCellNode,
$getTableNodeFromLexicalNodeOrThrow,
$getTableRowIndexFromTableCellNode,
$insertTableColumn__EXPERIMENTAL,
$insertTableRow__EXPERIMENTAL,
$isGridCellNode,
$isGridSelection,
$isTableCellNode,
$isTableRowNode,
$unmergeCell,
getTableSelectionFromTableElement,
GridCellNode,
GridSelection,
HTMLTableElementWithWithTableSelectionState,
TableCellHeaderStates,
@ -42,8 +41,6 @@ import {
$isParagraphNode,
$isRangeSelection,
$isTextNode,
DEPRECATED_$getNodeTriplet,
DEPRECATED_$isGridCellNode,
} from 'lexical';
import * as React from 'react';
import {ReactPortal, useCallback, useEffect, useRef, useState} from 'react';
@ -115,11 +112,11 @@ function $canUnmerge(): boolean {
) {
return false;
}
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor);
const [cell] = $getNodeTriplet(selection.anchor);
return cell.__colSpan > 1 || cell.__rowSpan > 1;
}
function $cellContainsEmptyParagraph(cell: DEPRECATED_GridCellNode): boolean {
function $cellContainsEmptyParagraph(cell: GridCellNode): boolean {
if (cell.getChildrenSize() !== 1) {
return false;
}
@ -145,7 +142,7 @@ function currentCellBackgroundColor(editor: LexicalEditor): null | string {
return editor.getEditorState().read(() => {
const selection = $getSelection();
if ($isRangeSelection(selection) || $isGridSelection(selection)) {
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor);
const [cell] = $getNodeTriplet(selection.anchor);
if ($isTableCellNode(cell)) {
return cell.getBackgroundColor();
}
@ -303,10 +300,10 @@ function TableActionMenu({
if ($isGridSelection(selection)) {
const {columns, rows} = computeSelectionCount(selection);
const nodes = selection.getNodes();
let firstCell: null | DEPRECATED_GridCellNode = null;
let firstCell: null | GridCellNode = null;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (DEPRECATED_$isGridCellNode(node)) {
if ($isGridCellNode(node)) {
if (firstCell === null) {
node.setColSpan(columns).setRowSpan(rows);
firstCell = node;
@ -318,7 +315,7 @@ function TableActionMenu({
) {
firstChild.remove();
}
} else if (DEPRECATED_$isGridCellNode(firstCell)) {
} else if ($isGridCellNode(firstCell)) {
const isEmpty = $cellContainsEmptyParagraph(node);
if (!isEmpty) {
firstCell.append(...node.getChildren());
@ -469,7 +466,7 @@ function TableActionMenu({
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection) || $isGridSelection(selection)) {
const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor);
const [cell] = $getNodeTriplet(selection.anchor);
if ($isTableCellNode(cell)) {
cell.setBackgroundColor(value);
}

View File

@ -7,16 +7,20 @@
*/
import type {
GridCellNode,
HTMLTableElementWithWithTableSelectionState,
InsertTableCommandPayload,
TableSelection,
} from '@lexical/table';
import type {DEPRECATED_GridCellNode, NodeKey} from 'lexical';
import type {NodeKey} from 'lexical';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {
$computeGridMap,
$createTableCellNode,
$createTableNodeWithDimensions,
$getNodeTriplet,
$isGridRowNode,
$isTableCellNode,
$isTableNode,
applyTableHandlers,
@ -31,9 +35,6 @@ import {
$isTextNode,
$nodesOfType,
COMMAND_PRIORITY_EDITOR,
DEPRECATED_$computeGridMap,
DEPRECATED_$getNodeTriplet,
DEPRECATED_$isGridRowNode,
} from 'lexical';
import {useEffect} from 'react';
import invariant from 'shared/invariant';
@ -150,14 +151,14 @@ export function TablePlugin({
if (node.getColSpan() > 1 || node.getRowSpan() > 1) {
// When we have rowSpan we have to map the entire Table to understand where the new Cells
// fit best; let's analyze all Cells at once to save us from further transform iterations
const [, , gridNode] = DEPRECATED_$getNodeTriplet(node);
const [gridMap] = DEPRECATED_$computeGridMap(gridNode, node, node);
const [, , gridNode] = $getNodeTriplet(node);
const [gridMap] = $computeGridMap(gridNode, node, node);
// TODO this function expects Tables to be normalized. Look into this once it exists
const rowsCount = gridMap.length;
const columnsCount = gridMap[0].length;
let row = gridNode.getFirstChild();
invariant(
DEPRECATED_$isGridRowNode(row),
$isGridRowNode(row),
'Expected TableNode first child to be a RowNode',
);
const unmerged = [];
@ -165,11 +166,11 @@ export function TablePlugin({
if (i !== 0) {
row = row.getNextSibling();
invariant(
DEPRECATED_$isGridRowNode(row),
$isGridRowNode(row),
'Expected TableNode first child to be a RowNode',
);
}
let lastRowCell: null | DEPRECATED_GridCellNode = null;
let lastRowCell: null | GridCellNode = null;
for (let j = 0; j < columnsCount; j++) {
const cellMap = gridMap[i][j];
const cell = cellMap.cell;

View File

@ -22,9 +22,6 @@ import type {
import {
ElementNode,
deprecated_GridCellNode,
deprecated_GridRowNode,
deprecated_GridNode,
} from 'lexical';
/**
@ -40,7 +37,7 @@ export const TableCellHeaderStates = {
export type TableCellHeaderState = $Values<typeof TableCellHeaderStates>;
declare export class TableCellNode extends deprecated_GridCellNode {
declare export class TableCellNode extends GridCellNode {
__headerState: TableCellHeaderState;
__width?: number;
__backgroundColor: null | string;
@ -84,7 +81,7 @@ declare export function $isTableCellNode(
* LexicalTableNode
*/
declare export class TableNode extends deprecated_GridNode {
declare export class TableNode extends GridNode {
static getType(): string;
static clone(node: TableNode): TableNode;
constructor(grid: ?Grid, key?: NodeKey): void;
@ -113,7 +110,7 @@ declare export function $isTableNode(
* LexicalTableRowNode
*/
declare export class TableRowNode extends deprecated_GridRowNode {
declare export class TableRowNode extends GridRowNode {
static getType(): string;
static clone(node: TableRowNode): TableRowNode;
constructor(height?: ?number, key?: NodeKey): void;
@ -226,13 +223,34 @@ declare export function $deleteTableColumn(
declare export function $insertTableRow__EXPERIMENTAL(
insertAfter: boolean,
): void;
declare export function $insertTableColumn__EXPERIMENTAL(
insertAfter: boolean,
): void;
declare export function $deleteTableRow__EXPERIMENTAL(): void;
declare export function $deleteTableColumn__EXPERIMENTAL(): void;
declare export function $unmergeCell(): void;
declare export function $computeGridMap(
grid: GridNode,
cellA: GridCellNode,
cellB: GridCellNode,
): [GridMapType, GridMapValueType, GridMapValueType];
declare export function $getNodeTriplet(
source: PointType | LexicalNode | GridCellNode,
): [GridCellNode, GridRowNode, GridNode];
declare export function $getGridCellNodeRect(gridCellNode: GridCellNode): {
rowIndex: number;
columnIndex: number;
rowSpan: number;
colSpan: number;
} | null;
/**
* LexicalTableSelection.js
*/
@ -303,3 +321,41 @@ declare export function $isGridSelection(
): x is GridSelection;
declare export function $createGridSelection(): GridSelection;
/**
* Grid
*/
export type GridMapValueType = {
cell: GridCellNode,
startRow: number,
startColumn: number,
};
export type GridMapType = Array<Array<GridMapValueType>>;
declare export class GridNode extends ElementNode {}
declare export function $isGridNode(
node: ?LexicalNode,
): node is GridNode;
declare export class GridRowNode extends ElementNode {}
declare export function $isGridRowNode(
node: ?LexicalNode,
): node is GridRowNode;
declare export class GridCellNode extends ElementNode {
__colSpan: number;
__rowSpan: number;
constructor(colSpan: number, key?: NodeKey): void;
getColSpan(): number;
setColSpan(colSpan: number): this;
getRowSpan(): number;
setRowSpan(rowSpan: number): this;
}
declare export function $isGridCellNode(
node: ?LexicalNode,
): node is GridCellNode;

View File

@ -13,7 +13,7 @@ import type {
Spread,
} from 'lexical';
import {ElementNode} from './LexicalElementNode';
import {ElementNode} from 'lexical';
export type SerializedGridCellNode = Spread<
{
@ -24,7 +24,7 @@ export type SerializedGridCellNode = Spread<
>;
/** @noInheritDoc */
export class DEPRECATED_GridCellNode extends ElementNode {
export class GridCellNode extends ElementNode {
/** @internal */
__colSpan: number;
__rowSpan: number;
@ -62,8 +62,8 @@ export class DEPRECATED_GridCellNode extends ElementNode {
}
}
export function DEPRECATED_$isGridCellNode(
node: DEPRECATED_GridCellNode | LexicalNode | null | undefined,
): node is DEPRECATED_GridCellNode {
return node instanceof DEPRECATED_GridCellNode;
export function $isGridCellNode(
node: GridCellNode | LexicalNode | null | undefined,
): node is GridCellNode {
return node instanceof GridCellNode;
}

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalNode} from 'lexical';
import {ElementNode} from 'lexical';
export class GridNode extends ElementNode {}
export function $isGridNode(
node: LexicalNode | null | undefined,
): node is GridNode {
return node instanceof GridNode;
}

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalNode} from 'lexical';
import {ElementNode} from 'lexical';
export class GridRowNode extends ElementNode {}
export function $isGridRowNode(
node: LexicalNode | null | undefined,
): node is GridRowNode {
return node instanceof GridRowNode;
}

View File

@ -13,12 +13,6 @@ import {
$isElementNode,
$normalizeSelection__EXPERIMENTAL,
BaseSelection,
DEPRECATED_$computeGridMap,
DEPRECATED_$getGridCellNodeRect,
DEPRECATED_$isGridCellNode,
DEPRECATED_$isGridNode,
DEPRECATED_$isGridRowNode,
GridMapValueType,
isCurrentlyReadOnlyMode,
LexicalNode,
NodeKey,
@ -26,6 +20,12 @@ import {
} from 'lexical';
import invariant from 'shared/invariant';
import {$isGridCellNode} from './LexicalGridCellNode';
import {$isGridNode} from './LexicalGridNode';
import {$isGridRowNode} from './LexicalGridRowNode';
import {GridMapValueType} from './LexicalTableSelection';
import {$computeGridMap, $getGridCellNodeRect} from './LexicalTableUtils';
export type GridSelectionShape = {
fromX: number;
fromY: number;
@ -126,10 +126,10 @@ export class GridSelection implements BaseSelection {
getShape(): GridSelectionShape {
const anchorCellNode = $getNodeByKey(this.anchor.key);
invariant(
DEPRECATED_$isGridCellNode(anchorCellNode),
$isGridCellNode(anchorCellNode),
'Expected GridSelection anchor to be (or a child of) GridCellNode',
);
const anchorCellNodeRect = DEPRECATED_$getGridCellNodeRect(anchorCellNode);
const anchorCellNodeRect = $getGridCellNodeRect(anchorCellNode);
invariant(
anchorCellNodeRect !== null,
'getCellRect: expected to find AnchorNode',
@ -137,10 +137,10 @@ export class GridSelection implements BaseSelection {
const focusCellNode = $getNodeByKey(this.focus.key);
invariant(
DEPRECATED_$isGridCellNode(focusCellNode),
$isGridCellNode(focusCellNode),
'Expected GridSelection focus to be (or a child of) GridCellNode',
);
const focusCellNodeRect = DEPRECATED_$getGridCellNodeRect(focusCellNode);
const focusCellNodeRect = $getGridCellNodeRect(focusCellNode);
invariant(
focusCellNodeRect !== null,
'getCellRect: expected to find focusCellNode',
@ -180,31 +180,25 @@ export class GridSelection implements BaseSelection {
const anchorNode = this.anchor.getNode();
const focusNode = this.focus.getNode();
const anchorCell = $findMatchingParent(
anchorNode,
DEPRECATED_$isGridCellNode,
);
const anchorCell = $findMatchingParent(anchorNode, $isGridCellNode);
// todo replace with triplet
const focusCell = $findMatchingParent(
focusNode,
DEPRECATED_$isGridCellNode,
);
const focusCell = $findMatchingParent(focusNode, $isGridCellNode);
invariant(
DEPRECATED_$isGridCellNode(anchorCell),
$isGridCellNode(anchorCell),
'Expected GridSelection anchor to be (or a child of) GridCellNode',
);
invariant(
DEPRECATED_$isGridCellNode(focusCell),
$isGridCellNode(focusCell),
'Expected GridSelection focus to be (or a child of) GridCellNode',
);
const anchorRow = anchorCell.getParent();
invariant(
DEPRECATED_$isGridRowNode(anchorRow),
$isGridRowNode(anchorRow),
'Expected anchorCell to have a parent GridRowNode',
);
const gridNode = anchorRow.getParent();
invariant(
DEPRECATED_$isGridNode(gridNode),
$isGridNode(gridNode),
'Expected tableNode to have a parent GridNode',
);
@ -231,7 +225,7 @@ export class GridSelection implements BaseSelection {
// once (on load) and iterate on it as updates occur. However, to do this we need to have the
// ability to store a state. Killing GridSelection and moving the logic to the plugin would make
// this possible.
const [map, cellAMap, cellBMap] = DEPRECATED_$computeGridMap(
const [map, cellAMap, cellBMap] = $computeGridMap(
gridNode,
anchorCell,
focusCell,
@ -313,7 +307,7 @@ export class GridSelection implements BaseSelection {
const {cell} = map[i][j];
const currentRow = cell.getParent();
invariant(
DEPRECATED_$isGridRowNode(currentRow),
$isGridRowNode(currentRow),
'Expected GridCellNode parent to be a GridRowNode',
);
if (currentRow !== lastRow) {

View File

@ -14,7 +14,6 @@ import type {
LexicalEditor,
LexicalNode,
NodeKey,
SerializedGridCellNode,
Spread,
} from 'lexical';
@ -24,10 +23,10 @@ import {
$createParagraphNode,
$isElementNode,
$isLineBreakNode,
DEPRECATED_GridCellNode,
} from 'lexical';
import {PIXEL_VALUE_REG_EXP} from './constants';
import {GridCellNode, SerializedGridCellNode} from './LexicalGridCellNode';
export const TableCellHeaderStates = {
BOTH: 3,
@ -49,7 +48,7 @@ export type SerializedTableCellNode = Spread<
>;
/** @noInheritDoc */
export class TableCellNode extends DEPRECATED_GridCellNode {
export class TableCellNode extends GridCellNode {
/** @internal */
__headerState: TableCellHeaderState;
/** @internal */

View File

@ -20,12 +20,9 @@ import type {
} from 'lexical';
import {addClassNamesToElement, isHTMLElement} from '@lexical/utils';
import {
$applyNodeReplacement,
$getNearestNodeFromDOMNode,
DEPRECATED_GridNode,
} from 'lexical';
import {$applyNodeReplacement, $getNearestNodeFromDOMNode} from 'lexical';
import {GridNode} from './LexicalGridNode';
import {$isTableCellNode} from './LexicalTableCellNode';
import {$isTableRowNode, TableRowNode} from './LexicalTableRowNode';
import {getTableGrid} from './LexicalTableSelectionHelpers';
@ -33,7 +30,7 @@ import {getTableGrid} from './LexicalTableSelectionHelpers';
export type SerializedTableNode = SerializedElementNode;
/** @noInheritDoc */
export class TableNode extends DEPRECATED_GridNode {
export class TableNode extends GridNode {
/** @internal */
__grid?: Grid;

View File

@ -11,7 +11,6 @@ import type {Spread} from 'lexical';
import {addClassNamesToElement} from '@lexical/utils';
import {
$applyNodeReplacement,
DEPRECATED_GridRowNode,
DOMConversionMap,
DOMConversionOutput,
EditorConfig,
@ -21,6 +20,7 @@ import {
} from 'lexical';
import {PIXEL_VALUE_REG_EXP} from './constants';
import {GridRowNode} from './LexicalGridRowNode';
export type SerializedTableRowNode = Spread<
{
@ -30,7 +30,7 @@ export type SerializedTableRowNode = Spread<
>;
/** @noInheritDoc */
export class TableRowNode extends DEPRECATED_GridRowNode {
export class TableRowNode extends GridRowNode {
/** @internal */
__height?: number;

View File

@ -27,6 +27,7 @@ import {
import {CAN_USE_DOM} from 'shared/canUseDOM';
import invariant from 'shared/invariant';
import {GridCellNode} from './LexicalGridCellNode';
import {
type GridSelection,
$createGridSelection,
@ -39,6 +40,13 @@ import {
getTableGrid,
} from './LexicalTableSelectionHelpers';
export type GridMapValueType = {
cell: GridCellNode;
startRow: number;
startColumn: number;
};
export type GridMapType = Array<Array<GridMapValueType>>;
export type Cell = {
elem: HTMLElement;
highlighted: boolean;

View File

@ -12,7 +12,6 @@ import type {TableNode} from './LexicalTableNode';
import type {Cell, Cells, Grid} from './LexicalTableSelection';
import type {
BaseSelection,
DEPRECATED_GridNode,
LexicalCommand,
LexicalEditor,
LexicalNode,
@ -36,9 +35,6 @@ import {
DELETE_CHARACTER_COMMAND,
DELETE_LINE_COMMAND,
DELETE_WORD_COMMAND,
DEPRECATED_$isGridCellNode,
DEPRECATED_$isGridNode,
DEPRECATED_$isGridRowNode,
FOCUS_COMMAND,
FORMAT_TEXT_COMMAND,
KEY_ARROW_DOWN_COMMAND,
@ -54,6 +50,9 @@ import {
} from 'lexical';
import invariant from 'shared/invariant';
import {$isGridCellNode} from './LexicalGridCellNode';
import {$isGridNode, GridNode} from './LexicalGridNode';
import {$isGridRowNode} from './LexicalGridRowNode';
import {$createGridSelection, $isGridSelection} from './LexicalGridSelection';
import {$isTableCellNode} from './LexicalTableCellNode';
import {$isTableNode} from './LexicalTableNode';
@ -473,16 +472,16 @@ export function applyTableHandlers(
const isSelectionInsideOfGrid =
(isRangeSelection &&
$findMatchingParent(selection.anchor.getNode(), (n) =>
DEPRECATED_$isGridCellNode(n),
$isGridCellNode(n),
) !== null &&
$findMatchingParent(selection.focus.getNode(), (n) =>
DEPRECATED_$isGridCellNode(n),
$isGridCellNode(n),
) !== null) ||
isGridSelection;
if (
nodes.length !== 1 ||
!DEPRECATED_$isGridNode(nodes[0]) ||
!$isGridNode(nodes[0]) ||
!isSelectionInsideOfGrid ||
anchorAndFocus === null
) {
@ -493,25 +492,23 @@ export function applyTableHandlers(
const newGrid = nodes[0];
const newGridRows = newGrid.getChildren();
const newColumnCount = newGrid
.getFirstChildOrThrow<DEPRECATED_GridNode>()
.getFirstChildOrThrow<GridNode>()
.getChildrenSize();
const newRowCount = newGrid.getChildrenSize();
const gridCellNode = $findMatchingParent(anchor.getNode(), (n) =>
DEPRECATED_$isGridCellNode(n),
$isGridCellNode(n),
);
const gridRowNode =
gridCellNode &&
$findMatchingParent(gridCellNode, (n) =>
DEPRECATED_$isGridRowNode(n),
);
$findMatchingParent(gridCellNode, (n) => $isGridRowNode(n));
const gridNode =
gridRowNode &&
$findMatchingParent(gridRowNode, (n) => DEPRECATED_$isGridNode(n));
$findMatchingParent(gridRowNode, (n) => $isGridNode(n));
if (
!DEPRECATED_$isGridCellNode(gridCellNode) ||
!DEPRECATED_$isGridRowNode(gridRowNode) ||
!DEPRECATED_$isGridNode(gridNode)
!$isGridCellNode(gridCellNode) ||
!$isGridRowNode(gridRowNode) ||
!$isGridNode(gridNode)
) {
return false;
}
@ -538,13 +535,13 @@ export function applyTableHandlers(
for (let r = fromY; r <= toY; r++) {
const currentGridRowNode = gridRowNodes[r];
if (!DEPRECATED_$isGridRowNode(currentGridRowNode)) {
if (!$isGridRowNode(currentGridRowNode)) {
return false;
}
const newGridRowNode = newGridRows[newRowIdx];
if (!DEPRECATED_$isGridRowNode(newGridRowNode)) {
if (!$isGridRowNode(newGridRowNode)) {
return false;
}
@ -555,13 +552,13 @@ export function applyTableHandlers(
for (let c = fromX; c <= toX; c++) {
const currentGridCellNode = gridCellNodes[c];
if (!DEPRECATED_$isGridCellNode(currentGridCellNode)) {
if (!$isGridCellNode(currentGridCellNode)) {
return false;
}
const newGridCellNode = newGridCellNodes[newColumnIdx];
if (!DEPRECATED_$isGridCellNode(newGridCellNode)) {
if (!$isGridCellNode(newGridCellNode)) {
return false;
}

View File

@ -6,8 +6,12 @@
*
*/
import type {Grid} from './LexicalTableSelection';
import type {DEPRECATED_GridRowNode, ElementNode} from 'lexical';
import type {
Grid,
GridMapType,
GridMapValueType,
} from './LexicalTableSelection';
import type {ElementNode, PointType} from 'lexical';
import {$findMatchingParent} from '@lexical/utils';
import {
@ -15,15 +19,14 @@ import {
$createTextNode,
$getSelection,
$isRangeSelection,
DEPRECATED_$computeGridMap,
DEPRECATED_$getNodeTriplet,
DEPRECATED_$isGridRowNode,
DEPRECATED_GridCellNode,
LexicalNode,
} from 'lexical';
import invariant from 'shared/invariant';
import {$isGridSelection, InsertTableCommandPayloadHeaders} from '.';
import {$isGridCellNode, GridCellNode} from './LexicalGridCellNode';
import {$isGridNode, GridNode} from './LexicalGridNode';
import {$isGridRowNode, GridRowNode} from './LexicalGridRowNode';
import {
$createTableCellNode,
$isTableCellNode,
@ -234,12 +237,8 @@ export function $insertTableRow__EXPERIMENTAL(insertAfter = true): void {
'Expected a RangeSelection or GridSelection',
);
const focus = selection.focus.getNode();
const [focusCell, , grid] = DEPRECATED_$getNodeTriplet(focus);
const [gridMap, focusCellMap] = DEPRECATED_$computeGridMap(
grid,
focusCell,
focusCell,
);
const [focusCell, , grid] = $getNodeTriplet(focus);
const [gridMap, focusCellMap] = $computeGridMap(grid, focusCell, focusCell);
const columnCount = gridMap[0].length;
const {startRow: focusStartRow} = focusCellMap;
if (insertAfter) {
@ -260,7 +259,7 @@ export function $insertTableRow__EXPERIMENTAL(insertAfter = true): void {
}
const focusEndRowNode = grid.getChildAtIndex(focusEndRow);
invariant(
DEPRECATED_$isGridRowNode(focusEndRowNode),
$isGridRowNode(focusEndRowNode),
'focusEndRow is not a GridRowNode',
);
focusEndRowNode.insertAfter(newRow);
@ -281,7 +280,7 @@ export function $insertTableRow__EXPERIMENTAL(insertAfter = true): void {
}
const focusStartRowNode = grid.getChildAtIndex(focusStartRow);
invariant(
DEPRECATED_$isGridRowNode(focusStartRowNode),
$isGridRowNode(focusStartRowNode),
'focusEndRow is not a GridRowNode',
);
focusStartRowNode.insertBefore(newRow);
@ -355,9 +354,9 @@ export function $insertTableColumn__EXPERIMENTAL(insertAfter = true): void {
);
const anchor = selection.anchor.getNode();
const focus = selection.focus.getNode();
const [anchorCell] = DEPRECATED_$getNodeTriplet(anchor);
const [focusCell, , grid] = DEPRECATED_$getNodeTriplet(focus);
const [gridMap, focusCellMap, anchorCellMap] = DEPRECATED_$computeGridMap(
const [anchorCell] = $getNodeTriplet(anchor);
const [focusCell, , grid] = $getNodeTriplet(focus);
const [gridMap, focusCellMap, anchorCellMap] = $computeGridMap(
grid,
focusCell,
anchorCell,
@ -371,10 +370,10 @@ export function $insertTableColumn__EXPERIMENTAL(insertAfter = true): void {
: startColumn - 1;
const gridFirstChild = grid.getFirstChild();
invariant(
DEPRECATED_$isGridRowNode(gridFirstChild),
$isGridRowNode(gridFirstChild),
'Expected firstTable child to be a row',
);
let firstInsertedCell: null | DEPRECATED_GridCellNode = null;
let firstInsertedCell: null | GridCellNode = null;
function $createTableCellNodeForInsertTableColumn() {
const cell = $createTableCellNode(TableCellHeaderStates.NO_STATUS).append(
$createParagraphNode(),
@ -384,12 +383,12 @@ export function $insertTableColumn__EXPERIMENTAL(insertAfter = true): void {
}
return cell;
}
let loopRow: DEPRECATED_GridRowNode = gridFirstChild;
let loopRow: GridRowNode = gridFirstChild;
rowLoop: for (let i = 0; i < rowCount; i++) {
if (i !== 0) {
const currentRow = loopRow.getNextSibling();
invariant(
DEPRECATED_$isGridRowNode(currentRow),
$isGridRowNode(currentRow),
'Expected row nextSibling to be a row',
);
loopRow = currentRow;
@ -405,7 +404,7 @@ export function $insertTableColumn__EXPERIMENTAL(insertAfter = true): void {
startRow: currentStartRow,
} = rowMap[insertAfterColumn];
if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {
let insertAfterCell: DEPRECATED_GridCellNode = currentCell;
let insertAfterCell: GridCellNode = currentCell;
let insertAfterCellRowStart = currentStartRow;
let prevCellIndex = insertAfterColumn;
while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {
@ -460,9 +459,9 @@ export function $deleteTableRow__EXPERIMENTAL(): void {
);
const anchor = selection.anchor.getNode();
const focus = selection.focus.getNode();
const [anchorCell, , grid] = DEPRECATED_$getNodeTriplet(anchor);
const [focusCell] = DEPRECATED_$getNodeTriplet(focus);
const [gridMap, anchorCellMap, focusCellMap] = DEPRECATED_$computeGridMap(
const [anchorCell, , grid] = $getNodeTriplet(anchor);
const [focusCell] = $getNodeTriplet(focus);
const [gridMap, anchorCellMap, focusCellMap] = $computeGridMap(
grid,
anchorCell,
focusCell,
@ -477,9 +476,7 @@ export function $deleteTableRow__EXPERIMENTAL(): void {
}
const columnCount = gridMap[0].length;
const nextRow = gridMap[focusEndRow + 1];
const nextRowNode: null | DEPRECATED_GridRowNode = grid.getChildAtIndex(
focusEndRow + 1,
);
const nextRowNode: null | GridRowNode = grid.getChildAtIndex(focusEndRow + 1);
for (let row = focusEndRow; row >= anchorStartRow; row--) {
for (let column = columnCount - 1; column >= 0; column--) {
const {
@ -512,7 +509,7 @@ export function $deleteTableRow__EXPERIMENTAL(): void {
}
const rowNode = grid.getChildAtIndex(row);
invariant(
DEPRECATED_$isGridRowNode(rowNode),
$isGridRowNode(rowNode),
'Expected GridNode childAtIndex(%s) to be RowNode',
String(row),
);
@ -536,9 +533,9 @@ export function $deleteTableColumn__EXPERIMENTAL(): void {
);
const anchor = selection.anchor.getNode();
const focus = selection.focus.getNode();
const [anchorCell, , grid] = DEPRECATED_$getNodeTriplet(anchor);
const [focusCell] = DEPRECATED_$getNodeTriplet(focus);
const [gridMap, anchorCellMap, focusCellMap] = DEPRECATED_$computeGridMap(
const [anchorCell, , grid] = $getNodeTriplet(anchor);
const [focusCell] = $getNodeTriplet(focus);
const [gridMap, anchorCellMap, focusCellMap] = $computeGridMap(
grid,
anchorCell,
focusCell,
@ -595,7 +592,7 @@ export function $deleteTableColumn__EXPERIMENTAL(): void {
}
}
function $moveSelectionToCell(cell: DEPRECATED_GridCellNode): void {
function $moveSelectionToCell(cell: GridCellNode): void {
const firstDescendant = cell.getFirstDescendant();
if (firstDescendant == null) {
cell.selectStart();
@ -620,7 +617,7 @@ export function $unmergeCell(): void {
'Expected a RangeSelection or GridSelection',
);
const anchor = selection.anchor.getNode();
const [cell, row, grid] = DEPRECATED_$getNodeTriplet(anchor);
const [cell, row, grid] = $getNodeTriplet(anchor);
const colSpan = cell.__colSpan;
const rowSpan = cell.__rowSpan;
if (colSpan > 1) {
@ -630,7 +627,7 @@ export function $unmergeCell(): void {
cell.setColSpan(1);
}
if (rowSpan > 1) {
const [map, cellMap] = DEPRECATED_$computeGridMap(grid, cell, cell);
const [map, cellMap] = $computeGridMap(grid, cell, cell);
const {startColumn, startRow} = cellMap;
let currentRowNode;
for (let i = 1; i < rowSpan; i++) {
@ -638,10 +635,10 @@ export function $unmergeCell(): void {
const currentRowMap = map[currentRow];
currentRowNode = (currentRowNode || row).getNextSibling();
invariant(
DEPRECATED_$isGridRowNode(currentRowNode),
$isGridRowNode(currentRowNode),
'Expected row next sibling to be a row',
);
let insertAfterCell: null | DEPRECATED_GridCellNode = null;
let insertAfterCell: null | GridCellNode = null;
for (let column = 0; column < startColumn; column++) {
const currentCellMap = currentRowMap[column];
const currentCell = currentCellMap.cell;
@ -670,3 +667,148 @@ export function $unmergeCell(): void {
cell.setRowSpan(1);
}
}
export function $computeGridMap(
grid: GridNode,
cellA: GridCellNode,
cellB: GridCellNode,
): [GridMapType, GridMapValueType, GridMapValueType] {
const tableMap: GridMapType = [];
let cellAValue: null | GridMapValueType = null;
let cellBValue: null | GridMapValueType = null;
function write(startRow: number, startColumn: number, cell: GridCellNode) {
const value = {
cell,
startColumn,
startRow,
};
const rowSpan = cell.__rowSpan;
const colSpan = cell.__colSpan;
for (let i = 0; i < rowSpan; i++) {
if (tableMap[startRow + i] === undefined) {
tableMap[startRow + i] = [];
}
for (let j = 0; j < colSpan; j++) {
tableMap[startRow + i][startColumn + j] = value;
}
}
if (cellA.is(cell)) {
cellAValue = value;
}
if (cellB.is(cell)) {
cellBValue = value;
}
}
function isEmpty(row: number, column: number) {
return tableMap[row] === undefined || tableMap[row][column] === undefined;
}
const gridChildren = grid.getChildren();
for (let i = 0; i < gridChildren.length; i++) {
const row = gridChildren[i];
invariant(
$isGridRowNode(row),
'Expected GridNode children to be GridRowNode',
);
const rowChildren = row.getChildren();
let j = 0;
for (const cell of rowChildren) {
invariant(
$isGridCellNode(cell),
'Expected GridRowNode children to be GridCellNode',
);
while (!isEmpty(i, j)) {
j++;
}
write(i, j, cell);
j += cell.__colSpan;
}
}
invariant(cellAValue !== null, 'Anchor not found in Grid');
invariant(cellBValue !== null, 'Focus not found in Grid');
return [tableMap, cellAValue, cellBValue];
}
export function $getNodeTriplet(
source: PointType | LexicalNode | GridCellNode,
): [GridCellNode, GridRowNode, GridNode] {
let cell: GridCellNode;
if (source instanceof GridCellNode) {
cell = source;
} else if ('__type' in source) {
const cell_ = $findMatchingParent(source, $isGridCellNode);
invariant($isGridCellNode(cell_), 'Expected to find a parent GridCellNode');
cell = cell_;
} else {
const cell_ = $findMatchingParent(source.getNode(), $isGridCellNode);
invariant($isGridCellNode(cell_), 'Expected to find a parent GridCellNode');
cell = cell_;
}
const row = cell.getParent();
invariant(
$isGridRowNode(row),
'Expected GridCellNode to have a parent GridRowNode',
);
const grid = row.getParent();
invariant(
$isGridNode(grid),
'Expected GridRowNode to have a parent GridNode',
);
return [cell, row, grid];
}
export function $getGridCellNodeRect(gridCellNode: GridCellNode): {
rowIndex: number;
columnIndex: number;
rowSpan: number;
colSpan: number;
} | null {
const [CellNode, , gridNode] = $getNodeTriplet(gridCellNode);
const rows = gridNode.getChildren<GridRowNode>();
const rowCount = rows.length;
const columnCount = rows[0].getChildren().length;
// Create a matrix of the same size as the table to track the position of each cell
const cellMatrix = new Array(rowCount);
for (let i = 0; i < rowCount; i++) {
cellMatrix[i] = new Array(columnCount);
}
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
const row = rows[rowIndex];
const cells = row.getChildren<GridCellNode>();
let columnIndex = 0;
for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) {
// Find the next available position in the matrix, skip the position of merged cells
while (cellMatrix[rowIndex][columnIndex]) {
columnIndex++;
}
const cell = cells[cellIndex];
const rowSpan = cell.__rowSpan || 1;
const colSpan = cell.__colSpan || 1;
// Put the cell into the corresponding position in the matrix
for (let i = 0; i < rowSpan; i++) {
for (let j = 0; j < colSpan; j++) {
cellMatrix[rowIndex + i][columnIndex + j] = cell;
}
}
// Return to the original index, row span and column span of the cell.
if (CellNode === cell) {
return {
colSpan,
columnIndex,
rowIndex,
rowSpan,
};
}
columnIndex += colSpan;
}
}
return null;
}

View File

@ -11,6 +11,9 @@ import type {LexicalCommand} from 'lexical';
import {createCommand} from 'lexical';
export {$isGridCellNode, GridCellNode} from './LexicalGridCellNode';
export {$isGridNode, GridNode} from './LexicalGridNode';
export {$isGridRowNode, GridRowNode} from './LexicalGridRowNode';
export type {GridSelection, GridSelectionShape} from './LexicalGridSelection';
export {$createGridSelection, $isGridSelection} from './LexicalGridSelection';
export type {SerializedTableCellNode} from './LexicalTableCellNode';
@ -42,10 +45,13 @@ export {
getTableSelectionFromTableElement,
} from './LexicalTableSelectionHelpers';
export {
$computeGridMap,
$createTableNodeWithDimensions,
$deleteTableColumn,
$deleteTableColumn__EXPERIMENTAL,
$deleteTableRow__EXPERIMENTAL,
$getGridCellNodeRect,
$getNodeTriplet,
$getTableCellNodeFromLexicalNode,
$getTableColumnIndexFromTableCellNode,
$getTableNodeFromLexicalNodeOrThrow,

View File

@ -535,20 +535,7 @@ declare export function $isRangeSelection(
declare export function $getSelection(): null | BaseSelection;
declare export function $getPreviousSelection(): null | BaseSelection;
declare export function $insertNodes(nodes: Array<LexicalNode>): void;
export type GridMapValueType = {
cell: deprecated_GridCellNode,
startRow: number,
startColumn: number,
};
export type GridMapType = Array<Array<GridMapValueType>>;
declare export function DEPRECATED_$computeGridMap(
grid: deprecated_GridNode,
cellA: deprecated_GridCellNode,
cellB: deprecated_GridCellNode,
): [GridMapType, GridMapValueType, GridMapValueType];
declare export function DEPRECATED_$getNodeTriplet(
source: PointType | LexicalNode | deprecated_GridCellNode,
): [deprecated_GridCellNode, deprecated_GridRowNode, deprecated_GridNode];
/**
* LexicalTextNode
@ -806,33 +793,6 @@ declare export function $isParagraphNode(
node: ?LexicalNode,
): node is ParagraphNode;
declare export class deprecated_GridNode extends ElementNode {}
declare export function DEPRECATED_$isGridNode(
node: ?LexicalNode,
): node is deprecated_GridNode;
declare export class deprecated_GridRowNode extends ElementNode {}
declare export function DEPRECATED_$isGridRowNode(
node: ?LexicalNode,
): node is deprecated_GridRowNode;
declare export class deprecated_GridCellNode extends ElementNode {
__colSpan: number;
__rowSpan: number;
constructor(colSpan: number, key?: NodeKey): void;
getColSpan(): number;
setColSpan(colSpan: number): this;
getRowSpan(): number;
setRowSpan(rowSpan: number): this;
}
declare export function DEPRECATED_$isGridCellNode(
node: ?LexicalNode,
): node is deprecated_GridCellNode;
/**
* LexicalUtils
*/

View File

@ -24,12 +24,6 @@ import {
$isRootNode,
$isTextNode,
$setSelection,
DEPRECATED_$isGridCellNode,
DEPRECATED_$isGridNode,
DEPRECATED_$isGridRowNode,
DEPRECATED_GridCellNode,
DEPRECATED_GridNode,
DEPRECATED_GridRowNode,
SELECTION_CHANGE_COMMAND,
TextNode,
} from '.';
@ -46,7 +40,6 @@ import {
isCurrentlyReadOnlyMode,
} from './LexicalUpdates';
import {
$findMatchingParent,
$getAdjacentNode,
$getAncestor,
$getCompositionKey,
@ -95,13 +88,6 @@ export type ElementPointType = {
export type PointType = TextPointType | ElementPointType;
export type GridMapValueType = {
cell: DEPRECATED_GridCellNode;
startRow: number;
startColumn: number;
};
export type GridMapType = Array<Array<GridMapValueType>>;
export class Point {
key: NodeKey;
offset: number;
@ -408,64 +394,6 @@ export function $isRangeSelection(x: unknown): x is RangeSelection {
return x instanceof RangeSelection;
}
export function DEPRECATED_$getGridCellNodeRect(
GridCellNode: DEPRECATED_GridCellNode,
): {
rowIndex: number;
columnIndex: number;
rowSpan: number;
colSpan: number;
} | null {
const [CellNode, , GridNode] = DEPRECATED_$getNodeTriplet(GridCellNode);
const rows = GridNode.getChildren<DEPRECATED_GridRowNode>();
const rowCount = rows.length;
const columnCount = rows[0].getChildren().length;
// Create a matrix of the same size as the table to track the position of each cell
const cellMatrix = new Array(rowCount);
for (let i = 0; i < rowCount; i++) {
cellMatrix[i] = new Array(columnCount);
}
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
const row = rows[rowIndex];
const cells = row.getChildren<DEPRECATED_GridCellNode>();
let columnIndex = 0;
for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) {
// Find the next available position in the matrix, skip the position of merged cells
while (cellMatrix[rowIndex][columnIndex]) {
columnIndex++;
}
const cell = cells[cellIndex];
const rowSpan = cell.__rowSpan || 1;
const colSpan = cell.__colSpan || 1;
// Put the cell into the corresponding position in the matrix
for (let i = 0; i < rowSpan; i++) {
for (let j = 0; j < colSpan; j++) {
cellMatrix[rowIndex + i][columnIndex + j] = cell;
}
}
// Return to the original index, row span and column span of the cell.
if (CellNode === cell) {
return {
colSpan,
columnIndex,
rowIndex,
rowSpan,
};
}
columnIndex += colSpan;
}
}
return null;
}
export class RangeSelection implements BaseSelection {
format: number;
style: string;
@ -2721,108 +2649,6 @@ export function $getTextContent(): string {
return selection.getTextContent();
}
export function DEPRECATED_$computeGridMap(
grid: DEPRECATED_GridNode,
cellA: DEPRECATED_GridCellNode,
cellB: DEPRECATED_GridCellNode,
): [GridMapType, GridMapValueType, GridMapValueType] {
const tableMap: GridMapType = [];
let cellAValue: null | GridMapValueType = null;
let cellBValue: null | GridMapValueType = null;
function write(
startRow: number,
startColumn: number,
cell: DEPRECATED_GridCellNode,
) {
const value = {
cell,
startColumn,
startRow,
};
const rowSpan = cell.__rowSpan;
const colSpan = cell.__colSpan;
for (let i = 0; i < rowSpan; i++) {
if (tableMap[startRow + i] === undefined) {
tableMap[startRow + i] = [];
}
for (let j = 0; j < colSpan; j++) {
tableMap[startRow + i][startColumn + j] = value;
}
}
if (cellA.is(cell)) {
cellAValue = value;
}
if (cellB.is(cell)) {
cellBValue = value;
}
}
function isEmpty(row: number, column: number) {
return tableMap[row] === undefined || tableMap[row][column] === undefined;
}
const gridChildren = grid.getChildren();
for (let i = 0; i < gridChildren.length; i++) {
const row = gridChildren[i];
invariant(
DEPRECATED_$isGridRowNode(row),
'Expected GridNode children to be GridRowNode',
);
const rowChildren = row.getChildren();
let j = 0;
for (const cell of rowChildren) {
invariant(
DEPRECATED_$isGridCellNode(cell),
'Expected GridRowNode children to be GridCellNode',
);
while (!isEmpty(i, j)) {
j++;
}
write(i, j, cell);
j += cell.__colSpan;
}
}
invariant(cellAValue !== null, 'Anchor not found in Grid');
invariant(cellBValue !== null, 'Focus not found in Grid');
return [tableMap, cellAValue, cellBValue];
}
export function DEPRECATED_$getNodeTriplet(
source: PointType | LexicalNode | DEPRECATED_GridCellNode,
): [DEPRECATED_GridCellNode, DEPRECATED_GridRowNode, DEPRECATED_GridNode] {
let cell: DEPRECATED_GridCellNode;
if (source instanceof DEPRECATED_GridCellNode) {
cell = source;
} else if (source instanceof LexicalNode) {
const cell_ = $findMatchingParent(source, DEPRECATED_$isGridCellNode);
invariant(
DEPRECATED_$isGridCellNode(cell_),
'Expected to find a parent GridCellNode',
);
cell = cell_;
} else {
const cell_ = $findMatchingParent(
source.getNode(),
DEPRECATED_$isGridCellNode,
);
invariant(
DEPRECATED_$isGridCellNode(cell_),
'Expected to find a parent GridCellNode',
);
cell = cell_;
}
const row = cell.getParent();
invariant(
DEPRECATED_$isGridRowNode(row),
'Expected GridCellNode to have a parent GridRowNode',
);
const grid = row.getParent();
invariant(
DEPRECATED_$isGridNode(grid),
'Expected GridRowNode to have a parent GridNode',
);
return [cell, row, grid];
}
function removeTextAndSplitBlock(selection: RangeSelection): number {
if (!selection.isCollapsed()) {
selection.removeText();

View File

@ -43,8 +43,6 @@ export type {
export type {
BaseSelection,
ElementPointType as ElementPoint,
GridMapType,
GridMapValueType,
NodeSelection,
Point,
PointType,
@ -55,7 +53,6 @@ export type {
ElementFormatType,
SerializedElementNode,
} from './nodes/LexicalElementNode';
export type {SerializedGridCellNode} from './nodes/LexicalGridCellNode';
export type {SerializedRootNode} from './nodes/LexicalRootNode';
export type {
SerializedTextNode,
@ -134,9 +131,6 @@ export {
$isBlockElementNode,
$isNodeSelection,
$isRangeSelection,
DEPRECATED_$computeGridMap,
DEPRECATED_$getGridCellNodeRect,
DEPRECATED_$getNodeTriplet,
} from './LexicalSelection';
export {$parseSerializedNode, isCurrentlyReadOnlyMode} from './LexicalUpdates';
export {
@ -166,18 +160,6 @@ export {
} from './LexicalUtils';
export {$isDecoratorNode, DecoratorNode} from './nodes/LexicalDecoratorNode';
export {$isElementNode, ElementNode} from './nodes/LexicalElementNode';
export {
DEPRECATED_$isGridCellNode,
DEPRECATED_GridCellNode,
} from './nodes/LexicalGridCellNode';
export {
DEPRECATED_$isGridNode,
DEPRECATED_GridNode,
} from './nodes/LexicalGridNode';
export {
DEPRECATED_$isGridRowNode,
DEPRECATED_GridRowNode,
} from './nodes/LexicalGridRowNode';
export type {SerializedLineBreakNode} from './nodes/LexicalLineBreakNode';
export {
$createLineBreakNode,

View File

@ -1,19 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalNode} from '../LexicalNode';
import {ElementNode} from './LexicalElementNode';
export class DEPRECATED_GridNode extends ElementNode {}
export function DEPRECATED_$isGridNode(
node: LexicalNode | null | undefined,
): node is DEPRECATED_GridNode {
return node instanceof DEPRECATED_GridNode;
}

View File

@ -1,19 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalNode} from '../LexicalNode';
import {ElementNode} from './LexicalElementNode';
export class DEPRECATED_GridRowNode extends ElementNode {}
export function DEPRECATED_$isGridRowNode(
node: LexicalNode | null | undefined,
): node is DEPRECATED_GridRowNode {
return node instanceof DEPRECATED_GridRowNode;
}