@lexical/react 0.8.1 → 0.9.1

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 (95) hide show
  1. package/LexicalAutoEmbedPlugin.d.ts +1 -0
  2. package/LexicalAutoEmbedPlugin.dev.js +11 -0
  3. package/LexicalAutoFocusPlugin.dev.js +1 -0
  4. package/LexicalAutoLinkPlugin.d.ts +7 -0
  5. package/LexicalAutoLinkPlugin.dev.js +63 -7
  6. package/LexicalAutoLinkPlugin.js.flow +5 -0
  7. package/LexicalAutoLinkPlugin.prod.js +1 -1
  8. package/LexicalBlockWithAlignableContents.dev.js +13 -2
  9. package/LexicalBlockWithAlignableContents.prod.js +4 -4
  10. package/LexicalCharacterLimitPlugin.d.ts +1 -0
  11. package/LexicalCharacterLimitPlugin.dev.js +46 -7
  12. package/LexicalCheckListPlugin.dev.js +48 -10
  13. package/LexicalClearEditorPlugin.d.ts +1 -0
  14. package/LexicalClearEditorPlugin.dev.js +1 -1
  15. package/LexicalCollaborationContext.dev.js +3 -0
  16. package/LexicalCollaborationPlugin.d.ts +3 -2
  17. package/LexicalCollaborationPlugin.dev.js +35 -6
  18. package/LexicalComposer.d.ts +1 -0
  19. package/LexicalComposer.dev.js +10 -6
  20. package/LexicalComposerContext.dev.js +6 -0
  21. package/LexicalContentEditable.dev.js +0 -1
  22. package/LexicalDecoratorBlockNode.d.ts +1 -0
  23. package/LexicalDecoratorBlockNode.dev.js +5 -0
  24. package/LexicalErrorBoundary.d.ts +1 -0
  25. package/LexicalHashtagPlugin.d.ts +1 -0
  26. package/LexicalHashtagPlugin.dev.js +43 -73
  27. package/LexicalHorizontalRuleNode.d.ts +3 -2
  28. package/LexicalHorizontalRuleNode.dev.js +22 -0
  29. package/LexicalHorizontalRulePlugin.dev.js +4 -0
  30. package/LexicalLinkPlugin.dev.js +10 -4
  31. package/LexicalListPlugin.dev.js +2 -0
  32. package/LexicalMarkdownShortcutPlugin.dev.js +2 -2
  33. package/LexicalNestedComposer.dev.js +12 -6
  34. package/LexicalNestedComposer.prod.js +2 -2
  35. package/LexicalNodeEventPlugin.dev.js +3 -5
  36. package/LexicalOnChangePlugin.d.ts +1 -1
  37. package/LexicalOnChangePlugin.dev.js +2 -2
  38. package/LexicalOnChangePlugin.prod.js +2 -2
  39. package/LexicalPlainTextPlugin.d.ts +1 -0
  40. package/LexicalPlainTextPlugin.dev.js +12 -8
  41. package/LexicalRichTextPlugin.d.ts +1 -0
  42. package/LexicalRichTextPlugin.dev.js +12 -8
  43. package/LexicalTabIndentationPlugin.dev.js +3 -1
  44. package/{LexicalTableOfContents__EXPERIMENTAL.d.ts → LexicalTableOfContents.d.ts} +1 -0
  45. package/{LexicalTableOfContents__EXPERIMENTAL.dev.js → LexicalTableOfContents.dev.js} +33 -5
  46. package/{DEPRECATED_useLexical.js → LexicalTableOfContents.js} +2 -2
  47. package/LexicalTablePlugin.d.ts +1 -0
  48. package/LexicalTablePlugin.dev.js +19 -5
  49. package/LexicalTreeView.d.ts +1 -0
  50. package/LexicalTreeView.dev.js +113 -21
  51. package/LexicalTreeView.prod.js +16 -15
  52. package/LexicalTypeaheadMenuPlugin.dev.js +123 -17
  53. package/LexicalTypeaheadMenuPlugin.prod.js +18 -18
  54. package/package.json +19 -19
  55. package/shared/useYjsCollaboration.d.ts +3 -4
  56. package/useLexicalEditable.dev.js +5 -1
  57. package/useLexicalIsTextContentEmpty.dev.js +0 -1
  58. package/useLexicalNodeSelection.dev.js +7 -0
  59. package/useLexicalSubscription.dev.js +3 -1
  60. package/DEPRECATED_useLexical.d.ts +0 -18
  61. package/DEPRECATED_useLexical.dev.js +0 -104
  62. package/DEPRECATED_useLexical.js.flow +0 -25
  63. package/DEPRECATED_useLexical.prod.js +0 -8
  64. package/DEPRECATED_useLexicalCanShowPlaceholder.d.ts +0 -9
  65. package/DEPRECATED_useLexicalCanShowPlaceholder.dev.js +0 -72
  66. package/DEPRECATED_useLexicalCanShowPlaceholder.js +0 -9
  67. package/DEPRECATED_useLexicalCanShowPlaceholder.js.flow +0 -15
  68. package/DEPRECATED_useLexicalCanShowPlaceholder.prod.js +0 -8
  69. package/DEPRECATED_useLexicalCharacterLimit.d.ts +0 -8
  70. package/DEPRECATED_useLexicalCharacterLimit.dev.js +0 -213
  71. package/DEPRECATED_useLexicalCharacterLimit.js +0 -9
  72. package/DEPRECATED_useLexicalCharacterLimit.js.flow +0 -31
  73. package/DEPRECATED_useLexicalCharacterLimit.prod.js +0 -13
  74. package/DEPRECATED_useLexicalEditor.d.ts +0 -9
  75. package/DEPRECATED_useLexicalEditor.dev.js +0 -87
  76. package/DEPRECATED_useLexicalEditor.js +0 -9
  77. package/DEPRECATED_useLexicalEditor.prod.js +0 -8
  78. package/DEPRECATED_useLexicalHistory.d.ts +0 -12
  79. package/DEPRECATED_useLexicalHistory.dev.js +0 -38
  80. package/DEPRECATED_useLexicalHistory.js +0 -9
  81. package/DEPRECATED_useLexicalHistory.js.flow +0 -34
  82. package/DEPRECATED_useLexicalHistory.prod.js +0 -7
  83. package/DEPRECATED_useLexicalPlainText.d.ts +0 -10
  84. package/DEPRECATED_useLexicalPlainText.dev.js +0 -88
  85. package/DEPRECATED_useLexicalPlainText.js +0 -9
  86. package/DEPRECATED_useLexicalPlainText.js.flow +0 -17
  87. package/DEPRECATED_useLexicalPlainText.prod.js +0 -8
  88. package/DEPRECATED_useLexicalRichText.d.ts +0 -10
  89. package/DEPRECATED_useLexicalRichText.dev.js +0 -88
  90. package/DEPRECATED_useLexicalRichText.js +0 -9
  91. package/DEPRECATED_useLexicalRichText.js.flow +0 -17
  92. package/DEPRECATED_useLexicalRichText.prod.js +0 -8
  93. package/LexicalTableOfContents__EXPERIMENTAL.js +0 -9
  94. /package/{LexicalTableOfContents__EXPERIMENTAL.js.flow → LexicalTableOfContents.js.flow} +0 -0
  95. /package/{LexicalTableOfContents__EXPERIMENTAL.prod.js → LexicalTableOfContents.prod.js} +0 -0
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  /**
2
3
  * Copyright (c) Meta Platforms, Inc. and affiliates.
3
4
  *
@@ -28,6 +28,7 @@ class AutoEmbedOption extends LexicalTypeaheadMenuPlugin.TypeaheadOption {
28
28
  this.title = title;
29
29
  this.onSelect = options.onSelect.bind(this);
30
30
  }
31
+
31
32
  }
32
33
  function LexicalAutoEmbedPlugin({
33
34
  embedConfigs,
@@ -45,10 +46,12 @@ function LexicalAutoEmbedPlugin({
45
46
  const checkIfLinkNodeIsEmbeddable = React.useCallback(key => {
46
47
  editor.getEditorState().read(async () => {
47
48
  const linkNode = lexical.$getNodeByKey(key);
49
+
48
50
  if (link.$isLinkNode(linkNode)) {
49
51
  for (let i = 0; i < embedConfigs.length; i++) {
50
52
  const embedConfig = embedConfigs[i];
51
53
  const urlMatch = await Promise.resolve(embedConfig.parseUrl(linkNode.__url));
54
+
52
55
  if (urlMatch != null) {
53
56
  setActiveEmbedConfig(embedConfig);
54
57
  setNodeKey(linkNode.getKey());
@@ -70,6 +73,7 @@ function LexicalAutoEmbedPlugin({
70
73
  }
71
74
  }
72
75
  };
76
+
73
77
  return utils.mergeRegister(...[link.LinkNode, link.AutoLinkNode].map(Klass => editor.registerMutationListener(Klass, (...args) => listener(...args))));
74
78
  }, [checkIfLinkNodeIsEmbeddable, editor, embedConfigs, nodeKey, reset]);
75
79
  React.useEffect(() => {
@@ -77,10 +81,12 @@ function LexicalAutoEmbedPlugin({
77
81
  const embedConfig = embedConfigs.find(({
78
82
  type
79
83
  }) => type === embedConfigType);
84
+
80
85
  if (embedConfig) {
81
86
  onOpenEmbedModalForConfig(embedConfig);
82
87
  return true;
83
88
  }
89
+
84
90
  return false;
85
91
  }, lexical.COMMAND_PRIORITY_EDITOR);
86
92
  }, [editor, embedConfigs, onOpenEmbedModalForConfig]);
@@ -88,16 +94,21 @@ function LexicalAutoEmbedPlugin({
88
94
  if (activeEmbedConfig != null && nodeKey != null) {
89
95
  const linkNode = editor.getEditorState().read(() => {
90
96
  const node = lexical.$getNodeByKey(nodeKey);
97
+
91
98
  if (link.$isLinkNode(node)) {
92
99
  return node;
93
100
  }
101
+
94
102
  return null;
95
103
  });
104
+
96
105
  if (link.$isLinkNode(linkNode)) {
97
106
  const result = await Promise.resolve(activeEmbedConfig.parseUrl(linkNode.__url));
107
+
98
108
  if (result != null) {
99
109
  editor.update(() => {
100
110
  activeEmbedConfig.insertNode(editor, result);
111
+
101
112
  if (linkNode.isAttached()) {
102
113
  linkNode.remove();
103
114
  }
@@ -28,6 +28,7 @@ function AutoFocusPlugin({
28
28
  // of this plugin, which should preserve focus too.
29
29
  const activeElement = document.activeElement;
30
30
  const rootElement = editor.getRootElement();
31
+
31
32
  if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
32
33
  // Note: preventScroll won't work in Webkit.
33
34
  rootElement.focus({
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
+ /// <reference types="react" />
8
9
  import type { LinkAttributes } from '@lexical/link';
9
10
  declare type ChangeHandler = (url: string | null, prevUrl: string | null) => void;
10
11
  declare type LinkMatcherResult = {
@@ -15,6 +16,12 @@ declare type LinkMatcherResult = {
15
16
  url: string;
16
17
  };
17
18
  export declare 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;
18
25
  export declare function AutoLinkPlugin({ matchers, onChange, }: {
19
26
  matchers: Array<LinkMatcher>;
20
27
  onChange?: ChangeHandler;
@@ -19,65 +19,98 @@ var react = require('react');
19
19
  * LICENSE file in the root directory of this source tree.
20
20
  *
21
21
  */
