@lexical/react 0.1.11 → 0.1.12

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 (48) hide show
  1. package/DEPRECATED_useLexical.dev.js +3 -7
  2. package/DEPRECATED_useLexical.prod.js +1 -1
  3. package/DEPRECATED_useLexicalAutoFormatter.dev.js +14 -9
  4. package/DEPRECATED_useLexicalAutoFormatter.prod.js +18 -18
  5. package/DEPRECATED_useLexicalPlainText.dev.js +33 -27
  6. package/DEPRECATED_useLexicalPlainText.prod.js +12 -12
  7. package/DEPRECATED_useLexicalRichText.dev.js +43 -388
  8. package/DEPRECATED_useLexicalRichText.prod.js +17 -25
  9. package/LexicalAutoFormatterPlugin.d.ts +9 -0
  10. package/LexicalAutoFormatterPlugin.dev.js +14 -9
  11. package/LexicalAutoFormatterPlugin.prod.js +18 -18
  12. package/LexicalAutoLinkPlugin.d.ts +20 -0
  13. package/LexicalCharacterLimitPlugin.d.ts +11 -0
  14. package/LexicalClearEditorPlugin.d.ts +14 -0
  15. package/LexicalClearEditorPlugin.dev.js +22 -1
  16. package/LexicalClearEditorPlugin.prod.js +2 -1
  17. package/LexicalCollaborationPlugin.d.ts +49 -0
  18. package/LexicalCollaborationPlugin.js.flow +1 -1
  19. package/LexicalComposer.d.ts +22 -0
  20. package/LexicalComposer.dev.js +27 -5
  21. package/LexicalComposer.js.flow +2 -1
  22. package/LexicalComposer.prod.js +3 -3
  23. package/LexicalComposerContext.d.ts +24 -0
  24. package/LexicalComposerContext.js.flow +1 -1
  25. package/LexicalContentEditable.d.ts +32 -0
  26. package/LexicalContentEditable.dev.js +22 -1
  27. package/LexicalContentEditable.prod.js +3 -3
  28. package/LexicalHashtagPlugin.d.ts +9 -0
  29. package/LexicalHashtagPlugin.js.flow +0 -10
  30. package/LexicalHistoryPlugin.d.ts +29 -0
  31. package/LexicalHorizontalRuleNode.d.ts +23 -0
  32. package/LexicalLinkPlugin.d.ts +9 -0
  33. package/LexicalListPlugin.d.ts +9 -0
  34. package/LexicalNestedComposer.d.ts +20 -0
  35. package/LexicalOnChangePlugin.d.ts +12 -0
  36. package/LexicalPlainTextPlugin.d.ts +15 -0
  37. package/LexicalPlainTextPlugin.dev.js +11 -26
  38. package/LexicalPlainTextPlugin.prod.js +8 -8
  39. package/LexicalRichTextPlugin.d.ts +15 -0
  40. package/LexicalRichTextPlugin.dev.js +24 -390
  41. package/LexicalRichTextPlugin.prod.js +13 -21
  42. package/LexicalTablePlugin.d.ts +9 -0
  43. package/LexicalTreeView.d.ts +17 -0
  44. package/package.json +6 -5
  45. package/useLexicalDecoratorMap.d.ts +14 -0
  46. package/useLexicalIsTextContentEmpty.d.ts +13 -0
  47. package/useLexicalNodeSelection.d.ts +12 -0
  48. package/withSubscriptions.d.ts +12 -0
@@ -10,6 +10,7 @@ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
10
10
  var React = require('react');
11
11
  var lexical = require('lexical');
12
12
  var reactDom = require('react-dom');
13
+ var clipboard = require('@lexical/clipboard');
13
14
 
14
15
  /**
15
16
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -181,6 +182,10 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
181
182
  const isRTL = $isParentElementRTL(selection);
182
183
  $moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
183
184
  }
185
+ function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
186
+ const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
187
+ return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
188
+ }
184
189
 
185
190
  /**
186
191
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -190,17 +195,6 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
190
195
  *
191
196
  *
192
197
  */
