@lexical/list
Version:
This package provides the list feature for Lexical.
10 lines (8 loc) • 18.9 kB
JavaScript
/**
* 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 t,removeClassNamesFromElement as e,addClassNamesToElement as n,isHTMLElement as r,mergeRegister as i,$findMatchingParent as s,calculateZoomLevel as o}from"@lexical/utils";import{$getSelection as l,$isRangeSelection as c,$isRootOrShadowRoot as a,$createParagraphNode as u,$isElementNode as g,$isLeafNode as h,$setPointFromCaret as d,$normalizeCaret as f,$getChildCaret as p,ElementNode as m,$isParagraphNode as _,$applyNodeReplacement as y,$createTextNode as C,createCommand as T,COMMAND_PRIORITY_LOW as S,KEY_ARROW_DOWN_COMMAND as v,KEY_ARROW_UP_COMMAND as x,KEY_ESCAPE_COMMAND as k,KEY_SPACE_COMMAND as b,$getNearestNodeFromDOMNode as N,KEY_ARROW_LEFT_COMMAND as L,getNearestEditorFromDOMNode as F,INSERT_PARAGRAPH_COMMAND as P,$isTextNode as O,TextNode as A}from"lexical";import{getStyleObjectFromCSS as E}from"@lexical/selection";function w(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function I(t){let e=1,n=t.getParent();for(;null!=n;){if(Z(n)){const t=n.getParent();if(ot(t)){e++,n=t.getParent();continue}w(40)}return e}return e}function D(t){let e=t.getParent();ot(e)||w(40);let n=e;for(;null!==n;)n=n.getParent(),ot(n)&&(e=n);return e}function M(t){let e=[];const n=t.getChildren().filter(Z);for(let t=0;t<n.length;t++){const r=n[t],i=r.getFirstChild();ot(i)?e=e.concat(M(i)):e.push(r)}return e}function R(t){return Z(t)&&ot(t.getFirstChild())}function J(t){return Y().append(t)}function B(t,e){return Z(t)&&(0===e.length||1===e.length&&t.is(e[0])&&0===t.getChildrenSize())}function W(t){const e=l();if(null!==e){let n=e.getNodes();if(c(e)){const r=e.getStartEndPoints();null===r&&w(143);const[i]=r,s=i.getNode(),o=s.getParent();if(a(s)){const t=s.getFirstChild();if(t)n=t.selectStart().getNodes();else{const t=u();s.append(t),n=t.select().getNodes()}}else if(B(s,n)){const e=st(t);if(a(o)){s.replace(e);const t=Y();g(s)&&(t.setFormat(s.getFormatType()),t.setIndent(s.getIndent())),e.append(t)}else if(Z(s)){const t=s.getParentOrThrow();K(e,t.getChildren()),t.replace(e)}return}}const r=new Set;for(let e=0;e<n.length;e++){const i=n[e];if(g(i)&&i.isEmpty()&&!Z(i)&&!r.has(i.getKey())){U(i,t);continue}let s=h(i)?i.getParent():Z(i)&&i.isEmpty()?i:null;for(;null!=s;){const e=s.getKey();if(ot(s)){if(!r.has(e)){const n=st(t);K(n,s.getChildren()),s.replace(n),r.add(e)}break}{const n=s.getParent();if(a(n)&&!r.has(e)){r.add(e),U(s,t);break}s=n}}}}}function K(t,e){t.splice(t.getChildrenSize(),0,e)}function U(t,e){if(ot(t))return t;const n=t.getPreviousSibling(),r=t.getNextSibling(),i=Y();let s;if(K(i,t.getChildren()),ot(n)&&e===n.getListType())n.append(i),ot(r)&&e===r.getListType()&&(K(n,r.getChildren()),r.remove()),s=n;else if(ot(r)&&e===r.getListType())r.getFirstChildOrThrow().insertBefore(i),s=r;else{const n=st(e);n.append(i),t.replace(n),s=n}return i.setFormat(t.getFormatType()),i.setIndent(t.getIndent()),t.remove(),s}function V(t,e){const n=t.getLastChild(),r=e.getFirstChild();n&&r&&R(n)&&R(r)&&(V(n.getFirstChild(),r.getFirstChild()),r.remove());const i=e.getChildren();i.length>0&&t.append(...i),e.remove()}function z(){const e=l();if(c(e)){const n=new Set,r=e.getNodes(),i=e.anchor.getNode();if(B(i,r))n.add(D(i));else for(let e=0;e<r.length;e++){const i=r[e];if(h(i)){const e=t(i,j);null!=e&&n.add(D(e))}}for(const t of n){let n=t;const r=M(t);for(const t of r){const r=u().setTextStyle(e.style).setTextFormat(e.format);K(r,t.getChildren()),n.insertAfter(r),n=r,t.__key===e.anchor.key&&d(e.anchor,f(p(r,"next"))),t.__key===e.focus.key&&d(e.focus,f(p(r,"next"))),t.remove()}t.remove()}}}function $(t){const e=new Set;if(R(t)||e.has(t.getKey()))return;const n=t.getParent(),r=t.getNextSibling(),i=t.getPreviousSibling();if(R(r)&&R(i)){const n=i.getFirstChild();if(ot(n)){n.append(t);const i=r.getFirstChild();if(ot(i)){K(n,i.getChildren()),r.remove(),e.add(r.getKey())}}}else if(R(r)){const e=r.getFirstChild();if(ot(e)){const n=e.getFirstChild();null!==n&&n.insertBefore(t)}}else if(R(i)){const e=i.getFirstChild();ot(e)&&e.append(t)}else if(ot(n)){const e=Y().setTextFormat(t.getTextFormat()).setTextStyle(t.getTextStyle()),s=st(n.getListType()).setTextFormat(n.getTextFormat()).setTextStyle(n.getTextStyle());e.append(s),s.append(t),i?i.insertAfter(e):r?r.insertBefore(e):n.append(e)}}function q(t){if(R(t))return;const e=t.getParent(),n=e?e.getParent():void 0;if(ot(n?n.getParent():void 0)&&Z(n)&&ot(e)){const r=e?e.getFirstChild():void 0,i=e?e.getLastChild():void 0;if(t.is(r))n.insertBefore(t),e.isEmpty()&&n.remove();else if(t.is(i))n.insertAfter(t),e.isEmpty()&&n.remove();else{const r=e.getListType(),i=Y(),s=st(r);i.append(s),t.getPreviousSiblings().forEach((t=>s.append(t)));const o=Y(),l=st(r);o.append(l),K(l,t.getNextSiblings()),n.insertBefore(i),n.insertAfter(o),n.replace(t)}}}function H(){const t=l();if(!c(t)||!t.isCollapsed())return!1;const e=t.anchor.getNode();if(!Z(e)||0!==e.getChildrenSize())return!1;const n=D(e),r=e.getParent();ot(r)||w(40);const i=r.getParent();let s;if(a(i))s=u(),n.insertAfter(s);else{if(!Z(i))return!1;s=Y(),i.insertAfter(s)}s.setTextStyle(t.style).setTextFormat(t.format).select();const o=e.getNextSiblings();if(o.length>0){const t=st(r.getListType());if(Z(s)){const e=Y();e.append(t),s.insertAfter(e)}else s.insertAfter(t);t.append(...o)}return function(t){let e=t;for(;null==e.getNextSibling()&&null==e.getPreviousSibling();){const t=e.getParent();if(null==t||!Z(t)&&!ot(t))break;e=t}e.remove()}(e),!0}function X(...t){const e=[];for(const n of t)if(n&&"string"==typeof n)for(const[t]of n.matchAll(/\S+/g))e.push(t);return e}class j extends m{static getType(){return"listitem"}static clone(t){return new j(t.__value,t.__checked,t.__key)}constructor(t,e,n){super(n),this.__value=void 0===t?1:t,this.__checked=e}createDOM(t){const e=document.createElement("li");return this.updateListItemDOM(null,e,t),e}updateListItemDOM(t,r,i){const s=this.getParent();ot(s)&&"check"===s.getListType()&&function(t,e,n,r){ot(e.getFirstChild())?(t.removeAttribute("role"),t.removeAttribute("tabIndex"),t.removeAttribute("aria-checked")):(t.setAttribute("role","checkbox"),t.setAttribute("tabIndex","-1"),n&&e.__checked===n.__checked||t.setAttribute("aria-checked",e.getChecked()?"true":"false"))}(r,this,t),r.value=this.__value,function(t,r,i){const s=[],o=[],l=r.list,c=l?l.listitem:void 0;let a;l&&l.nested&&(a=l.nested.listitem);void 0!==c&&s.push(...X(c));if(l){const t=i.getParent(),e=ot(t)&&"check"===t.getListType(),n=i.getChecked();e&&!n||o.push(l.listitemUnchecked),e&&n||o.push(l.listitemChecked),e&&s.push(n?l.listitemChecked:l.listitemUnchecked)}if(void 0!==a){const t=X(a);i.getChildren().some((t=>ot(t)))?s.push(...t):o.push(...t)}o.length>0&&e(t,...o);s.length>0&&n(t,...s)}(r,i.theme,this);const o=t?t.__style:"",l=this.__style;o!==l&&(""===l?r.removeAttribute("style"):r.style.cssText=l),function(t,e,n){const r=E(e.__textStyle);for(const e in r)t.style.setProperty(`--listitem-marker-${e}`,r[e]);if(n)for(const e in E(n.__textStyle))e in r||t.style.removeProperty(`--listitem-marker-${e}`)}(r,this,t)}updateDOM(t,e,n){const r=e;return this.updateListItemDOM(t,r,n),!1}static transform(){return t=>{if(Z(t)||w(144),null==t.__checked)return;const e=t.getParent();ot(e)&&"check"!==e.getListType()&&null!=t.getChecked()&&t.setChecked(void 0)}}static importDOM(){return{li:()=>({conversion:G,priority:0})}}static importJSON(t){return Y().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setValue(t.value).setChecked(t.checked)}exportDOM(t){const e=this.createDOM(t._config),n=this.getFormatType();n&&(e.style.textAlign=n);const r=this.getDirection();return r&&(e.dir=r),{element:e}}exportJSON(){return{...super.exportJSON(),checked:this.getChecked(),value:this.getValue()}}append(...t){for(let e=0;e<t.length;e++){const n=t[e];if(g(n)&&this.canMergeWith(n)){const t=n.getChildren();this.append(...t),n.remove()}else super.append(n)}return this}replace(t,e){if(Z(t))return super.replace(t);this.setIndent(0);const n=this.getParentOrThrow();if(!ot(n))return t;if(n.__first===this.getKey())n.insertBefore(t);else if(n.__last===this.getKey())n.insertAfter(t);else{const e=st(n.getListType());let r=this.getNextSibling();for(;r;){const t=r;r=r.getNextSibling(),e.append(t)}n.insertAfter(t),t.insertAfter(e)}return e&&(g(t)||w(139),this.getChildren().forEach((e=>{t.append(e)}))),this.remove(),0===n.getChildrenSize()&&n.remove(),t}insertAfter(t,e=!0){const n=this.getParentOrThrow();if(ot(n)||w(39),Z(t))return super.insertAfter(t,e);const r=this.getNextSiblings();if(n.insertAfter(t,e),0!==r.length){const i=st(n.getListType());r.forEach((t=>i.append(t))),t.insertAfter(i,e)}return t}remove(t){const e=this.getPreviousSibling(),n=this.getNextSibling();super.remove(t),e&&n&&R(e)&&R(n)&&(V(e.getFirstChild(),n.getFirstChild()),n.remove())}insertNewAfter(t,e=!0){const n=Y().updateFromJSON(this.exportJSON()).setChecked(!this.getChecked()&&void 0);return this.insertAfter(n,e),n}collapseAtStart(t){const e=u();this.getChildren().forEach((t=>e.append(t)));const n=this.getParentOrThrow(),r=n.getParentOrThrow(),i=Z(r);if(1===n.getChildrenSize())if(i)n.remove(),r.select();else{n.insertBefore(e),n.remove();const r=t.anchor,i=t.focus,s=e.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(e),this.remove();return!0}getValue(){return this.getLatest().__value}setValue(t){const e=this.getWritable();return e.__value=t,e}getChecked(){const t=this.getLatest();let e;const n=this.getParent();return ot(n)&&(e=n.getListType()),"check"===e?Boolean(t.__checked):void 0}setChecked(t){const e=this.getWritable();return e.__checked=t,e}toggleChecked(){const t=this.getWritable();return t.setChecked(!t.__checked)}getIndent(){const t=this.getParent();if(null===t||!this.isAttached())return this.getLatest().__indent;let e=t.getParentOrThrow(),n=0;for(;Z(e);)e=e.getParentOrThrow().getParentOrThrow(),n++;return n}setIndent(t){"number"!=typeof t&&w(117),(t=Math.floor(t))>=0||w(199);let e=this.getIndent();for(;e!==t;)e<t?($(this),e++):(q(this),e--);return this}canInsertAfter(t){return Z(t)}canReplaceWith(t){return Z(t)}canMergeWith(t){return Z(t)||_(t)}extractWithChild(t,e){if(!c(e))return!1;const n=e.anchor.getNode(),r=e.focus.getNode();return this.isParentOf(n)&&this.isParentOf(r)&&this.getTextContent().length===e.getTextContent().length}isParentRequired(){return!0}createParentElementNode(){return st("bullet")}canMergeWhenEmpty(){return!0}}function G(t){if(t.classList.contains("task-list-item"))for(const e of t.children)if("INPUT"===e.tagName)return Q(e);const e=t.getAttribute("aria-checked");return{node:Y("true"===e||"false"!==e&&void 0)}}function Q(t){if(!("checkbox"===t.getAttribute("type")))return{node:null};return{node:Y(t.hasAttribute("checked"))}}function Y(t){return y(new j(void 0,t))}function Z(t){return t instanceof j}class tt extends m{static getType(){return"list"}static clone(t){const e=t.__listType||it[t.__tag];return new tt(e,t.__start,t.__key)}constructor(t="number",e=1,n){super(n);const r=it[t]||t;this.__listType=r,this.__tag="number"===r?"ol":"ul",this.__start=e}getTag(){return this.__tag}setListType(t){const e=this.getWritable();return e.__listType=t,e.__tag="number"===t?"ol":"ul",e}getListType(){return this.__listType}getStart(){return this.__start}setStart(t){const e=this.getWritable();return e.__start=t,e}createDOM(t,e){const n=this.__tag,r=document.createElement(n);return 1!==this.__start&&r.setAttribute("start",String(this.__start)),r.__lexicalListType=this.__listType,et(r,t.theme,this),r}updateDOM(t,e,n){return t.__tag!==this.__tag||(et(e,n.theme,this),!1)}static transform(){return t=>{ot(t)||w(163),function(t){const e=t.getNextSibling();ot(e)&&t.getListType()===e.getListType()&&V(t,e)}(t),function(t){const e="check"!==t.getListType();let n=t.getStart();for(const r of t.getChildren())Z(r)&&(r.getValue()!==n&&r.setValue(n),e&&null!=r.getLatest().__checked&&r.setChecked(void 0),ot(r.getFirstChild())||n++)}(t)}}static importDOM(){return{ol:()=>({conversion:rt,priority:0}),ul:()=>({conversion:rt,priority:0})}}static importJSON(t){return st().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setListType(t.listType).setStart(t.start)}exportDOM(t){const e=this.createDOM(t._config,t);return r(e)&&(1!==this.__start&&e.setAttribute("start",String(this.__start)),"check"===this.__listType&&e.setAttribute("__lexicalListType","check")),{element:e}}exportJSON(){return{...super.exportJSON(),listType:this.getListType(),start:this.getStart(),tag:this.getTag()}}canBeEmpty(){return!1}canIndent(){return!1}splice(t,e,n){let r=n;for(let t=0;t<n.length;t++){const e=n[t];Z(e)||(r===n&&(r=[...n]),r[t]=Y().append(!g(e)||ot(e)||e.isInline()?e:C(e.getTextContent())))}return super.splice(t,e,r)}extractWithChild(t){return Z(t)}}function et(t,r,i){const s=[],o=[],l=r.list;if(void 0!==l){const t=l[`${i.__tag}Depth`]||[],e=I(i)-1,n=e%t.length,r=t[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(...X(r));for(let e=0;e<t.length;e++)e!==n&&o.push(i.__tag+e)}if(void 0!==a){const t=X(a);e>1?s.push(...t):o.push(...t)}}o.length>0&&e(t,...o),s.length>0&&n(t,...s)}function nt(t){const e=[];for(let n=0;n<t.length;n++){const r=t[n];if(Z(r)){e.push(r);const t=r.getChildren();t.length>1&&t.forEach((t=>{ot(t)&&e.push(J(t))}))}else e.push(J(r))}return e}function rt(t){const e=t.nodeName.toLowerCase();let n=null;if("ol"===e){n=st("number",t.start)}else"ul"===e&&(n=function(t){if("check"===t.getAttribute("__lexicallisttype")||t.classList.contains("contains-task-list"))return!0;for(const e of t.childNodes)if(r(e)&&e.hasAttribute("aria-checked"))return!0;return!1}(t)?st("check"):st("bullet"));return{after:nt,node:n}}const it={ol:"number",ul:"bullet"};function st(t="number",e=1){return y(new tt(t,e))}function ot(t){return t instanceof tt}const lt=T("INSERT_CHECK_LIST_COMMAND");function ct(t){return i(t.registerCommand(lt,(()=>(W("check"),!0)),S),t.registerCommand(v,(e=>dt(e,t,!1)),S),t.registerCommand(x,(e=>dt(e,t,!0)),S),t.registerCommand(k,(()=>{if(null!=ht()){const e=t.getRootElement();return null!=e&&e.focus(),!0}return!1}),S),t.registerCommand(b,(e=>{const n=ht();return!(null==n||!t.isEditable())&&(t.update((()=>{const t=N(n);Z(t)&&(e.preventDefault(),t.toggleChecked())})),!0)}),S),t.registerCommand(L,(e=>t.getEditorState().read((()=>{const n=l();if(c(n)&&n.isCollapsed()){const{anchor:r}=n,i="element"===r.type;if(i||0===r.offset){const n=r.getNode(),o=s(n,(t=>g(t)&&!t.isInline()));if(Z(o)){const r=o.getParent();if(ot(r)&&"check"===r.getListType()&&(i||o.getFirstDescendant()===n)){const n=t.getElementByKey(o.__key);if(null!=n&&document.activeElement!==n)return n.focus(),e.preventDefault(),!0}}}}return!1}))),S),t.registerRootListener(((t,e)=>{null!==t&&(t.addEventListener("click",ut),t.addEventListener("pointerdown",gt)),null!==e&&(e.removeEventListener("click",ut),e.removeEventListener("pointerdown",gt))})))}function at(t,e){const n=t.target;if(!r(n))return;const i=n.firstChild;if(r(i)&&("UL"===i.tagName||"OL"===i.tagName))return;const s=n.parentNode;if(!s||"check"!==s.__lexicalListType)return;const l=n.getBoundingClientRect(),c=t.pageX/o(n),a=window.getComputedStyle?window.getComputedStyle(n,"::before"):{width:"0px"},u=parseFloat(a.width);("rtl"===n.dir?c<l.right&&c>l.right-u:c>l.left&&c<l.left+u)&&e()}function ut(t){at(t,(()=>{if(r(t.target)){const e=t.target,n=F(e);null!=n&&n.isEditable()&&n.update((()=>{const t=N(e);Z(t)&&(e.focus(),t.toggleChecked())}))}}))}function gt(t){at(t,(()=>{t.preventDefault()}))}function ht(){const t=document.activeElement;return r(t)&&"LI"===t.tagName&&null!=t.parentNode&&"check"===t.parentNode.__lexicalListType?t:null}function dt(t,e,n){const r=ht();return null!=r&&e.update((()=>{const i=N(r);if(!Z(i))return;const s=function(t,e){let n=e?t.getPreviousSibling():t.getNextSibling(),r=t;for(;null==n&&Z(r);)r=r.getParentOrThrow().getParent(),null!=r&&(n=e?r.getPreviousSibling():r.getNextSibling());for(;Z(n);){const t=e?n.getLastChild():n.getFirstChild();if(!ot(t))return n;n=e?t.getLastChild():t.getFirstChild()}return null}(i,n);if(null!=s){s.selectStart();const n=e.getElementByKey(s.__key);null!=n&&(t.preventDefault(),setTimeout((()=>{n.focus()}),0))}})),!1}const ft=T("INSERT_UNORDERED_LIST_COMMAND"),pt=T("INSERT_ORDERED_LIST_COMMAND"),mt=T("REMOVE_LIST_COMMAND");function _t(t){return i(t.registerCommand(pt,(()=>(W("number"),!0)),S),t.registerCommand(ft,(()=>(W("bullet"),!0)),S),t.registerCommand(mt,(()=>(z(),!0)),S),t.registerCommand(P,(()=>H()),S),t.registerNodeTransform(j,(t=>{const e=t.getFirstChild();if(e){if(O(e)){const n=e.getStyle(),r=e.getFormat();t.getTextStyle()!==n&&t.setTextStyle(n),t.getTextFormat()!==r&&t.setTextFormat(r)}}else{const e=l();c(e)&&(e.style!==t.getTextStyle()||e.format!==t.getTextFormat())&&e.isCollapsed()&&t.is(e.anchor.getNode())&&t.setTextStyle(e.style).setTextFormat(e.format)}})),t.registerNodeTransform(A,(t=>{const e=t.getParent();if(Z(e)&&t.is(e.getFirstChild())){const n=t.getStyle(),r=t.getFormat();n===e.getTextStyle()&&r===e.getTextFormat()||e.setTextStyle(n).setTextFormat(r)}})))}function yt(t){const e=t=>{const e=t.getParent();if(ot(t.getFirstChild())||!ot(e))return;const n=s(t,(t=>Z(t)&&ot(t.getParent())&&Z(t.getPreviousSibling())));if(null===n&&t.getIndent()>0)t.setIndent(0);else if(Z(n)){const r=n.getPreviousSibling();if(Z(r)){const n=function(t){let e=t,n=e.getFirstChild();for(;ot(n);){const t=n.getLastChild();if(!Z(t))break;e=t,n=e.getFirstChild()}return e}(r),i=n.getParent();if(ot(i)){const n=I(i);n+1<I(e)&&t.setIndent(n)}}}};return t.registerNodeTransform(tt,(t=>{const n=[t];for(;n.length>0;){const t=n.shift();if(ot(t))for(const r of t.getChildren())if(Z(r)){e(r);const t=r.getFirstChild();ot(t)&&n.push(t)}}}))}function Ct(t,e){t.update((()=>W(e)))}function Tt(t){t.update((()=>z()))}export{Y as $createListItemNode,st as $createListNode,I as $getListDepth,H as $handleListInsertParagraph,W as $insertList,Z as $isListItemNode,ot as $isListNode,z as $removeList,lt as INSERT_CHECK_LIST_COMMAND,pt as INSERT_ORDERED_LIST_COMMAND,ft as INSERT_UNORDERED_LIST_COMMAND,j as ListItemNode,tt as ListNode,mt as REMOVE_LIST_COMMAND,Ct as insertList,ct as registerCheckList,_t as registerList,yt as registerListStrictIndentTransform,Tt as removeList};