lexical 0.3.1 → 0.3.4

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.
package/Lexical.dev.js CHANGED
@@ -6,6 +6,58 @@
6
6
  */
7
7
  'use strict';
8
8
 
9
+ /**
10
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
11
+ *
12
+ * This source code is licensed under the MIT license found in the
13
+ * LICENSE file in the root directory of this source tree.
14
+ *
15
+ */
16
+ function createCommand() {
17
+ return {};
18
+ }
19
+ const SELECTION_CHANGE_COMMAND = createCommand();
20
+ const CLICK_COMMAND = createCommand();
21
+ const DELETE_CHARACTER_COMMAND = createCommand();
22
+ const INSERT_LINE_BREAK_COMMAND = createCommand();
23
+ const INSERT_PARAGRAPH_COMMAND = createCommand();
24
+ const CONTROLLED_TEXT_INSERTION_COMMAND = createCommand();
25
+ const PASTE_COMMAND = createCommand();
26
+ const REMOVE_TEXT_COMMAND = createCommand();
27
+ const DELETE_WORD_COMMAND = createCommand();
28
+ const DELETE_LINE_COMMAND = createCommand();
29
+ const FORMAT_TEXT_COMMAND = createCommand();
30
+ const UNDO_COMMAND = createCommand();
31
+ const REDO_COMMAND = createCommand();
32
+ const KEY_ARROW_RIGHT_COMMAND = createCommand();
33
+ const MOVE_TO_END = createCommand();
34
+ const KEY_ARROW_LEFT_COMMAND = createCommand();
35
+ const MOVE_TO_START = createCommand();
36
+ const KEY_ARROW_UP_COMMAND = createCommand();
37
+ const KEY_ARROW_DOWN_COMMAND = createCommand();
38
+ const KEY_ENTER_COMMAND = createCommand();
39
+ const KEY_SPACE_COMMAND = createCommand();
40
+ const KEY_BACKSPACE_COMMAND = createCommand();
41
+ const KEY_ESCAPE_COMMAND = createCommand();
42
+ const KEY_DELETE_COMMAND = createCommand();
43
+ const KEY_TAB_COMMAND = createCommand();
44
+ const INDENT_CONTENT_COMMAND = createCommand();
45
+ const OUTDENT_CONTENT_COMMAND = createCommand();
46
+ const DROP_COMMAND = createCommand();
47
+ const FORMAT_ELEMENT_COMMAND = createCommand();
48
+ const DRAGSTART_COMMAND = createCommand();
49
+ const DRAGOVER_COMMAND = createCommand();
50
+ const DRAGEND_COMMAND = createCommand();
51
+ const COPY_COMMAND = createCommand();
52
+ const CUT_COMMAND = createCommand();
53
+ const CLEAR_EDITOR_COMMAND = createCommand();
54
+ const CLEAR_HISTORY_COMMAND = createCommand();
55
+ const CAN_REDO_COMMAND = createCommand();
56
+ const CAN_UNDO_COMMAND = createCommand();
57
+ const FOCUS_COMMAND = createCommand();
58
+ const BLUR_COMMAND = createCommand();
59
+ const KEY_MODIFIER_COMMAND = createCommand();
60
+
9
61
  /**
10
62
  * Copyright (c) Meta Platforms, Inc. and affiliates.
11
63
  *
@@ -173,12 +225,25 @@ function handleTextMutation(target, node, editor) {
173
225
  $updateTextNodeFromDOMContent(node, text, anchorOffset, focusOffset, false);
174
226
  }
175
227
 
228
+ function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) {
229
+ if ($isRangeSelection(selection)) {
230
+ const anchorNode = selection.anchor.getNode();
231
+
232
+ if (anchorNode.is(targetNode) && selection.format !== anchorNode.getFormat()) {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();
238
+ }
239
+
176
240
  function $flushMutations$1(editor, mutations, observer) {
177
241
  isProcessingMutations = true;
178
242
  const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp > TEXT_MUTATION_VARIANCE;
179
243
 
180
244
  try {
181
245
  updateEditor(editor, () => {
246
+ const selection = $getSelection() || getLastSelection(editor);
182
247
  const badDOMTargets = new Map();
183
248
  const rootElement = editor.getRootElement(); // We use the current edtior state, as that reflects what is
184
249
  // actually "on screen".
@@ -200,7 +265,7 @@ function $flushMutations$1(editor, mutations, observer) {
200
265
  if (type === 'characterData') {
201
266
  // Text mutations are deferred and passed to mutation listeners to be
202
267
  // processed outside of the Lexical engine.
203
- if (shouldFlushTextMutations && targetDOM.nodeType === DOM_TEXT_TYPE && $isTextNode(targetNode) && targetNode.isAttached()) {
268
+ if (shouldFlushTextMutations && $isTextNode(targetNode) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)) {
204
269
  handleTextMutation( // nodeType === DOM_TEXT_TYPE is a Text DOM node
205
270
  targetDOM, targetNode);
206
271
  }
@@ -315,8 +380,6 @@ function $flushMutations$1(editor, mutations, observer) {
315
380
  observer.takeRecords();
316
381
  }
317
382
 
318
- const selection = $getSelection() || getLastSelection(editor);
319
-
320
383
  if (selection !== null) {
321
384
  if (shouldRevertSelection) {
322
385
  selection.dirty = true;
@@ -664,7 +727,6 @@ function $setSelection(selection) {
664
727
  const editorState = getActiveEditorState();
665
728
 
666
729
  if (selection !== null) {
667
- // @ts-ignore
668
730
  {
669
731
  if (Object.isFrozen(selection)) {
670
732
  {
@@ -1173,11 +1235,12 @@ function scrollIntoViewIfNeeded(editor, anchor, rootElement, tags) {
1173
1235
  } else if (rect.top < 0) {
1174
1236
  element.scrollIntoView();
1175
1237
  } else {
1176
- const rootRect = rootElement.getBoundingClientRect();
1238
+ const rootRect = rootElement.getBoundingClientRect(); // Rects can returning decimal numbers that differ due to rounding
1239
+ // differences. So let's normalize the values.
1177
1240
 
1178
- if (rect.bottom > rootRect.bottom) {
1241
+ if (Math.floor(rect.bottom) > Math.floor(rootRect.bottom)) {
1179
1242
  element.scrollIntoView(false);
1180
- } else if (rect.top < rootRect.top) {
1243
+ } else if (Math.floor(rect.top) < Math.floor(rootRect.top)) {
1181
1244
  element.scrollIntoView();
1182
1245
  }
1183
1246
  }
@@ -1473,7 +1536,7 @@ function createNode(key, parentDOM, insertDOM) {
1473
1536
  const text = node.getTextContent();
1474
1537
 
1475
1538
  if ($isDecoratorNode(node)) {
1476
- const decorator = node.decorate(activeEditor$1);
1539
+ const decorator = node.decorate(activeEditor$1, activeEditorConfig);
1477
1540
 
1478
1541
  if (decorator !== null) {
1479
1542
  reconcileDecorator(key, decorator);
@@ -1513,8 +1576,7 @@ function createNode(key, parentDOM, insertDOM) {
1513
1576
  parentDOM.appendChild(dom);
1514
1577
  }
1515
1578
  }
1516
- } // @ts-ignore
1517
-
1579
+ }
1518
1580
 
1519
1581
  {
1520
1582
  // Freeze the node in DEV to prevent accidental mutations
@@ -1789,7 +1851,7 @@ function reconcileNode(key, parentDOM) {
1789
1851
  const text = nextNode.getTextContent();
1790
1852
 
1791
1853
  if ($isDecoratorNode(nextNode)) {
1792
- const decorator = nextNode.decorate(activeEditor$1);
1854
+ const decorator = nextNode.decorate(activeEditor$1, activeEditorConfig);
1793
1855
 
1794
1856
  if (decorator !== null) {
1795
1857
  reconcileDecorator(key, decorator);
@@ -1810,8 +1872,7 @@ function reconcileNode(key, parentDOM) {
1810
1872
  // Cache the latest text content.
1811
1873
  nextNode = nextNode.getWritable();
1812
1874
  nextNode.__cachedText = editorTextContent;
1813
- } // @ts-ignore
1814
-
1875
+ }
1815
1876
 
1816
1877
  {
1817
1878
  // Freeze the node in DEV to prevent accidental mutations
@@ -1970,58 +2031,6 @@ function getPrevElementByKeyOrThrow(key) {
1970
2031
  return element;
1971
2032
  }
1972
2033
 
1973
- /**
1974
- * Copyright (c) Meta Platforms, Inc. and affiliates.
1975
- *
1976
- * This source code is licensed under the MIT license found in the
1977
- * LICENSE file in the root directory of this source tree.
1978
- *
1979
- */
1980
- function createCommand() {
1981
- return {};
1982
- }
1983
- const SELECTION_CHANGE_COMMAND = createCommand();
1984
- const CLICK_COMMAND = createCommand();
1985
- const DELETE_CHARACTER_COMMAND = createCommand();
1986
- const INSERT_LINE_BREAK_COMMAND = createCommand();
1987
- const INSERT_PARAGRAPH_COMMAND = createCommand();
1988
- const CONTROLLED_TEXT_INSERTION_COMMAND = createCommand();
1989
- const PASTE_COMMAND = createCommand();
1990
- const REMOVE_TEXT_COMMAND = createCommand();
1991
- const DELETE_WORD_COMMAND = createCommand();
1992
- const DELETE_LINE_COMMAND = createCommand();
1993
- const FORMAT_TEXT_COMMAND = createCommand();
1994
- const UNDO_COMMAND = createCommand();
1995
- const REDO_COMMAND = createCommand();
1996
- const KEY_ARROW_RIGHT_COMMAND = createCommand();
1997
- const MOVE_TO_END = createCommand();
1998
- const KEY_ARROW_LEFT_COMMAND = createCommand();
1999
- const MOVE_TO_START = createCommand();
2000
- const KEY_ARROW_UP_COMMAND = createCommand();
2001
- const KEY_ARROW_DOWN_COMMAND = createCommand();
2002
- const KEY_ENTER_COMMAND = createCommand();
2003
- const KEY_SPACE_COMMAND = createCommand();
2004
- const KEY_BACKSPACE_COMMAND = createCommand();
2005
- const KEY_ESCAPE_COMMAND = createCommand();
2006
- const KEY_DELETE_COMMAND = createCommand();
2007
- const KEY_TAB_COMMAND = createCommand();
2008
- const INDENT_CONTENT_COMMAND = createCommand();
2009
- const OUTDENT_CONTENT_COMMAND = createCommand();
2010
- const DROP_COMMAND = createCommand();
2011
- const FORMAT_ELEMENT_COMMAND = createCommand();
2012
- const DRAGSTART_COMMAND = createCommand();
2013
- const DRAGOVER_COMMAND = createCommand();
2014
- const DRAGEND_COMMAND = createCommand();
2015
- const COPY_COMMAND = createCommand();
2016
- const CUT_COMMAND = createCommand();
2017
- const CLEAR_EDITOR_COMMAND = createCommand();
2018
- const CLEAR_HISTORY_COMMAND = createCommand();
2019
- const CAN_REDO_COMMAND = createCommand();
2020
- const CAN_UNDO_COMMAND = createCommand();
2021
- const FOCUS_COMMAND = createCommand();
2022
- const BLUR_COMMAND = createCommand();
2023
- const KEY_MODIFIER_COMMAND = createCommand();
2024
-
2025
2034
  /**
2026
2035
  * Copyright (c) Meta Platforms, Inc. and affiliates.
2027
2036
  *
@@ -2038,6 +2047,7 @@ if (CAN_USE_BEFORE_INPUT) {
2038
2047
  }
2039
2048
 
2040
2049
  let lastKeyDownTimeStamp = 0;
2050
+ let lastKeyCode = 0;
2041
2051
  let rootElementsRegistered = 0;
2042
2052
  let isSelectionChangeFromDOMUpdate = false;
2043
2053
  let isInsertLineBreak = false;
@@ -2179,6 +2189,10 @@ function $canRemoveText(anchorNode, focusNode) {
2179
2189
  return anchorNode !== focusNode || $isElementNode(anchorNode) || $isElementNode(focusNode) || !$isTokenOrInert(anchorNode) || !$isTokenOrInert(focusNode);
2180
2190
  }
2181
2191
 
2192
+ function isPossiblyAndroidKeyPress(timeStamp) {
2193
+ return lastKeyCode === 229 && timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY;
2194
+ }
2195
+
2182
2196
  function onBeforeInput(event, editor) {
2183
2197
  const inputType = event.inputType; // We let the browser do its own thing for composition.
2184
2198
 
@@ -2195,7 +2209,9 @@ function onBeforeInput(event, editor) {
2195
2209
  // during composition and see if the previous text contains
2196
2210
  // part of the composed text to work out the actual text that
2197
2211
  // we need to insert.
2198
- const composedText = event.data;
2212
+ const composedText = event.data; // TODO: evaluate if this is Android only. It doesn't always seem
2213
+ // to have any real impact, so could probably be refactored or removed
2214
+ // for an alternative approach.
2199
2215
 
2200
2216
  if (composedText) {
2201
2217
  updateEditor(editor, () => {
@@ -2239,20 +2255,32 @@ function onBeforeInput(event, editor) {
2239
2255
  }
2240
2256
 
2241
2257
  $setSelection(prevSelection.clone());
2242
- } // Used for Android
2258
+ }
2243
2259
 
2260
+ if ($isRangeSelection(selection)) {
2261
+ // Used for handling backspace in Android.
2262
+ if (isPossiblyAndroidKeyPress(event.timeStamp) && selection.anchor.key === selection.focus.key) {
2263
+ $setCompositionKey(null);
2264
+ lastKeyDownTimeStamp = 0; // Fixes an Android bug where selection flickers when backspacing
2244
2265
 
2245
- $setCompositionKey(null);
2246
- event.preventDefault();
2247
- lastKeyDownTimeStamp = 0;
2248
- dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true); // Fixes an Android bug where selection flickers when backspacing
2266
+ setTimeout(() => {
2267
+ updateEditor(editor, () => {
2268
+ $setCompositionKey(null);
2269
+ });
2270
+ }, ANDROID_COMPOSITION_LATENCY);
2249
2271
 
2250
- setTimeout(() => {
2251
- updateEditor(editor, () => {
2252
- $setCompositionKey(null);
2253
- });
2254
- }, ANDROID_COMPOSITION_LATENCY);
2255
- return;
2272
+ if ($isRangeSelection(selection)) {
2273
+ const anchorNode = selection.anchor.getNode();
2274
+ anchorNode.markDirty();
2275
+ selection.format = anchorNode.getFormat();
2276
+ }
2277
+ } else {
2278
+ event.preventDefault();
2279
+ dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false);
2280
+ }
2281
+
2282
+ return;
2283
+ }
2256
2284
  }
2257
2285
 
2258
2286
  if (!$isRangeSelection(selection)) {
@@ -2438,9 +2466,8 @@ function onInput(event, editor) {
2438
2466
  updateEditor(editor, () => {
2439
2467
  const selection = $getSelection();
2440
2468
  const data = event.data;
2441
- const possibleTextReplacement = event.inputType === 'insertText' && data != null && data.length > 1 && !doesContainGrapheme(data);
2442
2469
 
2443
- if (data != null && $isRangeSelection(selection) && (possibleTextReplacement || $shouldPreventDefaultAndInsertText(selection, data))) {
2470
+ if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, data)) {
2444
2471
  // Given we're over-riding the default behavior, we will need
2445
2472
  // to ensure to disable composition before dispatching the
2446
2473
  // insertText command for when changing the sequence for FF.
@@ -2449,24 +2476,7 @@ function onInput(event, editor) {
2449
2476
  isFirefoxEndingComposition = false;
2450
2477
  }
2451
2478
 
2452
- dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);
2453
-
2454
- if (possibleTextReplacement) {
2455
- // If the DOM selection offset is higher than the existing
2456
- // offset, then restore the offset as it's likely correct
2457
- // in the case of text replacements.
2458
- const {
2459
- anchorOffset
2460
- } = window.getSelection();
2461
- const anchor = selection.anchor;
2462
- const focus = selection.focus;
2463
-
2464
- if (anchorOffset > anchor.offset) {
2465
- anchor.set(anchor.key, anchorOffset, anchor.type);
2466
- focus.set(anchor.key, anchorOffset, anchor.type);
2467
- }
2468
- } // This ensures consistency on Android.
2469
-
2479
+ dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); // This ensures consistency on Android.
2470
2480
 
2471
2481
  if (!IS_SAFARI && !IS_IOS && editor.isComposing()) {
2472
2482
  lastKeyDownTimeStamp = 0;
@@ -2565,6 +2575,7 @@ function onCompositionEnd(event, editor) {
2565
2575
 
2566
2576
  function onKeyDown(event, editor) {
2567
2577
  lastKeyDownTimeStamp = event.timeStamp;
2578
+ lastKeyCode = event.keyCode;
2568
2579
 
2569
2580
  if (editor.isComposing()) {
2570
2581
  return;
@@ -2647,12 +2658,18 @@ function onKeyDown(event, editor) {
2647
2658
  } else if (isRedo(keyCode, shiftKey, metaKey, ctrlKey)) {
2648
2659
  event.preventDefault();
2649
2660
  dispatchCommand(editor, REDO_COMMAND, undefined);
2650
- } else if (isCopy(keyCode, shiftKey, metaKey, ctrlKey)) {
2651
- event.preventDefault();
2652
- dispatchCommand(editor, COPY_COMMAND, event);
2653
- } else if (isCut(keyCode, shiftKey, metaKey, ctrlKey)) {
2654
- event.preventDefault();
2655
- dispatchCommand(editor, CUT_COMMAND, event);
2661
+ } else {
2662
+ const prevSelection = editor._editorState._selection;
2663
+
2664
+ if ($isNodeSelection(prevSelection)) {
2665
+ if (isCopy(keyCode, shiftKey, metaKey, ctrlKey)) {
2666
+ event.preventDefault();
2667
+ dispatchCommand(editor, COPY_COMMAND, event);
2668
+ } else if (isCut(keyCode, shiftKey, metaKey, ctrlKey)) {
2669
+ event.preventDefault();
2670
+ dispatchCommand(editor, CUT_COMMAND, event);
2671
+ }
2672
+ }
2656
2673
  }
2657
2674
 
2658
2675
  if (isModifier(ctrlKey, shiftKey, altKey, metaKey)) {
@@ -2824,7 +2841,6 @@ function markCollapsedSelectionFormat(format, offset, key, timeStamp) {
2824
2841
  * LICENSE file in the root directory of this source tree.
2825
2842
  *
2826
2843
  */
