@lexical/react 0.35.1-nightly.20250924.0 → 0.36.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 (154) hide show
  1. package/ExtensionComponent.d.ts +42 -0
  2. package/LexicalAutoEmbedPlugin.dev.js +2 -0
  3. package/LexicalAutoEmbedPlugin.dev.mjs +2 -0
  4. package/LexicalAutoEmbedPlugin.prod.js +1 -1
  5. package/LexicalAutoEmbedPlugin.prod.mjs +1 -1
  6. package/LexicalAutoLinkPlugin.d.ts +2 -17
  7. package/LexicalAutoLinkPlugin.dev.js +7 -309
  8. package/LexicalAutoLinkPlugin.dev.mjs +9 -310
  9. package/LexicalAutoLinkPlugin.js.flow +4 -18
  10. package/LexicalAutoLinkPlugin.prod.js +1 -1
  11. package/LexicalAutoLinkPlugin.prod.mjs +1 -1
  12. package/LexicalClearEditorPlugin.dev.js +2 -23
  13. package/LexicalClearEditorPlugin.dev.mjs +2 -23
  14. package/LexicalClearEditorPlugin.prod.js +1 -1
  15. package/LexicalClearEditorPlugin.prod.mjs +1 -1
  16. package/LexicalClickableLinkPlugin.dev.js +5 -70
  17. package/LexicalClickableLinkPlugin.dev.mjs +6 -71
  18. package/LexicalClickableLinkPlugin.prod.js +1 -1
  19. package/LexicalClickableLinkPlugin.prod.mjs +1 -1
  20. package/LexicalCollaborationContext.prod.js +1 -1
  21. package/LexicalCollaborationContext.prod.mjs +1 -1
  22. package/LexicalCollaborationPlugin.dev.mjs +2 -2
  23. package/LexicalCollaborationPlugin.prod.mjs +1 -1
  24. package/LexicalContentEditable.dev.js +2 -3
  25. package/LexicalContentEditable.dev.mjs +2 -3
  26. package/LexicalContentEditable.prod.js +1 -1
  27. package/LexicalContentEditable.prod.mjs +1 -1
  28. package/LexicalContextMenuPlugin.dev.js +2 -0
  29. package/LexicalContextMenuPlugin.dev.mjs +4 -2
  30. package/LexicalContextMenuPlugin.prod.js +1 -1
  31. package/LexicalContextMenuPlugin.prod.mjs +1 -1
  32. package/LexicalDecoratorBlockNode.dev.js +1 -0
  33. package/LexicalDecoratorBlockNode.dev.mjs +1 -0
  34. package/LexicalDecoratorBlockNode.js.flow +7 -0
  35. package/LexicalDecoratorBlockNode.prod.js +1 -1
  36. package/LexicalDecoratorBlockNode.prod.mjs +1 -1
  37. package/LexicalDraggableBlockPlugin.dev.js +6 -0
  38. package/LexicalDraggableBlockPlugin.dev.mjs +6 -0
  39. package/LexicalDraggableBlockPlugin.prod.js +1 -1
  40. package/LexicalDraggableBlockPlugin.prod.mjs +1 -1
  41. package/LexicalExtensionComponent.dev.js +53 -0
  42. package/LexicalExtensionComponent.dev.mjs +51 -0
  43. package/LexicalExtensionComponent.js +11 -0
  44. package/LexicalExtensionComponent.js.flow +12 -0
  45. package/LexicalExtensionComponent.mjs +12 -0
  46. package/LexicalExtensionComponent.node.mjs +10 -0
  47. package/LexicalExtensionComponent.prod.js +9 -0
  48. package/LexicalExtensionComponent.prod.mjs +9 -0
  49. package/LexicalExtensionComposer.d.ts +69 -0
  50. package/LexicalExtensionComposer.dev.js +105 -0
  51. package/LexicalExtensionComposer.dev.mjs +103 -0
  52. package/LexicalExtensionComposer.js +11 -0
  53. package/LexicalExtensionComposer.js.flow +20 -0
  54. package/LexicalExtensionComposer.mjs +12 -0
  55. package/LexicalExtensionComposer.node.mjs +10 -0
  56. package/LexicalExtensionComposer.prod.js +9 -0
  57. package/LexicalExtensionComposer.prod.mjs +9 -0
  58. package/LexicalHashtagPlugin.dev.js +1 -136
  59. package/LexicalHashtagPlugin.dev.mjs +3 -138
  60. package/LexicalHashtagPlugin.prod.js +1 -1
  61. package/LexicalHashtagPlugin.prod.mjs +1 -1
  62. package/LexicalHorizontalRuleNode.d.ts +10 -11
  63. package/LexicalHorizontalRuleNode.dev.js +12 -26
  64. package/LexicalHorizontalRuleNode.dev.mjs +14 -27
  65. package/LexicalHorizontalRuleNode.js.flow +2 -3
  66. package/LexicalHorizontalRuleNode.prod.js +1 -1
  67. package/LexicalHorizontalRuleNode.prod.mjs +1 -1
  68. package/LexicalLinkPlugin.d.ts +1 -1
  69. package/LexicalLinkPlugin.dev.js +7 -52
  70. package/LexicalLinkPlugin.dev.mjs +8 -53
  71. package/LexicalLinkPlugin.prod.js +1 -1
  72. package/LexicalLinkPlugin.prod.mjs +1 -1
  73. package/LexicalListPlugin.js.flow +5 -0
  74. package/LexicalMarkdownShortcutPlugin.dev.mjs +1 -1
  75. package/LexicalMarkdownShortcutPlugin.prod.mjs +1 -1
  76. package/LexicalNestedComposer.js.flow +10 -6
  77. package/LexicalNodeContextMenuPlugin.dev.js +10 -0
  78. package/LexicalNodeContextMenuPlugin.dev.mjs +11 -1
  79. package/LexicalNodeContextMenuPlugin.prod.js +1 -1
  80. package/LexicalNodeContextMenuPlugin.prod.mjs +1 -1
  81. package/LexicalNodeMenuPlugin.dev.js +2 -0
  82. package/LexicalNodeMenuPlugin.dev.mjs +4 -2
  83. package/LexicalNodeMenuPlugin.prod.js +1 -1
  84. package/LexicalNodeMenuPlugin.prod.mjs +1 -1
  85. package/LexicalPlainTextPlugin.d.ts +1 -1
  86. package/LexicalPlainTextPlugin.dev.js +85 -30
  87. package/LexicalPlainTextPlugin.dev.mjs +85 -30
  88. package/LexicalPlainTextPlugin.prod.js +1 -1
  89. package/LexicalPlainTextPlugin.prod.mjs +1 -1
  90. package/LexicalReactExtension.dev.js +187 -0
  91. package/LexicalReactExtension.dev.mjs +184 -0
  92. package/LexicalReactExtension.js +11 -0
  93. package/LexicalReactExtension.js.flow +68 -0
  94. package/LexicalReactExtension.mjs +13 -0
  95. package/LexicalReactExtension.node.mjs +11 -0
  96. package/LexicalReactExtension.prod.js +9 -0
  97. package/LexicalReactExtension.prod.mjs +9 -0
  98. package/LexicalReactPluginHostExtension.dev.js +189 -0
  99. package/LexicalReactPluginHostExtension.dev.mjs +181 -0
  100. package/LexicalReactPluginHostExtension.js +11 -0
  101. package/LexicalReactPluginHostExtension.js.flow +84 -0
  102. package/LexicalReactPluginHostExtension.mjs +18 -0
  103. package/LexicalReactPluginHostExtension.node.mjs +16 -0
  104. package/LexicalReactPluginHostExtension.prod.js +9 -0
  105. package/LexicalReactPluginHostExtension.prod.mjs +9 -0
  106. package/LexicalReactProviderExtension.dev.js +33 -0
  107. package/LexicalReactProviderExtension.dev.mjs +31 -0
  108. package/LexicalReactProviderExtension.js +11 -0
  109. package/LexicalReactProviderExtension.js.flow +12 -0
  110. package/LexicalReactProviderExtension.mjs +12 -0
  111. package/LexicalReactProviderExtension.node.mjs +10 -0
  112. package/LexicalReactProviderExtension.prod.js +9 -0
  113. package/LexicalReactProviderExtension.prod.mjs +9 -0
  114. package/LexicalRichTextPlugin.d.ts +1 -1
  115. package/LexicalRichTextPlugin.dev.js +85 -30
  116. package/LexicalRichTextPlugin.dev.mjs +85 -30
  117. package/LexicalRichTextPlugin.prod.js +1 -1
  118. package/LexicalRichTextPlugin.prod.mjs +1 -1
  119. package/LexicalTabIndentationPlugin.d.ts +2 -2
  120. package/LexicalTabIndentationPlugin.dev.js +3 -57
  121. package/LexicalTabIndentationPlugin.dev.mjs +3 -56
  122. package/LexicalTabIndentationPlugin.prod.js +1 -1
  123. package/LexicalTabIndentationPlugin.prod.mjs +1 -1
  124. package/LexicalTreeViewExtension.dev.js +57 -0
  125. package/LexicalTreeViewExtension.dev.mjs +54 -0
  126. package/LexicalTreeViewExtension.js +11 -0
  127. package/LexicalTreeViewExtension.js.flow +12 -0
  128. package/LexicalTreeViewExtension.mjs +13 -0
  129. package/LexicalTreeViewExtension.node.mjs +11 -0
  130. package/LexicalTreeViewExtension.prod.js +9 -0
  131. package/LexicalTreeViewExtension.prod.mjs +9 -0
  132. package/LexicalTypeaheadMenuPlugin.dev.js +2 -0
  133. package/LexicalTypeaheadMenuPlugin.dev.mjs +4 -2
  134. package/LexicalTypeaheadMenuPlugin.prod.js +1 -1
  135. package/LexicalTypeaheadMenuPlugin.prod.mjs +1 -1
  136. package/ReactExtension.d.ts +41 -0
  137. package/ReactPluginHostExtension.d.ts +56 -0
  138. package/ReactProviderExtension.d.ts +9 -0
  139. package/TreeViewExtension.d.ts +18 -0
  140. package/package.json +228 -17
  141. package/shared/LegacyDecorators.d.ts +23 -0
  142. package/shared/buildEditorComponent.d.ts +11 -0
  143. package/shared/mergeRefs.d.ts +2 -1
  144. package/shared/types.d.ts +89 -0
  145. package/shared/useReactDecorators.d.ts +12 -0
  146. package/useExtensionComponent.d.ts +10 -0
  147. package/useLexicalExtensionComponent.dev.js +37 -0
  148. package/useLexicalExtensionComponent.dev.mjs +34 -0
  149. package/useLexicalExtensionComponent.js +11 -0
  150. package/useLexicalExtensionComponent.js.flow +12 -0
  151. package/useLexicalExtensionComponent.mjs +13 -0
  152. package/useLexicalExtensionComponent.node.mjs +11 -0
  153. package/useLexicalExtensionComponent.prod.js +9 -0
  154. package/useLexicalExtensionComponent.prod.mjs +9 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import type { ComponentProps } from 'react';
