mirror of
https://github.com/facebook/lexical.git
synced 2025-08-06 08:30:33 +08:00
Rename GridSelection to TableSelection (#5534)
This commit is contained in:
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
assertGridSelectionCoordinates,
|
||||
assertTableSelectionCoordinates,
|
||||
click,
|
||||
focusEditor,
|
||||
initialize,
|
||||
@ -18,7 +18,7 @@ import {
|
||||
|
||||
test.describe('Regression test #4697', () => {
|
||||
test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
|
||||
test('repeated table selection results in grid selection', async ({
|
||||
test('repeated table selection results in table selection', async ({
|
||||
page,
|
||||
isPlainText,
|
||||
isCollab,
|
||||
@ -46,7 +46,7 @@ test.describe('Regression test #4697', () => {
|
||||
false,
|
||||
);
|
||||
|
||||
await assertGridSelectionCoordinates(page, {
|
||||
await assertTableSelectionCoordinates(page, {
|
||||
anchor: {x: 2, y: 1},
|
||||
focus: {x: 2, y: 2},
|
||||
});
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
import {
|
||||
assertGridSelectionCoordinates,
|
||||
assertTableSelectionCoordinates,
|
||||
click,
|
||||
focusEditor,
|
||||
initialize,
|
||||
@ -48,7 +48,7 @@ test.describe('Regression test #4872', () => {
|
||||
false,
|
||||
);
|
||||
|
||||
await assertGridSelectionCoordinates(page, {
|
||||
await assertTableSelectionCoordinates(page, {
|
||||
anchor: {x: 1, y: 4},
|
||||
focus: {x: 2, y: 4},
|
||||
});
|
||||
|
@ -216,15 +216,15 @@ async function retryAsync(page, fn, attempts) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function assertGridSelectionCoordinates(page, coordinates) {
|
||||
export async function assertTableSelectionCoordinates(page, coordinates) {
|
||||
const pageOrFrame = IS_COLLAB ? await page.frame('left') : page;
|
||||
|
||||
const {_anchor, _focus} = await pageOrFrame.evaluate(() => {
|
||||
const editor = window.lexicalEditor;
|
||||
const editorState = editor.getEditorState();
|
||||
const selection = editorState._selection;
|
||||
if (!selection.gridKey) {
|
||||
throw new Error('Expected grid selection');
|
||||
if (!selection.tableKey) {
|
||||
throw new Error('Expected table selection');
|
||||
}
|
||||
const anchorElement = editor.getElementByKey(selection.anchor.key);
|
||||
const focusElement = editor.getElementByKey(selection.focus.key);
|
||||
|
@ -20,16 +20,16 @@ import {
|
||||
$getTableRowIndexFromTableCellNode,
|
||||
$insertTableColumn__EXPERIMENTAL,
|
||||
$insertTableRow__EXPERIMENTAL,
|
||||
$isGridSelection,
|
||||
$isTableCellNode,
|
||||
$isTableRowNode,
|
||||
$isTableSelection,
|
||||
$unmergeCell,
|
||||
getTableObserverFromTableElement,
|
||||
GridSelection,
|
||||
HTMLTableElementWithWithTableSelectionState,
|
||||
TableCellHeaderStates,
|
||||
TableCellNode,
|
||||
TableRowNode,
|
||||
TableSelection,
|
||||
} from '@lexical/table';
|
||||
import {
|
||||
$createParagraphNode,
|
||||
@ -48,7 +48,7 @@ import invariant from 'shared/invariant';
|
||||
import useModal from '../../hooks/useModal';
|
||||
import ColorPicker from '../../ui/ColorPicker';
|
||||
|
||||
function computeSelectionCount(selection: GridSelection): {
|
||||
function computeSelectionCount(selection: TableSelection): {
|
||||
columns: number;
|
||||
rows: number;
|
||||
} {
|
||||
@ -61,7 +61,7 @@ function computeSelectionCount(selection: GridSelection): {
|
||||
|
||||
// This is important when merging cells as there is no good way to re-merge weird shapes (a result
|
||||
// of selecting merged cells and non-merged)
|
||||
function isGridSelectionRectangular(selection: GridSelection): boolean {
|
||||
function isTableSelectionRectangular(selection: TableSelection): boolean {
|
||||
const nodes = selection.getNodes();
|
||||
const currentRows: Array<number> = [];
|
||||
let currentRow = null;
|
||||
@ -105,8 +105,8 @@ function $canUnmerge(): boolean {
|
||||
const selection = $getSelection();
|
||||
if (
|
||||
($isRangeSelection(selection) && !selection.isCollapsed()) ||
|
||||
($isGridSelection(selection) && !selection.anchor.is(selection.focus)) ||
|
||||
(!$isRangeSelection(selection) && !$isGridSelection(selection))
|
||||
($isTableSelection(selection) && !selection.anchor.is(selection.focus)) ||
|
||||
(!$isRangeSelection(selection) && !$isTableSelection(selection))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@ -139,7 +139,7 @@ function $selectLastDescendant(node: ElementNode): void {
|
||||
function currentCellBackgroundColor(editor: LexicalEditor): null | string {
|
||||
return editor.getEditorState().read(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection) || $isGridSelection(selection)) {
|
||||
if ($isRangeSelection(selection) || $isTableSelection(selection)) {
|
||||
const [cell] = $getNodeTriplet(selection.anchor);
|
||||
if ($isTableCellNode(cell)) {
|
||||
return cell.getBackgroundColor();
|
||||
@ -200,11 +200,11 @@ function TableActionMenu({
|
||||
editor.getEditorState().read(() => {
|
||||
const selection = $getSelection();
|
||||
// Merge cells
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
const currentSelectionCounts = computeSelectionCount(selection);
|
||||
updateSelectionCounts(computeSelectionCount(selection));
|
||||
setCanMergeCells(
|
||||
isGridSelectionRectangular(selection) &&
|
||||
isTableSelectionRectangular(selection) &&
|
||||
(currentSelectionCounts.columns > 1 ||
|
||||
currentSelectionCounts.rows > 1),
|
||||
);
|
||||
@ -295,7 +295,7 @@ function TableActionMenu({
|
||||
const mergeTableCellsAtSelection = () => {
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
const {columns, rows} = computeSelectionCount(selection);
|
||||
const nodes = selection.getNodes();
|
||||
let firstCell: null | TableCellNode = null;
|
||||
@ -463,13 +463,13 @@ function TableActionMenu({
|
||||
(value: string) => {
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
if ($isRangeSelection(selection) || $isGridSelection(selection)) {
|
||||
if ($isRangeSelection(selection) || $isTableSelection(selection)) {
|
||||
const [cell] = $getNodeTriplet(selection.anchor);
|
||||
if ($isTableCellNode(cell)) {
|
||||
cell.setBackgroundColor(value);
|
||||
}
|
||||
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
const nodes = selection.getNodes();
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
|
@ -16,10 +16,10 @@ import {
|
||||
$getTableColumnIndexFromTableCellNode,
|
||||
$getTableNodeFromLexicalNodeOrThrow,
|
||||
$getTableRowIndexFromTableCellNode,
|
||||
$isGridSelection,
|
||||
$isTableCellNode,
|
||||
$isTableRowNode,
|
||||
getCellFromTarget,
|
||||
$isTableSelection,
|
||||
getDOMCellFromTarget,
|
||||
TableCellNode,
|
||||
} from '@lexical/table';
|
||||
import {
|
||||
@ -69,10 +69,10 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
|
||||
SELECTION_CHANGE_COMMAND,
|
||||
(payload) => {
|
||||
const selection = $getSelection();
|
||||
const isGridSelection = $isGridSelection(selection);
|
||||
const isTableSelection = $isTableSelection(selection);
|
||||
|
||||
if (isSelectingGrid !== isGridSelection) {
|
||||
updateIsSelectingGrid(isGridSelection);
|
||||
if (isSelectingGrid !== isTableSelection) {
|
||||
updateIsSelectingGrid(isTableSelection);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -108,7 +108,7 @@ function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
|
||||
|
||||
if (targetRef.current !== target) {
|
||||
targetRef.current = target as HTMLElement;
|
||||
const cell = getCellFromTarget(target as HTMLElement);
|
||||
const cell = getDOMCellFromTarget(target as HTMLElement);
|
||||
|
||||
if (cell && activeCell !== cell) {
|
||||
editor.update(() => {
|
||||
|
@ -15,7 +15,7 @@ import type {NodeKey} from 'lexical';
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {
|
||||
$computeGridMap,
|
||||
$computeTableMap,
|
||||
$createTableCellNode,
|
||||
$createTableNodeWithDimensions,
|
||||
$getNodeTriplet,
|
||||
@ -151,7 +151,7 @@ export function TablePlugin({
|
||||
// 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] = $getNodeTriplet(node);
|
||||
const [gridMap] = $computeGridMap(gridNode, node, node);
|
||||
const [gridMap] = $computeTableMap(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;
|
||||
|
@ -19,7 +19,7 @@ import type {
|
||||
import {$generateHtmlFromNodes} from '@lexical/html';
|
||||
import {$isLinkNode, LinkNode} from '@lexical/link';
|
||||
import {$isMarkNode} from '@lexical/mark';
|
||||
import {$isGridSelection, GridSelection} from '@lexical/table';
|
||||
import {$isTableSelection, TableSelection} from '@lexical/table';
|
||||
import {mergeRegister} from '@lexical/utils';
|
||||
import {
|
||||
$getRoot,
|
||||
@ -373,8 +373,8 @@ function printNodeSelection(selection: BaseSelection): string {
|
||||
return `: node\n └ [${Array.from(selection._nodes).join(', ')}]`;
|
||||
}
|
||||
|
||||
function printGridSelection(selection: GridSelection): string {
|
||||
return `: grid\n └ { grid: ${selection.gridKey}, anchorCell: ${selection.anchor.key}, focusCell: ${selection.focus.key} }`;
|
||||
function printTableSelection(selection: TableSelection): string {
|
||||
return `: table\n └ { table: ${selection.tableKey}, anchorCell: ${selection.anchor.key}, focusCell: ${selection.focus.key} }`;
|
||||
}
|
||||
|
||||
function generateContent(
|
||||
@ -427,8 +427,8 @@ function generateContent(
|
||||
? ': null'
|
||||
: $isRangeSelection(selection)
|
||||
? printRangeSelection(selection)
|
||||
: $isGridSelection(selection)
|
||||
? printGridSelection(selection)
|
||||
: $isTableSelection(selection)
|
||||
? printTableSelection(selection)
|
||||
: printNodeSelection(selection);
|
||||
});
|
||||
|
||||
|
@ -37,7 +37,7 @@ export const TableCellHeaderStates = {
|
||||
|
||||
export type TableCellHeaderState = $Values<typeof TableCellHeaderStates>;
|
||||
|
||||
declare export class TableCellNode extends GridCellNode {
|
||||
declare export class TableCellNode extends TableCellNode {
|
||||
__headerState: TableCellHeaderState;
|
||||
__width?: number;
|
||||
__backgroundColor: null | string;
|
||||
@ -81,24 +81,29 @@ declare export function $isTableCellNode(
|
||||
* LexicalTableNode
|
||||
*/
|
||||
|
||||
declare export class TableNode extends GridNode {
|
||||
export type TableMapValueType = {
|
||||
cell: TableCellNode,
|
||||
startRow: number,
|
||||
startColumn: number,
|
||||
};
|
||||
export type TableMapType = Array<Array<TableMapValueType>>;
|
||||
|
||||
declare export class TableNode extends TableNode {
|
||||
static getType(): string;
|
||||
static clone(node: TableNode): TableNode;
|
||||
constructor(grid: ?Grid, key?: NodeKey): void;
|
||||
constructor(key?: NodeKey): void;
|
||||
createDOM(config: EditorConfig): HTMLElement;
|
||||
updateDOM(prevNode: TableNode, dom: HTMLElement): boolean;
|
||||
insertNewAfter(selection: RangeSelection): null | ParagraphNode | TableNode;
|
||||
collapseAtStart(): true;
|
||||
getCordsFromCellNode(
|
||||
tableCellNode: TableCellNode,
|
||||
grid: Grid,
|
||||
table: TableDOMTable,
|
||||
): {x: number, y: number};
|
||||
getCellFromCords(x: number, y: number, grid: Grid): ?Cell;
|
||||
getCellFromCordsOrThrow(x: number, y: number, grid: Grid): Cell;
|
||||
getCellNodeFromCords(x: number, y: number, grid: Grid): ?TableCellNode;
|
||||
getCellNodeFromCordsOrThrow(x: number, y: number, grid: Grid): TableCellNode;
|
||||
setGrid(grid: ?Grid): TableNode;
|
||||
getGrid(): ?Grid;
|
||||
getDOMCellFromCords(x: number, y: number, table: TableDOMTable): ?TableDOMCell;
|
||||
getDOMCellFromCordsOrThrow(x: number, y: number, table: TableDOMTable): TableDOMCell;
|
||||
getCellNodeFromCords(x: number, y: number, table: TableDOMTable): ?TableCellNode;
|
||||
getCellNodeFromCordsOrThrow(x: number, y: number, table: TableDOMTable): TableCellNode;
|
||||
canSelectBefore(): true;
|
||||
}
|
||||
declare export function $createTableNode(): TableNode;
|
||||
@ -110,7 +115,7 @@ declare export function $isTableNode(
|
||||
* LexicalTableRowNode
|
||||
*/
|
||||
|
||||
declare export class TableRowNode extends GridRowNode {
|
||||
declare export class TableRowNode extends TableRowNode {
|
||||
static getType(): string;
|
||||
static clone(node: TableRowNode): TableRowNode;
|
||||
constructor(height?: ?number, key?: NodeKey): void;
|
||||
@ -142,7 +147,7 @@ export type TableDOMCell = {
|
||||
export type TableDOMRows = Array<Array<TableDOMCell>>;
|
||||
|
||||
export type TableDOMTable = {
|
||||
cells: Cells,
|
||||
cells: TableDOMRows,
|
||||
columns: number,
|
||||
rows: number,
|
||||
};
|
||||
@ -156,13 +161,13 @@ declare export function applyTableHandlers(
|
||||
declare export function $getElementForTableNode(
|
||||
editor: LexicalEditor,
|
||||
tableNode: TableNode,
|
||||
): Grid;
|
||||
): TableDOMTable;
|
||||
|
||||
declare export function getTableObserverFromTableElement(
|
||||
tableElement: HTMLElement,
|
||||
): null | TableObserver;
|
||||
|
||||
declare export function getCellFromTarget(node: Node): Cell | null;
|
||||
declare export function getDOMCellFromTarget(node: Node): null | TableDOMCell;
|
||||
|
||||
/**
|
||||
* LexicalTableUtils
|
||||
@ -204,7 +209,7 @@ declare export function $insertTableRow(
|
||||
targetIndex: number,
|
||||
shouldInsertAfter?: boolean,
|
||||
rowCount: number,
|
||||
grid: Grid,
|
||||
table: TableDOMTable,
|
||||
): TableNode;
|
||||
|
||||
declare export function $insertTableColumn(
|
||||
@ -212,7 +217,7 @@ declare export function $insertTableColumn(
|
||||
targetIndex: number,
|
||||
shouldInsertAfter?: boolean,
|
||||
columnCount: number,
|
||||
grid: Grid,
|
||||
table: TableDOMTable,
|
||||
): TableNode;
|
||||
|
||||
declare export function $deleteTableColumn(
|
||||
@ -235,16 +240,16 @@ declare export function $deleteTableColumn__EXPERIMENTAL(): void;
|
||||
declare export function $unmergeCell(): void;
|
||||
|
||||
declare export function $computeGridMap(
|
||||
grid: GridNode,
|
||||
cellA: GridCellNode,
|
||||
cellB: GridCellNode,
|
||||
): [GridMapType, GridMapValueType, GridMapValueType];
|
||||
table: TableNode,
|
||||
cellA: TableCellNode,
|
||||
cellB: TableCellNode,
|
||||
): [TableMapType, TableMapValueType, TableMapValueType];
|
||||
|
||||
declare export function $getNodeTriplet(
|
||||
source: PointType | LexicalNode | GridCellNode,
|
||||
): [GridCellNode, GridRowNode, GridNode];
|
||||
source: PointType | LexicalNode | TableCellNode,
|
||||
): [TableCellNode, TableRowNode, TableNode];
|
||||
|
||||
declare export function $getGridCellNodeRect(gridCellNode: GridCellNode): {
|
||||
declare export function $getTableCellNodeRect(tableCellNode: TableCellNode): {
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
rowSpan: number;
|
||||
@ -254,11 +259,12 @@ declare export function $getGridCellNodeRect(gridCellNode: GridCellNode): {
|
||||
/**
|
||||
* LexicalTableObserver.js
|
||||
*/
|
||||
|
||||
declare export class TableObserver {
|
||||
currentX: number;
|
||||
currentY: number;
|
||||
listenersToRemove: Set<() => void>;
|
||||
grid: Grid;
|
||||
table: TableDOMTable;
|
||||
isHighlightingCells: boolean;
|
||||
isMouseDown: boolean;
|
||||
startX: number;
|
||||
@ -266,42 +272,42 @@ declare export class TableObserver {
|
||||
nodeKey: string;
|
||||
editor: LexicalEditor;
|
||||
constructor(editor: LexicalEditor, nodeKey: string): void;
|
||||
getGrid(): Grid;
|
||||
getTable(): TableDOMTable;
|
||||
removeListeners(): void;
|
||||
trackTableGrid(): void;
|
||||
trackTable(): void;
|
||||
clearHighlight(): void;
|
||||
setFocusCellForSelection(cell: Cell): void;
|
||||
setAnchorCellForSelection(cell: Cell): void;
|
||||
setFocusCellForSelection(cell: TableDOMCell): void;
|
||||
setAnchorCellForSelection(cell: TableDOMCell): void;
|
||||
formatCells(type: TextFormatType): void;
|
||||
clearText(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* LexicalGridSelection.ts
|
||||
* LexicalTableSelection.ts
|
||||
*/
|
||||
|
||||
export type GridSelectionShape = {
|
||||
export type TableSelectionShape = {
|
||||
fromX: number,
|
||||
fromY: number,
|
||||
toX: number,
|
||||
toY: number,
|
||||
};
|
||||
declare export class GridSelection implements BaseSelection {
|
||||
gridKey: NodeKey;
|
||||
declare export class TableSelection implements BaseSelection {
|
||||
tableKey: NodeKey;
|
||||
anchor: PointType;
|
||||
focus: PointType;
|
||||
dirty: boolean;
|
||||
constructor(gridKey: NodeKey, anchor: PointType, focus: PointType): void;
|
||||
constructor(tableKey: NodeKey, anchor: PointType, focus: PointType): void;
|
||||
is(selection: null | BaseSelection): boolean;
|
||||
set(gridKey: NodeKey, anchorCellKey: NodeKey, focusCellKey: NodeKey): void;
|
||||
clone(): GridSelection;
|
||||
set(tableKey: NodeKey, anchorCellKey: NodeKey, focusCellKey: NodeKey): void;
|
||||
clone(): TableSelection;
|
||||
getCharacterOffsets(): [number, number];
|
||||
extract(): Array<LexicalNode>;
|
||||
insertRawText(): void;
|
||||
insertText(): void;
|
||||
isCollapsed(): false;
|
||||
isBackward(): boolean;
|
||||
getShape(): GridSelectionShape;
|
||||
getShape(): TableSelectionShape;
|
||||
getNodes(): Array<LexicalNode>;
|
||||
getTextContent(): string;
|
||||
insertNodes(nodes: Array<LexicalNode>): void;
|
||||
@ -310,49 +316,11 @@ declare export class GridSelection implements BaseSelection {
|
||||
setCachedNodes(nodes: null | Array<LexicalNode>): void;
|
||||
}
|
||||
|
||||
declare export function $isGridSelection(
|
||||
declare export function $isTableSelection(
|
||||
x: ?mixed,
|
||||
): x is GridSelection;
|
||||
): x is TableSelection;
|
||||
|
||||
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;
|
||||
declare export function $createTableSelection(): TableSelection;
|
||||
|
||||
/**
|
||||
* LexicalTableCommands
|
||||
|
@ -126,12 +126,12 @@ export class TableNode extends ElementNode {
|
||||
|
||||
getCordsFromCellNode(
|
||||
tableCellNode: TableCellNode,
|
||||
grid: TableDOMTable,
|
||||
table: TableDOMTable,
|
||||
): {x: number; y: number} {
|
||||
const {rows, cells} = grid;
|
||||
const {rows, domRows} = table;
|
||||
|
||||
for (let y = 0; y < rows; y++) {
|
||||
const row = cells[y];
|
||||
const row = domRows[y];
|
||||
|
||||
if (row == null) {
|
||||
continue;
|
||||
@ -152,14 +152,14 @@ export class TableNode extends ElementNode {
|
||||
throw new Error('Cell not found in table.');
|
||||
}
|
||||
|
||||
getCellFromCords(
|
||||
getDOMCellFromCords(
|
||||
x: number,
|
||||
y: number,
|
||||
grid: TableDOMTable,
|
||||
): TableDOMCell | null {
|
||||
const {cells} = grid;
|
||||
table: TableDOMTable,
|
||||
): null | TableDOMCell {
|
||||
const {domRows} = table;
|
||||
|
||||
const row = cells[y];
|
||||
const row = domRows[y];
|
||||
|
||||
if (row == null) {
|
||||
return null;
|
||||
@ -174,12 +174,12 @@ export class TableNode extends ElementNode {
|
||||
return cell;
|
||||
}
|
||||
|
||||
getCellFromCordsOrThrow(
|
||||
getDOMCellFromCordsOrThrow(
|
||||
x: number,
|
||||
y: number,
|
||||
grid: TableDOMTable,
|
||||
table: TableDOMTable,
|
||||
): TableDOMCell {
|
||||
const cell = this.getCellFromCords(x, y, grid);
|
||||
const cell = this.getDOMCellFromCords(x, y, table);
|
||||
|
||||
if (!cell) {
|
||||
throw new Error('Cell not found at cords.');
|
||||
@ -191,9 +191,9 @@ export class TableNode extends ElementNode {
|
||||
getCellNodeFromCords(
|
||||
x: number,
|
||||
y: number,
|
||||
grid: TableDOMTable,
|
||||
): TableCellNode | null {
|
||||
const cell = this.getCellFromCords(x, y, grid);
|
||||
table: TableDOMTable,
|
||||
): null | TableCellNode {
|
||||
const cell = this.getDOMCellFromCords(x, y, table);
|
||||
|
||||
if (cell == null) {
|
||||
return null;
|
||||
@ -211,9 +211,9 @@ export class TableNode extends ElementNode {
|
||||
getCellNodeFromCordsOrThrow(
|
||||
x: number,
|
||||
y: number,
|
||||
grid: TableDOMTable,
|
||||
table: TableDOMTable,
|
||||
): TableCellNode {
|
||||
const node = this.getCellNodeFromCords(x, y, grid);
|
||||
const node = this.getCellNodeFromCords(x, y, table);
|
||||
|
||||
if (!node) {
|
||||
throw new Error('Node at cords not TableCellNode.');
|
||||
|
@ -27,13 +27,13 @@ import {
|
||||
import {CAN_USE_DOM} from 'shared/canUseDOM';
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
import {
|
||||
type GridSelection,
|
||||
$createGridSelection,
|
||||
$isGridSelection,
|
||||
} from './LexicalGridSelection';
|
||||
import {$isTableCellNode} from './LexicalTableCellNode';
|
||||
import {$isTableNode} from './LexicalTableNode';
|
||||
import {
|
||||
type TableSelection,
|
||||
$createTableSelection,
|
||||
$isTableSelection,
|
||||
} from './LexicalTableSelection';
|
||||
import {$updateDOMForSelection, getTable} from './LexicalTableSelectionHelpers';
|
||||
|
||||
export type TableDOMCell = {
|
||||
@ -47,7 +47,7 @@ export type TableDOMCell = {
|
||||
export type TableDOMRows = Array<Array<TableDOMCell | undefined> | undefined>;
|
||||
|
||||
export type TableDOMTable = {
|
||||
cells: TableDOMRows;
|
||||
domRows: TableDOMRows;
|
||||
columns: number;
|
||||
rows: number;
|
||||
};
|
||||
@ -69,7 +69,7 @@ export class TableObserver {
|
||||
anchorCellNodeKey: NodeKey | null;
|
||||
focusCellNodeKey: NodeKey | null;
|
||||
editor: LexicalEditor;
|
||||
gridSelection: GridSelection | null;
|
||||
tableSelection: TableSelection | null;
|
||||
hasHijackedSelectionStyles: boolean;
|
||||
|
||||
constructor(editor: LexicalEditor, tableNodeKey: string) {
|
||||
@ -82,11 +82,11 @@ export class TableObserver {
|
||||
this.tableNodeKey = tableNodeKey;
|
||||
this.editor = editor;
|
||||
this.table = {
|
||||
cells: [],
|
||||
columns: 0,
|
||||
domRows: [],
|
||||
rows: 0,
|
||||
};
|
||||
this.gridSelection = null;
|
||||
this.tableSelection = null;
|
||||
this.anchorCellNodeKey = null;
|
||||
this.focusCellNodeKey = null;
|
||||
this.anchorCell = null;
|
||||
@ -156,7 +156,7 @@ export class TableObserver {
|
||||
this.anchorY = -1;
|
||||
this.focusX = -1;
|
||||
this.focusY = -1;
|
||||
this.gridSelection = null;
|
||||
this.tableSelection = null;
|
||||
this.anchorCellNodeKey = null;
|
||||
this.focusCellNodeKey = null;
|
||||
this.anchorCell = null;
|
||||
@ -217,18 +217,18 @@ export class TableObserver {
|
||||
});
|
||||
}
|
||||
|
||||
updateTableGridSelection(selection: GridSelection | null): void {
|
||||
if (selection !== null && selection.gridKey === this.tableNodeKey) {
|
||||
updateTableTableSelection(selection: TableSelection | null): void {
|
||||
if (selection !== null && selection.tableKey === this.tableNodeKey) {
|
||||
const editor = this.editor;
|
||||
this.gridSelection = selection;
|
||||
this.tableSelection = selection;
|
||||
this.isHighlightingCells = true;
|
||||
this.disableHighlightStyle();
|
||||
$updateDOMForSelection(editor, this.table, this.gridSelection);
|
||||
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
||||
} else if (selection == null) {
|
||||
this.clearHighlight();
|
||||
} else {
|
||||
this.tableNodeKey = selection.gridKey;
|
||||
this.updateTableGridSelection(selection);
|
||||
this.tableNodeKey = selection.tableKey;
|
||||
this.updateTableTableSelection(selection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,27 +281,27 @@ export class TableObserver {
|
||||
const focusTableCellNode = $getNearestNodeFromDOMNode(cell.elem);
|
||||
|
||||
if (
|
||||
this.gridSelection != null &&
|
||||
this.tableSelection != null &&
|
||||
this.anchorCellNodeKey != null &&
|
||||
$isTableCellNode(focusTableCellNode)
|
||||
) {
|
||||
const focusNodeKey = focusTableCellNode.getKey();
|
||||
|
||||
this.gridSelection =
|
||||
this.gridSelection.clone() || $createGridSelection();
|
||||
this.tableSelection =
|
||||
this.tableSelection.clone() || $createTableSelection();
|
||||
|
||||
this.focusCellNodeKey = focusNodeKey;
|
||||
this.gridSelection.set(
|
||||
this.tableSelection.set(
|
||||
this.tableNodeKey,
|
||||
this.anchorCellNodeKey,
|
||||
this.focusCellNodeKey,
|
||||
);
|
||||
|
||||
$setSelection(this.gridSelection);
|
||||
$setSelection(this.tableSelection);
|
||||
|
||||
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined);
|
||||
|
||||
$updateDOMForSelection(editor, this.table, this.gridSelection);
|
||||
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -318,10 +318,10 @@ export class TableObserver {
|
||||
|
||||
if ($isTableCellNode(anchorTableCellNode)) {
|
||||
const anchorNodeKey = anchorTableCellNode.getKey();
|
||||
this.gridSelection =
|
||||
this.gridSelection != null
|
||||
? this.gridSelection.clone()
|
||||
: $createGridSelection();
|
||||
this.tableSelection =
|
||||
this.tableSelection != null
|
||||
? this.tableSelection.clone()
|
||||
: $createTableSelection();
|
||||
this.anchorCellNodeKey = anchorNodeKey;
|
||||
}
|
||||
});
|
||||
@ -331,7 +331,7 @@ export class TableObserver {
|
||||
this.editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
|
||||
if (!$isGridSelection(selection)) {
|
||||
if (!$isTableSelection(selection)) {
|
||||
invariant(false, 'Expected grid selection');
|
||||
}
|
||||
|
||||
@ -365,7 +365,7 @@ export class TableObserver {
|
||||
|
||||
const selection = $getSelection();
|
||||
|
||||
if (!$isGridSelection(selection)) {
|
||||
if (!$isTableSelection(selection)) {
|
||||
invariant(false, 'Expected grid selection');
|
||||
}
|
||||
|
||||
|
@ -23,37 +23,37 @@ import invariant from 'shared/invariant';
|
||||
import {$isTableCellNode, TableCellNode} from './LexicalTableCellNode';
|
||||
import {$isTableNode} from './LexicalTableNode';
|
||||
import {$isTableRowNode} from './LexicalTableRowNode';
|
||||
import {$computeGridMap, $getGridCellNodeRect} from './LexicalTableUtils';
|
||||
import {$computeTableMap, $getTableCellNodeRect} from './LexicalTableUtils';
|
||||
|
||||
export type GridSelectionShape = {
|
||||
export type TableSelectionShape = {
|
||||
fromX: number;
|
||||
fromY: number;
|
||||
toX: number;
|
||||
toY: number;
|
||||
};
|
||||
|
||||
export type GridMapValueType = {
|
||||
export type TableMapValueType = {
|
||||
cell: TableCellNode;
|
||||
startRow: number;
|
||||
startColumn: number;
|
||||
};
|
||||
export type GridMapType = Array<Array<GridMapValueType>>;
|
||||
export type TableMapType = Array<Array<TableMapValueType>>;
|
||||
|
||||
export class GridSelection implements BaseSelection {
|
||||
gridKey: NodeKey;
|
||||
export class TableSelection implements BaseSelection {
|
||||
tableKey: NodeKey;
|
||||
anchor: PointType;
|
||||
focus: PointType;
|
||||
_cachedNodes: Array<LexicalNode> | null;
|
||||
dirty: boolean;
|
||||
|
||||
constructor(gridKey: NodeKey, anchor: PointType, focus: PointType) {
|
||||
constructor(tableKey: NodeKey, anchor: PointType, focus: PointType) {
|
||||
this.anchor = anchor;
|
||||
this.focus = focus;
|
||||
anchor._selection = this;
|
||||
focus._selection = this;
|
||||
this._cachedNodes = null;
|
||||
this.dirty = false;
|
||||
this.gridKey = gridKey;
|
||||
this.tableKey = tableKey;
|
||||
}
|
||||
|
||||
getStartEndPoints(): [PointType, PointType] {
|
||||
@ -78,26 +78,26 @@ export class GridSelection implements BaseSelection {
|
||||
}
|
||||
|
||||
is(selection: null | BaseSelection): boolean {
|
||||
if (!$isGridSelection(selection)) {
|
||||
if (!$isTableSelection(selection)) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
this.gridKey === selection.gridKey &&
|
||||
this.tableKey === selection.tableKey &&
|
||||
this.anchor.is(selection.anchor) &&
|
||||
this.focus.is(selection.focus)
|
||||
);
|
||||
}
|
||||
|
||||
set(gridKey: NodeKey, anchorCellKey: NodeKey, focusCellKey: NodeKey): void {
|
||||
set(tableKey: NodeKey, anchorCellKey: NodeKey, focusCellKey: NodeKey): void {
|
||||
this.dirty = true;
|
||||
this.gridKey = gridKey;
|
||||
this.tableKey = tableKey;
|
||||
this.anchor.key = anchorCellKey;
|
||||
this.focus.key = focusCellKey;
|
||||
this._cachedNodes = null;
|
||||
}
|
||||
|
||||
clone(): GridSelection {
|
||||
return new GridSelection(this.gridKey, this.anchor, this.focus);
|
||||
clone(): TableSelection {
|
||||
return new TableSelection(this.tableKey, this.anchor, this.focus);
|
||||
}
|
||||
|
||||
isCollapsed(): boolean {
|
||||
@ -120,7 +120,7 @@ export class GridSelection implements BaseSelection {
|
||||
const focusNode = this.focus.getNode();
|
||||
invariant(
|
||||
$isElementNode(focusNode),
|
||||
'Expected GridSelection focus to be an ElementNode',
|
||||
'Expected TableSelection focus to be an ElementNode',
|
||||
);
|
||||
const selection = $normalizeSelection__EXPERIMENTAL(
|
||||
focusNode.select(0, focusNode.getChildrenSize()),
|
||||
@ -129,13 +129,13 @@ export class GridSelection implements BaseSelection {
|
||||
}
|
||||
|
||||
// TODO Deprecate this method. It's confusing when used with colspan|rowspan
|
||||
getShape(): GridSelectionShape {
|
||||
getShape(): TableSelectionShape {
|
||||
const anchorCellNode = $getNodeByKey(this.anchor.key);
|
||||
invariant(
|
||||
$isTableCellNode(anchorCellNode),
|
||||
'Expected GridSelection anchor to be (or a child of) GridCellNode',
|
||||
'Expected TableSelection anchor to be (or a child of) TableCellNode',
|
||||
);
|
||||
const anchorCellNodeRect = $getGridCellNodeRect(anchorCellNode);
|
||||
const anchorCellNodeRect = $getTableCellNodeRect(anchorCellNode);
|
||||
invariant(
|
||||
anchorCellNodeRect !== null,
|
||||
'getCellRect: expected to find AnchorNode',
|
||||
@ -144,9 +144,9 @@ export class GridSelection implements BaseSelection {
|
||||
const focusCellNode = $getNodeByKey(this.focus.key);
|
||||
invariant(
|
||||
$isTableCellNode(focusCellNode),
|
||||
'Expected GridSelection focus to be (or a child of) GridCellNode',
|
||||
'Expected TableSelection focus to be (or a child of) TableCellNode',
|
||||
);
|
||||
const focusCellNodeRect = $getGridCellNodeRect(focusCellNode);
|
||||
const focusCellNodeRect = $getTableCellNodeRect(focusCellNode);
|
||||
invariant(
|
||||
focusCellNodeRect !== null,
|
||||
'getCellRect: expected to find focusCellNode',
|
||||
@ -191,30 +191,30 @@ export class GridSelection implements BaseSelection {
|
||||
const focusCell = $findMatchingParent(focusNode, $isTableCellNode);
|
||||
invariant(
|
||||
$isTableCellNode(anchorCell),
|
||||
'Expected GridSelection anchor to be (or a child of) GridCellNode',
|
||||
'Expected TableSelection anchor to be (or a child of) TableCellNode',
|
||||
);
|
||||
invariant(
|
||||
$isTableCellNode(focusCell),
|
||||
'Expected GridSelection focus to be (or a child of) GridCellNode',
|
||||
'Expected TableSelection focus to be (or a child of) TableCellNode',
|
||||
);
|
||||
const anchorRow = anchorCell.getParent();
|
||||
invariant(
|
||||
$isTableRowNode(anchorRow),
|
||||
'Expected anchorCell to have a parent GridRowNode',
|
||||
'Expected anchorCell to have a parent TableRowNode',
|
||||
);
|
||||
const gridNode = anchorRow.getParent();
|
||||
const tableNode = anchorRow.getParent();
|
||||
invariant(
|
||||
$isTableNode(gridNode),
|
||||
'Expected tableNode to have a parent GridNode',
|
||||
$isTableNode(tableNode),
|
||||
'Expected tableNode to have a parent TableNode',
|
||||
);
|
||||
|
||||
const focusCellGrid = focusCell.getParents()[1];
|
||||
if (focusCellGrid !== gridNode) {
|
||||
if (!gridNode.isParentOf(focusCell)) {
|
||||
if (focusCellGrid !== tableNode) {
|
||||
if (!tableNode.isParentOf(focusCell)) {
|
||||
// focus is on higher Grid level than anchor
|
||||
const gridParent = gridNode.getParent();
|
||||
const gridParent = tableNode.getParent();
|
||||
invariant(gridParent != null, 'Expected gridParent to have a parent');
|
||||
this.set(this.gridKey, gridParent.getKey(), focusCell.getKey());
|
||||
this.set(this.tableKey, gridParent.getKey(), focusCell.getKey());
|
||||
} else {
|
||||
// anchor is on higher Grid level than focus
|
||||
const focusCellParent = focusCellGrid.getParent();
|
||||
@ -222,17 +222,17 @@ export class GridSelection implements BaseSelection {
|
||||
focusCellParent != null,
|
||||
'Expected focusCellParent to have a parent',
|
||||
);
|
||||
this.set(this.gridKey, focusCell.getKey(), focusCellParent.getKey());
|
||||
this.set(this.tableKey, focusCell.getKey(), focusCellParent.getKey());
|
||||
}
|
||||
return this.getNodes();
|
||||
}
|
||||
|
||||
// TODO Mapping the whole Grid every time not efficient. We need to compute the entire state only
|
||||
// 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
|
||||
// ability to store a state. Killing TableSelection and moving the logic to the plugin would make
|
||||
// this possible.
|
||||
const [map, cellAMap, cellBMap] = $computeGridMap(
|
||||
gridNode,
|
||||
const [map, cellAMap, cellBMap] = $computeTableMap(
|
||||
tableNode,
|
||||
anchorCell,
|
||||
focusCell,
|
||||
);
|
||||
@ -251,7 +251,7 @@ export class GridSelection implements BaseSelection {
|
||||
let exploredMinRow = minRow;
|
||||
let exploredMaxColumn = minColumn;
|
||||
let exploredMaxRow = minRow;
|
||||
function expandBoundary(mapValue: GridMapValueType): void {
|
||||
function expandBoundary(mapValue: TableMapValueType): void {
|
||||
const {
|
||||
cell,
|
||||
startColumn: cellStartColumn,
|
||||
@ -306,7 +306,7 @@ export class GridSelection implements BaseSelection {
|
||||
}
|
||||
}
|
||||
|
||||
const nodes: Array<LexicalNode> = [gridNode];
|
||||
const nodes: Array<LexicalNode> = [tableNode];
|
||||
let lastRow = null;
|
||||
for (let i = minRow; i <= maxRow; i++) {
|
||||
for (let j = minColumn; j <= maxColumn; j++) {
|
||||
@ -314,7 +314,7 @@ export class GridSelection implements BaseSelection {
|
||||
const currentRow = cell.getParent();
|
||||
invariant(
|
||||
$isTableRowNode(currentRow),
|
||||
'Expected GridCellNode parent to be a GridRowNode',
|
||||
'Expected TableCellNode parent to be a TableRowNode',
|
||||
);
|
||||
if (currentRow !== lastRow) {
|
||||
nodes.push(currentRow);
|
||||
@ -340,14 +340,14 @@ export class GridSelection implements BaseSelection {
|
||||
}
|
||||
}
|
||||
|
||||
export function $isGridSelection(x: unknown): x is GridSelection {
|
||||
return x instanceof GridSelection;
|
||||
export function $isTableSelection(x: unknown): x is TableSelection {
|
||||
return x instanceof TableSelection;
|
||||
}
|
||||
|
||||
export function $createGridSelection(): GridSelection {
|
||||
export function $createTableSelection(): TableSelection {
|
||||
const anchor = $createPoint('root', 0, 'element');
|
||||
const focus = $createPoint('root', 0, 'element');
|
||||
return new GridSelection('root', anchor, focus);
|
||||
return new TableSelection('root', anchor, focus);
|
||||
}
|
||||
|
||||
export function $getChildrenRecursively(node: LexicalNode): Array<LexicalNode> {
|
@ -6,10 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import type {GridSelection} from './LexicalGridSelection';
|
||||
import type {TableCellNode} from './LexicalTableCellNode';
|
||||
import type {TableNode} from './LexicalTableNode';
|
||||
import type {TableDOMCell, TableDOMRows} from './LexicalTableObserver';
|
||||
import type {TableSelection} from './LexicalTableSelection';
|
||||
import type {
|
||||
BaseSelection,
|
||||
LexicalCommand,
|
||||
@ -50,11 +50,14 @@ import {
|
||||
} from 'lexical';
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
import {$createGridSelection, $isGridSelection} from './LexicalGridSelection';
|
||||
import {$isTableCellNode} from './LexicalTableCellNode';
|
||||
import {$isTableNode} from './LexicalTableNode';
|
||||
import {TableDOMTable, TableObserver} from './LexicalTableObserver';
|
||||
import {$isTableRowNode} from './LexicalTableRowNode';
|
||||
import {
|
||||
$createTableSelection,
|
||||
$isTableSelection,
|
||||
} from './LexicalTableSelection';
|
||||
|
||||
const LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';
|
||||
|
||||
@ -85,7 +88,7 @@ export function applyTableHandlers(
|
||||
return;
|
||||
}
|
||||
|
||||
const anchorCell = getCellFromTarget(event.target as Node);
|
||||
const anchorCell = getDOMCellFromTarget(event.target as Node);
|
||||
if (anchorCell !== null) {
|
||||
stopEvent(event);
|
||||
tableObserver.setAnchorCellForSelection(anchorCell);
|
||||
@ -97,7 +100,7 @@ export function applyTableHandlers(
|
||||
};
|
||||
|
||||
const onMouseMove = (moveEvent: MouseEvent) => {
|
||||
const focusCell = getCellFromTarget(moveEvent.target as Node);
|
||||
const focusCell = getDOMCellFromTarget(moveEvent.target as Node);
|
||||
if (
|
||||
focusCell !== null &&
|
||||
(tableObserver.anchorX !== focusCell.x ||
|
||||
@ -123,8 +126,8 @@ export function applyTableHandlers(
|
||||
const selection = $getSelection();
|
||||
const target = event.target as Node;
|
||||
if (
|
||||
$isGridSelection(selection) &&
|
||||
selection.gridKey === tableObserver.tableNodeKey &&
|
||||
$isTableSelection(selection) &&
|
||||
selection.tableKey === tableObserver.tableNodeKey &&
|
||||
rootElement.contains(target)
|
||||
) {
|
||||
tableObserver.clearHighlight();
|
||||
@ -178,7 +181,7 @@ export function applyTableHandlers(
|
||||
KEY_ESCAPE_COMMAND,
|
||||
(event) => {
|
||||
const selection = $getSelection();
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
const focusCellNode = $findMatchingParent(
|
||||
selection.focus.getNode(),
|
||||
$isTableCellNode,
|
||||
@ -203,7 +206,7 @@ export function applyTableHandlers(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
tableObserver.clearText();
|
||||
|
||||
return true;
|
||||
@ -297,7 +300,7 @@ export function applyTableHandlers(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
tableObserver.clearText();
|
||||
@ -343,7 +346,7 @@ export function applyTableHandlers(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
tableObserver.formatCells(payload);
|
||||
|
||||
return true;
|
||||
@ -374,7 +377,7 @@ export function applyTableHandlers(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($isGridSelection(selection)) {
|
||||
if ($isTableSelection(selection)) {
|
||||
tableObserver.clearHighlight();
|
||||
|
||||
return false;
|
||||
@ -453,7 +456,7 @@ export function applyTableHandlers(
|
||||
tableCellNode,
|
||||
tableObserver.table,
|
||||
);
|
||||
return tableNode.getCellFromCordsOrThrow(
|
||||
return tableNode.getDOMCellFromCordsOrThrow(
|
||||
currentCords.x,
|
||||
currentCords.y,
|
||||
tableObserver.table,
|
||||
@ -466,7 +469,7 @@ export function applyTableHandlers(
|
||||
(selectionPayload) => {
|
||||
const {nodes, selection} = selectionPayload;
|
||||
const anchorAndFocus = selection.getStartEndPoints();
|
||||
const isGridSelection = $isGridSelection(selection);
|
||||
const isTableSelection = $isTableSelection(selection);
|
||||
const isRangeSelection = $isRangeSelection(selection);
|
||||
const isSelectionInsideOfGrid =
|
||||
(isRangeSelection &&
|
||||
@ -476,7 +479,7 @@ export function applyTableHandlers(
|
||||
$findMatchingParent(selection.focus.getNode(), (n) =>
|
||||
$isTableCellNode(n),
|
||||
) !== null) ||
|
||||
isGridSelection;
|
||||
isTableSelection;
|
||||
|
||||
if (
|
||||
nodes.length !== 1 ||
|
||||
@ -584,13 +587,13 @@ export function applyTableHandlers(
|
||||
newRowIdx++;
|
||||
}
|
||||
if (newAnchorCellKey && newFocusCellKey) {
|
||||
const newGridSelection = $createGridSelection();
|
||||
newGridSelection.set(
|
||||
const newTableSelection = $createTableSelection();
|
||||
newTableSelection.set(
|
||||
nodes[0].getKey(),
|
||||
newAnchorCellKey,
|
||||
newFocusCellKey,
|
||||
);
|
||||
$setSelection(newGridSelection);
|
||||
$setSelection(newTableSelection);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
@ -648,21 +651,21 @@ export function applyTableHandlers(
|
||||
if (
|
||||
selection &&
|
||||
!selection.is(prevSelection) &&
|
||||
($isGridSelection(selection) || $isGridSelection(prevSelection)) &&
|
||||
tableObserver.gridSelection &&
|
||||
!tableObserver.gridSelection.is(prevSelection)
|
||||
($isTableSelection(selection) || $isTableSelection(prevSelection)) &&
|
||||
tableObserver.tableSelection &&
|
||||
!tableObserver.tableSelection.is(prevSelection)
|
||||
) {
|
||||
if (
|
||||
$isGridSelection(selection) &&
|
||||
selection.gridKey === tableObserver.tableNodeKey
|
||||
$isTableSelection(selection) &&
|
||||
selection.tableKey === tableObserver.tableNodeKey
|
||||
) {
|
||||
tableObserver.updateTableGridSelection(selection);
|
||||
tableObserver.updateTableTableSelection(selection);
|
||||
} else if (
|
||||
!$isGridSelection(selection) &&
|
||||
$isGridSelection(prevSelection) &&
|
||||
prevSelection.gridKey === tableObserver.tableNodeKey
|
||||
!$isTableSelection(selection) &&
|
||||
$isTableSelection(prevSelection) &&
|
||||
prevSelection.tableKey === tableObserver.tableNodeKey
|
||||
) {
|
||||
tableObserver.updateTableGridSelection(null);
|
||||
tableObserver.updateTableTableSelection(null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -704,7 +707,7 @@ export function getTableObserverFromTableElement(
|
||||
return tableElement[LEXICAL_ELEMENT_KEY];
|
||||
}
|
||||
|
||||
export function getCellFromTarget(node: Node): TableDOMCell | null {
|
||||
export function getDOMCellFromTarget(node: Node): TableDOMCell | null {
|
||||
let currentNode: ParentNode | Node | null = node;
|
||||
|
||||
while (currentNode != null) {
|
||||
@ -741,16 +744,16 @@ export function doesTargetContainText(node: Node): boolean {
|
||||
}
|
||||
|
||||
export function getTable(tableElement: HTMLElement): TableDOMTable {
|
||||
const cells: TableDOMRows = [];
|
||||
const domRows: TableDOMRows = [];
|
||||
const grid = {
|
||||
cells,
|
||||
columns: 0,
|
||||
domRows,
|
||||
rows: 0,
|
||||
};
|
||||
let currentNode = tableElement.firstChild;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
cells.length = 0;
|
||||
domRows.length = 0;
|
||||
|
||||
while (currentNode != null) {
|
||||
const nodeMame = currentNode.nodeName;
|
||||
@ -768,9 +771,9 @@ export function getTable(tableElement: HTMLElement): TableDOMTable {
|
||||
// @ts-expect-error: internal field
|
||||
currentNode._cell = cell;
|
||||
|
||||
let row = cells[y];
|
||||
let row = domRows[y];
|
||||
if (row === undefined) {
|
||||
row = cells[y] = [];
|
||||
row = domRows[y] = [];
|
||||
}
|
||||
|
||||
row[x] = cell;
|
||||
@ -815,7 +818,7 @@ export function getTable(tableElement: HTMLElement): TableDOMTable {
|
||||
export function $updateDOMForSelection(
|
||||
editor: LexicalEditor,
|
||||
table: TableDOMTable,
|
||||
selection: GridSelection | RangeSelection | null,
|
||||
selection: TableSelection | RangeSelection | null,
|
||||
) {
|
||||
const selectedCellNodes = new Set(selection ? selection.getNodes() : []);
|
||||
$forEachTableCell(table, (cell, lexicalNode) => {
|
||||
@ -845,10 +848,10 @@ export function $forEachTableCell(
|
||||
},
|
||||
) => void,
|
||||
) {
|
||||
const {cells} = grid;
|
||||
const {domRows} = grid;
|
||||
|
||||
for (let y = 0; y < cells.length; y++) {
|
||||
const row = cells[y];
|
||||
for (let y = 0; y < domRows.length; y++) {
|
||||
const row = domRows[y];
|
||||
if (!row) {
|
||||
continue;
|
||||
}
|
||||
@ -981,7 +984,7 @@ const adjustFocusNodeInDirection = (
|
||||
case 'forward':
|
||||
if (x !== (isForward ? tableObserver.table.columns - 1 : 0)) {
|
||||
tableObserver.setFocusCellForSelection(
|
||||
tableNode.getCellFromCordsOrThrow(
|
||||
tableNode.getDOMCellFromCordsOrThrow(
|
||||
x + (isForward ? 1 : -1),
|
||||
y,
|
||||
tableObserver.table,
|
||||
@ -993,7 +996,7 @@ const adjustFocusNodeInDirection = (
|
||||
case 'up':
|
||||
if (y !== 0) {
|
||||
tableObserver.setFocusCellForSelection(
|
||||
tableNode.getCellFromCordsOrThrow(x, y - 1, tableObserver.table),
|
||||
tableNode.getDOMCellFromCordsOrThrow(x, y - 1, tableObserver.table),
|
||||
);
|
||||
|
||||
return true;
|
||||
@ -1003,7 +1006,7 @@ const adjustFocusNodeInDirection = (
|
||||
case 'down':
|
||||
if (y !== tableObserver.table.rows - 1) {
|
||||
tableObserver.setFocusCellForSelection(
|
||||
tableNode.getCellFromCordsOrThrow(x, y + 1, tableObserver.table),
|
||||
tableNode.getDOMCellFromCordsOrThrow(x, y + 1, tableObserver.table),
|
||||
);
|
||||
|
||||
return true;
|
||||
@ -1019,7 +1022,7 @@ function $isSelectionInTable(
|
||||
selection: null | BaseSelection,
|
||||
tableNode: TableNode,
|
||||
): boolean {
|
||||
if ($isRangeSelection(selection) || $isGridSelection(selection)) {
|
||||
if ($isRangeSelection(selection) || $isTableSelection(selection)) {
|
||||
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
||||
const isFocusInside = tableNode.isParentOf(selection.focus.getNode());
|
||||
|
||||
@ -1185,7 +1188,7 @@ function $handleArrowKey(
|
||||
);
|
||||
|
||||
if (event.shiftKey) {
|
||||
const cell = tableNode.getCellFromCordsOrThrow(
|
||||
const cell = tableNode.getDOMCellFromCordsOrThrow(
|
||||
cords.x,
|
||||
cords.y,
|
||||
tableObserver.table,
|
||||
@ -1204,7 +1207,7 @@ function $handleArrowKey(
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if ($isGridSelection(selection)) {
|
||||
} else if ($isTableSelection(selection)) {
|
||||
const {anchor, focus} = selection;
|
||||
const anchorCellNode = $findMatchingParent(
|
||||
anchor.getNode(),
|
||||
@ -1227,11 +1230,11 @@ function $handleArrowKey(
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
tableObserver.updateTableGridSelection(selection);
|
||||
tableObserver.updateTableTableSelection(selection);
|
||||
|
||||
const grid = getTable(tableElement);
|
||||
const cordsAnchor = tableNode.getCordsFromCellNode(anchorCellNode, grid);
|
||||
const anchorCell = tableNode.getCellFromCordsOrThrow(
|
||||
const anchorCell = tableNode.getDOMCellFromCordsOrThrow(
|
||||
cordsAnchor.x,
|
||||
cordsAnchor.y,
|
||||
grid,
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import type {GridMapType, GridMapValueType} from './LexicalGridSelection';
|
||||
import type {TableMapType, TableMapValueType} from './LexicalTableSelection';
|
||||
import type {ElementNode, PointType} from 'lexical';
|
||||
|
||||
import {$findMatchingParent} from '@lexical/utils';
|
||||
@ -20,7 +20,6 @@ import {
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
import {InsertTableCommandPayloadHeaders} from '.';
|
||||
import {$isGridSelection} from './LexicalGridSelection';
|
||||
import {
|
||||
$createTableCellNode,
|
||||
$isTableCellNode,
|
||||
@ -34,6 +33,7 @@ import {
|
||||
$isTableRowNode,
|
||||
TableRowNode,
|
||||
} from './LexicalTableRowNode';
|
||||
import {$isTableSelection} from './LexicalTableSelection';
|
||||
|
||||
export function $createTableNodeWithDimensions(
|
||||
rowCount: number,
|
||||
@ -228,12 +228,12 @@ export function $insertTableRow(
|
||||
export function $insertTableRow__EXPERIMENTAL(insertAfter = true): void {
|
||||
const selection = $getSelection();
|
||||
invariant(
|
||||
$isRangeSelection(selection) || $isGridSelection(selection),
|
||||
$isRangeSelection(selection) || $isTableSelection(selection),
|
||||
'Expected a RangeSelection or GridSelection',
|
||||
);
|
||||
const focus = selection.focus.getNode();
|
||||
const [focusCell, , grid] = $getNodeTriplet(focus);
|
||||
const [gridMap, focusCellMap] = $computeGridMap(grid, focusCell, focusCell);
|
||||
const [gridMap, focusCellMap] = $computeTableMap(grid, focusCell, focusCell);
|
||||
const columnCount = gridMap[0].length;
|
||||
const {startRow: focusStartRow} = focusCellMap;
|
||||
if (insertAfter) {
|
||||
@ -344,14 +344,14 @@ export function $insertTableColumn(
|
||||
export function $insertTableColumn__EXPERIMENTAL(insertAfter = true): void {
|
||||
const selection = $getSelection();
|
||||
invariant(
|
||||
$isRangeSelection(selection) || $isGridSelection(selection),
|
||||
$isRangeSelection(selection) || $isTableSelection(selection),
|
||||
'Expected a RangeSelection or GridSelection',
|
||||
);
|
||||
const anchor = selection.anchor.getNode();
|
||||
const focus = selection.focus.getNode();
|
||||
const [anchorCell] = $getNodeTriplet(anchor);
|
||||
const [focusCell, , grid] = $getNodeTriplet(focus);
|
||||
const [gridMap, focusCellMap, anchorCellMap] = $computeGridMap(
|
||||
const [gridMap, focusCellMap, anchorCellMap] = $computeTableMap(
|
||||
grid,
|
||||
focusCell,
|
||||
anchorCell,
|
||||
@ -449,14 +449,14 @@ export function $deleteTableColumn(
|
||||
export function $deleteTableRow__EXPERIMENTAL(): void {
|
||||
const selection = $getSelection();
|
||||
invariant(
|
||||
$isRangeSelection(selection) || $isGridSelection(selection),
|
||||
$isRangeSelection(selection) || $isTableSelection(selection),
|
||||
'Expected a RangeSelection or GridSelection',
|
||||
);
|
||||
const anchor = selection.anchor.getNode();
|
||||
const focus = selection.focus.getNode();
|
||||
const [anchorCell, , grid] = $getNodeTriplet(anchor);
|
||||
const [focusCell] = $getNodeTriplet(focus);
|
||||
const [gridMap, anchorCellMap, focusCellMap] = $computeGridMap(
|
||||
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(
|
||||
grid,
|
||||
anchorCell,
|
||||
focusCell,
|
||||
@ -525,14 +525,14 @@ export function $deleteTableRow__EXPERIMENTAL(): void {
|
||||
export function $deleteTableColumn__EXPERIMENTAL(): void {
|
||||
const selection = $getSelection();
|
||||
invariant(
|
||||
$isRangeSelection(selection) || $isGridSelection(selection),
|
||||
$isRangeSelection(selection) || $isTableSelection(selection),
|
||||
'Expected a RangeSelection or GridSelection',
|
||||
);
|
||||
const anchor = selection.anchor.getNode();
|
||||
const focus = selection.focus.getNode();
|
||||
const [anchorCell, , grid] = $getNodeTriplet(anchor);
|
||||
const [focusCell] = $getNodeTriplet(focus);
|
||||
const [gridMap, anchorCellMap, focusCellMap] = $computeGridMap(
|
||||
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(
|
||||
grid,
|
||||
anchorCell,
|
||||
focusCell,
|
||||
@ -610,7 +610,7 @@ function $insertFirst(parent: ElementNode, node: LexicalNode): void {
|
||||
export function $unmergeCell(): void {
|
||||
const selection = $getSelection();
|
||||
invariant(
|
||||
$isRangeSelection(selection) || $isGridSelection(selection),
|
||||
$isRangeSelection(selection) || $isTableSelection(selection),
|
||||
'Expected a RangeSelection or GridSelection',
|
||||
);
|
||||
const anchor = selection.anchor.getNode();
|
||||
@ -624,7 +624,7 @@ export function $unmergeCell(): void {
|
||||
cell.setColSpan(1);
|
||||
}
|
||||
if (rowSpan > 1) {
|
||||
const [map, cellMap] = $computeGridMap(grid, cell, cell);
|
||||
const [map, cellMap] = $computeTableMap(grid, cell, cell);
|
||||
const {startColumn, startRow} = cellMap;
|
||||
let currentRowNode;
|
||||
for (let i = 1; i < rowSpan; i++) {
|
||||
@ -665,14 +665,14 @@ export function $unmergeCell(): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function $computeGridMap(
|
||||
export function $computeTableMap(
|
||||
grid: TableNode,
|
||||
cellA: TableCellNode,
|
||||
cellB: TableCellNode,
|
||||
): [GridMapType, GridMapValueType, GridMapValueType] {
|
||||
const tableMap: GridMapType = [];
|
||||
let cellAValue: null | GridMapValueType = null;
|
||||
let cellBValue: null | GridMapValueType = null;
|
||||
): [TableMapType, TableMapValueType, TableMapValueType] {
|
||||
const tableMap: TableMapType = [];
|
||||
let cellAValue: null | TableMapValueType = null;
|
||||
let cellBValue: null | TableMapValueType = null;
|
||||
function write(startRow: number, startColumn: number, cell: TableCellNode) {
|
||||
const value = {
|
||||
cell,
|
||||
@ -760,7 +760,7 @@ export function $getNodeTriplet(
|
||||
return [cell, row, grid];
|
||||
}
|
||||
|
||||
export function $getGridCellNodeRect(tableCellNode: TableCellNode): {
|
||||
export function $getTableCellNodeRect(tableCellNode: TableCellNode): {
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
rowSpan: number;
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import {$createGridSelection} from '@lexical/table';
|
||||
import {$createTableSelection} from '@lexical/table';
|
||||
import {
|
||||
type LexicalEditor,
|
||||
$createParagraphNode,
|
||||
@ -20,7 +20,7 @@ import {createRef, useEffect, useMemo} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import * as ReactTestUtils from 'react-dom/test-utils';
|
||||
|
||||
describe('grid selection', () => {
|
||||
describe('table selection', () => {
|
||||
let originalText;
|
||||
let parsedParagraph;
|
||||
let parsedRoot;
|
||||
@ -90,7 +90,7 @@ describe('grid selection', () => {
|
||||
await update(() => {
|
||||
const paragraph = $createParagraphNode();
|
||||
originalText = $createTextNode('Hello world');
|
||||
const selection = $createGridSelection();
|
||||
const selection = $createTableSelection();
|
||||
selection.set(
|
||||
originalText.getKey(),
|
||||
originalText.getKey(),
|
@ -7,8 +7,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
export type {GridSelection, GridSelectionShape} from './LexicalGridSelection';
|
||||
export {$createGridSelection, $isGridSelection} from './LexicalGridSelection';
|
||||
export type {SerializedTableCellNode} from './LexicalTableCellNode';
|
||||
export {
|
||||
$createTableCellNode,
|
||||
@ -36,21 +34,29 @@ export {
|
||||
$isTableRowNode,
|
||||
TableRowNode,
|
||||
} from './LexicalTableRowNode';
|
||||
export type {
|
||||
TableSelection,
|
||||
TableSelectionShape,
|
||||
} from './LexicalTableSelection';
|
||||
export {
|
||||
$createTableSelection,
|
||||
$isTableSelection,
|
||||
} from './LexicalTableSelection';
|
||||
export type {HTMLTableElementWithWithTableSelectionState} from './LexicalTableSelectionHelpers';
|
||||
export {
|
||||
applyTableHandlers,
|
||||
getCellFromTarget,
|
||||
getDOMCellFromTarget,
|
||||
getTableObserverFromTableElement,
|
||||
} from './LexicalTableSelectionHelpers';
|
||||
export {
|
||||
$computeGridMap,
|
||||
$computeTableMap,
|
||||
$createTableNodeWithDimensions,
|
||||
$deleteTableColumn,
|
||||
$deleteTableColumn__EXPERIMENTAL,
|
||||
$deleteTableRow__EXPERIMENTAL,
|
||||
$getGridCellNodeRect,
|
||||
$getNodeTriplet,
|
||||
$getTableCellNodeFromLexicalNode,
|
||||
$getTableCellNodeRect,
|
||||
$getTableColumnIndexFromTableCellNode,
|
||||
$getTableNodeFromLexicalNodeOrThrow,
|
||||
$getTableRowIndexFromTableCellNode,
|
||||
|
@ -131,5 +131,33 @@
|
||||
"129": "Expected parentElement of Text not to be null",
|
||||
"130": "LexicalNode: Node %s does not match the serialized type. Check if .exportJSON() is implemented and it is returning the correct type.",
|
||||
"131": "Expected to find LexicalNode from Table Cell DOMNode",
|
||||
"132": "Expected TextNode createDOM to always return a HTMLElement"
|
||||
"132": "Expected TextNode createDOM to always return a HTMLElement",
|
||||
"133": "Children of a root must be ElementNode",
|
||||
"134": "Expected RangeSelection after insertParagraph",
|
||||
"135": "Expected 'firstBlock' to be an ElementNode",
|
||||
"136": "Expected ancestor to be an ElementNode",
|
||||
"137": "LexicalNode: Node %s does not implement .isInline().",
|
||||
"138": "Children of root nodes must be elements",
|
||||
"139": "includeChildren should only be true for ElementNodes",
|
||||
"140": "insertRangeAfter: lastToInsert must be a later sibling of firstToInsert",
|
||||
"141": "Point.getNode() must return TextNode when type is text",
|
||||
"142": "Anchor node must be a TextNode",
|
||||
"143": "insertList: anchor should be defined",
|
||||
"144": "node is not a ListItemNode",
|
||||
"145": "focusEndRow is not a TableRowNode",
|
||||
"146": "Expected GridNode children to be TableRowNode",
|
||||
"147": "Expected TableRowNode children to be TableCellNode",
|
||||
"148": "Expected to find a parent TableCellNode",
|
||||
"149": "Expected TableCellNode to have a parent TableRowNode",
|
||||
"150": "Expected TableRowNode to have a parent GridNode",
|
||||
"151": "Expected TableSelection focus to be an ElementNode",
|
||||
"152": "Expected TableSelection anchor to be (or a child of) TableCellNode",
|
||||
"153": "getCellRect: expected to find AnchorNode",
|
||||
"154": "Expected TableSelection focus to be (or a child of) TableCellNode",
|
||||
"155": "getCellRect: expected to find focusCellNode",
|
||||
"156": "Expected anchorCell to have a parent TableRowNode",
|
||||
"157": "Expected tableNode to have a parent TableNode",
|
||||
"158": "Expected gridParent to have a parent",
|
||||
"159": "Expected focusCellParent to have a parent",
|
||||
"160": "Expected TableCellNode parent to be a TableRowNode"
|
||||
}
|
||||
|
Reference in New Issue
Block a user