From bba84b912e98034f5117f5470a7ae6484568906e Mon Sep 17 00:00:00 2001
From: Katsiaryna <47710336+KatsiarynaDzibrova@users.noreply.github.com>
Date: Mon, 22 Apr 2024 23:29:12 +0100
Subject: [PATCH 1/2] Fix selecting table selects an image after (#5917)
---
packages/lexical-table/src/LexicalTableSelectionHelpers.ts | 4 +---
packages/lexical/src/LexicalSelection.ts | 2 +-
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
index ed443fc3f17..cc4d9d681cf 100644
--- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
+++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
@@ -707,9 +707,7 @@ export function applyTableHandlers(
if (isFocusInside) {
newSelection.focus.set(
tableNode.getParentOrThrow().getKey(),
- isBackward
- ? tableNode.getIndexWithinParent()
- : tableNode.getIndexWithinParent() + 1,
+ tableNode.getIndexWithinParent(),
'element',
);
} else {
diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts
index 520541f8e9b..959c9d4ac4a 100644
--- a/packages/lexical/src/LexicalSelection.ts
+++ b/packages/lexical/src/LexicalSelection.ts
@@ -1940,13 +1940,13 @@ function internalResolveSelectionPoint(
: child.getFirstDescendant();
if (descendant === null) {
resolvedElement = child;
- resolvedOffset = 0;
} else {
child = descendant;
resolvedElement = $isElementNode(child)
? child
: child.getParentOrThrow();
}
+ resolvedOffset = 0;
}
if ($isTextNode(child)) {
resolvedNode = child;
From da06d8f8b0dce523bad6459ff2007ca747c88227 Mon Sep 17 00:00:00 2001
From: Serey Roth <88986106+serey-roth@users.noreply.github.com>
Date: Mon, 22 Apr 2024 15:32:01 -0700
Subject: [PATCH 2/2] Preserve selection in tables with open typeahead menu
(#5820)
---
.../__tests__/e2e/Tables.spec.mjs | 205 ++++++++++++++----
.../src/LexicalTableSelectionHelpers.ts | 20 ++
2 files changed, 183 insertions(+), 42 deletions(-)
diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
index 419b90fc364..55087f0a50d 100644
--- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
+++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs
@@ -12,6 +12,7 @@ import {
moveLeft,
moveRight,
moveToEditorBeginning,
+ moveUp,
pressBackspace,
selectAll,
} from '../keyboardShortcuts/index.mjs';
@@ -44,6 +45,7 @@ import {
test,
toggleColumnHeader,
unmergeTableCell,
+ waitForSelector,
} from '../utils/index.mjs';
async function fillTablePartiallyWithText(page) {
@@ -486,52 +488,171 @@ test.describe('Tables', () => {
});
});
- test(`Can navigate table with keyboard`, async ({
- page,
- isPlainText,
- isCollab,
- }) => {
- await initialize({isCollab, page});
- test.skip(isPlainText);
+ test.describe(`Can navigate table with keyboard`, () => {
+ test(`Can navigate cells horizontally`, async ({
+ page,
+ isPlainText,
+ isCollab,
+ }) => {
+ await initialize({isCollab, page});
+ test.skip(isPlainText);
- await focusEditor(page);
- await insertTable(page, 2, 3);
+ await focusEditor(page);
+ await insertTable(page, 2, 2);
- await fillTablePartiallyWithText(page);
+ await assertHTML(
+ page,
+ html`
+
+
+
+
+
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+ |
+
+
+
+ `,
+ undefined,
+ {ignoreClasses: true},
+ );
- await assertHTML(
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 0, 0],
+ });
+
+ await moveRight(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 1, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 1, 0],
+ });
+
+ await moveRight(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 1, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 1, 0, 0],
+ });
+
+ await moveRight(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 1, 1, 0],
+ focusOffset: 0,
+ focusPath: [1, 1, 1, 0],
+ });
+
+ await moveLeft(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 1, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 1, 0, 0],
+ });
+
+ await moveLeft(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 1, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 1, 0],
+ });
+
+ await moveLeft(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 0, 0],
+ });
+ });
+
+ test(`Can navigate cells vertically`, async ({
page,
- html`
-
-
-
-
- a
- |
-
- bb
- |
-
- cc
- |
-
-
-
- d
- |
-
- e
- |
-
- f
- |
-
-
-
- `,
- undefined,
- {ignoreClasses: true},
- );
+ isPlainText,
+ isCollab,
+ }) => {
+ await initialize({isCollab, page});
+ test.skip(isPlainText);
+
+ await focusEditor(page);
+ await insertTable(page, 2, 2);
+
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 0, 0],
+ });
+
+ await moveDown(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 1, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 1, 0, 0],
+ });
+
+ await moveUp(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 0,
+ anchorPath: [1, 0, 0, 0],
+ focusOffset: 0,
+ focusPath: [1, 0, 0, 0],
+ });
+ });
+
+ test('Should not navigate cells when typeahead menu is open and focused', async ({
+ page,
+ isCollab,
+ isPlainText,
+ }) => {
+ await initialize({isCollab, page});
+ test.skip(isPlainText);
+
+ await focusEditor(page);
+ await insertTable(page, 2, 2);
+
+ await page.keyboard.type('@A');
+ await assertSelection(page, {
+ anchorOffset: 2,
+ anchorPath: [1, 0, 0, 0, 0, 0],
+ focusOffset: 2,
+ focusPath: [1, 0, 0, 0, 0, 0],
+ });
+
+ await waitForSelector(page, `#typeahead-menu ul li:first-child.selected`);
+
+ await moveDown(page, 1);
+ await assertSelection(page, {
+ anchorOffset: 2,
+ anchorPath: [1, 0, 0, 0, 0, 0],
+ focusOffset: 2,
+ focusPath: [1, 0, 0, 0, 0, 0],
+ });
+
+ await waitForSelector(
+ page,
+ '#typeahead-menu ul li:nth-child(2).selected',
+ );
+ });
});
test(`Can select cells using Table selection`, async ({
diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
index cc4d9d681cf..e45c366faa3 100644
--- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
+++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts
@@ -1263,6 +1263,13 @@ function $handleArrowKey(
tableNode: TableNode,
tableObserver: TableObserver,
): boolean {
+ if (
+ (direction === 'up' || direction === 'down') &&
+ isTypeaheadMenuInView(editor)
+ ) {
+ return false;
+ }
+
const selection = $getSelection();
if (!$isSelectionInTable(selection, tableNode)) {
@@ -1479,6 +1486,19 @@ function stopEvent(event: Event) {
event.stopPropagation();
}
+function isTypeaheadMenuInView(editor: LexicalEditor) {
+ // There is no inbuilt way to check if the component picker is in view
+ // but we can check if the root DOM element has the aria-controls attribute "typeahead-menu".
+ const root = editor.getRootElement();
+ if (!root) {
+ return false;
+ }
+ return (
+ root.hasAttribute('aria-controls') &&
+ root.getAttribute('aria-controls') === 'typeahead-menu'
+ );
+}
+
function isExitingTableAnchor(
type: string,
offset: number,