9
+ import { type AnyLexicalExtension, type LexicalExtensionOutput } from 'lexical';
10
+ /**
11
+ * The lexical:extension prop combined with the props of the given Extension's
12
+ * output Component.
13
+ */
14
+ export type ExtensionComponentProps<Extension extends AnyLexicalExtension> = {
15
+ /** The Extension */ 'lexical:extension': Extension;
16
+ } & ([LexicalExtensionOutput<Extension>] extends [
17
+ {
18
+ Component: infer OutputComponentType extends React.ComponentType;
19
+ }
20
+ ] ? Omit<ComponentProps<OutputComponentType>, 'lexical:extension'> : never);
21
+ /**
22
+ * A convenient way to get an Extension's output Component with {@link useExtensionComponent}
23
+ * and construct it in one step.
24
+ *
25
+ * @example
26
+ * Usage
27
+ * ```tsx
28
+ * return (
29
+ * <ExtensionComponent
30
+ * lexical:extension={TreeViewExtension}
31
+ * viewClassName="tree-view-output" />
32
+ * );
33
+ * ```
34
+ *
35
+ * @example
36
+ * Alternative without ExtensionComponent
37
+ * ```tsx
38
+ * const TreeViewComponent = useExtensionComponent(TreeViewExtension);
39
+ * return (<TreeViewComponent viewClassName="tree-view-output" />);
40
+ * ```
41
+ */
42
+ export declare function ExtensionComponent<Extension extends AnyLexicalExtension>({ 'lexical:extension': extension, ...props }: ExtensionComponentProps<Extension>): import("react/jsx-runtime").JSX.Element;
@@ -27,6 +27,8 @@ var jsxRuntime = require('react/jsx-runtime');
27
27
  const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
