@lexical/react 0.4.1 → 0.5.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/DEPRECATED_useLexical.js.flow +0 -1
  2. package/DEPRECATED_useLexicalDecorators.d.ts +2 -1
  3. package/DEPRECATED_useLexicalDecorators.dev.js +125 -10
  4. package/DEPRECATED_useLexicalDecorators.js.flow +8 -0
  5. package/DEPRECATED_useLexicalDecorators.prod.js +6 -2
  6. package/DEPRECATED_useLexicalPlainText.d.ts +2 -2
  7. package/DEPRECATED_useLexicalPlainText.dev.js +4 -4
  8. package/DEPRECATED_useLexicalPlainText.js.flow +0 -1
  9. package/DEPRECATED_useLexicalPlainText.prod.js +2 -2
  10. package/DEPRECATED_useLexicalRichText.d.ts +2 -2
  11. package/DEPRECATED_useLexicalRichText.dev.js +4 -4
  12. package/DEPRECATED_useLexicalRichText.js.flow +0 -1
  13. package/DEPRECATED_useLexicalRichText.prod.js +2 -2
  14. package/LexicalAutoEmbedPlugin.d.ts +3 -13
  15. package/LexicalAutoEmbedPlugin.dev.js +3 -19
  16. package/LexicalAutoEmbedPlugin.js.flow +3 -11
  17. package/LexicalAutoEmbedPlugin.prod.js +4 -5
  18. package/LexicalAutoLinkPlugin.dev.js +49 -45
  19. package/LexicalAutoLinkPlugin.prod.js +6 -6
  20. package/LexicalBlockWithAlignableContents.dev.js +1 -1
  21. package/LexicalBlockWithAlignableContents.prod.js +1 -1
  22. package/LexicalCollaborationPlugin.d.ts +5 -1
  23. package/LexicalCollaborationPlugin.dev.js +54 -16
  24. package/LexicalCollaborationPlugin.js.flow +1 -0
  25. package/LexicalCollaborationPlugin.prod.js +9 -9
  26. package/LexicalComposer.d.ts +1 -2
  27. package/LexicalComposer.dev.js +15 -1
  28. package/LexicalComposer.js.flow +14 -7
  29. package/LexicalComposer.prod.js +3 -3
  30. package/LexicalContentEditable.dev.js +1 -1
  31. package/LexicalContentEditable.prod.js +1 -1
  32. package/LexicalHorizontalRuleNode.d.ts +4 -2
  33. package/LexicalHorizontalRuleNode.dev.js +25 -3
  34. package/LexicalHorizontalRuleNode.js.flow +0 -1
  35. package/LexicalHorizontalRuleNode.prod.js +5 -5
  36. package/LexicalNestedComposer.d.ts +4 -2
  37. package/LexicalNestedComposer.dev.js +25 -3
  38. package/LexicalNestedComposer.js.flow +1 -0
  39. package/LexicalNestedComposer.prod.js +3 -3
  40. package/LexicalOnChangePlugin.d.ts +1 -2
  41. package/LexicalOnChangePlugin.dev.js +3 -9
  42. package/LexicalOnChangePlugin.js.flow +0 -2
  43. package/LexicalOnChangePlugin.prod.js +2 -2
  44. package/LexicalPlainTextPlugin.d.ts +3 -3
  45. package/LexicalPlainTextPlugin.dev.js +111 -20
  46. package/LexicalPlainTextPlugin.js.flow +3 -1
  47. package/LexicalPlainTextPlugin.prod.js +6 -4
  48. package/LexicalRichTextPlugin.d.ts +3 -3
  49. package/LexicalRichTextPlugin.dev.js +111 -20
  50. package/LexicalRichTextPlugin.js.flow +3 -1
  51. package/LexicalRichTextPlugin.prod.js +6 -4
  52. package/LexicalTableOfContents__EXPERIMENTAL.js.flow +1 -1
  53. package/LexicalTablePlugin.dev.js +1 -1
  54. package/LexicalTablePlugin.prod.js +1 -1
  55. package/LexicalTreeView.dev.js +28 -13
  56. package/LexicalTreeView.prod.js +14 -13
  57. package/LexicalTypeaheadMenuPlugin.d.ts +20 -8
  58. package/LexicalTypeaheadMenuPlugin.dev.js +200 -57
  59. package/LexicalTypeaheadMenuPlugin.js.flow +19 -21
  60. package/LexicalTypeaheadMenuPlugin.prod.js +18 -14
  61. package/package.json +19 -19
  62. package/shared/ReactErrorBoundary.d.ts +63 -0
  63. package/shared/useDecorators.d.ts +8 -1
  64. package/shared/usePlainTextSetup.d.ts +1 -2
  65. package/shared/useRichTextSetup.d.ts +1 -2
  66. package/shared/useYjsCollaboration.d.ts +4 -1
