@@ -57,6 +57,7 @@ import {
57
57
} from '../utils/environment'
58
58
import Hotkeys from '../utils/hotkeys'
59
59
import {
60
+ IS_NODE_MAP_DIRTY ,
60
61
EDITOR_TO_ELEMENT ,
61
62
EDITOR_TO_FORCE_RENDER ,
62
63
EDITOR_TO_PENDING_INSERTION_MARKS ,
@@ -209,6 +210,11 @@ export const Editable = forwardRef(
209
210
const onDOMSelectionChange = useMemo (
210
211
( ) =>
211
212
throttle ( ( ) => {
213
+ if ( IS_NODE_MAP_DIRTY . get ( editor ) ) {
214
+ onDOMSelectionChange ( )
215
+ return
216
+ }
217
+
212
218
const el = ReactEditor . toDOMNode ( editor , editor )
213
219
const root = el . getRootNode ( )
214
220
@@ -573,55 +579,62 @@ export const Editable = forwardRef(
573
579
native = false
574
580
}
575
581
576
- // Chrome also has issues correctly editing the end of anchor elements: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100
577
- // Therefore we don't allow native events to insert text at the end of anchor nodes.
578
- const { anchor } = selection
582
+ // If the NODE_MAP is dirty, we can't trust the selection anchor (eg ReactEditor.toDOMPoint)
583
+ if ( ! IS_NODE_MAP_DIRTY . get ( editor ) ) {
584
+ // Chrome also has issues correctly editing the end of anchor elements: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100
585
+ // Therefore we don't allow native events to insert text at the end of anchor nodes.
586
+ const { anchor } = selection
579
587
580
- const [ node , offset ] = ReactEditor . toDOMPoint ( editor , anchor )
581
- const anchorNode = node . parentElement ?. closest ( 'a' )
588
+ const [ node , offset ] = ReactEditor . toDOMPoint ( editor , anchor )
589
+ const anchorNode = node . parentElement ?. closest ( 'a' )
582
590
583
- const window = ReactEditor . getWindow ( editor )
584
-
585
- if (
586
- native &&
587
- anchorNode &&
588
- ReactEditor . hasDOMNode ( editor , anchorNode )
589
- ) {
590
- // Find the last text node inside the anchor.
591
- const lastText = window ?. document
592
- . createTreeWalker ( anchorNode , NodeFilter . SHOW_TEXT )
593
- . lastChild ( ) as DOMText | null
591
+ const window = ReactEditor . getWindow ( editor )
594
592
595
593
if (
596
- lastText === node &&
597
- lastText . textContent ?. length === offset
594
+ native &&
595
+ anchorNode &&
596
+ ReactEditor . hasDOMNode ( editor , anchorNode )
598
597
) {
599
- native = false
598
+ // Find the last text node inside the anchor.
599
+ const lastText = window ?. document
600
+ . createTreeWalker ( anchorNode , NodeFilter . SHOW_TEXT )
601
+ . lastChild ( ) as DOMText | null
602
+
603
+ if (
604
+ lastText === node &&
605
+ lastText . textContent ?. length === offset
606
+ ) {
607
+ native = false
608
+ }
600
609
}
601
- }
602
610
603
- // Chrome has issues with the presence of tab characters inside elements with whiteSpace = 'pre'
604
- // causing abnormal insert behavior: https://bugs.chromium.org/p/chromium/issues/detail?id=1219139
605
- if (
606
- native &&
607
- node . parentElement &&
608
- window ?. getComputedStyle ( node . parentElement ) ?. whiteSpace === 'pre'
609
- ) {
610
- const block = Editor . above ( editor , {
611
- at : anchor . path ,
612
- match : n => Element . isElement ( n ) && Editor . isBlock ( editor , n ) ,
613
- } )
611
+ // Chrome has issues with the presence of tab characters inside elements with whiteSpace = 'pre'
612
+ // causing abnormal insert behavior: https://bugs.chromium.org/p/chromium/issues/detail?id=1219139
613
+ if (
614
+ native &&
615
+ node . parentElement &&
616
+ window ?. getComputedStyle ( node . parentElement ) ?. whiteSpace ===
617
+ 'pre'
618
+ ) {
619
+ const block = Editor . above ( editor , {
620
+ at : anchor . path ,
621
+ match : n => Element . isElement ( n ) && Editor . isBlock ( editor , n ) ,
622
+ } )
614
623
615
- if ( block && Node . string ( block [ 0 ] ) . includes ( '\t' ) ) {
616
- native = false
624
+ if ( block && Node . string ( block [ 0 ] ) . includes ( '\t' ) ) {
625
+ native = false
626
+ }
617
627
}
618
628
}
619
629
}
620
-
621
630
// COMPAT: For the deleting forward/backward input types we don't want
622
631
// to change the selection because it is the range that will be deleted,
623
632
// and those commands determine that for themselves.
624
- if ( ! type . startsWith ( 'delete' ) || type . startsWith ( 'deleteBy' ) ) {
633
+ // If the NODE_MAP is dirty, we can't trust the selection anchor (eg ReactEditor.toDOMPoint via ReactEditor.toSlateRange)
634
+ if (
635
+ ( ! type . startsWith ( 'delete' ) || type . startsWith ( 'deleteBy' ) ) &&
636
+ ! IS_NODE_MAP_DIRTY . get ( editor )
637
+ ) {
625
638
const [ targetRange ] = ( event as any ) . getTargetRanges ( )
626
639
627
640
if ( targetRange ) {
0 commit comments