22
+ function createLinkMatcherWithRegExp(regExp, urlTransformer = text => text) {
23
+ return text => {
24
+ const match = regExp.exec(text);
25
+ if (match === null) return null;
26
+ return {
27
+ index: match.index,
28
+ length: match[0].length,
29
+ text: match[0],
30
+ url: urlTransformer(text)
31
+ };
32
+ };
33
+ }
34
+
22
35
  function findFirstMatch(text, matchers) {
23
36
  for (let i = 0; i < matchers.length; i++) {
24
37
  const match = matchers[i](text);
38
+
25
39
  if (match) {
26
40
  return match;
27
41
  }
28
42
  }
43
+
29
44
  return null;
30
45
  }
46
+
31
47
  const PUNCTUATION_OR_SPACE = /[.,;\s]/;
48
+
32
49
  function isSeparator(char) {
33
50
  return PUNCTUATION_OR_SPACE.test(char);
34
51
  }
52
+
35
53
  function endsWithSeparator(textContent) {
36
54
  return isSeparator(textContent[textContent.length - 1]);
37
55
  }
56
+
38
57
  function startsWithSeparator(textContent) {
39
58
  return isSeparator(textContent[0]);
40
59
  }
60
+
41
61
  function isPreviousNodeValid(node) {
42
62
  let previousNode = node.getPreviousSibling();
63
+
43
64
  if (lexical.$isElementNode(previousNode)) {
44
65
  previousNode = previousNode.getLastDescendant();
45
66
  }
67
+
46
68
  return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
47
69
  }