@@ -4,17 +4,18 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- 'use strict';var l=require("@lexical/link"),q=require("@lexical/mark"),t=require("lexical"),D=require("react");let E=Object.freeze({"\t":"\\t","\n":"\\n"}),F=new RegExp(Object.keys(E).join("|"),"g"),G=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"\u251c",isLastChild:"\u2514",selectedChar:"^",selectedLine:">"});
8
- function H(a){let b="",c=I(a),d=a.anchor;a=a.focus;let e=d.offset,g=a.offset;b=b+`: range ${""!==c?`{ ${c} }`:""}`+`\n \u251c anchor { key: ${d.key}, offset: ${null===e?"null":e}, type: ${d.type} }`;return b+=`\n \u2514 focus { key: ${a.key}, offset: ${null===g?"null":g}, type: ${a.type} }`}
9
- function K(a){let b=" root\n";a=a.read(()=>{const c=t.$getSelection();L(t.$getRoot(),(d,e)=>{const g=`(${d.getKey()})`,h=d.getType()||"",n=d.isSelected(),w=q.$isMarkNode(d)?` id: [ ${d.getIDs().join(", ")} ] `:"";var v=b,r=n?G.selectedLine:" ",x=e.join(" ");if(t.$isTextNode(d)){var f=d.getTextContent(!0);var m=0===f.length?"(empty)":`"${M(f)}"`;f=[I(d),N(d),O(d)].filter(Boolean).join(", ");f=[m,0!==f.length?`{ ${f} }`:null].filter(Boolean).join(" ").trim()}else if(l.$isLinkNode(d)){f=d.getURL();f=
10
- 0===f.length?"(empty)":`"${M(f)}"`;m=d.getTarget();null!=m&&(m="target: "+m);var y=Boolean;let u=d.getRel();null!=u&&(u="rel: "+u);m=[m,u].filter(y).join(", ");f=[f,0!==m.length?`{ ${m} }`:null].filter(Boolean).join(" ").trim()}else f="";b=v+`${r} ${x} ${g} ${h} ${w} ${f}\n`;b+=P({indent:e,isSelected:n,node:d,nodeKeyDisplay:g,selection:c,typeDisplay:h})});return null===c?": null":t.$isRangeSelection(c)?H(c):t.$isGridSelection(c)?`: grid\n \u2514 { grid: ${c.gridKey}, anchorCell: ${c.anchor.key}, focusCell: ${c.focus.key} }`:
11
- `: node\n \u2514 [${Array.from(c._nodes).join(", ")}]`});return b+"\n selection"+a}function L(a,b,c=[]){a=a.getChildren();let d=a.length;a.forEach((e,g)=>{b(e,c.concat(g===d-1?G.isLastChild:G.hasNextSibling));t.$isElementNode(e)&&L(e,b,c.concat(g===d-1?G.ancestorIsLastChild:G.ancestorHasNextSibling))})}function M(a){return Object.entries(E).reduce((b,[c,d])=>b.replace(new RegExp(c,"g"),String(d)),a)}
12
- let Q=[a=>a.hasFormat("bold")&&"Bold",a=>a.hasFormat("code")&&"Code",a=>a.hasFormat("italic")&&"Italic",a=>a.hasFormat("strikethrough")&&"Strikethrough",a=>a.hasFormat("subscript")&&"Subscript",a=>a.hasFormat("superscript")&&"Superscript",a=>a.hasFormat("underline")&&"Underline"],R=[a=>a.isDirectionless()&&"Directionless",a=>a.isUnmergeable()&&"Unmergeable"],S=[a=>a.isToken()&&"Token",a=>a.isSegmented()&&"Segmented",a=>a.isInert()&&"Inert"];
13
- function N(a){let b=R.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="detail: "+b);return b}function O(a){let b=S.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="mode: "+b);return b}function I(a){let b=Q.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="format: "+b);return b}
14
- function P({indent:a,isSelected:b,node:c,nodeKeyDisplay:d,selection:e,typeDisplay:g}){if(!t.$isTextNode(c)||!t.$isRangeSelection(e)||!b||t.$isElementNode(c))return"";b=e.anchor;var h=e.focus;if(""===c.getTextContent()||b.getNode()===e.focus.getNode()&&b.offset===h.offset)return"";h=e.anchor;let n=e.focus,w=c.getTextContent(!0),v=w.length;b=e=-1;if("text"===h.type&&"text"===n.type){let f=h.getNode(),m=n.getNode();f===m&&c===f&&h.offset!==n.offset?[e,b]=h.offset<n.offset?[h.offset,n.offset]:[n.offset,
15
- h.offset]:c===f?[e,b]=f.isBefore(m)?[h.offset,v]:[0,h.offset]:c===m?[e,b]=m.isBefore(f)?[n.offset,v]:[0,n.offset]:[e,b]=[0,v]}c=(w.slice(0,e).match(F)||[]).length;h=(w.slice(e,b).match(F)||[]).length;let [r,x]=[e+c,b+c+h];if(r===x)return"";c=a[a.length-1]===G.hasNextSibling?G.ancestorHasNextSibling:G.ancestorIsLastChild;a=[...a.slice(0,a.length-1),c];c=Array(r+1).fill(" ");e=Array(x-r).fill(G.selectedChar);d=Array(d.length+(g.length+3)).fill(" ");return[G.selectedLine,a.join(" "),[...d,...c,...e].join("")].join(" ")+
7
+ 'use strict';var k=require("@lexical/link"),r=require("@lexical/mark"),v=require("@lexical/utils"),C=require("lexical"),D=require("react");let E=Object.freeze({"\t":"\\t","\n":"\\n"}),F=new RegExp(Object.keys(E).join("|"),"g"),G=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"\u251c",isLastChild:"\u2514",selectedChar:"^",selectedLine:">"});
8
+ function H(a){let c="",e=K(a),l=a.anchor;a=a.focus;let f=l.offset,b=a.offset;c=c+`: range ${""!==e?`{ ${e} }`:""}`+`\n \u251c anchor { key: ${l.key}, offset: ${null===f?"null":f}, type: ${l.type} }`;return c+=`\n \u2514 focus { key: ${a.key}, offset: ${null===b?"null":b}, type: ${a.type} }`}
9
+ function L(a,c,e,l){let f=" root\n";a=a.read(()=>{const b=C.$getSelection();M(C.$getRoot(),(d,n)=>{const x=`(${d.getKey()})`,t=d.getType()||"",q=d.isSelected(),z=r.$isMarkNode(d)?` id: [ ${d.getIDs().join(", ")} ] `:"";var m=f,w=q?G.selectedLine:" ",A=n.join(" ");if(C.$isTextNode(d)){var h=d.getTextContent();var p=0===h.length?"(empty)":`"${N(h)}"`;h=[K(d),O(d),P(d)].filter(Boolean).join(", ");h=[p,0!==h.length?`{ ${h} }`:null].filter(Boolean).join(" ").trim()}else if(k.$isLinkNode(d)){h=d.getURL();
10
+ h=0===h.length?"(empty)":`"${N(h)}"`;p=d.getTarget();null!=p&&(p="target: "+p);var y=Boolean;let g=d.getRel();null!=g&&(g="rel: "+g);p=[p,g].filter(y).join(", ");h=[h,0!==p.length?`{ ${p} }`:null].filter(Boolean).join(" ").trim()}else h="";f=m+`${w} ${A} ${x} ${t} ${z} ${h}\n`;f+=Q({indent:n,isSelected:q,node:d,nodeKeyDisplay:x,selection:b,typeDisplay:t})});return null===b?": null":C.$isRangeSelection(b)?H(b):C.DEPRECATED_$isGridSelection(b)?`: grid\n \u2514 { grid: ${b.gridKey}, anchorCell: ${b.anchor.key}, focusCell: ${b.focus.key} }`:
11
+ `: node\n \u2514 [${Array.from(b._nodes).join(", ")}]`});f+="\n selection"+a;f+="\n\n editor:";f+=`\n \u2514 namespace ${c.namespace}`;null!==e&&(f+=`\n \u2514 compositionKey ${e}`);return f+=`\n \u2514 editable ${String(l)}`}function M(a,c,e=[]){a=a.getChildren();let l=a.length;a.forEach((f,b)=>{c(f,e.concat(b===l-1?G.isLastChild:G.hasNextSibling));C.$isElementNode(f)&&M(f,c,e.concat(b===l-1?G.ancestorIsLastChild:G.ancestorHasNextSibling))})}
12
+ function N(a){return Object.entries(E).reduce((c,[e,l])=>c.replace(new RegExp(e,"g"),String(l)),a)}
13
+ let R=[a=>a.hasFormat("bold")&&"Bold",a=>a.hasFormat("code")&&"Code",a=>a.hasFormat("italic")&&"Italic",a=>a.hasFormat("strikethrough")&&"Strikethrough",a=>a.hasFormat("subscript")&&"Subscript",a=>a.hasFormat("superscript")&&"Superscript",a=>a.hasFormat("underline")&&"Underline"],S=[a=>a.isDirectionless()&&"Directionless",a=>a.isUnmergeable()&&"Unmergeable"],T=[a=>a.isToken()&&"Token",a=>a.isSegmented()&&"Segmented"];
14
+ function O(a){let c=S.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="detail: "+c);return c}function P(a){let c=T.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="mode: "+c);return c}function K(a){let c=R.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="format: "+c);return c}
15
+ function Q({indent:a,isSelected:c,node:e,nodeKeyDisplay:l,selection:f,typeDisplay:b}){if(!C.$isTextNode(e)||!C.$isRangeSelection(f)||!c||C.$isElementNode(e))return"";c=f.anchor;var d=f.focus;if(""===e.getTextContent()||c.getNode()===f.focus.getNode()&&c.offset===d.offset)return"";d=f.anchor;let n=f.focus,x=e.getTextContent(),t=x.length;c=f=-1;if("text"===d.type&&"text"===n.type){let m=d.getNode(),w=n.getNode();m===w&&e===m&&d.offset!==n.offset?[f,c]=d.offset<n.offset?[d.offset,n.offset]:[n.offset,
16
+ d.offset]:e===m?[f,c]=m.isBefore(w)?[d.offset,t]:[0,d.offset]:e===w?[f,c]=w.isBefore(m)?[n.offset,t]:[0,n.offset]:[f,c]=[0,t]}e=(x.slice(0,f).match(F)||[]).length;d=(x.slice(f,c).match(F)||[]).length;let [q,z]=[f+e,c+e+d];if(q===z)return"";e=a[a.length-1]===G.hasNextSibling?G.ancestorHasNextSibling:G.ancestorIsLastChild;a=[...a.slice(0,a.length-1),e];e=Array(q+1).fill(" ");f=Array(z-q).fill(G.selectedChar);l=Array(l.length+(b.length+3)).fill(" ");return[G.selectedLine,a.join(" "),[...l,...e,...f].join("")].join(" ")+
16
17
  "\n"}
