@@ -23,6 +23,7 @@ import type {
2323import { $findMatchingParent } from '@lexical/utils' ;
2424import {
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' ;
5355import invariant from 'shared/invariant' ;
5456
5557import { $isTableCellNode } from './LexicalTableCellNode' ;
@@ -64,6 +66,11 @@ import {$computeTableMap} from './LexicalTableUtils';
6466
6567const 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+
6774export 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}
0 commit comments