70
+
48
71
  function isNextNodeValid(node) {
49
72
  let nextNode = node.getNextSibling();
73
+
50
74
  if (lexical.$isElementNode(nextNode)) {
51
75
  nextNode = nextNode.getFirstDescendant();
52
76
  }
77
+
53
78
  return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
54
79
  }
80
+
55
81
  function isContentAroundIsValid(matchStart, matchEnd, text, node) {
56
82
  const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(node);
83
+
57
84
  if (!contentBeforeIsValid) {
58
85
  return false;
59
86
  }
87
+
60
88
  const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(node);
61
89
  return contentAfterIsValid;
62
90
  }
91
+
63
92
  function handleLinkCreation(node, matchers, onChange) {
64
93
  const nodeText = node.getTextContent();
65
94
  let text = nodeText;
66
95
  let invalidMatchEnd = 0;
67
96
  let remainingTextNode = node;
68
97
  let match;
98
+
69
99
  while ((match = findFirstMatch(text, matchers)) && match !== null) {
70
100
  const matchStart = match.index;
71
101
  const matchLength = match.length;
72
102
  const matchEnd = matchStart + matchLength;
73
103
  const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, nodeText, node);
104
+
74
105
  if (isValid) {
75
106
  let linkTextNode;
107
+
76
108
  if (invalidMatchEnd + matchStart === 0) {
77
109
  [linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchLength);
78
110
  } else {
79
111
  [, linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchStart, invalidMatchEnd + matchStart + matchLength);
80
112
  }
113
+
81
114
  const linkNode = link.$createAutoLinkNode(match.url, match.attributes);
82
115
  const textNode = lexical.$createTextNode(match.text);
83
116
  textNode.setFormat(linkTextNode.getFormat());
@@ -89,82 +122,99 @@ function handleLinkCreation(node, matchers, onChange) {
89
122
  } else {
90
123
  invalidMatchEnd += matchEnd;
91
124
  }
125
+
92
126
  text = text.substring(matchEnd);
93
127
  }
94
128
  }
