Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 4d36c98

Browse files
committed
[WIP] EventNormalizer: prevent backspace flickering
1 parent 23f1e41 commit 4d36c98

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

packages/plugin-dom-editable/src/EventNormalizer.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ const alphabetsContainingSpaces = new RegExp(
7979
')$',
8080
);
8181

82+
/**
83+
* Spell-checking on mobile devices does not stop at inline tags like b, i, u
84+
* but it hits a barrier on different nodes like div for example. The code
85+
* below constructs a crude selector to match if the node is such a barrier.
86+
*/
87+
const spellCheckingIgnoredTags = ['a', 'b', 'i', 'u', 'span', 'font', 'superscript', 'subscript'];
88+
const spellCheckingBarrier = spellCheckingIgnoredTags.map(t => `:not(${t})`).join('');
89+
console.log(spellCheckingBarrier);
90+
8291
/**
8392
* These javascript event types might, in case of safari or spell-checking
8493
* keyboard, trigger dom events in multiple javascript stacks. They will require
@@ -941,8 +950,11 @@ export class EventNormalizer {
941950
| DeleteWordAction
942951
| DeleteHardLineAction
943952
| DeleteContentAction {
944-
const isInsertOrRemoveAction = hasMutatedElements && !inputTypeCommands.has(inputType);
945-
if (isInsertOrRemoveAction) {
953+
const isMutationAction = hasMutatedElements && !inputTypeCommands.has(inputType);
954+
// These two particular keys might have been defaultPrevented to avoid
955+
// flickering and thus trigger no mutation but still need to be handled.
956+
const isRemoveAction = key === 'Backspace' || key === 'Delete';
957+
if (isMutationAction || isRemoveAction) {
946958
if (key === 'Backspace' || key === 'Delete') {
947959
return this._getRemoveAction(key, inputType);
948960
} else if (key === 'Enter') {
@@ -1599,6 +1611,27 @@ export class EventNormalizer {
15991611
const selection = this._getSelection();
16001612
const [offsetNode, offset] = targetDeepest(selection.anchorNode, selection.anchorOffset);
16011613
this._initialCaretPosition = { offsetNode, offset };
1614+
1615+
// Backspace cannot always be prevented as preventing a backspace in a
1616+
// text node would throw off spell-checking on mobile for example.
1617+
if (ev.key === 'Backspace') {
1618+
const forward = selection.direction === Direction.FORWARD;
1619+
const start = forward ? selection.anchorNode : selection.focusNode;
1620+
const startOffset = forward ? selection.anchorOffset : selection.focusOffset;
1621+
if (
1622+
(startOffset === 0 && !start.previousSibling) ||
1623+
selection.anchorNode.parentElement.closest(spellCheckingBarrier) !==
1624+
selection.focusNode.parentElement.closest(spellCheckingBarrier)
1625+
) {
1626+
console.log('prevented');
1627+
// Allowed cases for preventing is:
1628+
// 1. At the start of the node
1629+
// 2. When the anchor and focus of the selection are set in
1630+
// nodes that are separated of each other by a node that is
1631+
// considered to be a barrier for spell-checking purposes.
1632+
ev.preventDefault();
1633+
}
1634+
}
16021635
}
16031636
/**
16041637
* Set internal properties of the pointer down event to retrieve them later

0 commit comments

Comments
 (0)