@lexical/react
Version:
This package provides Lexical components and hooks for React applications.
10 lines (8 loc) • 6.68 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{useLexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import{createCommand as e,COMMAND_PRIORITY_LOW as n,KEY_ARROW_DOWN_COMMAND as o,KEY_ARROW_UP_COMMAND as l,KEY_ESCAPE_COMMAND as r,KEY_TAB_COMMAND as i,KEY_ENTER_COMMAND as u,$getSelection as s,$isRangeSelection as c,$getNodeByKey as a}from"lexical";import m,{useLayoutEffect as d,useEffect as p,useRef as f,useCallback as g,useState as h,useMemo as y}from"react";import{mergeRegister as w}from"@lexical/utils";import{jsx as v}from"react/jsx-runtime";const b="startTransition";const C="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,x=C?d:p;class E{key;ref;constructor(t){this.key=t,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(t){this.ref={current:t}}}const R=t=>{const e=document.getElementById("typeahead-menu");if(!e)return;const n=e.getBoundingClientRect();n.top+n.height>window.innerHeight&&e.scrollIntoView({block:"center"}),n.top<0&&e.scrollIntoView({block:"center"}),t.scrollIntoView({block:"nearest"})};function I(t,e){const n=t.getBoundingClientRect(),o=e.getBoundingClientRect();return n.top>=o.top-6&&n.top<=o.bottom+6}function O(e,n,o,l){const[r]=t();p(()=>{if(null!=n&&null!=e){const t=r.getRootElement(),e=null!=t?function(t){let e=getComputedStyle(t);const n="absolute"===e.position,o=/(auto|scroll)/;if("fixed"===e.position)return document.body;for(let l=t;l=l.parentElement;)if(e=getComputedStyle(l),(!n||"static"!==e.position)&&o.test(e.overflow+e.overflowY+e.overflowX))return l;return document.body}(t):document.body;let i=!1,u=I(n,e);const s=function(){i||(window.requestAnimationFrame(function(){o(),i=!1}),i=!0);const t=I(n,e);t!==u&&(u=t,null!=l&&l(t))},c=new ResizeObserver(o);return window.addEventListener("resize",o),document.addEventListener("scroll",s,{capture:!0,passive:!0}),c.observe(n),()=>{c.unobserve(n),window.removeEventListener("resize",o),document.removeEventListener("scroll",s,!0)}}},[n,r,l,o,e])}const A=e("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function S({close:t,editor:e,anchorElementRef:a,resolution:m,options:d,menuRenderFn:f,onSelectOption:v,shouldSplitNodeWithQuery:b=!1,commandPriority:C=n,preselectFirstItem:E=!0}){const[I,O]=h(null),S=m.match&&m.match.matchingString;p(()=>{E&&O(0)},[S,E]);const P=g(n=>{e.update(()=>{const e=null!=m.match&&b?function(t){const e=s();if(!c(e)||!e.isCollapsed())return null;const n=e.anchor;if("text"!==n.type)return null;const o=n.getNode();if(!o.isSimpleText())return null;const l=n.offset,r=o.getTextContent().slice(0,l),i=t.replaceableString.length,u=l-function(t,e,n){let o=n;for(let n=o;n<=e.length;n++)t.slice(-n)===e.substring(0,n)&&(o=n);return o}(r,t.matchingString,i);if(u<0)return null;let a;return 0===u?[a]=o.splitText(l):[,a]=o.splitText(u,l),a}(m.match):null;v(n,e,t,m.match?m.match.matchingString:"")})},[e,b,m.match,v,t]),T=g(t=>{const n=e.getRootElement();null!==n&&(n.setAttribute("aria-activedescendant","typeahead-item-"+t),O(t))},[e]);p(()=>()=>{const t=e.getRootElement();null!==t&&t.removeAttribute("aria-activedescendant")},[e]),x(()=>{null===d?O(null):null===I&&E&&T(0)},[d,I,T,E]),p(()=>w(e.registerCommand(A,({option:t})=>!(!t.ref||null==t.ref.current)&&(R(t.ref.current),!0),C)),[e,T,C]),p(()=>w(e.registerCommand(o,t=>{const n=t;if(null!==d&&d.length){const t=null===I?0:I!==d.length-1?I+1:0;T(t);const o=d[t];null!=o.ref&&o.ref.current&&e.dispatchCommand(A,{index:t,option:o}),n.preventDefault(),n.stopImmediatePropagation()}return!0},C),e.registerCommand(l,t=>{const e=t;if(null!==d&&d.length){const t=null===I?d.length-1:0!==I?I-1:d.length-1;T(t);const n=d[t];null!=n.ref&&n.ref.current&&R(n.ref.current),e.preventDefault(),e.stopImmediatePropagation()}return!0},C),e.registerCommand(r,e=>{const n=e;return n.preventDefault(),n.stopImmediatePropagation(),t(),!0},C),e.registerCommand(i,t=>{const e=t;return null!==d&&null!==I&&null!=d[I]&&(e.preventDefault(),e.stopImmediatePropagation(),P(d[I]),!0)},C),e.registerCommand(u,t=>null!==d&&null!==I&&null!=d[I]&&(null!==t&&(t.preventDefault(),t.stopImmediatePropagation()),P(d[I]),!0),C)),[P,t,e,d,I,T,C]);return f(a,y(()=>({options:d,selectOptionAndCleanUp:P,selectedIndex:I,setHighlightedIndex:O}),[P,I,d]),m.match?m.match.matchingString:"")}function P(t,e){null!=e&&(t.className=e),t.setAttribute("aria-label","Typeahead menu"),t.setAttribute("role","listbox"),t.style.display="block",t.style.position="absolute"}function T({options:e,nodeKey:o,onClose:l,onOpen:r,onSelectOption:i,menuRenderFn:u,anchorClassName:s,commandPriority:c=n,parent:d}){const[y]=t(),[w,x]=h(null),E=function(e,n,o,l=(C?document.body:void 0),r=!0){const[i]=t(),u=C?document.createElement("div"):null,s=f(u),c=g(()=>{if(null===s.current||void 0===l)return;s.current.style.top=s.current.style.bottom;const t=i.getRootElement(),n=s.current,u=n.firstChild;if(null!==t&&null!==e){const{left:i,top:c,width:a,height:m}=e.getRect(),d=s.current.offsetHeight;if(n.style.top=`${c+d+3+(r?window.pageYOffset:0)}px`,n.style.left=`${i+window.pageXOffset}px`,n.style.height=`${m}px`,n.style.width=`${a}px`,null!==u){u.style.top=`${c}`;const e=u.getBoundingClientRect(),o=e.height,l=e.width,s=t.getBoundingClientRect();i+l>s.right&&(n.style.left=`${s.right-l+window.pageXOffset}px`),(c+o>window.innerHeight||c+o>s.bottom)&&c-s.top>o+m&&(n.style.top=`${c-o-m+(r?window.pageYOffset:0)}px`)}n.isConnected||(P(n,o),l.append(n)),n.setAttribute("id","typeahead-menu"),t.setAttribute("aria-controls","typeahead-menu")}},[i,e,r,o,l]);p(()=>{const t=i.getRootElement();return null!==e&&c(),()=>{null!==t&&t.removeAttribute("aria-controls");const e=s.current;null!==e&&e.isConnected&&(e.remove(),e.removeAttribute("id"))}},[i,c,e]);const a=g(t=>{null!==e&&(t||n(null))},[e,n]);return O(e,s.current,c,a),null!=u&&u===s.current&&(P(u,o),null!=l&&l.append(u)),s}(w,x,s,d),R=g(()=>{x(null),null!=l&&null!==w&&l()},[l,w]),I=g(t=>{x(t),null!=r&&null===w&&r(t)},[r,w]),A=g(()=>{o?y.update(()=>{const t=a(o),e=y.getElementByKey(o);var n;null!=t&&null!=e&&null==w&&(n=()=>I({getRect:()=>e.getBoundingClientRect()}),b in m?m[b](n):n())}):null==o&&null!=w&&R()},[R,y,o,I,w]);return p(()=>{A()},[A,o]),p(()=>{if(null!=o)return y.registerUpdateListener(({dirtyElements:t})=>{t.get(o)&&A()})},[y,A,o]),null===E.current||null===w||null===y?null:v(S,{close:R,resolution:w,editor:y,anchorElementRef:E,options:e,menuRenderFn:u,onSelectOption:i,commandPriority:c})}export{T as LexicalNodeMenuPlugin,E as MenuOption};