28
28
  const INSERT_EMBED_COMMAND = lexical.createCommand('INSERT_EMBED_COMMAND');
29
29
  class AutoEmbedOption extends LexicalNodeMenuPlugin.MenuOption {
30
+ title;
31
+ onSelect;
30
32
  constructor(title, options) {
31
33
  super(title);
32
34
  this.title = title;
@@ -25,6 +25,8 @@ import { jsx } from 'react/jsx-runtime';
25
25
  const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
26
26
  const INSERT_EMBED_COMMAND = createCommand('INSERT_EMBED_COMMAND');
27
27
  class AutoEmbedOption extends MenuOption {
28
+ title;
29
+ onSelect;
28
30
  constructor(title, options) {
29
31
  super(title);
30
32
  this.title = title;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  */
8
8
 
9
- "use strict";var e=require("@lexical/link"),t=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/react/LexicalNodeMenuPlugin"),o=require("@lexical/utils"),i=require("lexical"),r=require("react"),l=require("react/jsx-runtime");const s=i.createCommand("INSERT_EMBED_COMMAND");class u extends n.MenuOption{constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}exports.AutoEmbedOption=u,exports.INSERT_EMBED_COMMAND=s,exports.LexicalAutoEmbedPlugin=function({embedConfigs:u,onOpenEmbedModalForConfig:a,getMenuOptions:c,menuRenderFn:d,menuCommandPriority:m=i.COMMAND_PRIORITY_LOW}){const[p]=t.useLexicalComposerContext(),[x,C]=r.useState(null),[f,M]=r.useState(null),g=r.useCallback((()=>{C(null),M(null)}),[]),E=r.useCallback((async t=>{const n=p.getEditorState().read((function(){const n=i.$getNodeByKey(t);if(e.$isLinkNode(n))return n.getURL()}));if(void 0!==n)for(const e of u){null!=await Promise.resolve(e.parseUrl(n))&&(M(e),C(t))}}),[p,u]);r.useEffect((()=>o.mergeRegister(...[e.LinkNode,e.AutoLinkNode].map((e=>p.registerMutationListener(e,((...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[o,r]of e)"created"===r&&t.has(i.PASTE_TAG)&&n.size<=3?E(o):o===x&&g()})(...e)),{skipInitialization:!0}))))),[E,p,u,x,g]),r.useEffect((()=>p.registerCommand(s,(e=>{const t=u.find((({type:t})=>t===e));return!!t&&(a(t),!0)}),i.COMMAND_PRIORITY_EDITOR)),[p,u,a]);const N=r.useCallback((async function(){if(null!=f&&null!=x){const t=p.getEditorState().read((()=>{const t=i.$getNodeByKey(x);return e.$isLinkNode(t)?t:null}));if(e.$isLinkNode(t)){const e=await Promise.resolve(f.parseUrl(t.__url));null!=e&&p.update((()=>{i.$getSelection()||t.selectEnd(),f.insertNode(p,e),t.isAttached()&&t.remove()}))}}}),[f,p,x]),L=r.useMemo((()=>null!=f&&null!=x?c(f,N,g):[]),[f,N,c,x,g]),A=r.useCallback(((e,t,n)=>{p.update((()=>{e.onSelect(t),n()}))}),[p]);return null!=x?l.jsx(n.LexicalNodeMenuPlugin,{nodeKey:x,onClose:g,onSelectOption:A,options:L,menuRenderFn:d,commandPriority:m}):null},exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
9
+ "use strict";var e=require("@lexical/link"),t=require("@lexical/react/LexicalComposerContext"),n=require("@lexical/react/LexicalNodeMenuPlugin"),o=require("@lexical/utils"),i=require("lexical"),l=require("react"),r=require("react/jsx-runtime");const s=i.createCommand("INSERT_EMBED_COMMAND");class u extends n.MenuOption{title;onSelect;constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}exports.AutoEmbedOption=u,exports.INSERT_EMBED_COMMAND=s,exports.LexicalAutoEmbedPlugin=function({embedConfigs:u,onOpenEmbedModalForConfig:a,getMenuOptions:c,menuRenderFn:d,menuCommandPriority:m=i.COMMAND_PRIORITY_LOW}){const[p]=t.useLexicalComposerContext(),[x,C]=l.useState(null),[f,M]=l.useState(null),g=l.useCallback((()=>{C(null),M(null)}),[]),E=l.useCallback((async t=>{const n=p.getEditorState().read((function(){const n=i.$getNodeByKey(t);if(e.$isLinkNode(n))return n.getURL()}));if(void 0!==n)for(const e of u){null!=await Promise.resolve(e.parseUrl(n))&&(M(e),C(t))}}),[p,u]);l.useEffect((()=>o.mergeRegister(...[e.LinkNode,e.AutoLinkNode].map((e=>p.registerMutationListener(e,((...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[o,l]of e)"created"===l&&t.has(i.PASTE_TAG)&&n.size<=3?E(o):o===x&&g()})(...e)),{skipInitialization:!0}))))),[E,p,u,x,g]),l.useEffect((()=>p.registerCommand(s,(e=>{const t=u.find((({type:t})=>t===e));return!!t&&(a(t),!0)}),i.COMMAND_PRIORITY_EDITOR)),[p,u,a]);const N=l.useCallback((async function(){if(null!=f&&null!=x){const t=p.getEditorState().read((()=>{const t=i.$getNodeByKey(x);return e.$isLinkNode(t)?t:null}));if(e.$isLinkNode(t)){const e=await Promise.resolve(f.parseUrl(t.__url));null!=e&&p.update((()=>{i.$getSelection()||t.selectEnd(),f.insertNode(p,e),t.isAttached()&&t.remove()}))}}}),[f,p,x]),L=l.useMemo((()=>null!=f&&null!=x?c(f,N,g):[]),[f,N,c,x,g]),A=l.useCallback(((e,t,n)=>{p.update((()=>{e.onSelect(t),n()}))}),[p]);return null!=x?r.jsx(n.LexicalNodeMenuPlugin,{nodeKey:x,onClose:g,onSelectOption:A,options:L,menuRenderFn:d,commandPriority:m}):null},exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  */
8
8
 
9
- import{$isLinkNode as e,LinkNode as t,AutoLinkNode as n}from"@lexical/link";import{useLexicalComposerContext as o}from"@lexical/react/LexicalComposerContext";import{MenuOption as r,LexicalNodeMenuPlugin as i}from"@lexical/react/LexicalNodeMenuPlugin";import{mergeRegister as l}from"@lexical/utils";import{createCommand as s,$getNodeByKey as a,COMMAND_PRIORITY_EDITOR as c,$getSelection as u,COMMAND_PRIORITY_LOW as m,PASTE_TAG as d}from"lexical";import{useState as p,useCallback as f,useEffect as x,useMemo as g}from"react";import{jsx as w}from"react/jsx-runtime";const C=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/,y=s("INSERT_EMBED_COMMAND");class E extends r{constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}function M({embedConfigs:r,onOpenEmbedModalForConfig:s,getMenuOptions:C,menuRenderFn:E,menuCommandPriority:M=m}){const[S]=o(),[h,_]=p(null),[v,z]=p(null),A=f((()=>{_(null),z(null)}),[]),L=f((async t=>{const n=S.getEditorState().read((function(){const n=a(t);if(e(n))return n.getURL()}));if(void 0!==n)for(const e of r){null!=await Promise.resolve(e.parseUrl(n))&&(z(e),_(t))}}),[S,r]);x((()=>l(...[t,n].map((e=>S.registerMutationListener(e,((...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[o,r]of e)"created"===r&&t.has(d)&&n.size<=3?L(o):o===h&&A()})(...e)),{skipInitialization:!0}))))),[L,S,r,h,A]),x((()=>S.registerCommand(y,(e=>{const t=r.find((({type:t})=>t===e));return!!t&&(s(t),!0)}),c)),[S,r,s]);const P=f((async function(){if(null!=v&&null!=h){const t=S.getEditorState().read((()=>{const t=a(h);return e(t)?t:null}));if(e(t)){const e=await Promise.resolve(v.parseUrl(t.__url));null!=e&&S.update((()=>{u()||t.selectEnd(),v.insertNode(S,e),t.isAttached()&&t.remove()}))}}}),[v,S,h]),b=g((()=>null!=v&&null!=h?C(v,P,A):[]),[v,P,C,h,A]),N=f(((e,t,n)=>{S.update((()=>{e.onSelect(t),n()}))}),[S]);return null!=h?w(i,{nodeKey:h,onClose:A,onSelectOption:N,options:b,menuRenderFn:E,commandPriority:M}):null}export{E as AutoEmbedOption,y as INSERT_EMBED_COMMAND,M as LexicalAutoEmbedPlugin,C as URL_MATCHER};
9
+ import{$isLinkNode as e,LinkNode as t,AutoLinkNode as n}from"@lexical/link";import{useLexicalComposerContext as o}from"@lexical/react/LexicalComposerContext";import{MenuOption as r,LexicalNodeMenuPlugin as i}from"@lexical/react/LexicalNodeMenuPlugin";import{mergeRegister as l}from"@lexical/utils";import{createCommand as s,$getNodeByKey as a,COMMAND_PRIORITY_EDITOR as c,$getSelection as u,COMMAND_PRIORITY_LOW as m,PASTE_TAG as d}from"lexical";import{useState as p,useCallback as f,useEffect as x,useMemo as g}from"react";import{jsx as w}from"react/jsx-runtime";const C=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/,S=s("INSERT_EMBED_COMMAND");class y extends r{title;onSelect;constructor(e,t){super(e),this.title=e,this.onSelect=t.onSelect.bind(this)}}function E({embedConfigs:r,onOpenEmbedModalForConfig:s,getMenuOptions:C,menuRenderFn:y,menuCommandPriority:E=m}){const[M]=o(),[h,_]=p(null),[v,z]=p(null),A=f((()=>{_(null),z(null)}),[]),L=f((async t=>{const n=M.getEditorState().read((function(){const n=a(t);if(e(n))return n.getURL()}));if(void 0!==n)for(const e of r){null!=await Promise.resolve(e.parseUrl(n))&&(z(e),_(t))}}),[M,r]);x((()=>l(...[t,n].map((e=>M.registerMutationListener(e,((...e)=>((e,{updateTags:t,dirtyLeaves:n})=>{for(const[o,r]of e)"created"===r&&t.has(d)&&n.size<=3?L(o):o===h&&A()})(...e)),{skipInitialization:!0}))))),[L,M,r,h,A]),x((()=>M.registerCommand(S,(e=>{const t=r.find((({type:t})=>t===e));return!!t&&(s(t),!0)}),c)),[M,r,s]);const P=f((async function(){if(null!=v&&null!=h){const t=M.getEditorState().read((()=>{const t=a(h);return e(t)?t:null}));if(e(t)){const e=await Promise.resolve(v.parseUrl(t.__url));null!=e&&M.update((()=>{u()||t.selectEnd(),v.insertNode(M,e),t.isAttached()&&t.remove()}))}}}),[v,M,h]),b=g((()=>null!=v&&null!=h?C(v,P,A):[]),[v,P,C,h,A]),N=f(((e,t,n)=>{M.update((()=>{e.onSelect(t),n()}))}),[M]);return null!=h?w(i,{nodeKey:h,onClose:A,onSelectOption:N,options:b,menuRenderFn:y,commandPriority:E}):null}export{y as AutoEmbedOption,S as INSERT_EMBED_COMMAND,E as LexicalAutoEmbedPlugin,C as URL_MATCHER};
@@ -5,25 +5,10 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- import type { AutoLinkAttributes } from '@lexical/link';
8
+ import type { ChangeHandler, LinkMatcher } from '@lexical/link';
9
9
  import type { JSX } from 'react';
