2 * Copyright (c) Meta Platforms, Inc. and affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
9 import type {RangeSelection, TextNode} from '.';
10 import type {PointType} from './LexicalSelection';
12 import {$isElementNode, $isTextNode} from '.';
13 import {getActiveEditor} from './LexicalUpdates';
15 function $canSimpleTextNodesBeMerged(
19 const node1Mode = node1.__mode;
20 const node1Format = node1.__format;
21 const node1Style = node1.__style;
22 const node2Mode = node2.__mode;
23 const node2Format = node2.__format;
24 const node2Style = node2.__style;
26 (node1Mode === null || node1Mode === node2Mode) &&
27 (node1Format === null || node1Format === node2Format) &&
28 (node1Style === null || node1Style === node2Style)
32 function $mergeTextNodes(node1: TextNode, node2: TextNode): TextNode {
33 const writableNode1 = node1.mergeWithSibling(node2);
35 const normalizedNodes = getActiveEditor()._normalizedNodes;
37 normalizedNodes.add(node1.__key);
38 normalizedNodes.add(node2.__key);
42 export function $normalizeTextNode(textNode: TextNode): void {
45 if (node.__text === '' && node.isSimpleText() && !node.isUnmergeable()) {
54 (previousNode = node.getPreviousSibling()) !== null &&
55 $isTextNode(previousNode) &&
56 previousNode.isSimpleText() &&
57 !previousNode.isUnmergeable()
59 if (previousNode.__text === '') {
60 previousNode.remove();
61 } else if ($canSimpleTextNodesBeMerged(previousNode, node)) {
62 node = $mergeTextNodes(previousNode, node);
73 (nextNode = node.getNextSibling()) !== null &&
74 $isTextNode(nextNode) &&
75 nextNode.isSimpleText() &&
76 !nextNode.isUnmergeable()
78 if (nextNode.__text === '') {
80 } else if ($canSimpleTextNodesBeMerged(node, nextNode)) {
81 node = $mergeTextNodes(node, nextNode);
89 export function $normalizeSelection(selection: RangeSelection): RangeSelection {
90 $normalizePoint(selection.anchor);
91 $normalizePoint(selection.focus);
95 function $normalizePoint(point: PointType): void {
96 while (point.type === 'element') {
97 const node = point.getNode();
98 const offset = point.offset;
101 if (offset === node.getChildrenSize()) {
102 nextNode = node.getChildAtIndex(offset - 1);
103 nextOffsetAtEnd = true;
105 nextNode = node.getChildAtIndex(offset);
106 nextOffsetAtEnd = false;
108 if ($isTextNode(nextNode)) {
111 nextOffsetAtEnd ? nextNode.getTextContentSize() : 0,
115 } else if (!$isElementNode(nextNode)) {
120 nextOffsetAtEnd ? nextNode.getChildrenSize() : 0,