129
+
95
130
  function handleLinkEdit(linkNode, matchers, onChange) {
96
131
  // Check children are simple text
97
132
  const children = linkNode.getChildren();
98
133
  const childrenLength = children.length;
134
+
99
135
  for (let i = 0; i < childrenLength; i++) {
100
136
  const child = children[i];
137
+
101
138
  if (!lexical.$isTextNode(child) || !child.isSimpleText()) {
102
139
  replaceWithChildren(linkNode);
103
140
  onChange(null, linkNode.getURL());
104
141
  return;
105
142
  }
106
- }
143
+ } // Check text content fully matches
144
+
107
145
 
108
- // Check text content fully matches
109
146
  const text = linkNode.getTextContent();
110
147
  const match = findFirstMatch(text, matchers);
148
+
111
149
  if (match === null || match.text !== text) {
112
150
  replaceWithChildren(linkNode);
113
151
  onChange(null, linkNode.getURL());
114
152
  return;
115
- }
153
+ } // Check neighbors
154
+
116
155
 
117
- // Check neighbors
118
156
  if (!isPreviousNodeValid(linkNode) || !isNextNodeValid(linkNode)) {
119
157
  replaceWithChildren(linkNode);
120
158
  onChange(null, linkNode.getURL());
121
159
  return;
122
160
  }
161
+
123
162
  const url = linkNode.getURL();
163
+
124
164
  if (url !== match.url) {
125
165
  linkNode.setURL(match.url);
126
166
  onChange(match.url, url);
127
167
  }
168
+
128
169
  if (match.attributes) {
129
170
  const rel = linkNode.getRel();
171
+
130
172
  if (rel !== match.attributes.rel) {
131
173
  linkNode.setRel(match.attributes.rel || null);
132
174
  onChange(match.attributes.rel || null, rel);
133
175
  }
176
+
134
177
  const target = linkNode.getTarget();
178
+
135
179
  if (target !== match.attributes.target) {
136
180
  linkNode.setTarget(match.attributes.target || null);
137
181
  onChange(match.attributes.target || null, target);
138
182
  }
139
183
  }
140
- }
141
-
142
- // Bad neighbours are edits in neighbor nodes that make AutoLinks incompatible.
184
+ } // Bad neighbours are edits in neighbor nodes that make AutoLinks incompatible.
143
185
  // Given the creation preconditions, these can only be simple text nodes.