10
- type ChangeHandler = (url: string | null, prevUrl: string | null) => void;
11
- type LinkMatcherResult = {
12
- attributes?: AutoLinkAttributes;
13
- index: number;
14
- length: number;
15
- text: string;
16
- url: string;
17
- };
18
- export type LinkMatcher = (text: string) => LinkMatcherResult | null;
19
- export declare function createLinkMatcherWithRegExp(regExp: RegExp, urlTransformer?: (text: string) => string): (text: string) => {
20
- index: number;
21
- length: number;
22
- text: string;
23
- url: string;
24
- } | null;
10
+ export { type ChangeHandler, createLinkMatcherWithRegExp, type LinkMatcher, } from '@lexical/link';
25
11
  export declare function AutoLinkPlugin({ matchers, onChange, }: {
26
12
  matchers: Array<LinkMatcher>;
27
13
  onChange?: ChangeHandler;
28
14
  }): JSX.Element | null;
29
- export {};
@@ -10,8 +10,6 @@
10
10
 
11
11
  var link = require('@lexical/link');
12
12
  var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
13
- var utils = require('@lexical/utils');
14
- var lexical = require('lexical');
15
13
  var react = require('react');
16
14
 
17
15
  /**
@@ -28,279 +26,6 @@ function formatDevErrorMessage(message) {
28
26
  throw new Error(message);
29
27
  }
30
28
 
31
- function createLinkMatcherWithRegExp(regExp, urlTransformer = text => text) {
32
- return text => {
33
- const match = regExp.exec(text);
34
- if (match === null) {
35
- return null;
36
- }
37
- return {
38
- index: match.index,
39
- length: match[0].length,
40
- text: match[0],
41
- url: urlTransformer(match[0])
42
- };
43
- };
44
- }
45
- function findFirstMatch(text, matchers) {
46
- for (let i = 0; i < matchers.length; i++) {
47
- const match = matchers[i](text);
48
- if (match) {
49
- return match;
50
- }
51
- }
52
- return null;
53
- }
54
- const PUNCTUATION_OR_SPACE = /[.,;\s]/;
55
- function isSeparator(char) {
56
- return PUNCTUATION_OR_SPACE.test(char);
57
- }
58
- function endsWithSeparator(textContent) {
59
- return isSeparator(textContent[textContent.length - 1]);
60
- }
61
- function startsWithSeparator(textContent) {
62
- return isSeparator(textContent[0]);
63
- }
64
-
65
- /**
66
- * Check if the text content starts with a fullstop followed by a top-level domain.
67
- * Meaning if the text content can be a beginning of a top level domain.
68
- * @param textContent
69
- * @param isEmail
70
- * @returns boolean
71
- */
72
- function startsWithTLD(textContent, isEmail) {
73
- if (isEmail) {
74
- return /^\.[a-zA-Z]{2,}/.test(textContent);
75
- } else {
76
- return /^\.[a-zA-Z0-9]{1,}/.test(textContent);
77
- }
78
- }
79
- function isPreviousNodeValid(node) {
80
- let previousNode = node.getPreviousSibling();
81
- if (lexical.$isElementNode(previousNode)) {
82
- previousNode = previousNode.getLastDescendant();
83
- }
84
- return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
85
- }
86
- function isNextNodeValid(node) {
87
- let nextNode = node.getNextSibling();
88
- if (lexical.$isElementNode(nextNode)) {
89
- nextNode = nextNode.getFirstDescendant();
90
- }
91
- return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
92
- }
93
- function isContentAroundIsValid(matchStart, matchEnd, text, nodes) {
94
- const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(nodes[0]);
95
- if (!contentBeforeIsValid) {
96
- return false;
97
- }
98
- const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(nodes[nodes.length - 1]);
99
- return contentAfterIsValid;
100
- }
101
- function extractMatchingNodes(nodes, startIndex, endIndex) {
102
- const unmodifiedBeforeNodes = [];
103
- const matchingNodes = [];
104
- const unmodifiedAfterNodes = [];
105
- let matchingOffset = 0;
106
- let currentOffset = 0;
107
- const currentNodes = [...nodes];
108
- while (currentNodes.length > 0) {
109
- const currentNode = currentNodes[0];
110
- const currentNodeText = currentNode.getTextContent();
111
- const currentNodeLength = currentNodeText.length;
112
- const currentNodeStart = currentOffset;
113
- const currentNodeEnd = currentOffset + currentNodeLength;
114
- if (currentNodeEnd <= startIndex) {
115
- unmodifiedBeforeNodes.push(currentNode);
116
- matchingOffset += currentNodeLength;
117
- } else if (currentNodeStart >= endIndex) {
118
- unmodifiedAfterNodes.push(currentNode);
119
- } else {
120
- matchingNodes.push(currentNode);
121
- }
122
- currentOffset += currentNodeLength;
123
- currentNodes.shift();
124
- }
125
- return [matchingOffset, unmodifiedBeforeNodes, matchingNodes, unmodifiedAfterNodes];
126
- }
127
- function $createAutoLinkNode_(nodes, startIndex, endIndex, match) {
128
- const linkNode = link.$createAutoLinkNode(match.url, match.attributes);
129
- if (nodes.length === 1) {
130
- let remainingTextNode = nodes[0];
131
- let linkTextNode;
132
- if (startIndex === 0) {
133
- [linkTextNode, remainingTextNode] = remainingTextNode.splitText(endIndex);
134
- } else {
135
- [, linkTextNode, remainingTextNode] = remainingTextNode.splitText(startIndex, endIndex);
136
- }
137
- const textNode = lexical.$createTextNode(match.text);
138
- textNode.setFormat(linkTextNode.getFormat());
139
- textNode.setDetail(linkTextNode.getDetail());
140
- textNode.setStyle(linkTextNode.getStyle());
141
- linkNode.append(textNode);
142
- linkTextNode.replace(linkNode);
143
- return remainingTextNode;
144
- } else if (nodes.length > 1) {
145
- const firstTextNode = nodes[0];
146
- let offset = firstTextNode.getTextContent().length;
147
- let firstLinkTextNode;
148
- if (startIndex === 0) {
149
- firstLinkTextNode = firstTextNode;
150
- } else {
151
- [, firstLinkTextNode] = firstTextNode.splitText(startIndex);
152
- }
153
- const linkNodes = [];
154
- let remainingTextNode;
155
- for (let i = 1; i < nodes.length; i++) {
156
- const currentNode = nodes[i];
157
- const currentNodeText = currentNode.getTextContent();
158
- const currentNodeLength = currentNodeText.length;
159
- const currentNodeStart = offset;
160
- const currentNodeEnd = offset + currentNodeLength;
161
- if (currentNodeStart < endIndex) {
162
- if (currentNodeEnd <= endIndex) {
163
- linkNodes.push(currentNode);
164
- } else {
165
- const [linkTextNode, endNode] = currentNode.splitText(endIndex - currentNodeStart);
166
- linkNodes.push(linkTextNode);
167
- remainingTextNode = endNode;
168
- }
169
- }
170
- offset += currentNodeLength;
171
- }
172
- const selection = lexical.$getSelection();
173
- const selectedTextNode = selection ? selection.getNodes().find(lexical.$isTextNode) : undefined;
174
- const textNode = lexical.$createTextNode(firstLinkTextNode.getTextContent());
175
- textNode.setFormat(firstLinkTextNode.getFormat());
176
- textNode.setDetail(firstLinkTextNode.getDetail());
177
- textNode.setStyle(firstLinkTextNode.getStyle());
178
- linkNode.append(textNode, ...linkNodes);
179
- // it does not preserve caret position if caret was at the first text node
180
- // so we need to restore caret position
181
- if (selectedTextNode && selectedTextNode === firstLinkTextNode) {
182
- if (lexical.$isRangeSelection(selection)) {
183
- textNode.select(selection.anchor.offset, selection.focus.offset);
184
- } else if (lexical.$isNodeSelection(selection)) {
185
- textNode.select(0, textNode.getTextContent().length);
186
- }
187
- }
188
- firstLinkTextNode.replace(linkNode);
189
- return remainingTextNode;
190
- }
191
- return undefined;
192
- }
193
- function $handleLinkCreation(nodes, matchers, onChange) {
194
- let currentNodes = [...nodes];
195
- const initialText = currentNodes.map(node => node.getTextContent()).join('');
196
- let text = initialText;
197
- let match;
198
- let invalidMatchEnd = 0;
199
- while ((match = findFirstMatch(text, matchers)) && match !== null) {
200
- const matchStart = match.index;
201
- const matchLength = match.length;
202
- const matchEnd = matchStart + matchLength;
203
- const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, initialText, currentNodes);
204
- if (isValid) {
205
- const [matchingOffset,, matchingNodes, unmodifiedAfterNodes] = extractMatchingNodes(currentNodes, invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd);
206
- const actualMatchStart = invalidMatchEnd + matchStart - matchingOffset;
207
- const actualMatchEnd = invalidMatchEnd + matchEnd - matchingOffset;
208
- const remainingTextNode = $createAutoLinkNode_(matchingNodes, actualMatchStart, actualMatchEnd, match);
209
- currentNodes = remainingTextNode ? [remainingTextNode, ...unmodifiedAfterNodes] : unmodifiedAfterNodes;
210
- onChange(match.url, null);
211
- invalidMatchEnd = 0;
212
- } else {
213
- invalidMatchEnd += matchEnd;
214
- }
215
- text = text.substring(matchEnd);
216
- }
217
- }
218
- function handleLinkEdit(linkNode, matchers, onChange) {
219
- // Check children are simple text
220
- const children = linkNode.getChildren();
221
- const childrenLength = children.length;
222
- for (let i = 0; i < childrenLength; i++) {
223
- const child = children[i];
224
- if (!lexical.$isTextNode(child) || !child.isSimpleText()) {
225
- replaceWithChildren(linkNode);
226
- onChange(null, linkNode.getURL());
227
- return;
228
- }
229
- }
230
-
231
- // Check text content fully matches
232
- const text = linkNode.getTextContent();
233
- const match = findFirstMatch(text, matchers);
234
- if (match === null || match.text !== text) {
235
- replaceWithChildren(linkNode);
236
- onChange(null, linkNode.getURL());
237
- return;
238
- }
239
-
240
- // Check neighbors
241
- if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {
242
- replaceWithChildren(linkNode);
243
- onChange(null, linkNode.getURL());
244
- return;
245
- }
246
- const url = linkNode.getURL();
247
- if (url !== match.url) {
248
- linkNode.setURL(match.url);
249
- onChange(match.url, url);
250
- }
251
- if (match.attributes) {
252
- const rel = linkNode.getRel();
253
- if (rel !== match.attributes.rel) {
254
- linkNode.setRel(match.attributes.rel || null);
255
- onChange(match.attributes.rel || null, rel);
256
- }
257
- const target = linkNode.getTarget();
258
- if (target !== match.attributes.target) {
259
- linkNode.setTarget(match.attributes.target || null);
260
- onChange(match.attributes.target || null, target);
261
- }
262
- }
263
- }
264
-
265
- // Bad neighbors are edits in neighbor nodes that make AutoLinks incompatible.
266
- // Given the creation preconditions, these can only be simple text nodes.
267
- function handleBadNeighbors(textNode, matchers, onChange) {
268
- const previousSibling = textNode.getPreviousSibling();
269
- const nextSibling = textNode.getNextSibling();
270
- const text = textNode.getTextContent();
271
- if (link.$isAutoLinkNode(previousSibling) && !previousSibling.getIsUnlinked() && (!startsWithSeparator(text) || startsWithTLD(text, previousSibling.isEmailURI()))) {
272
- previousSibling.append(textNode);
273
- handleLinkEdit(previousSibling, matchers, onChange);
274
- onChange(null, previousSibling.getURL());
275
- }
276
- if (link.$isAutoLinkNode(nextSibling) && !nextSibling.getIsUnlinked() && !endsWithSeparator(text)) {
277
- replaceWithChildren(nextSibling);
278
- handleLinkEdit(nextSibling, matchers, onChange);
279
- onChange(null, nextSibling.getURL());
280
- }
281
- }
282
- function replaceWithChildren(node) {
283
- const children = node.getChildren();
284
- const childrenLength = children.length;
285
- for (let j = childrenLength - 1; j >= 0; j--) {
286
- node.insertAfter(children[j]);
287
- }
288
- node.remove();
289
- return children.map(child => child.getLatest());
290
- }
291
- function getTextNodesToMatch(textNode) {
292
- // check if next siblings are simple text nodes till a node contains a space separator
293
- const textNodesToMatch = [textNode];
294
- let nextSibling = textNode.getNextSibling();
295
- while (nextSibling !== null && lexical.$isTextNode(nextSibling) && nextSibling.isSimpleText()) {
296
- textNodesToMatch.push(nextSibling);
297
- if (/[\s]/.test(nextSibling.getTextContent())) {
298
- break;
299
- }
300
- nextSibling = nextSibling.getNextSibling();
301
- }
302
- return textNodesToMatch;
303
- }
304
29
  function useAutoLink(editor, matchers, onChange) {
305
30
  react.useEffect(() => {
306
31
  if (!editor.hasNodes([link.AutoLinkNode])) {
@@ -308,39 +33,12 @@ function useAutoLink(editor, matchers, onChange) {
308
33
  formatDevErrorMessage(`LexicalAutoLinkPlugin: AutoLinkNode not registered on editor`);
309
34
  }
310
35
  }
311
- const onChangeWrapped = (url, prevUrl) => {
312
- if (onChange) {
313
- onChange(url, prevUrl);
314
- }
315
- };
316
- return utils.mergeRegister(editor.registerNodeTransform(lexical.TextNode, textNode => {
317
- const parent = textNode.getParentOrThrow();
318
- const previous = textNode.getPreviousSibling();
319
- if (link.$isAutoLinkNode(parent) && !parent.getIsUnlinked()) {
320
- handleLinkEdit(parent, matchers, onChangeWrapped);
321
- } else if (!link.$isLinkNode(parent)) {
322
- if (textNode.isSimpleText() && (startsWithSeparator(textNode.getTextContent()) || !link.$isAutoLinkNode(previous))) {
323
- const textNodesToMatch = getTextNodesToMatch(textNode);
324
- $handleLinkCreation(textNodesToMatch, matchers, onChangeWrapped);
325
- }
326
- handleBadNeighbors(textNode, matchers, onChangeWrapped);
327
- }
328
- }), editor.registerCommand(link.TOGGLE_LINK_COMMAND, payload => {
329
- const selection = lexical.$getSelection();
330
- if (payload !== null || !lexical.$isRangeSelection(selection)) {
331
- return false;
332
- }
333
- const nodes = selection.extract();
334
- nodes.forEach(node => {
335
- const parent = node.getParent();
336
- if (link.$isAutoLinkNode(parent)) {
337
- // invert the value
338
- parent.setIsUnlinked(!parent.getIsUnlinked());
339
- parent.markDirty();
340
- }
341
- });
342
- return false;
343
- }, lexical.COMMAND_PRIORITY_LOW));
36
+ });
37
+ react.useEffect(() => {
38
+ return link.registerAutoLink(editor, {
39
+ changeHandlers: onChange ? [onChange] : [],
40
+ matchers
41
+ });
344
42
  }, [editor, matchers, onChange]);
345
43
  }
346
44
  function AutoLinkPlugin({
@@ -352,5 +50,5 @@ function AutoLinkPlugin({
352
50
  return null;
353
51
  }
354
52
 
53
+ exports.createLinkMatcherWithRegExp = link.createLinkMatcherWithRegExp;
355
54
  exports.AutoLinkPlugin = AutoLinkPlugin;
356
- exports.createLinkMatcherWithRegExp = createLinkMatcherWithRegExp;