193
- function $insertDataTransferForPlainText(dataTransfer, selection) {
194
- const text = dataTransfer.getData('text/plain');
195
-
196
- if (text != null) {
197
- selection.insertRawText(text);
198
- }
199
- }
200
- function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
201
- const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
202
- return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
203
- }
204
198
  function onPasteForPlainText(event, editor) {
205
199
  event.preventDefault();
206
200
  editor.update(() => {
@@ -208,7 +202,7 @@ function onPasteForPlainText(event, editor) {
208
202
  const clipboardData = event.clipboardData;
209
203
 
210
204
  if (clipboardData != null && lexical.$isRangeSelection(selection)) {
211
- $insertDataTransferForPlainText(clipboardData, selection);
205
+ clipboard.$insertDataTransferForPlainText(clipboardData, selection);
212
206
  }
213
207
  });
214
208
  }
@@ -230,19 +224,10 @@ function onCopyForPlainText(event, editor) {
230
224
 
231
225
  if (selection !== null) {
232
226
  if (clipboardData != null) {
233
- const domSelection = window.getSelection(); // If we haven't selected a range, then don't copy anything
234
-
235
- if (domSelection.isCollapsed) {
236
- return;
237
- }
238
-
239
- const range = domSelection.getRangeAt(0);
227
+ const htmlString = clipboard.getHtmlContent(editor);
240
228
 
241
- if (range) {
242
- const container = document.createElement('div');
243
- const frag = range.cloneContents();
244
- container.appendChild(frag);
245
- clipboardData.setData('text/html', container.innerHTML);
229
+ if (htmlString !== null) {
230
+ clipboardData.setData('text/html', htmlString);
246
231
  }
247
232
 
248
233
  clipboardData.setData('text/plain', selection.getTextContent());
@@ -404,7 +389,7 @@ function useLexicalDragonSupport(editor) {
404
389
  *
405
390
  */
406
391
  function usePlainTextSetup(editor, initialEditorState) {
407
- React.useEffect(() => {
392
+ useLayoutEffect(() => {
408
393
  const removeListener = editor.addListener('command', (type, payload) => {
409
394
  const selection = lexical.$getSelection();
410
395
 
@@ -444,7 +429,7 @@ function usePlainTextSetup(editor, initialEditorState) {
444
429
  const dataTransfer = eventOrText.dataTransfer;
445
430
 
446
431
  if (dataTransfer != null) {
447
- $insertDataTransferForPlainText(dataTransfer, selection);
432
+ clipboard.$insertDataTransferForPlainText(dataTransfer, selection);
448
433
  } else {
449
434
  const data = eventOrText.data;
450
435
 
@@ -4,15 +4,15 @@
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
- var g=require("@lexical/react/LexicalComposerContext"),h=require("react"),t=require("lexical"),u=require("react-dom");function v(a,d=!0){if(a)return!1;a=t.$getRoot().getTextContent();d&&(a=a.trim());return""===a}
8
- function w(a){if(!v(a,!1))return!1;a=t.$getRoot().getChildren();const d=a.length;if(1<d)return!1;for(let c=0;c<d;c++){var e=a[c];if(t.$isElementNode(e)){if("paragraph"!==e.__type||0!==e.__indent)return!1;e=e.getChildren();const b=e.length;for(let f=0;f<b;f++)if(!t.$isTextNode(e[c]))return!1}}return!0}function x(a){return()=>w(a)}var y="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;
9
- function z(a){const [d,e]=h.useState(a.getEditorState().read(x(a.isComposing())));y(()=>a.addListener("update",({editorState:c})=>{const b=a.isComposing();c=c.read(x(b));e(c)}),[a]);return d}function A(a){const [d,e]=h.useState(()=>a.getDecorators());y(()=>a.addListener("decorator",c=>{u.flushSync(()=>{e(c)})}),[a]);return h.useMemo(()=>{const c=[],b=Object.keys(d);for(let p=0;p<b.length;p++){var f=b[p];const r=d[f];f=a.getElementByKey(f);null!==f&&c.push(u.createPortal(r,f))}return c},[d,a])}
10
- function C(a){a=a.anchor.getNode();return"rtl"===(t.$isRootNode(a)?a:a.getParentOrThrow()).getDirection()}function D(a,d){a=a.getData("text/plain");null!=a&&d.insertRawText(a)}function E(a,d){a=t.$getDecoratorNode(a.focus,d);return t.$isDecoratorNode(a)&&!a.isIsolated()}function F(a,d){a.preventDefault();d.update(()=>{const e=t.$getSelection(),c=a.clipboardData;null!=c&&t.$isRangeSelection(e)&&D(c,e)})}
11
- function G(a,d){H(a,d);d.update(()=>{const e=t.$getSelection();t.$isRangeSelection(e)&&e.removeText()})}function H(a,d){a.preventDefault();d.update(()=>{const e=a.clipboardData,c=t.$getSelection();if(null!==c&&null!=e){var b=window.getSelection();if(!b.isCollapsed){var f=b.getRangeAt(0);f&&(b=document.createElement("div"),f=f.cloneContents(),b.appendChild(f),e.setData("text/html",b.innerHTML));e.setData("text/plain",c.getTextContent())}}})}const I={tag:"history-merge"};
7
+ var g=require("@lexical/react/LexicalComposerContext"),h=require("react"),t=require("lexical"),u=require("react-dom"),v=require("@lexical/clipboard");function w(a,d=!0){if(a)return!1;a=t.$getRoot().getTextContent();d&&(a=a.trim());return""===a}
8
+ function x(a){if(!w(a,!1))return!1;a=t.$getRoot().getChildren();const d=a.length;if(1<d)return!1;for(let c=0;c<d;c++){var e=a[c];if(t.$isElementNode(e)){if("paragraph"!==e.__type||0!==e.__indent)return!1;e=e.getChildren();const b=e.length;for(let f=0;f<b;f++)if(!t.$isTextNode(e[c]))return!1}}return!0}function y(a){return()=>x(a)}var z="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;
9
+ function A(a){const [d,e]=h.useState(a.getEditorState().read(y(a.isComposing())));z(()=>a.addListener("update",({editorState:c})=>{const b=a.isComposing();c=c.read(y(b));e(c)}),[a]);return d}function C(a){const [d,e]=h.useState(()=>a.getDecorators());z(()=>a.addListener("decorator",c=>{u.flushSync(()=>{e(c)})}),[a]);return h.useMemo(()=>{const c=[],b=Object.keys(d);for(let p=0;p<b.length;p++){var f=b[p];const r=d[f];f=a.getElementByKey(f);null!==f&&c.push(u.createPortal(r,f))}return c},[d,a])}
10
+ function D(a){a=a.anchor.getNode();return"rtl"===(t.$isRootNode(a)?a:a.getParentOrThrow()).getDirection()}function E(a,d){a=t.$getDecoratorNode(a.focus,d);return t.$isDecoratorNode(a)&&!a.isIsolated()}function F(a,d){a.preventDefault();d.update(()=>{const e=t.$getSelection(),c=a.clipboardData;null!=c&&t.$isRangeSelection(e)&&v.$insertDataTransferForPlainText(c,e)})}function G(a,d){H(a,d);d.update(()=>{const e=t.$getSelection();t.$isRangeSelection(e)&&e.removeText()})}
11
+ function H(a,d){a.preventDefault();d.update(()=>{const e=a.clipboardData,c=t.$getSelection();if(null!==c&&null!=e){const b=v.getHtmlContent(d);null!==b&&e.setData("text/html",b);e.setData("text/plain",c.getTextContent())}})}const I={tag:"history-merge"};
12
12
  function J(a,d){if(null!==d)if(void 0===d)a.update(()=>{var e=t.$getRoot();if(null===e.getFirstChild()){const c=t.$createParagraphNode();e.append(c);e=document.activeElement;(null!==t.$getSelection()||null!==e&&e===a.getRootElement())&&c.select()}},I);else if(null!==d)switch(typeof d){case "string":d=a.parseEditorState(d);a.setEditorState(d,I);break;case "object":a.setEditorState(d,I);break;case "function":a.update(d,I)}}
13
13
  function K(a){h.useEffect(()=>{const d=e=>{var c=a.getRootElement();if(document.activeElement===c&&(c=e.data,"string"===typeof c)){try{var b=JSON.parse(c)}catch(f){return}if(b&&"nuanria_messaging"===b.protocol&&"request"===b.type&&(b=b.payload)&&"makeChanges"===b.functionId&&(b=b.args)){const [f,p,r,B,L]=b;a.update(()=>{const q=t.$getSelection();if(t.$isRangeSelection(q)){var n=q.anchor;let k=n.getNode(),l=0,m=0;t.$isTextNode(k)&&0<=f&&0<=p&&(l=f,m=f+p,q.setTextNodeRange(k,l,k,m));if(l!==m||""!==
14
14
  r)q.insertRawText(r),k=n.getNode();t.$isTextNode(k)&&(l=B,m=B+L,n=k.getTextContentSize(),l=l>n?n:l,m=m>n?n:m,q.setTextNodeRange(k,l,k,m));e.stopImmediatePropagation()}})}}};window.addEventListener("message",d,!0);return()=>{window.removeEventListener("message",d,!0)}},[a])}
15
- function M(a,d){h.useEffect(()=>{const e=a.addListener("command",(c,b)=>{const f=t.$getSelection();if(!t.$isRangeSelection(f))return!1;switch(c){case "deleteCharacter":return f.deleteCharacter(b),!0;case "deleteWord":return f.deleteWord(b),!0;case "deleteLine":return f.deleteLine(b),!0;case "insertText":return"string"===typeof b?f.insertText(b):(c=b.dataTransfer,null!=c?D(c,f):(b=b.data)&&f.insertText(b)),!0;case "removeText":return f.removeText(),!0;case "insertLineBreak":return f.insertLineBreak(b),
16
- !0;case "insertParagraph":return f.insertLineBreak(),!0;case "indentContent":case "outdentContent":case "insertHorizontalRule":case "insertImage":case "insertTable":case "formatElement":case "formatText":return!0;case "keyArrowLeft":c=b.shiftKey;if(E(f,!0))return b.preventDefault(),b=c,c=C(f),f.modify(b?"extend":"move",!c,"character"),!0;break;case "keyArrowRight":c=b.shiftKey;if(E(f,!1))return b.preventDefault(),b=c,c=C(f),f.modify(b?"extend":"move",c,"character"),!0;break;case "keyBackspace":return b.preventDefault(),
15
+ function M(a,d){z(()=>{const e=a.addListener("command",(c,b)=>{const f=t.$getSelection();if(!t.$isRangeSelection(f))return!1;switch(c){case "deleteCharacter":return f.deleteCharacter(b),!0;case "deleteWord":return f.deleteWord(b),!0;case "deleteLine":return f.deleteLine(b),!0;case "insertText":return"string"===typeof b?f.insertText(b):(c=b.dataTransfer,null!=c?v.$insertDataTransferForPlainText(c,f):(b=b.data)&&f.insertText(b)),!0;case "removeText":return f.removeText(),!0;case "insertLineBreak":return f.insertLineBreak(b),
16
+ !0;case "insertParagraph":return f.insertLineBreak(),!0;case "indentContent":case "outdentContent":case "insertHorizontalRule":case "insertImage":case "insertTable":case "formatElement":case "formatText":return!0;case "keyArrowLeft":c=b.shiftKey;if(E(f,!0))return b.preventDefault(),b=c,c=D(f),f.modify(b?"extend":"move",!c,"character"),!0;break;case "keyArrowRight":c=b.shiftKey;if(E(f,!1))return b.preventDefault(),b=c,c=D(f),f.modify(b?"extend":"move",c,"character"),!0;break;case "keyBackspace":return b.preventDefault(),
17
17
  a.execCommand("deleteCharacter",!0);case "keyDelete":return b.preventDefault(),a.execCommand("deleteCharacter",!1);case "keyEnter":return b.preventDefault(),a.execCommand("insertLineBreak");case "copy":return H(b,a),!0;case "cut":return G(b,a),!0;case "paste":return F(b,a),!0;case "drop":case "dragstart":return b.preventDefault(),!0}return!1},0);J(a,d);return e},[a]);K(a)}
18
- module.exports=function({contentEditable:a,placeholder:d,initialEditorState:e}){const [c]=g.useLexicalComposerContext(),b=z(c);M(c,e);e=A(c);return h.createElement(h.Fragment,null,a,b&&d,e)};
18
+ module.exports=function({contentEditable:a,placeholder:d,initialEditorState:e}){const [c]=g.useLexicalComposerContext(),b=A(c);M(c,e);e=C(c);return h.createElement(h.Fragment,null,a,b&&d,e)};
@@ -0,0 +1,15 @@
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
+
9
+ import type {EditorState} from 'lexical';
10
+ type InitialEditorStateType = null | string | EditorState | (() => void);
11
+ export default function RichTextPlugin(arg0: {
12
+ contentEditable: React.ReactNode;
13
+ initialEditorState?: InitialEditorStateType;
14
+ placeholder: React.ReactNode;
15
+ }): React.ReactNode;
@@ -10,6 +10,7 @@ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
10
10
  var React = require('react');
11
11
  var lexical = require('lexical');
12
12
  var reactDom = require('react-dom');
13
+ var clipboard = require('@lexical/clipboard');
13
14
 
14
15
  /**
15
16
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -169,188 +170,6 @@ function useDecorators(editor) {
169
170
  *
170
171
  */
171
172
 
172
- function $cloneWithProperties(node) {
173
- const latest = node.getLatest();
174
- const constructor = latest.constructor;
175
- const clone = constructor.clone(latest);
176
- clone.__parent = latest.__parent;
177
-
178
- if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
179
- clone.__children = Array.from(latest.__children);
180
- clone.__format = latest.__format;
181
- clone.__indent = latest.__indent;
182
- clone.__dir = latest.__dir;
183
- } else if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
184
- clone.__format = latest.__format;
185
- clone.__style = latest.__style;
186
- clone.__mode = latest.__mode;
187
- clone.__detail = latest.__detail;
188
- } else if (lexical.$isDecoratorNode(latest) && lexical.$isDecoratorNode(clone)) {
189
- clone.__state = latest.__state;
190
- } // $FlowFixMe
191
-
192
-
193
- return clone;
194
- }
195
-
196
- function $getIndexFromPossibleClone(node, parent, nodeMap) {
197
- const parentClone = nodeMap.get(parent.getKey());
198
-
199
- if (lexical.$isElementNode(parentClone)) {
200
- return parentClone.__children.indexOf(node.getKey());
201
- }
202
-
203
- return node.getIndexWithinParent();
204
- }
205
-
206
- function $getParentAvoidingExcludedElements(node) {
207
- let parent = node.getParent();
208
-
209
- while (parent !== null && parent.excludeFromCopy()) {
210
- parent = parent.getParent();
211
- }
212
-
213
- return parent;
214
- }
215
-
216
- function $copyLeafNodeBranchToRoot(leaf, startingOffset, isLeftSide, range, nodeMap) {
217
- let node = leaf;
218
- let offset = startingOffset;
219
-
220
- while (node !== null) {
221
- const parent = $getParentAvoidingExcludedElements(node);
222
-
223
- if (parent === null) {
224
- break;
225
- }
226
-
227
- if (!lexical.$isElementNode(node) || !node.excludeFromCopy()) {
228
- const key = node.getKey();
229
- let clone = nodeMap.get(key);
230
- const needsClone = clone === undefined;
231
-
232
- if (needsClone) {
233
- clone = $cloneWithProperties(node);
234
- nodeMap.set(key, clone);
235
- }
236
-
237
- if (lexical.$isTextNode(clone) && !clone.isSegmented() && !clone.isToken()) {
238
- clone.__text = clone.__text.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset);
239
- } else if (lexical.$isElementNode(clone)) {
240
- clone.__children = clone.__children.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset + 1);
241
- }
242
-
243
- if (lexical.$isRootNode(parent)) {
244
- if (needsClone) {
245
- // We only want to collect a range of top level nodes.
246
- // So if the parent is the root, we know this is a top level.
247
- range.push(key);
248
- }
249
-
250
- break;
251
- }
252
- }
253
-
254
- offset = $getIndexFromPossibleClone(node, parent, nodeMap);
255
- node = parent;
256
- }
257
- }
258
-
259
- function $cloneContents(selection) {
260
- if (!lexical.$isRangeSelection(selection)) {
261
- {
262
- throw Error(`TODO`);
263
- }
264
- }
265
-
266
- const anchor = selection.anchor;
267
- const focus = selection.focus;
268
- const anchorOffset = anchor.getCharacterOffset();
269
- const focusOffset = focus.getCharacterOffset();
270
- const anchorNode = anchor.getNode();
271
- const focusNode = focus.getNode();
272
- const anchorNodeParent = anchorNode.getParentOrThrow(); // Handle a single text node extraction
273
-
274
- if (anchorNode === focusNode && lexical.$isTextNode(anchorNode) && (anchorNodeParent.canBeEmpty() || anchorNodeParent.getChildrenSize() > 1)) {
275
- const clonedFirstNode = $cloneWithProperties(anchorNode);
276
- const isBefore = focusOffset > anchorOffset;
277
- const startOffset = isBefore ? anchorOffset : focusOffset;
278
- const endOffset = isBefore ? focusOffset : anchorOffset;
279
- clonedFirstNode.__text = clonedFirstNode.__text.slice(startOffset, endOffset);
280
- const key = clonedFirstNode.getKey();
281
- return {
282
- nodeMap: [[key, clonedFirstNode]],
283
- range: [key]
284
- };
285
- }
286
-
287
- const nodes = selection.getNodes();
288
-
289
- if (nodes.length === 0) {
290
- return {
291
- nodeMap: [],
292
- range: []
293
- };
294
- } // Check if we can use the parent of the nodes, if the
295
- // parent can't be empty, then it's important that we
296
- // also copy that element node along with its children.
297
-
298
-
299
- let nodesLength = nodes.length;
300
- const firstNode = nodes[0];
301
- const firstNodeParent = firstNode.getParent();
302
-
303
- if (firstNodeParent !== null && (!firstNodeParent.canBeEmpty() || lexical.$isRootNode(firstNodeParent))) {
304
- const parentChildren = firstNodeParent.__children;
305
- const parentChildrenLength = parentChildren.length;
306
-
307
- if (parentChildrenLength === nodesLength) {
308
- let areTheSame = true;
309
-
310
- for (let i = 0; i < parentChildren.length; i++) {
311
- if (parentChildren[i] !== nodes[i].__key) {
312
- areTheSame = false;
313
- break;
314
- }
315
- }
316
-
317
- if (areTheSame) {
318
- nodesLength++;
319
- nodes.push(firstNodeParent);
320
- }
321
- }
322
- }
323
-
324
- const lastNode = nodes[nodesLength - 1];
325
- const isBefore = anchor.isBefore(focus);
326
- const nodeMap = new Map();
327
- const range = []; // Do first node to root
328
-
329
- $copyLeafNodeBranchToRoot(firstNode, isBefore ? anchorOffset : focusOffset, true, range, nodeMap); // Copy all nodes between
330
-
331
- for (let i = 0; i < nodesLength; i++) {
332
- const node = nodes[i];
333
- const key = node.getKey();
334
-
335
- if (!nodeMap.has(key) && (!lexical.$isElementNode(node) || !node.excludeFromCopy())) {
336
- const clone = $cloneWithProperties(node);
337
-
338
- if (lexical.$isRootNode(node.getParent())) {
339
- range.push(node.getKey());
340
- }
341
-
342
- nodeMap.set(key, clone);
343
- }
344
- } // Do last node to root
345
-
346
-
347
- $copyLeafNodeBranchToRoot(lastNode, isBefore ? focusOffset : anchorOffset, false, range, nodeMap);
348
- return {
349
- nodeMap: Array.from(nodeMap.entries()),
350
- range
351
- };
352
- }
353
-
354
173
  function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
355
174
  selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
356
175
  }
@@ -363,6 +182,10 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
363
182
  const isRTL = $isParentElementRTL(selection);
364
183
  $moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
365
184
  }
185
+ function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
186
+ const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
187
+ return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
188
+ }
366
189
 
367
190
  /**
368
191
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -372,197 +195,6 @@ function $moveCharacter(selection, isHoldingShift, isBackward) {
372
195
  *
373
196
  *
374
197
  */
375
-
376
- function $generateNodes(nodeRange) {
377
- const {
378
- range,
379
- nodeMap
380
- } = nodeRange;
381
- const parsedNodeMap = new Map(nodeMap);
382
- const nodes = [];
383
-
384
- for (let i = 0; i < range.length; i++) {
385
- const key = range[i];
386
- const parsedNode = parsedNodeMap.get(key);
387
-
388
- if (parsedNode !== undefined) {
389
- const node = lexical.$createNodeFromParse(parsedNode, parsedNodeMap);
390
- nodes.push(node);
391
- }
392
- }
393
-
394
- return nodes;
395
- }
396
-
397
- function getConversionFunction(domNode, editor) {
398
- const {
399
- nodeName
400
- } = domNode;
401
-
402
- const cachedConversions = editor._htmlConversions.get(nodeName.toLowerCase());
403
-
404
- let currentConversion = null;
405
-
406
- if (cachedConversions !== undefined) {
407
- cachedConversions.forEach(cachedConversion => {
408
- const domConversion = cachedConversion(domNode);
409
-
410
- if (domConversion !== null) {
411
- if (currentConversion === null || currentConversion.priority < domConversion.priority) {
412
- currentConversion = domConversion;
413
- }
414
- }
415
- });
416
- }
417
-
418
- return currentConversion !== null ? currentConversion.conversion : null;
419
- }
420
-
421
- function $createNodesFromDOM(node, editor, forChildMap = new Map()) {
422
- let lexicalNodes = [];
423
- let currentLexicalNode = null;
424
- const transformFunction = getConversionFunction(node, editor);
425
- const transformOutput = transformFunction ? transformFunction(node) : null;
426
- let postTransform = null;
427
-
428
- if (transformOutput !== null) {
429
- postTransform = transformOutput.after;
430
- currentLexicalNode = transformOutput.node;
431
-
432
- if (currentLexicalNode !== null) {
433
- lexicalNodes.push(currentLexicalNode);
434
- const forChildFunctions = Array.from(forChildMap.values());
435
-
436
- for (let i = 0; i < forChildFunctions.length; i++) {
437
- forChildFunctions[i](currentLexicalNode);
438
- }
439
- }
440
-
441
- if (transformOutput.forChild != null) {
442
- forChildMap.set(node.nodeName, transformOutput.forChild);
443
- }
444
- } // If the DOM node doesn't have a transformer, we don't know what
445
- // to do with it but we still need to process any childNodes.
446
-
447
-
448
- const children = node.childNodes;
449
- let childLexicalNodes = [];
450
-
451
- for (let i = 0; i < children.length; i++) {
452
- childLexicalNodes.push(...$createNodesFromDOM(children[i], editor, forChildMap));
453
- }
454
-
455
- if (postTransform != null) {
456
- childLexicalNodes = postTransform(childLexicalNodes);
457
- }
458
-
459
- if (currentLexicalNode == null) {
460
- // If it hasn't been converted to a LexicalNode, we hoist its children
461
- // up to the same level as it.
462
- lexicalNodes = lexicalNodes.concat(childLexicalNodes);
463
- } else {
464
- if (lexical.$isElementNode(currentLexicalNode)) {
465
- // If the current node is a ElementNode after conversion,
466
- // we can append all the children to it.
467
- currentLexicalNode.append(...childLexicalNodes);
468
- }
469
- }
470
-
471
- return lexicalNodes;
472
- }
473
-
474
- function $generateNodesFromDOM(dom, editor) {
475
- let lexicalNodes = [];
476
- const elements = dom.body ? Array.from(dom.body.childNodes) : [];
477
- const elementsLength = elements.length;
478
-
479
- for (let i = 0; i < elementsLength; i++) {
480
- const lexicalNode = $createNodesFromDOM(elements[i], editor);
481
-
482
- if (lexicalNode !== null) {
483
- lexicalNodes = lexicalNodes.concat(lexicalNode);
484
- }
485
- }
486
-
487
- return lexicalNodes;
488
- }
489
-
490
- function $insertDataTransferForRichText(dataTransfer, selection, editor) {
491
- const lexicalNodesString = dataTransfer.getData('application/x-lexical-editor');
492
-
493
- if (lexicalNodesString) {
494
- const namespace = editor._config.namespace;
495
-
496
- try {
497
- const lexicalClipboardData = JSON.parse(lexicalNodesString);
498
-
499
- if (lexicalClipboardData.namespace === namespace) {
500
- const nodeRange = lexicalClipboardData.state;
501
- const nodes = $generateNodes(nodeRange);
502
- selection.insertNodes(nodes);
503
- return;
504
- }
505
- } catch (e) {// Malformed, missing nodes..
506
- }
507
- }
508
-
509
- const textHtmlMimeType = 'text/html';
510
- const htmlString = dataTransfer.getData(textHtmlMimeType);
511
-
512
- if (htmlString) {
513
- const parser = new DOMParser();
514
- const dom = parser.parseFromString(htmlString, textHtmlMimeType);
515
- const nodes = $generateNodesFromDOM(dom, editor); // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
516
-
517
- const topLevelBlocks = [];
518
- let currentBlock = null;
519
-
520
- for (let i = 0; i < nodes.length; i++) {
521
- const node = nodes[i];
522
-
523
- if (!lexical.$isElementNode(node) || node.isInline()) {
524
- if (currentBlock === null) {
525
- currentBlock = lexical.$createParagraphNode();
526
- topLevelBlocks.push(currentBlock);
527
- }
528
-
529
- if (currentBlock !== null) {
530
- currentBlock.append(node);
531
- }
532
- } else {
533
- topLevelBlocks.push(node);
534
- currentBlock = null;
535
- }
536
- }
537
-
538
- selection.insertNodes(topLevelBlocks);
539
- return;
540
- }
541
-
542
- $insertDataTransferForPlainText(dataTransfer, selection);
543
- }
544
- function $insertDataTransferForPlainText(dataTransfer, selection) {
545
- const text = dataTransfer.getData('text/plain');
546
-
547
- if (text != null) {
548
- selection.insertRawText(text);
549
- }
550
- }
551
- function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
552
- const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
553
- return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
554
- }
555
- function onPasteForRichText(event, editor) {
556
- event.preventDefault();
557
- editor.update(() => {
558
- const selection = lexical.$getSelection();
559
- const clipboardData = event.clipboardData;
560
-
561
- if (clipboardData != null && lexical.$isRangeSelection(selection)) {
562
- $insertDataTransferForRichText(clipboardData, selection, editor);
563
- }
564
- });
565
- }
566
198
  function onCutForRichText(event, editor) {
567
199
  onCopyForRichText(event, editor);
568
200
  editor.update(() => {
@@ -581,31 +213,33 @@ function onCopyForRichText(event, editor) {
581
213
 
582
214
  if (selection !== null) {
583
215
  if (clipboardData != null) {
584
- const domSelection = window.getSelection(); // If we haven't selected a range, then don't copy anything
216
+ const htmlString = clipboard.getHtmlContent(editor);
217
+ const lexicalString = clipboard.$getLexicalContent(editor);
585
218
 
586
- if (domSelection.isCollapsed) {
587
- return;
219
+ if (htmlString !== null) {
220
+ clipboardData.setData('text/html', htmlString);
588
221
  }
589
222
 
590
- const range = domSelection.getRangeAt(0);
591
-
592
- if (range) {
593
- const container = document.createElement('div');
594
- const frag = range.cloneContents();
595
- container.appendChild(frag);
596
- clipboardData.setData('text/html', container.innerHTML);
223
+ if (lexicalString !== null) {
224
+ clipboardData.setData('application/x-lexical-editor', lexicalString);
597
225
  }
598
226
 
599
227
  clipboardData.setData('text/plain', selection.getTextContent());
600
- const namespace = editor._config.namespace;
601
- clipboardData.setData('application/x-lexical-editor', JSON.stringify({
602
- namespace,
603
- state: $cloneContents(selection)
604
- }));
605
228
  }
606
229
  }
607
230
  });
608
231
  }
232
+ function onPasteForRichText(event, editor) {
233
+ event.preventDefault();
234
+ editor.update(() => {
235
+ const selection = lexical.$getSelection();
236
+ const clipboardData = event.clipboardData;
237
+
238
+ if (clipboardData != null && lexical.$isRangeSelection(selection)) {
239
+ clipboard.$insertDataTransferForRichText(clipboardData, selection, editor);
240
+ }
241
+ });
242
+ }
609
243
 
610
244
  /**
611
245
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -760,7 +394,7 @@ function useLexicalDragonSupport(editor) {
760
394
  *
761
395
  */
762
396
  function useRichTextSetup(editor, initialEditorState) {
763
- React.useLayoutEffect(() => {
397
+ useLayoutEffect(() => {
764
398
  const removeListener = editor.addListener('command', (type, payload) => {
765
399
  const selection = lexical.$getSelection();
766
400
 
@@ -805,7 +439,7 @@ function useRichTextSetup(editor, initialEditorState) {
805
439
  const dataTransfer = eventOrText.dataTransfer;
806
440
 
807
441
  if (dataTransfer != null) {
808
- $insertDataTransferForRichText(dataTransfer, selection, editor);
442
+ clipboard.$insertDataTransferForRichText(dataTransfer, selection, editor);
809
443
  } else {
810
444
  const data = eventOrText.data;
811
445