17
- exports.TreeView=function({timeTravelButtonClassName:a,timeTravelPanelSliderClassName:b,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:e,editor:g}){let [h,n]=D.useState([]),[w,v]=D.useState(""),[r,x]=D.useState(!1),f=D.useRef(0),m=D.useRef(null),y=D.useRef(null),[u,C]=D.useState(!1);D.useEffect(()=>{v(K(g.getEditorState()));return g.registerUpdateListener(({editorState:k})=>{let p=g._compositionKey,z=K(g.getEditorState());v([z,null!==p&&`Composition key: ${p}`].filter(Boolean).join("\n\n"));r||
18
- n(B=>[...B,[Date.now(),k]])})},[r,g]);let A=h.length;D.useEffect(()=>{if(u){let k,p=()=>{const z=f.current;z===A-1?C(!1):k=setTimeout(()=>{f.current++;const B=f.current,J=y.current;null!==J&&(J.value=String(B));g.setEditorState(h[B][1]);p()},h[z+1][0]-h[z][0])};p();return()=>{clearTimeout(k)}}},[h,u,g,A]);D.useEffect(()=>{let k=m.current;if(null!==k)return k.__lexicalEditor=g,()=>{k.__lexicalEditor=null}},[g]);return D.createElement("div",{className:d},!r&&2<A&&D.createElement("button",{onClick:()=>
19
- {let k=g.getRootElement();null!==k&&(k.contentEditable="false",f.current=A-1,x(!0))},className:a,type:"button"},"Time Travel"),D.createElement("pre",{ref:m},w),r&&D.createElement("div",{className:e},D.createElement("button",{className:c,onClick:()=>{C(!u)},type:"button"},u?"Pause":"Play"),D.createElement("input",{className:b,ref:y,onChange:k=>{k=Number(k.target.value);let p=h[k];p&&(f.current=k,g.setEditorState(p[1]))},type:"range",min:"1",max:A-1}),D.createElement("button",{className:c,onClick:()=>
20
- {var k=g.getRootElement();if(null!==k){k.contentEditable="true";k=h.length-1;g.setEditorState(h[k][1]);let p=y.current;null!==p&&(p.value=String(k));x(!1);C(!1)}},type:"button"},"Exit")))}
18
+ exports.TreeView=function({timeTravelButtonClassName:a,timeTravelPanelSliderClassName:c,timeTravelPanelButtonClassName:e,viewClassName:l,timeTravelPanelClassName:f,editor:b}){let [d,n]=D.useState([]),[x,t]=D.useState(""),[q,z]=D.useState(!1),m=D.useRef(0),w=D.useRef(null),A=D.useRef(null),[h,p]=D.useState(!1);D.useEffect(()=>{t(L(b.getEditorState(),b._config,b._compositionKey,b._editable));return v.mergeRegister(b.registerUpdateListener(({editorState:g})=>{let u=L(b.getEditorState(),b._config,b._compositionKey,
19
+ b._editable);t(u);q||n(B=>[...B,[Date.now(),g]])}),b.registerEditableListener(()=>{let g=L(b.getEditorState(),b._config,b._compositionKey,b._editable);t(g)}))},[q,b]);let y=d.length;D.useEffect(()=>{if(h){let g,u=()=>{const B=m.current;B===y-1?p(!1):g=setTimeout(()=>{m.current++;const I=m.current,J=A.current;null!==J&&(J.value=String(I));b.setEditorState(d[I][1]);u()},d[B+1][0]-d[B][0])};u();return()=>{clearTimeout(g)}}},[d,h,b,y]);D.useEffect(()=>{let g=w.current;if(null!==g)return g.__lexicalEditor=
20
+ b,()=>{g.__lexicalEditor=null}},[b]);return D.createElement("div",{className:l},!q&&2<y&&D.createElement("button",{onClick:()=>{let g=b.getRootElement();null!==g&&(g.contentEditable="false",m.current=y-1,z(!0))},className:a,type:"button"},"Time Travel"),D.createElement("pre",{ref:w},x),q&&D.createElement("div",{className:f},D.createElement("button",{className:e,onClick:()=>{m.current===y-1&&(m.current=1);p(!h)},type:"button"},h?"Pause":"Play"),D.createElement("input",{className:c,ref:A,onChange:g=>
21
+ {g=Number(g.target.value);let u=d[g];u&&(m.current=g,b.setEditorState(u[1]))},type:"range",min:"1",max:y-1}),D.createElement("button",{className:e,onClick:()=>{var g=b.getRootElement();if(null!==g){g.contentEditable="true";g=d.length-1;b.setEditorState(d[g][1]);let u=A.current;null!==u&&(u.value=String(g));z(!1);p(!1)}},type:"button"},"Exit")))}
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- import { LexicalEditor, NodeKey, TextNode } from 'lexical';
8
+ import { LexicalCommand, LexicalEditor, NodeKey, TextNode } from 'lexical';
9
9
  import { MutableRefObject, ReactPortal } from 'react';
