@lexical/clipboard 0.3.0 → 0.3.3

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.
@@ -23,8 +23,8 @@ export function $insertDataTransferForRichText(
23
23
  editor: LexicalEditor,
24
24
  ): void;
25
25
 
26
- export function $getHtmlContent(editor: LexicalEditor): string;
27
-
26
+ export function $getHtmlContent(editor: LexicalEditor): string | null;
27
+ export function $getLexicalContent(editor: LexicalEditor): string | null;
28
28
  /*
29
29
  * Plain Text
30
30
  */
@@ -7,6 +7,7 @@
7
7
  'use strict';
8
8
 
9
9
  var html = require('@lexical/html');
10
+ var selection = require('@lexical/selection');
10
11
  var utils = require('@lexical/utils');
11
12
  var lexical = require('lexical');
12
13
 
@@ -31,6 +32,20 @@ function $getHtmlContent(editor) {
31
32
 
32
33
  return html.$generateHtmlFromNodes(editor, selection);
33
34
  }
35
+ function $getLexicalContent(editor) {
36
+ const selection = lexical.$getSelection();
37
+
38
+ if (selection == null) {
39
+ throw new Error('Expected valid LexicalSelection');
40
+ } // If we haven't selected anything
41
+
42
+
43
+ if (lexical.$isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {
44
+ return null;
45
+ }
46
+
47
+ return JSON.stringify($generateJSONFromSelectedNodes(editor, selection));
48
+ }
34
49
  function $insertDataTransferForPlainText(dataTransfer, selection) {
35
50
  const text = dataTransfer.getData('text/plain');
36
51
 
@@ -39,25 +54,42 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
39
54
  }
40
55
  }
41
56
  function $insertDataTransferForRichText(dataTransfer, selection, editor) {
42
- const isSelectionInsideOfGrid = lexical.$isGridSelection(selection) || utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isGridCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => lexical.$isGridCellNode(n)) !== null;
43
- const textHtmlMimeType = 'text/html';
44
- const htmlString = dataTransfer.getData(textHtmlMimeType);
57
+ const htmlString = dataTransfer.getData('text/html');
58
+ const lexicalString = dataTransfer.getData('application/x-lexical-editor');
59
+
60
+ if (lexicalString) {
61
+ try {
62
+ const payload = JSON.parse(lexicalString);
63
+
64
+ if (payload.namespace === editor._config.namespace && Array.isArray(payload.nodes)) {
65
+ const nodes = $generateNodesFromSerializedNodes(payload.nodes);
66
+ return $insertGeneratedNodes(editor, nodes, selection);
67
+ } // eslint-disable-next-line no-empty
68
+
69
+ } catch {}
70
+ }
45
71
 
46
72
  if (htmlString) {
47
- const parser = new DOMParser();
48
- const dom = parser.parseFromString(htmlString, textHtmlMimeType);
49
- const nodes = html.$generateNodesFromDOM(editor, dom);
73
+ try {
74
+ const parser = new DOMParser();
75
+ const dom = parser.parseFromString(htmlString, 'text/html');
76
+ return $insertGeneratedNodes(editor, html.$generateNodesFromDOM(editor, dom), selection); // eslint-disable-next-line no-empty
77
+ } catch {}
78
+ }
50
79
 
51
- if (isSelectionInsideOfGrid && nodes.length === 1 && lexical.$isGridNode(nodes[0])) {
52
- $mergeGridNodesStrategy(nodes, selection, false, editor);
53
- return;
54
- }
80
+ $insertDataTransferForPlainText(dataTransfer, selection);
81
+ }
82
+
83
+ function $insertGeneratedNodes(editor, nodes, selection) {
84
+ const isSelectionInsideOfGrid = lexical.$isGridSelection(selection) || utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isGridCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => lexical.$isGridCellNode(n)) !== null;
55
85
 
