1 import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list";
2 import {EditorConfig} from "lexical/LexicalEditor";
3 import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical";
5 import {el} from "../utils/dom";
6 import {$isCustomListNode} from "./custom-list";
8 function updateListItemChecked(
10 listItemNode: ListItemNode,
12 // Only set task list attrs for leaf list items
13 const shouldBeTaskItem = !$isListNode(listItemNode.getFirstChild());
14 dom.classList.toggle('task-list-item', shouldBeTaskItem);
15 if (listItemNode.__checked) {
16 dom.setAttribute('checked', 'checked');
18 dom.removeAttribute('checked');
23 export class CustomListItemNode extends ListItemNode {
24 static getType(): string {
25 return 'custom-list-item';
28 static clone(node: CustomListItemNode): CustomListItemNode {
29 return new CustomListItemNode(node.__value, node.__checked, node.__key);
32 createDOM(config: EditorConfig): HTMLElement {
33 const element = document.createElement('li');
34 const parent = this.getParent();
36 if ($isListNode(parent) && parent.getListType() === 'check') {
37 updateListItemChecked(element, this);
40 element.value = this.__value;
42 if ($hasNestedListWithoutLabel(this)) {
43 element.style.listStyle = 'none';
50 prevNode: ListItemNode,
54 const parent = this.getParent();
55 if ($isListNode(parent) && parent.getListType() === 'check') {
56 updateListItemChecked(dom, this);
59 dom.style.listStyle = $hasNestedListWithoutLabel(this) ? 'none' : '';
60 // @ts-expect-error - this is always HTMLListItemElement
61 dom.value = this.__value;
66 exportDOM(editor: LexicalEditor): DOMExportOutput {
67 const element = this.createDOM(editor._config);
68 element.style.textAlign = this.getFormatType();
70 if (element.classList.contains('task-list-item')) {
71 const input = el('input', {
75 if (element.hasAttribute('checked')) {
76 input.setAttribute('checked', 'checked');
77 element.removeAttribute('checked');
80 element.prepend(input);
88 exportJSON(): SerializedListItemNode {
90 ...super.exportJSON(),
91 type: 'custom-list-item',
96 function $hasNestedListWithoutLabel(node: CustomListItemNode): boolean {
97 const children = node.getChildren();
99 let hasNestedList = false;
101 for (const child of children) {
102 if ($isCustomListNode(child)) {
103 hasNestedList = true;
104 } else if (child.getTextContent().trim().length > 0) {
109 return hasNestedList && !hasLabel;
112 export function $isCustomListItemNode(
113 node: LexicalNode | null | undefined,
114 ): node is CustomListItemNode {
115 return node instanceof CustomListItemNode;
118 export function $createCustomListItemNode(): CustomListItemNode {
119 return new CustomListItemNode();