@lexical/clipboard 0.12.2 → 0.12.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.
@@ -18,6 +18,7 @@ var lexical = require('lexical');
18
18
  * LICENSE file in the root directory of this source tree.
19
19
  *
20
20
  */
21
+
21
22
  const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
22
23
 
23
24
  /**
@@ -27,8 +28,8 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
27
28
  * LICENSE file in the root directory of this source tree.
28
29
  *
29
30
  */
30
-
31
31
  const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
32
+
32
33
  /**
33
34
  * Returns the *currently selected* Lexical content as an HTML string, relying on the
34
35
  * logic defined in the exportDOM methods on the LexicalNode classes. Note that
@@ -38,24 +39,21 @@ const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).g
38
39
  * @param editor - LexicalEditor instance to get HTML content from
39
40
  * @returns a string of HTML content
40
41
  */
41
-
42
-
43
42
  function $getHtmlContent(editor) {
44
43
  const selection = lexical.$getSelection();
45
-
46
44
  if (selection == null) {
47
45
  {
48
46
  throw Error(`Expected valid LexicalSelection`);
49
47
  }
50
- } // If we haven't selected anything
51
-
48
+ }
52
49
 
50
+ // If we haven't selected anything
53
51
  if (lexical.$isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {
54
52
  return '';
55
53
  }
56
-
57
54
  return html.$generateHtmlFromNodes(editor, selection);
58
55
  }
56
+
59
57
  /**
60
58
  * Returns the *currently selected* Lexical content as a JSON string, relying on the
61
59
  * logic defined in the exportJSON methods on the LexicalNode classes. Note that
@@ -65,23 +63,21 @@ function $getHtmlContent(editor) {
65
63
  * @param editor - LexicalEditor instance to get the JSON content from
66
64
  * @returns
67
65
  */
68
-
69
66
  function $getLexicalContent(editor) {
70
67
  const selection = lexical.$getSelection();
71
-
72
68
  if (selection == null) {
73
69
  {
74
70
  throw Error(`Expected valid LexicalSelection`);
75
71
  }
76
- } // If we haven't selected anything
77
-
72
+ }
78
73
 
74
+ // If we haven't selected anything
79
75
  if (lexical.$isRangeSelection(selection) && selection.isCollapsed() || selection.getNodes().length === 0) {
80
76
  return null;
81
77
  }
82
-
83
78
  return JSON.stringify($generateJSONFromSelectedNodes(editor, selection));
84
79
  }
80
+
85
81
  /**
86
82
  * Attempts to insert content of the mime-types text/plain or text/uri-list from
87
83
  * the provided DataTransfer object into the editor at the provided selection.
@@ -90,14 +86,13 @@ function $getLexicalContent(editor) {
90
86
  * @param dataTransfer an object conforming to the [DataTransfer interface] (https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface)
91
87
  * @param selection the selection to use as the insertion point for the content in the DataTransfer object
92
88
  */
93
-
94
89
  function $insertDataTransferForPlainText(dataTransfer, selection) {
95
90
  const text = dataTransfer.getData('text/plain') || dataTransfer.getData('text/uri-list');
96
-
97
91
  if (text != null) {
98
92
  selection.insertRawText(text);
99
93
  }
100
94
  }
95
+
101
96
  /**
102
97
  * Attempts to insert content of the mime-types application/x-lexical-editor, text/html,
103
98
  * text/plain, or text/uri-list (in descending order of priority) from the provided DataTransfer
@@ -107,47 +102,43 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
107
102
  * @param selection the selection to use as the insertion point for the content in the DataTransfer object
108
103
  * @param editor the LexicalEditor the content is being inserted into.
109
104
  */
110
-
111
105
  function $insertDataTransferForRichText(dataTransfer, selection, editor) {
112
106
  const lexicalString = dataTransfer.getData('application/x-lexical-editor');
113
-
114
107
  if (lexicalString) {
115
108
  try {
116
109
  const payload = JSON.parse(lexicalString);
117
-
118
110
  if (payload.namespace === editor._config.namespace && Array.isArray(payload.nodes)) {
119
111
  const nodes = $generateNodesFromSerializedNodes(payload.nodes);
120
112
  return $insertGeneratedNodes(editor, nodes, selection);
121
113
  }
122
- } catch {// Fail silently.
114
+ } catch (_unused) {
115
+ // Fail silently.
123
116
  }
124
117
  }
125
-
126
118
  const htmlString = dataTransfer.getData('text/html');
127
-
128
119
  if (htmlString) {
129
120
  try {
130
121
  const parser = new DOMParser();
131
122
  const dom = parser.parseFromString(htmlString, 'text/html');
132
123
  const nodes = html.$generateNodesFromDOM(editor, dom);
133
124
  return $insertGeneratedNodes(editor, nodes, selection);
134
- } catch {// Fail silently.
125
+ } catch (_unused2) {
126
+ // Fail silently.
135
127
  }
136
- } // Multi-line plain text in rich text mode pasted as separate paragraphs
128
+ }
129
+
130
+ // Multi-line plain text in rich text mode pasted as separate paragraphs
137
131
  // instead of single paragraph with linebreaks.