186
+
187
+
144
188
  function handleBadNeighbors(textNode, matchers, onChange) {
145
189
  const previousSibling = textNode.getPreviousSibling();
146
190
  const nextSibling = textNode.getNextSibling();
147
191
  const text = textNode.getTextContent();
192
+
148
193
  if (link.$isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {
149
194
  previousSibling.append(textNode);
150
195
  handleLinkEdit(previousSibling, matchers, onChange);
151
196
  onChange(null, previousSibling.getURL());
152
197
  }
198
+
153
199
  if (link.$isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {
154
200
  replaceWithChildren(nextSibling);
155
201
  handleLinkEdit(nextSibling, matchers, onChange);
156
202
  onChange(null, nextSibling.getURL());
157
203
  }
158
204
  }
205
+
159
206
  function replaceWithChildren(node) {
160
207
  const children = node.getChildren();
161
208
  const childrenLength = children.length;
209
+
162
210
  for (let j = childrenLength - 1; j >= 0; j--) {
163
211
  node.insertAfter(children[j]);
164
212
  }
213
+
165
214
  node.remove();
166
215
  return children.map(child => child.getLatest());
167
216
  }
217
+
168
218
  function useAutoLink(editor, matchers, onChange) {
169
219
  react.useEffect(() => {
170
220
  if (!editor.hasNodes([link.AutoLinkNode])) {
@@ -172,25 +222,30 @@ function useAutoLink(editor, matchers, onChange) {
172
222
  throw Error(`LexicalAutoLinkPlugin: AutoLinkNode not registered on editor`);
173
223
  }
174
224
  }
225
+
175
226
  const onChangeWrapped = (url, prevUrl) => {
176
227
  if (onChange) {
177
228
  onChange(url, prevUrl);
178
229
  }
179
230
  };
231
+
180
232
  return utils.mergeRegister(editor.registerNodeTransform(lexical.TextNode, textNode => {
181
233
  const parent = textNode.getParentOrThrow();
182
234
  const previous = textNode.getPreviousSibling();
235
+
183
236
  if (link.$isAutoLinkNode(parent)) {
184
237
  handleLinkEdit(parent, matchers, onChangeWrapped);
185
238
  } else if (!link.$isLinkNode(parent)) {
186
239
  if (textNode.isSimpleText() && (startsWithSeparator(textNode.getTextContent()) || !link.$isAutoLinkNode(previous))) {
187
240
  handleLinkCreation(textNode, matchers, onChangeWrapped);
188
241
  }
242
+
189
243
  handleBadNeighbors(textNode, matchers, onChangeWrapped);
190
244
  }
191
245
  }));
192
246
  }, [editor, matchers, onChange]);
193
247
  }
248
+
194
249
  function AutoLinkPlugin({
195
250
  matchers,
196
251
  onChange
@@ -201,3 +256,4 @@ function AutoLinkPlugin({
201
256
  }
202
257
 
203
258
  exports.AutoLinkPlugin = AutoLinkPlugin;
259
+ exports.createLinkMatcherWithRegExp = createLinkMatcherWithRegExp;
@@ -21,6 +21,11 @@ type LinkMatcherResult = {
21
21
 
22
22
  export type LinkMatcher = (text: string) => LinkMatcherResult | null;
23
23
 
24
+ declare export function createLinkMatcherWithRegExp(
25
+ regExp: RegExp,
26
+ urlTransformer?: (text: string) => string,
27
+ ): LinkMatcher;
28
+
24
29
  declare export function AutoLinkPlugin(props: {
25
30
  matchers: Array<LinkMatcher>,
26
31
  onChange?: ChangeHandler,
@@ -10,4 +10,4 @@ function F(a,b,c){var d=a.getChildren();let e=d.length;for(let f=0;f<e;f++){let
10
10
  null,d)))):(G(a),c(null,a.getURL()))}function G(a){let b=a.getChildren();var c=b.length;for(--c;0<=c;c--)a.insertAfter(b[c]);a.remove();return b.map(d=>d.getLatest())}
11
11
  function H(a,b,c){w.useEffect(()=>{if(!a.hasNodes([h.AutoLinkNode]))throw Error("Minified Lexical error #77; visit https://lexical.dev/docs/error?code=77 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");let d=(e,f)=>{c&&c(e,f)};return p.mergeRegister(a.registerNodeTransform(u.TextNode,e=>{var f=e.getParentOrThrow(),l=e.getPreviousSibling();if(h.$isAutoLinkNode(f))F(f,b,d);else if(!h.$isLinkNode(f)){if(e.isSimpleText()&&(B.test(e.getTextContent()[0])||
12
12
  !h.$isAutoLinkNode(l))){l=f=e.getTextContent();let m=0,v=e;for(var g;(g=A(l,b))&&null!==g;){let r=g.index,x=g.length,y=r+x;var t=m+r,q=m+y,z=f,D=e;if((0<t?B.test(z[t-1]):C(D))&&(q<z.length?B.test(z[q]):E(D))){var k=void 0;0===m+r?[k,v]=v.splitText(m+x):[,k,v]=v.splitText(m+r,m+r+x);t=h.$createAutoLinkNode(g.url,g.attributes);q=u.$createTextNode(g.text);q.setFormat(k.getFormat());q.setDetail(k.getDetail());t.append(q);k.replace(t);c&&c(g.url,null);m=0}else m+=y;l=l.substring(y)}}f=e.getPreviousSibling();
13
- g=e.getNextSibling();k=e.getTextContent();h.$isAutoLinkNode(f)&&!B.test(k[0])&&(f.append(e),F(f,b,d),e=f.getURL(),c&&c(null,e));h.$isAutoLinkNode(g)&&!B.test(k[k.length-1])&&(G(g),F(g,b,d),e=g.getURL(),c&&c(null,e))}}))},[a,b,c])}exports.AutoLinkPlugin=function({matchers:a,onChange:b}){let [c]=n.useLexicalComposerContext();H(c,a,b);return null}
13
+ g=e.getNextSibling();k=e.getTextContent();h.$isAutoLinkNode(f)&&!B.test(k[0])&&(f.append(e),F(f,b,d),e=f.getURL(),c&&c(null,e));h.$isAutoLinkNode(g)&&!B.test(k[k.length-1])&&(G(g),F(g,b,d),e=g.getURL(),c&&c(null,e))}}))},[a,b,c])}exports.AutoLinkPlugin=function({matchers:a,onChange:b}){let [c]=n.useLexicalComposerContext();H(c,a,b);return null};exports.createLinkMatcherWithRegExp=function(a,b=c=>c){return c=>{let d=a.exec(c);return null===d?null:{index:d.index,length:d[0].length,text:d[0],url:b(c)}}}
@@ -34,25 +34,31 @@ function BlockWithAlignableContents({
34
34
  event.preventDefault();
35
35
  editor.update(() => {
36
36
  const node = lexical.$getNodeByKey(nodeKey);
37
+ if (node === null) return;
38
+ lexical.$setSelection(node.selectPrevious());
39
+
37
40
  if (lexical.$isDecoratorNode(node)) {
38
41
  node.remove();
39
42
  }
40
- setSelected(false);
41
43
  });
42
44
  }
45
+
43
46
  return false;
44
- }, [editor, isSelected, nodeKey, setSelected]);
47
+ }, [editor, isSelected, nodeKey]);
45
48
  React.useEffect(() => {
46
49
  return utils.mergeRegister(editor.registerCommand(lexical.FORMAT_ELEMENT_COMMAND, formatType => {
47
50
  if (isSelected) {
48
51
  const selection = lexical.$getSelection();
52
+
49
53
  if (lexical.$isNodeSelection(selection)) {
50
54
  const node = lexical.$getNodeByKey(nodeKey);
55
+
51
56
  if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
52
57
  node.setFormat(formatType);
53
58
  }
54
59
  } else if (lexical.$isRangeSelection(selection)) {
55
60
  const nodes = selection.getNodes();
61
+
56
62
  for (const node of nodes) {
57
63
  if (LexicalDecoratorBlockNode.$isDecoratorBlockNode(node)) {
58
64
  node.setFormat(formatType);
@@ -62,18 +68,23 @@ function BlockWithAlignableContents({
62
68
  }
63
69
  }
64
70
  }
71
+
65
72
  return true;
66
73
  }
74
+
67
75
  return false;
68
76
  }, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.CLICK_COMMAND, event => {
69
77
  if (event.target === ref.current) {
70
78
  event.preventDefault();
79
+
71
80
  if (!event.shiftKey) {
72
81
  clearSelection();
73
82
  }
83
+
74
84
  setSelected(!isSelected);
75
85
  return true;
76
86
  }
87
+
77
88
  return false;
78
89
  }, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_DELETE_COMMAND, onDelete, lexical.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, onDelete, lexical.COMMAND_PRIORITY_LOW));
79
90
  }, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected]);
