UNPKG

@lexical/react

Version:

This package provides Lexical components and hooks for React applications.

10 lines (8 loc) 6.96 kB
/** * 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{mergeRegister as e,calculateZoomLevel as n}from"@lexical/utils";import{createCommand as o,KEY_ARROW_DOWN_COMMAND as l,KEY_ARROW_UP_COMMAND as r,KEY_ESCAPE_COMMAND as i,KEY_TAB_COMMAND as u,KEY_ENTER_COMMAND as c,COMMAND_PRIORITY_LOW as s,$getSelection as a,$isRangeSelection as m,isDOMNode as d}from"lexical";import*as p from"react";import{useLayoutEffect as f,useEffect as g,useState as h,useCallback as v,useMemo as w,useRef as y}from"react";import{jsx as b}from"react/jsx-runtime";const C="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,E=C?f:g;class R{constructor(t){this.key=t,this.ref={current:null},this.setRefElement=this.setRefElement.bind(this)}setRefElement(t){this.ref={current:t}}}const x=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 O(t,e){const n=t.getBoundingClientRect(),o=e.getBoundingClientRect();return n.top>o.top&&n.top<o.bottom}function I(e,n,o,l){const[r]=t();g((()=>{if(null!=n&&null!=e){const t=r.getRootElement(),e=null!=t?function(t,e){let n=getComputedStyle(t);const o="absolute"===n.position,l=/(auto|scroll)/;if("fixed"===n.position)return document.body;for(let e=t;e=e.parentElement;)if(n=getComputedStyle(e),(!o||"static"!==n.position)&&l.test(n.overflow+n.overflowY+n.overflowX))return e;return document.body}(t):document.body;let i=!1,u=O(n,e);const c=function(){i||(window.requestAnimationFrame((function(){o(),i=!1})),i=!0);const t=O(n,e);t!==u&&(u=t,null!=l&&l(t))},s=new ResizeObserver(o);return window.addEventListener("resize",o),document.addEventListener("scroll",c,{capture:!0,passive:!0}),s.observe(n),()=>{s.unobserve(n),window.removeEventListener("resize",o),document.removeEventListener("scroll",c,!0)}}}),[n,r,l,o,e])}const A=o("SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND");function S({close:t,editor:n,anchorElementRef:o,resolution:d,options:p,menuRenderFn:f,onSelectOption:y,shouldSplitNodeWithQuery:b=!1,commandPriority:C=s,preselectFirstItem:R=!0}){const[O,I]=h(null),S=d.match&&d.match.matchingString;g((()=>{R&&I(0)}),[S,R]);const L=v((e=>{n.update((()=>{const n=null!=d.match&&b?function(t){const e=a();if(!m(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 c;return 0===u?[c]=o.splitText(l):[,c]=o.splitText(u,l),c}(d.match):null;y(e,n,t,d.match?d.match.matchingString:"")}))}),[n,b,d.match,y,t]),P=v((t=>{const e=n.getRootElement();null!==e&&(e.setAttribute("aria-activedescendant","typeahead-item-"+t),I(t))}),[n]);g((()=>()=>{const t=n.getRootElement();null!==t&&t.removeAttribute("aria-activedescendant")}),[n]),E((()=>{null===p?I(null):null===O&&R&&P(0)}),[p,O,P,R]),g((()=>e(n.registerCommand(A,(({option:t})=>!(!t.ref||null==t.ref.current)&&(x(t.ref.current),!0)),C))),[n,P,C]),g((()=>e(n.registerCommand(l,(t=>{const e=t;if(null!==p&&p.length){const t=null===O?0:O!==p.length-1?O+1:0;P(t);const o=p[t];null!=o.ref&&o.ref.current&&n.dispatchCommand(A,{index:t,option:o}),e.preventDefault(),e.stopImmediatePropagation()}return!0}),C),n.registerCommand(r,(t=>{const e=t;if(null!==p&&p.length){const t=null===O?p.length-1:0!==O?O-1:p.length-1;P(t);const n=p[t];null!=n.ref&&n.ref.current&&x(n.ref.current),e.preventDefault(),e.stopImmediatePropagation()}return!0}),C),n.registerCommand(i,(e=>{const n=e;return n.preventDefault(),n.stopImmediatePropagation(),t(),!0}),C),n.registerCommand(u,(t=>{const e=t;return null!==p&&null!==O&&null!=p[O]&&(e.preventDefault(),e.stopImmediatePropagation(),L(p[O]),!0)}),C),n.registerCommand(c,(t=>null!==p&&null!==O&&null!=p[O]&&(null!==t&&(t.preventDefault(),t.stopImmediatePropagation()),L(p[O]),!0)),C))),[L,t,n,p,O,P,C]);return f(o,w((()=>({options:p,selectOptionAndCleanUp:L,selectedIndex:O,setHighlightedIndex:I})),[L,O,p]),d.match?d.match.matchingString:"")}function L(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 P({options:e,onWillOpen:o,onClose:l,onOpen:r,onSelectOption:i,menuRenderFn:u,anchorClassName:c,commandPriority:a=s,parent:m}){const[f]=t(),[w,E]=h(null),R=p.useRef(null),x=function(e,n,o,l=(C?document.body:void 0),r=!0){const[i]=t(),u=y(C?document.createElement("div"):null),c=v((()=>{if(null===u.current||void 0===l)return;u.current.style.top=u.current.style.bottom;const t=i.getRootElement(),n=u.current,c=n.firstChild;if(null!==t&&null!==e){const{left:i,top:s,width:a,height:m}=e.getRect(),d=u.current.offsetHeight;if(n.style.top=`${s+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!==c){c.style.top=`${s}`;const e=c.getBoundingClientRect(),o=e.height,l=e.width,u=t.getBoundingClientRect();i+l>u.right&&(n.style.left=`${u.right-l+window.pageXOffset}px`),(s+o>window.innerHeight||s+o>u.bottom)&&s-u.top>o+m&&(n.style.top=`${s-o-m+(r?window.pageYOffset:0)}px`)}n.isConnected||(L(n,o),l.append(n)),n.setAttribute("id","typeahead-menu"),u.current=n,t.setAttribute("aria-controls","typeahead-menu")}}),[i,e,r,o,l]);g((()=>{const t=i.getRootElement();return null!==e&&c(),()=>{null!==t&&t.removeAttribute("aria-controls");const e=u.current;null!==e&&e.isConnected&&(e.remove(),e.removeAttribute("id"))}}),[i,c,e]);const s=v((t=>{null!==e&&(t||n(null))}),[e,n]);I(e,u.current,c,s);const a=u.current;return null!=a&&(L(a,o),null!=l&&l.append(a)),u}(w,E,c,m),O=v((()=>{E(null),null!=l&&null!==w&&l()}),[l,w]),A=v((t=>{E(t),null!=r&&null===w&&r(t)}),[r,w]),P=v((t=>{t.preventDefault(),null!=o&&o(t);const e=n(t.target);A({getRect:()=>new DOMRect(t.clientX/e,t.clientY/e,1,1)})}),[A,o]),D=v((t=>{null!==w&&null!=R.current&&null!=t.target&&d(t.target)&&!R.current.contains(t.target)&&O()}),[O,w]);return g((()=>{const t=f.getRootElement();if(t)return t.addEventListener("contextmenu",P),()=>t.removeEventListener("contextmenu",P)}),[f,P]),g((()=>(document.addEventListener("click",D),()=>document.removeEventListener("click",D))),[f,D]),null===x.current||null===w||null===f?null:b(S,{close:O,resolution:w,editor:f,anchorElementRef:x,options:e,menuRenderFn:(t,e)=>u(t,e,{setMenuRef:t=>{R.current=t}}),onSelectOption:i,commandPriority:a})}export{P as LexicalContextMenuPlugin,R as MenuOption};