@lexical/selection
Version:
This package contains utilities and helpers for handling Lexical selection.
10 lines (8 loc) • 11.2 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.
*
*/
;var e=require("lexical");function t(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.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 n(e){let t=e;for(;null!=t;){if(t.nodeType===Node.TEXT_NODE)return t;t=t.firstChild}return null}function o(e){const t=e.parentNode;if(null==t)throw new Error("Should never happen");return[t,Array.from(t.childNodes).indexOf(e)]}function r(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function i(t){const n=e.$getEditor().getElementByKey(t.getKey());if(null===n)return null;const o=n.ownerDocument.defaultView;return null===o?null:o.getComputedStyle(n)}function s(t){return i(e.$isRootNode(t)?t:t.getParentOrThrow())}function l(t,n,o){let r=n.getNode(),i=o;if(e.$isElementNode(r)){const e=r.getDescendantByIndex(n.offset);null!==e&&(r=e)}for(;i>0&&null!==r;){if(e.$isElementNode(r)){const e=r.getLastDescendant();null!==e&&(r=e)}let o=r.getPreviousSibling(),s=0;if(null===o){let e=r.getParentOrThrow(),t=e.getPreviousSibling();for(;null===t;){if(e=e.getParent(),null===e){o=null;break}t=e.getPreviousSibling()}null!==e&&(s=e.isInline()?0:2,o=t)}let l=r.getTextContent();""===l&&e.$isElementNode(r)&&!r.isInline()&&(l="\n\n");const c=l.length;if(!e.$isTextNode(r)||i>=c){const t=r.getParent();r.remove(),null==t||0!==t.getChildrenSize()||e.$isRootNode(t)||t.remove(),i-=c+s,r=o}else{const o=r.getKey(),s=t.getEditorState().read(()=>{const t=e.$getNodeByKey(o);return e.$isTextNode(t)&&t.isSimpleText()?t.getTextContent():null}),f=c-i,d=l.slice(0,f);if(null!==s&&s!==l){const t=e.$getPreviousSelection();let n=r;if(r.isSimpleText())r.setTextContent(s);else{const t=e.$createTextNode(s);r.replace(t),n=t}if(e.$isRangeSelection(t)&&t.isCollapsed()){const e=t.anchor.offset;n.select(e,e)}}else if(r.isSimpleText()){const e=n.key===o;let t=n.offset;t<i&&(t=c);const s=e?t-i:0,l=e?t:f;if(e&&0===s){const[e]=r.splitText(s,l);e.remove()}else{const[,e]=r.splitText(s,l);e.remove()}}else{const t=e.$createTextNode(d);r.replace(t)}i=0}}}const c=()=>{};function f(n,o){(e.$isRangeSelection(n)?n.isCollapsed():e.$isTextNode(n)||e.$isElementNode(n))||t(280);const i=e.getStyleObjectFromCSS(e.$isRangeSelection(n)?n.style:e.$isTextNode(n)?n.getStyle():n.getTextStyle()),s=r(Object.entries(o).reduce((e,[t,o])=>("function"==typeof o?e[t]=o(i[t],n):null===o?delete e[t]:e[t]=o,e),{...i}));e.$isRangeSelection(n)||e.$isTextNode(n)?n.setStyle(s):n.setTextStyle(s)}function d(t){const n=e.$getSelection();if(!n)return;const o=new Map,r=e=>o.get(e.getKey())||[0,e.getTextContentSize()];if(e.$isRangeSelection(n))for(const t of e.$caretRangeFromSelection(n).getTextSlices())t&&o.set(t.caret.origin.getKey(),t.getSliceIndices());const i=n.getNodes();for(const n of i){if(!e.$isTextNode(n)||!n.canHaveFormat())continue;const[o,i]=r(n);if(i!==o)if(e.$isTokenOrSegmented(n)||0===o&&i===n.getTextContentSize())t(n);else{t(n.splitText(o,i)[0===o?0:1])}}e.$isRangeSelection(n)&&"text"===n.anchor.type&&"text"===n.focus.type&&n.anchor.key===n.focus.key&&a(n)}function a(e){if(e.isBackward()){const{anchor:t,focus:n}=e,{key:o,offset:r,type:i}=t;t.set(n.key,n.offset,n.type),n.set(o,r,i)}}function g(e,t){const n=e.getFormatType(),o=e.getIndent();n!==t.getFormatType()&&t.setFormat(n),o!==t.getIndent()&&t.setIndent(o)}function u(e){return e.getNode().isAttached()}function p(t){let n=t;for(;null!==n&&!e.$isRootOrShadowRoot(n);){const e=n.getLatest(),t=n.getParent();0===e.getChildrenSize()&&n.remove(!0),n=t}}function $(n,o,r,i,s=null){if(0===o.length)return;const l=o[0],c=new Map,f=[];let d=e.$isElementNode(l)?l:l.getParentOrThrow();d.isInline()&&(d=d.getParentOrThrow());let a=!1;for(;null!==d;){const t=d.getPreviousSibling();if(null!==t){d=t,a=!0;break}if(d=d.getParentOrThrow(),e.$isRootOrShadowRoot(d))break}const g=new Set;for(let t=0;t<r;t++){const n=o[t];e.$isElementNode(n)&&0===n.getChildrenSize()&&g.add(n.getKey())}const $=new Set;for(let n=0;n<r;n++){const r=o[n];let s=r.getParent();if(null!==s&&s.isInline()&&(s=s.getParent()),null!==s&&e.$isLeafNode(r)&&!$.has(r.getKey())){const t=s.getKey();if(void 0===c.get(t)){const n=i();n.setFormat(s.getFormatType()),n.setIndent(s.getIndent()),f.push(n),c.set(t,n);const o=s.getChildren();n.splice(n.getChildrenSize(),0,o);for(const t of o)if($.add(t.getKey()),e.$isElementNode(t))for(const e of t.getChildrenKeys())$.add(e);p(s)}}else if(g.has(r.getKey())){e.$isElementNode(r)||t(179);const n=i();n.setFormat(r.getFormatType()),n.setIndent(r.getIndent()),f.push(n),r.remove(!0)}}if(null!==s)for(let e=0;e<f.length;e++){const t=f[e];s.append(t)}let S=null;if(e.$isRootOrShadowRoot(d))if(a)if(null!==s)d.insertAfter(s);else for(let e=f.length-1;e>=0;e--){const t=f[e];d.insertAfter(t)}else{const t=d.getFirstChild();if(e.$isElementNode(t)&&(d=t),null===t)if(s)d.append(s);else for(let e=0;e<f.length;e++){const t=f[e];d.append(t),S=t}else if(null!==s)t.insertBefore(s);else for(let e=0;e<f.length;e++){const n=f[e];t.insertBefore(n),S=n}}else if(s)d.insertAfter(s);else for(let e=f.length-1;e>=0;e--){const t=f[e];d.insertAfter(t),S=t}const h=e.$getPreviousSelection();e.$isRangeSelection(h)&&u(h.anchor)&&u(h.focus)?e.$setSelection(h.clone()):null!==S?S.selectEnd():n.dirty=!0}function S(e){const t=h(e);return null!==t&&"vertical-rl"===t.writingMode}function h(t){const n=t.anchor.getNode();return e.$isElementNode(n)?i(n):s(n)}function m(e,t,n,o){e.modify(t?"extend":"move",n,o)}function N(e){const t=h(e);return null!==t&&"rtl"===t.direction}function y(t,n,o){const r=t.getStyle(),i=e.getStyleObjectFromCSS(r);return null!==i&&i[n]||o}const x=e.getStyleObjectFromCSS,T=l;exports.$cloneWithProperties=e.$cloneWithProperties,exports.$selectAll=e.$selectAll,exports.$addNodeStyle=c,exports.$copyBlockFormatIndent=g,exports.$ensureForwardRangeSelection=a,exports.$forEachSelectedTextNode=d,exports.$getComputedStyleForElement=i,exports.$getComputedStyleForParent=s,exports.$getSelectionStyleValueForProperty=function(t,n,o=""){let r=null;const i=t.getNodes();let s,l;if(e.$isRangeSelection(t)){if(t.isCollapsed()&&""!==t.style){const o=e.getStyleObjectFromCSS(t.style);if(null!==o&&n in o)return o[n]}const{anchor:o,focus:r}=t,i=t.isBackward(),c=i?r.getNode():o.getNode(),f=i?o.getNode():r.getNode(),d=i?r.offset:o.offset,a=i?o.offset:r.offset;e.$isTextNode(c)&&d===c.getTextContentSize()&&(s=c),0===a&&(l=f)}for(let t=0;t<i.length;t++){const c=i[t];if(e.$isTextNode(c)&&!c.is(0===t?s:l)){const e=y(c,n,o);if(null===r)r=e;else if(r!==e){r="";break}}}return null===r?o:r},exports.$isAtNodeEnd=function(n){if("text"===n.type)return n.offset===n.getNode().getTextContentSize();const o=n.getNode();return e.$isElementNode(o)||t(177),n.offset===o.getChildrenSize()},exports.$isParentElementRTL=N,exports.$isParentRTL=function(e){const t=s(e);return null!==t&&"rtl"===t.direction},exports.$moveCaretSelection=m,exports.$moveCharacter=function(e,t,n){const o=N(e);let r;r=S(e)||o?!n:n,m(e,t,r,"character")},exports.$patchStyleText=function(t,n){if(e.$isRangeSelection(t)&&t.isCollapsed()){f(t,n);const o=t.anchor.getNode();e.$isElementNode(o)&&o.isEmpty()&&f(o,n)}d(e=>{f(e,n)});const o=t.getNodes();if(o.length>0){const t=new Set;for(const r of o){if(!e.$isElementNode(r)||!r.canBeEmpty()||0!==r.getChildrenSize())continue;const o=r.getKey();t.has(o)||(t.add(o),f(r,n))}}},exports.$setBlocksType=function(t,n,o=g){if(!t)return;const r=t.getStartEndPoints();let i=!1,s=null;const l=new Map;if(r){const[t,n]=r,o=e.$findMatchingParent(t.getNode(),e.INTERNAL_$isBlock);s=e.$findMatchingParent(n.getNode(),e.INTERNAL_$isBlock),i=e.$isElementNode(s)&&!s.is(o)&&function(t,n){if(0!==t.offset)return!1;let o=t.getNode();if(e.$isElementNode(o)&&o.isEmpty())return!1;for(;!o.is(n);){if(null!==o.getPreviousSibling())return!1;const e=o.getParent();if(null===e)return!1;o=e}return!0}(n,s),e.$isElementNode(o)&&l.set(o.getKey(),o),e.$isElementNode(s)&&!i&&l.set(s.getKey(),s)}for(const n of t.getNodes())if(e.$isElementNode(n)&&e.INTERNAL_$isBlock(n)){if(i&&n.is(s))continue;l.set(n.getKey(),n)}else if(!r){const t=e.$findMatchingParent(n,e.INTERNAL_$isBlock);e.$isElementNode(t)&&l.set(t.getKey(),t)}for(const e of l.values()){const t=n();o(e,t),e.replace(t,!0)}},exports.$shouldOverrideDefaultCharacterSelection=function(t,n){let o=S(t)?!n:n;N(t)&&(o=!o);const r=e.$caretFromPoint(t.focus,o?"previous":"next");if(e.$isExtendableTextPointCaret(r))return!1;for(const t of e.$extendCaretToRange(r)){if(e.$isChildCaret(t))return!t.origin.isInline();if(!e.$isElementNode(t.origin)){if(e.$isDecoratorNode(t.origin))return!0;break}}return!1},exports.$sliceSelectedTextNodeContent=function(t,n,o="self"){const r=t.getStartEndPoints();if(n.isSelected(t)&&!e.$isTokenOrSegmented(n)&&null!==r){const[i,s]=r,l=t.isBackward(),c=i.getNode(),f=s.getNode(),d=n.is(c),a=n.is(f);if(d||a){const[r,i]=e.$getCharacterOffsets(t),s=c.is(f),d=n.is(l?f:c),a=n.is(l?c:f);let g,u=0;if(s)u=r>i?i:r,g=r>i?r:i;else if(d){u=l?i:r,g=void 0}else if(a){u=0,g=l?r:i}const p=n.__text.slice(u,g);p!==n.__text&&("clone"===o&&(n=e.$cloneWithPropertiesEphemeral(n)),n.__text=p)}}return n},exports.$trimTextContentFromAnchor=l,exports.$wrapNodes=function(t,n,o=null){const r=t.getStartEndPoints(),i=r?r[0]:null,s=t.getNodes(),l=s.length;if(null!==i&&(0===l||1===l&&"element"===i.type&&0===i.getNode().getChildrenSize())){const e="text"===i.type?i.getNode().getParentOrThrow():i.getNode(),t=e.getChildren();let r=n();return r.setFormat(e.getFormatType()),r.setIndent(e.getIndent()),t.forEach(e=>r.append(e)),o&&(r=o.append(r)),void e.replace(r)}let c=null,f=[];for(let r=0;r<l;r++){const i=s[r];e.$isRootOrShadowRoot(i)?($(t,f,f.length,n,o),f=[],c=i):null===c||null!==c&&e.$hasAncestor(i,c)?f.push(i):($(t,f,f.length,n,o),f=[i])}$(t,f,f.length,n,o)},exports.createDOMRange=function(t,r,i,s,l){const c=r.getKey(),f=s.getKey(),d=document.createRange();let a=t.getElementByKey(c),g=t.getElementByKey(f),u=i,p=l;if(e.$isTextNode(r)&&(a=n(a)),e.$isTextNode(s)&&(g=n(g)),void 0===r||void 0===s||null===a||null===g)return null;"BR"===a.nodeName&&([a,u]=o(a)),"BR"===g.nodeName&&([g,p]=o(g));const $=a.firstChild;a===g&&null!=$&&"BR"===$.nodeName&&0===u&&0===p&&(p=1);try{d.setStart(a,u),d.setEnd(g,p)}catch(e){return null}return!d.collapsed||u===p&&c===f||(d.setStart(g,p),d.setEnd(a,u)),d},exports.createRectsFromDOMRange=function(e,t){const n=e.getRootElement();if(null===n)return[];const o=n.getBoundingClientRect(),r=getComputedStyle(n),i=parseFloat(r.paddingLeft)+parseFloat(r.paddingRight),s=Array.from(t.getClientRects());let l,c=s.length;s.sort((e,t)=>{const n=e.top-t.top;return Math.abs(n)<=3?e.left-t.left:n});for(let e=0;e<c;e++){const t=s[e],n=l&&l.top<=t.top&&l.top+l.height>t.top&&l.left+l.width>t.left,r=t.width+i===o.width;n||r?(s.splice(e--,1),c--):l=t}return s},exports.getCSSFromStyleObject=r,exports.getStyleObjectFromCSS=x,exports.trimTextContentFromAnchor=T;