@@ -4,7 +4,7 @@
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 a=require("@lexical/react/LexicalComposerContext"),h=require("@lexical/react/LexicalDecoratorBlockNode"),m=require("@lexical/react/useLexicalNodeSelection"),n=require("@lexical/utils"),u=require("lexical"),v=require("react");
8
- exports.BlockWithAlignableContents=function({children:w,format:p,nodeKey:g,className:q}){let [d]=a.useLexicalComposerContext(),[e,k,r]=m.useLexicalNodeSelection(g),t=v.useRef(null),l=v.useCallback(b=>{e&&u.$isNodeSelection(u.$getSelection())&&(b.preventDefault(),d.update(()=>{const c=u.$getNodeByKey(g);u.$isDecoratorNode(c)&&c.remove();k(!1)}));return!1},[d,e,g,k]);v.useEffect(()=>n.mergeRegister(d.registerCommand(u.FORMAT_ELEMENT_COMMAND,b=>{if(e){var c=u.$getSelection();if(u.$isNodeSelection(c)){var f=
9
- u.$getNodeByKey(g);h.$isDecoratorBlockNode(f)&&f.setFormat(b)}else if(u.$isRangeSelection(c)){c=c.getNodes();for(f of c)h.$isDecoratorBlockNode(f)?f.setFormat(b):n.$getNearestBlockElementAncestorOrThrow(f).setFormat(b)}return!0}return!1},u.COMMAND_PRIORITY_LOW),d.registerCommand(u.CLICK_COMMAND,b=>b.target===t.current?(b.preventDefault(),b.shiftKey||r(),k(!e),!0):!1,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_DELETE_COMMAND,l,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_BACKSPACE_COMMAND,l,
10
- u.COMMAND_PRIORITY_LOW)),[r,d,e,g,l,k]);return v.createElement("div",{className:[q.base,e?q.focus:null].filter(Boolean).join(" "),ref:t,style:{textAlign:p?p:void 0}},w)}
7
+ 'use strict';var a=require("@lexical/react/LexicalComposerContext"),h=require("@lexical/react/LexicalDecoratorBlockNode"),l=require("@lexical/react/useLexicalNodeSelection"),m=require("@lexical/utils"),u=require("lexical"),v=require("react");
8
+ exports.BlockWithAlignableContents=function({children:w,format:n,nodeKey:g,className:p}){let [d]=a.useLexicalComposerContext(),[e,q,r]=l.useLexicalNodeSelection(g),t=v.useRef(null),k=v.useCallback(c=>{e&&u.$isNodeSelection(u.$getSelection())&&(c.preventDefault(),d.update(()=>{const b=u.$getNodeByKey(g);null!==b&&(u.$setSelection(b.selectPrevious()),u.$isDecoratorNode(b)&&b.remove())}));return!1},[d,e,g]);v.useEffect(()=>m.mergeRegister(d.registerCommand(u.FORMAT_ELEMENT_COMMAND,c=>{if(e){var b=u.$getSelection();
9
+ if(u.$isNodeSelection(b)){var f=u.$getNodeByKey(g);h.$isDecoratorBlockNode(f)&&f.setFormat(c)}else if(u.$isRangeSelection(b)){b=b.getNodes();for(f of b)h.$isDecoratorBlockNode(f)?f.setFormat(c):m.$getNearestBlockElementAncestorOrThrow(f).setFormat(c)}return!0}return!1},u.COMMAND_PRIORITY_LOW),d.registerCommand(u.CLICK_COMMAND,c=>c.target===t.current?(c.preventDefault(),c.shiftKey||r(),q(!e),!0):!1,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_DELETE_COMMAND,k,u.COMMAND_PRIORITY_LOW),d.registerCommand(u.KEY_BACKSPACE_COMMAND,
10
+ k,u.COMMAND_PRIORITY_LOW)),[r,d,e,g,k,q]);return v.createElement("div",{className:[p.base,e?p.focus:null].filter(Boolean).join(" "),ref:t,style:{textAlign:n?n:void 0}},w)}
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
+ /// <reference types="react" />
8
9
  export declare function CharacterLimitPlugin({ charset, maxLength, }: {
9
10
  charset: 'UTF-8' | 'UTF-16';
10
11
  maxLength: number;
@@ -45,13 +45,16 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
45
45
  }) => {
46
46
  const isComposing = editor.isComposing();
47
47
  const hasDirtyLeaves = dirtyLeaves.size > 0;
48
+
48
49
  if (isComposing || !hasDirtyLeaves) {
49
50
  return;
50
51
  }
52
+
51
53
  const textLength = strlen(text$1);
52
54
  const textLengthAboveThreshold = textLength > maxCharacters || lastComputedTextLength !== null && lastComputedTextLength > maxCharacters;
53
55
  const diff = maxCharacters - textLength;
54
56
  remainingCharacters(diff);
57
+
55
58
  if (lastComputedTextLength === null || textLengthAboveThreshold) {
56
59
  const offset = findOffset(text$1, maxCharacters, strlen);
57
60
  editor.update(() => {
@@ -60,62 +63,75 @@ function useCharacterLimit(editor, maxCharacters, optional = Object.freeze({}))
60
63
  tag: 'history-merge'
61
64
  });
62
65
  }
66
+
63
67
  lastComputedTextLength = textLength;
64
68
  }));