138
132
  // Webkit-specific: Supports read 'text/uri-list' in clipboard.
139
-
140
-
141
133
  const text = dataTransfer.getData('text/plain') || dataTransfer.getData('text/uri-list');
142
-
143
134
  if (text != null) {
144
135
  if (lexical.$isRangeSelection(selection)) {
145
136
  const parts = text.split(/(\r?\n|\t)/);
146
- const partsLength = parts.length;
147
-
148
- for (let i = 0; i < partsLength; i++) {
137
+ if (parts[parts.length - 1] === '') {
138
+ parts.pop();
139
+ }
140
+ for (let i = 0; i < parts.length; i++) {
149
141
  const part = parts[i];
150
-
151
142
  if (part === '\n' || part === '\r\n') {
152
143
  selection.insertParagraph();
153
144
  } else if (part === '\t') {
@@ -161,6 +152,7 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
161
152
  }
162
153
  }
163
154
  }
155
+
164
156
  /**
165
157
  * Inserts Lexical nodes into the editor using different strategies depending on
166
158
  * some simple selection-based heuristics. If you're looking for a generic way to
@@ -171,39 +163,32 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
171
163
  * @param nodes The nodes to insert.
172
164
  * @param selection The selection to insert the nodes into.
173
165
  */
174
-
175
166
  function $insertGeneratedNodes(editor, nodes, selection) {
176
167
  const isSelectionInsideOfGrid = lexical.DEPRECATED_$isGridSelection(selection) || utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null;
177
-
178
168
  if (isSelectionInsideOfGrid && nodes.length === 1 && lexical.DEPRECATED_$isGridNode(nodes[0])) {
179
169
  $mergeGridNodesStrategy(nodes, selection, false, editor);
180
170
  return;
181
171
  }
182
-
183
172
  $basicInsertStrategy(nodes, selection);
184
173
  return;
185
174
  }
186
-
187
175
  function $basicInsertStrategy(nodes, selection) {
188
176
  // Wrap text and inline nodes in paragraph nodes so we have all blocks at the top-level
189
177
  const topLevelBlocks = [];
190
178
  let currentBlock = null;
191
-
192
179
  for (let i = 0; i < nodes.length; i++) {
193
180
  const node = nodes[i];
194
181
  const isLineBreakNode = lexical.$isLineBreakNode(node);
195
-
196
182
  if (isLineBreakNode || lexical.$isDecoratorNode(node) && node.isInline() || lexical.$isElementNode(node) && node.isInline() || lexical.$isTextNode(node) || node.isParentRequired()) {
197
183
  if (currentBlock === null) {
198
184
  currentBlock = node.createParentElementNode();
199
- topLevelBlocks.push(currentBlock); // In the case of LineBreakNode, we just need to
185
+ topLevelBlocks.push(currentBlock);
186
+ // In the case of LineBreakNode, we just need to
200
187
  // add an empty ParagraphNode to the topLevelBlocks.
201
-
202
188
  if (isLineBreakNode) {
203
189
  continue;
204
190
  }
205
191
  }
206
-
207
192
  if (currentBlock !== null) {
208
193
  currentBlock.append(node);
209
194
  }
@@ -212,30 +197,25 @@ function $basicInsertStrategy(nodes, selection) {
212
197
  currentBlock = null;
213
198
  }
214
199
  }
215
-
216
200
  if (lexical.$isRangeSelection(selection)) {
217
201
  selection.insertNodes(topLevelBlocks);
218
202
  } else if (lexical.DEPRECATED_$isGridSelection(selection)) {
219
203
  // If there's an active grid selection and a non grid is pasted, add to the anchor.
220
204
  const anchorCell = selection.anchor.getNode();
221
-
222
205
  if (!lexical.DEPRECATED_$isGridCellNode(anchorCell)) {
223
206
  {
224
207
  throw Error(`Expected Grid Cell in Grid Selection`);
225
208
  }
226
209
  }
227
-
228
210
  anchorCell.append(...topLevelBlocks);
229
211
  }
230
212
  }
231
-
232
213
  function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
233
214
  if (nodes.length !== 1 || !lexical.DEPRECATED_$isGridNode(nodes[0])) {
234
215
  {
235
216
  throw Error(`$mergeGridNodesStrategy: Expected Grid insertion.`);
236
217
  }
237
218
  }
238
-
239
219
  const newGrid = nodes[0];
240
220
  const newGridRows = newGrid.getChildren();
241
221
  const newColumnCount = newGrid.getFirstChildOrThrow().getChildrenSize();
@@ -243,13 +223,11 @@ function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
243
223
  const gridCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n));
244
224
  const gridRowNode = gridCellNode && utils.$findMatchingParent(gridCellNode, n => lexical.DEPRECATED_$isGridRowNode(n));
245
225
  const gridNode = gridRowNode && utils.$findMatchingParent(gridRowNode, n => lexical.DEPRECATED_$isGridNode(n));
246
-
247
226
  if (!lexical.DEPRECATED_$isGridCellNode(gridCellNode) || !lexical.DEPRECATED_$isGridRowNode(gridRowNode) || !lexical.DEPRECATED_$isGridNode(gridNode)) {
248
227
  {
249
228
  throw Error(`$mergeGridNodesStrategy: Expected selection to be inside of a Grid.`);
250
229
  }
251
230
  }
252
-
253
231
  const startY = gridRowNode.getIndexWithinParent();
254
232
  const stopY = Math.min(gridNode.getChildrenSize() - 1, startY + newRowCount - 1);
255
233
  const startX = gridCellNode.getIndexWithinParent();
@@ -262,51 +240,40 @@ function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
262
240
  let newRowIdx = 0;
263
241
  let newAnchorCellKey;
264
242
  let newFocusCellKey;
265
-
266
243
  for (let r = fromY; r <= toY; r++) {
267
244
  const currentGridRowNode = gridRowNodes[r];
268
-
269
245
  if (!lexical.DEPRECATED_$isGridRowNode(currentGridRowNode)) {
270
246
  {
271
247
  throw Error(`getNodes: expected to find GridRowNode`);
272
248
  }
273
249
  }
274
-
275
250
  const newGridRowNode = newGridRows[newRowIdx];
276
-
277
251
  if (!lexical.DEPRECATED_$isGridRowNode(newGridRowNode)) {
278
252
  {
279
253
  throw Error(`getNodes: expected to find GridRowNode`);
280
254
  }
281
255
  }
282
-
283
256
  const gridCellNodes = currentGridRowNode.getChildren();
284
257
  const newGridCellNodes = newGridRowNode.getChildren();
285
258
  let newColumnIdx = 0;
286
-
287
259
  for (let c = fromX; c <= toX; c++) {
288
260
  const currentGridCellNode = gridCellNodes[c];
289
-
290
261
  if (!lexical.DEPRECATED_$isGridCellNode(currentGridCellNode)) {
291
262
  {
292
263
  throw Error(`getNodes: expected to find GridCellNode`);
293
264
  }
294
265
  }
295
-
296
266
  const newGridCellNode = newGridCellNodes[newColumnIdx];
297
-
298
267
  if (!lexical.DEPRECATED_$isGridCellNode(newGridCellNode)) {
299
268
  {
300
269
  throw Error(`getNodes: expected to find GridCellNode`);
301
270
  }
302
271
  }
303
-
304
272
  if (r === fromY && c === fromX) {
305
273
  newAnchorCellKey = currentGridCellNode.getKey();
306
274
  } else if (r === toY && c === toX) {
307
275
  newFocusCellKey = currentGridCellNode.getKey();
308
276
  }
309
-
310
277
  const originalChildren = currentGridCellNode.getChildren();
311
278
  newGridCellNode.getChildren().forEach(child => {
312
279
  if (lexical.$isTextNode(child)) {
@@ -320,10 +287,8 @@ function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
320
287
  originalChildren.forEach(n => n.remove());
321
288
  newColumnIdx++;
322
289
  }
323
-
324
290
  newRowIdx++;
325
291
  }
326
-
327
292
  if (newAnchorCellKey && newFocusCellKey) {
328
293
  const newGridSelection = lexical.DEPRECATED_$createGridSelection();
329
294
  newGridSelection.set(gridNode.getKey(), newAnchorCellKey, newFocusCellKey);
@@ -331,20 +296,19 @@ function $mergeGridNodesStrategy(nodes, selection, isFromLexical, editor) {
331
296
  editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
332
297
  }
333
298
  }
334
-
335
299
  function exportNodeToJSON(node) {
336
300
  const serializedNode = node.exportJSON();
337
- const nodeClass = node.constructor; // @ts-expect-error TODO Replace Class utility type with InstanceType
301
+ const nodeClass = node.constructor;
338
302
 
303
+ // @ts-expect-error TODO Replace Class utility type with InstanceType
339
304
  if (serializedNode.type !== nodeClass.getType()) {
340
305
  {
341
306
  throw Error(`LexicalNode: Node ${nodeClass.name} does not implement .exportJSON().`);
342
307
  }
343
- } // @ts-expect-error TODO Replace Class utility type with InstanceType
344
-
308
+ }
345
309
 
310
+ // @ts-expect-error TODO Replace Class utility type with InstanceType
346
311
  const serializedChildren = serializedNode.children;
347
-
348
312
  if (lexical.$isElementNode(node)) {
349
313
  if (!Array.isArray(serializedChildren)) {
350
314
  {
@@ -352,50 +316,44 @@ function exportNodeToJSON(node) {
352
316
  }
353
317
  }
354
318
  }
355
-
356
319
  return serializedNode;
357
320
  }
358
-
359
321
  function $appendNodesToJSON(editor, selection$1, currentNode, targetArray = []) {
360
322
  let shouldInclude = selection$1 != null ? currentNode.isSelected(selection$1) : true;
361
323
  const shouldExclude = lexical.$isElementNode(currentNode) && currentNode.excludeFromCopy('html');
362
324
  let target = currentNode;
363
-
364
325
  if (selection$1 !== null) {
365
326
  let clone = selection.$cloneWithProperties(currentNode);
366
327
  clone = lexical.$isTextNode(clone) && selection$1 != null ? selection.$sliceSelectedTextNodeContent(selection$1, clone) : clone;
367
328
  target = clone;
368
329
  }
369
-
370
330
  const children = lexical.$isElementNode(target) ? target.getChildren() : [];
371
- const serializedNode = exportNodeToJSON(target); // TODO: TextNode calls getTextContent() (NOT node.__text) within it's exportJSON method
331
+ const serializedNode = exportNodeToJSON(target);
332
+
333
+ // TODO: TextNode calls getTextContent() (NOT node.__text) within it's exportJSON method
372
334
  // which uses getLatest() to get the text from the original node with the same key.
373
335
  // This is a deeper issue with the word "clone" here, it's still a reference to the
374
336
  // same node as far as the LexicalEditor is concerned since it shares a key.
375
337
  // We need a way to create a clone of a Node in memory with it's own key, but
376
338
  // until then this hack will work for the selected text extract use case.
377
-
378
339
  if (lexical.$isTextNode(target)) {
379
- const text = target.__text; // If an uncollapsed selection ends or starts at the end of a line of specialized,
340
+ const text = target.__text;
341
+ // If an uncollapsed selection ends or starts at the end of a line of specialized,
380
342
  // TextNodes, such as code tokens, we will get a 'blank' TextNode here, i.e., one
381
343
  // with text of length 0. We don't want this, it makes a confusing mess. Reset!
382
-
383
344
  if (text.length > 0) {
384
345
  serializedNode.text = text;
385
346
  } else {
386
347
  shouldInclude = false;
387
348
  }
388
349
  }
389
-
390
350
  for (let i = 0; i < children.length; i++) {
391
351
  const childNode = children[i];
392
352
  const shouldIncludeChild = $appendNodesToJSON(editor, selection$1, childNode, serializedNode.children);
393
-
394
353
  if (!shouldInclude && lexical.$isElementNode(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection$1, 'clone')) {
395
354
  shouldInclude = true;
396
355
  }
397
356
  }
398
-
399
357
  if (shouldInclude && !shouldExclude) {
400
358
  targetArray.push(serializedNode);
401
359
  } else if (Array.isArray(serializedNode.children)) {
@@ -404,10 +362,10 @@ function $appendNodesToJSON(editor, selection$1, currentNode, targetArray = [])
404
362
  targetArray.push(serializedChildNode);
405
363
  }
406
364
  }
407
-
408
365
  return shouldInclude;
409
- } // TODO why $ function with Editor instance?
366
+ }
410
367
 
368
+ // TODO why $ function with Editor instance?
411
369
  /**
412
370
  * Gets the Lexical JSON of the nodes inside the provided Selection.
413
371
  *
@@ -415,23 +373,20 @@ function $appendNodesToJSON(editor, selection$1, currentNode, targetArray = [])
415
373
  * @param selection Selection to get the JSON content from.
416
374
  * @returns an object with the editor namespace and a list of serializable nodes as JavaScript objects.
417
375
  */
418
-
419
-
420
376
  function $generateJSONFromSelectedNodes(editor, selection) {
421
377
  const nodes = [];
422
378
  const root = lexical.$getRoot();
423
379
  const topLevelChildren = root.getChildren();
424
-
425
380
  for (let i = 0; i < topLevelChildren.length; i++) {
426
381
  const topLevelNode = topLevelChildren[i];
427
382
  $appendNodesToJSON(editor, selection, topLevelNode, nodes);
428
383
  }
429
-
430
384
  return {
431
385
  namespace: editor._config.namespace,
432
386
  nodes
433
387
  };
434
388
  }
389
+
435
390
  /**
436
391
  * This method takes an array of objects conforming to the BaseSeralizedNode interface and returns
437
392
  * an Array containing instances of the corresponding LexicalNode classes registered on the editor.
@@ -440,27 +395,23 @@ function $generateJSONFromSelectedNodes(editor, selection) {
440
395
  * @param serializedNodes an Array of objects conforming to the BaseSerializedNode interface.
441
396
  * @returns an Array of Lexical Node objects.
442
397
  */
443
-
444
398
  function $generateNodesFromSerializedNodes(serializedNodes) {
445
399
  const nodes = [];
446
-
447
400
  for (let i = 0; i < serializedNodes.length; i++) {
448
401
  const serializedNode = serializedNodes[i];
449
402
  const node = lexical.$parseSerializedNode(serializedNode);
450
-
451
403
  if (lexical.$isTextNode(node)) {
452
404
  selection.$addNodeStyle(node);
453
405
  }
454
-
455
406
  nodes.push(node);
456
407
  }
457
-
458
408
  return nodes;
459
409
  }
460
410
  const EVENT_LATENCY = 50;
461
- let clipboardEventTimeout = null; // TODO custom selection
462
- // TODO potentially have a node customizable version for plain text
411
+ let clipboardEventTimeout = null;
463
412
 
413
+ // TODO custom selection
414
+ // TODO potentially have a node customizable version for plain text
464
415
  /**
465
416
  * Copies the content of the current selection to the clipboard in
466
417
  * text/plain, text/html, and application/x-lexical-editor (Lexical JSON)
@@ -470,14 +421,12 @@ let clipboardEventTimeout = null; // TODO custom selection
470
421
  * @param event the native browser ClipboardEvent to add the content to.
471
422
  * @returns
472
423
  */
473
-
474
424
  async function copyToClipboard(editor, event) {
475
425
  if (clipboardEventTimeout !== null) {
476
426
  // Prevent weird race conditions that can happen when this function is run multiple times
477
427
  // synchronously. In the future, we can do better, we can cancel/override the previously running job.
478
428
  return false;
479
429
  }
480
-
481
430
  if (event !== null) {
482
431
  return new Promise((resolve, reject) => {
483
432
  editor.update(() => {
@@ -485,15 +434,12 @@ async function copyToClipboard(editor, event) {
485
434
  });
486
435
  });
487
436
  }
488
-
489
437
  const rootElement = editor.getRootElement();
490
438
  const windowDocument = editor._window == null ? window.document : editor._window.document;
491
439
  const domSelection = getDOMSelection(editor._window);
492
-
493
440
  if (rootElement === null || domSelection === null) {
494
441
  return false;
495
442
  }
496
-
497
443
  const element = windowDocument.createElement('span');
498
444
  element.style.cssText = 'position: fixed; top: -1000px;';
499
445
  element.append(windowDocument.createTextNode('#'));
@@ -507,20 +453,17 @@ async function copyToClipboard(editor, event) {
507
453
  const removeListener = editor.registerCommand(lexical.COPY_COMMAND, secondEvent => {
508
454
  if (utils.objectKlassEquals(secondEvent, ClipboardEvent)) {
509
455
  removeListener();
510
-
511
456
  if (clipboardEventTimeout !== null) {
512
457
  window.clearTimeout(clipboardEventTimeout);
513
458
  clipboardEventTimeout = null;
514
459
  }
515
-
516
460
  resolve($copyToClipboardEvent(editor, secondEvent));
517
- } // Block the entire copy flow while we wait for the next ClipboardEvent
518
-
519
-
461
+ }
462
+ // Block the entire copy flow while we wait for the next ClipboardEvent
520
463
  return true;
521
- }, lexical.COMMAND_PRIORITY_CRITICAL); // If the above hack execCommand hack works, this timeout code should never fire. Otherwise,
464
+ }, lexical.COMMAND_PRIORITY_CRITICAL);
465
+ // If the above hack execCommand hack works, this timeout code should never fire. Otherwise,
522
466
  // the listener will be quickly freed so that the user can reuse it again
523
-
524
467
  clipboardEventTimeout = window.setTimeout(() => {
525
468
  removeListener();
526
469
  clipboardEventTimeout = null;
@@ -529,46 +472,37 @@ async function copyToClipboard(editor, event) {
529
472
  windowDocument.execCommand('copy');
530
473
  element.remove();
531
474
  });
532
- } // TODO shouldn't pass editor (pass namespace directly)
475
+ }
533
476
 
477
+ // TODO shouldn't pass editor (pass namespace directly)
534
478
  function $copyToClipboardEvent(editor, event) {
535
479
  const domSelection = getDOMSelection(editor._window);
536
-
537
480
  if (!domSelection) {
538
481
  return false;
539
482
  }
540
-
541
483
  const anchorDOM = domSelection.anchorNode;
542
484
  const focusDOM = domSelection.focusNode;
543
-
544
485
  if (anchorDOM !== null && focusDOM !== null && !lexical.isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
545
486
  return false;
546
487
  }
547
-
548
488
  event.preventDefault();
549
489
  const clipboardData = event.clipboardData;
550
490
  const selection = lexical.$getSelection();
551
-
552
491
  if (clipboardData === null || selection === null) {
553
492
  return false;
554
493
  }
555
-
556
494
  const htmlString = $getHtmlContent(editor);
557
495
  const lexicalString = $getLexicalContent(editor);
558
496
  let plainString = '';
559
-
560
497
  if (selection !== null) {
561
498
  plainString = selection.getTextContent();
562
499
  }
563
-
564
500
  if (htmlString !== null) {
565
501
  clipboardData.setData('text/html', htmlString);
566
502
  }
567
-
568
503
  if (lexicalString !== null) {
569
504
  clipboardData.setData('application/x-lexical-editor', lexicalString);
570
505
  }
571
-
572
506
  clipboardData.setData('text/plain', plainString);
573
507
  return true;
574
508
  }
@@ -6,16 +6,16 @@
6
6
  */
7
7
  'use strict';var d=require("@lexical/html"),p=require("@lexical/selection"),r=require("@lexical/utils"),u=require("lexical");function z(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}
8
8
  let A="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement;function B(a){let b=u.$getSelection();if(null==b)throw Error("Expected valid LexicalSelection");return u.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?"":d.$generateHtmlFromNodes(a,b)}
9
- function C(a){let b=u.$getSelection();if(null==b)throw Error("Expected valid LexicalSelection");return u.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(D(a,b))}function E(a,b,c){(u.DEPRECATED_$isGridSelection(c)||null!==r.$findMatchingParent(c.anchor.getNode(),e=>u.DEPRECATED_$isGridCellNode(e))&&null!==r.$findMatchingParent(c.focus.getNode(),e=>u.DEPRECATED_$isGridCellNode(e)))&&1===b.length&&u.DEPRECATED_$isGridNode(b[0])?F(b,c,!1,a):I(b,c)}
10
- function I(a,b){let c=[],e=null;for(let f=0;f<a.length;f++){let h=a[f],g=u.$isLineBreakNode(h);if(g||u.$isDecoratorNode(h)&&h.isInline()||u.$isElementNode(h)&&h.isInline()||u.$isTextNode(h)||h.isParentRequired()){if(null===e&&(e=h.createParentElementNode(),c.push(e),g))continue;null!==e&&e.append(h)}else c.push(h),e=null}u.$isRangeSelection(b)?b.insertNodes(c):u.DEPRECATED_$isGridSelection(b)&&(a=b.anchor.getNode(),u.DEPRECATED_$isGridCellNode(a)||z(41),a.append(...c))}
11
- function F(a,b,c,e){1===a.length&&u.DEPRECATED_$isGridNode(a[0])||z(42);var f=a[0];a=f.getChildren();c=f.getFirstChildOrThrow().getChildrenSize();var h=f.getChildrenSize(),g=r.$findMatchingParent(b.anchor.getNode(),l=>u.DEPRECATED_$isGridCellNode(l));b=(f=g&&r.$findMatchingParent(g,l=>u.DEPRECATED_$isGridRowNode(l)))&&r.$findMatchingParent(f,l=>u.DEPRECATED_$isGridNode(l));u.DEPRECATED_$isGridCellNode(g)&&u.DEPRECATED_$isGridRowNode(f)&&u.DEPRECATED_$isGridNode(b)||z(43);var k=f.getIndexWithinParent(),
12
- m=Math.min(b.getChildrenSize()-1,k+h-1);h=g.getIndexWithinParent();g=Math.min(f.getChildrenSize()-1,h+c-1);c=Math.min(h,g);f=Math.min(k,m);h=Math.max(h,g);k=Math.max(k,m);m=b.getChildren();g=0;let n,q;for(let l=f;l<=k;l++){var t=m[l];u.DEPRECATED_$isGridRowNode(t)||z(24);var y=a[g];u.DEPRECATED_$isGridRowNode(y)||z(24);t=t.getChildren();y=y.getChildren();let G=0;for(let v=c;v<=h;v++){let w=t[v];u.DEPRECATED_$isGridCellNode(w)||z(25);let H=y[G];u.DEPRECATED_$isGridCellNode(H)||z(25);l===f&&v===c?n=
13
- w.getKey():l===k&&v===h&&(q=w.getKey());let N=w.getChildren();H.getChildren().forEach(x=>{u.$isTextNode(x)&&u.$createParagraphNode().append(x);w.append(x)});N.forEach(x=>x.remove());G++}g++}n&&q&&(a=u.DEPRECATED_$createGridSelection(),a.set(b.getKey(),n,q),u.$setSelection(a),e.dispatchCommand(u.SELECTION_CHANGE_COMMAND,void 0))}
14
- function J(a,b,c,e=[]){let f=null!=b?c.isSelected(b):!0,h=u.$isElementNode(c)&&c.excludeFromCopy("html");var g=c;if(null!==b){var k=p.$cloneWithProperties(c);g=k=u.$isTextNode(k)&&null!=b?p.$sliceSelectedTextNodeContent(b,k):k}let m=u.$isElementNode(g)?g.getChildren():[];var n=g;k=n.exportJSON();var q=n.constructor;k.type!==q.getType()&&z(58,q.name);let t=k.children;u.$isElementNode(n)&&(Array.isArray(t)||z(59,q.name));u.$isTextNode(g)&&(g=g.__text,0<g.length?k.text=g:f=!1);for(g=0;g<m.length;g++)n=
15
- m[g],q=J(a,b,n,k.children),!f&&u.$isElementNode(c)&&q&&c.extractWithChild(n,b,"clone")&&(f=!0);if(f&&!h)e.push(k);else if(Array.isArray(k.children))for(a=0;a<k.children.length;a++)e.push(k.children[a]);return f}function D(a,b){let c=[],e=u.$getRoot().getChildren();for(let f=0;f<e.length;f++)J(a,b,e[f],c);return{namespace:a._config.namespace,nodes:c}}function K(a){let b=[];for(let c=0;c<a.length;c++){let e=u.$parseSerializedNode(a[c]);u.$isTextNode(e)&&p.$addNodeStyle(e);b.push(e)}return b}let L=null;
16
- function M(a,b){var c=A?(a._window||window).getSelection():null;if(!c)return!1;var e=c.anchorNode;c=c.focusNode;if(null!==e&&null!==c&&!u.isSelectionWithinEditor(a,e,c))return!1;b.preventDefault();b=b.clipboardData;e=u.$getSelection();if(null===b||null===e)return!1;c=B(a);a=C(a);let f="";null!==e&&(f=e.getTextContent());null!==c&&b.setData("text/html",c);null!==a&&b.setData("application/x-lexical-editor",a);b.setData("text/plain",f);return!0}exports.$generateJSONFromSelectedNodes=D;
9
+ function C(a){let b=u.$getSelection();if(null==b)throw Error("Expected valid LexicalSelection");return u.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(D(a,b))}function E(a,b,c){(u.DEPRECATED_$isGridSelection(c)||null!==r.$findMatchingParent(c.anchor.getNode(),f=>u.DEPRECATED_$isGridCellNode(f))&&null!==r.$findMatchingParent(c.focus.getNode(),f=>u.DEPRECATED_$isGridCellNode(f)))&&1===b.length&&u.DEPRECATED_$isGridNode(b[0])?F(b,c,!1,a):I(b,c)}
10
+ function I(a,b){let c=[],f=null;for(let e=0;e<a.length;e++){let g=a[e],h=u.$isLineBreakNode(g);if(h||u.$isDecoratorNode(g)&&g.isInline()||u.$isElementNode(g)&&g.isInline()||u.$isTextNode(g)||g.isParentRequired()){if(null===f&&(f=g.createParentElementNode(),c.push(f),h))continue;null!==f&&f.append(g)}else c.push(g),f=null}u.$isRangeSelection(b)?b.insertNodes(c):u.DEPRECATED_$isGridSelection(b)&&(a=b.anchor.getNode(),u.DEPRECATED_$isGridCellNode(a)||z(41),a.append(...c))}
11
+ function F(a,b,c,f){1===a.length&&u.DEPRECATED_$isGridNode(a[0])||z(42);var e=a[0];a=e.getChildren();c=e.getFirstChildOrThrow().getChildrenSize();var g=e.getChildrenSize(),h=r.$findMatchingParent(b.anchor.getNode(),l=>u.DEPRECATED_$isGridCellNode(l));b=(e=h&&r.$findMatchingParent(h,l=>u.DEPRECATED_$isGridRowNode(l)))&&r.$findMatchingParent(e,l=>u.DEPRECATED_$isGridNode(l));u.DEPRECATED_$isGridCellNode(h)&&u.DEPRECATED_$isGridRowNode(e)&&u.DEPRECATED_$isGridNode(b)||z(43);var k=e.getIndexWithinParent(),
12
+ m=Math.min(b.getChildrenSize()-1,k+g-1);g=h.getIndexWithinParent();h=Math.min(e.getChildrenSize()-1,g+c-1);c=Math.min(g,h);e=Math.min(k,m);g=Math.max(g,h);k=Math.max(k,m);m=b.getChildren();h=0;let n,q;for(let l=e;l<=k;l++){var t=m[l];u.DEPRECATED_$isGridRowNode(t)||z(24);var y=a[h];u.DEPRECATED_$isGridRowNode(y)||z(24);t=t.getChildren();y=y.getChildren();let G=0;for(let v=c;v<=g;v++){let w=t[v];u.DEPRECATED_$isGridCellNode(w)||z(25);let H=y[G];u.DEPRECATED_$isGridCellNode(H)||z(25);l===e&&v===c?n=
13
+ w.getKey():l===k&&v===g&&(q=w.getKey());let N=w.getChildren();H.getChildren().forEach(x=>{u.$isTextNode(x)&&u.$createParagraphNode().append(x);w.append(x)});N.forEach(x=>x.remove());G++}h++}n&&q&&(a=u.DEPRECATED_$createGridSelection(),a.set(b.getKey(),n,q),u.$setSelection(a),f.dispatchCommand(u.SELECTION_CHANGE_COMMAND,void 0))}
14
+ function J(a,b,c,f=[]){let e=null!=b?c.isSelected(b):!0,g=u.$isElementNode(c)&&c.excludeFromCopy("html");var h=c;if(null!==b){var k=p.$cloneWithProperties(c);h=k=u.$isTextNode(k)&&null!=b?p.$sliceSelectedTextNodeContent(b,k):k}let m=u.$isElementNode(h)?h.getChildren():[];var n=h;k=n.exportJSON();var q=n.constructor;k.type!==q.getType()&&z(58,q.name);let t=k.children;u.$isElementNode(n)&&(Array.isArray(t)||z(59,q.name));u.$isTextNode(h)&&(h=h.__text,0<h.length?k.text=h:e=!1);for(h=0;h<m.length;h++)n=
15
+ m[h],q=J(a,b,n,k.children),!e&&u.$isElementNode(c)&&q&&c.extractWithChild(n,b,"clone")&&(e=!0);if(e&&!g)f.push(k);else if(Array.isArray(k.children))for(a=0;a<k.children.length;a++)f.push(k.children[a]);return e}function D(a,b){let c=[],f=u.$getRoot().getChildren();for(let e=0;e<f.length;e++)J(a,b,f[e],c);return{namespace:a._config.namespace,nodes:c}}function K(a){let b=[];for(let c=0;c<a.length;c++){let f=u.$parseSerializedNode(a[c]);u.$isTextNode(f)&&p.$addNodeStyle(f);b.push(f)}return b}let L=null;
16
+ function M(a,b){var c=A?(a._window||window).getSelection():null;if(!c)return!1;var f=c.anchorNode;c=c.focusNode;if(null!==f&&null!==c&&!u.isSelectionWithinEditor(a,f,c))return!1;b.preventDefault();b=b.clipboardData;f=u.$getSelection();if(null===b||null===f)return!1;c=B(a);a=C(a);let e="";null!==f&&(e=f.getTextContent());null!==c&&b.setData("text/html",c);null!==a&&b.setData("application/x-lexical-editor",a);b.setData("text/plain",e);return!0}exports.$generateJSONFromSelectedNodes=D;
17
17
  exports.$generateNodesFromSerializedNodes=K;exports.$getHtmlContent=B;exports.$getLexicalContent=C;exports.$insertDataTransferForPlainText=function(a,b){a=a.getData("text/plain")||a.getData("text/uri-list");null!=a&&b.insertRawText(a)};
18
- exports.$insertDataTransferForRichText=function(a,b,c){var e=a.getData("application/x-lexical-editor");if(e)try{let g=JSON.parse(e);if(g.namespace===c._config.namespace&&Array.isArray(g.nodes)){let k=K(g.nodes);return E(c,k,b)}}catch{}if(e=a.getData("text/html"))try{var f=(new DOMParser).parseFromString(e,"text/html"),h=d.$generateNodesFromDOM(c,f);return E(c,h,b)}catch{}a=a.getData("text/plain")||a.getData("text/uri-list");if(null!=a)if(u.$isRangeSelection(b))for(a=a.split(/(\r?\n|\t)/),c=a.length,
19
- f=0;f<c;f++)h=a[f],"\n"===h||"\r\n"===h?b.insertParagraph():"\t"===h?b.insertNodes([u.$createTabNode()]):b.insertText(h);else b.insertRawText(a)};exports.$insertGeneratedNodes=E;
20
- exports.copyToClipboard=async function(a,b){if(null!==L)return!1;if(null!==b)return new Promise(g=>{a.update(()=>{g(M(a,b))})});var c=a.getRootElement();let e=null==a._window?window.document:a._window.document,f=A?(a._window||window).getSelection():null;if(null===c||null===f)return!1;let h=e.createElement("span");h.style.cssText="position: fixed; top: -1000px;";h.append(e.createTextNode("#"));c.append(h);c=new Range;c.setStart(h,0);c.setEnd(h,1);f.removeAllRanges();f.addRange(c);return new Promise(g=>
21
- {let k=a.registerCommand(u.COPY_COMMAND,m=>{r.objectKlassEquals(m,ClipboardEvent)&&(k(),null!==L&&(window.clearTimeout(L),L=null),g(M(a,m)));return!0},u.COMMAND_PRIORITY_CRITICAL);L=window.setTimeout(()=>{k();L=null;g(!1)},50);e.execCommand("copy");h.remove()})}
18
+ exports.$insertDataTransferForRichText=function(a,b,c){var f=a.getData("application/x-lexical-editor");if(f)try{let g=JSON.parse(f);if(g.namespace===c._config.namespace&&Array.isArray(g.nodes)){let h=K(g.nodes);return E(c,h,b)}}catch(g){}if(f=a.getData("text/html"))try{var e=(new DOMParser).parseFromString(f,"text/html");let g=d.$generateNodesFromDOM(c,e);return E(c,g,b)}catch(g){}a=a.getData("text/plain")||a.getData("text/uri-list");if(null!=a)if(u.$isRangeSelection(b))for(a=a.split(/(\r?\n|\t)/),
19
+ ""===a[a.length-1]&&a.pop(),c=0;c<a.length;c++)e=a[c],"\n"===e||"\r\n"===e?b.insertParagraph():"\t"===e?b.insertNodes([u.$createTabNode()]):b.insertText(e);else b.insertRawText(a)};exports.$insertGeneratedNodes=E;
20
+ exports.copyToClipboard=async function(a,b){if(null!==L)return!1;if(null!==b)return new Promise(h=>{a.update(()=>{h(M(a,b))})});var c=a.getRootElement();let f=null==a._window?window.document:a._window.document,e=A?(a._window||window).getSelection():null;if(null===c||null===e)return!1;let g=f.createElement("span");g.style.cssText="position: fixed; top: -1000px;";g.append(f.createTextNode("#"));c.append(g);c=new Range;c.setStart(g,0);c.setEnd(g,1);e.removeAllRanges();e.addRange(c);return new Promise(h=>
21
+ {let k=a.registerCommand(u.COPY_COMMAND,m=>{r.objectKlassEquals(m,ClipboardEvent)&&(k(),null!==L&&(window.clearTimeout(L),L=null),h(M(a,m)));return!0},u.COMMAND_PRIORITY_CRITICAL);L=window.setTimeout(()=>{k();L=null;h(!1)},50);f.execCommand("copy");g.remove()})}
package/package.json CHANGED
@@ -9,16 +9,16 @@
9
9
  "paste"
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "0.12.2",
12
+ "version": "0.12.3",
13
13
  "main": "LexicalClipboard.js",
14
14
  "peerDependencies": {
15
- "lexical": "0.12.2"
15
+ "lexical": "0.12.3"
16
16
  },
17
17
  "dependencies": {
18
- "@lexical/utils": "0.12.2",
19
- "@lexical/list": "0.12.2",
20
- "@lexical/selection": "0.12.2",
21
- "@lexical/html": "0.12.2"
18
+ "@lexical/utils": "0.12.3",
19
+ "@lexical/list": "0.12.3",
20
+ "@lexical/selection": "0.12.3",
21
+ "@lexical/html": "0.12.3"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",