From 6a239b6ae1807e9dae1b434482b5ecd9513e77fa Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Mon, 17 Apr 2023 22:19:34 +0100 Subject: [PATCH] Table Cell Background Color (#4306) --- .../__tests__/e2e/Tables.spec.mjs | 36 +++++- .../__tests__/utils/index.mjs | 5 + .../plugins/TableActionMenuPlugin/index.tsx | 77 +++++++++++-- .../src/plugins/ToolbarPlugin/index.tsx | 6 +- .../lexical-playground/src/ui/ColorPicker.tsx | 103 +++++++----------- .../src/ui/DropdownColorPicker.tsx | 41 +++++++ .../__tests__/unit/LexicalSelection.test.tsx | 2 +- .../lexical-table/src/LexicalTableCellNode.ts | 36 +++++- .../src/LexicalTableSelection.ts | 43 +++++--- .../src/LexicalTableSelectionHelpers.ts | 68 +++++++++--- .../unit/LexicalSerialization.test.ts | 4 +- 11 files changed, 307 insertions(+), 114 deletions(-) create mode 100644 packages/lexical-playground/src/ui/DropdownColorPicker.tsx diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 92b00fad215..fe3fa55aec8 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -36,6 +36,7 @@ import { SAMPLE_IMAGE_URL, selectCellsFromTableCords, selectFromAdditionalStylesDropdown, + setBackgroundColor, test, unmergeTableCell, } from '../utils/index.mjs'; @@ -1484,7 +1485,6 @@ test.describe('Tables', () => { ); await mergeTableCells(page); await insertTableColumnBefore(page); - await page.pause(); await assertHTML( page, @@ -1646,9 +1646,7 @@ test.describe('Tables', () => { await insertTable(page, 1, 1); await selectAll(page); - await page.pause(); await click(page, 'div[contenteditable="true"] p:first-of-type'); - await page.pause(); await assertSelection(page, { anchorOffset: 3, @@ -1657,4 +1655,36 @@ test.describe('Tables', () => { focusPath: [0, 0, 0], }); }); + + test('Background color to cell', async ({page, isPlainText}) => { + test.skip(isPlainText); + if (IS_COLLAB) { + // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) + page.setViewportSize({height: 1000, width: 3000}); + } + + await focusEditor(page); + + await insertTable(page, 1, 1); + await setBackgroundColor(page); + await click(page, '.color-picker-basic-color button'); + await click(page, '.Modal__closeButton'); + + await assertHTML( + page, + html` +


+ + + + +
+


+
+


+ `, + ); + }); }); diff --git a/packages/lexical-playground/__tests__/utils/index.mjs b/packages/lexical-playground/__tests__/utils/index.mjs index d3c62f3647d..60631a64b8d 100644 --- a/packages/lexical-playground/__tests__/utils/index.mjs +++ b/packages/lexical-playground/__tests__/utils/index.mjs @@ -826,6 +826,11 @@ export async function deleteTable(page) { await click(page, '.item[data-test-id="table-delete"]'); } +export async function setBackgroundColor(page) { + await click(page, '.table-cell-action-button-container'); + await click(page, '.item[data-test-id="table-background-color"]'); +} + export async function enableCompositionKeyEvents(page) { const targetPage = IS_COLLAB ? await page.frame('left') : page; await targetPage.evaluate(() => { diff --git a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx index c83c683ab5b..1af0f280d95 100644 --- a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx @@ -6,7 +6,11 @@ * */ -import type {DEPRECATED_GridCellNode, ElementNode} from 'lexical'; +import type { + DEPRECATED_GridCellNode, + ElementNode, + LexicalEditor, +} from 'lexical'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import useLexicalEditable from '@lexical/react/useLexicalEditable'; @@ -45,6 +49,9 @@ import {ReactPortal, useCallback, useEffect, useRef, useState} from 'react'; import {createPortal} from 'react-dom'; import invariant from 'shared/invariant'; +import useModal from '../../hooks/useModal'; +import ColorPicker from '../../ui/ColorPicker'; + function computeSelectionCount(selection: GridSelection): { columns: number; rows: number; @@ -134,10 +141,30 @@ function $selectLastDescendant(node: ElementNode): void { } } +function currentCellBackgroundColor(editor: LexicalEditor): null | string { + return editor.getEditorState().read(() => { + const selection = $getSelection(); + if ( + $isRangeSelection(selection) || + DEPRECATED_$isGridSelection(selection) + ) { + const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor); + if ($isTableCellNode(cell)) { + return cell.getBackgroundColor(); + } + } + return null; + }); +} + type TableCellActionMenuProps = Readonly<{ contextRef: {current: null | HTMLElement}; onClose: () => void; setIsMenuOpen: (isOpen: boolean) => void; + showColorPickerModal: ( + title: string, + showModal: (onClose: () => void) => JSX.Element, + ) => void; tableCellNode: TableCellNode; cellMerge: boolean; }>; @@ -148,6 +175,7 @@ function TableActionMenu({ setIsMenuOpen, contextRef, cellMerge, + showColorPickerModal, }: TableCellActionMenuProps) { const [editor] = useLexicalComposerContext(); const dropDownRef = useRef(null); @@ -158,6 +186,9 @@ function TableActionMenu({ }); const [canMergeCells, setCanMergeCells] = useState(false); const [canUnmergeCell, setCanUnmergeCell] = useState(false); + const [backgroundColor, setBackgroundColor] = useState( + () => currentCellBackgroundColor(editor) || '', + ); useEffect(() => { return editor.registerMutationListener(TableCellNode, (nodeMutations) => { @@ -168,6 +199,7 @@ function TableActionMenu({ editor.getEditorState().read(() => { updateTableCellNode(tableCellNode.getLatest()); }); + setBackgroundColor(currentCellBackgroundColor(editor) || ''); } }); }, [editor, tableCellNode]); @@ -410,6 +442,24 @@ function TableActionMenu({ }); }, [editor, tableCellNode, clearTableSelection, onClose]); + const handleCellBackgroundColor = useCallback( + (value: string) => { + editor.update(() => { + const selection = $getSelection(); + if ( + $isRangeSelection(selection) || + DEPRECATED_$isGridSelection(selection) + ) { + const [cell] = DEPRECATED_$getNodeTriplet(selection.anchor); + if ($isTableCellNode(cell)) { + cell.setBackgroundColor(value); + } + } + }); + }, + [editor], + ); + let mergeCellButton: null | JSX.Element = null; if (cellMerge) { if (canMergeCells) { @@ -441,12 +491,21 @@ function TableActionMenu({ onClick={(e) => { e.stopPropagation(); }}> - {mergeCellButton !== null && ( - <> - {mergeCellButton} -
- - )} + {mergeCellButton} + +
+ {colorPickerModal} {isMenuOpen && ( setIsMenuOpen(false)} tableCellNode={tableCellNode} cellMerge={cellMerge} + showColorPickerModal={showColorPickerModal} /> )} diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx index 5c1461cdd1f..600ed8a44c8 100644 --- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx @@ -75,8 +75,8 @@ import {IS_APPLE} from 'shared/environment'; import useModal from '../../hooks/useModal'; import catTypingGif from '../../images/cat-typing.gif'; import {$createStickyNode} from '../../nodes/StickyNode'; -import ColorPicker from '../../ui/ColorPicker'; import DropDown, {DropDownItem} from '../../ui/DropDown'; +import DropdownColorPicker from '../../ui/DropdownColorPicker'; import {getSelectedNode} from '../../utils/getSelectedNode'; import {sanitizeUrl} from '../../utils/url'; import {EmbedConfigs} from '../AutoEmbedPlugin'; @@ -759,7 +759,7 @@ export default function ToolbarPlugin(): JSX.Element { type="button"> - - void; - stopCloseOnClickSelf?: boolean; - title?: string; } const basicColors = [ @@ -50,11 +41,7 @@ const HEIGHT = 150; export default function ColorPicker({ color, - children, onChange, - disabled = false, - stopCloseOnClickSelf = true, - ...rest }: Readonly): JSX.Element { const [selfColor, setSelfColor] = useState(transformColor('hex', color)); const [inputColor, setInputColor] = useState(color); @@ -118,57 +105,51 @@ export default function ColorPicker({ }, [color]); return ( - -
- -
- {basicColors.map((basicColor) => ( -
- -
- - -
+ +
+ {basicColors.map((basicColor) => ( +
+
-
- {children} - +
+ +
+ +
+
); } diff --git a/packages/lexical-playground/src/ui/DropdownColorPicker.tsx b/packages/lexical-playground/src/ui/DropdownColorPicker.tsx new file mode 100644 index 00000000000..ca99ca23658 --- /dev/null +++ b/packages/lexical-playground/src/ui/DropdownColorPicker.tsx @@ -0,0 +1,41 @@ +/** + * 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 * as React from 'react'; + +import ColorPicker from './ColorPicker'; +import DropDown from './DropDown'; + +type Props = { + disabled?: boolean; + buttonAriaLabel?: string; + buttonClassName: string; + buttonIconClassName?: string; + buttonLabel?: string; + title?: string; + stopCloseOnClickSelf?: boolean; + color: string; + onChange?: (color: string) => void; +}; + +export default function DropdownColorPicker({ + disabled = false, + stopCloseOnClickSelf = true, + color, + onChange, + ...rest +}: Props) { + return ( + + + + ); +} diff --git a/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx b/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx index 5857d0c0ee6..5122194a452 100644 --- a/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx +++ b/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx @@ -2638,7 +2638,7 @@ describe('LexicalSelection tests', () => { }); expect(JSON.stringify(testEditor._pendingEditorState.toJSON())).toBe( - '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"children":[{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":3},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}', + '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"children":[{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":3},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1},{"children":[],"direction":null,"format":"","indent":0,"type":"heading","version":1,"tag":"h1"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}', ); }); }); diff --git a/packages/lexical-table/src/LexicalTableCellNode.ts b/packages/lexical-table/src/LexicalTableCellNode.ts index e68cfd2e160..2014b098830 100644 --- a/packages/lexical-table/src/LexicalTableCellNode.ts +++ b/packages/lexical-table/src/LexicalTableCellNode.ts @@ -41,6 +41,7 @@ export type SerializedTableCellNode = Spread< { headerState: TableCellHeaderState; width?: number; + backgroundColor?: null | string; }, SerializedGridCellNode >; @@ -51,20 +52,23 @@ export class TableCellNode extends DEPRECATED_GridCellNode { __headerState: TableCellHeaderState; /** @internal */ __width?: number; + /** @internal */ + __backgroundColor: null | string; static getType(): string { return 'tablecell'; } static clone(node: TableCellNode): TableCellNode { - const tableNode = new TableCellNode( + const cellNode = new TableCellNode( node.__headerState, node.__colSpan, node.__width, node.__key, ); - tableNode.__rowSpan = node.__rowSpan; - return tableNode; + cellNode.__rowSpan = node.__rowSpan; + cellNode.__backgroundColor = node.__backgroundColor; + return cellNode; } static importDOM(): DOMConversionMap | null { @@ -87,6 +91,7 @@ export class TableCellNode extends DEPRECATED_GridCellNode { serializedNode.width || undefined, ); cellNode.__rowSpan = serializedNode.rowSpan; + cellNode.__backgroundColor = serializedNode.backgroundColor || null; return cellNode; } @@ -99,6 +104,7 @@ export class TableCellNode extends DEPRECATED_GridCellNode { super(colSpan, key); this.__headerState = headerState; this.__width = width; + this.__backgroundColor = null; } createDOM(config: EditorConfig): HTMLElement { @@ -115,6 +121,9 @@ export class TableCellNode extends DEPRECATED_GridCellNode { if (this.__rowSpan > 1) { element.rowSpan = this.__rowSpan; } + if (this.__backgroundColor !== null) { + element.style.backgroundColor = this.__backgroundColor; + } addClassNamesToElement( element, @@ -146,7 +155,10 @@ export class TableCellNode extends DEPRECATED_GridCellNode { element_.style.verticalAlign = 'top'; element_.style.textAlign = 'start'; - if (this.hasHeader()) { + const backgroundColor = this.getBackgroundColor(); + if (backgroundColor !== null) { + element_.style.backgroundColor = backgroundColor; + } else if (this.hasHeader()) { element_.style.backgroundColor = '#f2f3f5'; } } @@ -159,6 +171,7 @@ export class TableCellNode extends DEPRECATED_GridCellNode { exportJSON(): SerializedTableCellNode { return { ...super.exportJSON(), + backgroundColor: this.getBackgroundColor(), headerState: this.__headerState, type: 'tablecell', width: this.getWidth(), @@ -189,6 +202,14 @@ export class TableCellNode extends DEPRECATED_GridCellNode { return this.getLatest().__width; } + getBackgroundColor(): null | string { + return this.__backgroundColor; + } + + setBackgroundColor(newBackgroundColor: null | string): void { + this.getWritable().__backgroundColor = newBackgroundColor; + } + toggleHeaderStyle(headerStateToToggle: TableCellHeaderState): TableCellNode { const self = this.getWritable(); @@ -214,7 +235,8 @@ export class TableCellNode extends DEPRECATED_GridCellNode { prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width || prevNode.__colSpan !== this.__colSpan || - prevNode.__rowSpan !== this.__rowSpan + prevNode.__rowSpan !== this.__rowSpan || + prevNode.__backgroundColor !== this.__backgroundColor ); } @@ -248,6 +270,10 @@ export function convertTableCellNodeElement( ); tableCellNode.__colSpan = domNode_.colSpan; tableCellNode.__rowSpan = domNode_.rowSpan; + const backgroundColor = domNode_.style.backgroundColor; + if (backgroundColor !== '') { + tableCellNode.__backgroundColor = backgroundColor; + } return { forChild: (lexicalNode, parentLexicalNode) => { diff --git a/packages/lexical-table/src/LexicalTableSelection.ts b/packages/lexical-table/src/LexicalTableSelection.ts index cc0aabcdad3..a6c1c27bab8 100644 --- a/packages/lexical-table/src/LexicalTableSelection.ts +++ b/packages/lexical-table/src/LexicalTableSelection.ts @@ -37,9 +37,12 @@ import { getTableGrid, } from './LexicalTableSelectionHelpers'; +export const BACKGROUND_COLOR = 'background-color'; +export const BACKGROUND_IMAGE = 'background-image'; export type Cell = { elem: HTMLElement; highlighted: boolean; + hasBackgroundColor: boolean; x: number; y: number; }; @@ -150,6 +153,7 @@ export class TableSelection { } clearHighlight() { + const editor = this.editor; this.isHighlightingCells = false; this.anchorX = -1; this.anchorY = -1; @@ -164,29 +168,30 @@ export class TableSelection { this.enableHighlightStyle(); - this.editor.update(() => { + editor.update(() => { const tableNode = $getNodeByKey(this.tableNodeKey); if (!$isTableNode(tableNode)) { throw new Error('Expected TableNode.'); } - const tableElement = this.editor.getElementByKey(this.tableNodeKey); + const tableElement = editor.getElementByKey(this.tableNodeKey); if (!tableElement) { throw new Error('Expected to find TableElement in DOM'); } const grid = getTableGrid(tableElement); - $updateDOMForSelection(grid, null); + $updateDOMForSelection(editor, grid, null); $setSelection(null); - this.editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); + editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); }); } enableHighlightStyle() { - this.editor.update(() => { - const tableElement = this.editor.getElementByKey(this.tableNodeKey); + const editor = this.editor; + editor.update(() => { + const tableElement = editor.getElementByKey(this.tableNodeKey); if (!tableElement) { throw new Error('Expected to find TableElement in DOM'); @@ -198,8 +203,9 @@ export class TableSelection { } disableHighlightStyle() { - this.editor.update(() => { - const tableElement = this.editor.getElementByKey(this.tableNodeKey); + const editor = this.editor; + editor.update(() => { + const tableElement = editor.getElementByKey(this.tableNodeKey); if (!tableElement) { throw new Error('Expected to find TableElement in DOM'); @@ -212,24 +218,26 @@ export class TableSelection { updateTableGridSelection(selection: GridSelection | null) { if (selection != null && selection.gridKey === this.tableNodeKey) { + const editor = this.editor; this.gridSelection = selection; this.isHighlightingCells = true; this.disableHighlightStyle(); - $updateDOMForSelection(this.grid, this.gridSelection); + $updateDOMForSelection(editor, this.grid, this.gridSelection); } else if (selection == null) { this.clearHighlight(); } } setFocusCellForSelection(cell: Cell, ignoreStart = false) { - this.editor.update(() => { + const editor = this.editor; + editor.update(() => { const tableNode = $getNodeByKey(this.tableNodeKey); if (!$isTableNode(tableNode)) { throw new Error('Expected TableNode.'); } - const tableElement = this.editor.getElementByKey(this.tableNodeKey); + const tableElement = editor.getElementByKey(this.tableNodeKey); if (!tableElement) { throw new Error('Expected to find TableElement in DOM'); @@ -240,7 +248,7 @@ export class TableSelection { this.focusCell = cell; if (this.anchorCell !== null) { - const domSelection = getDOMSelection(this.editor._window); + const domSelection = getDOMSelection(editor._window); // Collapse the selection if (domSelection) { domSelection.setBaseAndExtent( @@ -287,9 +295,9 @@ export class TableSelection { $setSelection(this.gridSelection); - this.editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); + editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); - $updateDOMForSelection(this.grid, this.gridSelection); + $updateDOMForSelection(editor, this.grid, this.gridSelection); } } }); @@ -340,7 +348,8 @@ export class TableSelection { } clearText() { - this.editor.update(() => { + const editor = this.editor; + editor.update(() => { const tableNode = $getNodeByKey(this.tableNodeKey); if (!$isTableNode(tableNode)) { @@ -378,11 +387,11 @@ export class TableSelection { } }); - $updateDOMForSelection(this.grid, null); + $updateDOMForSelection(editor, this.grid, null); $setSelection(null); - this.editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); + editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); }); } } diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts index 6bf61bc79f0..f2577a4f83c 100644 --- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts +++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts @@ -50,6 +50,7 @@ import { KEY_TAB_COMMAND, SELECTION_CHANGE_COMMAND, } from 'lexical'; +import invariant from 'shared/invariant'; import {$isTableCellNode} from './LexicalTableCellNode'; import {TableSelection} from './LexicalTableSelection'; @@ -905,7 +906,7 @@ export function applyTableHandlers( isRangeSelectionHijacked = true; $setSelection(modifiedSelection); - $addHighlightStyleToTable(tableSelection); + $addHighlightStyleToTable(editor, tableSelection); return true; } else if (selectionIsInsideTable) { @@ -967,13 +968,13 @@ export function applyTableHandlers( tableSelection.hasHijackedSelectionStyles && !tableNode.isSelected() ) { - $removeHighlightStyleToTable(tableSelection); + $removeHighlightStyleToTable(editor, tableSelection); isRangeSelectionHijacked = false; } else if ( !tableSelection.hasHijackedSelectionStyles && tableNode.isSelected() ) { - $addHighlightStyleToTable(tableSelection); + $addHighlightStyleToTable(editor, tableSelection); } return false; @@ -1056,6 +1057,7 @@ export function getTableGrid(tableElement: HTMLElement): Grid { const elem = currentNode as HTMLElement; const cell = { elem, + hasBackgroundColor: elem.style.backgroundColor !== '', highlighted: false, x, y, @@ -1108,6 +1110,7 @@ export function getTableGrid(tableElement: HTMLElement): Grid { } export function $updateDOMForSelection( + editor: LexicalEditor, grid: Grid, selection: GridSelection | RangeSelection | null, ): Array { @@ -1118,14 +1121,11 @@ export function $updateDOMForSelection( if (selectedCellNodes.has(lexicalNode)) { cell.highlighted = true; - elem.style.setProperty('background-color', 'rgb(172, 206, 247)'); - elem.style.setProperty('caret-color', 'transparent'); + $addHighlightToDOM(editor, cell); highlightedCells.push(cell); } else { cell.highlighted = false; - elem.style.removeProperty('background-color'); - elem.style.removeProperty('caret-color'); - + $removeHighlightFromDOM(editor, cell); if (!elem.getAttribute('style')) { elem.removeAttribute('style'); } @@ -1165,23 +1165,26 @@ export function $forEachGridCell( } } -export function $addHighlightStyleToTable(tableSelection: TableSelection) { +export function $addHighlightStyleToTable( + editor: LexicalEditor, + tableSelection: TableSelection, +) { tableSelection.disableHighlightStyle(); $forEachGridCell(tableSelection.grid, (cell) => { - const elem = cell.elem; cell.highlighted = true; - elem.style.setProperty('background-color', 'rgb(172, 206, 247)'); - elem.style.setProperty('caret-color', 'transparent'); + $addHighlightToDOM(editor, cell); }); } -export function $removeHighlightStyleToTable(tableSelection: TableSelection) { +export function $removeHighlightStyleToTable( + editor: LexicalEditor, + tableSelection: TableSelection, +) { tableSelection.enableHighlightStyle(); $forEachGridCell(tableSelection.grid, (cell) => { const elem = cell.elem; cell.highlighted = false; - elem.style.removeProperty('background-color'); - elem.style.removeProperty('caret-color'); + $removeHighlightFromDOM(editor, cell); if (!elem.getAttribute('style')) { elem.removeAttribute('style'); @@ -1326,3 +1329,38 @@ function selectTableCellNode(tableCell: TableCellNode) { tableCell.selectEnd(); } } + +const BROWSER_BLUE_RGB = '172,206,247'; +function $addHighlightToDOM(editor: LexicalEditor, cell: Cell): void { + const element = cell.elem; + const node = $getNearestNodeFromDOMNode(element); + invariant( + $isTableCellNode(node), + 'Expected to find LexicalNode from Table Cell DOMNode', + ); + const backgroundColor = node.getBackgroundColor(); + if (backgroundColor === null) { + element.style.setProperty('background-color', `rgb(${BROWSER_BLUE_RGB})`); + } else { + element.style.setProperty( + 'background-image', + `linear-gradient(to right, rgba(${BROWSER_BLUE_RGB},0.85), rgba(${BROWSER_BLUE_RGB},0.85))`, + ); + } + element.style.setProperty('caret-color', 'transparent'); +} + +function $removeHighlightFromDOM(editor: LexicalEditor, cell: Cell): void { + const element = cell.elem; + const node = $getNearestNodeFromDOMNode(element); + invariant( + $isTableCellNode(node), + 'Expected to find LexicalNode from Table Cell DOMNode', + ); + const backgroundColor = node.getBackgroundColor(); + if (backgroundColor === null) { + element.style.removeProperty('background-color'); + } + element.style.removeProperty('background-image'); + element.style.removeProperty('caret-color'); +} diff --git a/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts b/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts index 84d9a614cb6..7eb7846891e 100644 --- a/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts @@ -110,7 +110,7 @@ describe('LexicalSerialization tests', () => { }); const stringifiedEditorState = JSON.stringify(editor.getEditorState()); - const expectedStringifiedEditorState = `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":3},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1}],"direction":"ltr","format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`; + const expectedStringifiedEditorState = `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":3},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1}],"direction":"ltr","format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`; expect(stringifiedEditorState).toBe(expectedStringifiedEditorState); @@ -119,7 +119,7 @@ describe('LexicalSerialization tests', () => { const otherStringifiedEditorState = JSON.stringify(editorState); expect(otherStringifiedEditorState).toBe( - `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":3},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`, + `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":3},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":2},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"colSpan":1,"rowSpan":1,"backgroundColor":null,"headerState":0}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`, ); }); });