2827
-
2828
2844
  class Point {
2829
2845
  constructor(key, offset, type) {
2830
2846
  this._selection = null;
@@ -3461,6 +3477,7 @@ class RangeSelection {
3461
3477
 
3462
3478
  if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
3463
3479
  nextSibling = $createTextNode();
3480
+ nextSibling.setFormat(format);
3464
3481
 
3465
3482
  if (!firstNodeParent.canInsertTextAfter()) {
3466
3483
  firstNodeParent.insertAfter(nextSibling);
@@ -3481,6 +3498,7 @@ class RangeSelection {
3481
3498
 
3482
3499
  if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
3483
3500
  prevSibling = $createTextNode();
3501
+ prevSibling.setFormat(format);
3484
3502
 
3485
3503
  if (!firstNodeParent.canInsertTextBefore()) {
3486
3504
  firstNodeParent.insertBefore(prevSibling);
@@ -3498,6 +3516,7 @@ class RangeSelection {
3498
3516
  }
3499
3517
  } else if (firstNode.isSegmented() && startOffset !== firstNodeTextLength) {
3500
3518
  const textNode = $createTextNode(firstNode.getTextContent());
3519
+ textNode.setFormat(format);
3501
3520
  firstNode.replace(textNode);
3502
3521
  firstNode = textNode;
3503
3522
  } else if (!this.isCollapsed() && text !== '') {
@@ -3555,10 +3574,14 @@ class RangeSelection {
3555
3574
 
3556
3575
  if (firstNode.getTextContent() === '') {
3557
3576
  firstNode.remove();
3558
- } else if (firstNode.isComposing() && this.anchor.type === 'text') {
3559
- // When composing, we need to adjust the anchor offset so that
3560
- // we correctly replace that right range.
3561
- this.anchor.offset -= text.length;
3577
+ } else if (this.anchor.type === 'text') {
3578
+ if (firstNode.isComposing()) {
3579
+ // When composing, we need to adjust the anchor offset so that
3580
+ // we correctly replace that right range.
3581
+ this.anchor.offset -= text.length;
3582
+ } else {
3583
+ this.format = firstNodeFormat;
3584
+ }
3562
3585
  }
3563
3586
  } else {
3564
3587
  const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]); // We have to get the parent elements before the next section,
@@ -4757,15 +4780,15 @@ function internalMakeRangeSelection(anchorKey, anchorOffset, focusKey, focusOffs
4757
4780
  editorState._selection = selection;
4758
4781
  return selection;
4759
4782
  }
4760
- function $createEmptyRangeSelection() {
4783
+ function $createRangeSelection() {
4761
4784
  const anchor = $createPoint('root', 0, 'element');
4762
4785
  const focus = $createPoint('root', 0, 'element');
4763
4786
  return new RangeSelection(anchor, focus, 0);
4764
4787
  }
4765
- function $createEmptyObjectSelection() {
4788
+ function $createNodeSelection() {
4766
4789
  return new NodeSelection(new Set());
4767
4790
  }
4768
- function $createEmptyGridSelection() {
4791
+ function $createGridSelection() {
4769
4792
  const anchor = $createPoint('root', 0, 'element');
4770
4793
  const focus = $createPoint('root', 0, 'element');
4771
4794
  return new GridSelection('root', anchor, focus);
@@ -5359,7 +5382,7 @@ function parseEditorState(serializedEditorState, editor, updateFn) {
5359
5382
  } // Make the editorState immutable
5360
5383
 
5361
5384
 
5362
- editorState._readOnly = true; // @ts-ignore
5385
+ editorState._readOnly = true;
5363
5386
 
5364
5387
  {
5365
5388
  handleDEVOnlyPendingUpdateGuarantees(editorState);
@@ -5464,6 +5487,9 @@ function commitPendingUpdates(editor) {
5464
5487
  isAttemptingToRecoverFromReconcilerError = true;
5465
5488
  commitPendingUpdates(editor);
5466
5489
  isAttemptingToRecoverFromReconcilerError = false;
5490
+ } else {
5491
+ // To avoid a possible situation of infinite loops, lets throw
5492
+ throw error;
5467
5493
  }
5468
5494
 
5469
5495
  return;
@@ -5480,7 +5506,7 @@ function commitPendingUpdates(editor) {
5480
5506
  }
5481
5507
  }
5482
5508
 
5483
- pendingEditorState._readOnly = true; // @ts-ignore
5509
+ pendingEditorState._readOnly = true;
5484
5510
 
5485
5511
  {
5486
5512
  handleDEVOnlyPendingUpdateGuarantees(pendingEditorState);
@@ -5821,8 +5847,17 @@ function updateEditor(editor, updateFn, options) {
5821
5847
  beginUpdate(editor, updateFn, options);
5822
5848
  }
5823
5849
  }
5850
+ function internalGetActiveEditor() {
5851
+ return activeEditor;
5852
+ }
5824
5853
 
5825
- /* eslint-disable no-constant-condition */
5854
+ /**
5855
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
5856
+ *
5857
+ * This source code is licensed under the MIT license found in the
5858
+ * LICENSE file in the root directory of this source tree.
5859
+ *
5860
+ */
5826
5861
  function removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
5827
5862
  errorOnReadOnly();
5828
5863
  const key = nodeToRemove.__key;
@@ -5889,6 +5924,7 @@ function $getNodeByKeyOrThrow(key) {
5889
5924
  return node;
5890
5925
  }
5891
5926
  class LexicalNode {
5927
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5892
5928
  // Flow doesn't support abstract classes unfortunately, so we can't _force_
5893
5929
  // subclasses of Node to implement statics. All subclasses of Node should have
5894
5930
  // a static getType and clone method though. We define getType and clone here so we can call it
@@ -5910,7 +5946,7 @@ class LexicalNode {
5910
5946
  // @ts-expect-error
5911
5947
  this.__type = this.constructor.getType();
5912
5948
  this.__parent = null;
5913
- $setNodeKey(this, key); // @ts-ignore
5949
+ $setNodeKey(this, key);
5914
5950
 
5915
5951
  {
5916
5952
  if (this.__type !== 'root') {
@@ -6379,52 +6415,11 @@ class LexicalNode {
6379
6415
 
6380
6416
  exportDOM(editor) {
6381
6417
  const element = this.createDOM(editor._config, editor);
6382
- const serializedNode = this.exportJSON();
6383
- element.setAttribute('data-lexical-node-type', this.__type);
6384
- element.setAttribute('data-lexical-node-json', JSON.stringify(serializedNode));
6385
- element.setAttribute('data-lexical-editor-key', editor._key);
6386
6418
  return {
6387
6419
  element
6388
6420
  };
6389
6421
  }
6390
6422
 
6391
- static importDOM() {
6392
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6393
- const proto = this.prototype.constructor;
6394
- return {
6395
- // Catch-all key because we don't know the nodeName of the element returned by exportDOM.
6396
- '*': domNode => {
6397
- if (!(domNode instanceof HTMLElement)) return null;
6398
- const editorKey = domNode.getAttribute('data-lexical-editor-key');
6399
- const nodeType = domNode.getAttribute('data-lexical-node-type');
6400
- if (editorKey == null || nodeType == null) return null;
6401
- const editor = getActiveEditor();
6402
-
6403
- if (editorKey === editor.getKey() && nodeType === proto.getType()) {
6404
- try {
6405
- const json = domNode.getAttribute('data-lexical-node-json');
6406
-
6407
- if (json != null) {
6408
- const serializedNode = JSON.parse(json);
6409
- const node = proto.importJSON(serializedNode);
6410
- return {
6411
- conversion: () => ({
6412
- node
6413
- }),
6414
- // Max priority because of the 'data-lexical-node-type' attribute
6415
- // matching the one on node klass guarantees a match.
6416
- priority: 4
6417
- }; // eslint-disable-next-line no-empty
6418
- } // eslint-disable-next-line no-empty
6419
-
6420
- } catch {}
6421
- }
6422
-
6423
- return null;
6424
- }
6425
- };
6426
- }
6427
-
6428
6423
  exportJSON() {
6429
6424
  {
6430
6425
  throw Error(`exportJSON: base method not extended`);
@@ -6643,7 +6638,7 @@ class DecoratorNode extends LexicalNode {
6643
6638
  super(key);
6644
6639
  }
6645
6640
 
6646
- decorate(editor) {
6641
+ decorate(editor, config) {
6647
6642
  {
6648
6643
  throw Error(`decorate: base method not extended`);
6649
6644
  }
@@ -7112,7 +7107,7 @@ class ElementNode extends LexicalNode {
7112
7107
  return false;
7113
7108
  }
7114
7109
 
7115
- excludeFromCopy() {
7110
+ excludeFromCopy(destination) {
7116
7111
  return false;
7117
7112
  }
7118
7113
 
@@ -7555,7 +7550,9 @@ function setTextContent(nextText, dom, node) {
7555
7550
  dom.textContent = text;
7556
7551
  } else {
7557
7552
  const nodeValue = firstChild.nodeValue;
7558
- if (nodeValue !== text) if (isComposing) {
7553
+ if (nodeValue !== text) if (isComposing || IS_FIREFOX) {
7554
+ // We also use the diff composed text for general text in FF to avoid
7555
+ // the spellcheck red line from flickering.
7559
7556
  const [index, remove, insert] = diffComposedText(nodeValue, text);
7560
7557
 
7561
7558
  if (remove !== 0) {
@@ -8164,8 +8161,21 @@ function convertBringAttentionToElement(domNode) {
8164
8161
  }
8165
8162
 
8166
8163
  function convertTextDOMNode(domNode) {
8164
+ const {
8165
+ parentElement,
8166
+ textContent
8167
+ } = domNode;
8168
+ const textContentTrim = textContent.trim();
8169
+ const isPre = parentElement != null && parentElement.tagName.toLowerCase() === 'pre';
8170
+
8171
+ if (!isPre && textContentTrim.length === 0 && textContent.includes('\n')) {
8172
+ return {
8173
+ node: null
8174
+ };
8175
+ }
8176
+
8167
8177
  return {
8168
- node: $createTextNode(domNode.textContent)
8178
+ node: $createTextNode(textContent)
8169
8179
  };
8170
8180
  }
8171
8181
 
@@ -8378,10 +8388,11 @@ function initializeConversionCache(nodes) {
8378
8388
  const conversionCache = new Map();
8379
8389
  const handledConversions = new Set();
8380
8390
  nodes.forEach(node => {
8381
- // @ts-expect-error TODO Replace Class utility type with InstanceType
8382
- const importDOM = node.klass.importDOM.bind(node.klass); // debugger;
8391
+ const importDOM = // @ts-expect-error TODO Replace Class utility type with InstanceType
8392
+ node.klass.importDOM != null ? // @ts-expect-error TODO Replace Class utility type with InstanceType
8393
+ node.klass.importDOM.bind(node.klass) : null;
8383
8394
 
8384
- if (handledConversions.has(importDOM)) {
8395
+ if (importDOM == null || handledConversions.has(importDOM)) {
8385
8396
  return;
8386
8397
  }
8387
8398
 
@@ -8404,69 +8415,77 @@ function initializeConversionCache(nodes) {
8404
8415
  return conversionCache;
8405
8416
  }
8406
8417
 
8407
- function createEditor(editorConfig = {}) {
8408
- const config = editorConfig;
8418
+ function createEditor(editorConfig) {
8419
+ const config = editorConfig || {};
8420
+ const activeEditor = internalGetActiveEditor();
8409
8421
  const theme = config.theme || {};
8410
- const parentEditor = config.parentEditor || null;
8422
+ const parentEditor = editorConfig === undefined ? activeEditor : config.parentEditor || null;
8411
8423
  const disableEvents = config.disableEvents || false;
8412
8424
  const editorState = createEmptyEditorState();
8425
+ const namespace = config.namespace || (parentEditor !== null ? parentEditor._config.namespace : createUID());
8413
8426
  const initialEditorState = config.editorState;
8414
8427
  const nodes = [RootNode, TextNode, LineBreakNode, ParagraphNode, ...(config.nodes || [])];
8415
8428
  const onError = config.onError;
8416
8429
  const isReadOnly = config.readOnly || false;
8417
- const registeredNodes = new Map();
8430
+ let registeredNodes;
8418
8431
 
8419
- for (let i = 0; i < nodes.length; i++) {
8420
- const klass = nodes[i]; // Ensure custom nodes implement required methods.
8421
- // @ts-ignore
8432
+ if (editorConfig === undefined && activeEditor !== null) {
8433
+ registeredNodes = activeEditor._nodes;
8434
+ } else {
8435
+ registeredNodes = new Map();
8422
8436
 
8423
- {
8424
- const name = klass.name;
8425
-
8426
- if (name !== 'RootNode') {
8427
- const proto = klass.prototype;
8428
- ['getType', 'clone'].forEach(method => {
8429
- // eslint-disable-next-line no-prototype-builtins
8430
- if (!klass.hasOwnProperty(method)) {
8431
- console.warn(`${name} must implement static "${method}" method`);
8432
- }
8433
- });
8437
+ for (let i = 0; i < nodes.length; i++) {
8438
+ const klass = nodes[i]; // Ensure custom nodes implement required methods.
8434
8439
 
8435
- if ( // eslint-disable-next-line no-prototype-builtins
8436
- !klass.hasOwnProperty('importDOM') && // eslint-disable-next-line no-prototype-builtins
8437
- klass.hasOwnProperty('exportDOM') && process.env.NODE_ENV !== 'test') {
8438
- console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
8439
- }
8440
+ {
8441
+ const name = klass.name;
8442
+
8443
+ if (name !== 'RootNode') {
8444
+ const proto = klass.prototype;
8445
+ ['getType', 'clone'].forEach(method => {
8446
+ // eslint-disable-next-line no-prototype-builtins
8447
+ if (!klass.hasOwnProperty(method)) {
8448
+ console.warn(`${name} must implement static "${method}" method`);
8449
+ }
8450
+ });
8440
8451
 
8441
- if (proto instanceof DecoratorNode) {
8442
- // eslint-disable-next-line no-prototype-builtins
8443
- if (!proto.hasOwnProperty('decorate')) {
8444
- console.warn(`${this.constructor.name} must implement "decorate" method`);
8452
+ if ( // eslint-disable-next-line no-prototype-builtins
8453
+ !klass.hasOwnProperty('importDOM') && // eslint-disable-next-line no-prototype-builtins
8454
+ klass.hasOwnProperty('exportDOM')) {
8455
+ console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`);
8445
8456
  }
8446
- }
8447
8457
 
8448
- if ( // eslint-disable-next-line no-prototype-builtins
8449
- !klass.hasOwnProperty('importJSON') && process.env.NODE_ENV !== 'test') {
8450
- console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
8451
- }
8458
+ if (proto instanceof DecoratorNode) {
8459
+ // eslint-disable-next-line no-prototype-builtins
8460
+ if (!proto.hasOwnProperty('decorate')) {
8461
+ console.warn(`${this.constructor.name} must implement "decorate" method`);
8462
+ }
8463
+ }
8452
8464
 
8453
- if ( // eslint-disable-next-line no-prototype-builtins
8454
- !proto.hasOwnProperty('exportJSON') && process.env.NODE_ENV !== 'test') {
8455
- console.warn(`${name} should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected`);
8465
+ if ( // eslint-disable-next-line no-prototype-builtins
8466
+ !klass.hasOwnProperty('importJSON')) {
8467
+ console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`);
8468
+ }
8469
+
8470
+ if ( // eslint-disable-next-line no-prototype-builtins
8471
+ !proto.hasOwnProperty('exportJSON')) {
8472
+ console.warn(`${name} should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected`);
8473
+ }
8456
8474
  }
8457
- }
8458
- } // @ts-expect-error TODO Replace Class utility type with InstanceType
8475
+ } // @ts-expect-error TODO Replace Class utility type with InstanceType
8459
8476
 
8460
8477
 
8461
- const type = klass.getType();
8462
- registeredNodes.set(type, {
8463
- klass,
8464
- transforms: new Set()
8465
- });
8478
+ const type = klass.getType();
8479
+ registeredNodes.set(type, {
8480
+ klass,
8481
+ transforms: new Set()
8482
+ });
8483
+ }
8466
8484
  }
8467
8485
 
8468
8486
  const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {
8469
8487
  disableEvents,
8488
+ namespace,
8470
8489
  theme
8471
8490
  }, onError, initializeConversionCache(registeredNodes), isReadOnly);
8472
8491
 
@@ -8623,9 +8642,7 @@ class LexicalEditor {
8623
8642
  };
8624
8643
  }
8625
8644
 
8626
- registerNodeTransform( // There's no Flow-safe way to preserve the T in Transform<T>, but <T = LexicalNode> in the
8627
- // declaration below guarantees these are LexicalNodes.
8628
- klass, listener) {
8645
+ registerNodeTransform(klass, listener) {
8629
8646
  // @ts-expect-error TODO Replace Class utility type with InstanceType
8630
8647
  const type = klass.getType();
8631
8648
 
@@ -8647,7 +8664,7 @@ class LexicalEditor {
8647
8664
 
8648
8665
  hasNodes(nodes) {
8649
8666
  for (let i = 0; i < nodes.length; i++) {
8650
- const klass = nodes[i]; // @ts-expect-error TODO Replace Class utility type with InstanceType
8667
+ const klass = nodes[i]; // @ts-expect-error
8651
8668
 
8652
8669
  const type = klass.getType();
8653
8670
 
@@ -8816,7 +8833,7 @@ class LexicalEditor {
8816
8833
 
8817
8834
  toJSON() {
8818
8835
  return {
8819
- editorState: this._editorState
8836
+ editorState: this._editorState.toJSON()
8820
8837
  };
8821
8838
  }
8822
8839
 
@@ -8829,7 +8846,7 @@ class LexicalEditor {
8829
8846
  * LICENSE file in the root directory of this source tree.
8830
8847
  *
8831
8848
  */
8832
- const VERSION = '0.3.1';
8849
+ const VERSION = '0.3.4';
8833
8850
 
8834
8851
  /**
8835
8852
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -8879,11 +8896,11 @@ function $isGridRowNode(node) {
8879
8896
  return node instanceof GridRowNode;
8880
8897
  }
8881
8898
 
8882
- exports.$createGridSelection = $createEmptyGridSelection;
8899
+ exports.$createGridSelection = $createGridSelection;
8883
8900
  exports.$createLineBreakNode = $createLineBreakNode;
8884
- exports.$createNodeSelection = $createEmptyObjectSelection;
8901
+ exports.$createNodeSelection = $createNodeSelection;
8885
8902
  exports.$createParagraphNode = $createParagraphNode;
8886
- exports.$createRangeSelection = $createEmptyRangeSelection;
8903
+ exports.$createRangeSelection = $createRangeSelection;
8887
8904
  exports.$createTextNode = $createTextNode;
8888
8905
  exports.$getDecoratorNode = $getDecoratorNode;
8889
8906
  exports.$getNearestNodeFromDOMNode = $getNearestNodeFromDOMNode;