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);
58 // @ts-expect-error - this is always HTMLListItemElement
59 dom.value = this.__value;
64 exportDOM(editor: LexicalEditor): DOMExportOutput {
65 const element = this.createDOM(editor._config);
66 element.style.textAlign = this.getFormatType();
68 if (element.classList.contains('task-list-item')) {
69 const input = el('input', {
73 if (element.hasAttribute('checked')) {
74 input.setAttribute('checked', 'checked');
75 element.removeAttribute('checked');
78 element.prepend(input);
86 exportJSON(): SerializedListItemNode {
88 ...super.exportJSON(),
89 type: 'custom-list-item',
94 function $hasNestedListWithoutLabel(node: CustomListItemNode): boolean {
95 const children = node.getChildren();
97 let hasNestedList = false;
99 for (const child of children) {
100 if ($isCustomListNode(child)) {
101 hasNestedList = true;
102 } else if (child.getTextContent().trim().length > 0) {
107 return hasNestedList && !hasLabel;
110 export function $isCustomListItemNode(
111 node: LexicalNode | null | undefined,
112 ): node is CustomListItemNode {
113 return node instanceof CustomListItemNode;
116 export function $createCustomListItemNode(): CustomListItemNode {
117 return new CustomListItemNode();