Skip to content

Commit

Permalink
[lexical-utils] Bug Fix: Refactor markSelection for getDOMSlot and no…
Browse files Browse the repository at this point in the history
…t using updateDOM (#6961)
  • Loading branch information
etrepum authored Dec 15, 2024
1 parent 26c6f26 commit bf44530
Showing 1 changed file with 81 additions and 81 deletions.
162 changes: 81 additions & 81 deletions packages/lexical-utils/src/markSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,54 @@

import {
$getSelection,
$isElementNode,
$isRangeSelection,
$isTextNode,
type EditorState,
ElementNode,
getDOMTextNode,
type LexicalEditor,
Point,
TextNode,
} from 'lexical';

import mergeRegister from './mergeRegister';
import positionNodeOnRange from './positionNodeOnRange';
import px from './px';

function rangeTargetFromPoint(
point: Point,
node: ElementNode | TextNode,
dom: HTMLElement,
): [HTMLElement | Text, number] {
if (point.type === 'text' || !$isElementNode(node)) {
const textDOM = getDOMTextNode(dom) || dom;
return [textDOM, point.offset];
} else {
const slot = node.getDOMSlot(dom);
return [slot.element, slot.getFirstChildOffset() + point.offset];
}
}

function rangeFromPoints(
editor: LexicalEditor,
anchor: Point,
anchorNode: ElementNode | TextNode,
anchorDOM: HTMLElement,
focus: Point,
focusNode: ElementNode | TextNode,
focusDOM: HTMLElement,
): Range {
const editorDocument = editor._window ? editor._window.document : document;
const range = editorDocument.createRange();
if (focusNode.isBefore(anchorNode)) {
range.setStart(...rangeTargetFromPoint(focus, focusNode, focusDOM));
range.setEnd(...rangeTargetFromPoint(anchor, anchorNode, anchorDOM));
} else {
range.setStart(...rangeTargetFromPoint(anchor, anchorNode, anchorDOM));
range.setEnd(...rangeTargetFromPoint(focus, focusNode, focusDOM));
}
return range;
}
/**
* Place one or multiple newly created Nodes at the current selection. Multiple
* nodes will only be created when the selection spans multiple lines (aka
Expand All @@ -34,8 +69,10 @@ export default function markSelection(
onReposition?: (node: Array<HTMLElement>) => void,
): () => void {
let previousAnchorNode: null | TextNode | ElementNode = null;
let previousAnchorNodeDOM: null | HTMLElement = null;
let previousAnchorOffset: null | number = null;
let previousFocusNode: null | TextNode | ElementNode = null;
let previousFocusNodeDOM: null | HTMLElement = null;
let previousFocusOffset: null | number = null;
let removeRangeListener: () => void = () => {};
function compute(editorState: EditorState) {
Expand All @@ -62,103 +99,66 @@ export default function markSelection(
const currentFocusNodeDOM = editor.getElementByKey(currentFocusNodeKey);
const differentAnchorDOM =
previousAnchorNode === null ||
currentAnchorNodeDOM === null ||
currentAnchorNodeDOM !== previousAnchorNodeDOM ||
currentAnchorOffset !== previousAnchorOffset ||
currentAnchorNodeKey !== previousAnchorNode.getKey() ||
(currentAnchorNode !== previousAnchorNode &&
(!$isTextNode(previousAnchorNode) ||
($isTextNode(currentAnchorNode) &&
currentAnchorNode.updateDOM(
previousAnchorNode,
currentAnchorNodeDOM,
editor._config,
))));
currentAnchorNodeKey !== previousAnchorNode.getKey();
const differentFocusDOM =
previousFocusNode === null ||
currentFocusNodeDOM === null ||
currentFocusNodeDOM !== previousFocusNodeDOM ||
currentFocusOffset !== previousFocusOffset ||
currentFocusNodeKey !== previousFocusNode.getKey() ||
(currentFocusNode !== previousFocusNode &&
(!$isTextNode(previousFocusNode) ||
($isTextNode(currentFocusNode) &&
currentFocusNode.updateDOM(
previousFocusNode,
currentFocusNodeDOM,
editor._config,
))));
if (differentAnchorDOM || differentFocusDOM) {
const anchorHTMLElement = editor.getElementByKey(
anchor.getNode().getKey(),
currentFocusNodeKey !== previousFocusNode.getKey();
if (
(differentAnchorDOM || differentFocusDOM) &&
currentAnchorNodeDOM !== null &&
currentFocusNodeDOM !== null
) {
const range = rangeFromPoints(
editor,
anchor,
currentAnchorNode,
currentAnchorNodeDOM,
focus,
currentFocusNode,
currentFocusNodeDOM,
);
const focusHTMLElement = editor.getElementByKey(
focus.getNode().getKey(),
);
if (anchorHTMLElement !== null && focusHTMLElement !== null) {
const range = document.createRange();
let firstHTMLElement;
let firstOffset;
let lastHTMLElement;
let lastOffset;
if (focus.isBefore(anchor)) {
firstHTMLElement = focusHTMLElement;
firstOffset = focus.offset;
lastHTMLElement = anchorHTMLElement;
lastOffset = anchor.offset;
} else {
firstHTMLElement = anchorHTMLElement;
firstOffset = anchor.offset;
lastHTMLElement = focusHTMLElement;
lastOffset = focus.offset;
}
const firstHTMLElementTextChild = getDOMTextNode(firstHTMLElement);
const lastHTMLElementtextChild = getDOMTextNode(lastHTMLElement);
range.setStart(
firstHTMLElementTextChild || firstHTMLElement,
firstOffset,
);
range.setEnd(lastHTMLElementtextChild || lastHTMLElement, lastOffset);
removeRangeListener();
removeRangeListener = positionNodeOnRange(
editor,
range,
(domNodes) => {
if (onReposition === undefined) {
for (const domNode of domNodes) {
const domNodeStyle = domNode.style;
removeRangeListener();
removeRangeListener = positionNodeOnRange(editor, range, (domNodes) => {
if (onReposition === undefined) {
for (const domNode of domNodes) {
const domNodeStyle = domNode.style;

if (domNodeStyle.background !== 'Highlight') {
domNodeStyle.background = 'Highlight';
}
if (domNodeStyle.color !== 'HighlightText') {
domNodeStyle.color = 'HighlightText';
}
if (domNodeStyle.marginTop !== px(-1.5)) {
domNodeStyle.marginTop = px(-1.5);
}
if (domNodeStyle.paddingTop !== px(4)) {
domNodeStyle.paddingTop = px(4);
}
if (domNodeStyle.paddingBottom !== px(0)) {
domNodeStyle.paddingBottom = px(0);
}
}
} else {
onReposition(domNodes);
if (domNodeStyle.background !== 'Highlight') {
domNodeStyle.background = 'Highlight';
}
if (domNodeStyle.color !== 'HighlightText') {
domNodeStyle.color = 'HighlightText';
}
if (domNodeStyle.marginTop !== px(-1.5)) {
domNodeStyle.marginTop = px(-1.5);
}
},
);
}
if (domNodeStyle.paddingTop !== px(4)) {
domNodeStyle.paddingTop = px(4);
}
if (domNodeStyle.paddingBottom !== px(0)) {
domNodeStyle.paddingBottom = px(0);
}
}
} else {
onReposition(domNodes);
}
});
}
previousAnchorNode = currentAnchorNode;
previousAnchorNodeDOM = currentAnchorNodeDOM;
previousAnchorOffset = currentAnchorOffset;
previousFocusNode = currentFocusNode;
previousFocusNodeDOM = currentFocusNodeDOM;
previousFocusOffset = currentFocusOffset;
});
}
compute(editor.getEditorState());
return mergeRegister(
editor.registerUpdateListener(({editorState}) => compute(editorState)),
removeRangeListener,
() => {
removeRangeListener();
},
Expand Down

0 comments on commit bf44530

Please sign in to comment.