Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@lexical/list

Package Overview
Dependencies
Maintainers
6
Versions
611
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lexical/list - npm Package Compare versions

Comparing version
0.44.1-nightly.20260519.0
to
0.45.0
+19
dist/checkList.d.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalCommand, LexicalEditor } from 'lexical';
import { Signal } from '@lexical/extension';
export declare const INSERT_CHECK_LIST_COMMAND: LexicalCommand<void>;
/**
* Registers the checklist plugin with the editor.
* @param editor The LexicalEditor instance.
* @param options Optional configuration.
* - disableTakeFocusOnClick: If true, clicking a checklist item will not focus the editor (useful for mobile).
*/
export declare function registerCheckList(editor: LexicalEditor, options?: {
disableTakeFocusOnClick?: boolean | Signal<boolean>;
}): () => void;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { ListItemNode, ListNode } from './';
import { ListType } from './LexicalListNode';
/**
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export declare function $insertList(listType: ListType): void;
/**
* A recursive function that goes through each list and their children, including nested lists,
* appending list2 children after list1 children and updating ListItemNode values.
* @param list1 - The first list to be merged.
* @param list2 - The second list to be merged.
*/
export declare function mergeLists(list1: ListNode, list2: ListNode): void;
/**
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
*/
export declare function $removeList(): void;
/**
* Takes the value of a child ListItemNode and makes it the value the ListItemNode
* 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.
*/
export declare function updateChildrenListItemValue(list: ListNode): void;
/**
* Merge the next sibling list if same type.
* <ul> will merge with <ul>, but NOT <ul> with <ol>.
* @param list - The list whose next sibling should be potentially merged
*/
export declare function mergeNextSiblingListIfSameType(list: ListNode): void;
/**
* Adds an empty ListNode/ListItemNode chain at listItemNode, so as to
* create an indent effect. Won't indent ListItemNodes that have a ListNode as
* a child, but does merge sibling ListItemNodes if one has a nested ListNode.
* @param listItemNode - The ListItemNode to be indented.
*/
export declare function $handleIndent(listItemNode: ListItemNode): void;
/**
* Removes an indent by removing an empty ListNode/ListItemNode chain. An indented ListItemNode
* has a great grandparent node of type ListNode, which is where the ListItemNode will reside
* within as a child.
* @param listItemNode - The ListItemNode to remove the indent (outdent).
*/
export declare function $handleOutdent(listItemNode: ListItemNode): void;
/**
* Attempts to insert a ParagraphNode at selection and selects the new node. The selection must contain a ListItemNode
* or a node that does not already contain text. If its grandparent is the root/shadow root, it will get the ListNode
* (which should be the parent node) and insert the ParagraphNode as a sibling to the ListNode. If the ListNode is
* nested in a ListItemNode instead, it will add the ParagraphNode after the grandparent ListItemNode.
* Throws an invariant if the selection is not a child of a ListNode.
* @returns true if a ParagraphNode was inserted successfully, false if there is no selection
* or the selection does not contain a ListItemNode or the node already holds text.
*/
export declare function $handleListInsertParagraph(restoreNumbering?: boolean): boolean;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { SerializedListItemNode } from './LexicalListItemNode';
import type { ListNodeTagType, ListType, SerializedListNode } from './LexicalListNode';
import type { LexicalEditor } from 'lexical';
import { INSERT_CHECK_LIST_COMMAND, registerCheckList } from './checkList';
import { $handleListInsertParagraph, $insertList, $removeList } from './formatList';
import { $createListItemNode, $isListItemNode, ListItemNode } from './LexicalListItemNode';
import { $createListNode, $isListNode, ListNode } from './LexicalListNode';
import { $getListDepth } from './utils';
export { type CheckListConfig, CheckListExtension, type ListConfig, ListExtension, } from './LexicalListExtension';
export { ListImportExtension, ListImportRules, ListSchema, } from './ListImportExtension';
export { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, registerList, type RegisterListOptions, registerListStrictIndentTransform, REMOVE_LIST_COMMAND, UPDATE_LIST_START_COMMAND, } from './registerList';
export { $createListItemNode, $createListNode, $getListDepth, $handleListInsertParagraph, $insertList, $isListItemNode, $isListNode, $removeList, INSERT_CHECK_LIST_COMMAND, ListItemNode, ListNode, ListNodeTagType, ListType, registerCheckList, SerializedListItemNode, SerializedListNode, };
/**
* @deprecated use {@link $insertList} from an update or command listener.
*
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param editor - The lexical editor.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export declare function insertList(editor: LexicalEditor, listType: ListType): void;
/**
* @deprecated use {@link $removeList} from an update or command listener.
*
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
* @param editor - The lexical editor.
*/
export declare function removeList(editor: LexicalEditor): void;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict'
const LexicalList = process.env.NODE_ENV !== 'production' ? require('./LexicalList.dev.js') : require('./LexicalList.prod.js');
module.exports = LexicalList;