56
- $basicInsertStrategy(nodes, selection, false);
86
+ if (isSelectionInsideOfGrid && nodes.length === 1 && lexical.$isGridNode(nodes[0])) {
87
+ $mergeGridNodesStrategy(nodes, selection, false, editor);
57
88
  return;
58
89
  }
59
90
 
60
- $insertDataTransferForPlainText(dataTransfer, selection);
91
+ $basicInsertStrategy(nodes, selection, false);
92
+ return;
61
93
  }
62
94
 
63
95
  function $basicInsertStrategy(nodes, selection, isFromLexical) {
@@ -210,6 +242,96 @@ function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
210
242
  }
211
243
  }
212
244
 
245
+ function exportNodeToJSON(node) {
246
+ const serializedNode = node.exportJSON();
247
+ const nodeClass = node.constructor; // @ts-expect-error TODO Replace Class utility type with InstanceType
248
+
249
+ if (serializedNode.type !== nodeClass.getType()) {
250
+ {
251
+ throw Error(`LexicalNode: Node ${nodeClass.name} does not implement .exportJSON().`);
252
+ }
253
+ } // @ts-expect-error TODO Replace Class utility type with InstanceType
254
+
255
+
256
+ const serializedChildren = serializedNode.children;
257
+
258
+ if (lexical.$isElementNode(node)) {
259
+ if (!Array.isArray(serializedChildren)) {
260
+ {
261
+ throw Error(`LexicalNode: Node ${nodeClass.name} is an element but .exportJSON() does not have a children array.`);
262
+ }
263
+ }
264
+ }
265
+
266
+ return serializedNode;
267
+ }
268
+
269
+ function $appendNodesToJSON(editor, selection$1, currentNode, targetArray) {
270
+ let shouldInclude = selection$1 != null ? currentNode.isSelected() : true;
271
+ const shouldExclude = lexical.$isElementNode(currentNode) && currentNode.excludeFromCopy('html');
272
+ let clone = selection.$cloneWithProperties(currentNode);
273
+ clone = lexical.$isTextNode(clone) && selection$1 != null ? selection.$sliceSelectedTextNodeContent(selection$1, clone) : clone;
274
+ const children = lexical.$isElementNode(clone) ? clone.getChildren() : [];
275
+ const serializedNode = exportNodeToJSON(clone); // TODO: TextNode calls getTextContent() (NOT node.__text) within it's exportJSON method
276
+ // which uses getLatest() to get the text from the original node with the same key.
277
+ // This is a deeper issue with the word "clone" here, it's still a reference to the
278
+ // same node as far as the LexicalEditor is concerned since it shares a key.
279
+ // We need a way to create a clone of a Node in memory with it's own key, but
280
+ // until then this hack will work for the selected text extract use case.
281
+
282
+ if (lexical.$isTextNode(clone)) {
283
+ // @ts-ignore
284
+ serializedNode.text = clone.__text;
285
+ }
286
+
287
+ for (let i = 0; i < children.length; i++) {
288
+ const childNode = children[i];
289
+ const shouldIncludeChild = $appendNodesToJSON(editor, selection$1, childNode, serializedNode.children);
290
+
291
+ if (!shouldInclude && lexical.$isElementNode(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection$1, 'clone')) {
292
+ shouldInclude = true;
293
+ }
294
+ }
295
+
296
+ if (shouldInclude && !shouldExclude) {
297
+ targetArray.push(serializedNode);
298
+ } else if (Array.isArray(serializedNode.children)) {
299
+ for (let i = 0; i < serializedNode.children.length; i++) {
300
+ const serializedChildNode = serializedNode.children[i];
301
+ targetArray.push(serializedChildNode);
302
+ }
303
+ }
304
+
305
+ return shouldInclude;
306
+ }
307
+
308
+ function $generateJSONFromSelectedNodes(editor, selection) {
309
+ const nodes = [];
310
+ const root = lexical.$getRoot();
311
+ const topLevelChildren = root.getChildren();
312
+
313
+ for (let i = 0; i < topLevelChildren.length; i++) {
314
+ const topLevelNode = topLevelChildren[i];
315
+ $appendNodesToJSON(editor, selection, topLevelNode, nodes);
316
+ }
317
+
318
+ return {
319
+ namespace: editor._config.namespace,
320
+ nodes
321
+ };
322
+ }
323
+ function $generateNodesFromSerializedNodes(serializedNodes) {
324
+ const nodes = [];
325
+
326
+ for (let i = 0; i < serializedNodes.length; i++) {
327
+ const serializedNode = serializedNodes[i];
328
+ nodes.push(lexical.$parseSerializedNode(serializedNode));
329
+ }
330
+
331
+ return nodes;
332
+ }
333
+
213
334
  exports.$getHtmlContent = $getHtmlContent;
