Skip to content

Commit c4e9dec

Browse files
Fix selection started from inside of the table (#5766)
1 parent 3ac5836 commit c4e9dec

File tree

4 files changed

+82
-12
lines changed

4 files changed

+82
-12
lines changed

packages/lexical-table/src/LexicalTableObserver.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
$setSelection,
2525
SELECTION_CHANGE_COMMAND,
2626
} from 'lexical';
27-
import {CAN_USE_DOM} from 'shared/canUseDOM';
2827
import invariant from 'shared/invariant';
2928

3029
import {$isTableCellNode} from './LexicalTableCellNode';
@@ -34,7 +33,12 @@ import {
3433
$createTableSelection,
3534
$isTableSelection,
3635
} from './LexicalTableSelection';
37-
import {$updateDOMForSelection, getTable} from './LexicalTableSelectionHelpers';
36+
import {
37+
$findTableNode,
38+
$updateDOMForSelection,
39+
getDOMSelection,
40+
getTable,
41+
} from './LexicalTableSelectionHelpers';
3842

3943
export type TableDOMCell = {
4044
elem: HTMLElement;
@@ -52,9 +56,6 @@ export type TableDOMTable = {
5256
rows: number;
5357
};
5458

55-
const getDOMSelection = (targetWindow: Window | null): Selection | null =>
56-
CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
57-
5859
export class TableObserver {
5960
focusX: number;
6061
focusY: number;
@@ -283,7 +284,8 @@ export class TableObserver {
283284
if (
284285
this.tableSelection != null &&
285286
this.anchorCellNodeKey != null &&
286-
$isTableCellNode(focusTableCellNode)
287+
$isTableCellNode(focusTableCellNode) &&
288+
tableNode.is($findTableNode(focusTableCellNode))
287289
) {
288290
const focusNodeKey = focusTableCellNode.getKey();
289291

packages/lexical-table/src/LexicalTableSelectionHelpers.ts

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
import {$findMatchingParent} from '@lexical/utils';
2424
import {
2525
$createParagraphNode,
26+
$createRangeSelectionFromDom,
2627
$getNearestNodeFromDOMNode,
2728
$getPreviousSelection,
2829
$getSelection,
@@ -50,6 +51,7 @@ import {
5051
SELECTION_CHANGE_COMMAND,
5152
SELECTION_INSERT_CLIPBOARD_NODES_COMMAND,
5253
} from 'lexical';
54+
import {CAN_USE_DOM} from 'shared/canUseDOM';
5355
import invariant from 'shared/invariant';
5456

5557
import {$isTableCellNode} from './LexicalTableCellNode';
@@ -64,6 +66,11 @@ import {$computeTableMap} from './LexicalTableUtils';
6466

6567
const LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';
6668

69+
export const getDOMSelection = (
70+
targetWindow: Window | null,
71+
): Selection | null =>
72+
CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
73+
6774
export function applyTableHandlers(
6875
tableNode: TableNode,
6976
tableElement: HTMLTableElementWithWithTableSelectionState,
@@ -684,11 +691,19 @@ export function applyTableHandlers(
684691

685692
if (isPartialyWithinTable) {
686693
const newSelection = selection.clone();
687-
newSelection.focus.set(
688-
tableNode.getKey(),
689-
isBackward ? 0 : tableNode.getChildrenSize(),
690-
'element',
691-
);
694+
if (isFocusInside) {
695+
newSelection.focus.set(
696+
tableNode.getKey(),
697+
isBackward ? 0 : tableNode.getChildrenSize(),
698+
'element',
699+
);
700+
} else {
701+
newSelection.anchor.set(
702+
tableNode.getKey(),
703+
isBackward ? tableNode.getChildrenSize() : 0,
704+
'element',
705+
);
706+
}
692707
$setSelection(newSelection);
693708
$addHighlightStyleToTable(editor, tableObserver);
694709
} else if (isWithinTable) {
@@ -704,6 +719,51 @@ export function applyTableHandlers(
704719
);
705720
}
706721
}
722+
} else if (
723+
selection &&
724+
$isTableSelection(selection) &&
725+
selection.is(prevSelection) &&
726+
selection.tableKey === tableNode.getKey()
727+
) {
728+
// if selection goes outside of the table we need to change it to Range selection
729+
const domSelection = getDOMSelection(editor._window);
730+
if (
731+
domSelection &&
732+
domSelection.anchorNode &&
733+
domSelection.focusNode
734+
) {
735+
const focusNode = $getNearestNodeFromDOMNode(
736+
domSelection.focusNode,
737+
);
738+
const isFocusOutside =
739+
focusNode && !tableNode.is($findTableNode(focusNode));
740+
741+
const anchorNode = $getNearestNodeFromDOMNode(
742+
domSelection.anchorNode,
743+
);
744+
const isAnchorInside =
745+
anchorNode && tableNode.is($findTableNode(anchorNode));
746+
747+
if (
748+
isFocusOutside &&
749+
isAnchorInside &&
750+
domSelection.rangeCount > 0
751+
) {
752+
const newSelection = $createRangeSelectionFromDom(
753+
domSelection,
754+
editor,
755+
);
756+
if (newSelection) {
757+
newSelection.anchor.set(
758+
tableNode.getKey(),
759+
selection.isBackward() ? tableNode.getChildrenSize() : 0,
760+
'element',
761+
);
762+
domSelection.removeAllRanges();
763+
$setSelection(newSelection);
764+
}
765+
}
766+
}
707767
}
708768

709769
if (
@@ -1141,7 +1201,7 @@ function $findCellNode(node: LexicalNode): null | TableCellNode {
11411201
return $isTableCellNode(cellNode) ? cellNode : null;
11421202
}
11431203

1144-
function $findTableNode(node: LexicalNode): null | TableNode {
1204+
export function $findTableNode(node: LexicalNode): null | TableNode {
11451205
const tableNode = $findMatchingParent(node, $isTableNode);
11461206
return $isTableNode(tableNode) ? tableNode : null;
11471207
}

packages/lexical/src/LexicalSelection.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,6 +2201,13 @@ export function internalCreateSelection(
22012201
return lastSelection.clone();
22022202
}
22032203

2204+
export function $createRangeSelectionFromDom(
2205+
domSelection: Selection | null,
2206+
editor: LexicalEditor,
2207+
): null | RangeSelection {
2208+
return internalCreateRangeSelection(null, domSelection, editor, null);
2209+
}
2210+
22042211
export function internalCreateRangeSelection(
22052212
lastSelection: null | BaseSelection,
22062213
domSelection: Selection | null,

packages/lexical/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export {
123123
$createNodeSelection,
124124
$createPoint,
125125
$createRangeSelection,
126+
$createRangeSelectionFromDom,
126127
$getCharacterOffsets,
127128
$getPreviousSelection,
128129
$getSelection,

0 commit comments

Comments
 (0)