]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Merged list nodes
authorDan Brown <redacted>
Tue, 3 Dec 2024 19:03:52 +0000 (19:03 +0000)
committerDan Brown <redacted>
Tue, 3 Dec 2024 19:03:52 +0000 (19:03 +0000)
resources/js/wysiwyg/lexical/list/LexicalListItemNode.ts
resources/js/wysiwyg/lexical/list/LexicalListNode.ts
resources/js/wysiwyg/lexical/list/__tests__/unit/LexicalListItemNode.test.ts
resources/js/wysiwyg/nodes/custom-list-item.ts [deleted file]
resources/js/wysiwyg/nodes/custom-list.ts [deleted file]
resources/js/wysiwyg/nodes/index.ts
resources/js/wysiwyg/services/keyboard-handling.ts
resources/js/wysiwyg/ui/framework/helpers/task-list-handler.ts
resources/js/wysiwyg/utils/formats.ts
resources/js/wysiwyg/utils/lists.ts

index c20329e4be960a4d39d4ec88f1a1512b7837407d..33b021298a67a70bcc8ca1a60129c60fd37e58c1 100644 (file)
@@ -13,7 +13,6 @@ import type {
   DOMConversionOutput,
   DOMExportOutput,
   EditorConfig,
-  EditorThemeClasses,
   LexicalNode,
   NodeKey,
   ParagraphNode,
@@ -22,10 +21,6 @@ import type {
   Spread,
 } from 'lexical';
 
-import {
-  addClassNamesToElement,
-  removeClassNamesFromElement,
-} from '@lexical/utils';
 import {
   $applyNodeReplacement,
   $createParagraphNode,
@@ -36,11 +31,11 @@ import {
   LexicalEditor,
 } from 'lexical';
 import invariant from 'lexical/shared/invariant';
-import normalizeClassNames from 'lexical/shared/normalizeClassNames';
 
 import {$createListNode, $isListNode} from './';
-import {$handleIndent, $handleOutdent, mergeLists} from './formatList';
+import {mergeLists} from './formatList';
 import {isNestedListNode} from './utils';
+import {el} from "../../utils/dom";
 
 export type SerializedListItemNode = Spread<
   {
@@ -74,11 +69,17 @@ export class ListItemNode extends ElementNode {
   createDOM(config: EditorConfig): HTMLElement {
     const element = document.createElement('li');
     const parent = this.getParent();
+
     if ($isListNode(parent) && parent.getListType() === 'check') {
-      updateListItemChecked(element, this, null, parent);
+      updateListItemChecked(element, this);
     }
+
     element.value = this.__value;
-    $setListItemThemeClassNames(element, config.theme, this);
+
+    if ($hasNestedListWithoutLabel(this)) {
+      element.style.listStyle = 'none';
+    }
+
     return element;
   }
 
@@ -89,11 +90,12 @@ export class ListItemNode extends ElementNode {
   ): boolean {
     const parent = this.getParent();
     if ($isListNode(parent) && parent.getListType() === 'check') {
-      updateListItemChecked(dom, this, prevNode, parent);
+      updateListItemChecked(dom, this);
     }
+
+    dom.style.listStyle = $hasNestedListWithoutLabel(this) ? 'none' : '';
     // @ts-expect-error - this is always HTMLListItemElement
     dom.value = this.__value;
-    $setListItemThemeClassNames(dom, config.theme, this);
 
     return false;
   }
@@ -132,6 +134,20 @@ export class ListItemNode extends ElementNode {
 
   exportDOM(editor: LexicalEditor): DOMExportOutput {
     const element = this.createDOM(editor._config);
+
+    if (element.classList.contains('task-list-item')) {
+      const input = el('input', {
+        type: 'checkbox',
+        disabled: 'disabled',
+      });
+      if (element.hasAttribute('checked')) {
+        input.setAttribute('checked', 'checked');
+        element.removeAttribute('checked');
+      }
+
+      element.prepend(input);
+    }
+
     return {
       element,
     };
@@ -390,89 +406,33 @@ export class ListItemNode extends ElementNode {
   }
 }
 
-function $setListItemThemeClassNames(
-  dom: HTMLElement,
-  editorThemeClasses: EditorThemeClasses,
-  node: ListItemNode,
-): void {
-  const classesToAdd = [];
-  const classesToRemove = [];
-  const listTheme = editorThemeClasses.list;
-  const listItemClassName = listTheme ? listTheme.listitem : undefined;
-  let nestedListItemClassName;
-
-  if (listTheme && listTheme.nested) {
-    nestedListItemClassName = listTheme.nested.listitem;
-  }
-
-  if (listItemClassName !== undefined) {
-    classesToAdd.push(...normalizeClassNames(listItemClassName));
-  }
-
-  if (listTheme) {
-    const parentNode = node.getParent();
-    const isCheckList =
-      $isListNode(parentNode) && parentNode.getListType() === 'check';
-    const checked = node.getChecked();
-
-    if (!isCheckList || checked) {
-      classesToRemove.push(listTheme.listitemUnchecked);
-    }
-
-    if (!isCheckList || !checked) {
-      classesToRemove.push(listTheme.listitemChecked);
-    }
+function $hasNestedListWithoutLabel(node: ListItemNode): boolean {
+  const children = node.getChildren();
+  let hasLabel = false;
+  let hasNestedList = false;
 
-    if (isCheckList) {
-      classesToAdd.push(
-        checked ? listTheme.listitemChecked : listTheme.listitemUnchecked,
-      );
+  for (const child of children) {
+    if ($isListNode(child)) {
+      hasNestedList = true;
+    } else if (child.getTextContent().trim().length > 0) {
+      hasLabel = true;
     }
   }
 
-  if (nestedListItemClassName !== undefined) {
-    const nestedListItemClasses = normalizeClassNames(nestedListItemClassName);
-
-    if (node.getChildren().some((child) => $isListNode(child))) {
-      classesToAdd.push(...nestedListItemClasses);
-    } else {
-      classesToRemove.push(...nestedListItemClasses);
-    }
-  }
-
-  if (classesToRemove.length > 0) {
-    removeClassNamesFromElement(dom, ...classesToRemove);
-  }
-
-  if (classesToAdd.length > 0) {
-    addClassNamesToElement(dom, ...classesToAdd);
-  }
+  return hasNestedList && !hasLabel;
 }
 
 function updateListItemChecked(
   dom: HTMLElement,
   listItemNode: ListItemNode,
-  prevListItemNode: ListItemNode | null,
-  listNode: ListNode,
 ): void {
-  // Only add attributes for leaf list items
-  if ($isListNode(listItemNode.getFirstChild())) {
-    dom.removeAttribute('role');
-    dom.removeAttribute('tabIndex');
-    dom.removeAttribute('aria-checked');
+  // Only set task list attrs for leaf list items
+  const shouldBeTaskItem = !$isListNode(listItemNode.getFirstChild());
+  dom.classList.toggle('task-list-item', shouldBeTaskItem);
+  if (listItemNode.__checked) {
+    dom.setAttribute('checked', 'checked');
   } else {
-    dom.setAttribute('role', 'checkbox');
-    dom.setAttribute('tabIndex', '-1');
-
-    if (
-      !prevListItemNode ||
-      listItemNode.__checked !== prevListItemNode.__checked
-    ) {
-      dom.setAttribute(
-        'aria-checked',
-        listItemNode.getChecked() ? 'true' : 'false',
-      );
-    }
+    dom.removeAttribute('checked');
   }
 }
 
index e22fbf7717f3570de675d98a867c1fb8d4fac458..138c895e6b8154f88df1770a626cc68d55253693 100644 (file)
@@ -36,9 +36,11 @@ import {
   updateChildrenListItemValue,
 } from './formatList';
 import {$getListDepth, $wrapInListItem} from './utils';
+import {extractDirectionFromElement} from "../../nodes/_common";
 
 export type SerializedListNode = Spread<
   {
+    id: string;
     listType: ListType;
     start: number;
     tag: ListNodeTagType;
@@ -58,15 +60,18 @@ export class ListNode extends ElementNode {
   __start: number;
   /** @internal */
   __listType: ListType;
+  /** @internal */
+  __id: string = '';
 
   static getType(): string {
     return 'list';
   }
 
   static clone(node: ListNode): ListNode {
-    const listType = node.__listType || TAG_TO_LIST_TYPE[node.__tag];
-
-    return new ListNode(listType, node.__start, node.__key);
+    const newNode = new ListNode(node.__listType, node.__start, node.__key);
+    newNode.__id = node.__id;
+    newNode.__dir = node.__dir;
+    return newNode;
   }
 
   constructor(listType: ListType, start: number, key?: NodeKey) {
@@ -81,6 +86,16 @@ export class ListNode extends ElementNode {
     return this.__tag;
   }
 
+  setId(id: string) {
+    const self = this.getWritable();
+    self.__id = id;
+  }
+
+  getId(): string {
+    const self = this.getLatest();
+    return self.__id;
+  }
+
   setListType(type: ListType): void {
     const writable = this.getWritable();
     writable.__listType = type;
@@ -108,6 +123,14 @@ export class ListNode extends ElementNode {
     dom.__lexicalListType = this.__listType;
     $setListThemeClassNames(dom, config.theme, this);
 
+    if (this.__id) {
+      dom.setAttribute('id', this.__id);
+    }
+
+    if (this.__dir) {
+      dom.setAttribute('dir', this.__dir);
+    }
+
     return dom;
   }
 
@@ -116,7 +139,11 @@ export class ListNode extends ElementNode {
     dom: HTMLElement,
     config: EditorConfig,
   ): boolean {
-    if (prevNode.__tag !== this.__tag) {
+    if (
+        prevNode.__tag !== this.__tag
+        || prevNode.__dir !== this.__dir
+        || prevNode.__id !== this.__id
+    ) {
       return true;
     }
 
@@ -148,8 +175,7 @@ export class ListNode extends ElementNode {
 
   static importJSON(serializedNode: SerializedListNode): ListNode {
     const node = $createListNode(serializedNode.listType, serializedNode.start);
-    node.setFormat(serializedNode.format);
-    node.setIndent(serializedNode.indent);
+    node.setId(serializedNode.id);
     node.setDirection(serializedNode.direction);
     return node;
   }
@@ -177,6 +203,7 @@ export class ListNode extends ElementNode {
       tag: this.getTag(),
       type: 'list',
       version: 1,
+      id: this.__id,
     };
   }
 
@@ -277,28 +304,21 @@ function $setListThemeClassNames(
 }
 
 /*
- * This function normalizes the children of a ListNode after the conversion from HTML,
- * ensuring that they are all ListItemNodes and contain either a single nested ListNode
- * or some other inline content.
+ * This function is a custom normalization function to allow nested lists within list item elements.
+ * Original taken from https://github.com/facebook/lexical/blob/6e10210fd1e113ccfafdc999b1d896733c5c5bea/packages/lexical-list/src/LexicalListNode.ts#L284-L303
+ * With modifications made.
  */
 function $normalizeChildren(nodes: Array<LexicalNode>): Array<ListItemNode> {
   const normalizedListItems: Array<ListItemNode> = [];
-  for (let i = 0; i < nodes.length; i++) {
-    const node = nodes[i];
+
+  for (const node of nodes) {
     if ($isListItemNode(node)) {
       normalizedListItems.push(node);
-      const children = node.getChildren();
-      if (children.length > 1) {
-        children.forEach((child) => {
-          if ($isListNode(child)) {
-            normalizedListItems.push($wrapInListItem(child));
-          }
-        });
-      }
     } else {
       normalizedListItems.push($wrapInListItem(node));
     }
   }
+
   return normalizedListItems;
 }
 
@@ -334,6 +354,14 @@ function $convertListNode(domNode: HTMLElement): DOMConversionOutput {
     }
   }
 
+  if (domNode.id && node) {
+    node.setId(domNode.id);
+  }
+
+  if (domNode.dir && node) {
+    node.setDirection(extractDirectionFromElement(domNode));
+  }
+
   return {
     after: $normalizeChildren,
     node,
index 581db0294f5b2af97da705d762611e8c147f9cf3..523c7eb126ee0d536037cac78dd36cf02c534ca9 100644 (file)
@@ -1265,99 +1265,5 @@ describe('LexicalListItemNode tests', () => {
         expect($isListItemNode(listItemNode)).toBe(true);
       });
     });
-
-    describe('ListItemNode.setIndent()', () => {
-      let listNode: ListNode;
-      let listItemNode1: ListItemNode;
-      let listItemNode2: ListItemNode;
-
-      beforeEach(async () => {
-        const {editor} = testEnv;
-
-        await editor.update(() => {
-          const root = $getRoot();
-          listNode = new ListNode('bullet', 1);
-          listItemNode1 = new ListItemNode();
-
-          listItemNode2 = new ListItemNode();
-
-          root.append(listNode);
-          listNode.append(listItemNode1, listItemNode2);
-          listItemNode1.append(new TextNode('one'));
-          listItemNode2.append(new TextNode('two'));
-        });
-      });
-      it('indents and outdents list item', async () => {
-        const {editor} = testEnv;
-
-        await editor.update(() => {
-          listItemNode1.setIndent(3);
-        });
-
-        await editor.update(() => {
-          expect(listItemNode1.getIndent()).toBe(3);
-        });
-
-        expectHtmlToBeEqual(
-          editor.getRootElement()!.innerHTML,
-          html`
-            <ul>
-              <li value="1">
-                <ul>
-                  <li value="1">
-                    <ul>
-                      <li value="1">
-                        <ul>
-                          <li value="1">
-                            <span data-lexical-text="true">one</span>
-                          </li>
-                        </ul>
-                      </li>
-                    </ul>
-                  </li>
-                </ul>
-              </li>
-              <li value="1">
-                <span data-lexical-text="true">two</span>
-              </li>
-            </ul>
-          `,
-        );
-
-        await editor.update(() => {
-          listItemNode1.setIndent(0);
-        });
-
-        await editor.update(() => {
-          expect(listItemNode1.getIndent()).toBe(0);
-        });
-
-        expectHtmlToBeEqual(
-          editor.getRootElement()!.innerHTML,
-          html`
-            <ul>
-              <li value="1">
-                <span data-lexical-text="true">one</span>
-              </li>
-              <li value="2">
-                <span data-lexical-text="true">two</span>
-              </li>
-            </ul>
-          `,
-        );
-      });
-
-      it('handles fractional indent values', async () => {
-        const {editor} = testEnv;
-
-        await editor.update(() => {
-          listItemNode1.setIndent(0.5);
-        });
-
-        await editor.update(() => {
-          expect(listItemNode1.getIndent()).toBe(0);
-        });
-      });
-    });
   });
 });
diff --git a/resources/js/wysiwyg/nodes/custom-list-item.ts b/resources/js/wysiwyg/nodes/custom-list-item.ts
deleted file mode 100644 (file)
index 11887b4..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical";
-
-import {el} from "../utils/dom";
-import {$isCustomListNode} from "./custom-list";
-
-function updateListItemChecked(
-    dom: HTMLElement,
-    listItemNode: ListItemNode,
-): void {
-    // Only set task list attrs for leaf list items
-    const shouldBeTaskItem = !$isListNode(listItemNode.getFirstChild());
-    dom.classList.toggle('task-list-item', shouldBeTaskItem);
-    if (listItemNode.__checked) {
-        dom.setAttribute('checked', 'checked');
-    } else {
-        dom.removeAttribute('checked');
-    }
-}
-
-
-export class CustomListItemNode extends ListItemNode {
-    static getType(): string {
-        return 'custom-list-item';
-    }
-
-    static clone(node: CustomListItemNode): CustomListItemNode {
-        return new CustomListItemNode(node.__value, node.__checked, node.__key);
-    }
-
-    createDOM(config: EditorConfig): HTMLElement {
-        const element = document.createElement('li');
-        const parent = this.getParent();
-
-        if ($isListNode(parent) && parent.getListType() === 'check') {
-            updateListItemChecked(element, this);
-        }
-
-        element.value = this.__value;
-
-        if ($hasNestedListWithoutLabel(this)) {
-            element.style.listStyle = 'none';
-        }
-
-        return element;
-    }
-
-    updateDOM(
-        prevNode: ListItemNode,
-        dom: HTMLElement,
-        config: EditorConfig,
-    ): boolean {
-        const parent = this.getParent();
-        if ($isListNode(parent) && parent.getListType() === 'check') {
-            updateListItemChecked(dom, this);
-        }
-
-        dom.style.listStyle = $hasNestedListWithoutLabel(this) ? 'none' : '';
-        // @ts-expect-error - this is always HTMLListItemElement
-        dom.value = this.__value;
-
-        return false;
-    }
-
-    exportDOM(editor: LexicalEditor): DOMExportOutput {
-        const element = this.createDOM(editor._config);
-        element.style.textAlign = this.getFormatType();
-
-        if (element.classList.contains('task-list-item')) {
-            const input = el('input', {
-                type: 'checkbox',
-                disabled: 'disabled',
-            });
-            if (element.hasAttribute('checked')) {
-                input.setAttribute('checked', 'checked');
-                element.removeAttribute('checked');
-            }
-
-            element.prepend(input);
-        }
-
-        return {
-            element,
-        };
-    }
-
-    exportJSON(): SerializedListItemNode {
-        return {
-            ...super.exportJSON(),
-            type: 'custom-list-item',
-        };
-    }
-}
-
-function $hasNestedListWithoutLabel(node: CustomListItemNode): boolean {
-    const children = node.getChildren();
-    let hasLabel = false;
-    let hasNestedList = false;
-
-    for (const child of children) {
-        if ($isCustomListNode(child)) {
-            hasNestedList = true;
-        } else if (child.getTextContent().trim().length > 0) {
-            hasLabel = true;
-        }
-    }
-
-    return hasNestedList && !hasLabel;
-}
-
-export function $isCustomListItemNode(
-    node: LexicalNode | null | undefined,
-): node is CustomListItemNode {
-    return node instanceof CustomListItemNode;
-}
-
-export function $createCustomListItemNode(): CustomListItemNode {
-    return new CustomListItemNode();
-}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/nodes/custom-list.ts b/resources/js/wysiwyg/nodes/custom-list.ts
deleted file mode 100644 (file)
index 4b05fa6..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-import {
-    DOMConversionFn,
-    DOMConversionMap, EditorConfig,
-    LexicalNode,
-    Spread
-} from "lexical";
-import {$isListItemNode, ListItemNode, ListNode, ListType, SerializedListNode} from "@lexical/list";
-import {$createCustomListItemNode} from "./custom-list-item";
-import {extractDirectionFromElement} from "./_common";
-
-
-export type SerializedCustomListNode = Spread<{
-    id: string;
-}, SerializedListNode>
-
-export class CustomListNode extends ListNode {
-    __id: string = '';
-
-    static getType() {
-        return 'custom-list';
-    }
-
-    setId(id: string) {
-        const self = this.getWritable();
-        self.__id = id;
-    }
-
-    getId(): string {
-        const self = this.getLatest();
-        return self.__id;
-    }
-
-    static clone(node: CustomListNode) {
-        const newNode = new CustomListNode(node.__listType, node.__start, node.__key);
-        newNode.__id = node.__id;
-        newNode.__dir = node.__dir;
-        return newNode;
-    }
-
-    createDOM(config: EditorConfig): HTMLElement {
-        const dom = super.createDOM(config);
-        if (this.__id) {
-            dom.setAttribute('id', this.__id);
-        }
-
-        if (this.__dir) {
-            dom.setAttribute('dir', this.__dir);
-        }
-
-        return dom;
-    }
-
-    updateDOM(prevNode: ListNode, dom: HTMLElement, config: EditorConfig): boolean {
-        return super.updateDOM(prevNode, dom, config) ||
-            prevNode.__dir !== this.__dir;
-    }
-
-    exportJSON(): SerializedCustomListNode {
-        return {
-            ...super.exportJSON(),
-            type: 'custom-list',
-            version: 1,
-            id: this.__id,
-        };
-    }
-
-    static importJSON(serializedNode: SerializedCustomListNode): CustomListNode {
-        const node = $createCustomListNode(serializedNode.listType);
-        node.setId(serializedNode.id);
-        node.setDirection(serializedNode.direction);
-        return node;
-    }
-
-    static importDOM(): DOMConversionMap | null {
-        // @ts-ignore
-        const converter = super.importDOM().ol().conversion as DOMConversionFn<HTMLElement>;
-        const customConvertFunction = (element: HTMLElement) => {
-            const baseResult = converter(element);
-            if (element.id && baseResult?.node) {
-                (baseResult.node as CustomListNode).setId(element.id);
-            }
-
-            if (element.dir && baseResult?.node) {
-                (baseResult.node as CustomListNode).setDirection(extractDirectionFromElement(element));
-            }
-
-            if (baseResult) {
-                baseResult.after = $normalizeChildren;
-            }
-
-            return baseResult;
-        };
-
-        return {
-            ol: () => ({
-                conversion: customConvertFunction,
-                priority: 0,
-            }),
-            ul: () => ({
-                conversion: customConvertFunction,
-                priority: 0,
-            }),
-        };
-    }
-}
-
-/*
- * This function is a custom normalization function to allow nested lists within list item elements.
- * Original taken from https://github.com/facebook/lexical/blob/6e10210fd1e113ccfafdc999b1d896733c5c5bea/packages/lexical-list/src/LexicalListNode.ts#L284-L303
- * With modifications made.
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- * MIT license
- */
-function $normalizeChildren(nodes: Array<LexicalNode>): Array<ListItemNode> {
-    const normalizedListItems: Array<ListItemNode> = [];
-
-    for (const node of nodes) {
-        if ($isListItemNode(node)) {
-            normalizedListItems.push(node);
-        } else {
-            normalizedListItems.push($wrapInListItem(node));
-        }
-    }
-
-    return normalizedListItems;
-}
-
-function $wrapInListItem(node: LexicalNode): ListItemNode {
-    const listItemWrapper = $createCustomListItemNode();
-    return listItemWrapper.append(node);
-}
-
-export function $createCustomListNode(type: ListType): CustomListNode {
-    return new CustomListNode(type, 1);
-}
-
-export function $isCustomListNode(node: LexicalNode | null | undefined): node is CustomListNode {
-    return node instanceof CustomListNode;
-}
\ No newline at end of file
index 7b274eba13c83eabb09523d2e005d4f0163290d0..7e0ce9daf2bf437fe44019a8f335077825b7350d 100644 (file)
@@ -17,10 +17,8 @@ import {CodeBlockNode} from "./code-block";
 import {DiagramNode} from "./diagram";
 import {EditorUiContext} from "../ui/framework/core";
 import {MediaNode} from "./media";
-import {CustomListItemNode} from "./custom-list-item";
 import {CustomTableCellNode} from "./custom-table-cell";
 import {CustomTableRowNode} from "./custom-table-row";
-import {CustomListNode} from "./custom-list";
 import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
 import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
 
@@ -32,8 +30,8 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         CalloutNode,
         HeadingNode,
         QuoteNode,
-        CustomListNode,
-        CustomListItemNode, // TODO - Alignment?
+        ListNode,
+        ListItemNode,
         CustomTableNode,
         CustomTableRowNode,
         CustomTableCellNode,
@@ -45,18 +43,6 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         MediaNode, // TODO - Alignment
         ParagraphNode,
         LinkNode,
-        {
-            replace: ListNode,
-            with: (node: ListNode) => {
-                return new CustomListNode(node.getListType(), node.getStart());
-            }
-        },
-        {
-            replace: ListItemNode,
-            with: (node: ListItemNode) => {
-                return new CustomListItemNode(node.__value, node.__checked);
-            }
-        },
         {
             replace: TableNode,
             with(node: TableNode) {
index 3f0b0c495e0c724337dd5f8831ca62c5c1898630..5f7f41ef02c12f8bb3a73b601098978d04622fb2 100644 (file)
@@ -14,8 +14,8 @@ import {$isImageNode} from "../nodes/image";
 import {$isMediaNode} from "../nodes/media";
 import {getLastSelection} from "../utils/selection";
 import {$getNearestNodeBlockParent} from "../utils/nodes";
-import {$isCustomListItemNode} from "../nodes/custom-list-item";
 import {$setInsetForSelection} from "../utils/lists";
+import {$isListItemNode} from "@lexical/list";
 
 function isSingleSelectedNode(nodes: LexicalNode[]): boolean {
     if (nodes.length === 1) {
@@ -62,7 +62,7 @@ function handleInsetOnTab(editor: LexicalEditor, event: KeyboardEvent|null): boo
     const change = event?.shiftKey ? -40 : 40;
     const selection = $getSelection();
     const nodes = selection?.getNodes() || [];
-    if (nodes.length > 1 || (nodes.length === 1 && $isCustomListItemNode(nodes[0].getParent()))) {
+    if (nodes.length > 1 || (nodes.length === 1 && $isListItemNode(nodes[0].getParent()))) {
         editor.update(() => {
             $setInsetForSelection(editor, change);
         });
index da8c0eae3dd0bc5dcd95e2a1757c1d8c03ad45e4..62a784d83ed6f8e596f1615547f067b3c7cf0b65 100644 (file)
@@ -1,5 +1,5 @@
 import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
-import {$isCustomListItemNode} from "../../../nodes/custom-list-item";
+import {$isListItemNode} from "@lexical/list";
 
 class TaskListHandler {
     protected editorContainer: HTMLElement;
@@ -38,7 +38,7 @@ class TaskListHandler {
 
         this.editor.update(() => {
             const node = $getNearestNodeFromDOMNode(listItem);
-            if ($isCustomListItemNode(node)) {
+            if ($isListItemNode(node)) {
                 node.setChecked(!node.getChecked());
             }
         });
index d724730e3a28db326c18237457acb2a2e149dec1..1be802ebf1c326e594dd60eeb77fa1af8d7963a9 100644 (file)
@@ -16,8 +16,7 @@ import {
 } from "./selection";
 import {$createCodeBlockNode, $isCodeBlockNode, $openCodeEditorForNode, CodeBlockNode} from "../nodes/code-block";
 import {$createCalloutNode, $isCalloutNode, CalloutCategory} from "../nodes/callout";
-import {insertList, ListNode, ListType, removeList} from "@lexical/list";
-import {$isCustomListNode} from "../nodes/custom-list";
+import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/list";
 import {$createLinkNode, $isLinkNode} from "@lexical/link";
 import {$createHeadingNode, $isHeadingNode, HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
 import {$createQuoteNode, $isQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
@@ -51,7 +50,7 @@ export function toggleSelectionAsList(editor: LexicalEditor, type: ListType) {
     editor.getEditorState().read(() => {
         const selection = $getSelection();
         const listSelected = $selectionContainsNodeType(selection, (node: LexicalNode | null | undefined): boolean => {
-            return $isCustomListNode(node) && (node as ListNode).getListType() === type;
+            return $isListNode(node) && (node as ListNode).getListType() === type;
         });
 
         if (listSelected) {
index 30a97cbc1f985aa806420d9965fbdfbb856c12de..646f341c2ba3d436b2d105f4c247f8a00a8e5846 100644 (file)
@@ -1,22 +1,21 @@
-import {$createCustomListItemNode, $isCustomListItemNode, CustomListItemNode} from "../nodes/custom-list-item";
-import {$createCustomListNode, $isCustomListNode} from "../nodes/custom-list";
 import {$getSelection, BaseSelection, LexicalEditor} from "lexical";
 import {$getBlockElementNodesInSelection, $selectNodes, $toggleSelection} from "./selection";
 import {nodeHasInset} from "./nodes";
+import {$createListItemNode, $createListNode, $isListItemNode, $isListNode, ListItemNode} from "@lexical/list";
 
 
-export function $nestListItem(node: CustomListItemNode): CustomListItemNode {
+export function $nestListItem(node: ListItemNode): ListItemNode {
     const list = node.getParent();
-    if (!$isCustomListNode(list)) {
+    if (!$isListNode(list)) {
         return node;
     }
 
-    const listItems = list.getChildren() as CustomListItemNode[];
+    const listItems = list.getChildren() as ListItemNode[];
     const nodeIndex = listItems.findIndex((n) => n.getKey() === node.getKey());
     const isFirst = nodeIndex === 0;
 
-    const newListItem = $createCustomListItemNode();
-    const newList = $createCustomListNode(list.getListType());
+    const newListItem = $createListItemNode();
+    const newList = $createListNode(list.getListType());
     newList.append(newListItem);
     newListItem.append(...node.getChildren());
 
@@ -31,11 +30,11 @@ export function $nestListItem(node: CustomListItemNode): CustomListItemNode {
     return newListItem;
 }
 
-export function $unnestListItem(node: CustomListItemNode): CustomListItemNode {
+export function $unnestListItem(node: ListItemNode): ListItemNode {
     const list = node.getParent();
     const parentListItem = list?.getParent();
     const outerList = parentListItem?.getParent();
-    if (!$isCustomListNode(list) || !$isCustomListNode(outerList) || !$isCustomListItemNode(parentListItem)) {
+    if (!$isListNode(list) || !$isListNode(outerList) || !$isListItemNode(parentListItem)) {
         return node;
     }
 
@@ -51,19 +50,19 @@ export function $unnestListItem(node: CustomListItemNode): CustomListItemNode {
     return node;
 }
 
-function getListItemsForSelection(selection: BaseSelection|null): (CustomListItemNode|null)[] {
+function getListItemsForSelection(selection: BaseSelection|null): (ListItemNode|null)[] {
     const nodes = selection?.getNodes() || [];
     const listItemNodes = [];
 
     outer: for (const node of nodes) {
-        if ($isCustomListItemNode(node)) {
+        if ($isListItemNode(node)) {
             listItemNodes.push(node);
             continue;
         }
 
         const parents = node.getParents();
         for (const parent of parents) {
-            if ($isCustomListItemNode(parent)) {
+            if ($isListItemNode(parent)) {
                 listItemNodes.push(parent);
                 continue outer;
             }
@@ -75,8 +74,8 @@ function getListItemsForSelection(selection: BaseSelection|null): (CustomListIte
     return listItemNodes;
 }
 
-function $reduceDedupeListItems(listItems: (CustomListItemNode|null)[]): CustomListItemNode[] {
-    const listItemMap: Record<string, CustomListItemNode> = {};
+function $reduceDedupeListItems(listItems: (ListItemNode|null)[]): ListItemNode[] {
+    const listItemMap: Record<string, ListItemNode> = {};
 
     for (const item of listItems) {
         if (item === null) {