335
+ exports.$getLexicalContent = $getLexicalContent;
214
336
  exports.$insertDataTransferForPlainText = $insertDataTransferForPlainText;
215
337
  exports.$insertDataTransferForRichText = $insertDataTransferForRichText;
@@ -24,8 +24,10 @@ declare export function $insertDataTransferForRichText(
24
24
  editor: LexicalEditor,
25
25
  ): void;
26
26
 
27
- declare export function $getHtmlContent(editor: LexicalEditor): string;
28
-
27
+ declare export function $getHtmlContent(editor: LexicalEditor): string | null;
28
+ declare export function $getLexicalContent(
29
+ editor: LexicalEditor,
30
+ ): string | null;
29
31
  /*
30
32
  * Plain Text
31
33
  */
@@ -4,9 +4,13 @@
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 b=require("@lexical/html"),l=require("@lexical/utils"),n=require("lexical");function y(a){throw Error(`Minified Lexical error #${a}; see codes.json for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function z(a,c){a=a.getData("text/plain");null!=a&&c.insertRawText(a)}
8
- function C(a,c,f){if(!f){f=[];let h=null;for(let e=0;e<a.length;e++){let d=a[e];n.$isDecoratorNode(d)&&!d.isTopLevel()||n.$isElementNode(d)&&d.isInline()||n.$isTextNode(d)||n.$isLineBreakNode(d)?(null===h&&(h=n.$createParagraphNode(),f.push(h)),null!==h&&h.append(d)):(f.push(d),h=null)}a=f}n.$isRangeSelection(c)?c.insertNodes(a):n.$isGridSelection(c)&&(c=c.anchor.getNode(),n.$isGridCellNode(c)||y(41),c.append(...a))}
9
- function D(a,c,f,h){1===a.length&&n.$isGridNode(a[0])||y(42);var e=a[0];a=e.getChildren();f=e.getFirstChildOrThrow().getChildrenSize();var d=e.getChildrenSize(),k=l.$findMatchingParent(c.anchor.getNode(),g=>n.$isGridCellNode(g));c=(e=k&&l.$findMatchingParent(k,g=>n.$isGridRowNode(g)))&&l.$findMatchingParent(e,g=>n.$isGridNode(g));n.$isGridCellNode(k)&&n.$isGridRowNode(e)&&n.$isGridNode(c)||y(43);var m=e.getIndexWithinParent(),t=Math.min(c.getChildrenSize()-1,m+d-1);d=k.getIndexWithinParent();k=Math.min(e.getChildrenSize()-
10
- 1,d+f-1);f=Math.min(d,k);e=Math.min(m,t);d=Math.max(d,k);m=Math.max(m,t);t=c.getChildren();k=0;let w,x;for(let g=e;g<=m;g++){var u=t[g];n.$isGridRowNode(u)||y(24);var v=a[k];n.$isGridRowNode(v)||y(24);u=u.getChildren();v=v.getChildren();let A=0;for(let p=f;p<=d;p++){let q=u[p];n.$isGridCellNode(q)||y(25);let B=v[A];n.$isGridCellNode(B)||y(25);g===e&&p===f?w=q.getKey():g===m&&p===d&&(x=q.getKey());let E=q.getChildren();B.getChildren().forEach(r=>{n.$isTextNode(r)&&n.$createParagraphNode().append(r);
11
- q.append(r)});E.forEach(r=>r.remove());A++}k++}w&&x&&(a=n.$createGridSelection(),a.set(c.getKey(),w,x),n.$setSelection(a),h.dispatchCommand(n.SELECTION_CHANGE_COMMAND,void 0))}exports.$getHtmlContent=function(a){let c=n.$getSelection();if(null==c)throw Error("Expected valid LexicalSelection");return n.$isRangeSelection(c)&&c.isCollapsed()||0===c.getNodes().length?null:b.$generateHtmlFromNodes(a,c)};exports.$insertDataTransferForPlainText=z;
12
- exports.$insertDataTransferForRichText=function(a,c,f){let h=n.$isGridSelection(c)||null!==l.$findMatchingParent(c.anchor.getNode(),d=>n.$isGridCellNode(d))&&null!==l.$findMatchingParent(c.focus.getNode(),d=>n.$isGridCellNode(d)),e=a.getData("text/html");e?(a=(new DOMParser).parseFromString(e,"text/html"),a=b.$generateNodesFromDOM(f,a),h&&1===a.length&&n.$isGridNode(a[0])?D(a,c,!1,f):C(a,c,!1)):z(a,c)}
7
+ 'use strict';var b=require("@lexical/html"),p=require("@lexical/selection"),t=require("@lexical/utils"),y=require("lexical");function z(c){throw Error(`Minified Lexical error #${c}; see codes.json for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function A(c,a){c=c.getData("text/plain");null!=c&&a.insertRawText(c)}
8
+ function B(c,a,d){(y.$isGridSelection(d)||null!==t.$findMatchingParent(d.anchor.getNode(),h=>y.$isGridCellNode(h))&&null!==t.$findMatchingParent(d.focus.getNode(),h=>y.$isGridCellNode(h)))&&1===a.length&&y.$isGridNode(a[0])?E(a,d,!1,c):F(a,d,!1)}
9
+ function F(c,a,d){if(!d){d=[];let h=null;for(let g=0;g<c.length;g++){let f=c[g];y.$isDecoratorNode(f)&&!f.isTopLevel()||y.$isElementNode(f)&&f.isInline()||y.$isTextNode(f)||y.$isLineBreakNode(f)?(null===h&&(h=y.$createParagraphNode(),d.push(h)),null!==h&&h.append(f)):(d.push(f),h=null)}c=d}y.$isRangeSelection(a)?a.insertNodes(c):y.$isGridSelection(a)&&(a=a.anchor.getNode(),y.$isGridCellNode(a)||z(41),a.append(...c))}
10
+ function E(c,a,d,h){1===c.length&&y.$isGridNode(c[0])||z(42);var g=c[0];c=g.getChildren();d=g.getFirstChildOrThrow().getChildrenSize();var f=g.getChildrenSize(),e=t.$findMatchingParent(a.anchor.getNode(),l=>y.$isGridCellNode(l));a=(g=e&&t.$findMatchingParent(e,l=>y.$isGridRowNode(l)))&&t.$findMatchingParent(g,l=>y.$isGridNode(l));y.$isGridCellNode(e)&&y.$isGridRowNode(g)&&y.$isGridNode(a)||z(43);var m=g.getIndexWithinParent(),n=Math.min(a.getChildrenSize()-1,m+f-1);f=e.getIndexWithinParent();e=Math.min(g.getChildrenSize()-
11
+ 1,f+d-1);d=Math.min(f,e);g=Math.min(m,n);f=Math.max(f,e);m=Math.max(m,n);n=a.getChildren();e=0;let k,q;for(let l=g;l<=m;l++){var r=n[l];y.$isGridRowNode(r)||z(24);var x=c[e];y.$isGridRowNode(x)||z(24);r=r.getChildren();x=x.getChildren();let C=0;for(let u=d;u<=f;u++){let v=r[u];y.$isGridCellNode(v)||z(25);let D=x[C];y.$isGridCellNode(D)||z(25);l===g&&u===d?k=v.getKey():l===m&&u===f&&(q=v.getKey());let H=v.getChildren();D.getChildren().forEach(w=>{y.$isTextNode(w)&&y.$createParagraphNode().append(w);
12
+ v.append(w)});H.forEach(w=>w.remove());C++}e++}k&&q&&(c=y.$createGridSelection(),c.set(a.getKey(),k,q),y.$setSelection(c),h.dispatchCommand(y.SELECTION_CHANGE_COMMAND,void 0))}
13
+ function G(c,a,d,h){let g=null!=a?d.isSelected():!0,f=y.$isElementNode(d)&&d.excludeFromCopy("html");var e=p.$cloneWithProperties(d);e=y.$isTextNode(e)&&null!=a?p.$sliceSelectedTextNodeContent(a,e):e;let m=y.$isElementNode(e)?e.getChildren():[];var n=e;let k=n.exportJSON();var q=n.constructor;k.type!==q.getType()&&z(58,q.name);let r=k.children;y.$isElementNode(n)&&(Array.isArray(r)||z(59,q.name));y.$isTextNode(e)&&(k.text=e.__text);for(e=0;e<m.length;e++)n=m[e],q=G(c,a,n,k.children),!g&&y.$isElementNode(d)&&
14
+ q&&d.extractWithChild(n,a,"clone")&&(g=!0);if(g&&!f)h.push(k);else if(Array.isArray(k.children))for(c=0;c<k.children.length;c++)h.push(k.children[c]);return g}exports.$getHtmlContent=function(c){let a=y.$getSelection();if(null==a)throw Error("Expected valid LexicalSelection");return y.$isRangeSelection(a)&&a.isCollapsed()||0===a.getNodes().length?null:b.$generateHtmlFromNodes(c,a)};
15
+ exports.$getLexicalContent=function(c){let a=y.$getSelection();if(null==a)throw Error("Expected valid LexicalSelection");if(y.$isRangeSelection(a)&&a.isCollapsed()||0===a.getNodes().length)return null;var d=JSON,h=d.stringify;let g=[],f=y.$getRoot().getChildren();for(let e=0;e<f.length;e++)G(c,a,f[e],g);return h.call(d,{namespace:c._config.namespace,nodes:g})};exports.$insertDataTransferForPlainText=A;
16
+ exports.$insertDataTransferForRichText=function(c,a,d){let h=c.getData("text/html");var g=c.getData("application/x-lexical-editor");if(g)try{var f=JSON.parse(g);if(f.namespace===d._config.namespace&&Array.isArray(f.nodes)){var e=f.nodes;g=[];for(f=0;f<e.length;f++)g.push(y.$parseSerializedNode(e[f]));return B(d,g,a)}}catch{}if(h)try{let m=(new DOMParser).parseFromString(h,"text/html");return B(d,b.$generateNodesFromDOM(d,m),a)}catch{}A(c,a)}
package/package.json CHANGED
@@ -9,15 +9,15 @@
9
9
  "paste"
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "0.3.0",
12
+ "version": "0.3.3",
13
13
  "main": "LexicalClipboard.js",
14
14
  "peerDependencies": {
15
- "lexical": "0.3.0"
15
+ "lexical": "0.3.3"
16
16
  },
17
17
  "dependencies": {
18
- "@lexical/utils": "0.3.0",
19
- "@lexical/selection": "0.3.0",
20
- "@lexical/html": "0.3.0"
18
+ "@lexical/utils": "0.3.3",
19
+ "@lexical/selection": "0.3.3",
20
+ "@lexical/html": "0.3.3"
21
21
  },
22
22
  "repository": {
23
23
  "type": "git",