From fcc374018043620ec025262b352baa91d9536b6e Mon Sep 17 00:00:00 2001 From: liuwei Date: Mon, 10 Feb 2025 14:19:16 +0800 Subject: [PATCH] [lexical-table] Feature: TableCellNode add verticalAlign attribute (#7077) Co-authored-by: Ivaylo Pavlov Co-authored-by: Bob Ippolito --- .../html/TablesHTMLCopyAndPaste.spec.mjs | 24 ++++++-- .../src/images/icons/vertical-bottom.svg | 1 + .../src/images/icons/vertical-middle.svg | 1 + .../src/images/icons/vertical-top.svg | 1 + packages/lexical-playground/src/index.css | 15 +++++ .../plugins/TableActionMenuPlugin/index.tsx | 59 +++++++++++++++++++ .../lexical-table/src/LexicalTableCellNode.ts | 38 +++++++++++- .../unit/LexicalTableCellNode.test.ts | 18 ++++++ .../__tests__/unit/LexicalTableNode.test.tsx | 12 ++-- 9 files changed, 154 insertions(+), 15 deletions(-) create mode 100644 packages/lexical-playground/src/images/icons/vertical-bottom.svg create mode 100644 packages/lexical-playground/src/images/icons/vertical-middle.svg create mode 100644 packages/lexical-playground/src/images/icons/vertical-top.svg diff --git a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs index bf61c484ccc..7f462e36d5b 100644 --- a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs @@ -281,14 +281,18 @@ test.describe('HTML Tables CopyAndPaste', () => { - +

a

- +

@@ -300,7 +304,9 @@ test.describe('HTML Tables CopyAndPaste', () => { b

- +

@@ -309,21 +315,27 @@ test.describe('HTML Tables CopyAndPaste', () => { - +

d

- +

e

- +

diff --git a/packages/lexical-playground/src/images/icons/vertical-bottom.svg b/packages/lexical-playground/src/images/icons/vertical-bottom.svg new file mode 100644 index 00000000000..edd2ece6169 --- /dev/null +++ b/packages/lexical-playground/src/images/icons/vertical-bottom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/lexical-playground/src/images/icons/vertical-middle.svg b/packages/lexical-playground/src/images/icons/vertical-middle.svg new file mode 100644 index 00000000000..7d06ffe6061 --- /dev/null +++ b/packages/lexical-playground/src/images/icons/vertical-middle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/lexical-playground/src/images/icons/vertical-top.svg b/packages/lexical-playground/src/images/icons/vertical-top.svg new file mode 100644 index 00000000000..1dc151d0b65 --- /dev/null +++ b/packages/lexical-playground/src/images/icons/vertical-top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/lexical-playground/src/index.css b/packages/lexical-playground/src/index.css index 2f271a3e1c3..b0c81a69455 100644 --- a/packages/lexical-playground/src/index.css +++ b/packages/lexical-playground/src/index.css @@ -513,6 +513,21 @@ i.justify-align { background-image: url(images/icons/justify.svg); } +.icon.vertical-top, +i.left-align { + background-image: url(images/icons/vertical-top.svg); +} + +.icon.vertical-middle, +i.center-align { + background-image: url(images/icons/vertical-middle.svg); +} + +.icon.vertical-bottom, +i.right-align { + background-image: url(images/icons/vertical-bottom.svg); +} + i.indent { background-image: url(images/icons/indent.svg); } diff --git a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx index 06e8510163a..1103ba78299 100644 --- a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx @@ -54,6 +54,7 @@ import invariant from 'shared/invariant'; import useModal from '../../hooks/useModal'; import ColorPicker from '../../ui/ColorPicker'; +import DropDown, {DropDownItem} from '../../ui/DropDown'; function computeSelectionCount(selection: TableSelection): { columns: number; @@ -473,6 +474,29 @@ function TableActionMenu({ [editor], ); + const formatVerticalAlign = (value: string) => { + editor.update(() => { + const selection = $getSelection(); + if ($isRangeSelection(selection) || $isTableSelection(selection)) { + const [cell] = $getNodeTriplet(selection.anchor); + if ($isTableCellNode(cell)) { + cell.setVerticalAlign(value); + } + + if ($isTableSelection(selection)) { + const nodes = selection.getNodes(); + + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if ($isTableCellNode(node)) { + node.setVerticalAlign(value); + } + } + } + } + }); + }; + let mergeCellButton: null | JSX.Element = null; if (cellMerge) { if (canMergeCells) { @@ -528,6 +552,41 @@ function TableActionMenu({ data-test-id="table-row-striping"> Toggle Row Striping + + { + formatVerticalAlign('top'); + }} + className="item wide"> +

+ + Top Align +
+ + { + formatVerticalAlign('middle'); + }} + className="item wide"> +
+ + Middle Align +
+
+ { + formatVerticalAlign('bottom'); + }} + className="item wide"> +
+ + Bottom Align +
+
+