65
69
  }, [editor, maxCharacters, remainingCharacters, strlen]);
66
70
  }
71
+
67
72
  function findOffset(text, maxCharacters, strlen) {
68
73
  // @ts-ignore This is due to be added in a later version of TS
69
74
  const Segmenter = Intl.Segmenter;
70
75
  let offsetUtf16 = 0;
71
76
  let offset = 0;
77
+
72
78
  if (typeof Segmenter === 'function') {
73
79
  const segmenter = new Segmenter();
74
80
  const graphemes = segmenter.segment(text);
81
+
75
82
  for (const {
76
83
  segment: grapheme
77
84
  } of graphemes) {
78
85
  const nextOffset = offset + strlen(grapheme);
86
+
79
87
  if (nextOffset > maxCharacters) {
80
88
  break;
81
89
  }
90
+
82
91
  offset = nextOffset;
83
92
  offsetUtf16 += grapheme.length;
84
93
  }
85
94
  } else {
86
95
  const codepoints = Array.from(text);
87
96
  const codepointsLength = codepoints.length;
97
+
88
98
  for (let i = 0; i < codepointsLength; i++) {
89
99
  const codepoint = codepoints[i];
90
100
  const nextOffset = offset + strlen(codepoint);
101
+
91
102
  if (nextOffset > maxCharacters) {
92
103
  break;
93
104
  }
105
+
94
106
  offset = nextOffset;
95
107
  offsetUtf16 += codepoint.length;
96
108
  }
97
109
  }
110
+
98
111
  return offsetUtf16;
99
112
  }
