Skip to content

Commit

Permalink
fix: Improve performance of updateChildrenListItemValue facebook#5589
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed Feb 6, 2024
1 parent 48c19cf commit 70adb2c
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 96 deletions.
45 changes: 8 additions & 37 deletions packages/lexical-list/src/LexicalListItemNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ import {
import invariant from 'shared/invariant';

import {$createListNode, $isListNode} from './';
import {
$handleIndent,
$handleOutdent,
mergeLists,
updateChildrenListItemValue,
} from './formatList';
import {$handleIndent, $handleOutdent, mergeLists} from './formatList';
import {isNestedListNode} from './utils';

export type SerializedListItemNode = Spread<
Expand Down Expand Up @@ -105,10 +100,12 @@ export class ListItemNode extends ElementNode {

static transform(): (node: LexicalNode) => void {
return (node: LexicalNode) => {
invariant($isListItemNode(node), 'node is not a ListItemNode');
if (node.__checked == null) {
return;
}
const parent = node.getParent();
if ($isListNode(parent)) {
updateChildrenListItemValue(parent);
invariant($isListItemNode(node), 'node is not a ListItemNode');
if (parent.getListType() !== 'check' && node.getChecked() != null) {
node.setChecked(undefined);
}
Expand Down Expand Up @@ -220,19 +217,12 @@ export class ListItemNode extends ElementNode {
);
}

const siblings = this.getNextSiblings();

if ($isListItemNode(node)) {
const after = super.insertAfter(node, restoreSelection);
const afterListNode = node.getParentOrThrow();

if ($isListNode(afterListNode)) {
updateChildrenListItemValue(afterListNode);
}

return after;
return super.insertAfter(node, restoreSelection);
}

const siblings = this.getNextSiblings();

// Attempt to merge if the list is of the same type.

if ($isListNode(node)) {
Expand Down Expand Up @@ -276,12 +266,6 @@ export class ListItemNode extends ElementNode {
) {
mergeLists(prevSibling.getFirstChild(), nextSibling.getFirstChild());
nextSibling.remove();
} else if (nextSibling) {
const parent = nextSibling.getParent();

if ($isListNode(parent)) {
updateChildrenListItemValue(parent);
}
}
}

Expand Down Expand Up @@ -398,19 +382,6 @@ export class ListItemNode extends ElementNode {
return this;
}

insertBefore(nodeToInsert: LexicalNode): LexicalNode {
if ($isListItemNode(nodeToInsert)) {
const parent = this.getParentOrThrow();

if ($isListNode(parent)) {
const siblings = this.getNextSiblings();
updateChildrenListItemValue(parent, siblings);
}
}

return super.insertBefore(nodeToInsert);
}

canInsertAfter(node: LexicalNode): boolean {
return $isListItemNode(node);
}
Expand Down
9 changes: 8 additions & 1 deletion packages/lexical-list/src/LexicalListNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
SerializedElementNode,
Spread,
} from 'lexical';
import invariant from 'shared/invariant';

import {$createListItemNode, $isListItemNode, ListItemNode} from '.';
import {updateChildrenListItemValue} from './formatList';
Expand Down Expand Up @@ -120,6 +121,13 @@ export class ListNode extends ElementNode {
return false;
}

static transform(): (node: LexicalNode) => void {
return (node: LexicalNode) => {
invariant($isListNode(node), 'node is not a ListNode');
updateChildrenListItemValue(node);
};
}

static importDOM(): DOMConversionMap | null {
return {
ol: (node: Node) => ({
Expand Down Expand Up @@ -195,7 +203,6 @@ export class ListNode extends ElementNode {
super.append(listItemNode);
}
}
updateChildrenListItemValue(this);
return this;
}

Expand Down
73 changes: 15 additions & 58 deletions packages/lexical-list/src/formatList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,33 +52,6 @@ function $isSelectingEmptyListItem(
);
}

function $getListItemValue(listItem: ListItemNode): number {
const list = listItem.getParent();

let value = 1;

if (list != null) {
if (!$isListNode(list)) {
invariant(
false,
'$getListItemValue: list node is not parent of list item node',
);
} else {
value = list.getStart();
}
}

const siblings = listItem.getPreviousSiblings();
for (let i = 0; i < siblings.length; i++) {
const sibling = siblings[i];

if ($isListItemNode(sibling) && !$isListNode(sibling.getFirstChild())) {
value++;
}
}
return value;
}

/**
* Inserts a new ListNode. If the selection's anchor node is an empty ListItemNode and is a child of
* the root/shadow root, it will replace the ListItemNode with a ListNode and the old ListItemNode.
Expand Down Expand Up @@ -147,7 +120,6 @@ export function insertList(editor: LexicalEditor, listType: ListType): void {
const newListNode = $createListNode(listType);
append(newListNode, parent.getChildren());
parent.replace(newListNode);
updateChildrenListItemValue(newListNode);
handled.add(parentKey);
}

Expand Down Expand Up @@ -214,7 +186,6 @@ function createListOrMerge(node: ElementNode, listType: ListType): ListNode {
const list = $createListNode(listType);
list.append(listItem);
node.replace(list);
updateChildrenListItemValue(list);
return list;
}
}
Expand Down Expand Up @@ -242,7 +213,6 @@ export function mergeLists(list1: ListNode, list2: ListNode): void {
const toMerge = list2.getChildren();
if (toMerge.length > 0) {
list1.append(...toMerge);
updateChildrenListItemValue(list1);
}

list2.remove();
Expand Down Expand Up @@ -316,26 +286,23 @@ export function removeList(editor: LexicalEditor): void {

/**
* Takes the value of a child ListItemNode and makes it the value the ListItemNode
* should be if it isn't already. If only certain children should be updated, they
* can be passed optionally in an array.
* should be if it isn't already. Also ensures that checked is undefined if the
* parent does not have a list type of 'check'.
* @param list - The list whose children are updated.
* @param children - An array of the children to be updated.
*/
export function updateChildrenListItemValue(
list: ListNode,
children?: Array<LexicalNode>,
): void {
const childrenOrExisting = children || list.getChildren();
if (childrenOrExisting !== undefined) {
for (let i = 0; i < childrenOrExisting.length; i++) {
const child = childrenOrExisting[i];
if ($isListItemNode(child)) {
const prevValue = child.getValue();
const nextValue = $getListItemValue(child);

if (prevValue !== nextValue) {
child.setValue(nextValue);
}
export function updateChildrenListItemValue(list: ListNode): void {
const isNotChecklist = list.getListType() !== 'check';
let value = list.getStart();
for (const child of list.getChildren()) {
if ($isListItemNode(child)) {
if (child.getValue() !== value) {
child.setValue(value);
}
if (isNotChecklist && child.getChecked() != null) {
child.setChecked(undefined);
}
if (!$isListNode(child.getFirstChild())) {
value++;
}
}
}
Expand Down Expand Up @@ -377,7 +344,6 @@ export function $handleIndent(listItemNode: ListItemNode): void {
nextSibling.remove();
removed.add(nextSibling.getKey());
}
updateChildrenListItemValue(innerList);
}
} else if (isNestedListNode(nextSibling)) {
// if the ListItemNode is next to a nested ListNode, merge them
Expand All @@ -389,14 +355,12 @@ export function $handleIndent(listItemNode: ListItemNode): void {
if (firstChild !== null) {
firstChild.insertBefore(listItemNode);
}
updateChildrenListItemValue(innerList);
}
} else if (isNestedListNode(previousSibling)) {
const innerList = previousSibling.getFirstChild();

if ($isListNode(innerList)) {
innerList.append(listItemNode);
updateChildrenListItemValue(innerList);
}
} else {
// otherwise, we need to create a new nested ListNode
Expand All @@ -414,13 +378,8 @@ export function $handleIndent(listItemNode: ListItemNode): void {
} else {
parent.append(newListItem);
}
updateChildrenListItemValue(newList);
}
}

if ($isListNode(parent)) {
updateChildrenListItemValue(parent);
}
}

/**
Expand Down Expand Up @@ -485,8 +444,6 @@ export function $handleOutdent(listItemNode: ListItemNode): void {
// replace the grandparent list item (now between the siblings) with the outdented list item.
grandparentListItem.replace(listItemNode);
}
updateChildrenListItemValue(parentList);
updateChildrenListItemValue(greatGrandparentList);
}
}

Expand Down

0 comments on commit 70adb2c

Please sign in to comment.