Skip to content

Commit

Permalink
Clean up DOM instanceof and nodeType checks
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed Dec 18, 2024
1 parent ee05919 commit bab7626
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 111 deletions.
11 changes: 2 additions & 9 deletions packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
DRAGOVER_COMMAND,
DRAGSTART_COMMAND,
DROP_COMMAND,
getDOMSelection,
getDOMSelectionFromTarget,
isHTMLElement,
LexicalCommand,
LexicalEditor,
Expand Down Expand Up @@ -367,14 +367,7 @@ function canDropImage(event: DragEvent): boolean {

function getDragSelection(event: DragEvent): Range | null | undefined {
let range;
const target = event.target as null | Element | Document;
const targetWindow =
target == null
? null
: target.nodeType === 9
? (target as Document).defaultView
: (target as Element).ownerDocument.defaultView;
const domSelection = getDOMSelection(targetWindow);
const domSelection = getDOMSelectionFromTarget(event.target);
if (document.caretRangeFromPoint) {
range = document.caretRangeFromPoint(event.clientX, event.clientY);
} else if (event.rangeParent && domSelection !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
DRAGOVER_COMMAND,
DRAGSTART_COMMAND,
DROP_COMMAND,
getDOMSelection,
getDOMSelectionFromTarget,
isHTMLElement,
LexicalCommand,
LexicalEditor,
Expand Down Expand Up @@ -319,14 +319,7 @@ function canDropImage(event: DragEvent): boolean {

function getDragSelection(event: DragEvent): Range | null | undefined {
let range;
const target = event.target as null | Element | Document;
const targetWindow =
target == null
? null
: target.nodeType === 9
? (target as Document).defaultView
: (target as Element).ownerDocument.defaultView;
const domSelection = getDOMSelection(targetWindow);
const domSelection = getDOMSelectionFromTarget(event.target);
if (document.caretRangeFromPoint) {
range = document.caretRangeFromPoint(event.clientX, event.clientY);
} else if (event.rangeParent && domSelection !== null) {
Expand Down
2 changes: 2 additions & 0 deletions packages/lexical/src/LexicalConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
// DOM
export const DOM_ELEMENT_TYPE = 1;
export const DOM_TEXT_TYPE = 3;
export const DOM_DOCUMENT_TYPE = 9;
export const DOM_DOCUMENT_FRAGMENT_TYPE = 11;

// Reconciling
export const NO_DIRTY_NODES = 0;
Expand Down
4 changes: 2 additions & 2 deletions packages/lexical/src/LexicalEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
markNodesWithTypesAsDirty,
} from './LexicalUtils';
import {ArtificialNode__DO_NOT_USE} from './nodes/ArtificialNode';
import {DecoratorNode} from './nodes/LexicalDecoratorNode';
import {$isDecoratorNode} from './nodes/LexicalDecoratorNode';
import {LineBreakNode} from './nodes/LexicalLineBreakNode';
import {ParagraphNode} from './nodes/LexicalParagraphNode';
import {RootNode} from './nodes/LexicalRootNode';
Expand Down Expand Up @@ -498,7 +498,7 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor {
`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`,
);
}
if (proto instanceof DecoratorNode) {
if ($isDecoratorNode(proto)) {
// eslint-disable-next-line no-prototype-builtins
if (!proto.hasOwnProperty('decorate')) {
console.warn(
Expand Down
82 changes: 35 additions & 47 deletions packages/lexical/src/LexicalEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ import {
KEY_TAB_COMMAND,
MOVE_TO_END,
MOVE_TO_START,
ParagraphNode,
PASTE_COMMAND,
REDO_COMMAND,
REMOVE_TEXT_COMMAND,
Expand All @@ -69,8 +68,6 @@ import {
import {KEY_MODIFIER_COMMAND, SELECT_ALL_COMMAND} from './LexicalCommands';
import {
COMPOSITION_START_CHAR,
DOM_ELEMENT_TYPE,
DOM_TEXT_TYPE,
DOUBLE_LINE_BREAK,
IS_ALL_FORMATTING,
} from './LexicalConstants';
Expand All @@ -92,6 +89,7 @@ import {
doesContainGrapheme,
getAnchorTextFromDOM,
getDOMSelection,
getDOMSelectionFromTarget,
getDOMTextNode,
getEditorPropertyFromDOMNode,
getEditorsToPropagate,
Expand All @@ -109,8 +107,10 @@ import {
isDeleteWordBackward,
isDeleteWordForward,
isDOMNode,
isDOMTextNode,
isEscape,
isFirefoxClipboardEvents,
isHTMLElement,
isItalic,
isLexicalEditor,
isLineBreak,
Expand Down Expand Up @@ -254,9 +254,8 @@ function shouldSkipSelectionChange(
offset: number,
): boolean {
return (
domNode !== null &&
isDOMTextNode(domNode) &&
domNode.nodeValue !== null &&
domNode.nodeType === DOM_TEXT_TYPE &&
offset !== 0 &&
offset !== domNode.nodeValue.length
);
Expand Down Expand Up @@ -349,11 +348,15 @@ function onSelectionChange(
selection.format = anchorNode.getFormat();
selection.style = anchorNode.getStyle();
} else if (anchor.type === 'element' && !isRootTextContentEmpty) {
invariant(
$isElementNode(anchorNode),
'Point.getNode() must return ElementNode when type is element',
);
const lastNode = anchor.getNode();
selection.style = '';
if (
lastNode instanceof ParagraphNode &&
lastNode.getChildrenSize() === 0
// This previously applied to all ParagraphNode
lastNode.isEmpty()
) {
selection.format = lastNode.getTextFormat();
selection.style = lastNode.getTextStyle();
Expand Down Expand Up @@ -455,21 +458,18 @@ function onClick(event: PointerEvent, editor: LexicalEditor): void {
// This is used to update the selection on touch devices when the user clicks on text after a
// node selection. See isSelectionChangeFromMouseDown for the inverse
const domAnchorNode = domSelection.anchorNode;
if (domAnchorNode !== null) {
const nodeType = domAnchorNode.nodeType;
// If the user is attempting to click selection back onto text, then
// we should attempt create a range selection.
// When we click on an empty paragraph node or the end of a paragraph that ends
// with an image/poll, the nodeType will be ELEMENT_NODE
if (nodeType === DOM_ELEMENT_TYPE || nodeType === DOM_TEXT_TYPE) {
const newSelection = $internalCreateRangeSelection(
lastSelection,
domSelection,
editor,
event,
);
$setSelection(newSelection);
}
// If the user is attempting to click selection back onto text, then
// we should attempt create a range selection.
// When we click on an empty paragraph node or the end of a paragraph that ends
// with an image/poll, the nodeType will be ELEMENT_NODE
if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) {
const newSelection = $internalCreateRangeSelection(
lastSelection,
domSelection,
editor,
event,
);
$setSelection(newSelection);
}
}
}
Expand Down Expand Up @@ -1133,14 +1133,7 @@ function getRootElementRemoveHandles(
const activeNestedEditorsMap: Map<string, LexicalEditor> = new Map();

function onDocumentSelectionChange(event: Event): void {
const target = event.target as null | Element | Document;
const targetWindow =
target == null
? null
: target.nodeType === 9
? (target as Document).defaultView
: (target as Element).ownerDocument.defaultView;
const domSelection = getDOMSelection(targetWindow);
const domSelection = getDOMSelectionFromTarget(event.target);
if (domSelection === null) {
return;
}
Expand All @@ -1154,24 +1147,19 @@ function onDocumentSelectionChange(event: Event): void {
updateEditor(nextActiveEditor, () => {
const lastSelection = $getPreviousSelection();
const domAnchorNode = domSelection.anchorNode;
if (domAnchorNode === null) {
return;
}
const nodeType = domAnchorNode.nodeType;
// If the user is attempting to click selection back onto text, then
// we should attempt create a range selection.
// When we click on an empty paragraph node or the end of a paragraph that ends
// with an image/poll, the nodeType will be ELEMENT_NODE
if (nodeType !== DOM_ELEMENT_TYPE && nodeType !== DOM_TEXT_TYPE) {
return;
if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) {
// If the user is attempting to click selection back onto text, then
// we should attempt create a range selection.
// When we click on an empty paragraph node or the end of a paragraph that ends
// with an image/poll, the nodeType will be ELEMENT_NODE
const newSelection = $internalCreateRangeSelection(
lastSelection,
domSelection,
nextActiveEditor,
event,
);
$setSelection(newSelection);
}
const newSelection = $internalCreateRangeSelection(
lastSelection,
domSelection,
nextActiveEditor,
event,
);
$setSelection(newSelection);
});
}

Expand Down
12 changes: 4 additions & 8 deletions packages/lexical/src/LexicalMutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
$isTextNode,
$setSelection,
} from '.';
import {DOM_TEXT_TYPE} from './LexicalConstants';
import {updateEditor} from './LexicalUpdates';
import {
$getNodeByKey,
Expand All @@ -32,6 +31,7 @@ import {
getParentElement,
getWindow,
internalGetRoot,
isDOMTextNode,
isDOMUnmanaged,
isFirefoxClipboardEvents,
isHTMLElement,
Expand Down Expand Up @@ -112,7 +112,7 @@ function shouldUpdateTextNodeFromMutation(
return false;
}
}
return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();
return isDOMTextNode(targetDOM) && targetNode.isAttached();
}

function $getNearestManagedNodePairFromDOMNode(
Expand Down Expand Up @@ -183,14 +183,10 @@ export function $flushMutations(
if (
shouldFlushTextMutations &&
$isTextNode(targetNode) &&
isDOMTextNode(targetDOM) &&
shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)
) {
$handleTextMutation(
// nodeType === DOM_TEXT_TYPE is a Text DOM node
targetDOM as Text,
targetNode,
editor,
);
$handleTextMutation(targetDOM, targetNode, editor);
}
} else if (type === 'childList') {
shouldRevertSelection = true;
Expand Down
7 changes: 4 additions & 3 deletions packages/lexical/src/LexicalSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
SELECTION_CHANGE_COMMAND,
TextNode,
} from '.';
import {DOM_ELEMENT_TYPE, TEXT_TYPE_TO_FORMAT} from './LexicalConstants';
import {TEXT_TYPE_TO_FORMAT} from './LexicalConstants';
import {
markCollapsedSelectionFormat,
markSelectionChangeFromDOMUpdate,
Expand Down Expand Up @@ -56,6 +56,7 @@ import {
getElementByKeyOrThrow,
getTextNodeOffset,
INTERNAL_$isBlock,
isHTMLElement,
isSelectionCapturedInDecoratorInput,
isSelectionWithinEditor,
removeDOMBlockCursorElement,
Expand Down Expand Up @@ -2065,7 +2066,7 @@ function $internalResolveSelectionPoint(
// need to figure out (using the offset) what text
// node should be selected.

if (dom.nodeType === DOM_ELEMENT_TYPE) {
if (isHTMLElement(dom)) {
// Resolve element to a ElementNode, or TextNode, or null
let moveSelectionToEnd = false;
// Given we're moving selection to another node, selection is
Expand Down Expand Up @@ -2903,7 +2904,7 @@ export function updateDOMSelection(
rootElement === document.activeElement
) {
const selectionTarget: null | Range | HTMLElement | Text =
nextSelection instanceof RangeSelection &&
$isRangeSelection(nextSelection) &&
nextSelection.anchor.type === 'element'
? (nextAnchorNode.childNodes[nextAnchorOffset] as HTMLElement | Text) ||
null
Expand Down
Loading

0 comments on commit bab7626

Please sign in to comment.