113
+
100
114
  function $wrapOverflowedNodes(offset) {
101
115
  const dfsNodes = utils.$dfs();
102
116
  const dfsNodesLength = dfsNodes.length;
103
117
  let accumulatedLength = 0;
118
+
104
119
  for (let i = 0; i < dfsNodesLength; i += 1) {
105
120
  const {
106
121
  node
107
122
  } = dfsNodes[i];
123
+
108
124
  if (overflow.$isOverflowNode(node)) {
109
125
  const previousLength = accumulatedLength;
110
126
  const nextLength = accumulatedLength + node.getTextContentSize();
127
+
111
128
  if (nextLength <= offset) {
112
129
  const parent = node.getParent();
113
130
  const previousSibling = node.getPreviousSibling();
114
131
  const nextSibling = node.getNextSibling();
115
132
  $unwrapNode(node);
116
- const selection = lexical.$getSelection();
133
+ const selection = lexical.$getSelection(); // Restore selection when the overflow children are removed
117
134
 
118
- // Restore selection when the overflow children are removed
119
135
  if (lexical.$isRangeSelection(selection) && (!selection.anchor.getNode().isAttached() || !selection.focus.getNode().isAttached())) {
120
136
  if (lexical.$isTextNode(previousSibling)) {
121
137
  previousSibling.select();
@@ -128,11 +144,12 @@ function $wrapOverflowedNodes(offset) {
128
144
  } else if (previousLength < offset) {
129
145
  const descendant = node.getFirstDescendant();
130
146
  const descendantLength = descendant !== null ? descendant.getTextContentSize() : 0;
131
- const previousPlusDescendantLength = previousLength + descendantLength;
132
- // For simple text we can redimension the overflow into a smaller and more accurate
147
+ const previousPlusDescendantLength = previousLength + descendantLength; // For simple text we can redimension the overflow into a smaller and more accurate
133
148
  // container
149
+
134
150
  const firstDescendantIsSimpleText = lexical.$isTextNode(descendant) && descendant.isSimpleText();
135
151
  const firstDescendantDoesNotOverflow = previousPlusDescendantLength <= offset;
152
+
136
153
  if (firstDescendantIsSimpleText || firstDescendantDoesNotOverflow) {
137
154
  $unwrapNode(node);
138
155
  }
@@ -140,49 +157,59 @@ function $wrapOverflowedNodes(offset) {
140
157
  } else if (lexical.$isLeafNode(node)) {
141
158
  const previousAccumulatedLength = accumulatedLength;
142
159
  accumulatedLength += node.getTextContentSize();
160
+
143
161
  if (accumulatedLength > offset && !overflow.$isOverflowNode(node.getParent())) {
144
162
  const previousSelection = lexical.$getSelection();
145
- let overflowNode;
146
-
147
- // For simple text we can improve the limit accuracy by splitting the TextNode
163
+ let overflowNode; // For simple text we can improve the limit accuracy by splitting the TextNode
148
164
  // on the split point
165
+
149
166
  if (previousAccumulatedLength < offset && lexical.$isTextNode(node) && node.isSimpleText()) {
150
167
  const [, overflowedText] = node.splitText(offset - previousAccumulatedLength);
151
168
  overflowNode = $wrapNode(overflowedText);
152
169
  } else {
153
170
  overflowNode = $wrapNode(node);
154
171
  }
172
+
155
173
  if (previousSelection !== null) {
156
174
  lexical.$setSelection(previousSelection);
157
175
  }
176
+
158
177
  mergePrevious(overflowNode);
159
178
  }
160
179
  }
161
180
  }
162
181
  }
182
+
163
183
  function $wrapNode(node) {
164
184
  const overflowNode = overflow.$createOverflowNode();
165
185
  node.insertBefore(overflowNode);
166
186
  overflowNode.append(node);
167
187
  return overflowNode;
168
188
  }
189
+
169
190
  function $unwrapNode(node) {
170
191
  const children = node.getChildren();
171
192
  const childrenLength = children.length;
193
+
172
194
  for (let i = 0; i < childrenLength; i++) {
173
195
  node.insertBefore(children[i]);
174
196
  }
197
+
175
198
  node.remove();
176
199
  return childrenLength > 0 ? children[childrenLength - 1] : null;
177
200
  }
201
+
178
202
  function mergePrevious(overflowNode) {
179
203
  const previousNode = overflowNode.getPreviousSibling();
204
+
180
205
  if (!overflow.$isOverflowNode(previousNode)) {
181
206
  return;
182
207
  }
208
+
183
209
  const firstChild = overflowNode.getFirstChild();
184
210
  const previousNodeChildren = previousNode.getChildren();
185
211
  const previousNodeChildrenLength = previousNodeChildren.length;
212
+
186
213
  if (firstChild === null) {
187
214
  overflowNode.append(...previousNodeChildren);
188
215
  } else {
@@ -190,23 +217,28 @@ function mergePrevious(overflowNode) {
190
217
  firstChild.insertBefore(previousNodeChildren[i]);
191
218
  }
192
219
  }
220
+
193
221
  const selection = lexical.$getSelection();
222
+
194
223
  if (lexical.$isRangeSelection(selection)) {
195
224
  const anchor = selection.anchor;
196
225
  const anchorNode = anchor.getNode();
197
226
  const focus = selection.focus;
198
227
  const focusNode = anchor.getNode();
228
+
199
229
  if (anchorNode.is(previousNode)) {
200
230
  anchor.set(overflowNode.getKey(), anchor.offset, 'element');
201
231
  } else if (anchorNode.is(overflowNode)) {
202
232
  anchor.set(overflowNode.getKey(), previousNodeChildrenLength + anchor.offset, 'element');
203
233
  }
234
+
204
235
  if (focusNode.is(previousNode)) {
205
236
  focus.set(overflowNode.getKey(), focus.offset, 'element');
206
237
  } else if (focusNode.is(overflowNode)) {
207
238
  focus.set(overflowNode.getKey(), previousNodeChildrenLength + focus.offset, 'element');
208
239
  }
209
240
  }
241
+
210
242
  previousNode.remove();
211
243
  }
212
244
 
@@ -219,24 +251,31 @@ function mergePrevious(overflowNode) {
219
251
  */
220
252
  const CHARACTER_LIMIT = 5;
221
253
  let textEncoderInstance = null;
254
+
222
255
  function textEncoder() {
223
256
  if (window.TextEncoder === undefined) {
224
257
  return null;
225
258
  }
259
+
226
260
  if (textEncoderInstance === null) {
227
261
  textEncoderInstance = new window.TextEncoder();
228
262
  }
263
+
229
264
  return textEncoderInstance;
230
265
  }
266
+
231
267
  function utf8Length(text) {
232
268
  const currentTextEncoder = textEncoder();
269
+
233
270
  if (currentTextEncoder === null) {
234
271
  // http://stackoverflow.com/a/5515960/210370
235
272
  const m = encodeURIComponent(text).match(/%[89ABab]/g);
236
273
  return text.length + (m ? m.length : 0);
237
274
  }
275
+
238
276
  return currentTextEncoder.encode(text).length;
239
277
  }
278
+
240
279
  function CharacterLimitPlugin({
241
280
  charset = 'UTF-16',
242
281
  maxLength = CHARACTER_LIMIT