Sorry, the diff of this file is not supported yet

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import * as modDev from './LexicalList.dev.mjs';
import * as modProd from './LexicalList.prod.mjs';
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
export const $createListItemNode = mod.$createListItemNode;
export const $createListNode = mod.$createListNode;
export const $getListDepth = mod.$getListDepth;
export const $handleListInsertParagraph = mod.$handleListInsertParagraph;
export const $insertList = mod.$insertList;
export const $isListItemNode = mod.$isListItemNode;
export const $isListNode = mod.$isListNode;
export const $removeList = mod.$removeList;
export const CheckListExtension = mod.CheckListExtension;
export const INSERT_CHECK_LIST_COMMAND = mod.INSERT_CHECK_LIST_COMMAND;
export const INSERT_ORDERED_LIST_COMMAND = mod.INSERT_ORDERED_LIST_COMMAND;
export const INSERT_UNORDERED_LIST_COMMAND = mod.INSERT_UNORDERED_LIST_COMMAND;
export const ListExtension = mod.ListExtension;
export const ListImportExtension = mod.ListImportExtension;
export const ListImportRules = mod.ListImportRules;
export const ListItemNode = mod.ListItemNode;
export const ListNode = mod.ListNode;
export const ListSchema = mod.ListSchema;
export const REMOVE_LIST_COMMAND = mod.REMOVE_LIST_COMMAND;
export const UPDATE_LIST_START_COMMAND = mod.UPDATE_LIST_START_COMMAND;
export const insertList = mod.insertList;
export const registerCheckList = mod.registerCheckList;
export const registerList = mod.registerList;
export const registerListStrictIndentTransform = mod.registerListStrictIndentTransform;
export const removeList = mod.removeList;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalList.dev.mjs') : import('./LexicalList.prod.mjs'));
export const $createListItemNode = mod.$createListItemNode;
export const $createListNode = mod.$createListNode;
export const $getListDepth = mod.$getListDepth;
export const $handleListInsertParagraph = mod.$handleListInsertParagraph;
export const $insertList = mod.$insertList;
export const $isListItemNode = mod.$isListItemNode;
export const $isListNode = mod.$isListNode;
export const $removeList = mod.$removeList;
export const CheckListExtension = mod.CheckListExtension;
export const INSERT_CHECK_LIST_COMMAND = mod.INSERT_CHECK_LIST_COMMAND;
export const INSERT_ORDERED_LIST_COMMAND = mod.INSERT_ORDERED_LIST_COMMAND;
export const INSERT_UNORDERED_LIST_COMMAND = mod.INSERT_UNORDERED_LIST_COMMAND;
export const ListExtension = mod.ListExtension;
export const ListImportExtension = mod.ListImportExtension;
export const ListImportRules = mod.ListImportRules;
export const ListItemNode = mod.ListItemNode;
export const ListNode = mod.ListNode;
export const ListSchema = mod.ListSchema;
export const REMOVE_LIST_COMMAND = mod.REMOVE_LIST_COMMAND;
export const UPDATE_LIST_START_COMMAND = mod.UPDATE_LIST_START_COMMAND;
export const insertList = mod.insertList;
export const registerCheckList = mod.registerCheckList;
export const registerList = mod.registerList;
export const registerListStrictIndentTransform = mod.registerListStrictIndentTransform;
export const removeList = mod.removeList;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
"use strict";var e=require("@lexical/utils"),t=require("lexical"),n=require("@lexical/extension"),r=require("@lexical/html");function i(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function s(e){let t=1,n=e.getParent();for(;null!=n;){if(O(n)){const e=n.getParent();if(M(e)){t++,n=e.getParent();continue}i(40)}return t}return t}function o(e){let t=e.getParent();M(t)||i(40);let n=t;for(;null!==n;)n=n.getParent(),M(n)&&(t=n);return t}function l(e){let t=[];const n=e.getChildren().filter(O);for(let e=0;e<n.length;e++){const r=n[e],i=r.getFirstChild();M(i)?t=t.concat(l(i)):t.push(r)}return t}function c(e){return O(e)&&M(e.getFirstChild())}function a(e,t){return O(e)&&(0===t.length||1===t.length&&e.is(t[0])&&0===e.getChildrenSize())}function d(e){const n=t.$getSelection();if(null!==n){let r=n.getNodes();if(t.$isRangeSelection(n)){const[i]=n.getStartEndPoints(),s=i.getNode(),o=s.getParent();if(t.$isRootOrShadowRoot(s)){const e=s.getFirstChild();if(e)r=e.selectStart().getNodes();else{const e=t.$createParagraphNode();s.append(e),r=e.select().getNodes()}}else if(a(s,r)){const n=k(e);if(t.$isRootOrShadowRoot(o)){s.replace(n);const e=x();t.$isElementNode(s)&&(e.setFormat(s.getFormatType()),e.setIndent(s.getIndent())),n.append(e)}else if(O(s)){const e=s.getParentOrThrow();g(n,e.getChildren()),e.replace(n)}return}}const i=new Set;for(let n=0;n<r.length;n++){const s=r[n];if(t.$isElementNode(s)&&s.isEmpty()&&!O(s)&&!i.has(s.getKey())){u(s,e);continue}let o=t.$isLeafNode(s)?s.getParent():O(s)&&s.isEmpty()?s:null;for(;null!=o;){const n=o.getKey();if(M(o)){if(!i.has(n)){const t=k(e);g(t,o.getChildren()),o.replace(t),i.add(n)}break}{const r=o.getParent();if(t.$isRootOrShadowRoot(r)&&!i.has(n)){i.add(n),u(o,e);break}o=r}}}}}function g(e,t){e.splice(e.getChildrenSize(),0,t)}function u(e,n){if(M(e))return e;const r=e.getPreviousSibling(),i=e.getNextSibling(),s=x();let o;if(g(s,e.getChildren()),M(r)&&n===r.getListType())r.append(s),M(i)&&n===i.getListType()&&(g(r,i.getChildren()),i.remove()),o=r;else if(M(i)&&n===i.getListType())i.getFirstChildOrThrow().insertBefore(s),o=i;else{const t=k(n);t.append(s),e.replace(t),o=t}s.setFormat(e.getFormatType()),s.setIndent(e.getIndent());const l=t.$getSelection();return t.$isRangeSelection(l)&&(o.getKey()===l.anchor.key&&l.anchor.set(s.getKey(),l.anchor.offset,"element"),o.getKey()===l.focus.key&&l.focus.set(s.getKey(),l.focus.offset,"element")),e.remove(),o}function h(e,t){const n=e.getLastChild(),r=t.getFirstChild();n&&r&&c(n)&&c(r)&&(h(n.getFirstChild(),r.getFirstChild()),r.remove());const i=t.getChildren();i.length>0&&e.append(...i),t.remove()}function p(){const n=t.$getSelection();if(t.$isRangeSelection(n)){const r=new Set,i=n.getNodes(),s=n.anchor.getNode();if(a(s,i))r.add(o(s));else for(let n=0;n<i.length;n++){const s=i[n];if(t.$isLeafNode(s)){const t=e.$getNearestNodeOfType(s,N);null!=t&&r.add(o(t))}}for(const e of r){let r=e;const i=l(e);for(const e of i){const i=t.$createParagraphNode().setTextStyle(n.style).setTextFormat(n.format);g(i,e.getChildren()),r.insertAfter(i),r=i,e.__key===n.anchor.key&&t.$setPointFromCaret(n.anchor,t.$normalizeCaret(t.$getChildCaret(i,"next"))),e.__key===n.focus.key&&t.$setPointFromCaret(n.focus,t.$normalizeCaret(t.$getChildCaret(i,"next"))),e.remove()}e.remove()}}}function f(e){const t="check"!==e.getListType();let n=e.getStart();for(const r of e.getChildren())O(r)&&(r.getValue()!==n&&r.setValue(n),t&&null!=r.getLatest().__checked&&r.setChecked(void 0),M(r.getFirstChild())||n++)}function m(e){const n=new Set;if(c(e)||n.has(e.getKey()))return;const r=e.getParent(),i=e.getNextSibling(),s=e.getPreviousSibling();if(c(i)&&c(s)){const t=s.getFirstChild();if(M(t)){t.append(e);const r=i.getFirstChild();if(M(r)){g(t,r.getChildren()),i.remove(),n.add(i.getKey())}}}else if(c(i)){const t=i.getFirstChild();if(M(t)){const n=t.getFirstChild();null!==n&&n.insertBefore(e)}}else if(c(s)){const t=s.getFirstChild();M(t)&&t.append(e)}else if(M(r)){const n=t.$copyNode(e),o=t.$copyNode(r);n.append(o),o.append(e),s?s.insertAfter(n):i?i.insertBefore(n):r.append(n)}}function _(e){if(c(e))return;const n=e.getParent(),r=n?n.getParent():void 0;if(M(r?r.getParent():void 0)&&O(r)&&M(n)){const i=n?n.getFirstChild():void 0,s=n?n.getLastChild():void 0;if(e.is(i))r.insertBefore(e),n.isEmpty()&&r.remove();else if(e.is(s))r.insertAfter(e),n.isEmpty()&&r.remove();else{const i=t.$copyNode(e),s=t.$copyNode(n);i.append(s),e.getPreviousSiblings().forEach(e=>s.append(e));const o=t.$copyNode(e),l=t.$copyNode(n);o.append(l),g(l,e.getNextSiblings()),r.insertBefore(i),r.insertAfter(o),r.replace(e)}}}function C(e=!1){const n=t.$getSelection();if(!t.$isRangeSelection(n)||!n.isCollapsed())return!1;const r=n.anchor.getNode();let s=null;if(O(r)&&0===r.getChildrenSize())s=r;else if(t.$isTextNode(r)){const e=r.getParent();O(e)&&e.getChildren().every(e=>t.$isTextNode(e)&&""===e.getTextContent().trim())&&(s=e)}if(null===s)return!1;const l=o(s),c=s.getParent();M(c)||i(40);const a=c.getParent();let d;if(t.$isRootOrShadowRoot(a))d=t.$createParagraphNode(),l.insertAfter(d);else{if(!O(a))return!1;d=t.$copyNode(a),a.insertAfter(d)}d.setTextStyle(n.style).setTextFormat(n.format).select();const g=s.getNextSiblings();if(g.length>0){const n=e?function(e,t){return e.getStart()+t.getIndexWithinParent()}(c,s):1,r=t.$copyNode(c).setStart(n);if(O(d)){const e=t.$copyNode(d);e.append(r),d.insertAfter(e)}else d.insertAfter(r);r.append(...g)}return function(e){let t=e;for(;null==t.getNextSibling()&&null==t.getPreviousSibling();){const e=t.getParent();if(null==e||!O(e)&&!M(e))break;t=e}t.remove()}(s),!0}class N extends t.ElementNode{__value;__checked;$config(){return this.config("listitem",{$transform:n=>{const r=n.getParent();if(M(r))"check"!==r.getListType()&&null!=n.getChecked()&&n.setChecked(void 0);else if(r){const s=n.createParentElementNode();M(s)||i(340);const o=[n];for(const e of["previous","next"]){o.reverse();for(const{origin:r}of t.$getSiblingCaret(n,e)){if(!O(r))break;o.push(r)}}n.insertBefore(s),s.splice(0,0,o),t.$isRootOrShadowRoot(r)||(e.$insertNodeToNearestRootAtCaret(s,t.$rewindSiblingCaret(t.$getSiblingCaret(s,"next")),{$shouldSplit:()=>!1,removeEmptyDestination:!0}),r.isEmpty()&&r.isAttached()&&r.remove())}},extends:t.ElementNode,importDOM:t.buildImportMap({li:()=>({conversion:y,priority:0})})})}constructor(e=1,t=void 0,n){super(n),this.__value=void 0===e?1:e,this.__checked=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__value=e.__value,this.__checked=e.__checked}createDOM(e){const t=document.createElement("li");return this.updateListItemDOM(null,t,e),t}updateListItemDOM(n,r,i){!function(e,t){const n=t.getParent();!M(n)||"check"!==n.getListType()||M(t.getFirstChild())?(e.removeAttribute("role"),e.removeAttribute("tabIndex"),e.removeAttribute("aria-checked")):(e.setAttribute("role","checkbox"),e.setAttribute("tabIndex","-1"),e.setAttribute("aria-checked",t.getChecked()?"true":"false"))}(r,this),r.value=this.__value,function(n,r,i){const s=r.list;if(!s)return;const o=s.listitem,l=s.nested&&s.nested.listitem,c=i.getParent(),a=M(c)&&"check"===c.getListType(),d=i.getChecked(),g=i.getChildren().some(e=>M(e)),u=[];void 0!==s.listitemChecked&&u.push(s.listitemChecked);void 0!==s.listitemUnchecked&&u.push(s.listitemUnchecked);void 0!==l&&u.push(...t.normalizeClassNames(l));u.length>0&&e.removeClassNamesFromElement(n,...u);const h=[];void 0!==o&&h.push(...t.normalizeClassNames(o));if(a){const e=d?s.listitemChecked:s.listitemUnchecked;void 0!==e&&h.push(e)}void 0!==l&&g&&h.push(...t.normalizeClassNames(l));h.length>0&&e.addClassNamesToElement(n,...h)}(r,i.theme,this);const s=n?n.__style:"",o=this.__style;s!==o&&t.setDOMStyleFromCSS(r.style,o,s),function(e,n,r){const i=n.__textStyle,s=r?r.__textStyle:"";if(null!==r&&s===i)return;const o=t.getStyleObjectFromCSS(i);for(const t in o)e.style.setProperty(`--listitem-marker-${t}`,o[t]);if(""!==s)for(const n in t.getStyleObjectFromCSS(s))n in o||e.style.removeProperty(`--listitem-marker-${n}`)}(r,this,n)}updateDOM(e,t,n){const r=t;return this.updateListItemDOM(e,r,n),!1}updateFromJSON(e){return super.updateFromJSON(e).setValue(e.value).setChecked(e.checked)}exportDOM(e){const n=this.createDOM(e._config),r=this.getFormatType();r&&(n.style.textAlign=r);const i=this.getDirection();return i&&(n.dir=i),c(this)?{after(e){if(t.isHTMLElement(e)){const n=e.previousElementSibling;if(t.isHTMLElement(n)&&"LI"===n.nodeName){for(;e.firstChild;)n.append(e.firstChild);e.remove()}}return e},element:n}:{element:n}}exportJSON(){return{...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...e){for(let n=0;n<e.length;n++){const r=e[n];if(t.$isElementNode(r)&&this.canMergeWith(r)){const e=r.getChildren();this.append(...e),r.remove()}else super.append(r)}return this}replace(e,n){if(O(e))return super.replace(e);this.setIndent(0);const r=this.getParentOrThrow();if(!M(r))return e;if(r.__first===this.getKey())r.insertBefore(e);else if(r.__last===this.getKey())r.insertAfter(e);else{const n=t.$copyNode(r);let i=this.getNextSibling();for(;i;){const e=i;i=i.getNextSibling(),n.append(e)}r.insertAfter(e),e.insertAfter(n)}const s=this.__key;let o=0;if(n&&(t.$isElementNode(e)||i(139),o=e.getChildrenSize(),e.splice(o,0,this.getChildren())),n&&t.$isElementNode(e)){const n=t.$getSelection();if(t.$isRangeSelection(n))for(const t of n.getStartEndPoints())t.key===s&&"element"===t.type&&t.set(e.getKey(),o+t.offset,"element")}return this.remove(),0===r.getChildrenSize()&&r.remove(),e}insertAfter(e,n=!0){const r=this.getParentOrThrow();if(M(r)||i(39),O(e))return super.insertAfter(e,n);const s=this.getNextSiblings();if(r.insertAfter(e,n),0!==s.length){const i=t.$copyNode(r);s.forEach(e=>i.append(e)),e.insertAfter(i,n)}return e}remove(e){const t=this.getPreviousSibling(),n=this.getNextSibling();super.remove(e),t&&n&&c(t)&&c(n)&&(h(t.getFirstChild(),n.getFirstChild()),n.remove())}resetOnCopyNodeFrom(e){super.resetOnCopyNodeFrom(e),e.getChecked()&&this.setChecked(!1)}insertNewAfter(e,n=!0){const r=t.$copyNode(this);return this.insertAfter(r,n),r}collapseAtStart(e){const n=t.$createParagraphNode();this.getChildren().forEach(e=>n.append(e));const r=this.getParentOrThrow(),i=r.getParentOrThrow(),s=O(i);if(1===r.getChildrenSize())if(s)r.remove(),i.select();else{r.insertBefore(n),r.remove();const t=e.anchor,i=e.focus,s=n.getKey();"element"===t.type&&t.getNode().is(this)&&t.set(s,t.offset,"element"),"element"===i.type&&i.getNode().is(this)&&i.set(s,i.offset,"element")}else r.insertBefore(n),this.remove();return!0}getValue(){return this.getLatest().__value}setValue(e){const t=this.getWritable();return t.__value=e,t}getChecked(){const e=this.getLatest();let t;const n=this.getParent();return M(n)&&(t=n.getListType()),"check"===t?Boolean(e.__checked):void 0}setChecked(e){const t=this.getWritable();return t.__checked=e,t}toggleChecked(){const e=this.getWritable();return e.setChecked(!e.__checked)}getIndent(){const e=this.getParent();if(null===e||!this.isAttached())return this.getLatest().__indent;let t=e.getParentOrThrow(),n=0;for(;O(t);)t=t.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(e){"number"!=typeof e&&i(117),(e=Math.floor(e))>=0||i(199);let t=this.getIndent();for(;t!==e;)t<e?(m(this),t++):(_(this),t--);return this}canInsertAfter(e){return O(e)}canReplaceWith(e){return O(e)}canMergeWith(e){return O(e)||t.$isParagraphNode(e)}extractWithChild(e,n){if(!t.$isRangeSelection(n))return!1;const r=n.anchor.getNode(),i=n.focus.getNode();return this.isParentOf(r)&&this.isParentOf(i)&&this.getTextContent().length===n.getTextContent().length}isParentRequired(){return!0}createParentElementNode(){return k("bullet")}canMergeWhenEmpty(){return!0}}function y(e){if(e.classList.contains("task-list-item"))for(const t of e.children)if("INPUT"===t.tagName)return T(t);if(e.classList.contains("joplin-checkbox"))for(const t of e.children)if(t.classList.contains("checkbox-wrapper")&&t.children.length>0&&"INPUT"===t.children[0].tagName)return T(t.children[0]);const n=e.getAttribute("aria-checked"),r=x("true"===n||"false"!==n&&void 0);return t.$setFormatFromDOM(r,e),{after:S.bind(null,r),node:t.$setDirectionFromDOM(r,e)}}function T(e){if(!("checkbox"===e.getAttribute("type")))return{node:null};const t=x(e.hasAttribute("checked"));return{after:S.bind(null,t),node:t}}function S(e,n){const r=n[0];return 1===n.length&&t.$isParagraphNode(r)&&!e.getFormatType()&&r.getFormatType()?(e.setFormat(r.getFormatType()),r.getChildren()):n}function x(e){return t.$applyNodeReplacement(new N(void 0,e))}function O(e){return e instanceof N}class L extends t.ElementNode{__tag;__start;__listType;$config(){return this.config("list",{$transform:e=>{!function(e){const t=e.getNextSibling();M(t)&&e.getListType()===t.getListType()&&h(e,t)}(e),f(e)},extends:t.ElementNode,importDOM:t.buildImportMap({ol:()=>({conversion:E,priority:0}),ul:()=>({conversion:E,priority:0})})})}constructor(e="number",t=1,n){super(n);const r=$[e]||e;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__listType=e.__listType,this.__tag=e.__tag,this.__start=e.__start}getTag(){return this.getLatest().__tag}setListType(e){const t=this.getWritable();return t.__listType=e,t.__tag="number"===e?"ol":"ul",t}getListType(){return this.getLatest().__listType}getStart(){return this.getLatest().__start}setStart(e){const t=this.getWritable();return t.__start=e,t}createDOM(e,t){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,v(r,e.theme,this),r}updateDOM(e,t,n){return e.__tag!==this.__tag||e.__listType!==this.__listType||(v(t,n.theme,this),e.__start!==this.__start&&t.setAttribute("start",String(this.__start)),!1)}updateFromJSON(e){return super.updateFromJSON(e).setListType(e.listType).setStart(e.start)}exportDOM(t){const n=this.createDOM(t._config,t);return e.isHTMLElement(n)&&(1!==this.__start&&n.setAttribute("start",String(this.__start)),"check"===this.__listType&&n.setAttribute("__lexicalListType","check")),{element:n}}exportJSON(){return{...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return!1}canIndent(){return!1}splice(e,n,r){let i=r;for(let e=0;e<r.length;e++){const n=r[e];O(n)||(i===r&&(i=[...r]),i[e]=this.createListItemNode().append(!t.$isElementNode(n)||M(n)||n.isInline()?n:t.$createTextNode(n.getTextContent())))}return super.splice(e,n,i)}extractWithChild(e){return O(e)}createListItemNode(){return x()}}function v(n,r,i){const o=[],l=[],c=r.list;if(void 0!==c){const e=c[`${i.__tag}Depth`]||[],n=s(i)-1,r=n%e.length,a=e[r],d=c[i.__tag];let g;const u=c.nested,h=c.checklist;if(void 0!==u&&u.list&&(g=u.list),void 0!==d&&o.push(d),void 0!==h&&"check"===i.__listType&&o.push(h),void 0!==a){o.push(...t.normalizeClassNames(a));for(let t=0;t<e.length;t++)t!==r&&l.push(i.__tag+t)}if(void 0!==g){const e=t.normalizeClassNames(g);n>1?o.push(...e):l.push(...e)}}l.length>0&&e.removeClassNamesFromElement(n,...l),o.length>0&&e.addClassNamesToElement(n,...o)}function E(n){let r;if(function(t){return e.isHTMLElement(t)&&"ol"===t.nodeName.toLowerCase()}(n)){const e=n.start;r=k("number",e)}else r=function(t){if("check"===t.getAttribute("__lexicallisttype")||t.classList.contains("contains-task-list")||"1"===t.getAttribute("data-is-checklist"))return!0;for(const n of t.childNodes)if(e.isHTMLElement(n)&&n.hasAttribute("aria-checked"))return!0;return!1}(n)?k("check"):k("bullet");return t.$setDirectionFromDOM(r,n),{after:e=>function(e,t){const n=t.createListItemNode.bind(t),r=[];for(let t=0;t<e.length;t++){const i=e[t];if(O(i)){r.push(i);const e=i.getChildren();e.length>1&&e.forEach(e=>{M(e)&&r.push(n().append(e))})}else r.push(n().append(i))}return r}(e,r),node:r}}const $={ol:"number",ul:"bullet"};function k(e="number",n=1){return t.$applyNodeReplacement(new L(e,n))}function M(e){return e instanceof L}const b=t.createCommand("INSERT_CHECK_LIST_COMMAND");function P(n,r){const i=r&&r.disableTakeFocusOnClick||!1,s="boolean"==typeof i?()=>i:i.peek.bind(i),o=t=>{const n=t.target;if(!e.isHTMLElement(n))return!1;const r=n.__lexicalCheckListLastHandled;return void 0!==r&&t.timeStamp-r<500},l=t=>{const n=t.target;e.isHTMLElement(n)&&(n.__lexicalCheckListLastHandled=t.timeStamp)},c=e=>{o(e)||(l(e),F(e,s()))},a=e=>{"touch"===e.pointerType&&(o(e)||(l(e),F(e,s())))},g=e=>{!function(e,t){I(e,()=>{e.preventDefault(),t&&e.stopPropagation()})}(e,s())};return e.mergeRegister(n.registerCommand(b,()=>(d("check"),!0),t.COMMAND_PRIORITY_LOW),n.registerCommand(t.KEY_ARROW_DOWN_COMMAND,e=>A(e,n,!1),t.COMMAND_PRIORITY_LOW),n.registerCommand(t.KEY_ARROW_UP_COMMAND,e=>A(e,n,!0),t.COMMAND_PRIORITY_LOW),n.registerCommand(t.KEY_ESCAPE_COMMAND,()=>{if(null!=R()){const e=n.getRootElement();return null!=e&&e.focus(),!0}return!1},t.COMMAND_PRIORITY_LOW),n.registerCommand(t.KEY_SPACE_COMMAND,e=>{const r=R();return!(null==r||!n.isEditable())&&(n.update(()=>{const n=t.$getNearestNodeFromDOMNode(r);O(n)&&(e.preventDefault(),n.toggleChecked())}),!0)},t.COMMAND_PRIORITY_LOW),n.registerCommand(t.KEY_ARROW_LEFT_COMMAND,r=>n.getEditorState().read(()=>{const i=t.$getSelection();if(t.$isRangeSelection(i)&&i.isCollapsed()){const{anchor:s}=i,o="element"===s.type;if(o||0===s.offset){const i=s.getNode(),l=e.$findMatchingParent(i,e=>t.$isElementNode(e)&&!e.isInline());if(O(l)){const e=l.getParent();if(M(e)&&"check"===e.getListType()&&(o||l.getFirstDescendant()===i)){const e=n.getElementByKey(l.__key);if(null!=e&&document.activeElement!==e)return e.focus(),r.preventDefault(),!0}}}}return!1}),t.COMMAND_PRIORITY_LOW),n.registerRootListener(e=>{if(null!==e)return e.addEventListener("click",c),e.addEventListener("pointerup",a),e.addEventListener("pointerdown",g,{capture:!0}),e.addEventListener("mousedown",g,{capture:!0}),e.addEventListener("touchstart",g,{capture:!0,passive:!1}),()=>{e.removeEventListener("click",c),e.removeEventListener("pointerup",a),e.removeEventListener("pointerdown",g,{capture:!0}),e.removeEventListener("mousedown",g,{capture:!0}),e.removeEventListener("touchstart",g,{capture:!0})}}))}function I(t,n){const r=t.target;if(!e.isHTMLElement(r))return;const i=r.firstChild;if(e.isHTMLElement(i)&&("UL"===i.tagName||"OL"===i.tagName))return;const s=r.parentNode;if(!s||"check"!==s.__lexicalListType)return;let o=null,l=null;if("clientX"in t)o=t.clientX;else if("touches"in t){const e=t.touches;e.length>0&&(o=e[0].clientX,l="touch")}if(null==o)return;const c=r.getBoundingClientRect(),a=o/e.calculateZoomLevel(r),d=window.getComputedStyle?window.getComputedStyle(r,"::before"):{width:"0px"},g=parseFloat(d.width),u="touch"===l||"pointerType"in t&&"touch"===t.pointerType?32:0;("rtl"===r.dir?a<c.right+u&&a>c.right-g-u:a>c.left-u&&a<c.left+g+u)&&n()}function F(n,r){I(n,()=>{if(e.isHTMLElement(n.target)){const e=n.target,i=t.getNearestEditorFromDOMNode(e);null!=i&&i.isEditable()&&i.update(()=>{const n=t.$getNearestNodeFromDOMNode(e);O(n)&&(r?(t.$addUpdateTag(t.SKIP_SELECTION_FOCUS_TAG),t.$addUpdateTag(t.SKIP_DOM_SELECTION_TAG)):e.focus(),n.toggleChecked())})}})}function R(){const t=document.activeElement;return e.isHTMLElement(t)&&"LI"===t.tagName&&null!=t.parentNode&&"check"===t.parentNode.__lexicalListType?t:null}function A(e,n,r){const i=R();return null!=i&&n.update(()=>{const s=t.$getNearestNodeFromDOMNode(i);if(!O(s))return;const o=function(e,t){let n=t?e.getPreviousSibling():e.getNextSibling(),r=e;for(;null==n&&O(r);)r=r.getParentOrThrow().getParent(),null!=r&&(n=t?r.getPreviousSibling():r.getNextSibling());for(;O(n);){const e=t?n.getLastChild():n.getFirstChild();if(!M(e))return n;n=t?e.getLastChild():e.getFirstChild()}return null}(s,r);if(null!=o){o.selectStart();const t=n.getElementByKey(o.__key);null!=t&&(e.preventDefault(),setTimeout(()=>{t.focus()},0))}}),!1}const D=t.createCommand("UPDATE_LIST_START_COMMAND"),w=t.createCommand("INSERT_UNORDERED_LIST_COMMAND"),W=t.createCommand("INSERT_ORDERED_LIST_COMMAND"),K=t.createCommand("REMOVE_LIST_COMMAND");function H(n,r){return e.mergeRegister(n.registerCommand(W,()=>(d("number"),!0),t.COMMAND_PRIORITY_LOW),n.registerCommand(D,e=>{const{listNodeKey:n,newStart:r}=e,i=t.$getNodeByKey(n);return!!M(i)&&("number"===i.getListType()&&(i.setStart(r),f(i)),!0)},t.COMMAND_PRIORITY_LOW),n.registerCommand(w,()=>(d("bullet"),!0),t.COMMAND_PRIORITY_LOW),n.registerCommand(K,()=>(p(),!0),t.COMMAND_PRIORITY_LOW),n.registerCommand(t.INSERT_PARAGRAPH_COMMAND,()=>C(!!(r&&r.restoreNumbering)),t.COMMAND_PRIORITY_LOW),n.registerNodeTransform(N,e=>{const n=e.getFirstChild();if(n){if(t.$isTextNode(n)){const t=n.getStyle(),r=n.getFormat();e.getTextStyle()!==t&&e.setTextStyle(t),e.getTextFormat()!==r&&e.setTextFormat(r)}}else{const n=t.$getSelection();t.$isRangeSelection(n)&&(n.style!==e.getTextStyle()||n.format!==e.getTextFormat())&&n.isCollapsed()&&e.is(n.anchor.getNode())&&e.setTextStyle(n.style).setTextFormat(n.format)}}),n.registerNodeTransform(t.TextNode,e=>{const t=e.getParent();if(O(t)&&e.is(t.getFirstChild())){const n=e.getStyle(),r=e.getFormat();n===t.getTextStyle()&&r===t.getTextFormat()||t.setTextStyle(n).setTextFormat(r)}}))}function U(t){const n=t=>{const n=t.getParent();if(M(t.getFirstChild())||!M(n))return;const r=e.$findMatchingParent(t,e=>O(e)&&M(e.getParent())&&O(e.getPreviousSibling()));if(null===r&&t.getIndent()>0)t.setIndent(0);else if(O(r)){const e=r.getPreviousSibling();if(O(e)){const r=function(e){let t=e,n=t.getFirstChild();for(;M(n);){const e=n.getLastChild();if(!O(e))break;t=e,n=t.getFirstChild()}return t}(e),i=r.getParent();if(M(i)){const e=s(i);e+1<s(n)&&t.setIndent(e)}}}};return t.registerNodeTransform(L,e=>{const t=[e];for(;t.length>0;){const e=t.shift();if(M(e))for(const r of e.getChildren())if(O(r)){n(r);const e=r.getFirstChild();M(e)&&t.push(e)}}})}const Y=t.defineExtension({build:(e,t,r)=>n.namedSignals(t),config:t.safeCast({hasStrictIndent:!1,shouldPreserveNumbering:!1}),name:"@lexical/list/List",nodes:()=>[L,N],register(t,r,i){const s=i.getOutput();return e.mergeRegister(n.effect(()=>H(t,{restoreNumbering:s.shouldPreserveNumbering.value})),n.effect(()=>s.hasStrictIndent.value?U(t):void 0))}}),B=t.defineExtension({build:(e,t)=>n.namedSignals(t),config:t.safeCast({disableTakeFocusOnClick:!1}),dependencies:[Y],name:"@lexical/list/CheckList",register:(e,t,n)=>P(e,n.getOutput())});function z(e){const t=[];for(const n of e)if(O(n)){t.push(n);const e=n.getChildren();if(e.length>1)for(const n of e)M(n)&&t.push(x().append(n))}else t.push(x().append(n));return t}const q=r.defineImportRule({$import:(e,n)=>{let i;var s;return r.isElementOfTag(n,"ol")?i=k("number",n.start):i=(s=n).matches('[__lexicallisttype="check"], .contains-task-list, [data-is-checklist="1"]')||null!==s.querySelector(":scope > [aria-checked]")?k("check"):k("bullet"),t.$setDirectionFromDOM(i,n),[i.splice(0,0,z(e.$importChildren(n)))]},match:r.sel.tag("ol","ul"),name:"@lexical/list/list"});function J(e,n){if(1!==n.length)return n;const r=n[0];return t.$isParagraphNode(r)&&!e.getFormatType()&&r.getFormatType()?(e.setFormat(r.getFormatType()),r.getChildren()):n}const V=r.defineImportRule({$import:(e,n)=>{const r=n.getAttribute("aria-checked"),i=x("true"===r||"false"!==r&&void 0);return t.$setFormatFromDOM(i,n),t.$setDirectionFromDOM(i,n),[i.splice(0,0,J(i,e.$importChildren(n)))]},match:r.sel.tag("li"),name:"@lexical/list/li"});function j(e,n,i){const s=r.isElementOfTag(i,"input")?i:i.querySelector('input[type="checkbox"]');if(!s||"checkbox"!==s.getAttribute("type"))return[];const o=x(s.hasAttribute("checked"));return t.$setFormatFromDOM(o,n),t.$setDirectionFromDOM(o,n),[o.splice(0,0,J(o,e.$importChildren(n)))]}const G={$accepts:e=>O(e)||M(e),$packageRun:e=>[x().splice(0,0,e)],name:"ListSchema"},X=[r.defineImportRule({$import:(e,t,n)=>{const r=t.querySelector(':scope > input[type="checkbox"]');return r?j(e,t,r):n()},match:r.sel.tag("li").classAll("task-list-item"),name:"@lexical/list/li-task-list-item"}),r.defineImportRule({$import:(e,t,n)=>{const r=t.querySelector(":scope > .checkbox-wrapper");if(!r)return n();const i=r.querySelector(':scope > input[type="checkbox"]');return i?j(e,t,i):n()},match:r.sel.tag("li").classAll("joplin-checkbox"),name:"@lexical/list/li-joplin-checkbox"}),q,V],Z=t.defineExtension({dependencies:[r.CoreImportExtension,Y,t.configExtension(r.DOMImportExtension,{rules:X})],name:"@lexical/list/Import"});exports.$createListItemNode=x,exports.$createListNode=k,exports.$getListDepth=s,exports.$handleListInsertParagraph=C,exports.$insertList=d,exports.$isListItemNode=O,exports.$isListNode=M,exports.$removeList=p,exports.CheckListExtension=B,exports.INSERT_CHECK_LIST_COMMAND=b,exports.INSERT_ORDERED_LIST_COMMAND=W,exports.INSERT_UNORDERED_LIST_COMMAND=w,exports.ListExtension=Y,exports.ListImportExtension=Z,exports.ListImportRules=X,exports.ListItemNode=N,exports.ListNode=L,exports.ListSchema=G,exports.REMOVE_LIST_COMMAND=K,exports.UPDATE_LIST_START_COMMAND=D,exports.insertList=function(e,t){e.update(()=>d(t))},exports.registerCheckList=P,exports.registerList=H,exports.registerListStrictIndentTransform=U,exports.removeList=function(e){e.update(()=>p())};
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import{$getNearestNodeOfType as e,$insertNodeToNearestRootAtCaret as t,removeClassNamesFromElement as n,addClassNamesToElement as r,isHTMLElement as i,mergeRegister as s,$findMatchingParent as o,calculateZoomLevel as l}from"@lexical/utils";import{$getSelection as c,$isRangeSelection as a,$isTextNode as u,$isRootOrShadowRoot as g,$createParagraphNode as h,$copyNode as d,$isElementNode as f,$isLeafNode as p,$setPointFromCaret as m,$normalizeCaret as _,$getChildCaret as y,$applyNodeReplacement as C,ElementNode as v,buildImportMap as k,$getSiblingCaret as T,$rewindSiblingCaret as b,setDOMStyleFromCSS as S,isHTMLElement as x,$isParagraphNode as L,$setFormatFromDOM as N,$setDirectionFromDOM as F,normalizeClassNames as P,getStyleObjectFromCSS as A,$createTextNode as E,createCommand as O,COMMAND_PRIORITY_LOW as I,KEY_ARROW_DOWN_COMMAND as w,KEY_ARROW_UP_COMMAND as D,KEY_ESCAPE_COMMAND as M,KEY_SPACE_COMMAND as $,$getNearestNodeFromDOMNode as R,KEY_ARROW_LEFT_COMMAND as K,getNearestEditorFromDOMNode as B,$addUpdateTag as W,SKIP_SELECTION_FOCUS_TAG as U,SKIP_DOM_SELECTION_TAG as J,$getNodeByKey as V,INSERT_PARAGRAPH_COMMAND as q,TextNode as z,defineExtension as H,safeCast as j,configExtension as X}from"lexical";import{namedSignals as G,effect as Q}from"@lexical/extension";import{CoreImportExtension as Y,DOMImportExtension as Z,defineImportRule as ee,sel as te,isElementOfTag as ne}from"@lexical/html";function re(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function ie(e){let t=1,n=e.getParent();for(;null!=n;){if(be(n)){const e=n.getParent();if(Pe(e)){t++,n=e.getParent();continue}re(40)}return t}return t}function se(e){let t=e.getParent();Pe(t)||re(40);let n=t;for(;null!==n;)n=n.getParent(),Pe(n)&&(t=n);return t}function oe(e){let t=[];const n=e.getChildren().filter(be);for(let e=0;e<n.length;e++){const r=n[e],i=r.getFirstChild();Pe(i)?t=t.concat(oe(i)):t.push(r)}return t}function le(e){return be(e)&&Pe(e.getFirstChild())}function ce(e,t){return be(e)&&(0===t.length||1===t.length&&e.is(t[0])&&0===e.getChildrenSize())}function ae(e){const t=c();if(null!==t){let n=t.getNodes();if(a(t)){const[r]=t.getStartEndPoints(),i=r.getNode(),s=i.getParent();if(g(i)){const e=i.getFirstChild();if(e)n=e.selectStart().getNodes();else{const e=h();i.append(e),n=e.select().getNodes()}}else if(ce(i,n)){const t=Fe(e);if(g(s)){i.replace(t);const e=Te();f(i)&&(e.setFormat(i.getFormatType()),e.setIndent(i.getIndent())),t.append(e)}else if(be(i)){const e=i.getParentOrThrow();ue(t,e.getChildren()),e.replace(t)}return}}const r=new Set;for(let t=0;t<n.length;t++){const i=n[t];if(f(i)&&i.isEmpty()&&!be(i)&&!r.has(i.getKey())){ge(i,e);continue}let s=p(i)?i.getParent():be(i)&&i.isEmpty()?i:null;for(;null!=s;){const t=s.getKey();if(Pe(s)){if(!r.has(t)){const n=Fe(e);ue(n,s.getChildren()),s.replace(n),r.add(t)}break}{const n=s.getParent();if(g(n)&&!r.has(t)){r.add(t),ge(s,e);break}s=n}}}}}function ue(e,t){e.splice(e.getChildrenSize(),0,t)}function ge(e,t){if(Pe(e))return e;const n=e.getPreviousSibling(),r=e.getNextSibling(),i=Te();let s;if(ue(i,e.getChildren()),Pe(n)&&t===n.getListType())n.append(i),Pe(r)&&t===r.getListType()&&(ue(n,r.getChildren()),r.remove()),s=n;else if(Pe(r)&&t===r.getListType())r.getFirstChildOrThrow().insertBefore(i),s=r;else{const n=Fe(t);n.append(i),e.replace(n),s=n}i.setFormat(e.getFormatType()),i.setIndent(e.getIndent());const o=c();return a(o)&&(s.getKey()===o.anchor.key&&o.anchor.set(i.getKey(),o.anchor.offset,"element"),s.getKey()===o.focus.key&&o.focus.set(i.getKey(),o.focus.offset,"element")),e.remove(),s}function he(e,t){const n=e.getLastChild(),r=t.getFirstChild();n&&r&&le(n)&&le(r)&&(he(n.getFirstChild(),r.getFirstChild()),r.remove());const i=t.getChildren();i.length>0&&e.append(...i),t.remove()}function de(){const t=c();if(a(t)){const n=new Set,r=t.getNodes(),i=t.anchor.getNode();if(ce(i,r))n.add(se(i));else for(let t=0;t<r.length;t++){const i=r[t];if(p(i)){const t=e(i,ye);null!=t&&n.add(se(t))}}for(const e of n){let n=e;const r=oe(e);for(const e of r){const r=h().setTextStyle(t.style).setTextFormat(t.format);ue(r,e.getChildren()),n.insertAfter(r),n=r,e.__key===t.anchor.key&&m(t.anchor,_(y(r,"next"))),e.__key===t.focus.key&&m(t.focus,_(y(r,"next"))),e.remove()}e.remove()}}}function fe(e){const t="check"!==e.getListType();let n=e.getStart();for(const r of e.getChildren())be(r)&&(r.getValue()!==n&&r.setValue(n),t&&null!=r.getLatest().__checked&&r.setChecked(void 0),Pe(r.getFirstChild())||n++)}function pe(e){const t=new Set;if(le(e)||t.has(e.getKey()))return;const n=e.getParent(),r=e.getNextSibling(),i=e.getPreviousSibling();if(le(r)&&le(i)){const n=i.getFirstChild();if(Pe(n)){n.append(e);const i=r.getFirstChild();if(Pe(i)){ue(n,i.getChildren()),r.remove(),t.add(r.getKey())}}}else if(le(r)){const t=r.getFirstChild();if(Pe(t)){const n=t.getFirstChild();null!==n&&n.insertBefore(e)}}else if(le(i)){const t=i.getFirstChild();Pe(t)&&t.append(e)}else if(Pe(n)){const t=d(e),s=d(n);t.append(s),s.append(e),i?i.insertAfter(t):r?r.insertBefore(t):n.append(t)}}function me(e){if(le(e))return;const t=e.getParent(),n=t?t.getParent():void 0;if(Pe(n?n.getParent():void 0)&&be(n)&&Pe(t)){const r=t?t.getFirstChild():void 0,i=t?t.getLastChild():void 0;if(e.is(r))n.insertBefore(e),t.isEmpty()&&n.remove();else if(e.is(i))n.insertAfter(e),t.isEmpty()&&n.remove();else{const r=d(e),i=d(t);r.append(i),e.getPreviousSiblings().forEach(e=>i.append(e));const s=d(e),o=d(t);s.append(o),ue(o,e.getNextSiblings()),n.insertBefore(r),n.insertAfter(s),n.replace(e)}}}function _e(e=!1){const t=c();if(!a(t)||!t.isCollapsed())return!1;const n=t.anchor.getNode();let r=null;if(be(n)&&0===n.getChildrenSize())r=n;else if(u(n)){const e=n.getParent();be(e)&&e.getChildren().every(e=>u(e)&&""===e.getTextContent().trim())&&(r=e)}if(null===r)return!1;const i=se(r),s=r.getParent();Pe(s)||re(40);const o=s.getParent();let l;if(g(o))l=h(),i.insertAfter(l);else{if(!be(o))return!1;l=d(o),o.insertAfter(l)}l.setTextStyle(t.style).setTextFormat(t.format).select();const f=r.getNextSiblings();if(f.length>0){const t=e?function(e,t){return e.getStart()+t.getIndexWithinParent()}(s,r):1,n=d(s).setStart(t);if(be(l)){const e=d(l);e.append(n),l.insertAfter(e)}else l.insertAfter(n);n.append(...f)}return function(e){let t=e;for(;null==t.getNextSibling()&&null==t.getPreviousSibling();){const e=t.getParent();if(null==e||!be(e)&&!Pe(e))break;t=e}t.remove()}(r),!0}class ye extends v{__value;__checked;$config(){return this.config("listitem",{$transform:e=>{const n=e.getParent();if(Pe(n))"check"!==n.getListType()&&null!=e.getChecked()&&e.setChecked(void 0);else if(n){const r=e.createParentElementNode();Pe(r)||re(340);const i=[e];for(const t of["previous","next"]){i.reverse();for(const{origin:n}of T(e,t)){if(!be(n))break;i.push(n)}}e.insertBefore(r),r.splice(0,0,i),g(n)||(t(r,b(T(r,"next")),{$shouldSplit:()=>!1,removeEmptyDestination:!0}),n.isEmpty()&&n.isAttached()&&n.remove())}},extends:v,importDOM:k({li:()=>({conversion:Ce,priority:0})})})}constructor(e=1,t=void 0,n){super(n),this.__value=void 0===e?1:e,this.__checked=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__value=e.__value,this.__checked=e.__checked}createDOM(e){const t=document.createElement("li");return this.updateListItemDOM(null,t,e),t}updateListItemDOM(e,t,i){!function(e,t){const n=t.getParent();!Pe(n)||"check"!==n.getListType()||Pe(t.getFirstChild())?(e.removeAttribute("role"),e.removeAttribute("tabIndex"),e.removeAttribute("aria-checked")):(e.setAttribute("role","checkbox"),e.setAttribute("tabIndex","-1"),e.setAttribute("aria-checked",t.getChecked()?"true":"false"))}(t,this),t.value=this.__value,function(e,t,i){const s=t.list;if(!s)return;const o=s.listitem,l=s.nested&&s.nested.listitem,c=i.getParent(),a=Pe(c)&&"check"===c.getListType(),u=i.getChecked(),g=i.getChildren().some(e=>Pe(e)),h=[];void 0!==s.listitemChecked&&h.push(s.listitemChecked);void 0!==s.listitemUnchecked&&h.push(s.listitemUnchecked);void 0!==l&&h.push(...P(l));h.length>0&&n(e,...h);const d=[];void 0!==o&&d.push(...P(o));if(a){const e=u?s.listitemChecked:s.listitemUnchecked;void 0!==e&&d.push(e)}void 0!==l&&g&&d.push(...P(l));d.length>0&&r(e,...d)}(t,i.theme,this);const s=e?e.__style:"",o=this.__style;s!==o&&S(t.style,o,s),function(e,t,n){const r=t.__textStyle,i=n?n.__textStyle:"";if(null!==n&&i===r)return;const s=A(r);for(const t in s)e.style.setProperty(`--listitem-marker-${t}`,s[t]);if(""!==i)for(const t in A(i))t in s||e.style.removeProperty(`--listitem-marker-${t}`)}(t,this,e)}updateDOM(e,t,n){const r=t;return this.updateListItemDOM(e,r,n),!1}updateFromJSON(e){return super.updateFromJSON(e).setValue(e.value).setChecked(e.checked)}exportDOM(e){const t=this.createDOM(e._config),n=this.getFormatType();n&&(t.style.textAlign=n);const r=this.getDirection();return r&&(t.dir=r),le(this)?{after(e){if(x(e)){const t=e.previousElementSibling;if(x(t)&&"LI"===t.nodeName){for(;e.firstChild;)t.append(e.firstChild);e.remove()}}return e},element:t}:{element:t}}exportJSON(){return{...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...e){for(let t=0;t<e.length;t++){const n=e[t];if(f(n)&&this.canMergeWith(n)){const e=n.getChildren();this.append(...e),n.remove()}else super.append(n)}return this}replace(e,t){if(be(e))return super.replace(e);this.setIndent(0);const n=this.getParentOrThrow();if(!Pe(n))return e;if(n.__first===this.getKey())n.insertBefore(e);else if(n.__last===this.getKey())n.insertAfter(e);else{const t=d(n);let r=this.getNextSibling();for(;r;){const e=r;r=r.getNextSibling(),t.append(e)}n.insertAfter(e),e.insertAfter(t)}const r=this.__key;let i=0;if(t&&(f(e)||re(139),i=e.getChildrenSize(),e.splice(i,0,this.getChildren())),t&&f(e)){const t=c();if(a(t))for(const n of t.getStartEndPoints())n.key===r&&"element"===n.type&&n.set(e.getKey(),i+n.offset,"element")}return this.remove(),0===n.getChildrenSize()&&n.remove(),e}insertAfter(e,t=!0){const n=this.getParentOrThrow();if(Pe(n)||re(39),be(e))return super.insertAfter(e,t);const r=this.getNextSiblings();if(n.insertAfter(e,t),0!==r.length){const i=d(n);r.forEach(e=>i.append(e)),e.insertAfter(i,t)}return e}remove(e){const t=this.getPreviousSibling(),n=this.getNextSibling();super.remove(e),t&&n&&le(t)&&le(n)&&(he(t.getFirstChild(),n.getFirstChild()),n.remove())}resetOnCopyNodeFrom(e){super.resetOnCopyNodeFrom(e),e.getChecked()&&this.setChecked(!1)}insertNewAfter(e,t=!0){const n=d(this);return this.insertAfter(n,t),n}collapseAtStart(e){const t=h();this.getChildren().forEach(e=>t.append(e));const n=this.getParentOrThrow(),r=n.getParentOrThrow(),i=be(r);if(1===n.getChildrenSize())if(i)n.remove(),r.select();else{n.insertBefore(t),n.remove();const r=e.anchor,i=e.focus,s=t.getKey();"element"===r.type&&r.getNode().is(this)&&r.set(s,r.offset,"element"),"element"===i.type&&i.getNode().is(this)&&i.set(s,i.offset,"element")}else n.insertBefore(t),this.remove();return!0}getValue(){return this.getLatest().__value}setValue(e){const t=this.getWritable();return t.__value=e,t}getChecked(){const e=this.getLatest();let t;const n=this.getParent();return Pe(n)&&(t=n.getListType()),"check"===t?Boolean(e.__checked):void 0}setChecked(e){const t=this.getWritable();return t.__checked=e,t}toggleChecked(){const e=this.getWritable();return e.setChecked(!e.__checked)}getIndent(){const e=this.getParent();if(null===e||!this.isAttached())return this.getLatest().__indent;let t=e.getParentOrThrow(),n=0;for(;be(t);)t=t.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(e){"number"!=typeof e&&re(117),(e=Math.floor(e))>=0||re(199);let t=this.getIndent();for(;t!==e;)t<e?(pe(this),t++):(me(this),t--);return this}canInsertAfter(e){return be(e)}canReplaceWith(e){return be(e)}canMergeWith(e){return be(e)||L(e)}extractWithChild(e,t){if(!a(t))return!1;const n=t.anchor.getNode(),r=t.focus.getNode();return this.isParentOf(n)&&this.isParentOf(r)&&this.getTextContent().length===t.getTextContent().length}isParentRequired(){return!0}createParentElementNode(){return Fe("bullet")}canMergeWhenEmpty(){return!0}}function Ce(e){if(e.classList.contains("task-list-item"))for(const t of e.children)if("INPUT"===t.tagName)return ve(t);if(e.classList.contains("joplin-checkbox"))for(const t of e.children)if(t.classList.contains("checkbox-wrapper")&&t.children.length>0&&"INPUT"===t.children[0].tagName)return ve(t.children[0]);const t=e.getAttribute("aria-checked"),n=Te("true"===t||"false"!==t&&void 0);return N(n,e),{after:ke.bind(null,n),node:F(n,e)}}function ve(e){if(!("checkbox"===e.getAttribute("type")))return{node:null};const t=Te(e.hasAttribute("checked"));return{after:ke.bind(null,t),node:t}}function ke(e,t){const n=t[0];return 1===t.length&&L(n)&&!e.getFormatType()&&n.getFormatType()?(e.setFormat(n.getFormatType()),n.getChildren()):t}function Te(e){return C(new ye(void 0,e))}function be(e){return e instanceof ye}class Se extends v{__tag;__start;__listType;$config(){return this.config("list",{$transform:e=>{!function(e){const t=e.getNextSibling();Pe(t)&&e.getListType()===t.getListType()&&he(e,t)}(e),fe(e)},extends:v,importDOM:k({ol:()=>({conversion:Le,priority:0}),ul:()=>({conversion:Le,priority:0})})})}constructor(e="number",t=1,n){super(n);const r=Ne[e]||e;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__listType=e.__listType,this.__tag=e.__tag,this.__start=e.__start}getTag(){return this.getLatest().__tag}setListType(e){const t=this.getWritable();return t.__listType=e,t.__tag="number"===e?"ol":"ul",t}getListType(){return this.getLatest().__listType}getStart(){return this.getLatest().__start}setStart(e){const t=this.getWritable();return t.__start=e,t}createDOM(e,t){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,xe(r,e.theme,this),r}updateDOM(e,t,n){return e.__tag!==this.__tag||e.__listType!==this.__listType||(xe(t,n.theme,this),e.__start!==this.__start&&t.setAttribute("start",String(this.__start)),!1)}updateFromJSON(e){return super.updateFromJSON(e).setListType(e.listType).setStart(e.start)}exportDOM(e){const t=this.createDOM(e._config,e);return i(t)&&(1!==this.__start&&t.setAttribute("start",String(this.__start)),"check"===this.__listType&&t.setAttribute("__lexicalListType","check")),{element:t}}exportJSON(){return{...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return!1}canIndent(){return!1}splice(e,t,n){let r=n;for(let e=0;e<n.length;e++){const t=n[e];be(t)||(r===n&&(r=[...n]),r[e]=this.createListItemNode().append(!f(t)||Pe(t)||t.isInline()?t:E(t.getTextContent())))}return super.splice(e,t,r)}extractWithChild(e){return be(e)}createListItemNode(){return Te()}}function xe(e,t,i){const s=[],o=[],l=t.list;if(void 0!==l){const e=l[`${i.__tag}Depth`]||[],t=ie(i)-1,n=t%e.length,r=e[n],c=l[i.__tag];let a;const u=l.nested,g=l.checklist;if(void 0!==u&&u.list&&(a=u.list),void 0!==c&&s.push(c),void 0!==g&&"check"===i.__listType&&s.push(g),void 0!==r){s.push(...P(r));for(let t=0;t<e.length;t++)t!==n&&o.push(i.__tag+t)}if(void 0!==a){const e=P(a);t>1?s.push(...e):o.push(...e)}}o.length>0&&n(e,...o),s.length>0&&r(e,...s)}function Le(e){let t;if(function(e){return i(e)&&"ol"===e.nodeName.toLowerCase()}(e)){const n=e.start;t=Fe("number",n)}else t=function(e){if("check"===e.getAttribute("__lexicallisttype")||e.classList.contains("contains-task-list")||"1"===e.getAttribute("data-is-checklist"))return!0;for(const t of e.childNodes)if(i(t)&&t.hasAttribute("aria-checked"))return!0;return!1}(e)?Fe("check"):Fe("bullet");return F(t,e),{after:e=>function(e,t){const n=t.createListItemNode.bind(t),r=[];for(let t=0;t<e.length;t++){const i=e[t];if(be(i)){r.push(i);const e=i.getChildren();e.length>1&&e.forEach(e=>{Pe(e)&&r.push(n().append(e))})}else r.push(n().append(i))}return r}(e,t),node:t}}const Ne={ol:"number",ul:"bullet"};function Fe(e="number",t=1){return C(new Se(e,t))}function Pe(e){return e instanceof Se}const Ae=O("INSERT_CHECK_LIST_COMMAND");function Ee(e,t){const n=t&&t.disableTakeFocusOnClick||!1,r="boolean"==typeof n?()=>n:n.peek.bind(n),l=e=>{const t=e.target;if(!i(t))return!1;const n=t.__lexicalCheckListLastHandled;return void 0!==n&&e.timeStamp-n<500},u=e=>{const t=e.target;i(t)&&(t.__lexicalCheckListLastHandled=e.timeStamp)},g=e=>{l(e)||(u(e),Ie(e,r()))},h=e=>{"touch"===e.pointerType&&(l(e)||(u(e),Ie(e,r())))},d=e=>{!function(e,t){Oe(e,()=>{e.preventDefault(),t&&e.stopPropagation()})}(e,r())};return s(e.registerCommand(Ae,()=>(ae("check"),!0),I),e.registerCommand(w,t=>De(t,e,!1),I),e.registerCommand(D,t=>De(t,e,!0),I),e.registerCommand(M,()=>{if(null!=we()){const t=e.getRootElement();return null!=t&&t.focus(),!0}return!1},I),e.registerCommand($,t=>{const n=we();return!(null==n||!e.isEditable())&&(e.update(()=>{const e=R(n);be(e)&&(t.preventDefault(),e.toggleChecked())}),!0)},I),e.registerCommand(K,t=>e.getEditorState().read(()=>{const n=c();if(a(n)&&n.isCollapsed()){const{anchor:r}=n,i="element"===r.type;if(i||0===r.offset){const n=r.getNode(),s=o(n,e=>f(e)&&!e.isInline());if(be(s)){const r=s.getParent();if(Pe(r)&&"check"===r.getListType()&&(i||s.getFirstDescendant()===n)){const n=e.getElementByKey(s.__key);if(null!=n&&document.activeElement!==n)return n.focus(),t.preventDefault(),!0}}}}return!1}),I),e.registerRootListener(e=>{if(null!==e)return e.addEventListener("click",g),e.addEventListener("pointerup",h),e.addEventListener("pointerdown",d,{capture:!0}),e.addEventListener("mousedown",d,{capture:!0}),e.addEventListener("touchstart",d,{capture:!0,passive:!1}),()=>{e.removeEventListener("click",g),e.removeEventListener("pointerup",h),e.removeEventListener("pointerdown",d,{capture:!0}),e.removeEventListener("mousedown",d,{capture:!0}),e.removeEventListener("touchstart",d,{capture:!0})}}))}function Oe(e,t){const n=e.target;if(!i(n))return;const r=n.firstChild;if(i(r)&&("UL"===r.tagName||"OL"===r.tagName))return;const s=n.parentNode;if(!s||"check"!==s.__lexicalListType)return;let o=null,c=null;if("clientX"in e)o=e.clientX;else if("touches"in e){const t=e.touches;t.length>0&&(o=t[0].clientX,c="touch")}if(null==o)return;const a=n.getBoundingClientRect(),u=o/l(n),g=window.getComputedStyle?window.getComputedStyle(n,"::before"):{width:"0px"},h=parseFloat(g.width),d="touch"===c||"pointerType"in e&&"touch"===e.pointerType?32:0;("rtl"===n.dir?u<a.right+d&&u>a.right-h-d:u>a.left-d&&u<a.left+h+d)&&t()}function Ie(e,t){Oe(e,()=>{if(i(e.target)){const n=e.target,r=B(n);null!=r&&r.isEditable()&&r.update(()=>{const e=R(n);be(e)&&(t?(W(U),W(J)):n.focus(),e.toggleChecked())})}})}function we(){const e=document.activeElement;return i(e)&&"LI"===e.tagName&&null!=e.parentNode&&"check"===e.parentNode.__lexicalListType?e:null}function De(e,t,n){const r=we();return null!=r&&t.update(()=>{const i=R(r);if(!be(i))return;const s=function(e,t){let n=t?e.getPreviousSibling():e.getNextSibling(),r=e;for(;null==n&&be(r);)r=r.getParentOrThrow().getParent(),null!=r&&(n=t?r.getPreviousSibling():r.getNextSibling());for(;be(n);){const e=t?n.getLastChild():n.getFirstChild();if(!Pe(e))return n;n=t?e.getLastChild():e.getFirstChild()}return null}(i,n);if(null!=s){s.selectStart();const n=t.getElementByKey(s.__key);null!=n&&(e.preventDefault(),setTimeout(()=>{n.focus()},0))}}),!1}const Me=O("UPDATE_LIST_START_COMMAND"),$e=O("INSERT_UNORDERED_LIST_COMMAND"),Re=O("INSERT_ORDERED_LIST_COMMAND"),Ke=O("REMOVE_LIST_COMMAND");function Be(e,t){return s(e.registerCommand(Re,()=>(ae("number"),!0),I),e.registerCommand(Me,e=>{const{listNodeKey:t,newStart:n}=e,r=V(t);return!!Pe(r)&&("number"===r.getListType()&&(r.setStart(n),fe(r)),!0)},I),e.registerCommand($e,()=>(ae("bullet"),!0),I),e.registerCommand(Ke,()=>(de(),!0),I),e.registerCommand(q,()=>_e(!!(t&&t.restoreNumbering)),I),e.registerNodeTransform(ye,e=>{const t=e.getFirstChild();if(t){if(u(t)){const n=t.getStyle(),r=t.getFormat();e.getTextStyle()!==n&&e.setTextStyle(n),e.getTextFormat()!==r&&e.setTextFormat(r)}}else{const t=c();a(t)&&(t.style!==e.getTextStyle()||t.format!==e.getTextFormat())&&t.isCollapsed()&&e.is(t.anchor.getNode())&&e.setTextStyle(t.style).setTextFormat(t.format)}}),e.registerNodeTransform(z,e=>{const t=e.getParent();if(be(t)&&e.is(t.getFirstChild())){const n=e.getStyle(),r=e.getFormat();n===t.getTextStyle()&&r===t.getTextFormat()||t.setTextStyle(n).setTextFormat(r)}}))}function We(e){const t=e=>{const t=e.getParent();if(Pe(e.getFirstChild())||!Pe(t))return;const n=o(e,e=>be(e)&&Pe(e.getParent())&&be(e.getPreviousSibling()));if(null===n&&e.getIndent()>0)e.setIndent(0);else if(be(n)){const r=n.getPreviousSibling();if(be(r)){const n=function(e){let t=e,n=t.getFirstChild();for(;Pe(n);){const e=n.getLastChild();if(!be(e))break;t=e,n=t.getFirstChild()}return t}(r),i=n.getParent();if(Pe(i)){const n=ie(i);n+1<ie(t)&&e.setIndent(n)}}}};return e.registerNodeTransform(Se,e=>{const n=[e];for(;n.length>0;){const e=n.shift();if(Pe(e))for(const r of e.getChildren())if(be(r)){t(r);const e=r.getFirstChild();Pe(e)&&n.push(e)}}})}const Ue=H({build:(e,t,n)=>G(t),config:j({hasStrictIndent:!1,shouldPreserveNumbering:!1}),name:"@lexical/list/List",nodes:()=>[Se,ye],register(e,t,n){const r=n.getOutput();return s(Q(()=>Be(e,{restoreNumbering:r.shouldPreserveNumbering.value})),Q(()=>r.hasStrictIndent.value?We(e):void 0))}}),Je=H({build:(e,t)=>G(t),config:j({disableTakeFocusOnClick:!1}),dependencies:[Ue],name:"@lexical/list/CheckList",register:(e,t,n)=>Ee(e,n.getOutput())});function Ve(e){const t=[];for(const n of e)if(be(n)){t.push(n);const e=n.getChildren();if(e.length>1)for(const n of e)Pe(n)&&t.push(Te().append(n))}else t.push(Te().append(n));return t}const qe=ee({$import:(e,t)=>{let n;var r;return ne(t,"ol")?n=Fe("number",t.start):n=(r=t).matches('[__lexicallisttype="check"], .contains-task-list, [data-is-checklist="1"]')||null!==r.querySelector(":scope > [aria-checked]")?Fe("check"):Fe("bullet"),F(n,t),[n.splice(0,0,Ve(e.$importChildren(t)))]},match:te.tag("ol","ul"),name:"@lexical/list/list"});function ze(e,t){if(1!==t.length)return t;const n=t[0];return L(n)&&!e.getFormatType()&&n.getFormatType()?(e.setFormat(n.getFormatType()),n.getChildren()):t}const He=ee({$import:(e,t)=>{const n=t.getAttribute("aria-checked"),r=Te("true"===n||"false"!==n&&void 0);return N(r,t),F(r,t),[r.splice(0,0,ze(r,e.$importChildren(t)))]},match:te.tag("li"),name:"@lexical/list/li"});function je(e,t,n){const r=ne(n,"input")?n:n.querySelector('input[type="checkbox"]');if(!r||"checkbox"!==r.getAttribute("type"))return[];const i=Te(r.hasAttribute("checked"));return N(i,t),F(i,t),[i.splice(0,0,ze(i,e.$importChildren(t)))]}const Xe={$accepts:e=>be(e)||Pe(e),$packageRun:e=>[Te().splice(0,0,e)],name:"ListSchema"},Ge=[ee({$import:(e,t,n)=>{const r=t.querySelector(':scope > input[type="checkbox"]');return r?je(e,t,r):n()},match:te.tag("li").classAll("task-list-item"),name:"@lexical/list/li-task-list-item"}),ee({$import:(e,t,n)=>{const r=t.querySelector(":scope > .checkbox-wrapper");if(!r)return n();const i=r.querySelector(':scope > input[type="checkbox"]');return i?je(e,t,i):n()},match:te.tag("li").classAll("joplin-checkbox"),name:"@lexical/list/li-joplin-checkbox"}),qe,He],Qe=H({dependencies:[Y,Ue,X(Z,{rules:Ge})],name:"@lexical/list/Import"});function Ye(e,t){e.update(()=>ae(t))}function Ze(e){e.update(()=>de())}export{Te as $createListItemNode,Fe as $createListNode,ie as $getListDepth,_e as $handleListInsertParagraph,ae as $insertList,be as $isListItemNode,Pe as $isListNode,de as $removeList,Je as CheckListExtension,Ae as INSERT_CHECK_LIST_COMMAND,Re as INSERT_ORDERED_LIST_COMMAND,$e as INSERT_UNORDERED_LIST_COMMAND,Ue as ListExtension,Qe as ListImportExtension,Ge as ListImportRules,ye as ListItemNode,Se as ListNode,Xe as ListSchema,Ke as REMOVE_LIST_COMMAND,Me as UPDATE_LIST_START_COMMAND,Ye as insertList,Ee as registerCheckList,Be as registerList,We as registerListStrictIndentTransform,Ze as removeList};
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
export interface ListConfig {
/**
* When `true`, enforces strict indentation rules for list items, ensuring consistent structure.
* When `false` (default), indentation is more flexible.
*/
hasStrictIndent: boolean;
shouldPreserveNumbering: boolean;
}
/**
* Configures {@link ListNode}, {@link ListItemNode} and registers
* the strict indent transform if `hasStrictIndent` is true (default false).
*/
export declare const ListExtension: import("lexical").LexicalExtension<ListConfig, "@lexical/list/List", import("@lexical/extension").NamedSignalsOutput<ListConfig>, unknown>;
export interface CheckListConfig {
disableTakeFocusOnClick: boolean;
}
/**
* Registers checklist functionality for {@link ListNode} and
* {@link ListItemNode} with a `INSERT_CHECK_LIST_COMMAND` listener and
* the expected keyboard and mouse interactions for checkboxes.
*/
export declare const CheckListExtension: import("lexical").LexicalExtension<CheckListConfig, "@lexical/list/CheckList", import("@lexical/extension").NamedSignalsOutput<CheckListConfig>, unknown>;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { ListNode } from './';
import type { BaseSelection, DOMExportOutput, EditorConfig, LexicalNode, LexicalUpdateJSON, NodeKey, ParagraphNode, RangeSelection, SerializedElementNode, Spread } from 'lexical';
import { ElementNode, LexicalEditor } from 'lexical';
export type SerializedListItemNode = Spread<{
checked: boolean | undefined;
value: number;
}, SerializedElementNode>;
/** @noInheritDoc */
export declare class ListItemNode extends ElementNode {
/** @internal */
__value: number;
/** @internal */
__checked?: boolean;
/** @internal */
$config(): import("lexical").StaticNodeConfigRecord<"listitem", {
$transform: (node: ListItemNode) => void;
extends: typeof ElementNode;
importDOM: import("lexical").DOMConversionMap<HTMLElement>;
}>;
constructor(value?: number, checked?: undefined | boolean, key?: NodeKey);
afterCloneFrom(prevNode: this): void;
createDOM(config: EditorConfig): HTMLElement;
updateListItemDOM(prevNode: ListItemNode | null, dom: HTMLLIElement, config: EditorConfig): void;
updateDOM(prevNode: ListItemNode, dom: HTMLElement, config: EditorConfig): boolean;
updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedListItemNode>): this;
exportDOM(editor: LexicalEditor): DOMExportOutput;
exportJSON(): SerializedListItemNode;
append(...nodes: LexicalNode[]): this;
replace<N extends LexicalNode>(replaceWithNode: N, includeChildren?: boolean): N;
insertAfter(node: LexicalNode, restoreSelection?: boolean): LexicalNode;
remove(preserveEmptyParent?: boolean): void;
resetOnCopyNodeFrom(original: this): void;
insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ListItemNode | ParagraphNode;
collapseAtStart(selection: RangeSelection): true;
getValue(): number;
setValue(value: number): this;
getChecked(): boolean | undefined;
setChecked(checked?: boolean): this;
toggleChecked(): this;
getIndent(): number;
setIndent(indent: number): this;
/** @deprecated @internal */
canInsertAfter(node: LexicalNode): boolean;
/** @deprecated @internal */
canReplaceWith(replacement: LexicalNode): boolean;
canMergeWith(node: LexicalNode): boolean;
extractWithChild(child: LexicalNode, selection: BaseSelection): boolean;
isParentRequired(): true;
createParentElementNode(): ListNode;
canMergeWhenEmpty(): true;
}
/**
* Creates a new List Item node, passing true/false will convert it to a checkbox input.
* @param checked - Is the List Item a checkbox and, if so, is it checked? undefined/null: not a checkbox, true/false is a checkbox and checked/unchecked, respectively.
* @returns The new List Item.
*/
export declare function $createListItemNode(checked?: boolean): ListItemNode;
/**
* Checks to see if the node is a ListItemNode.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode, false otherwise.
*/
export declare function $isListItemNode(node: LexicalNode | null | undefined): node is ListItemNode;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { DOMExportOutput, EditorConfig, ElementNode, LexicalEditor, LexicalNode, LexicalUpdateJSON, NodeKey, SerializedElementNode, Spread } from 'lexical';
import { ListItemNode } from '.';
export type SerializedListNode = Spread<{
listType: ListType;
start: number;
tag: ListNodeTagType;
}, SerializedElementNode>;
export type ListType = 'number' | 'bullet' | 'check';
export type ListNodeTagType = 'ul' | 'ol';
/** @noInheritDoc */
export declare class ListNode extends ElementNode {
/** @internal */
__tag: ListNodeTagType;
/** @internal */
__start: number;
/** @internal */
__listType: ListType;
/** @internal */
$config(): import("lexical").StaticNodeConfigRecord<"list", {
$transform: (node: ListNode) => void;
extends: typeof ElementNode;
importDOM: import("lexical").DOMConversionMap<HTMLElement>;
}>;
constructor(listType?: ListType, start?: number, key?: NodeKey);
afterCloneFrom(prevNode: this): void;
getTag(): ListNodeTagType;
setListType(type: ListType): this;
getListType(): ListType;
getStart(): number;
setStart(start: number): this;
createDOM(config: EditorConfig, _editor?: LexicalEditor): HTMLElement;
updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean;
updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedListNode>): this;
exportDOM(editor: LexicalEditor): DOMExportOutput;
exportJSON(): SerializedListNode;
canBeEmpty(): false;
canIndent(): false;
splice(start: number, deleteCount: number, nodesToInsert: LexicalNode[]): this;
extractWithChild(child: LexicalNode): boolean;
/**
* Create an appropriate ListItemNode to be a child of this ListNode,
* {@link $createListItemNode} is the default implementation.
*
* @returns A new ListItemNode.
*/
createListItemNode(): ListItemNode;
}
/**
* Creates a ListNode of listType.
* @param listType - The type of list to be created. Can be 'number', 'bullet', or 'check'.
* @param start - Where an ordered list starts its count, start = 1 if left undefined.
* @returns The new ListNode
*/
export declare function $createListNode(listType?: ListType, start?: number): ListNode;
/**
* Checks to see if the node is a ListNode.
* @param node - The node to be checked.
* @returns true if the node is a ListNode, false otherwise.
*/
export declare function $isListNode(node: LexicalNode | null | undefined): node is ListNode;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { ChildSchema } from '@lexical/html';
/**
* A {@link ChildSchema} that enforces ListNode invariants: only
* `ListItemNode` and (immediately-nested) `ListNode` children are
* accepted; runs of other children get wrapped in a fresh
* `ListItemNode`.
*
* @experimental
*/
export declare const ListSchema: ChildSchema;
/**
* Import rules for {@link ListNode} and {@link ListItemNode}, including
* GitHub task-list and Joplin checkbox heuristics.
*
* @experimental
*/
export declare const ListImportRules: (import("@lexical/html").DOMImportRule<import("@lexical/html").ElementSelectorBuilder<HTMLOListElement | HTMLUListElement, Record<string, never>>> | import("@lexical/html").DOMImportRule<import("@lexical/html").ElementSelectorBuilder<HTMLLIElement, Record<string, never>>>)[];
/**
* Bundles {@link ListImportRules} (plus {@link CoreImportExtension}) into
* a single dependency.
*
* @experimental
*/
export declare const ListImportExtension: import("lexical").LexicalExtension<import("lexical").ExtensionConfigBase, "@lexical/list/Import", unknown, unknown>;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalCommand, LexicalEditor, NodeKey } from 'lexical';
export declare const UPDATE_LIST_START_COMMAND: LexicalCommand<{
listNodeKey: NodeKey;
newStart: number;
}>;
export declare const INSERT_UNORDERED_LIST_COMMAND: LexicalCommand<void>;
export declare const INSERT_ORDERED_LIST_COMMAND: LexicalCommand<void>;
export declare const REMOVE_LIST_COMMAND: LexicalCommand<void>;
export interface RegisterListOptions {
restoreNumbering?: boolean;
}
export declare function registerList(editor: LexicalEditor, options?: RegisterListOptions): () => void;
export declare function registerListStrictIndentTransform(editor: LexicalEditor): () => void;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalNode, Spread } from 'lexical';
import { ListItemNode, ListNode } from './';
/**
* Checks the depth of listNode from the root node.
* @param listNode - The ListNode to be checked.
* @returns The depth of the ListNode.
*/
export declare function $getListDepth(listNode: ListNode): number;
/**
* Finds the nearest ancestral ListNode and returns it, throws an invariant if listItem is not a ListItemNode.
* @param listItem - The node to be checked.
* @returns The ListNode found.
*/
export declare function $getTopListNode(listItem: LexicalNode): ListNode;
/**
* Checks if listItem has no child ListNodes and has no ListItemNode ancestors with siblings.
* @param listItem - the ListItemNode to be checked.
* @returns true if listItem has no child ListNode and no ListItemNode ancestors with siblings, false otherwise.
*/
export declare function $isLastItemInList(listItem: ListItemNode): boolean;
/**
* A recursive Depth-First Search (Postorder Traversal) that finds all of a node's children
* that are of type ListItemNode and returns them in an array.
* @param node - The ListNode to start the search.
* @returns An array containing all nodes of type ListItemNode found.
*/
export declare function $getAllListItems(node: ListNode): Array<ListItemNode>;
declare const NestedListNodeBrand: unique symbol;
/**
* Checks to see if the passed node is a ListItemNode and has a ListNode as a child.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode and has a ListNode child, false otherwise.
*/
export declare function isNestedListNode(node: LexicalNode | null | undefined): node is Spread<{
getFirstChild(): ListNode;
[NestedListNodeBrand]: never;
}, ListItemNode>;
/**
* Traverses up the tree and returns the first ListItemNode found.
* @param node - Node to start the search.
* @returns The first ListItemNode found, or null if none exist.
*/
export declare function $findNearestListItemNode(node: LexicalNode): ListItemNode | null;
/**
* Takes a deeply nested ListNode or ListItemNode and traverses up the branch to delete the first
* ancestral ListNode (which could be the root ListNode) or ListItemNode with siblings, essentially
* bringing the deeply nested node up the branch once. Would remove sublist if it has siblings.
* Should not break ListItem -> List -> ListItem chain as empty List/ItemNodes should be removed on .remove().
* @param sublist - The nested ListNode or ListItemNode to be brought up the branch.
*/
export declare function $removeHighestEmptyListParent(sublist: ListItemNode | ListNode): void;
/**
* Calculates the start value for a new list created by splitting an existing list.
*/
export declare function $getNewListStart(list: ListNode, listItem: ListItemNode): number;
export {};
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {ListItemNode} from './LexicalListItemNode';
import type {LexicalCommand, LexicalEditor} from 'lexical';
import {Signal} from '@lexical/extension';
import {
$findMatchingParent,
calculateZoomLevel,
isHTMLElement,
mergeRegister,
} from '@lexical/utils';
import {
$addUpdateTag,
$getNearestNodeFromDOMNode,
$getSelection,
$isElementNode,
$isRangeSelection,
COMMAND_PRIORITY_LOW,
createCommand,
getNearestEditorFromDOMNode,
KEY_ARROW_DOWN_COMMAND,
KEY_ARROW_LEFT_COMMAND,
KEY_ARROW_UP_COMMAND,
KEY_ESCAPE_COMMAND,
KEY_SPACE_COMMAND,
SKIP_DOM_SELECTION_TAG,
SKIP_SELECTION_FOCUS_TAG,
} from 'lexical';
import {$insertList} from './formatList';
import {$isListItemNode} from './LexicalListItemNode';
import {$isListNode} from './LexicalListNode';
export const INSERT_CHECK_LIST_COMMAND: LexicalCommand<void> = createCommand(
'INSERT_CHECK_LIST_COMMAND',
);
/**
* Registers the checklist plugin with the editor.
* @param editor The LexicalEditor instance.
* @param options Optional configuration.
* - disableTakeFocusOnClick: If true, clicking a checklist item will not focus the editor (useful for mobile).
*/
export function registerCheckList(
editor: LexicalEditor,
options?: {disableTakeFocusOnClick?: boolean | Signal<boolean>},
) {
const disableTakeFocusOnClick =
(options && options.disableTakeFocusOnClick) || false;
const peekDisableTakeFocusOnClick =
typeof disableTakeFocusOnClick === 'boolean'
? () => disableTakeFocusOnClick
: disableTakeFocusOnClick.peek.bind(disableTakeFocusOnClick);
// Mobile tap fix: the touchstart listener registered below calls
// event.preventDefault() to keep the caret away from the marker. On iOS
// Safari and Android Chrome that suppression also cancels the synthesized
// click, so handleClick never runs and the checkbox cannot be toggled by
// tap. We additionally listen for pointerup with pointerType === 'touch'
// and run the same toggle logic, deduplicating against any click that
// does fire on browsers where preventDefault doesn't suppress it.
//
// Dedup state is per-target: recorded as `__lexicalCheckListLastHandled`
// on the target element. A global window would
// block tapping a second checkbox within 500ms of toggling the first.
const DEDUP_WINDOW_MS = 500;
const isWithinDedupWindow = (
event: PointerEvent | MouseEvent | TouchEvent,
): boolean => {
const target = event.target;
if (!isHTMLElement(target)) {
return false;
}
// @ts-ignore internal field
const last = target.__lexicalCheckListLastHandled as number | undefined;
return last !== undefined && event.timeStamp - last < DEDUP_WINDOW_MS;
};
const recordHandled = (event: PointerEvent | MouseEvent | TouchEvent) => {
const target = event.target;
if (isHTMLElement(target)) {
// @ts-ignore internal field
target.__lexicalCheckListLastHandled = event.timeStamp;
}
};
const configHandleClick = (event: PointerEvent | MouseEvent | TouchEvent) => {
if (isWithinDedupWindow(event)) {
return;
}
recordHandled(event);
handleClick(event, peekDisableTakeFocusOnClick());
};
const configHandlePointerUp = (event: PointerEvent) => {
if (event.pointerType !== 'touch') {
return;
}
if (isWithinDedupWindow(event)) {
return;
}
recordHandled(event);
handleClick(event, peekDisableTakeFocusOnClick());
};
const configHandleSelectDefaults = (
event: PointerEvent | MouseEvent | TouchEvent,
) => {
handleSelectDefaults(event, peekDisableTakeFocusOnClick());
};
return mergeRegister(
editor.registerCommand(
INSERT_CHECK_LIST_COMMAND,
() => {
$insertList('check');
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ARROW_DOWN_COMMAND,
event => {
return handleArrowUpOrDown(event, editor, false);
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ARROW_UP_COMMAND,
event => {
return handleArrowUpOrDown(event, editor, true);
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ESCAPE_COMMAND,
() => {
const activeItem = getActiveCheckListItem();
if (activeItem != null) {
const rootElement = editor.getRootElement();
if (rootElement != null) {
rootElement.focus();
}
return true;
}
return false;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_SPACE_COMMAND,
event => {
const activeItem = getActiveCheckListItem();
if (activeItem != null && editor.isEditable()) {
editor.update(() => {
const listItemNode = $getNearestNodeFromDOMNode(activeItem);
if ($isListItemNode(listItemNode)) {
event.preventDefault();
listItemNode.toggleChecked();
}
});
return true;
}
return false;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ARROW_LEFT_COMMAND,
event => {
return editor.getEditorState().read(() => {
const selection = $getSelection();
if ($isRangeSelection(selection) && selection.isCollapsed()) {
const {anchor} = selection;
const isElement = anchor.type === 'element';
if (isElement || anchor.offset === 0) {
const anchorNode = anchor.getNode();
const elementNode = $findMatchingParent(
anchorNode,
node => $isElementNode(node) && !node.isInline(),
);
if ($isListItemNode(elementNode)) {
const parent = elementNode.getParent();
if (
$isListNode(parent) &&
parent.getListType() === 'check' &&
(isElement || elementNode.getFirstDescendant() === anchorNode)
) {
const domNode = editor.getElementByKey(elementNode.__key);
if (domNode != null && document.activeElement !== domNode) {
domNode.focus();
event.preventDefault();
return true;
}
}
}
}
}
return false;
});
},
COMMAND_PRIORITY_LOW,
),
editor.registerRootListener(rootElement => {
if (rootElement !== null) {
rootElement.addEventListener('click', configHandleClick);
rootElement.addEventListener('pointerup', configHandlePointerUp);
// Use capture so we run before other listeners that might move focus.
rootElement.addEventListener(
'pointerdown',
configHandleSelectDefaults,
{
capture: true,
},
);
// Some browsers / integrations still generate mousedown events; handle them too.
rootElement.addEventListener('mousedown', configHandleSelectDefaults, {
capture: true,
});
// Intercept touchstart to stop the mobile browser from placing the caret
// and opening the keyboard when tapping the checklist marker.
rootElement.addEventListener('touchstart', configHandleSelectDefaults, {
capture: true,
passive: false,
});
return () => {
rootElement.removeEventListener('click', configHandleClick);
rootElement.removeEventListener('pointerup', configHandlePointerUp);
rootElement.removeEventListener(
'pointerdown',
configHandleSelectDefaults,
{
capture: true,
},
);
rootElement.removeEventListener(
'mousedown',
configHandleSelectDefaults,
{
capture: true,
},
);
rootElement.removeEventListener(
'touchstart',
configHandleSelectDefaults,
{
capture: true,
},
);
};
}
}),
);
}
function handleCheckItemEvent(
event: PointerEvent | MouseEvent | TouchEvent,
callback: () => void,
) {
const target = event.target;
if (!isHTMLElement(target)) {
return;
}
// Ignore clicks on LI that have nested lists
const firstChild = target.firstChild;
if (
isHTMLElement(firstChild) &&
(firstChild.tagName === 'UL' || firstChild.tagName === 'OL')
) {
return;
}
const parentNode = target.parentNode;
// @ts-ignore internal field
if (!parentNode || parentNode.__lexicalListType !== 'check') {
return;
}
let clientX: number | null = null;
let pointerType: string | null = null;
if ('clientX' in event) {
clientX = event.clientX;
} else if ('touches' in event) {
const touches = event.touches;
if (touches.length > 0) {
clientX = touches[0].clientX;
pointerType = 'touch';
}
}
// If we couldn't resolve a clientX (unexpected input), bail out.
if (clientX == null) {
return;
}
const rect = target.getBoundingClientRect();
const zoom = calculateZoomLevel(target);
const clientXInPixels = clientX / zoom;
// Use getComputedStyle if available, otherwise fallback to 0px width
const beforeStyles = window.getComputedStyle
? window.getComputedStyle(target, '::before')
: ({width: '0px'} as CSSStyleDeclaration);
const beforeWidthInPixels = parseFloat(beforeStyles.width);
// Make click area slightly larger for touch devices to improve accessibility
// Determine whether this is a touch event; some environments may supply
// pointerType on PointerEvent while touch events use the `touches` API above.
const isTouchEvent =
pointerType === 'touch' ||
('pointerType' in event && event.pointerType === 'touch');
const clickAreaPadding = isTouchEvent ? 32 : 0; // Add 32px padding for touch events
if (
target.dir === 'rtl'
? clientXInPixels < rect.right + clickAreaPadding &&
clientXInPixels > rect.right - beforeWidthInPixels - clickAreaPadding
: clientXInPixels > rect.left - clickAreaPadding &&
clientXInPixels < rect.left + beforeWidthInPixels + clickAreaPadding
) {
callback();
}
}
function handleClick(
event: PointerEvent | MouseEvent | TouchEvent,
disableFocusOnClick: boolean,
) {
handleCheckItemEvent(event, () => {
if (isHTMLElement(event.target)) {
const domNode = event.target;
const editor = getNearestEditorFromDOMNode(domNode);
if (editor != null && editor.isEditable()) {
editor.update(() => {
const node = $getNearestNodeFromDOMNode(domNode);
if ($isListItemNode(node)) {
if (disableFocusOnClick) {
$addUpdateTag(SKIP_SELECTION_FOCUS_TAG);
$addUpdateTag(SKIP_DOM_SELECTION_TAG);
} else {
domNode.focus();
}
node.toggleChecked();
}
});
}
}
});
}
/**
* Prevents default focus switch behavior
*
* @param event might be of type PointerEvent, MouseEvent, or TouchEvent, hence the generic Event type
*
*/
function handleSelectDefaults(
event: PointerEvent | MouseEvent | TouchEvent,
disableTakeFocusOnClick: boolean,
) {
handleCheckItemEvent(event, () => {
// Prevents caret moving when clicking on check mark.
event.preventDefault();
if (disableTakeFocusOnClick) {
event.stopPropagation();
}
});
}
function getActiveCheckListItem(): HTMLElement | null {
const activeElement = document.activeElement;
return isHTMLElement(activeElement) &&
activeElement.tagName === 'LI' &&
activeElement.parentNode != null &&
// @ts-ignore internal field
activeElement.parentNode.__lexicalListType === 'check'
? activeElement
: null;
}
function findCheckListItemSibling(
node: ListItemNode,
backward: boolean,
): ListItemNode | null {
let sibling = backward ? node.getPreviousSibling() : node.getNextSibling();
let parent: ListItemNode | null = node;
// Going up in a tree to get non-null sibling
while (sibling == null && $isListItemNode(parent)) {
// Get li -> parent ul/ol -> parent li
parent = parent.getParentOrThrow().getParent();
if (parent != null) {
sibling = backward
? parent.getPreviousSibling()
: parent.getNextSibling();
}
}
// Going down in a tree to get first non-nested list item
while ($isListItemNode(sibling)) {
const firstChild = backward
? sibling.getLastChild()
: sibling.getFirstChild();
if (!$isListNode(firstChild)) {
return sibling;
}
sibling = backward ? firstChild.getLastChild() : firstChild.getFirstChild();
}
return null;
}
function handleArrowUpOrDown(
event: KeyboardEvent,
editor: LexicalEditor,
backward: boolean,
) {
const activeItem = getActiveCheckListItem();
if (activeItem != null) {
editor.update(() => {
const listItem = $getNearestNodeFromDOMNode(activeItem);
if (!$isListItemNode(listItem)) {
return;
}
const nextListItem = findCheckListItemSibling(listItem, backward);
if (nextListItem != null) {
nextListItem.selectStart();
const dom = editor.getElementByKey(nextListItem.__key);
if (dom != null) {
event.preventDefault();
setTimeout(() => {
dom.focus();
}, 0);
}
}
});
}
return false;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import invariant from '@lexical/internal/invariant';
import {$getNearestNodeOfType} from '@lexical/utils';
import {
$copyNode,
$createParagraphNode,
$getChildCaret,
$getSelection,
$isElementNode,
$isLeafNode,
$isRangeSelection,
$isRootOrShadowRoot,
$isTextNode,
$normalizeCaret,
$setPointFromCaret,
ElementNode,
LexicalNode,
NodeKey,
ParagraphNode,
} from 'lexical';
import {
$createListItemNode,
$createListNode,
$isListItemNode,
$isListNode,
ListItemNode,
ListNode,
} from './';
import {ListType} from './LexicalListNode';
import {
$getAllListItems,
$getNewListStart,
$getTopListNode,
$removeHighestEmptyListParent,
isNestedListNode,
} from './utils';
function $isSelectingEmptyListItem(
anchorNode: ListItemNode | LexicalNode,
nodes: Array<LexicalNode>,
): boolean {
return (
$isListItemNode(anchorNode) &&
(nodes.length === 0 ||
(nodes.length === 1 &&
anchorNode.is(nodes[0]) &&
anchorNode.getChildrenSize() === 0))
);
}
/**
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export function $insertList(listType: ListType): void {
const selection = $getSelection();
if (selection !== null) {
let nodes = selection.getNodes();
if ($isRangeSelection(selection)) {
const [anchor] = selection.getStartEndPoints();
const anchorNode = anchor.getNode();
const anchorNodeParent = anchorNode.getParent();
if ($isRootOrShadowRoot(anchorNode)) {
const firstChild = anchorNode.getFirstChild();
if (firstChild) {
nodes = firstChild.selectStart().getNodes();
} else {
const paragraph = $createParagraphNode();
anchorNode.append(paragraph);
nodes = paragraph.select().getNodes();
}
} else if ($isSelectingEmptyListItem(anchorNode, nodes)) {
const list = $createListNode(listType);
if ($isRootOrShadowRoot(anchorNodeParent)) {
anchorNode.replace(list);
const listItem = $createListItemNode();
if ($isElementNode(anchorNode)) {
listItem.setFormat(anchorNode.getFormatType());
listItem.setIndent(anchorNode.getIndent());
}
list.append(listItem);
} else if ($isListItemNode(anchorNode)) {
const parent = anchorNode.getParentOrThrow();
append(list, parent.getChildren());
parent.replace(list);
}
return;
}
}
const handled = new Set();
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (
$isElementNode(node) &&
node.isEmpty() &&
!$isListItemNode(node) &&
!handled.has(node.getKey())
) {
$createListOrMerge(node, listType);
continue;
}
let parent = $isLeafNode(node)
? node.getParent()
: $isListItemNode(node) && node.isEmpty()
? node
: null;
while (parent != null) {
const parentKey = parent.getKey();
if ($isListNode(parent)) {
if (!handled.has(parentKey)) {
const newListNode = $createListNode(listType);
append(newListNode, parent.getChildren());
parent.replace(newListNode);
handled.add(parentKey);
}
break;
} else {
const nextParent = parent.getParent();
if ($isRootOrShadowRoot(nextParent) && !handled.has(parentKey)) {
handled.add(parentKey);
$createListOrMerge(parent, listType);
break;
}
parent = nextParent;
}
}
}
}
}
function append(node: ElementNode, nodesToAppend: Array<LexicalNode>) {
node.splice(node.getChildrenSize(), 0, nodesToAppend);
}
function $createListOrMerge(node: ElementNode, listType: ListType): ListNode {
if ($isListNode(node)) {
return node;
}
const previousSibling = node.getPreviousSibling();
const nextSibling = node.getNextSibling();
const listItem = $createListItemNode();
append(listItem, node.getChildren());
let targetList;
if (
$isListNode(previousSibling) &&
listType === previousSibling.getListType()
) {
previousSibling.append(listItem);
// if the same type of list is on both sides, merge them.
if ($isListNode(nextSibling) && listType === nextSibling.getListType()) {
append(previousSibling, nextSibling.getChildren());
nextSibling.remove();
}
targetList = previousSibling;
} else if (
$isListNode(nextSibling) &&
listType === nextSibling.getListType()
) {
nextSibling.getFirstChildOrThrow().insertBefore(listItem);
targetList = nextSibling;
} else {
const list = $createListNode(listType);
list.append(listItem);
node.replace(list);
targetList = list;
}
// listItem needs to be attached to root prior to setting indent
listItem.setFormat(node.getFormatType());
listItem.setIndent(node.getIndent());
// Preserve element-anchored selections by updating them to anchor to the listItem instead of the listNode.
const selection = $getSelection();
if ($isRangeSelection(selection)) {
if (targetList.getKey() === selection.anchor.key) {
selection.anchor.set(
listItem.getKey(),
selection.anchor.offset,
'element',
);
}
if (targetList.getKey() === selection.focus.key) {
selection.focus.set(listItem.getKey(), selection.focus.offset, 'element');
}
}
node.remove();
return targetList;
}
/**
* A recursive function that goes through each list and their children, including nested lists,
* appending list2 children after list1 children and updating ListItemNode values.
* @param list1 - The first list to be merged.
* @param list2 - The second list to be merged.
*/
export function mergeLists(list1: ListNode, list2: ListNode): void {
const listItem1 = list1.getLastChild();
const listItem2 = list2.getFirstChild();
if (
listItem1 &&
listItem2 &&
isNestedListNode(listItem1) &&
isNestedListNode(listItem2)
) {
mergeLists(listItem1.getFirstChild(), listItem2.getFirstChild());
listItem2.remove();
}
const toMerge = list2.getChildren();
if (toMerge.length > 0) {
list1.append(...toMerge);
}
list2.remove();
}
/**
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
*/
export function $removeList(): void {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
const listNodes = new Set<ListNode>();
const nodes = selection.getNodes();
const anchorNode = selection.anchor.getNode();
if ($isSelectingEmptyListItem(anchorNode, nodes)) {
listNodes.add($getTopListNode(anchorNode));
} else {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if ($isLeafNode(node)) {
const listItemNode = $getNearestNodeOfType(node, ListItemNode);
if (listItemNode != null) {
listNodes.add($getTopListNode(listItemNode));
}
}
}
}
for (const listNode of listNodes) {
let insertionPoint: ListNode | ParagraphNode = listNode;
const listItems = $getAllListItems(listNode);
for (const listItemNode of listItems) {
const paragraph = $createParagraphNode()
.setTextStyle(selection.style)
.setTextFormat(selection.format);
append(paragraph, listItemNode.getChildren());
insertionPoint.insertAfter(paragraph);
insertionPoint = paragraph;
// When the anchor and focus fall on the textNode
// we don't have to change the selection because the textNode will be appended to
// the newly generated paragraph.
// When selection is in empty nested list item, selection is actually on the listItemNode.
// When the corresponding listItemNode is deleted and replaced by the newly generated paragraph
// we should manually set the selection's focus and anchor to the newly generated paragraph.
if (listItemNode.__key === selection.anchor.key) {
$setPointFromCaret(
selection.anchor,
$normalizeCaret($getChildCaret(paragraph, 'next')),
);
}
if (listItemNode.__key === selection.focus.key) {
$setPointFromCaret(
selection.focus,
$normalizeCaret($getChildCaret(paragraph, 'next')),
);
}
listItemNode.remove();
}
listNode.remove();
}
}
}
/**
* Takes the value of a child ListItemNode and makes it the value the ListItemNode
* 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.
*/
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.getLatest().__checked != null) {
child.setChecked(undefined);
}
if (!$isListNode(child.getFirstChild())) {
value++;
}
}
}
}
/**
* Merge the next sibling list if same type.
* <ul> will merge with <ul>, but NOT <ul> with <ol>.
* @param list - The list whose next sibling should be potentially merged
*/
export function mergeNextSiblingListIfSameType(list: ListNode): void {
const nextSibling = list.getNextSibling();
if (
$isListNode(nextSibling) &&
list.getListType() === nextSibling.getListType()
) {
mergeLists(list, nextSibling);
}
}
/**
* Adds an empty ListNode/ListItemNode chain at listItemNode, so as to
* create an indent effect. Won't indent ListItemNodes that have a ListNode as
* a child, but does merge sibling ListItemNodes if one has a nested ListNode.
* @param listItemNode - The ListItemNode to be indented.
*/
export function $handleIndent(listItemNode: ListItemNode): void {
// go through each node and decide where to move it.
const removed = new Set<NodeKey>();
if (isNestedListNode(listItemNode) || removed.has(listItemNode.getKey())) {
return;
}
const parent = listItemNode.getParent();
// We can cast both of the below `isNestedListNode` only returns a boolean type instead of a user-defined type guards
const nextSibling =
listItemNode.getNextSibling<ListItemNode>() as ListItemNode;
const previousSibling =
listItemNode.getPreviousSibling<ListItemNode>() as ListItemNode;
// if there are nested lists on either side, merge them all together.
if (isNestedListNode(nextSibling) && isNestedListNode(previousSibling)) {
const innerList = previousSibling.getFirstChild();
if ($isListNode(innerList)) {
innerList.append(listItemNode);
const nextInnerList = nextSibling.getFirstChild();
if ($isListNode(nextInnerList)) {
const children = nextInnerList.getChildren();
append(innerList, children);
nextSibling.remove();
removed.add(nextSibling.getKey());
}
}
} else if (isNestedListNode(nextSibling)) {
// if the ListItemNode is next to a nested ListNode, merge them
const innerList = nextSibling.getFirstChild();
if ($isListNode(innerList)) {
const firstChild = innerList.getFirstChild();
if (firstChild !== null) {
firstChild.insertBefore(listItemNode);
}
}
} else if (isNestedListNode(previousSibling)) {
const innerList = previousSibling.getFirstChild();
if ($isListNode(innerList)) {
innerList.append(listItemNode);
}
} else {
// otherwise, we need to create a new nested ListNode
if ($isListNode(parent)) {
const newListItem = $copyNode(listItemNode);
const newList = $copyNode(parent);
newListItem.append(newList);
newList.append(listItemNode);
if (previousSibling) {
previousSibling.insertAfter(newListItem);
} else if (nextSibling) {
nextSibling.insertBefore(newListItem);
} else {
parent.append(newListItem);
}
}
}
}
/**
* Removes an indent by removing an empty ListNode/ListItemNode chain. An indented ListItemNode
* has a great grandparent node of type ListNode, which is where the ListItemNode will reside
* within as a child.
* @param listItemNode - The ListItemNode to remove the indent (outdent).
*/
export function $handleOutdent(listItemNode: ListItemNode): void {
// go through each node and decide where to move it.
if (isNestedListNode(listItemNode)) {
return;
}
const parentList = listItemNode.getParent();
const grandparentListItem = parentList ? parentList.getParent() : undefined;
const greatGrandparentList = grandparentListItem
? grandparentListItem.getParent()
: undefined;
// If it doesn't have these ancestors, it's not indented.
if (
$isListNode(greatGrandparentList) &&
$isListItemNode(grandparentListItem) &&
$isListNode(parentList)
) {
// if it's the first child in it's parent list, insert it into the
// great grandparent list before the grandparent
const firstChild = parentList ? parentList.getFirstChild() : undefined;
const lastChild = parentList ? parentList.getLastChild() : undefined;
if (listItemNode.is(firstChild)) {
grandparentListItem.insertBefore(listItemNode);
if (parentList.isEmpty()) {
grandparentListItem.remove();
}
// if it's the last child in it's parent list, insert it into the
// great grandparent list after the grandparent.
} else if (listItemNode.is(lastChild)) {
grandparentListItem.insertAfter(listItemNode);
if (parentList.isEmpty()) {
grandparentListItem.remove();
}
} else {
// otherwise, we need to split the siblings into two new nested lists
const previousSiblingsListItem = $copyNode(listItemNode);
const previousSiblingsList = $copyNode(parentList);
previousSiblingsListItem.append(previousSiblingsList);
listItemNode
.getPreviousSiblings()
.forEach(sibling => previousSiblingsList.append(sibling));
const nextSiblingsListItem = $copyNode(listItemNode);
const nextSiblingsList = $copyNode(parentList);
nextSiblingsListItem.append(nextSiblingsList);
append(nextSiblingsList, listItemNode.getNextSiblings());
// put the sibling nested lists on either side of the grandparent list item in the great grandparent.
grandparentListItem.insertBefore(previousSiblingsListItem);
grandparentListItem.insertAfter(nextSiblingsListItem);
// replace the grandparent list item (now between the siblings) with the outdented list item.
grandparentListItem.replace(listItemNode);
}
}
}
/**
* Attempts to insert a ParagraphNode at selection and selects the new node. The selection must contain a ListItemNode
* or a node that does not already contain text. If its grandparent is the root/shadow root, it will get the ListNode
* (which should be the parent node) and insert the ParagraphNode as a sibling to the ListNode. If the ListNode is
* nested in a ListItemNode instead, it will add the ParagraphNode after the grandparent ListItemNode.
* Throws an invariant if the selection is not a child of a ListNode.
* @returns true if a ParagraphNode was inserted successfully, false if there is no selection
* or the selection does not contain a ListItemNode or the node already holds text.
*/
export function $handleListInsertParagraph(
restoreNumbering: boolean = false,
): boolean {
const selection = $getSelection();
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
return false;
}
// Only run this code on empty list items (including whitespace-only)
const anchor = selection.anchor.getNode();
let listItem: ListItemNode | null = null;
if ($isListItemNode(anchor) && anchor.getChildrenSize() === 0) {
// Truly empty list item (element selection)
listItem = anchor;
} else if ($isTextNode(anchor)) {
// Check if the entire list item contains only whitespace text nodes
const parentListItem = anchor.getParent();
if (
$isListItemNode(parentListItem) &&
parentListItem
.getChildren()
.every(node => $isTextNode(node) && node.getTextContent().trim() === '')
) {
listItem = parentListItem;
}
}
if (listItem === null) {
return false;
}
const topListNode = $getTopListNode(listItem);
const parent = listItem.getParent();
invariant(
$isListNode(parent),
'A ListItemNode must have a ListNode for a parent.',
);
const grandparent = parent.getParent();
let replacementNode: ParagraphNode | ListItemNode;
if ($isRootOrShadowRoot(grandparent)) {
replacementNode = $createParagraphNode();
topListNode.insertAfter(replacementNode);
} else if ($isListItemNode(grandparent)) {
replacementNode = $copyNode(grandparent);
grandparent.insertAfter(replacementNode);
} else {
return false;
}
replacementNode
.setTextStyle(selection.style)
.setTextFormat(selection.format)
.select();
const nextSiblings = listItem.getNextSiblings();
if (nextSiblings.length > 0) {
const newStart = restoreNumbering ? $getNewListStart(parent, listItem) : 1;
const newList = $copyNode(parent).setStart(newStart);
if ($isListItemNode(replacementNode)) {
const newListItem = $copyNode(replacementNode);
newListItem.append(newList);
replacementNode.insertAfter(newListItem);
} else {
replacementNode.insertAfter(newList);
}
newList.append(...nextSiblings);
}
// Don't leave hanging nested empty lists
$removeHighestEmptyListParent(listItem);
return true;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {SerializedListItemNode} from './LexicalListItemNode';
import type {
ListNodeTagType,
ListType,
SerializedListNode,
} from './LexicalListNode';
import type {LexicalEditor} from 'lexical';
import {INSERT_CHECK_LIST_COMMAND, registerCheckList} from './checkList';
import {
$handleListInsertParagraph,
$insertList,
$removeList,
} from './formatList';
import {
$createListItemNode,
$isListItemNode,
ListItemNode,
} from './LexicalListItemNode';
import {$createListNode, $isListNode, ListNode} from './LexicalListNode';
import {$getListDepth} from './utils';
export {
type CheckListConfig,
CheckListExtension,
type ListConfig,
ListExtension,
} from './LexicalListExtension';
export {
ListImportExtension,
ListImportRules,
ListSchema,
} from './ListImportExtension';
export {
INSERT_ORDERED_LIST_COMMAND,
INSERT_UNORDERED_LIST_COMMAND,
registerList,
type RegisterListOptions,
registerListStrictIndentTransform,
REMOVE_LIST_COMMAND,
UPDATE_LIST_START_COMMAND,
} from './registerList';
export {
$createListItemNode,
$createListNode,
$getListDepth,
$handleListInsertParagraph,
$insertList,
$isListItemNode,
$isListNode,
$removeList,
INSERT_CHECK_LIST_COMMAND,
ListItemNode,
ListNode,
ListNodeTagType,
ListType,
registerCheckList,
SerializedListItemNode,
SerializedListNode,
};
/**
* @deprecated use {@link $insertList} from an update or command listener.
*
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param editor - The lexical editor.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export function insertList(editor: LexicalEditor, listType: ListType): void {
editor.update(() => $insertList(listType));
}
/**
* @deprecated use {@link $removeList} from an update or command listener.
*
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
* @param editor - The lexical editor.
*/
export function removeList(editor: LexicalEditor): void {
editor.update(() => $removeList());
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {effect, namedSignals} from '@lexical/extension';
import {mergeRegister} from '@lexical/utils';
import {defineExtension, safeCast} from 'lexical';
import {registerCheckList} from './checkList';
import {ListItemNode} from './LexicalListItemNode';
import {ListNode} from './LexicalListNode';
import {registerList, registerListStrictIndentTransform} from './registerList';
export interface ListConfig {
/**
* When `true`, enforces strict indentation rules for list items, ensuring consistent structure.
* When `false` (default), indentation is more flexible.
*/
hasStrictIndent: boolean;
shouldPreserveNumbering: boolean;
}
/**
* Configures {@link ListNode}, {@link ListItemNode} and registers
* the strict indent transform if `hasStrictIndent` is true (default false).
*/
export const ListExtension = defineExtension({
build(editor, config, state) {
return namedSignals(config);
},
config: safeCast<ListConfig>({
hasStrictIndent: false,
shouldPreserveNumbering: false,
}),
name: '@lexical/list/List',
nodes: () => [ListNode, ListItemNode],
register(editor, config, state) {
const stores = state.getOutput();
return mergeRegister(
effect(() => {
return registerList(editor, {
restoreNumbering: stores.shouldPreserveNumbering.value,
});
}),
effect(() =>
stores.hasStrictIndent.value
? registerListStrictIndentTransform(editor)
: undefined,
),
);
},
});
export interface CheckListConfig {
disableTakeFocusOnClick: boolean;
}
/**
* Registers checklist functionality for {@link ListNode} and
* {@link ListItemNode} with a `INSERT_CHECK_LIST_COMMAND` listener and
* the expected keyboard and mouse interactions for checkboxes.
*/
export const CheckListExtension = defineExtension({
build: (editor, config) => namedSignals(config),
config: safeCast<CheckListConfig>({
disableTakeFocusOnClick: false,
}),
dependencies: [ListExtension],
name: '@lexical/list/CheckList',
register: (editor, config, state) =>
registerCheckList(editor, state.getOutput()),
});
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {ListNode, ListType} from './';
import type {
BaseSelection,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
EditorThemeClasses,
LexicalNode,
LexicalUpdateJSON,
NodeKey,
ParagraphNode,
RangeSelection,
SerializedElementNode,
Spread,
} from 'lexical';
import invariant from '@lexical/internal/invariant';
import {
$insertNodeToNearestRootAtCaret,
addClassNamesToElement,
removeClassNamesFromElement,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$copyNode,
$createParagraphNode,
$getSelection,
$getSiblingCaret,
$isElementNode,
$isParagraphNode,
$isRangeSelection,
$isRootOrShadowRoot,
$rewindSiblingCaret,
$setDirectionFromDOM,
$setFormatFromDOM,
buildImportMap,
ElementNode,
getStyleObjectFromCSS,
isHTMLElement,
LexicalEditor,
normalizeClassNames,
setDOMStyleFromCSS,
} from 'lexical';
import {$createListNode, $isListNode} from './';
import {$handleIndent, $handleOutdent, mergeLists} from './formatList';
import {isNestedListNode} from './utils';
export type SerializedListItemNode = Spread<
{
checked: boolean | undefined;
value: number;
},
SerializedElementNode
>;
function applyMarkerStyles(
dom: HTMLElement,
node: ListItemNode,
prevNode: ListItemNode | null,
): void {
const nextTextStyle = node.__textStyle;
const prevTextStyle = prevNode ? prevNode.__textStyle : '';
if (prevNode !== null && prevTextStyle === nextTextStyle) {
return;
}
const styles: Record<string, string> = getStyleObjectFromCSS(nextTextStyle);
for (const k in styles) {
dom.style.setProperty(`--listitem-marker-${k}`, styles[k]);
}
if (prevTextStyle !== '') {
for (const k in getStyleObjectFromCSS(prevTextStyle)) {
if (!(k in styles)) {
dom.style.removeProperty(`--listitem-marker-${k}`);
}
}
}
}
/** @noInheritDoc */
export class ListItemNode extends ElementNode {
/** @internal */
__value: number;
/** @internal */
__checked?: boolean;
/** @internal */
$config() {
return this.config('listitem', {
$transform: (node: ListItemNode): void => {
const parent = node.getParent();
if ($isListNode(parent)) {
if (parent.getListType() !== 'check' && node.getChecked() != null) {
node.setChecked(undefined);
}
} else if (parent) {
const newParent = node.createParentElementNode();
invariant(
$isListNode(newParent),
'ListItemNode.createParentElementNode() must return a ListNode',
);
// Insert an empty ListNode at the orphan's position, splitting
// any enclosing non-shadow-root blocks so the ListNode lifts to
// a valid container before we move the orphan in. The ListNode
// $transform merges adjacent same-type lists, so neighbouring
// orphans will coalesce once their own transforms run.
const children = [node];
for (const dir of ['previous', 'next'] as const) {
children.reverse();
for (const {origin} of $getSiblingCaret(node, dir)) {
if (!$isListItemNode(origin)) {
break;
}
children.push(origin);
}
}
node.insertBefore(newParent);
newParent.splice(0, 0, children);
if (!$isRootOrShadowRoot(parent)) {
$insertNodeToNearestRootAtCaret(
newParent,
$rewindSiblingCaret($getSiblingCaret(newParent, 'next')),
{$shouldSplit: () => false, removeEmptyDestination: true},
);
if (parent.isEmpty() && parent.isAttached()) {
parent.remove();
}
}
}
},
extends: ElementNode,
importDOM: buildImportMap({
li: () => ({
conversion: $convertListItemElement,
priority: 0,
}),
}),
});
}
constructor(
value: number = 1,
checked: undefined | boolean = undefined,
key?: NodeKey,
) {
super(key);
this.__value = value === undefined ? 1 : value;
this.__checked = checked;
}
afterCloneFrom(prevNode: this): void {
super.afterCloneFrom(prevNode);
this.__value = prevNode.__value;
this.__checked = prevNode.__checked;
}
createDOM(config: EditorConfig): HTMLElement {
const element = document.createElement('li');
this.updateListItemDOM(null, element, config);
return element;
}
updateListItemDOM(
prevNode: ListItemNode | null,
dom: HTMLLIElement,
config: EditorConfig,
) {
updateListItemChecked(dom, this, prevNode);
dom.value = this.__value;
$setListItemThemeClassNames(dom, config.theme, this);
const prevStyle = prevNode ? prevNode.__style : '';
const nextStyle = this.__style;
if (prevStyle !== nextStyle) {
setDOMStyleFromCSS(dom.style, nextStyle, prevStyle);
}
applyMarkerStyles(dom, this, prevNode);
}
updateDOM(
prevNode: ListItemNode,
dom: HTMLElement,
config: EditorConfig,
): boolean {
// @ts-expect-error - this is always HTMLListItemElement
const element: HTMLLIElement = dom;
this.updateListItemDOM(prevNode, element, config);
return false;
}
updateFromJSON(
serializedNode: LexicalUpdateJSON<SerializedListItemNode>,
): this {
return super
.updateFromJSON(serializedNode)
.setValue(serializedNode.value)
.setChecked(serializedNode.checked);
}
exportDOM(editor: LexicalEditor): DOMExportOutput {
const element = this.createDOM(editor._config);
const formatType = this.getFormatType();
if (formatType) {
element.style.textAlign = formatType;
}
const direction = this.getDirection();
if (direction) {
element.dir = direction;
}
if (isNestedListNode(this)) {
return {
after(containerElement) {
if (isHTMLElement(containerElement)) {
const prevSibling = containerElement.previousElementSibling;
if (isHTMLElement(prevSibling) && prevSibling.nodeName === 'LI') {
while (containerElement.firstChild) {
prevSibling.append(containerElement.firstChild);
}
containerElement.remove();
}
}
return containerElement;
},
element,
};
}
return {
element,
};
}
exportJSON(): SerializedListItemNode {
return {
...super.exportJSON(),
checked: this.getChecked(),
value: this.getValue(),
};
}
append(...nodes: LexicalNode[]): this {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if ($isElementNode(node) && this.canMergeWith(node)) {
const children = node.getChildren();
this.append(...children);
node.remove();
} else {
super.append(node);
}
}
return this;
}
replace<N extends LexicalNode>(
replaceWithNode: N,
includeChildren?: boolean,
): N {
if ($isListItemNode(replaceWithNode)) {
return super.replace(replaceWithNode);
}
this.setIndent(0);
const list = this.getParentOrThrow();
if (!$isListNode(list)) {
return replaceWithNode;
}
if (list.__first === this.getKey()) {
list.insertBefore(replaceWithNode);
} else if (list.__last === this.getKey()) {
list.insertAfter(replaceWithNode);
} else {
// Split the list
const newList = $copyNode(list);
let nextSibling = this.getNextSibling();
while (nextSibling) {
const nodeToAppend = nextSibling;
nextSibling = nextSibling.getNextSibling();
newList.append(nodeToAppend);
}
list.insertAfter(replaceWithNode);
replaceWithNode.insertAfter(newList);
}
const toReplaceKey = this.__key;
let prevSizeBeforeChildrenTransfer = 0;
if (includeChildren) {
invariant(
$isElementNode(replaceWithNode),
'includeChildren should only be true for ElementNodes',
);
prevSizeBeforeChildrenTransfer = replaceWithNode.getChildrenSize();
replaceWithNode.splice(
prevSizeBeforeChildrenTransfer,
0,
this.getChildren(),
);
}
// The base LexicalNode.replace remaps element-anchored selection points
// from the replaced node to the replacement, but this override skips
// super and the trailing this.remove() would otherwise drop selection
// onto a sibling list item via moveSelectionPointToSibling. Mirror the
// base behavior here for the element-anchored case.
if (includeChildren && $isElementNode(replaceWithNode)) {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
for (const point of selection.getStartEndPoints()) {
if (point.key === toReplaceKey && point.type === 'element') {
point.set(
replaceWithNode.getKey(),
prevSizeBeforeChildrenTransfer + point.offset,
'element',
);
}
}
}
}
this.remove();
if (list.getChildrenSize() === 0) {
list.remove();
}
return replaceWithNode;
}
insertAfter(node: LexicalNode, restoreSelection = true): LexicalNode {
const listNode = this.getParentOrThrow();
if (!$isListNode(listNode)) {
invariant(
false,
'insertAfter: list node is not parent of list item node',
);
}
if ($isListItemNode(node)) {
return super.insertAfter(node, restoreSelection);
}
const siblings = this.getNextSiblings();
// Split the lists and insert the node in between them
listNode.insertAfter(node, restoreSelection);
if (siblings.length !== 0) {
const newListNode = $copyNode(listNode);
siblings.forEach(sibling => newListNode.append(sibling));
node.insertAfter(newListNode, restoreSelection);
}
return node;
}
remove(preserveEmptyParent?: boolean): void {
const prevSibling = this.getPreviousSibling();
const nextSibling = this.getNextSibling();
super.remove(preserveEmptyParent);
if (
prevSibling &&
nextSibling &&
isNestedListNode(prevSibling) &&
isNestedListNode(nextSibling)
) {
mergeLists(prevSibling.getFirstChild(), nextSibling.getFirstChild());
nextSibling.remove();
}
}
resetOnCopyNodeFrom(original: this): void {
super.resetOnCopyNodeFrom(original);
if (original.getChecked()) {
this.setChecked(false);
}
}
insertNewAfter(
_: RangeSelection,
restoreSelection = true,
): ListItemNode | ParagraphNode {
const newElement = $copyNode(this);
this.insertAfter(newElement, restoreSelection);
return newElement;
}
collapseAtStart(selection: RangeSelection): true {
const paragraph = $createParagraphNode();
const children = this.getChildren();
children.forEach(child => paragraph.append(child));
const listNode = this.getParentOrThrow();
const listNodeParent = listNode.getParentOrThrow();
const isIndented = $isListItemNode(listNodeParent);
if (listNode.getChildrenSize() === 1) {
if (isIndented) {
// if the list node is nested, we just want to remove it,
// effectively unindenting it.
listNode.remove();
listNodeParent.select();
} else {
listNode.insertBefore(paragraph);
listNode.remove();
// If we have selection on the list item, we'll need to move it
// to the paragraph
const anchor = selection.anchor;
const focus = selection.focus;
const key = paragraph.getKey();
if (anchor.type === 'element' && anchor.getNode().is(this)) {
anchor.set(key, anchor.offset, 'element');
}
if (focus.type === 'element' && focus.getNode().is(this)) {
focus.set(key, focus.offset, 'element');
}
}
} else {
listNode.insertBefore(paragraph);
this.remove();
}
return true;
}
getValue(): number {
const self = this.getLatest();
return self.__value;
}
setValue(value: number): this {
const self = this.getWritable();
self.__value = value;
return self;
}
getChecked(): boolean | undefined {
const self = this.getLatest();
let listType: ListType | undefined;
const parent = this.getParent();
if ($isListNode(parent)) {
listType = parent.getListType();
}
return listType === 'check' ? Boolean(self.__checked) : undefined;
}
setChecked(checked?: boolean): this {
const self = this.getWritable();
self.__checked = checked;
return self;
}
toggleChecked(): this {
const self = this.getWritable();
return self.setChecked(!self.__checked);
}
getIndent(): number {
// If we don't have a parent, we are likely serializing
const parent = this.getParent();
if (parent === null || !this.isAttached()) {
return this.getLatest().__indent;
}
// ListItemNode should always have a ListNode for a parent.
let listNodeParent = parent.getParentOrThrow();
let indentLevel = 0;
while ($isListItemNode(listNodeParent)) {
listNodeParent = listNodeParent.getParentOrThrow().getParentOrThrow();
indentLevel++;
}
return indentLevel;
}
setIndent(indent: number): this {
invariant(typeof indent === 'number', 'Invalid indent value.');
indent = Math.floor(indent);
invariant(indent >= 0, 'Indent value must be non-negative.');
let currentIndent = this.getIndent();
while (currentIndent !== indent) {
if (currentIndent < indent) {
$handleIndent(this);
currentIndent++;
} else {
$handleOutdent(this);
currentIndent--;
}
}
return this;
}
/** @deprecated @internal */
canInsertAfter(node: LexicalNode): boolean {
return $isListItemNode(node);
}
/** @deprecated @internal */
canReplaceWith(replacement: LexicalNode): boolean {
return $isListItemNode(replacement);
}
canMergeWith(node: LexicalNode): boolean {
return $isListItemNode(node) || $isParagraphNode(node);
}
extractWithChild(child: LexicalNode, selection: BaseSelection): boolean {
if (!$isRangeSelection(selection)) {
return false;
}
const anchorNode = selection.anchor.getNode();
const focusNode = selection.focus.getNode();
return (
this.isParentOf(anchorNode) &&
this.isParentOf(focusNode) &&
this.getTextContent().length === selection.getTextContent().length
);
}
isParentRequired(): true {
return true;
}
createParentElementNode(): ListNode {
return $createListNode('bullet');
}
canMergeWhenEmpty(): true {
return true;
}
}
function $setListItemThemeClassNames(
dom: HTMLElement,
editorThemeClasses: EditorThemeClasses,
node: ListItemNode,
): void {
const listTheme = editorThemeClasses.list;
if (!listTheme) {
return;
}
const listItemClassName = listTheme.listitem;
const nestedListItemClassName = listTheme.nested && listTheme.nested.listitem;
const parentNode = node.getParent();
const isCheckList =
$isListNode(parentNode) && parentNode.getListType() === 'check';
const checked = node.getChecked();
const isNested = node.getChildren().some(child => $isListNode(child));
// Always remove the variable theme classes first so that the className
// string stays in a canonical order regardless of how the dom got here
// (fresh create vs. cross-parent reuse). classList.remove on a missing
// class is a no-op, so this is safe even on a freshly-created element.
const classesToRemove: string[] = [];
if (listTheme.listitemChecked !== undefined) {
classesToRemove.push(listTheme.listitemChecked);
}
if (listTheme.listitemUnchecked !== undefined) {
classesToRemove.push(listTheme.listitemUnchecked);
}
if (nestedListItemClassName !== undefined) {
classesToRemove.push(...normalizeClassNames(nestedListItemClassName));
}
if (classesToRemove.length > 0) {
removeClassNamesFromElement(dom, ...classesToRemove);
}
const classesToAdd: string[] = [];
if (listItemClassName !== undefined) {
classesToAdd.push(...normalizeClassNames(listItemClassName));
}
if (isCheckList) {
const checkClassName = checked
? listTheme.listitemChecked
: listTheme.listitemUnchecked;
if (checkClassName !== undefined) {
classesToAdd.push(checkClassName);
}
}
if (nestedListItemClassName !== undefined && isNested) {
classesToAdd.push(...normalizeClassNames(nestedListItemClassName));
}
if (classesToAdd.length > 0) {
addClassNamesToElement(dom, ...classesToAdd);
}
}
function updateListItemChecked(
dom: HTMLElement,
listItemNode: ListItemNode,
prevListItemNode: ListItemNode | null,
): void {
const parent = listItemNode.getParent();
const isCheckbox =
$isListNode(parent) &&
parent.getListType() === 'check' &&
// Only add attributes for leaf list items
!$isListNode(listItemNode.getFirstChild());
if (!isCheckbox) {
dom.removeAttribute('role');
dom.removeAttribute('tabIndex');
dom.removeAttribute('aria-checked');
} else {
dom.setAttribute('role', 'checkbox');
dom.setAttribute('tabIndex', '-1');
dom.setAttribute(
'aria-checked',
listItemNode.getChecked() ? 'true' : 'false',
);
}
}
function $convertListItemElement(domNode: HTMLElement): DOMConversionOutput {
const isGitHubCheckList = domNode.classList.contains('task-list-item');
if (isGitHubCheckList) {
for (const child of domNode.children) {
if (child.tagName === 'INPUT') {
return $convertCheckboxInput(child);
}
}
}
const isJoplinCheckList = domNode.classList.contains('joplin-checkbox');
if (isJoplinCheckList) {
for (const child of domNode.children) {
if (
child.classList.contains('checkbox-wrapper') &&
child.children.length > 0 &&
child.children[0].tagName === 'INPUT'
) {
return $convertCheckboxInput(child.children[0]);
}
}
}
const ariaCheckedAttr = domNode.getAttribute('aria-checked');
const checked =
ariaCheckedAttr === 'true'
? true
: ariaCheckedAttr === 'false'
? false
: undefined;
const node = $createListItemNode(checked);
$setFormatFromDOM(node, domNode);
return {
after: setFormatFromChildren.bind(null, node),
node: $setDirectionFromDOM(node, domNode),
};
}
function $convertCheckboxInput(domNode: Element): DOMConversionOutput {
const isCheckboxInput = domNode.getAttribute('type') === 'checkbox';
if (!isCheckboxInput) {
return {node: null};
}
const checked = domNode.hasAttribute('checked');
const node = $createListItemNode(checked);
return {after: setFormatFromChildren.bind(null, node), node};
}
function setFormatFromChildren(
listItemNode: ListItemNode,
children: LexicalNode[],
): LexicalNode[] {
const firstChild = children[0];
// google doc sets the alignment of the <p> tag inside the <li>
if (
children.length === 1 &&
$isParagraphNode(firstChild) &&
!listItemNode.getFormatType() &&
firstChild.getFormatType()
) {
listItemNode.setFormat(firstChild.getFormatType());
return firstChild.getChildren();
}
return children;
}
/**
* Creates a new List Item node, passing true/false will convert it to a checkbox input.
* @param checked - Is the List Item a checkbox and, if so, is it checked? undefined/null: not a checkbox, true/false is a checkbox and checked/unchecked, respectively.
* @returns The new List Item.
*/
export function $createListItemNode(checked?: boolean): ListItemNode {
return $applyNodeReplacement(new ListItemNode(undefined, checked));
}
/**
* Checks to see if the node is a ListItemNode.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode, false otherwise.
*/
export function $isListItemNode(
node: LexicalNode | null | undefined,
): node is ListItemNode {
return node instanceof ListItemNode;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {
addClassNamesToElement,
isHTMLElement,
removeClassNamesFromElement,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$createTextNode,
$isElementNode,
$setDirectionFromDOM,
buildImportMap,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
EditorThemeClasses,
ElementNode,
LexicalEditor,
LexicalNode,
LexicalUpdateJSON,
NodeKey,
normalizeClassNames,
SerializedElementNode,
Spread,
} from 'lexical';
import {$createListItemNode, $isListItemNode, ListItemNode} from '.';
import {
mergeNextSiblingListIfSameType,
updateChildrenListItemValue,
} from './formatList';
import {$getListDepth} from './utils';
export type SerializedListNode = Spread<
{
listType: ListType;
start: number;
tag: ListNodeTagType;
},
SerializedElementNode
>;
export type ListType = 'number' | 'bullet' | 'check';
export type ListNodeTagType = 'ul' | 'ol';
/** @noInheritDoc */
export class ListNode extends ElementNode {
/** @internal */
__tag: ListNodeTagType;
/** @internal */
__start: number;
/** @internal */
__listType: ListType;
/** @internal */
$config() {
return this.config('list', {
$transform: (node: ListNode): void => {
mergeNextSiblingListIfSameType(node);
updateChildrenListItemValue(node);
},
extends: ElementNode,
importDOM: buildImportMap({
ol: () => ({
conversion: $convertListNode,
priority: 0,
}),
ul: () => ({
conversion: $convertListNode,
priority: 0,
}),
}),
});
}
constructor(listType: ListType = 'number', start: number = 1, key?: NodeKey) {
super(key);
const _listType = TAG_TO_LIST_TYPE[listType] || listType;
this.__listType = _listType;
this.__tag = _listType === 'number' ? 'ol' : 'ul';
this.__start = start;
}
afterCloneFrom(prevNode: this): void {
super.afterCloneFrom(prevNode);
this.__listType = prevNode.__listType;
this.__tag = prevNode.__tag;
this.__start = prevNode.__start;
}
getTag(): ListNodeTagType {
return this.getLatest().__tag;
}
setListType(type: ListType): this {
const writable = this.getWritable();
writable.__listType = type;
writable.__tag = type === 'number' ? 'ol' : 'ul';
return writable;
}
getListType(): ListType {
return this.getLatest().__listType;
}
getStart(): number {
return this.getLatest().__start;
}
setStart(start: number): this {
const self = this.getWritable();
self.__start = start;
return self;
}
// View
createDOM(config: EditorConfig, _editor?: LexicalEditor): HTMLElement {
const tag = this.__tag;
const dom = document.createElement(tag);
if (this.__start !== 1) {
dom.setAttribute('start', String(this.__start));
}
// @ts-expect-error Internal field.
dom.__lexicalListType = this.__listType;
$setListThemeClassNames(dom, config.theme, this);
return dom;
}
updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean {
if (
prevNode.__tag !== this.__tag ||
prevNode.__listType !== this.__listType
) {
return true;
}
$setListThemeClassNames(dom, config.theme, this);
if (prevNode.__start !== this.__start) {
dom.setAttribute('start', String(this.__start));
}
return false;
}
updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedListNode>): this {
return super
.updateFromJSON(serializedNode)
.setListType(serializedNode.listType)
.setStart(serializedNode.start);
}
exportDOM(editor: LexicalEditor): DOMExportOutput {
const element = this.createDOM(editor._config, editor);
if (isHTMLElement(element)) {
if (this.__start !== 1) {
element.setAttribute('start', String(this.__start));
}
if (this.__listType === 'check') {
element.setAttribute('__lexicalListType', 'check');
}
}
return {
element,
};
}
exportJSON(): SerializedListNode {
return {
...super.exportJSON(),
listType: this.getListType(),
start: this.getStart(),
tag: this.getTag(),
};
}
canBeEmpty(): false {
return false;
}
canIndent(): false {
return false;
}
splice(
start: number,
deleteCount: number,
nodesToInsert: LexicalNode[],
): this {
let listItemNodesToInsert = nodesToInsert;
for (let i = 0; i < nodesToInsert.length; i++) {
const node = nodesToInsert[i];
if (!$isListItemNode(node)) {
if (listItemNodesToInsert === nodesToInsert) {
listItemNodesToInsert = [...nodesToInsert];
}
listItemNodesToInsert[i] = this.createListItemNode().append(
$isElementNode(node) && !($isListNode(node) || node.isInline())
? $createTextNode(node.getTextContent())
: node,
);
}
}
return super.splice(start, deleteCount, listItemNodesToInsert);
}
extractWithChild(child: LexicalNode): boolean {
return $isListItemNode(child);
}
/**
* Create an appropriate ListItemNode to be a child of this ListNode,
* {@link $createListItemNode} is the default implementation.
*
* @returns A new ListItemNode.
*/
createListItemNode(): ListItemNode {
return $createListItemNode();
}
}
function $setListThemeClassNames(
dom: HTMLElement,
editorThemeClasses: EditorThemeClasses,
node: ListNode,
): void {
const classesToAdd = [];
const classesToRemove = [];
const listTheme = editorThemeClasses.list;
if (listTheme !== undefined) {
const listLevelsClassNames = listTheme[`${node.__tag}Depth`] || [];
const listDepth = $getListDepth(node) - 1;
const normalizedListDepth = listDepth % listLevelsClassNames.length;
const listLevelClassName = listLevelsClassNames[normalizedListDepth];
const listClassName = listTheme[node.__tag];
let nestedListClassName;
const nestedListTheme = listTheme.nested;
const checklistClassName = listTheme.checklist;
if (nestedListTheme !== undefined && nestedListTheme.list) {
nestedListClassName = nestedListTheme.list;
}
if (listClassName !== undefined) {
classesToAdd.push(listClassName);
}
if (checklistClassName !== undefined && node.__listType === 'check') {
classesToAdd.push(checklistClassName);
}
if (listLevelClassName !== undefined) {
classesToAdd.push(...normalizeClassNames(listLevelClassName));
for (let i = 0; i < listLevelsClassNames.length; i++) {
if (i !== normalizedListDepth) {
classesToRemove.push(node.__tag + i);
}
}
}
if (nestedListClassName !== undefined) {
const nestedListItemClasses = normalizeClassNames(nestedListClassName);
if (listDepth > 1) {
classesToAdd.push(...nestedListItemClasses);
} else {
classesToRemove.push(...nestedListItemClasses);
}
}
}
if (classesToRemove.length > 0) {
removeClassNamesFromElement(dom, ...classesToRemove);
}
if (classesToAdd.length > 0) {
addClassNamesToElement(dom, ...classesToAdd);
}
}
/*
* 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.
*/
function $normalizeChildren(
nodes: LexicalNode[],
listNode: ListNode,
): ListItemNode[] {
const $createWrapperItem = listNode.createListItemNode.bind(listNode);
const normalizedListItems: ListItemNode[] = [];
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if ($isListItemNode(node)) {
normalizedListItems.push(node);
const children = node.getChildren();
if (children.length > 1) {
children.forEach(child => {
if ($isListNode(child)) {
normalizedListItems.push($createWrapperItem().append(child));
}
});
}
} else {
normalizedListItems.push($createWrapperItem().append(node));
}
}
return normalizedListItems;
}
function isDomChecklist(domNode: HTMLElement) {
if (
domNode.getAttribute('__lexicallisttype') === 'check' ||
// is github checklist
domNode.classList.contains('contains-task-list') ||
// is joplin checklist
domNode.getAttribute('data-is-checklist') === '1'
) {
return true;
}
// if children are checklist items, the node is a checklist ul. Applicable for googledoc checklist pasting.
for (const child of domNode.childNodes) {
if (isHTMLElement(child) && child.hasAttribute('aria-checked')) {
return true;
}
}
return false;
}
function isHTMLOListElement(node: unknown): node is HTMLOListElement {
return isHTMLElement(node) && node.nodeName.toLowerCase() === 'ol';
}
function $convertListNode(
domNode: HTMLOListElement | HTMLUListElement,
): DOMConversionOutput {
let node: ListNode;
if (isHTMLOListElement(domNode)) {
const start = domNode.start;
node = $createListNode('number', start);
} else if (isDomChecklist(domNode)) {
node = $createListNode('check');
} else {
node = $createListNode('bullet');
}
$setDirectionFromDOM(node, domNode);
return {
after: children => $normalizeChildren(children, node),
node,
};
}
const TAG_TO_LIST_TYPE: Record<string, ListType> = {
ol: 'number',
ul: 'bullet',
};
/**
* Creates a ListNode of listType.
* @param listType - The type of list to be created. Can be 'number', 'bullet', or 'check'.
* @param start - Where an ordered list starts its count, start = 1 if left undefined.
* @returns The new ListNode
*/
export function $createListNode(
listType: ListType = 'number',
start = 1,
): ListNode {
return $applyNodeReplacement(new ListNode(listType, start));
}
/**
* Checks to see if the node is a ListNode.
* @param node - The node to be checked.
* @returns true if the node is a ListNode, false otherwise.
*/
export function $isListNode(
node: LexicalNode | null | undefined,
): node is ListNode {
return node instanceof ListNode;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {ChildSchema, DOMImportContext} from '@lexical/html';
import {
CoreImportExtension,
defineImportRule,
DOMImportExtension,
isElementOfTag,
sel,
} from '@lexical/html';
import {
$isParagraphNode,
$setDirectionFromDOM,
$setFormatFromDOM,
configExtension,
defineExtension,
type LexicalNode,
} from 'lexical';
import {ListExtension} from './LexicalListExtension';
import {
$createListItemNode,
$isListItemNode,
type ListItemNode,
} from './LexicalListItemNode';
import {$createListNode, $isListNode} from './LexicalListNode';
/**
* Mirrors the legacy `isDomChecklist` heuristic from
* `@lexical/list`.
*/
function isDomChecklist(domNode: HTMLElement): boolean {
return (
domNode.matches(
'[__lexicallisttype="check"], .contains-task-list, [data-is-checklist="1"]',
) || domNode.querySelector(':scope > [aria-checked]') !== null
);
}
/**
* Lift nested `ListNode`s out of `ListItemNode`s into sibling
* `ListItemNode`s (the legacy `$normalizeChildren` shape). Also wraps any
* non-`ListItemNode` children in a new `ListItemNode`.
*/
function $normalizeListChildren(children: LexicalNode[]): ListItemNode[] {
const out: ListItemNode[] = [];
for (const child of children) {
if ($isListItemNode(child)) {
out.push(child);
const innerChildren = child.getChildren();
if (innerChildren.length > 1) {
for (const inner of innerChildren) {
if ($isListNode(inner)) {
out.push($createListItemNode().append(inner));
}
}
}
} else {
out.push($createListItemNode().append(child));
}
}
return out;
}
const ListRule = defineImportRule({
$import: (ctx, el) => {
let node;
if (isElementOfTag(el, 'ol')) {
node = $createListNode('number', el.start);
} else if (isDomChecklist(el)) {
node = $createListNode('check');
} else {
node = $createListNode('bullet');
}
$setDirectionFromDOM(node, el);
return [node.splice(0, 0, $normalizeListChildren(ctx.$importChildren(el)))];
},
match: sel.tag('ol', 'ul'),
name: '@lexical/list/list',
});
/**
* Apply formatting from the first child paragraph of `<li>` to the list
* item itself, then unwrap that paragraph (Google Docs sets the alignment
* of the `<p>` inside the `<li>`). Mirrors the legacy
* `setFormatFromChildren`.
*/
function $liftFormatFromSingleParagraph(
listItemNode: ListItemNode,
children: LexicalNode[],
): LexicalNode[] {
if (children.length !== 1) {
return children;
}
const firstChild = children[0];
if (
$isParagraphNode(firstChild) &&
!listItemNode.getFormatType() &&
firstChild.getFormatType()
) {
listItemNode.setFormat(firstChild.getFormatType());
return firstChild.getChildren();
}
return children;
}
const ListItemRule = defineImportRule({
$import: (ctx, el) => {
const ariaChecked = el.getAttribute('aria-checked');
const checked =
ariaChecked === 'true'
? true
: ariaChecked === 'false'
? false
: undefined;
const node = $createListItemNode(checked);
$setFormatFromDOM(node, el);
$setDirectionFromDOM(node, el);
return [
node.splice(
0,
0,
$liftFormatFromSingleParagraph(node, ctx.$importChildren(el)),
),
];
},
match: sel.tag('li'),
name: '@lexical/list/li',
});
function $buildChecklistItem(
ctx: DOMImportContext,
el: HTMLElement,
checkboxOwner: Element,
): LexicalNode[] {
const checkboxInput = isElementOfTag(checkboxOwner, 'input')
? checkboxOwner
: checkboxOwner.querySelector<HTMLInputElement>('input[type="checkbox"]');
if (!checkboxInput || checkboxInput.getAttribute('type') !== 'checkbox') {
return [];
}
const checked = checkboxInput.hasAttribute('checked');
const node = $createListItemNode(checked);
$setFormatFromDOM(node, el);
$setDirectionFromDOM(node, el);
return [
node.splice(
0,
0,
$liftFormatFromSingleParagraph(node, ctx.$importChildren(el)),
),
];
}
const TaskListItemRule = defineImportRule({
$import: (ctx, el, $next) => {
const input = el.querySelector(':scope > input[type="checkbox"]');
if (!input) {
return $next();
}
return $buildChecklistItem(ctx, el, input);
},
match: sel.tag('li').classAll('task-list-item'),
name: '@lexical/list/li-task-list-item',
});
const JoplinChecklistItemRule = defineImportRule({
$import: (ctx, el, $next) => {
const wrapper = el.querySelector(':scope > .checkbox-wrapper');
if (!wrapper) {
return $next();
}
const input = wrapper.querySelector(':scope > input[type="checkbox"]');
if (!input) {
return $next();
}
return $buildChecklistItem(ctx, el, input);
},
match: sel.tag('li').classAll('joplin-checkbox'),
name: '@lexical/list/li-joplin-checkbox',
});
/**
* A {@link ChildSchema} that enforces ListNode invariants: only
* `ListItemNode` and (immediately-nested) `ListNode` children are
* accepted; runs of other children get wrapped in a fresh
* `ListItemNode`.
*
* @experimental
*/
export const ListSchema: ChildSchema = {
$accepts: child => $isListItemNode(child) || $isListNode(child),
// Inline runs inside a `<ul>`/`<ol>` (e.g. text between two `<li>`s)
// become the children of a synthetic `ListItemNode`. `ListItemNode`
// is itself a block-level container of inlines, so no intermediate
// `ParagraphNode` is needed (and the demoted-paragraph normalization
// would strip one anyway).
$packageRun: run => [$createListItemNode().splice(0, 0, run)],
name: 'ListSchema',
};
/**
* Import rules for {@link ListNode} and {@link ListItemNode}, including
* GitHub task-list and Joplin checkbox heuristics.
*
* @experimental
*/
export const ListImportRules = [
// More specific rules (class-restricted) must precede the generic `li`
// rule so they win the dispatch race (lower array index = higher
// priority).
TaskListItemRule,
JoplinChecklistItemRule,
ListRule,
ListItemRule,
];
/**
* Bundles {@link ListImportRules} (plus {@link CoreImportExtension}) into
* a single dependency.
*
* @experimental
*/
export const ListImportExtension = defineExtension({
dependencies: [
CoreImportExtension,
ListExtension,
configExtension(DOMImportExtension, {rules: ListImportRules}),
],
name: '@lexical/list/Import',
});
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalCommand, LexicalEditor, NodeKey} from 'lexical';
import {$findMatchingParent, mergeRegister} from '@lexical/utils';
import {
$getNodeByKey,
$getSelection,
$isRangeSelection,
$isTextNode,
COMMAND_PRIORITY_LOW,
createCommand,
INSERT_PARAGRAPH_COMMAND,
TextNode,
} from 'lexical';
import {
$handleListInsertParagraph,
$insertList,
$removeList,
updateChildrenListItemValue,
} from './formatList';
import {$isListItemNode, ListItemNode} from './LexicalListItemNode';
import {$isListNode, ListNode} from './LexicalListNode';
import {$getListDepth} from './utils';
export const UPDATE_LIST_START_COMMAND: LexicalCommand<{
listNodeKey: NodeKey;
newStart: number;
}> = createCommand('UPDATE_LIST_START_COMMAND');
export const INSERT_UNORDERED_LIST_COMMAND: LexicalCommand<void> =
createCommand('INSERT_UNORDERED_LIST_COMMAND');
export const INSERT_ORDERED_LIST_COMMAND: LexicalCommand<void> = createCommand(
'INSERT_ORDERED_LIST_COMMAND',
);
export const REMOVE_LIST_COMMAND: LexicalCommand<void> = createCommand(
'REMOVE_LIST_COMMAND',
);
export interface RegisterListOptions {
restoreNumbering?: boolean;
}
export function registerList(
editor: LexicalEditor,
options?: RegisterListOptions,
): () => void {
const removeListener = mergeRegister(
editor.registerCommand(
INSERT_ORDERED_LIST_COMMAND,
() => {
$insertList('number');
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
UPDATE_LIST_START_COMMAND,
payload => {
const {listNodeKey, newStart} = payload;
const listNode = $getNodeByKey(listNodeKey);
if (!$isListNode(listNode)) {
return false;
}
if (listNode.getListType() === 'number') {
listNode.setStart(newStart);
updateChildrenListItemValue(listNode);
}
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
INSERT_UNORDERED_LIST_COMMAND,
() => {
$insertList('bullet');
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
REMOVE_LIST_COMMAND,
() => {
$removeList();
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
INSERT_PARAGRAPH_COMMAND,
() => {
const shouldRestore = options && options.restoreNumbering;
return $handleListInsertParagraph(!!shouldRestore);
},
COMMAND_PRIORITY_LOW,
),
editor.registerNodeTransform(ListItemNode, node => {
const firstChild = node.getFirstChild();
if (firstChild) {
if ($isTextNode(firstChild)) {
const style = firstChild.getStyle();
const format = firstChild.getFormat();
if (node.getTextStyle() !== style) {
node.setTextStyle(style);
}
if (node.getTextFormat() !== format) {
node.setTextFormat(format);
}
}
} else {
// If it's empty, check the selection
const selection = $getSelection();
if (
$isRangeSelection(selection) &&
(selection.style !== node.getTextStyle() ||
selection.format !== node.getTextFormat()) &&
selection.isCollapsed() &&
node.is(selection.anchor.getNode())
) {
node.setTextStyle(selection.style).setTextFormat(selection.format);
}
}
}),
editor.registerNodeTransform(TextNode, node => {
const listItemParentNode = node.getParent();
if (
$isListItemNode(listItemParentNode) &&
node.is(listItemParentNode.getFirstChild())
) {
const style = node.getStyle();
const format = node.getFormat();
if (
style !== listItemParentNode.getTextStyle() ||
format !== listItemParentNode.getTextFormat()
) {
listItemParentNode.setTextStyle(style).setTextFormat(format);
}
}
}),
);
return removeListener;
}
export function registerListStrictIndentTransform(
editor: LexicalEditor,
): () => void {
const $formatListIndentStrict = (listItemNode: ListItemNode): void => {
const listNode = listItemNode.getParent();
if ($isListNode(listItemNode.getFirstChild()) || !$isListNode(listNode)) {
return;
}
const startingListItemNode = $findMatchingParent(
listItemNode,
node =>
$isListItemNode(node) &&
$isListNode(node.getParent()) &&
$isListItemNode(node.getPreviousSibling()),
);
if (startingListItemNode === null && listItemNode.getIndent() > 0) {
listItemNode.setIndent(0);
} else if ($isListItemNode(startingListItemNode)) {
const prevListItemNode = startingListItemNode.getPreviousSibling();
if ($isListItemNode(prevListItemNode)) {
const endListItemNode = $findChildrenEndListItemNode(prevListItemNode);
const endListNode = endListItemNode.getParent();
if ($isListNode(endListNode)) {
const prevDepth = $getListDepth(endListNode);
const depth = $getListDepth(listNode);
if (prevDepth + 1 < depth) {
listItemNode.setIndent(prevDepth);
}
}
}
}
};
const $processListWithStrictIndent = (listNode: ListNode): void => {
const queue: ListNode[] = [listNode];
while (queue.length > 0) {
const node = queue.shift();
if (!$isListNode(node)) {
continue;
}
for (const child of node.getChildren()) {
if ($isListItemNode(child)) {
$formatListIndentStrict(child);
const firstChild = child.getFirstChild();
if ($isListNode(firstChild)) {
queue.push(firstChild);
}
}
}
}
};
return editor.registerNodeTransform(ListNode, $processListWithStrictIndent);
}
function $findChildrenEndListItemNode(
listItemNode: ListItemNode,
): ListItemNode {
let current = listItemNode;
let firstChild = current.getFirstChild();
while ($isListNode(firstChild)) {
const lastChild = firstChild.getLastChild();
if ($isListItemNode(lastChild)) {
current = lastChild;
firstChild = current.getFirstChild();
} else {
break;
}
}
return current;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {LexicalNode, Spread} from 'lexical';
import invariant from '@lexical/internal/invariant';
import {$findMatchingParent} from '@lexical/utils';
import {$isListItemNode, $isListNode, ListItemNode, ListNode} from './';
/**
* Checks the depth of listNode from the root node.
* @param listNode - The ListNode to be checked.
* @returns The depth of the ListNode.
*/
export function $getListDepth(listNode: ListNode): number {
let depth = 1;
let parent = listNode.getParent();
while (parent != null) {
if ($isListItemNode(parent)) {
const parentList = parent.getParent();
if ($isListNode(parentList)) {
depth++;
parent = parentList.getParent();
continue;
}
invariant(false, 'A ListItemNode must have a ListNode for a parent.');
}
return depth;
}
return depth;
}
/**
* Finds the nearest ancestral ListNode and returns it, throws an invariant if listItem is not a ListItemNode.
* @param listItem - The node to be checked.
* @returns The ListNode found.
*/
export function $getTopListNode(listItem: LexicalNode): ListNode {
let list = listItem.getParent<ListNode>();
if (!$isListNode(list)) {
invariant(false, 'A ListItemNode must have a ListNode for a parent.');
}
let parent: ListNode | null = list;
while (parent !== null) {
parent = parent.getParent();
if ($isListNode(parent)) {
list = parent;
}
}
return list;
}
/**
* Checks if listItem has no child ListNodes and has no ListItemNode ancestors with siblings.
* @param listItem - the ListItemNode to be checked.
* @returns true if listItem has no child ListNode and no ListItemNode ancestors with siblings, false otherwise.
*/
export function $isLastItemInList(listItem: ListItemNode): boolean {
let isLast = true;
const firstChild = listItem.getFirstChild();
if ($isListNode(firstChild)) {
return false;
}
let parent: ListItemNode | null = listItem;
while (parent !== null) {
if ($isListItemNode(parent)) {
if (parent.getNextSiblings().length > 0) {
isLast = false;
}
}
parent = parent.getParent();
}
return isLast;
}
/**
* A recursive Depth-First Search (Postorder Traversal) that finds all of a node's children
* that are of type ListItemNode and returns them in an array.
* @param node - The ListNode to start the search.
* @returns An array containing all nodes of type ListItemNode found.
*/
// This should probably be $getAllChildrenOfType
export function $getAllListItems(node: ListNode): Array<ListItemNode> {
let listItemNodes: Array<ListItemNode> = [];
const listChildren: Array<ListItemNode> = node
.getChildren()
.filter($isListItemNode);
for (let i = 0; i < listChildren.length; i++) {
const listItemNode = listChildren[i];
const firstChild = listItemNode.getFirstChild();
if ($isListNode(firstChild)) {
listItemNodes = listItemNodes.concat($getAllListItems(firstChild));
} else {
listItemNodes.push(listItemNode);
}
}
return listItemNodes;
}
const NestedListNodeBrand: unique symbol = Symbol.for(
'@lexical/NestedListNodeBrand',
);
/**
* Checks to see if the passed node is a ListItemNode and has a ListNode as a child.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode and has a ListNode child, false otherwise.
*/
export function isNestedListNode(
node: LexicalNode | null | undefined,
): node is Spread<
{getFirstChild(): ListNode; [NestedListNodeBrand]: never},
ListItemNode
> {
return $isListItemNode(node) && $isListNode(node.getFirstChild());
}
/**
* Traverses up the tree and returns the first ListItemNode found.
* @param node - Node to start the search.
* @returns The first ListItemNode found, or null if none exist.
*/
export function $findNearestListItemNode(
node: LexicalNode,
): ListItemNode | null {
const matchingParent = $findMatchingParent(node, parent =>
$isListItemNode(parent),
);
return matchingParent as ListItemNode | null;
}
/**
* Takes a deeply nested ListNode or ListItemNode and traverses up the branch to delete the first
* ancestral ListNode (which could be the root ListNode) or ListItemNode with siblings, essentially
* bringing the deeply nested node up the branch once. Would remove sublist if it has siblings.
* Should not break ListItem -> List -> ListItem chain as empty List/ItemNodes should be removed on .remove().
* @param sublist - The nested ListNode or ListItemNode to be brought up the branch.
*/
export function $removeHighestEmptyListParent(
sublist: ListItemNode | ListNode,
) {
// Nodes may be repeatedly indented, to create deeply nested lists that each
// contain just one bullet.
// Our goal is to remove these (empty) deeply nested lists. The easiest
// way to do that is crawl back up the tree until we find a node that has siblings
// (e.g. is actually part of the list contents) and delete that, or delete
// the root of the list (if no list nodes have siblings.)
let emptyListPtr = sublist;
while (
emptyListPtr.getNextSibling() == null &&
emptyListPtr.getPreviousSibling() == null
) {
const parent = emptyListPtr.getParent();
if (parent == null || !($isListItemNode(parent) || $isListNode(parent))) {
break;
}
emptyListPtr = parent;
}
emptyListPtr.remove();
}
/**
* Calculates the start value for a new list created by splitting an existing list.
*/
export function $getNewListStart(
list: ListNode,
listItem: ListItemNode,
): number {
return list.getStart() + listItem.getIndexWithinParent();
}
+33
-17

@@ -11,9 +11,11 @@ {

"license": "MIT",
"version": "0.44.1-nightly.20260519.0",
"main": "LexicalList.js",
"types": "index.d.ts",
"version": "0.45.0",
"main": "./dist/LexicalList.js",
"types": "./dist/index.d.ts",
"dependencies": {
"@lexical/extension": "0.44.1-nightly.20260519.0",
"@lexical/utils": "0.44.1-nightly.20260519.0",
"lexical": "0.44.1-nightly.20260519.0"
"@lexical/extension": "0.45.0",
"@lexical/internal": "0.45.0",
"lexical": "0.45.0",
"@lexical/utils": "0.45.0",
"@lexical/html": "0.45.0"
},

@@ -25,21 +27,35 @@ "repository": {

},
"module": "LexicalList.mjs",
"module": "./dist/LexicalList.mjs",
"sideEffects": false,
"exports": {
".": {
"source": "./src/index.ts",
"import": {
"types": "./index.d.ts",
"development": "./LexicalList.dev.mjs",
"production": "./LexicalList.prod.mjs",
"node": "./LexicalList.node.mjs",
"default": "./LexicalList.mjs"
"types": "./dist/index.d.ts",
"development": "./dist/LexicalList.dev.mjs",
"production": "./dist/LexicalList.prod.mjs",
"node": "./dist/LexicalList.node.mjs",
"default": "./dist/LexicalList.mjs"
},
"require": {
"types": "./index.d.ts",
"development": "./LexicalList.dev.js",
"production": "./LexicalList.prod.js",
"default": "./LexicalList.js"
"types": "./dist/index.d.ts",
"development": "./dist/LexicalList.dev.js",
"production": "./dist/LexicalList.prod.js",
"default": "./dist/LexicalList.js"
}
}
}
},
"files": [
"dist",
"src",
"!src/__tests__",
"!src/__bench__",
"!src/__mocks__",
"!src/**/*.test.ts",
"!src/**/*.test.tsx",
"!src/**/*.bench.ts",
"!src/**/*.bench.tsx",
"README.md",
"LICENSE"
]
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalCommand, LexicalEditor } from 'lexical';
import { Signal } from '@lexical/extension';
export declare const INSERT_CHECK_LIST_COMMAND: LexicalCommand<void>;
/**
* Registers the checklist plugin with the editor.
* @param editor The LexicalEditor instance.
* @param options Optional configuration.
* - disableTakeFocusOnClick: If true, clicking a checklist item will not focus the editor (useful for mobile).
*/
export declare function registerCheckList(editor: LexicalEditor, options?: {
disableTakeFocusOnClick?: boolean | Signal<boolean>;
}): () => void;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { ListItemNode, ListNode } from './';
import { ListType } from './LexicalListNode';
/**
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export declare function $insertList(listType: ListType): void;
/**
* A recursive function that goes through each list and their children, including nested lists,
* appending list2 children after list1 children and updating ListItemNode values.
* @param list1 - The first list to be merged.
* @param list2 - The second list to be merged.
*/
export declare function mergeLists(list1: ListNode, list2: ListNode): void;
/**
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
*/
export declare function $removeList(): void;
/**
* Takes the value of a child ListItemNode and makes it the value the ListItemNode
* 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.
*/
export declare function updateChildrenListItemValue(list: ListNode): void;
/**
* Merge the next sibling list if same type.
* <ul> will merge with <ul>, but NOT <ul> with <ol>.
* @param list - The list whose next sibling should be potentially merged
*/
export declare function mergeNextSiblingListIfSameType(list: ListNode): void;
/**
* Adds an empty ListNode/ListItemNode chain at listItemNode, so as to
* create an indent effect. Won't indent ListItemNodes that have a ListNode as
* a child, but does merge sibling ListItemNodes if one has a nested ListNode.
* @param listItemNode - The ListItemNode to be indented.
*/
export declare function $handleIndent(listItemNode: ListItemNode): void;
/**
* Removes an indent by removing an empty ListNode/ListItemNode chain. An indented ListItemNode
* has a great grandparent node of type ListNode, which is where the ListItemNode will reside
* within as a child.
* @param listItemNode - The ListItemNode to remove the indent (outdent).
*/
export declare function $handleOutdent(listItemNode: ListItemNode): void;
/**
* Attempts to insert a ParagraphNode at selection and selects the new node. The selection must contain a ListItemNode
* or a node that does not already contain text. If its grandparent is the root/shadow root, it will get the ListNode
* (which should be the parent node) and insert the ParagraphNode as a sibling to the ListNode. If the ListNode is
* nested in a ListItemNode instead, it will add the ParagraphNode after the grandparent ListItemNode.
* Throws an invariant if the selection is not a child of a ListNode.
* @returns true if a ParagraphNode was inserted successfully, false if there is no selection
* or the selection does not contain a ListItemNode or the node already holds text.
*/
export declare function $handleListInsertParagraph(restoreNumbering?: boolean): boolean;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { SerializedListItemNode } from './LexicalListItemNode';
import type { ListNodeTagType, ListType, SerializedListNode } from './LexicalListNode';
import type { LexicalCommand, LexicalEditor, NodeKey } from 'lexical';
import { INSERT_CHECK_LIST_COMMAND, registerCheckList } from './checkList';
import { $handleListInsertParagraph, $insertList, $removeList } from './formatList';
import { $createListItemNode, $isListItemNode, ListItemNode } from './LexicalListItemNode';
import { $createListNode, $isListNode, ListNode } from './LexicalListNode';
import { $getListDepth } from './utils';
export { $createListItemNode, $createListNode, $getListDepth, $handleListInsertParagraph, $insertList, $isListItemNode, $isListNode, $removeList, INSERT_CHECK_LIST_COMMAND, ListItemNode, ListNode, ListNodeTagType, ListType, registerCheckList, SerializedListItemNode, SerializedListNode, };
export declare const UPDATE_LIST_START_COMMAND: LexicalCommand<{
listNodeKey: NodeKey;
newStart: number;
}>;
export declare const INSERT_UNORDERED_LIST_COMMAND: LexicalCommand<void>;
export declare const INSERT_ORDERED_LIST_COMMAND: LexicalCommand<void>;
export declare const REMOVE_LIST_COMMAND: LexicalCommand<void>;
export interface RegisterListOptions {
restoreNumbering?: boolean;
}
export declare function registerList(editor: LexicalEditor, options?: RegisterListOptions): () => void;
export declare function registerListStrictIndentTransform(editor: LexicalEditor): () => void;
/**
* @deprecated use {@link $insertList} from an update or command listener.
*
* 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.
* Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children.
* If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode,
* unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with
* a new ListNode, or create a new ListNode at the nearest root/shadow root.
* @param editor - The lexical editor.
* @param listType - The type of list, "number" | "bullet" | "check".
*/
export declare function insertList(editor: LexicalEditor, listType: ListType): void;
/**
* @deprecated use {@link $removeList} from an update or command listener.
*
* Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode
* it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode,
* removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node
* inside a ListItemNode will be appended to the new ParagraphNodes.
* @param editor - The lexical editor.
*/
export declare function removeList(editor: LexicalEditor): void;
export interface ListConfig {
/**
* When `true`, enforces strict indentation rules for list items, ensuring consistent structure.
* When `false` (default), indentation is more flexible.
*/
hasStrictIndent: boolean;
shouldPreserveNumbering: boolean;
}
/**
* Configures {@link ListNode}, {@link ListItemNode} and registers
* the strict indent transform if `hasStrictIndent` is true (default false).
*/
export declare const ListExtension: import("lexical").LexicalExtension<ListConfig, "@lexical/list/List", import("@lexical/extension").NamedSignalsOutput<ListConfig>, unknown>;
export interface CheckListConfig {
disableTakeFocusOnClick: boolean;
}
/**
* Registers checklist functionality for {@link ListNode} and
* {@link ListItemNode} with a
* {@link INSERT_CHECK_LIST_COMMAND} listener and
* the expected keyboard and mouse interactions for
* checkboxes.
*/
export declare const CheckListExtension: import("lexical").LexicalExtension<CheckListConfig, "@lexical/list/CheckList", import("@lexical/extension").NamedSignalsOutput<CheckListConfig>, unknown>;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict'
const LexicalList = process.env.NODE_ENV !== 'production' ? require('./LexicalList.dev.js') : require('./LexicalList.prod.js');
module.exports = LexicalList;

Sorry, the diff of this file is not supported yet

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import * as modDev from './LexicalList.dev.mjs';
import * as modProd from './LexicalList.prod.mjs';
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
export const $createListItemNode = mod.$createListItemNode;
export const $createListNode = mod.$createListNode;
export const $getListDepth = mod.$getListDepth;
export const $handleListInsertParagraph = mod.$handleListInsertParagraph;
export const $insertList = mod.$insertList;
export const $isListItemNode = mod.$isListItemNode;
export const $isListNode = mod.$isListNode;
export const $removeList = mod.$removeList;
export const CheckListExtension = mod.CheckListExtension;
export const INSERT_CHECK_LIST_COMMAND = mod.INSERT_CHECK_LIST_COMMAND;
export const INSERT_ORDERED_LIST_COMMAND = mod.INSERT_ORDERED_LIST_COMMAND;
export const INSERT_UNORDERED_LIST_COMMAND = mod.INSERT_UNORDERED_LIST_COMMAND;
export const ListExtension = mod.ListExtension;
export const ListItemNode = mod.ListItemNode;
export const ListNode = mod.ListNode;
export const REMOVE_LIST_COMMAND = mod.REMOVE_LIST_COMMAND;
export const UPDATE_LIST_START_COMMAND = mod.UPDATE_LIST_START_COMMAND;
export const insertList = mod.insertList;
export const registerCheckList = mod.registerCheckList;
export const registerList = mod.registerList;
export const registerListStrictIndentTransform = mod.registerListStrictIndentTransform;
export const removeList = mod.removeList;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalList.dev.mjs') : import('./LexicalList.prod.mjs'));
export const $createListItemNode = mod.$createListItemNode;
export const $createListNode = mod.$createListNode;
export const $getListDepth = mod.$getListDepth;
export const $handleListInsertParagraph = mod.$handleListInsertParagraph;
export const $insertList = mod.$insertList;
export const $isListItemNode = mod.$isListItemNode;
export const $isListNode = mod.$isListNode;
export const $removeList = mod.$removeList;
export const CheckListExtension = mod.CheckListExtension;
export const INSERT_CHECK_LIST_COMMAND = mod.INSERT_CHECK_LIST_COMMAND;
export const INSERT_ORDERED_LIST_COMMAND = mod.INSERT_ORDERED_LIST_COMMAND;
export const INSERT_UNORDERED_LIST_COMMAND = mod.INSERT_UNORDERED_LIST_COMMAND;
export const ListExtension = mod.ListExtension;
export const ListItemNode = mod.ListItemNode;
export const ListNode = mod.ListNode;
export const REMOVE_LIST_COMMAND = mod.REMOVE_LIST_COMMAND;
export const UPDATE_LIST_START_COMMAND = mod.UPDATE_LIST_START_COMMAND;
export const insertList = mod.insertList;
export const registerCheckList = mod.registerCheckList;
export const registerList = mod.registerList;
export const registerListStrictIndentTransform = mod.registerListStrictIndentTransform;
export const removeList = mod.removeList;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
"use strict";var e=require("@lexical/extension"),t=require("@lexical/utils"),n=require("lexical");function r(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function i(e){let t=1,n=e.getParent();for(;null!=n;){if(L(n)){const e=n.getParent();if($(e)){t++,n=e.getParent();continue}r(40)}return t}return t}function s(e){let t=e.getParent();$(t)||r(40);let n=t;for(;null!==n;)n=n.getParent(),$(n)&&(t=n);return t}function o(e){let t=[];const n=e.getChildren().filter(L);for(let e=0;e<n.length;e++){const r=n[e],i=r.getFirstChild();$(i)?t=t.concat(o(i)):t.push(r)}return t}function l(e){return L(e)&&$(e.getFirstChild())}function a(e,t){return L(e)&&(0===t.length||1===t.length&&e.is(t[0])&&0===e.getChildrenSize())}function c(e){const t=n.$getSelection();if(null!==t){let r=t.getNodes();if(n.$isRangeSelection(t)){const[i]=t.getStartEndPoints(),s=i.getNode(),o=s.getParent();if(n.$isRootOrShadowRoot(s)){const e=s.getFirstChild();if(e)r=e.selectStart().getNodes();else{const e=n.$createParagraphNode();s.append(e),r=e.select().getNodes()}}else if(a(s,r)){const t=M(e);if(n.$isRootOrShadowRoot(o)){s.replace(t);const e=y();n.$isElementNode(s)&&(e.setFormat(s.getFormatType()),e.setIndent(s.getIndent())),t.append(e)}else if(L(s)){const e=s.getParentOrThrow();d(t,e.getChildren()),e.replace(t)}return}}const i=new Set;for(let t=0;t<r.length;t++){const s=r[t];if(n.$isElementNode(s)&&s.isEmpty()&&!L(s)&&!i.has(s.getKey())){g(s,e);continue}let o=n.$isLeafNode(s)?s.getParent():L(s)&&s.isEmpty()?s:null;for(;null!=o;){const t=o.getKey();if($(o)){if(!i.has(t)){const n=M(e);d(n,o.getChildren()),o.replace(n),i.add(t)}break}{const r=o.getParent();if(n.$isRootOrShadowRoot(r)&&!i.has(t)){i.add(t),g(o,e);break}o=r}}}}}function d(e,t){e.splice(e.getChildrenSize(),0,t)}function g(e,t){if($(e))return e;const r=e.getPreviousSibling(),i=e.getNextSibling(),s=y();let o;if(d(s,e.getChildren()),$(r)&&t===r.getListType())r.append(s),$(i)&&t===i.getListType()&&(d(r,i.getChildren()),i.remove()),o=r;else if($(i)&&t===i.getListType())i.getFirstChildOrThrow().insertBefore(s),o=i;else{const n=M(t);n.append(s),e.replace(n),o=n}s.setFormat(e.getFormatType()),s.setIndent(e.getIndent());const l=n.$getSelection();return n.$isRangeSelection(l)&&(o.getKey()===l.anchor.key&&l.anchor.set(s.getKey(),l.anchor.offset,"element"),o.getKey()===l.focus.key&&l.focus.set(s.getKey(),l.focus.offset,"element")),e.remove(),o}function u(e,t){const n=e.getLastChild(),r=t.getFirstChild();n&&r&&l(n)&&l(r)&&(u(n.getFirstChild(),r.getFirstChild()),r.remove());const i=t.getChildren();i.length>0&&e.append(...i),t.remove()}function h(){const e=n.$getSelection();if(n.$isRangeSelection(e)){const r=new Set,i=e.getNodes(),l=e.anchor.getNode();if(a(l,i))r.add(s(l));else for(let e=0;e<i.length;e++){const o=i[e];if(n.$isLeafNode(o)){const e=t.$getNearestNodeOfType(o,C);null!=e&&r.add(s(e))}}for(const t of r){let r=t;const i=o(t);for(const t of i){const i=n.$createParagraphNode().setTextStyle(e.style).setTextFormat(e.format);d(i,t.getChildren()),r.insertAfter(i),r=i,t.__key===e.anchor.key&&n.$setPointFromCaret(e.anchor,n.$normalizeCaret(n.$getChildCaret(i,"next"))),t.__key===e.focus.key&&n.$setPointFromCaret(e.focus,n.$normalizeCaret(n.$getChildCaret(i,"next"))),t.remove()}t.remove()}}}function f(e){const t="check"!==e.getListType();let n=e.getStart();for(const r of e.getChildren())L(r)&&(r.getValue()!==n&&r.setValue(n),t&&null!=r.getLatest().__checked&&r.setChecked(void 0),$(r.getFirstChild())||n++)}function p(e){const t=new Set;if(l(e)||t.has(e.getKey()))return;const r=e.getParent(),i=e.getNextSibling(),s=e.getPreviousSibling();if(l(i)&&l(s)){const n=s.getFirstChild();if($(n)){n.append(e);const r=i.getFirstChild();if($(r)){d(n,r.getChildren()),i.remove(),t.add(i.getKey())}}}else if(l(i)){const t=i.getFirstChild();if($(t)){const n=t.getFirstChild();null!==n&&n.insertBefore(e)}}else if(l(s)){const t=s.getFirstChild();$(t)&&t.append(e)}else if($(r)){const t=n.$copyNode(e),o=n.$copyNode(r);t.append(o),o.append(e),s?s.insertAfter(t):i?i.insertBefore(t):r.append(t)}}function m(e){if(l(e))return;const t=e.getParent(),r=t?t.getParent():void 0;if($(r?r.getParent():void 0)&&L(r)&&$(t)){const i=t?t.getFirstChild():void 0,s=t?t.getLastChild():void 0;if(e.is(i))r.insertBefore(e),t.isEmpty()&&r.remove();else if(e.is(s))r.insertAfter(e),t.isEmpty()&&r.remove();else{const i=n.$copyNode(e),s=n.$copyNode(t);i.append(s),e.getPreviousSiblings().forEach(e=>s.append(e));const o=n.$copyNode(e),l=n.$copyNode(t);o.append(l),d(l,e.getNextSiblings()),r.insertBefore(i),r.insertAfter(o),r.replace(e)}}}function _(e=!1){const t=n.$getSelection();if(!n.$isRangeSelection(t)||!t.isCollapsed())return!1;const i=t.anchor.getNode();let o=null;if(L(i)&&0===i.getChildrenSize())o=i;else if(n.$isTextNode(i)){const e=i.getParent();L(e)&&e.getChildren().every(e=>n.$isTextNode(e)&&""===e.getTextContent().trim())&&(o=e)}if(null===o)return!1;const l=s(o),a=o.getParent();$(a)||r(40);const c=a.getParent();let d;if(n.$isRootOrShadowRoot(c))d=n.$createParagraphNode(),l.insertAfter(d);else{if(!L(c))return!1;d=n.$copyNode(c),c.insertAfter(d)}d.setTextStyle(t.style).setTextFormat(t.format).select();const g=o.getNextSiblings();if(g.length>0){const t=e?function(e,t){return e.getStart()+t.getIndexWithinParent()}(a,o):1,r=n.$copyNode(a).setStart(t);if(L(d)){const e=n.$copyNode(d);e.append(r),d.insertAfter(e)}else d.insertAfter(r);r.append(...g)}return function(e){let t=e;for(;null==t.getNextSibling()&&null==t.getPreviousSibling();){const e=t.getParent();if(null==e||!L(e)&&!$(e))break;t=e}t.remove()}(o),!0}class C extends n.ElementNode{__value;__checked;$config(){return this.config("listitem",{$transform:e=>{const i=e.getParent();if($(i))"check"!==i.getListType()&&null!=e.getChecked()&&e.setChecked(void 0);else if(i){const s=e.createParentElementNode();$(s)||r(340);const o=[e];for(const t of["previous","next"]){o.reverse();for(const{origin:r}of n.$getSiblingCaret(e,t)){if(!L(r))break;o.push(r)}}e.insertBefore(s),s.splice(0,0,o),n.$isRootOrShadowRoot(i)||(t.$insertNodeToNearestRootAtCaret(s,n.$rewindSiblingCaret(n.$getSiblingCaret(s,"next")),{$shouldSplit:()=>!1,removeEmptyDestination:!0}),i.isEmpty()&&i.isAttached()&&i.remove())}},extends:n.ElementNode,importDOM:n.buildImportMap({li:()=>({conversion:N,priority:0})})})}constructor(e=1,t=void 0,n){super(n),this.__value=void 0===e?1:e,this.__checked=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__value=e.__value,this.__checked=e.__checked}createDOM(e){const t=document.createElement("li");return this.updateListItemDOM(null,t,e),t}updateListItemDOM(e,r,i){!function(e,t){const n=t.getParent();!$(n)||"check"!==n.getListType()||$(t.getFirstChild())?(e.removeAttribute("role"),e.removeAttribute("tabIndex"),e.removeAttribute("aria-checked")):(e.setAttribute("role","checkbox"),e.setAttribute("tabIndex","-1"),e.setAttribute("aria-checked",t.getChecked()?"true":"false"))}(r,this),r.value=this.__value,function(e,r,i){const s=r.list;if(!s)return;const o=s.listitem,l=s.nested&&s.nested.listitem,a=i.getParent(),c=$(a)&&"check"===a.getListType(),d=i.getChecked(),g=i.getChildren().some(e=>$(e)),u=[];void 0!==s.listitemChecked&&u.push(s.listitemChecked);void 0!==s.listitemUnchecked&&u.push(s.listitemUnchecked);void 0!==l&&u.push(...n.normalizeClassNames(l));u.length>0&&t.removeClassNamesFromElement(e,...u);const h=[];void 0!==o&&h.push(...n.normalizeClassNames(o));if(c){const e=d?s.listitemChecked:s.listitemUnchecked;void 0!==e&&h.push(e)}void 0!==l&&g&&h.push(...n.normalizeClassNames(l));h.length>0&&t.addClassNamesToElement(e,...h)}(r,i.theme,this);const s=e?e.__style:"",o=this.__style;s!==o&&n.setDOMStyleFromCSS(r.style,o,s),function(e,t,r){const i=t.__textStyle,s=r?r.__textStyle:"";if(null!==r&&s===i)return;const o=n.getStyleObjectFromCSS(i);for(const t in o)e.style.setProperty(`--listitem-marker-${t}`,o[t]);if(""!==s)for(const t in n.getStyleObjectFromCSS(s))t in o||e.style.removeProperty(`--listitem-marker-${t}`)}(r,this,e)}updateDOM(e,t,n){const r=t;return this.updateListItemDOM(e,r,n),!1}updateFromJSON(e){return super.updateFromJSON(e).setValue(e.value).setChecked(e.checked)}exportDOM(e){const t=this.createDOM(e._config),r=this.getFormatType();r&&(t.style.textAlign=r);const i=this.getDirection();return i&&(t.dir=i),l(this)?{after(e){if(n.isHTMLElement(e)){const t=e.previousElementSibling;if(n.isHTMLElement(t)&&"LI"===t.nodeName){for(;e.firstChild;)t.append(e.firstChild);e.remove()}}return e},element:t}:{element:t}}exportJSON(){return{...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...e){for(let t=0;t<e.length;t++){const r=e[t];if(n.$isElementNode(r)&&this.canMergeWith(r)){const e=r.getChildren();this.append(...e),r.remove()}else super.append(r)}return this}replace(e,t){if(L(e))return super.replace(e);this.setIndent(0);const i=this.getParentOrThrow();if(!$(i))return e;if(i.__first===this.getKey())i.insertBefore(e);else if(i.__last===this.getKey())i.insertAfter(e);else{const t=n.$copyNode(i);let r=this.getNextSibling();for(;r;){const e=r;r=r.getNextSibling(),t.append(e)}i.insertAfter(e),e.insertAfter(t)}const s=this.__key;let o=0;if(t&&(n.$isElementNode(e)||r(139),o=e.getChildrenSize(),e.splice(o,0,this.getChildren())),t&&n.$isElementNode(e)){const t=n.$getSelection();if(n.$isRangeSelection(t))for(const n of t.getStartEndPoints())n.key===s&&"element"===n.type&&n.set(e.getKey(),o+n.offset,"element")}return this.remove(),0===i.getChildrenSize()&&i.remove(),e}insertAfter(e,t=!0){const i=this.getParentOrThrow();if($(i)||r(39),L(e))return super.insertAfter(e,t);const s=this.getNextSiblings();if(i.insertAfter(e,t),0!==s.length){const r=n.$copyNode(i);s.forEach(e=>r.append(e)),e.insertAfter(r,t)}return e}remove(e){const t=this.getPreviousSibling(),n=this.getNextSibling();super.remove(e),t&&n&&l(t)&&l(n)&&(u(t.getFirstChild(),n.getFirstChild()),n.remove())}resetOnCopyNodeFrom(e){super.resetOnCopyNodeFrom(e),e.getChecked()&&this.setChecked(!1)}insertNewAfter(e,t=!0){const r=n.$copyNode(this);return this.insertAfter(r,t),r}collapseAtStart(e){const t=n.$createParagraphNode();this.getChildren().forEach(e=>t.append(e));const r=this.getParentOrThrow(),i=r.getParentOrThrow(),s=L(i);if(1===r.getChildrenSize())if(s)r.remove(),i.select();else{r.insertBefore(t),r.remove();const n=e.anchor,i=e.focus,s=t.getKey();"element"===n.type&&n.getNode().is(this)&&n.set(s,n.offset,"element"),"element"===i.type&&i.getNode().is(this)&&i.set(s,i.offset,"element")}else r.insertBefore(t),this.remove();return!0}getValue(){return this.getLatest().__value}setValue(e){const t=this.getWritable();return t.__value=e,t}getChecked(){const e=this.getLatest();let t;const n=this.getParent();return $(n)&&(t=n.getListType()),"check"===t?Boolean(e.__checked):void 0}setChecked(e){const t=this.getWritable();return t.__checked=e,t}toggleChecked(){const e=this.getWritable();return e.setChecked(!e.__checked)}getIndent(){const e=this.getParent();if(null===e||!this.isAttached())return this.getLatest().__indent;let t=e.getParentOrThrow(),n=0;for(;L(t);)t=t.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(e){"number"!=typeof e&&r(117),(e=Math.floor(e))>=0||r(199);let t=this.getIndent();for(;t!==e;)t<e?(p(this),t++):(m(this),t--);return this}canInsertAfter(e){return L(e)}canReplaceWith(e){return L(e)}canMergeWith(e){return L(e)||n.$isParagraphNode(e)}extractWithChild(e,t){if(!n.$isRangeSelection(t))return!1;const r=t.anchor.getNode(),i=t.focus.getNode();return this.isParentOf(r)&&this.isParentOf(i)&&this.getTextContent().length===t.getTextContent().length}isParentRequired(){return!0}createParentElementNode(){return M("bullet")}canMergeWhenEmpty(){return!0}}function N(e){if(e.classList.contains("task-list-item"))for(const t of e.children)if("INPUT"===t.tagName)return T(t);if(e.classList.contains("joplin-checkbox"))for(const t of e.children)if(t.classList.contains("checkbox-wrapper")&&t.children.length>0&&"INPUT"===t.children[0].tagName)return T(t.children[0]);const t=e.getAttribute("aria-checked"),r=y("true"===t||"false"!==t&&void 0);return n.$setFormatFromDOM(r,e),{after:S.bind(null,r),node:n.$setDirectionFromDOM(r,e)}}function T(e){if(!("checkbox"===e.getAttribute("type")))return{node:null};const t=y(e.hasAttribute("checked"));return{after:S.bind(null,t),node:t}}function S(e,t){const r=t[0];return 1===t.length&&n.$isParagraphNode(r)&&!e.getFormatType()&&r.getFormatType()?(e.setFormat(r.getFormatType()),r.getChildren()):t}function y(e){return n.$applyNodeReplacement(new C(void 0,e))}function L(e){return e instanceof C}class O extends n.ElementNode{__tag;__start;__listType;$config(){return this.config("list",{$transform:e=>{!function(e){const t=e.getNextSibling();$(t)&&e.getListType()===t.getListType()&&u(e,t)}(e),f(e)},extends:n.ElementNode,importDOM:n.buildImportMap({ol:()=>({conversion:x,priority:0}),ul:()=>({conversion:x,priority:0})})})}constructor(e="number",t=1,n){super(n);const r=E[e]||e;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__listType=e.__listType,this.__tag=e.__tag,this.__start=e.__start}getTag(){return this.getLatest().__tag}setListType(e){const t=this.getWritable();return t.__listType=e,t.__tag="number"===e?"ol":"ul",t}getListType(){return this.getLatest().__listType}getStart(){return this.getLatest().__start}setStart(e){const t=this.getWritable();return t.__start=e,t}createDOM(e,t){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,v(r,e.theme,this),r}updateDOM(e,t,n){return e.__tag!==this.__tag||e.__listType!==this.__listType||(v(t,n.theme,this),e.__start!==this.__start&&t.setAttribute("start",String(this.__start)),!1)}updateFromJSON(e){return super.updateFromJSON(e).setListType(e.listType).setStart(e.start)}exportDOM(e){const n=this.createDOM(e._config,e);return t.isHTMLElement(n)&&(1!==this.__start&&n.setAttribute("start",String(this.__start)),"check"===this.__listType&&n.setAttribute("__lexicalListType","check")),{element:n}}exportJSON(){return{...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return!1}canIndent(){return!1}splice(e,t,r){let i=r;for(let e=0;e<r.length;e++){const t=r[e];L(t)||(i===r&&(i=[...r]),i[e]=this.createListItemNode().append(!n.$isElementNode(t)||$(t)||t.isInline()?t:n.$createTextNode(t.getTextContent())))}return super.splice(e,t,i)}extractWithChild(e){return L(e)}createListItemNode(){return y()}}function v(e,r,s){const o=[],l=[],a=r.list;if(void 0!==a){const e=a[`${s.__tag}Depth`]||[],t=i(s)-1,r=t%e.length,c=e[r],d=a[s.__tag];let g;const u=a.nested,h=a.checklist;if(void 0!==u&&u.list&&(g=u.list),void 0!==d&&o.push(d),void 0!==h&&"check"===s.__listType&&o.push(h),void 0!==c){o.push(...n.normalizeClassNames(c));for(let t=0;t<e.length;t++)t!==r&&l.push(s.__tag+t)}if(void 0!==g){const e=n.normalizeClassNames(g);t>1?o.push(...e):l.push(...e)}}l.length>0&&t.removeClassNamesFromElement(e,...l),o.length>0&&t.addClassNamesToElement(e,...o)}function x(e){let r;if(function(e){return t.isHTMLElement(e)&&"ol"===e.nodeName.toLowerCase()}(e)){const t=e.start;r=M("number",t)}else r=function(e){if("check"===e.getAttribute("__lexicallisttype")||e.classList.contains("contains-task-list")||"1"===e.getAttribute("data-is-checklist"))return!0;for(const n of e.childNodes)if(t.isHTMLElement(n)&&n.hasAttribute("aria-checked"))return!0;return!1}(e)?M("check"):M("bullet");return n.$setDirectionFromDOM(r,e),{after:e=>function(e,t){const n=t.createListItemNode.bind(t),r=[];for(let t=0;t<e.length;t++){const i=e[t];if(L(i)){r.push(i);const e=i.getChildren();e.length>1&&e.forEach(e=>{$(e)&&r.push(n().append(e))})}else r.push(n().append(i))}return r}(e,r),node:r}}const E={ol:"number",ul:"bullet"};function M(e="number",t=1){return n.$applyNodeReplacement(new O(e,t))}function $(e){return e instanceof O}const P=n.createCommand("INSERT_CHECK_LIST_COMMAND");function b(e,r){const i=r&&r.disableTakeFocusOnClick||!1,s="boolean"==typeof i?()=>i:i.peek.bind(i),o=e=>{const n=e.target;if(!t.isHTMLElement(n))return!1;const r=n.__lexicalCheckListLastHandled;return void 0!==r&&e.timeStamp-r<500},l=e=>{const n=e.target;t.isHTMLElement(n)&&(n.__lexicalCheckListLastHandled=e.timeStamp)},a=e=>{o(e)||(l(e),A(e,s()))},d=e=>{"touch"===e.pointerType&&(o(e)||(l(e),A(e,s())))},g=e=>{!function(e,t){k(e,()=>{e.preventDefault(),t&&e.stopPropagation()})}(e,s())};return t.mergeRegister(e.registerCommand(P,()=>(c("check"),!0),n.COMMAND_PRIORITY_LOW),e.registerCommand(n.KEY_ARROW_DOWN_COMMAND,t=>R(t,e,!1),n.COMMAND_PRIORITY_LOW),e.registerCommand(n.KEY_ARROW_UP_COMMAND,t=>R(t,e,!0),n.COMMAND_PRIORITY_LOW),e.registerCommand(n.KEY_ESCAPE_COMMAND,()=>{if(null!=I()){const t=e.getRootElement();return null!=t&&t.focus(),!0}return!1},n.COMMAND_PRIORITY_LOW),e.registerCommand(n.KEY_SPACE_COMMAND,t=>{const r=I();return!(null==r||!e.isEditable())&&(e.update(()=>{const e=n.$getNearestNodeFromDOMNode(r);L(e)&&(t.preventDefault(),e.toggleChecked())}),!0)},n.COMMAND_PRIORITY_LOW),e.registerCommand(n.KEY_ARROW_LEFT_COMMAND,r=>e.getEditorState().read(()=>{const i=n.$getSelection();if(n.$isRangeSelection(i)&&i.isCollapsed()){const{anchor:s}=i,o="element"===s.type;if(o||0===s.offset){const i=s.getNode(),l=t.$findMatchingParent(i,e=>n.$isElementNode(e)&&!e.isInline());if(L(l)){const t=l.getParent();if($(t)&&"check"===t.getListType()&&(o||l.getFirstDescendant()===i)){const t=e.getElementByKey(l.__key);if(null!=t&&document.activeElement!==t)return t.focus(),r.preventDefault(),!0}}}}return!1}),n.COMMAND_PRIORITY_LOW),e.registerRootListener(e=>{if(null!==e)return e.addEventListener("click",a),e.addEventListener("pointerup",d),e.addEventListener("pointerdown",g,{capture:!0}),e.addEventListener("mousedown",g,{capture:!0}),e.addEventListener("touchstart",g,{capture:!0,passive:!1}),()=>{e.removeEventListener("click",a),e.removeEventListener("pointerup",d),e.removeEventListener("pointerdown",g,{capture:!0}),e.removeEventListener("mousedown",g,{capture:!0}),e.removeEventListener("touchstart",g,{capture:!0})}}))}function k(e,n){const r=e.target;if(!t.isHTMLElement(r))return;const i=r.firstChild;if(t.isHTMLElement(i)&&("UL"===i.tagName||"OL"===i.tagName))return;const s=r.parentNode;if(!s||"check"!==s.__lexicalListType)return;let o=null,l=null;if("clientX"in e)o=e.clientX;else if("touches"in e){const t=e.touches;t.length>0&&(o=t[0].clientX,l="touch")}if(null==o)return;const a=r.getBoundingClientRect(),c=o/t.calculateZoomLevel(r),d=window.getComputedStyle?window.getComputedStyle(r,"::before"):{width:"0px"},g=parseFloat(d.width),u="touch"===l||"pointerType"in e&&"touch"===e.pointerType?32:0;("rtl"===r.dir?c<a.right+u&&c>a.right-g-u:c>a.left-u&&c<a.left+g+u)&&n()}function A(e,r){k(e,()=>{if(t.isHTMLElement(e.target)){const t=e.target,i=n.getNearestEditorFromDOMNode(t);null!=i&&i.isEditable()&&i.update(()=>{const e=n.$getNearestNodeFromDOMNode(t);L(e)&&(r?(n.$addUpdateTag(n.SKIP_SELECTION_FOCUS_TAG),n.$addUpdateTag(n.SKIP_DOM_SELECTION_TAG)):t.focus(),e.toggleChecked())})}})}function I(){const e=document.activeElement;return t.isHTMLElement(e)&&"LI"===e.tagName&&null!=e.parentNode&&"check"===e.parentNode.__lexicalListType?e:null}function R(e,t,r){const i=I();return null!=i&&t.update(()=>{const s=n.$getNearestNodeFromDOMNode(i);if(!L(s))return;const o=function(e,t){let n=t?e.getPreviousSibling():e.getNextSibling(),r=e;for(;null==n&&L(r);)r=r.getParentOrThrow().getParent(),null!=r&&(n=t?r.getPreviousSibling():r.getNextSibling());for(;L(n);){const e=t?n.getLastChild():n.getFirstChild();if(!$(e))return n;n=t?e.getLastChild():e.getFirstChild()}return null}(s,r);if(null!=o){o.selectStart();const n=t.getElementByKey(o.__key);null!=n&&(e.preventDefault(),setTimeout(()=>{n.focus()},0))}}),!1}const F=n.createCommand("UPDATE_LIST_START_COMMAND"),D=n.createCommand("INSERT_UNORDERED_LIST_COMMAND"),w=n.createCommand("INSERT_ORDERED_LIST_COMMAND"),W=n.createCommand("REMOVE_LIST_COMMAND");function K(e,r){return t.mergeRegister(e.registerCommand(w,()=>(c("number"),!0),n.COMMAND_PRIORITY_LOW),e.registerCommand(F,e=>{const{listNodeKey:t,newStart:r}=e,i=n.$getNodeByKey(t);return!!$(i)&&("number"===i.getListType()&&(i.setStart(r),f(i)),!0)},n.COMMAND_PRIORITY_LOW),e.registerCommand(D,()=>(c("bullet"),!0),n.COMMAND_PRIORITY_LOW),e.registerCommand(W,()=>(h(),!0),n.COMMAND_PRIORITY_LOW),e.registerCommand(n.INSERT_PARAGRAPH_COMMAND,()=>_(!!(r&&r.restoreNumbering)),n.COMMAND_PRIORITY_LOW),e.registerNodeTransform(C,e=>{const t=e.getFirstChild();if(t){if(n.$isTextNode(t)){const n=t.getStyle(),r=t.getFormat();e.getTextStyle()!==n&&e.setTextStyle(n),e.getTextFormat()!==r&&e.setTextFormat(r)}}else{const t=n.$getSelection();n.$isRangeSelection(t)&&(t.style!==e.getTextStyle()||t.format!==e.getTextFormat())&&t.isCollapsed()&&e.is(t.anchor.getNode())&&e.setTextStyle(t.style).setTextFormat(t.format)}}),e.registerNodeTransform(n.TextNode,e=>{const t=e.getParent();if(L(t)&&e.is(t.getFirstChild())){const n=e.getStyle(),r=e.getFormat();n===t.getTextStyle()&&r===t.getTextFormat()||t.setTextStyle(n).setTextFormat(r)}}))}function H(e){const n=e=>{const n=e.getParent();if($(e.getFirstChild())||!$(n))return;const r=t.$findMatchingParent(e,e=>L(e)&&$(e.getParent())&&L(e.getPreviousSibling()));if(null===r&&e.getIndent()>0)e.setIndent(0);else if(L(r)){const t=r.getPreviousSibling();if(L(t)){const r=function(e){let t=e,n=t.getFirstChild();for(;$(n);){const e=n.getLastChild();if(!L(e))break;t=e,n=t.getFirstChild()}return t}(t),s=r.getParent();if($(s)){const t=i(s);t+1<i(n)&&e.setIndent(t)}}}};return e.registerNodeTransform(O,e=>{const t=[e];for(;t.length>0;){const e=t.shift();if($(e))for(const r of e.getChildren())if(L(r)){n(r);const e=r.getFirstChild();$(e)&&t.push(e)}}})}const U=n.defineExtension({build:(t,n,r)=>e.namedSignals(n),config:n.safeCast({hasStrictIndent:!1,shouldPreserveNumbering:!1}),name:"@lexical/list/List",nodes:()=>[O,C],register(n,r,i){const s=i.getOutput();return t.mergeRegister(e.effect(()=>K(n,{restoreNumbering:s.shouldPreserveNumbering.value})),e.effect(()=>s.hasStrictIndent.value?H(n):void 0))}}),Y=n.defineExtension({build:(t,n)=>e.namedSignals(n),config:n.safeCast({disableTakeFocusOnClick:!1}),dependencies:[U],name:"@lexical/list/CheckList",register:(e,t,n)=>b(e,n.getOutput())});exports.$createListItemNode=y,exports.$createListNode=M,exports.$getListDepth=i,exports.$handleListInsertParagraph=_,exports.$insertList=c,exports.$isListItemNode=L,exports.$isListNode=$,exports.$removeList=h,exports.CheckListExtension=Y,exports.INSERT_CHECK_LIST_COMMAND=P,exports.INSERT_ORDERED_LIST_COMMAND=w,exports.INSERT_UNORDERED_LIST_COMMAND=D,exports.ListExtension=U,exports.ListItemNode=C,exports.ListNode=O,exports.REMOVE_LIST_COMMAND=W,exports.UPDATE_LIST_START_COMMAND=F,exports.insertList=function(e,t){e.update(()=>c(t))},exports.registerCheckList=b,exports.registerList=K,exports.registerListStrictIndentTransform=H,exports.removeList=function(e){e.update(()=>h())};
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import{effect as e,namedSignals as t}from"@lexical/extension";import{$getNearestNodeOfType as n,$insertNodeToNearestRootAtCaret as r,removeClassNamesFromElement as i,addClassNamesToElement as s,isHTMLElement as o,mergeRegister as l,$findMatchingParent as c,calculateZoomLevel as a}from"@lexical/utils";import{$copyNode as u,$getSelection as g,$isRangeSelection as h,$isRootOrShadowRoot as d,$createParagraphNode as f,$isElementNode as p,$isLeafNode as m,$setPointFromCaret as _,$normalizeCaret as y,$getChildCaret as C,$isTextNode as v,ElementNode as T,buildImportMap as S,$getSiblingCaret as k,$rewindSiblingCaret as b,setDOMStyleFromCSS as x,isHTMLElement as L,$isParagraphNode as N,$applyNodeReplacement as P,$setFormatFromDOM as F,$setDirectionFromDOM as E,normalizeClassNames as O,getStyleObjectFromCSS as A,$createTextNode as I,COMMAND_PRIORITY_LOW as w,KEY_ARROW_DOWN_COMMAND as D,KEY_ARROW_UP_COMMAND as M,KEY_ESCAPE_COMMAND as K,KEY_SPACE_COMMAND as R,$getNearestNodeFromDOMNode as B,KEY_ARROW_LEFT_COMMAND as W,createCommand as U,getNearestEditorFromDOMNode as $,$addUpdateTag as J,SKIP_SELECTION_FOCUS_TAG as V,SKIP_DOM_SELECTION_TAG as z,defineExtension as H,safeCast as X,$getNodeByKey as j,INSERT_PARAGRAPH_COMMAND as q,TextNode as G}from"lexical";function Q(e,...t){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",e);for(const e of t)r.append("v",e);throw n.search=r.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function Y(e){let t=1,n=e.getParent();for(;null!=n;){if(_e(n)){const e=n.getParent();if(ke(e)){t++,n=e.getParent();continue}Q(40)}return t}return t}function Z(e){let t=e.getParent();ke(t)||Q(40);let n=t;for(;null!==n;)n=n.getParent(),ke(n)&&(t=n);return t}function ee(e){let t=[];const n=e.getChildren().filter(_e);for(let e=0;e<n.length;e++){const r=n[e],i=r.getFirstChild();ke(i)?t=t.concat(ee(i)):t.push(r)}return t}function te(e){return _e(e)&&ke(e.getFirstChild())}function ne(e,t){return _e(e)&&(0===t.length||1===t.length&&e.is(t[0])&&0===e.getChildrenSize())}function re(e){const t=g();if(null!==t){let n=t.getNodes();if(h(t)){const[r]=t.getStartEndPoints(),i=r.getNode(),s=i.getParent();if(d(i)){const e=i.getFirstChild();if(e)n=e.selectStart().getNodes();else{const e=f();i.append(e),n=e.select().getNodes()}}else if(ne(i,n)){const t=Se(e);if(d(s)){i.replace(t);const e=me();p(i)&&(e.setFormat(i.getFormatType()),e.setIndent(i.getIndent())),t.append(e)}else if(_e(i)){const e=i.getParentOrThrow();ie(t,e.getChildren()),e.replace(t)}return}}const r=new Set;for(let t=0;t<n.length;t++){const i=n[t];if(p(i)&&i.isEmpty()&&!_e(i)&&!r.has(i.getKey())){se(i,e);continue}let s=m(i)?i.getParent():_e(i)&&i.isEmpty()?i:null;for(;null!=s;){const t=s.getKey();if(ke(s)){if(!r.has(t)){const n=Se(e);ie(n,s.getChildren()),s.replace(n),r.add(t)}break}{const n=s.getParent();if(d(n)&&!r.has(t)){r.add(t),se(s,e);break}s=n}}}}}function ie(e,t){e.splice(e.getChildrenSize(),0,t)}function se(e,t){if(ke(e))return e;const n=e.getPreviousSibling(),r=e.getNextSibling(),i=me();let s;if(ie(i,e.getChildren()),ke(n)&&t===n.getListType())n.append(i),ke(r)&&t===r.getListType()&&(ie(n,r.getChildren()),r.remove()),s=n;else if(ke(r)&&t===r.getListType())r.getFirstChildOrThrow().insertBefore(i),s=r;else{const n=Se(t);n.append(i),e.replace(n),s=n}i.setFormat(e.getFormatType()),i.setIndent(e.getIndent());const o=g();return h(o)&&(s.getKey()===o.anchor.key&&o.anchor.set(i.getKey(),o.anchor.offset,"element"),s.getKey()===o.focus.key&&o.focus.set(i.getKey(),o.focus.offset,"element")),e.remove(),s}function oe(e,t){const n=e.getLastChild(),r=t.getFirstChild();n&&r&&te(n)&&te(r)&&(oe(n.getFirstChild(),r.getFirstChild()),r.remove());const i=t.getChildren();i.length>0&&e.append(...i),t.remove()}function le(){const e=g();if(h(e)){const t=new Set,r=e.getNodes(),i=e.anchor.getNode();if(ne(i,r))t.add(Z(i));else for(let e=0;e<r.length;e++){const i=r[e];if(m(i)){const e=n(i,he);null!=e&&t.add(Z(e))}}for(const n of t){let t=n;const r=ee(n);for(const n of r){const r=f().setTextStyle(e.style).setTextFormat(e.format);ie(r,n.getChildren()),t.insertAfter(r),t=r,n.__key===e.anchor.key&&_(e.anchor,y(C(r,"next"))),n.__key===e.focus.key&&_(e.focus,y(C(r,"next"))),n.remove()}n.remove()}}}function ce(e){const t="check"!==e.getListType();let n=e.getStart();for(const r of e.getChildren())_e(r)&&(r.getValue()!==n&&r.setValue(n),t&&null!=r.getLatest().__checked&&r.setChecked(void 0),ke(r.getFirstChild())||n++)}function ae(e){const t=new Set;if(te(e)||t.has(e.getKey()))return;const n=e.getParent(),r=e.getNextSibling(),i=e.getPreviousSibling();if(te(r)&&te(i)){const n=i.getFirstChild();if(ke(n)){n.append(e);const i=r.getFirstChild();if(ke(i)){ie(n,i.getChildren()),r.remove(),t.add(r.getKey())}}}else if(te(r)){const t=r.getFirstChild();if(ke(t)){const n=t.getFirstChild();null!==n&&n.insertBefore(e)}}else if(te(i)){const t=i.getFirstChild();ke(t)&&t.append(e)}else if(ke(n)){const t=u(e),s=u(n);t.append(s),s.append(e),i?i.insertAfter(t):r?r.insertBefore(t):n.append(t)}}function ue(e){if(te(e))return;const t=e.getParent(),n=t?t.getParent():void 0;if(ke(n?n.getParent():void 0)&&_e(n)&&ke(t)){const r=t?t.getFirstChild():void 0,i=t?t.getLastChild():void 0;if(e.is(r))n.insertBefore(e),t.isEmpty()&&n.remove();else if(e.is(i))n.insertAfter(e),t.isEmpty()&&n.remove();else{const r=u(e),i=u(t);r.append(i),e.getPreviousSiblings().forEach(e=>i.append(e));const s=u(e),o=u(t);s.append(o),ie(o,e.getNextSiblings()),n.insertBefore(r),n.insertAfter(s),n.replace(e)}}}function ge(e=!1){const t=g();if(!h(t)||!t.isCollapsed())return!1;const n=t.anchor.getNode();let r=null;if(_e(n)&&0===n.getChildrenSize())r=n;else if(v(n)){const e=n.getParent();_e(e)&&e.getChildren().every(e=>v(e)&&""===e.getTextContent().trim())&&(r=e)}if(null===r)return!1;const i=Z(r),s=r.getParent();ke(s)||Q(40);const o=s.getParent();let l;if(d(o))l=f(),i.insertAfter(l);else{if(!_e(o))return!1;l=u(o),o.insertAfter(l)}l.setTextStyle(t.style).setTextFormat(t.format).select();const c=r.getNextSiblings();if(c.length>0){const t=e?function(e,t){return e.getStart()+t.getIndexWithinParent()}(s,r):1,n=u(s).setStart(t);if(_e(l)){const e=u(l);e.append(n),l.insertAfter(e)}else l.insertAfter(n);n.append(...c)}return function(e){let t=e;for(;null==t.getNextSibling()&&null==t.getPreviousSibling();){const e=t.getParent();if(null==e||!_e(e)&&!ke(e))break;t=e}t.remove()}(r),!0}class he extends T{__value;__checked;$config(){return this.config("listitem",{$transform:e=>{const t=e.getParent();if(ke(t))"check"!==t.getListType()&&null!=e.getChecked()&&e.setChecked(void 0);else if(t){const n=e.createParentElementNode();ke(n)||Q(340);const i=[e];for(const t of["previous","next"]){i.reverse();for(const{origin:n}of k(e,t)){if(!_e(n))break;i.push(n)}}e.insertBefore(n),n.splice(0,0,i),d(t)||(r(n,b(k(n,"next")),{$shouldSplit:()=>!1,removeEmptyDestination:!0}),t.isEmpty()&&t.isAttached()&&t.remove())}},extends:T,importDOM:S({li:()=>({conversion:de,priority:0})})})}constructor(e=1,t=void 0,n){super(n),this.__value=void 0===e?1:e,this.__checked=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__value=e.__value,this.__checked=e.__checked}createDOM(e){const t=document.createElement("li");return this.updateListItemDOM(null,t,e),t}updateListItemDOM(e,t,n){!function(e,t){const n=t.getParent();!ke(n)||"check"!==n.getListType()||ke(t.getFirstChild())?(e.removeAttribute("role"),e.removeAttribute("tabIndex"),e.removeAttribute("aria-checked")):(e.setAttribute("role","checkbox"),e.setAttribute("tabIndex","-1"),e.setAttribute("aria-checked",t.getChecked()?"true":"false"))}(t,this),t.value=this.__value,function(e,t,n){const r=t.list;if(!r)return;const o=r.listitem,l=r.nested&&r.nested.listitem,c=n.getParent(),a=ke(c)&&"check"===c.getListType(),u=n.getChecked(),g=n.getChildren().some(e=>ke(e)),h=[];void 0!==r.listitemChecked&&h.push(r.listitemChecked);void 0!==r.listitemUnchecked&&h.push(r.listitemUnchecked);void 0!==l&&h.push(...O(l));h.length>0&&i(e,...h);const d=[];void 0!==o&&d.push(...O(o));if(a){const e=u?r.listitemChecked:r.listitemUnchecked;void 0!==e&&d.push(e)}void 0!==l&&g&&d.push(...O(l));d.length>0&&s(e,...d)}(t,n.theme,this);const r=e?e.__style:"",o=this.__style;r!==o&&x(t.style,o,r),function(e,t,n){const r=t.__textStyle,i=n?n.__textStyle:"";if(null!==n&&i===r)return;const s=A(r);for(const t in s)e.style.setProperty(`--listitem-marker-${t}`,s[t]);if(""!==i)for(const t in A(i))t in s||e.style.removeProperty(`--listitem-marker-${t}`)}(t,this,e)}updateDOM(e,t,n){const r=t;return this.updateListItemDOM(e,r,n),!1}updateFromJSON(e){return super.updateFromJSON(e).setValue(e.value).setChecked(e.checked)}exportDOM(e){const t=this.createDOM(e._config),n=this.getFormatType();n&&(t.style.textAlign=n);const r=this.getDirection();return r&&(t.dir=r),te(this)?{after(e){if(L(e)){const t=e.previousElementSibling;if(L(t)&&"LI"===t.nodeName){for(;e.firstChild;)t.append(e.firstChild);e.remove()}}return e},element:t}:{element:t}}exportJSON(){return{...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...e){for(let t=0;t<e.length;t++){const n=e[t];if(p(n)&&this.canMergeWith(n)){const e=n.getChildren();this.append(...e),n.remove()}else super.append(n)}return this}replace(e,t){if(_e(e))return super.replace(e);this.setIndent(0);const n=this.getParentOrThrow();if(!ke(n))return e;if(n.__first===this.getKey())n.insertBefore(e);else if(n.__last===this.getKey())n.insertAfter(e);else{const t=u(n);let r=this.getNextSibling();for(;r;){const e=r;r=r.getNextSibling(),t.append(e)}n.insertAfter(e),e.insertAfter(t)}const r=this.__key;let i=0;if(t&&(p(e)||Q(139),i=e.getChildrenSize(),e.splice(i,0,this.getChildren())),t&&p(e)){const t=g();if(h(t))for(const n of t.getStartEndPoints())n.key===r&&"element"===n.type&&n.set(e.getKey(),i+n.offset,"element")}return this.remove(),0===n.getChildrenSize()&&n.remove(),e}insertAfter(e,t=!0){const n=this.getParentOrThrow();if(ke(n)||Q(39),_e(e))return super.insertAfter(e,t);const r=this.getNextSiblings();if(n.insertAfter(e,t),0!==r.length){const i=u(n);r.forEach(e=>i.append(e)),e.insertAfter(i,t)}return e}remove(e){const t=this.getPreviousSibling(),n=this.getNextSibling();super.remove(e),t&&n&&te(t)&&te(n)&&(oe(t.getFirstChild(),n.getFirstChild()),n.remove())}resetOnCopyNodeFrom(e){super.resetOnCopyNodeFrom(e),e.getChecked()&&this.setChecked(!1)}insertNewAfter(e,t=!0){const n=u(this);return this.insertAfter(n,t),n}collapseAtStart(e){const t=f();this.getChildren().forEach(e=>t.append(e));const n=this.getParentOrThrow(),r=n.getParentOrThrow(),i=_e(r);if(1===n.getChildrenSize())if(i)n.remove(),r.select();else{n.insertBefore(t),n.remove();const r=e.anchor,i=e.focus,s=t.getKey();"element"===r.type&&r.getNode().is(this)&&r.set(s,r.offset,"element"),"element"===i.type&&i.getNode().is(this)&&i.set(s,i.offset,"element")}else n.insertBefore(t),this.remove();return!0}getValue(){return this.getLatest().__value}setValue(e){const t=this.getWritable();return t.__value=e,t}getChecked(){const e=this.getLatest();let t;const n=this.getParent();return ke(n)&&(t=n.getListType()),"check"===t?Boolean(e.__checked):void 0}setChecked(e){const t=this.getWritable();return t.__checked=e,t}toggleChecked(){const e=this.getWritable();return e.setChecked(!e.__checked)}getIndent(){const e=this.getParent();if(null===e||!this.isAttached())return this.getLatest().__indent;let t=e.getParentOrThrow(),n=0;for(;_e(t);)t=t.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(e){"number"!=typeof e&&Q(117),(e=Math.floor(e))>=0||Q(199);let t=this.getIndent();for(;t!==e;)t<e?(ae(this),t++):(ue(this),t--);return this}canInsertAfter(e){return _e(e)}canReplaceWith(e){return _e(e)}canMergeWith(e){return _e(e)||N(e)}extractWithChild(e,t){if(!h(t))return!1;const n=t.anchor.getNode(),r=t.focus.getNode();return this.isParentOf(n)&&this.isParentOf(r)&&this.getTextContent().length===t.getTextContent().length}isParentRequired(){return!0}createParentElementNode(){return Se("bullet")}canMergeWhenEmpty(){return!0}}function de(e){if(e.classList.contains("task-list-item"))for(const t of e.children)if("INPUT"===t.tagName)return fe(t);if(e.classList.contains("joplin-checkbox"))for(const t of e.children)if(t.classList.contains("checkbox-wrapper")&&t.children.length>0&&"INPUT"===t.children[0].tagName)return fe(t.children[0]);const t=e.getAttribute("aria-checked"),n=me("true"===t||"false"!==t&&void 0);return F(n,e),{after:pe.bind(null,n),node:E(n,e)}}function fe(e){if(!("checkbox"===e.getAttribute("type")))return{node:null};const t=me(e.hasAttribute("checked"));return{after:pe.bind(null,t),node:t}}function pe(e,t){const n=t[0];return 1===t.length&&N(n)&&!e.getFormatType()&&n.getFormatType()?(e.setFormat(n.getFormatType()),n.getChildren()):t}function me(e){return P(new he(void 0,e))}function _e(e){return e instanceof he}class ye extends T{__tag;__start;__listType;$config(){return this.config("list",{$transform:e=>{!function(e){const t=e.getNextSibling();ke(t)&&e.getListType()===t.getListType()&&oe(e,t)}(e),ce(e)},extends:T,importDOM:S({ol:()=>({conversion:ve,priority:0}),ul:()=>({conversion:ve,priority:0})})})}constructor(e="number",t=1,n){super(n);const r=Te[e]||e;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=t}afterCloneFrom(e){super.afterCloneFrom(e),this.__listType=e.__listType,this.__tag=e.__tag,this.__start=e.__start}getTag(){return this.getLatest().__tag}setListType(e){const t=this.getWritable();return t.__listType=e,t.__tag="number"===e?"ol":"ul",t}getListType(){return this.getLatest().__listType}getStart(){return this.getLatest().__start}setStart(e){const t=this.getWritable();return t.__start=e,t}createDOM(e,t){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,Ce(r,e.theme,this),r}updateDOM(e,t,n){return e.__tag!==this.__tag||e.__listType!==this.__listType||(Ce(t,n.theme,this),e.__start!==this.__start&&t.setAttribute("start",String(this.__start)),!1)}updateFromJSON(e){return super.updateFromJSON(e).setListType(e.listType).setStart(e.start)}exportDOM(e){const t=this.createDOM(e._config,e);return o(t)&&(1!==this.__start&&t.setAttribute("start",String(this.__start)),"check"===this.__listType&&t.setAttribute("__lexicalListType","check")),{element:t}}exportJSON(){return{...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return!1}canIndent(){return!1}splice(e,t,n){let r=n;for(let e=0;e<n.length;e++){const t=n[e];_e(t)||(r===n&&(r=[...n]),r[e]=this.createListItemNode().append(!p(t)||ke(t)||t.isInline()?t:I(t.getTextContent())))}return super.splice(e,t,r)}extractWithChild(e){return _e(e)}createListItemNode(){return me()}}function Ce(e,t,n){const r=[],o=[],l=t.list;if(void 0!==l){const e=l[`${n.__tag}Depth`]||[],t=Y(n)-1,i=t%e.length,s=e[i],c=l[n.__tag];let a;const u=l.nested,g=l.checklist;if(void 0!==u&&u.list&&(a=u.list),void 0!==c&&r.push(c),void 0!==g&&"check"===n.__listType&&r.push(g),void 0!==s){r.push(...O(s));for(let t=0;t<e.length;t++)t!==i&&o.push(n.__tag+t)}if(void 0!==a){const e=O(a);t>1?r.push(...e):o.push(...e)}}o.length>0&&i(e,...o),r.length>0&&s(e,...r)}function ve(e){let t;if(function(e){return o(e)&&"ol"===e.nodeName.toLowerCase()}(e)){const n=e.start;t=Se("number",n)}else t=function(e){if("check"===e.getAttribute("__lexicallisttype")||e.classList.contains("contains-task-list")||"1"===e.getAttribute("data-is-checklist"))return!0;for(const t of e.childNodes)if(o(t)&&t.hasAttribute("aria-checked"))return!0;return!1}(e)?Se("check"):Se("bullet");return E(t,e),{after:e=>function(e,t){const n=t.createListItemNode.bind(t),r=[];for(let t=0;t<e.length;t++){const i=e[t];if(_e(i)){r.push(i);const e=i.getChildren();e.length>1&&e.forEach(e=>{ke(e)&&r.push(n().append(e))})}else r.push(n().append(i))}return r}(e,t),node:t}}const Te={ol:"number",ul:"bullet"};function Se(e="number",t=1){return P(new ye(e,t))}function ke(e){return e instanceof ye}const be=U("INSERT_CHECK_LIST_COMMAND");function xe(e,t){const n=t&&t.disableTakeFocusOnClick||!1,r="boolean"==typeof n?()=>n:n.peek.bind(n),i=e=>{const t=e.target;if(!o(t))return!1;const n=t.__lexicalCheckListLastHandled;return void 0!==n&&e.timeStamp-n<500},s=e=>{const t=e.target;o(t)&&(t.__lexicalCheckListLastHandled=e.timeStamp)},a=e=>{i(e)||(s(e),Ne(e,r()))},u=e=>{"touch"===e.pointerType&&(i(e)||(s(e),Ne(e,r())))},d=e=>{!function(e,t){Le(e,()=>{e.preventDefault(),t&&e.stopPropagation()})}(e,r())};return l(e.registerCommand(be,()=>(re("check"),!0),w),e.registerCommand(D,t=>Fe(t,e,!1),w),e.registerCommand(M,t=>Fe(t,e,!0),w),e.registerCommand(K,()=>{if(null!=Pe()){const t=e.getRootElement();return null!=t&&t.focus(),!0}return!1},w),e.registerCommand(R,t=>{const n=Pe();return!(null==n||!e.isEditable())&&(e.update(()=>{const e=B(n);_e(e)&&(t.preventDefault(),e.toggleChecked())}),!0)},w),e.registerCommand(W,t=>e.getEditorState().read(()=>{const n=g();if(h(n)&&n.isCollapsed()){const{anchor:r}=n,i="element"===r.type;if(i||0===r.offset){const n=r.getNode(),s=c(n,e=>p(e)&&!e.isInline());if(_e(s)){const r=s.getParent();if(ke(r)&&"check"===r.getListType()&&(i||s.getFirstDescendant()===n)){const n=e.getElementByKey(s.__key);if(null!=n&&document.activeElement!==n)return n.focus(),t.preventDefault(),!0}}}}return!1}),w),e.registerRootListener(e=>{if(null!==e)return e.addEventListener("click",a),e.addEventListener("pointerup",u),e.addEventListener("pointerdown",d,{capture:!0}),e.addEventListener("mousedown",d,{capture:!0}),e.addEventListener("touchstart",d,{capture:!0,passive:!1}),()=>{e.removeEventListener("click",a),e.removeEventListener("pointerup",u),e.removeEventListener("pointerdown",d,{capture:!0}),e.removeEventListener("mousedown",d,{capture:!0}),e.removeEventListener("touchstart",d,{capture:!0})}}))}function Le(e,t){const n=e.target;if(!o(n))return;const r=n.firstChild;if(o(r)&&("UL"===r.tagName||"OL"===r.tagName))return;const i=n.parentNode;if(!i||"check"!==i.__lexicalListType)return;let s=null,l=null;if("clientX"in e)s=e.clientX;else if("touches"in e){const t=e.touches;t.length>0&&(s=t[0].clientX,l="touch")}if(null==s)return;const c=n.getBoundingClientRect(),u=s/a(n),g=window.getComputedStyle?window.getComputedStyle(n,"::before"):{width:"0px"},h=parseFloat(g.width),d="touch"===l||"pointerType"in e&&"touch"===e.pointerType?32:0;("rtl"===n.dir?u<c.right+d&&u>c.right-h-d:u>c.left-d&&u<c.left+h+d)&&t()}function Ne(e,t){Le(e,()=>{if(o(e.target)){const n=e.target,r=$(n);null!=r&&r.isEditable()&&r.update(()=>{const e=B(n);_e(e)&&(t?(J(V),J(z)):n.focus(),e.toggleChecked())})}})}function Pe(){const e=document.activeElement;return o(e)&&"LI"===e.tagName&&null!=e.parentNode&&"check"===e.parentNode.__lexicalListType?e:null}function Fe(e,t,n){const r=Pe();return null!=r&&t.update(()=>{const i=B(r);if(!_e(i))return;const s=function(e,t){let n=t?e.getPreviousSibling():e.getNextSibling(),r=e;for(;null==n&&_e(r);)r=r.getParentOrThrow().getParent(),null!=r&&(n=t?r.getPreviousSibling():r.getNextSibling());for(;_e(n);){const e=t?n.getLastChild():n.getFirstChild();if(!ke(e))return n;n=t?e.getLastChild():e.getFirstChild()}return null}(i,n);if(null!=s){s.selectStart();const n=t.getElementByKey(s.__key);null!=n&&(e.preventDefault(),setTimeout(()=>{n.focus()},0))}}),!1}const Ee=U("UPDATE_LIST_START_COMMAND"),Oe=U("INSERT_UNORDERED_LIST_COMMAND"),Ae=U("INSERT_ORDERED_LIST_COMMAND"),Ie=U("REMOVE_LIST_COMMAND");function we(e,t){return l(e.registerCommand(Ae,()=>(re("number"),!0),w),e.registerCommand(Ee,e=>{const{listNodeKey:t,newStart:n}=e,r=j(t);return!!ke(r)&&("number"===r.getListType()&&(r.setStart(n),ce(r)),!0)},w),e.registerCommand(Oe,()=>(re("bullet"),!0),w),e.registerCommand(Ie,()=>(le(),!0),w),e.registerCommand(q,()=>ge(!!(t&&t.restoreNumbering)),w),e.registerNodeTransform(he,e=>{const t=e.getFirstChild();if(t){if(v(t)){const n=t.getStyle(),r=t.getFormat();e.getTextStyle()!==n&&e.setTextStyle(n),e.getTextFormat()!==r&&e.setTextFormat(r)}}else{const t=g();h(t)&&(t.style!==e.getTextStyle()||t.format!==e.getTextFormat())&&t.isCollapsed()&&e.is(t.anchor.getNode())&&e.setTextStyle(t.style).setTextFormat(t.format)}}),e.registerNodeTransform(G,e=>{const t=e.getParent();if(_e(t)&&e.is(t.getFirstChild())){const n=e.getStyle(),r=e.getFormat();n===t.getTextStyle()&&r===t.getTextFormat()||t.setTextStyle(n).setTextFormat(r)}}))}function De(e){const t=e=>{const t=e.getParent();if(ke(e.getFirstChild())||!ke(t))return;const n=c(e,e=>_e(e)&&ke(e.getParent())&&_e(e.getPreviousSibling()));if(null===n&&e.getIndent()>0)e.setIndent(0);else if(_e(n)){const r=n.getPreviousSibling();if(_e(r)){const n=function(e){let t=e,n=t.getFirstChild();for(;ke(n);){const e=n.getLastChild();if(!_e(e))break;t=e,n=t.getFirstChild()}return t}(r),i=n.getParent();if(ke(i)){const n=Y(i);n+1<Y(t)&&e.setIndent(n)}}}};return e.registerNodeTransform(ye,e=>{const n=[e];for(;n.length>0;){const e=n.shift();if(ke(e))for(const r of e.getChildren())if(_e(r)){t(r);const e=r.getFirstChild();ke(e)&&n.push(e)}}})}function Me(e,t){e.update(()=>re(t))}function Ke(e){e.update(()=>le())}const Re=H({build:(e,n,r)=>t(n),config:X({hasStrictIndent:!1,shouldPreserveNumbering:!1}),name:"@lexical/list/List",nodes:()=>[ye,he],register(t,n,r){const i=r.getOutput();return l(e(()=>we(t,{restoreNumbering:i.shouldPreserveNumbering.value})),e(()=>i.hasStrictIndent.value?De(t):void 0))}}),Be=H({build:(e,n)=>t(n),config:X({disableTakeFocusOnClick:!1}),dependencies:[Re],name:"@lexical/list/CheckList",register:(e,t,n)=>xe(e,n.getOutput())});export{me as $createListItemNode,Se as $createListNode,Y as $getListDepth,ge as $handleListInsertParagraph,re as $insertList,_e as $isListItemNode,ke as $isListNode,le as $removeList,Be as CheckListExtension,be as INSERT_CHECK_LIST_COMMAND,Ae as INSERT_ORDERED_LIST_COMMAND,Oe as INSERT_UNORDERED_LIST_COMMAND,Re as ListExtension,he as ListItemNode,ye as ListNode,Ie as REMOVE_LIST_COMMAND,Ee as UPDATE_LIST_START_COMMAND,Me as insertList,xe as registerCheckList,we as registerList,De as registerListStrictIndentTransform,Ke as removeList};
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { ListNode } from './';
import type { BaseSelection, DOMExportOutput, EditorConfig, LexicalNode, LexicalUpdateJSON, NodeKey, ParagraphNode, RangeSelection, SerializedElementNode, Spread } from 'lexical';
import { ElementNode, LexicalEditor } from 'lexical';
export type SerializedListItemNode = Spread<{
checked: boolean | undefined;
value: number;
}, SerializedElementNode>;
/** @noInheritDoc */
export declare class ListItemNode extends ElementNode {
/** @internal */
__value: number;
/** @internal */
__checked?: boolean;
/** @internal */
$config(): import("lexical").StaticNodeConfigRecord<"listitem", {
$transform: (node: ListItemNode) => void;
extends: typeof ElementNode;
importDOM: import("lexical").DOMConversionMap<HTMLElement>;
}>;
constructor(value?: number, checked?: undefined | boolean, key?: NodeKey);
afterCloneFrom(prevNode: this): void;
createDOM(config: EditorConfig): HTMLElement;
updateListItemDOM(prevNode: ListItemNode | null, dom: HTMLLIElement, config: EditorConfig): void;
updateDOM(prevNode: ListItemNode, dom: HTMLElement, config: EditorConfig): boolean;
updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedListItemNode>): this;
exportDOM(editor: LexicalEditor): DOMExportOutput;
exportJSON(): SerializedListItemNode;
append(...nodes: LexicalNode[]): this;
replace<N extends LexicalNode>(replaceWithNode: N, includeChildren?: boolean): N;
insertAfter(node: LexicalNode, restoreSelection?: boolean): LexicalNode;
remove(preserveEmptyParent?: boolean): void;
resetOnCopyNodeFrom(original: this): void;
insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ListItemNode | ParagraphNode;
collapseAtStart(selection: RangeSelection): true;
getValue(): number;
setValue(value: number): this;
getChecked(): boolean | undefined;
setChecked(checked?: boolean): this;
toggleChecked(): this;
getIndent(): number;
setIndent(indent: number): this;
/** @deprecated @internal */
canInsertAfter(node: LexicalNode): boolean;
/** @deprecated @internal */
canReplaceWith(replacement: LexicalNode): boolean;
canMergeWith(node: LexicalNode): boolean;
extractWithChild(child: LexicalNode, selection: BaseSelection): boolean;
isParentRequired(): true;
createParentElementNode(): ListNode;
canMergeWhenEmpty(): true;
}
/**
* Creates a new List Item node, passing true/false will convert it to a checkbox input.
* @param checked - Is the List Item a checkbox and, if so, is it checked? undefined/null: not a checkbox, true/false is a checkbox and checked/unchecked, respectively.
* @returns The new List Item.
*/
export declare function $createListItemNode(checked?: boolean): ListItemNode;
/**
* Checks to see if the node is a ListItemNode.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode, false otherwise.
*/
export declare function $isListItemNode(node: LexicalNode | null | undefined): node is ListItemNode;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { DOMExportOutput, EditorConfig, ElementNode, LexicalEditor, LexicalNode, LexicalUpdateJSON, NodeKey, SerializedElementNode, Spread } from 'lexical';
import { ListItemNode } from '.';
export type SerializedListNode = Spread<{
listType: ListType;
start: number;
tag: ListNodeTagType;
}, SerializedElementNode>;
export type ListType = 'number' | 'bullet' | 'check';
export type ListNodeTagType = 'ul' | 'ol';
/** @noInheritDoc */
export declare class ListNode extends ElementNode {
/** @internal */
__tag: ListNodeTagType;
/** @internal */
__start: number;
/** @internal */
__listType: ListType;
/** @internal */
$config(): import("lexical").StaticNodeConfigRecord<"list", {
$transform: (node: ListNode) => void;
extends: typeof ElementNode;
importDOM: import("lexical").DOMConversionMap<HTMLElement>;
}>;
constructor(listType?: ListType, start?: number, key?: NodeKey);
afterCloneFrom(prevNode: this): void;
getTag(): ListNodeTagType;
setListType(type: ListType): this;
getListType(): ListType;
getStart(): number;
setStart(start: number): this;
createDOM(config: EditorConfig, _editor?: LexicalEditor): HTMLElement;
updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean;
updateFromJSON(serializedNode: LexicalUpdateJSON<SerializedListNode>): this;
exportDOM(editor: LexicalEditor): DOMExportOutput;
exportJSON(): SerializedListNode;
canBeEmpty(): false;
canIndent(): false;
splice(start: number, deleteCount: number, nodesToInsert: LexicalNode[]): this;
extractWithChild(child: LexicalNode): boolean;
/**
* Create an appropriate ListItemNode to be a child of this ListNode,
* {@link $createListItemNode} is the default implementation.
*
* @returns A new ListItemNode.
*/
createListItemNode(): ListItemNode;
}
/**
* Creates a ListNode of listType.
* @param listType - The type of list to be created. Can be 'number', 'bullet', or 'check'.
* @param start - Where an ordered list starts its count, start = 1 if left undefined.
* @returns The new ListNode
*/
export declare function $createListNode(listType?: ListType, start?: number): ListNode;
/**
* Checks to see if the node is a ListNode.
* @param node - The node to be checked.
* @returns true if the node is a ListNode, false otherwise.
*/
export declare function $isListNode(node: LexicalNode | null | undefined): node is ListNode;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { LexicalNode, Spread } from 'lexical';
import { ListItemNode, ListNode } from './';
/**
* Checks the depth of listNode from the root node.
* @param listNode - The ListNode to be checked.
* @returns The depth of the ListNode.
*/
export declare function $getListDepth(listNode: ListNode): number;
/**
* Finds the nearest ancestral ListNode and returns it, throws an invariant if listItem is not a ListItemNode.
* @param listItem - The node to be checked.
* @returns The ListNode found.
*/
export declare function $getTopListNode(listItem: LexicalNode): ListNode;
/**
* Checks if listItem has no child ListNodes and has no ListItemNode ancestors with siblings.
* @param listItem - the ListItemNode to be checked.
* @returns true if listItem has no child ListNode and no ListItemNode ancestors with siblings, false otherwise.
*/
export declare function $isLastItemInList(listItem: ListItemNode): boolean;
/**
* A recursive Depth-First Search (Postorder Traversal) that finds all of a node's children
* that are of type ListItemNode and returns them in an array.
* @param node - The ListNode to start the search.
* @returns An array containing all nodes of type ListItemNode found.
*/
export declare function $getAllListItems(node: ListNode): Array<ListItemNode>;
declare const NestedListNodeBrand: unique symbol;
/**
* Checks to see if the passed node is a ListItemNode and has a ListNode as a child.
* @param node - The node to be checked.
* @returns true if the node is a ListItemNode and has a ListNode child, false otherwise.
*/
export declare function isNestedListNode(node: LexicalNode | null | undefined): node is Spread<{
getFirstChild(): ListNode;
[NestedListNodeBrand]: never;
}, ListItemNode>;
/**
* Traverses up the tree and returns the first ListItemNode found.
* @param node - Node to start the search.
* @returns The first ListItemNode found, or null if none exist.
*/
export declare function $findNearestListItemNode(node: LexicalNode): ListItemNode | null;
/**
* Takes a deeply nested ListNode or ListItemNode and traverses up the branch to delete the first
* ancestral ListNode (which could be the root ListNode) or ListItemNode with siblings, essentially
* bringing the deeply nested node up the branch once. Would remove sublist if it has siblings.
* Should not break ListItem -> List -> ListItem chain as empty List/ItemNodes should be removed on .remove().
* @param sublist - The nested ListNode or ListItemNode to be brought up the branch.
*/
export declare function $removeHighestEmptyListParent(sublist: ListItemNode | ListNode): void;
/**
* Calculates the start value for a new list created by splitting an existing list.
*/
export declare function $getNewListStart(list: ListNode, listItem: ListItemNode): number;
export {};