10
10
  export declare type QueryMatch = {
11
11
  leadOffset: number;
@@ -14,7 +14,7 @@ export declare type QueryMatch = {
14
14
  };
15
15
  export declare type Resolution = {
16
16
  match: QueryMatch;
17
- getRect: () => ClientRect;
17
+ getRect: () => DOMRect;
18
18
  };
19
19
  export declare const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";
20
20
  export declare class TypeaheadOption {
@@ -23,30 +23,42 @@ export declare class TypeaheadOption {
23
23
  constructor(key: string);
24
24
  setRefElement(element: HTMLElement | null): void;
25
25
  }
26
- export declare type MenuRenderFn<TOption extends TypeaheadOption> = (anchorElement: HTMLElement | null, itemProps: {
26
+ export declare type MenuRenderFn<TOption extends TypeaheadOption> = (anchorElementRef: MutableRefObject<HTMLElement | null>, itemProps: {
27
27
  selectedIndex: number | null;
28
28
  selectOptionAndCleanUp: (option: TOption) => void;
29
29
  setHighlightedIndex: (index: number) => void;
30
+ options: Array<TOption>;
30
31
  }, matchingString: string) => ReactPortal | JSX.Element | null;
32
+ export declare function getScrollParent(element: HTMLElement, includeHidden: boolean): HTMLElement | HTMLBodyElement;
33
+ export declare function useDynamicPositioning(resolution: Resolution | null, targetElement: HTMLElement | null, onReposition: () => void, onVisibilityChange?: (isInView: boolean) => void): void;
34
+ export declare const SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
35
+ index: number;
36
+ option: TypeaheadOption;
37
+ }>;
31
38
  export declare function useBasicTypeaheadTriggerMatch(trigger: string, { minLength, maxLength }: {
32
39
  minLength?: number;
33
40
  maxLength?: number;
34
41
  }): TriggerFn;
35
- export declare type TypeaheadMenuPluginArgs<TOption extends TypeaheadOption> = {
42
+ export declare type TypeaheadMenuPluginProps<TOption extends TypeaheadOption> = {
36
43
  onQueryChange: (matchingString: string | null) => void;
37
44
  onSelectOption: (option: TOption, textNodeContainingQuery: TextNode | null, closeMenu: () => void, matchingString: string) => void;
38
45
  options: Array<TOption>;
39
46
  menuRenderFn: MenuRenderFn<TOption>;
40
47
  triggerFn: TriggerFn;
48
+ onOpen?: (resolution: Resolution) => void;
49
+ onClose?: () => void;
50
+ anchorClassName?: string;
41
51
  };
42
52
  export declare type TriggerFn = (text: string, editor: LexicalEditor) => QueryMatch | null;
43
- export declare function LexicalTypeaheadMenuPlugin<TOption extends TypeaheadOption>({ options, onQueryChange, onSelectOption, menuRenderFn, triggerFn, }: TypeaheadMenuPluginArgs<TOption>): JSX.Element | null;
44
- declare type NodeMenuPluginArgs<TOption extends TypeaheadOption> = {
53
+ export declare function LexicalTypeaheadMenuPlugin<TOption extends TypeaheadOption>({ options, onQueryChange, onSelectOption, onOpen, onClose, menuRenderFn, triggerFn, anchorClassName, }: TypeaheadMenuPluginProps<TOption>): JSX.Element | null;
54
+ declare type NodeMenuPluginProps<TOption extends TypeaheadOption> = {
45
55
  onSelectOption: (option: TOption, textNodeContainingQuery: TextNode | null, closeMenu: () => void, matchingString: string) => void;
46
56
  options: Array<TOption>;
47
57
  nodeKey: NodeKey | null;
48
- onClose: () => void;
58
+ onClose?: () => void;
59
+ onOpen?: (resolution: Resolution) => void;
49
60
  menuRenderFn: MenuRenderFn<TOption>;
61
+ anchorClassName?: string;
50
62
  };
51
- export declare function LexicalNodeMenuPlugin<TOption extends TypeaheadOption>({ options, nodeKey, onClose, onSelectOption, menuRenderFn, }: NodeMenuPluginArgs<TOption>): JSX.Element | null;
63
+ export declare function LexicalNodeMenuPlugin<TOption extends TypeaheadOption>({ options, nodeKey, onClose, onOpen, onSelectOption, menuRenderFn, anchorClassName, }: NodeMenuPluginProps<TOption>): JSX.Element | null;
52
64
  export {};
@@ -213,12 +213,90 @@ function startTransition(callback) {
213
213
  } else {
214
214
  callback();
215
215
  }
216
+ } // Got from https://stackoverflow.com/a/42543908/2013580
217
+
218
+
219
+ function getScrollParent(element, includeHidden) {
220
+ let style = getComputedStyle(element);
221
+ const excludeStaticParent = style.position === 'absolute';
222
+ const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
223
+
224
+ if (style.position === 'fixed') {
225
+ return document.body;
226
+ }
227
+
228
+ for (let parent = element; parent = parent.parentElement;) {
229
+ style = getComputedStyle(parent);
230
+
231
+ if (excludeStaticParent && style.position === 'static') {
232
+ continue;
233
+ }
234
+
235
+ if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
236
+ return parent;
237
+ }
238
+ }
239
+
240
+ return document.body;
216
241
  }
217
242
 
243
+ function isTriggerVisibleInNearestScrollContainer(targetElement, containerElement) {
244
+ const tRect = targetElement.getBoundingClientRect();
245
+ const cRect = containerElement.getBoundingClientRect();
246
+ return tRect.top > cRect.top && tRect.top < cRect.bottom;
247
+ } // Reposition the menu on scroll, window resize, and element resize.
248
+
249
+
250
+ function useDynamicPositioning(resolution, targetElement, onReposition, onVisibilityChange) {
251
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
252
+ React.useEffect(() => {
253
+ if (targetElement != null && resolution != null) {
254
+ const rootElement = editor.getRootElement();
255
+ const rootScrollParent = rootElement != null ? getScrollParent(rootElement, false) : document.body;
256
+ let ticking = false;
257
+ let previousIsInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
258
+
259
+ const handleScroll = function () {
260
+ if (!ticking) {
261
+ window.requestAnimationFrame(function () {
262
+ onReposition();
263
+ ticking = false;
264
+ });
265
+ ticking = true;
266
+ }
267
+
268
+ const isInView = isTriggerVisibleInNearestScrollContainer(targetElement, rootScrollParent);
269
+
270
+ if (isInView !== previousIsInView) {
271
+ previousIsInView = isInView;
272
+
273
+ if (onVisibilityChange != null) {
274
+ onVisibilityChange(isInView);
275
+ }
276
+ }
277
+ };
278
+
279
+ const resizeObserver = new ResizeObserver(onReposition);
280
+ window.addEventListener('resize', onReposition);
281
+ document.addEventListener('scroll', handleScroll, {
282
+ capture: true,
283
+ passive: true
284
+ });
285
+ resizeObserver.observe(targetElement);
286
+ return () => {
287
+ resizeObserver.unobserve(targetElement);
288
+ window.removeEventListener('resize', onReposition);
289
+ document.removeEventListener('scroll', handleScroll);
290
+ };
291
+ }
292
+ }, [targetElement, editor, onVisibilityChange, onReposition, resolution]);
293
+ }
294
+ const SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND = lexical.createCommand('SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND');
295
+
218
296
  function LexicalPopoverMenu({
219
297
  close,
220
298
  editor,
221
- anchorElement,
299
+ anchorElementRef,
222
300
  resolution,
223
301
  options,
224
302
  menuRenderFn,
@@ -228,7 +306,7 @@ function LexicalPopoverMenu({
228
306
  React.useEffect(() => {
229
307
  setHighlightedIndex(0);
230
308
  }, [resolution.match.matchingString]);
231
- const selectOptionAndCleanUp = React.useCallback(async selectedEntry => {
309
+ const selectOptionAndCleanUp = React.useCallback(selectedEntry => {
232
310
  editor.update(() => {
233
311
  const textNodeContainingQuery = splitNodeContainingQuery(editor, resolution.match);
234
312
  onSelectOption(selectedEntry, textNodeContainingQuery, close, resolution.match.matchingString);
@@ -258,6 +336,18 @@ function LexicalPopoverMenu({
258
336
  updateSelectedIndex(0);
259
337
  }
260
338
  }, [options, selectedIndex, updateSelectedIndex]);
339
+ React.useEffect(() => {
340
+ return utils.mergeRegister(editor.registerCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND, ({
341
+ option
342
+ }) => {
343
+ if (option.ref && option.ref.current != null) {
344
+ scrollIntoViewIfNeeded(option.ref.current);
345
+ return true;
346
+ }
347
+
348
+ return false;
349
+ }, lexical.COMMAND_PRIORITY_LOW));
350
+ }, [editor, updateSelectedIndex]);
261
351
  React.useEffect(() => {
262
352
  return utils.mergeRegister(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, payload => {
263
353
  const event = payload;
@@ -268,7 +358,10 @@ function LexicalPopoverMenu({
268
358
  const option = options[newSelectedIndex];
269
359
 
270
360
  if (option.ref != null && option.ref.current) {
271
- scrollIntoViewIfNeeded(option.ref.current);
361
+ editor.dispatchCommand(SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND, {
362
+ index: newSelectedIndex,
363
+ option
364
+ });
272
365
  }
273
366
 
274
367
  event.preventDefault();
@@ -276,7 +369,7 @@ function LexicalPopoverMenu({
276
369
  }
277
370
 
278
371
  return true;
279
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
372
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, payload => {
280
373
  const event = payload;
281
374
 
282
375
  if (options !== null && options.length && selectedIndex !== null) {
@@ -293,13 +386,13 @@ function LexicalPopoverMenu({
293
386
  }
294
387
 
295
388
  return true;
296
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, payload => {
389
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, payload => {
297
390
  const event = payload;
298
391
  event.preventDefault();
299
392
  event.stopImmediatePropagation();
300
393
  close();
301
394
  return true;
302
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
395
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_TAB_COMMAND, payload => {
303
396
  const event = payload;
304
397
 
305
398
  if (options === null || selectedIndex === null || options[selectedIndex] == null) {
@@ -310,7 +403,7 @@ function LexicalPopoverMenu({
310
403
  event.stopImmediatePropagation();
311
404
  selectOptionAndCleanUp(options[selectedIndex]);
312
405
  return true;
313
- }, lexical.COMMAND_PRIORITY_NORMAL), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
406
+ }, lexical.COMMAND_PRIORITY_CRITICAL), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
314
407
  if (options === null || selectedIndex === null || options[selectedIndex] == null) {
315
408
  return false;
316
409
  }
@@ -322,14 +415,15 @@ function LexicalPopoverMenu({
322
415
 
323
416
  selectOptionAndCleanUp(options[selectedIndex]);
324
417
  return true;
325
- }, lexical.COMMAND_PRIORITY_NORMAL));
418
+ }, lexical.COMMAND_PRIORITY_CRITICAL));
326
419
  }, [selectOptionAndCleanUp, close, editor, options, selectedIndex, updateSelectedIndex]);
327
420
  const listItemProps = React.useMemo(() => ({
421
+ options,
328
422
  selectOptionAndCleanUp,
329
423
  selectedIndex,
330
424
  setHighlightedIndex
331
- }), [selectOptionAndCleanUp, selectedIndex]);
332
- return menuRenderFn(anchorElement, listItemProps, resolution.match.matchingString);
425
+ }), [selectOptionAndCleanUp, selectedIndex, options]);
426
+ return menuRenderFn(anchorElementRef, listItemProps, resolution.match.matchingString);
333
427
  }
334
428
 
335
429
  function useBasicTypeaheadTriggerMatch(trigger, {
@@ -358,50 +452,68 @@ function useBasicTypeaheadTriggerMatch(trigger, {
358
452
  }, [maxLength, minLength, trigger]);
359
453
  }
360
454
 
361
- function useAnchorElementRef(resolution) {
455
+ function useMenuAnchorRef(resolution, setResolution, className) {
362
456
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
363
457
  const anchorElementRef = React.useRef(document.createElement('div'));
364
- React.useEffect(() => {
458
+ const positionMenu = React.useCallback(() => {
365
459
  const rootElement = editor.getRootElement();
460
+ const containerDiv = anchorElementRef.current;
461
+
462
+ if (rootElement !== null && resolution !== null) {
463
+ const {
464
+ left,
465
+ top,
466
+ width,
467
+ height
468
+ } = resolution.getRect();
469
+ containerDiv.style.top = `${top + window.pageYOffset}px`;
470
+ containerDiv.style.left = `${left + window.pageXOffset}px`;
471
+ containerDiv.style.height = `${height}px`;
472
+ containerDiv.style.width = `${width}px`;
473
+
474
+ if (!containerDiv.isConnected) {
475
+ if (className != null) {
476
+ containerDiv.className = className;
477
+ }
366
478
 
367
- function positionMenu() {
368
- const containerDiv = anchorElementRef.current;
369
- containerDiv.setAttribute('aria-label', 'Typeahead menu');
370
- containerDiv.setAttribute('id', 'typeahead-menu');
371
- containerDiv.setAttribute('role', 'listbox');
372
-
373
- if (rootElement !== null && resolution !== null) {
374
- const {
375
- left,
376
- top,
377
- height
378
- } = resolution.getRect();
379
- containerDiv.style.top = `${top + height + 5 + window.pageYOffset}px`;
380
- containerDiv.style.left = `${left + window.pageXOffset}px`;
479
+ containerDiv.setAttribute('aria-label', 'Typeahead menu');
480
+ containerDiv.setAttribute('id', 'typeahead-menu');
481
+ containerDiv.setAttribute('role', 'listbox');
381
482
  containerDiv.style.display = 'block';
382
483
  containerDiv.style.position = 'absolute';
383
-
384
- if (!containerDiv.isConnected) {
385
- document.body.append(containerDiv);
386
- }
387
-
388
- anchorElementRef.current = containerDiv;
389
- rootElement.setAttribute('aria-controls', 'typeahead-menu');
484
+ document.body.append(containerDiv);
390
485
  }
486
+
487
+ anchorElementRef.current = containerDiv;
488
+ rootElement.setAttribute('aria-controls', 'typeahead-menu');
391
489
  }
490
+ }, [editor, resolution, className]);
491
+ React.useEffect(() => {
492
+ const rootElement = editor.getRootElement();
392
493
 
393
494
  if (resolution !== null) {
394
495
  positionMenu();
395
- window.addEventListener('resize', positionMenu);
396
496
  return () => {
397
- window.removeEventListener('resize', positionMenu);
398
-
399
497
  if (rootElement !== null) {
400
498
  rootElement.removeAttribute('aria-controls');
401
499
  }
500
+
501
+ const containerDiv = anchorElementRef.current;
502
+
503
+ if (containerDiv !== null && containerDiv.isConnected) {
504
+ containerDiv.remove();
505
+ }
402
506
  };
403
507
  }
404
- }, [editor, resolution]);
508
+ }, [editor, positionMenu, resolution]);
509
+ const onVisibilityChange = React.useCallback(isInView => {
510
+ if (resolution !== null) {
511
+ if (!isInView) {
512
+ setResolution(null);
513
+ }
514
+ }
515
+ }, [resolution, setResolution]);
516
+ useDynamicPositioning(resolution, anchorElementRef.current, positionMenu, onVisibilityChange);
405
517
  return anchorElementRef;
406
518
  }
407
519
 
@@ -409,15 +521,31 @@ function LexicalTypeaheadMenuPlugin({
409
521
  options,
410
522
  onQueryChange,
411
523
  onSelectOption,
524
+ onOpen,
525
+ onClose,
412
526
  menuRenderFn,
413
- triggerFn
527
+ triggerFn,
528
+ anchorClassName
414
529
  }) {
415
530
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
416
531
  const [resolution, setResolution] = React.useState(null);
417
- const anchorElementRef = useAnchorElementRef(resolution);
532
+ const anchorElementRef = useMenuAnchorRef(resolution, setResolution, anchorClassName);
533
+ const closeTypeahead = React.useCallback(() => {
534
+ setResolution(null);
535
+
536
+ if (onClose != null && resolution !== null) {
537
+ onClose();
538
+ }
539
+ }, [onClose, resolution]);
540
+ const openTypeahead = React.useCallback(res => {
541
+ setResolution(res);
542
+
543
+ if (onOpen != null && resolution === null) {
544
+ onOpen(res);
545
+ }
546
+ }, [onOpen, resolution]);
418
547
  React.useEffect(() => {
419
548
  let activeRange = document.createRange();
420
- let previousText = null;
421
549
 
422
550
  const updateListener = () => {
423
551
  editor.getEditorState().read(() => {
@@ -425,12 +553,11 @@ function LexicalTypeaheadMenuPlugin({
425
553
  const selection = lexical.$getSelection();
426
554
  const text = getQueryTextForSearch(editor);
427
555
 
428
- if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed() || text === previousText || text === null || range === null) {
429
- setResolution(null);
556
+ if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed() || text === null || range === null) {
557
+ closeTypeahead();
430
558
  return;
431
559
  }
432
560
 
433
- previousText = text;
434
561
  const match = triggerFn(text, editor);
435
562
  onQueryChange(match ? match.matchingString : null);
436
563
 
@@ -438,7 +565,7 @@ function LexicalTypeaheadMenuPlugin({
438
565
  const isRangePositioned = tryToPositionRange(match.leadOffset, range);
439
566
 
440
567
  if (isRangePositioned !== null) {
441
- startTransition(() => setResolution({
568
+ startTransition(() => openTypeahead({
442
569
  getRect: () => range.getBoundingClientRect(),
443
570
  match
444
571
  }));
@@ -446,7 +573,7 @@ function LexicalTypeaheadMenuPlugin({
446
573
  }
447
574
  }
448
575
 
449
- setResolution(null);
576
+ closeTypeahead();
450
577
  });
451
578
  };
452
579
 
@@ -455,15 +582,12 @@ function LexicalTypeaheadMenuPlugin({
455
582
  activeRange = null;
456
583
  removeUpdateListener();
457
584
  };
458
- }, [editor, triggerFn, onQueryChange, resolution]);
459
- const closeTypeahead = React.useCallback(() => {
460
- setResolution(null);
461
- }, []);
585
+ }, [editor, triggerFn, onQueryChange, resolution, closeTypeahead, openTypeahead]);
462
586
  return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalPopoverMenu, {
463
587
  close: closeTypeahead,
464
588
  resolution: resolution,
465
589
  editor: editor,
466
- anchorElement: anchorElementRef.current,
590
+ anchorElementRef: anchorElementRef,
467
591
  options: options,
468
592
  menuRenderFn: menuRenderFn,
469
593
  onSelectOption: onSelectOption
@@ -473,12 +597,28 @@ function LexicalNodeMenuPlugin({
473
597
  options,
474
598
  nodeKey,
475
599
  onClose,
600
+ onOpen,
476
601
  onSelectOption,
477
- menuRenderFn
602
+ menuRenderFn,
603
+ anchorClassName
478
604
  }) {
479
605
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
480
606
  const [resolution, setResolution] = React.useState(null);
481
- const anchorElementRef = useAnchorElementRef(resolution);
607
+ const anchorElementRef = useMenuAnchorRef(resolution, setResolution, anchorClassName);
608
+ const closeNodeMenu = React.useCallback(() => {
609
+ setResolution(null);
610
+
611
+ if (onClose != null && resolution !== null) {
612
+ onClose();
613
+ }
614
+ }, [onClose, resolution]);
615
+ const openNodeMenu = React.useCallback(res => {
616
+ setResolution(res);
617
+
618
+ if (onOpen != null && resolution === null) {
619
+ onOpen(res);
620
+ }
621
+ }, [onOpen, resolution]);
482
622
  React.useEffect(() => {
483
623
  if (nodeKey && resolution == null) {
484
624
  editor.update(() => {
@@ -487,7 +627,7 @@ function LexicalNodeMenuPlugin({
487
627
 
488
628
  if (node != null && domElement != null) {
489
629
  const text = node.getTextContent();
490
- startTransition(() => setResolution({
630
+ startTransition(() => openNodeMenu({
491
631
  getRect: () => domElement.getBoundingClientRect(),
492
632
  match: {
493
633
  leadOffset: text.length,
@@ -498,14 +638,14 @@ function LexicalNodeMenuPlugin({
498
638
  }
499
639
  });
500
640
  } else if (nodeKey == null && resolution != null) {
501
- setResolution(null);
641
+ closeNodeMenu();
502
642
  }
503
- }, [editor, nodeKey, resolution]);
643
+ }, [closeNodeMenu, editor, nodeKey, openNodeMenu, resolution]);
504
644
  return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalPopoverMenu, {
505
- close: onClose,
645
+ close: closeNodeMenu,
506
646
  resolution: resolution,
507
647
  editor: editor,
508
- anchorElement: anchorElementRef.current,
648
+ anchorElementRef: anchorElementRef,
509
649
  options: options,
510
650
  menuRenderFn: menuRenderFn,
511
651
  onSelectOption: onSelectOption
@@ -515,5 +655,8 @@ function LexicalNodeMenuPlugin({
515
655
  exports.LexicalNodeMenuPlugin = LexicalNodeMenuPlugin;
516
656
  exports.LexicalTypeaheadMenuPlugin = LexicalTypeaheadMenuPlugin;
517
657
  exports.PUNCTUATION = PUNCTUATION;
658
+ exports.SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND = SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND;
518
659
  exports.TypeaheadOption = TypeaheadOption;
660
+ exports.getScrollParent = getScrollParent;
519
661
  exports.useBasicTypeaheadTriggerMatch = useBasicTypeaheadTriggerMatch;
662
+ exports.useDynamicPositioning = useDynamicPositioning;
@@ -7,7 +7,7 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
- import type {LexicalEditor, NodeKey, TextNode} from 'lexical';
10
+ import type {LexicalCommand, LexicalEditor, NodeKey, TextNode} from 'lexical';
11
11
  import * as React from 'react';
12
12
 
13
13
  export type QueryMatch = {
@@ -26,40 +26,33 @@ export const PUNCTUATION: string =
26
26
 
27
27
  declare export class TypeaheadOption {
28
28
  key: string;
29
- ref: React$ElementRef<HTMLElement | null>;
29
+ ref: {current: HTMLElement | null};
30
30
  constructor(key: string): void;
31
31
  setRefElement(element: HTMLElement | null): void;
32
32
  }
33
33
 
34
+ declare export var SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
35
+ index: number,
36
+ option: TypeaheadOption,
37
+ }>;
38
+
34
39
  export type MenuRenderFn<TOption> = (
35
- anchorElement: HTMLElement | null,
40
+ anchorElementRef: {current: HTMLElement | null},
36
41
  itemProps: {
37
42
  selectedIndex: number | null,
38
43
  selectOptionAndCleanUp: (option: TOption) => void,
39
44
  setHighlightedIndex: (index: number) => void,
45
+ options: Array<TOption>,
40
46
  },
41
47
  matchingString: string,
42
48
  ) => React.Portal | React.MixedElement | null;
43
49
 
44
- const scrollIntoViewIfNeeded = (target: HTMLElement) => {
45
- const container = document.getElementById('typeahead-menu');
46
- if (container) {
47
- const containerRect = container.getBoundingClientRect();
48
- const targetRect = target.getBoundingClientRect();
49
- if (targetRect.bottom > containerRect.bottom) {
50
- target.scrollIntoView(false);
51
- } else if (targetRect.top < containerRect.top) {
52
- target.scrollIntoView();
53
- }
54
- }
55
- };
56
-
57
50
  declare export function useBasicTypeaheadTriggerMatch(
58
51
  trigger: string,
59
52
  options: {minLength?: number, maxLength?: number},
60
53
  ): TriggerFn;
61
54
 
62
- export type TypeaheadMenuPluginArgs<TOption> = {
55
+ export type TypeaheadMenuPluginProps<TOption> = {
63
56
  onQueryChange: (matchingString: string | null) => void,
64
57
  onSelectOption: (
65
58
  option: TOption,
@@ -70,6 +63,9 @@ export type TypeaheadMenuPluginArgs<TOption> = {
70
63
  options: Array<TOption>,
71
64
  menuRenderFn: MenuRenderFn<TOption>,
72
65
  triggerFn: TriggerFn,
66
+ onOpen?: (resolution: Resolution) => void,
67
+ onClose?: () => void,
68
+ anchorClassName?: string,
73
69
  };
74
70
 
75
71
  export type TriggerFn = (
@@ -78,10 +74,10 @@ export type TriggerFn = (
78
74
  ) => QueryMatch | null;
79
75
 
80
76
  declare export function LexicalTypeaheadMenuPlugin<TOption>(
81
- options: TypeaheadMenuPluginArgs<TOption>,
77
+ options: TypeaheadMenuPluginProps<TOption>,
82
78
  ): React.MixedElement | null;
83
79
 
84
- type NodeMenuPluginArgs<TOption> = {
80
+ type NodeMenuPluginProps<TOption> = {
85
81
  onSelectOption: (
86
82
  option: TOption,
87
83
  textNodeContainingQuery: TextNode | null,
@@ -90,10 +86,12 @@ type NodeMenuPluginArgs<TOption> = {
90
86
  ) => void,
91
87
  options: Array<TOption>,
92
88
  nodeKey: NodeKey | null,
93
- onClose: () => void,
89
+ onClose?: () => void,
90
+ onOpen?: (resolution: Resolution) => void,
94
91
  menuRenderFn: MenuRenderFn<TOption>,
92
+ anchorClassName?: string,
95
93
  };
96
94
 
97
95
  declare export function LexicalNodeMenuPlugin<TOption>(
98
- options: NodeMenuPluginArgs<TOption>,
96
+ options: NodeMenuPluginProps<TOption>,
99
97
  ): React.MixedElement | null;