lexical 0.2.2 → 0.2.5

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
@@ -56,6 +56,7 @@ const IS_ALIGN_RIGHT = 3;
56
56
  const IS_ALIGN_JUSTIFY = 4; // Reconciliation
57
57
 
58
58
  const ZERO_WIDTH_CHAR = '\u200b';
59
+ const DOUBLE_LINE_BREAK = '\n\n';
59
60
  const RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
60
61
  const LTR = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' + '\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' + '\uFE00-\uFE6F\uFEFD-\uFFFF';
61
62
  const RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']');
@@ -181,6 +182,9 @@ function getTextDirection(text) {
181
182
 
182
183
  return null;
183
184
  }
185
+ function $isTokenOrInertOrSegmented(node) {
186
+ return $isTokenOrInert(node) || node.isSegmented();
187
+ }
184
188
  function $isTokenOrInert(node) {
185
189
  return node.isToken() || node.isInert();
186
190
  }
@@ -322,21 +326,24 @@ function $setCompositionKey(compositionKey) {
322
326
  errorOnReadOnly();
323
327
  const editor = getActiveEditor();
324
328
  const previousCompositionKey = editor._compositionKey;
325
- editor._compositionKey = compositionKey;
326
329
 
327
- if (previousCompositionKey !== null) {
328
- const node = $getNodeByKey(previousCompositionKey);
330
+ if (compositionKey !== previousCompositionKey) {
331
+ editor._compositionKey = compositionKey;
329
332
 
330
- if (node !== null) {
331
- node.getWritable();
333
+ if (previousCompositionKey !== null) {
334
+ const node = $getNodeByKey(previousCompositionKey);
335
+
336
+ if (node !== null) {
337
+ node.getWritable();
338
+ }
332
339
  }
333
- }
334
340
 
335
- if (compositionKey !== null) {
336
- const node = $getNodeByKey(compositionKey);
341
+ if (compositionKey !== null) {
342
+ const node = $getNodeByKey(compositionKey);
337
343
 
338
- if (node !== null) {
339
- node.getWritable();
344
+ if (node !== null) {
345
+ node.getWritable();
346
+ }
340
347
  }
341
348
  }
342
349
  }
@@ -543,7 +550,9 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
543
550
  const editor = getActiveEditor();
544
551
  setTimeout(() => {
545
552
  editor.update(() => {
546
- node.remove();
553
+ if (node.isAttached()) {
554
+ node.remove();
555
+ }
547
556
  });
548
557
  }, 20);
549
558
  } else {
@@ -724,6 +733,9 @@ function isMoveUp(keyCode, ctrlKey, shiftKey, altKey, metaKey) {
724
733
  function isMoveDown(keyCode, ctrlKey, shiftKey, altKey, metaKey) {
725
734
  return isArrowDown(keyCode) && !ctrlKey && !metaKey;
726
735
  }
736
+ function isModifier(ctrlKey, shiftKey, altKey, metaKey) {
737
+ return ctrlKey || shiftKey || altKey || metaKey;
738
+ }
727
739
  function controlOrMeta(metaKey, ctrlKey) {
728
740
  if (IS_APPLE) {
729
741
  return metaKey;
@@ -849,6 +861,9 @@ function isFirefoxClipboardEvents() {
849
861
  function dispatchCommand(editor, type, payload) {
850
862
  return triggerCommandListeners(editor, type, payload);
851
863
  }
864
+ function $textContentRequiresDoubleLinebreakAtEnd(node) {
865
+ return !$isRootNode(node) && !node.isLastChild() && !node.isInline();
866
+ }
852
867
 
853
868
  /**
854
869
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -1088,6 +1103,7 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
1088
1103
  node.__style = parsedNode.__style;
1089
1104
  node.__mode = parsedNode.__mode;
1090
1105
  node.__detail = parsedNode.__detail;
1106
+ node.__marks = parsedNode.__marks;
1091
1107
  } // The selection might refer to an old node whose key has changed. Produce a
1092
1108
  // new selection record with the old keys mapped to the new ones.
1093
1109
 
@@ -1138,8 +1154,8 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
1138
1154
  }
1139
1155
  } else if (originalSelection.type === 'grid') {
1140
1156
  const gridKey = originalSelection.gridKey;
1141
- const anchorCellKey = originalSelection.anchorCellKey;
1142
- const focusCellKey = originalSelection.focusCellKey;
1157
+ const anchorCellKey = originalSelection.anchor.key;
1158
+ const focusCellKey = originalSelection.focus.key;
1143
1159
 
1144
1160
  if (remappedSelection == null && (gridKey === parsedKey || gridKey === anchorCellKey || gridKey === focusCellKey)) {
1145
1161
  state.remappedSelection = remappedSelection = { ...originalSelection,
@@ -1153,11 +1169,11 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
1153
1169
  }
1154
1170
 
1155
1171
  if (anchorCellKey === parsedKey) {
1156
- remappedSelection.anchorCellKey = key;
1172
+ remappedSelection.anchor.key = key;
1157
1173
  }
1158
1174
 
1159
1175
  if (focusCellKey === parsedKey) {
1160
- remappedSelection.focusCellKey = key;
1176
+ remappedSelection.focus.key = key;
1161
1177
  }
1162
1178
  }
1163
1179
  }
@@ -1166,6 +1182,56 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
1166
1182
  return node;
1167
1183
  }
1168
1184
 
1185
+ /**
1186
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
1187
+ *
1188
+ * This source code is licensed under the MIT license found in the
1189
+ * LICENSE file in the root directory of this source tree.
1190
+ *
1191
+ *
1192
+ */
1193
+ function createCommand() {
1194
+ // $FlowFixMe: avoid freezing the object for perf reasons
1195
+ return {};
1196
+ }
1197
+ const SELECTION_CHANGE_COMMAND = createCommand();
1198
+ const CLICK_COMMAND = createCommand();
1199
+ const DELETE_CHARACTER_COMMAND = createCommand();
1200
+ const INSERT_LINE_BREAK_COMMAND = createCommand();
1201
+ const INSERT_PARAGRAPH_COMMAND = createCommand();
1202
+ const INSERT_TEXT_COMMAND = createCommand();
1203
+ const PASTE_COMMAND = createCommand();
1204
+ const REMOVE_TEXT_COMMAND = createCommand();
1205
+ const DELETE_WORD_COMMAND = createCommand();
1206
+ const DELETE_LINE_COMMAND = createCommand();
1207
+ const FORMAT_TEXT_COMMAND = createCommand();
1208
+ const UNDO_COMMAND = createCommand();
1209
+ const REDO_COMMAND = createCommand();
1210
+ const KEY_ARROW_RIGHT_COMMAND = createCommand();
1211
+ const KEY_ARROW_LEFT_COMMAND = createCommand();
1212
+ const KEY_ARROW_UP_COMMAND = createCommand();
1213
+ const KEY_ARROW_DOWN_COMMAND = createCommand();
1214
+ const KEY_ENTER_COMMAND = createCommand();
1215
+ const KEY_BACKSPACE_COMMAND = createCommand();
1216
+ const KEY_ESCAPE_COMMAND = createCommand();
1217
+ const KEY_DELETE_COMMAND = createCommand();
1218
+ const KEY_TAB_COMMAND = createCommand();
1219
+ const INDENT_CONTENT_COMMAND = createCommand();
1220
+ const OUTDENT_CONTENT_COMMAND = createCommand();
1221
+ const DROP_COMMAND = createCommand();
1222
+ const FORMAT_ELEMENT_COMMAND = createCommand();
1223
+ const DRAGSTART_COMMAND = createCommand();
1224
+ const DRAGEND_COMMAND = createCommand();
1225
+ const COPY_COMMAND = createCommand();
1226
+ const CUT_COMMAND = createCommand();
1227
+ const CLEAR_EDITOR_COMMAND = createCommand();
1228
+ const CLEAR_HISTORY_COMMAND = createCommand();
1229
+ const CAN_REDO_COMMAND = createCommand();
1230
+ const CAN_UNDO_COMMAND = createCommand();
1231
+ const FOCUS_COMMAND = createCommand();
1232
+ const BLUR_COMMAND = createCommand();
1233
+ const KEY_MODIFIER_COMMAND = createCommand();
1234
+
1169
1235
  /**
1170
1236
  * Copyright (c) Meta Platforms, Inc. and affiliates.
1171
1237
  *
@@ -1193,20 +1259,31 @@ if (CAN_USE_BEFORE_INPUT) {
1193
1259
  let lastKeyDownTimeStamp = 0;
1194
1260
  let rootElementsRegistered = 0;
1195
1261
  let isSelectionChangeFromReconcile = false;
1262
+ let isInsertLineBreak = false;
1263
+ let collapsedSelectionFormat = [0, 0, 'root', 0];
1264
+
1265
+ function shouldSkipSelectionChange(domNode, offset) {
1266
+ return domNode !== null && domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length;
1267
+ }
1196
1268
 
1197
1269
  function onSelectionChange(domSelection, editor, isActive) {
1198
1270
  if (isSelectionChangeFromReconcile) {
1199
1271
  isSelectionChangeFromReconcile = false;
1200
1272
  const {
1201
1273
  anchorNode,
1202
- focusNode
1274
+ anchorOffset,
1275
+ focusNode,
1276
+ focusOffset
1203
1277
  } = domSelection; // If native DOM selection is on a DOM element, then
1204
1278
  // we should continue as usual, as Lexical's selection
1205
1279
  // may have normalized to a better child. If the DOM
1206
1280
  // element is a text node, we can safely apply this
1207
1281
  // optimization and skip the selection change entirely.
1282
+ // We also need to check if the offset is at the boundary,
1283
+ // because in this case, we might need to normalize to a
1284
+ // sibling instead.
1208
1285
 
1209
- if (anchorNode !== null && focusNode !== null && anchorNode.nodeType === DOM_TEXT_TYPE && focusNode.nodeType === DOM_TEXT_TYPE) {
1286
+ if (shouldSkipSelectionChange(anchorNode, anchorOffset) && shouldSkipSelectionChange(focusNode, focusOffset)) {
1210
1287
  return;
1211
1288
  }
1212
1289
  }
@@ -1221,19 +1298,45 @@ function onSelectionChange(domSelection, editor, isActive) {
1221
1298
 
1222
1299
  const selection = $getSelection(); // Update the selection format
1223
1300
 
1224
- if ($isRangeSelection(selection) && selection.isCollapsed()) {
1225
- // Badly interpreted range selection when collapsed - #1482
1226
- if (domSelection.type === 'Range') {
1227
- selection.dirty = true;
1228
- }
1229
-
1301
+ if ($isRangeSelection(selection)) {
1230
1302
  const anchor = selection.anchor;
1303
+ const anchorNode = anchor.getNode();
1304
+
1305
+ if (selection.isCollapsed()) {
1306
+ // Badly interpreted range selection when collapsed - #1482
1307
+ if (domSelection.type === 'Range') {
1308
+ selection.dirty = true;
1309
+ } // If we have marked a collapsed selection format, and we're
1310
+ // within the given time range – then attempt to use that format
1311
+ // instead of getting the format from the anchor node.
1312
+
1313
+
1314
+ const currentTimeStamp = window.event.timeStamp;
1315
+ const [lastFormat, lastOffset, lastKey, timeStamp] = collapsedSelectionFormat;
1316
+
1317
+ if (currentTimeStamp < timeStamp + 200 && anchor.offset === lastOffset && anchor.key === lastKey) {
1318
+ selection.format = lastFormat;
1319
+ } else {
1320
+ if (anchor.type === 'text') {
1321
+ selection.format = anchorNode.getFormat();
1322
+ } else if (anchor.type === 'element') {
1323
+ selection.format = 0;
1324
+ }
1325
+ }
1326
+ } else {
1327
+ const focus = selection.focus;
1328
+ const focusNode = focus.getNode();
1329
+ let combinedFormat = 0;
1231
1330
 
1232
- if (anchor.type === 'text') {
1233
- const anchorNode = anchor.getNode();
1234
- selection.format = anchorNode.getFormat();
1235
- } else if (anchor.type === 'element') {
1236
- selection.format = 0;
1331
+ if (anchor.type === 'text') {
1332
+ combinedFormat |= anchorNode.getFormat();
1333
+ }
1334
+
1335
+ if (focus.type === 'text' && !anchorNode.is(focusNode)) {
1336
+ combinedFormat |= focusNode.getFormat();
1337
+ }
1338
+
1339
+ selection.format = combinedFormat;
1237
1340
  }
1238
1341
  }
1239
1342
 
@@ -1254,7 +1357,7 @@ function onClick(event, editor) {
1254
1357
  const anchor = selection.anchor;
1255
1358
 
1256
1359
  if (anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && $getRoot().getChildrenSize() === 1 && anchor.getNode().getTopLevelElementOrThrow().isEmpty()) {
1257
- const lastSelection = editor.getEditorState()._selection;
1360
+ const lastSelection = $getPreviousSelection();
1258
1361
 
1259
1362
  if (lastSelection !== null && selection.is(lastSelection)) {
1260
1363
  getDOMSelection().removeAllRanges();
@@ -1331,12 +1434,19 @@ function onBeforeInput(event, editor) {
1331
1434
  updateEditor(editor, () => {
1332
1435
  const selection = $getSelection();
1333
1436
 
1334
- if (!$isRangeSelection(selection)) {
1335
- return;
1336
- }
1337
-
1338
1437
  if (inputType === 'deleteContentBackward') {
1339
- // Used for Android
1438
+ if (selection === null) {
1439
+ // Use previous selection
1440
+ const prevSelection = $getPreviousSelection();
1441
+
1442
+ if (!$isRangeSelection(prevSelection)) {
1443
+ return;
1444
+ }
1445
+
1446
+ $setSelection(prevSelection.clone());
1447
+ } // Used for Android
1448
+
1449
+
1340
1450
  $setCompositionKey(null);
1341
1451
  event.preventDefault();
1342
1452
  lastKeyDownTimeStamp = 0;
@@ -1350,6 +1460,10 @@ function onBeforeInput(event, editor) {
1350
1460
  return;
1351
1461
  }
1352
1462
 
1463
+ if (!$isRangeSelection(selection)) {
1464
+ return;
1465
+ }
1466
+
1353
1467
  const data = event.data;
1354
1468
 
1355
1469
  if (!selection.dirty && selection.isCollapsed() && !$isRootNode(selection.anchor.getNode())) {
@@ -1365,7 +1479,7 @@ function onBeforeInput(event, editor) {
1365
1479
  if (data === '\n') {
1366
1480
  event.preventDefault();
1367
1481
  dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND);
1368
- } else if (data === '\n\n') {
1482
+ } else if (data === DOUBLE_LINE_BREAK) {
1369
1483
  event.preventDefault();
1370
1484
  dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
1371
1485
  } else if (data == null && event.dataTransfer) {
@@ -1414,8 +1528,16 @@ function onBeforeInput(event, editor) {
1414
1528
  case 'insertParagraph':
1415
1529
  {
1416
1530
  // Used for Android
1417
- $setCompositionKey(null);
1418
- dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
1531
+ $setCompositionKey(null); // Some browsers do not provide the type "insertLineBreak".
1532
+ // So instead, we need to infer it from the keyboard event.
1533
+
1534
+ if (isInsertLineBreak) {
1535
+ isInsertLineBreak = false;
1536
+ dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND);
1537
+ } else {
1538
+ dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
1539
+ }
1540
+
1419
1541
  break;
1420
1542
  }
1421
1543
 
@@ -1549,7 +1671,9 @@ function onCompositionStart(event, editor) {
1549
1671
 
1550
1672
  if ( // If it has been 30ms since the last keydown, then we should
1551
1673
  // apply the empty space heuristic.
1552
- event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY || anchor.type === 'element' || !selection.isCollapsed() || selection.anchor.getNode().getFormat() !== selection.format) {
1674
+ event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY || // FF has issues around composing multibyte characters, so we also
1675
+ // need to invoke the empty space heuristic below.
1676
+ IS_FIREFOX && anchor.type === 'element' || !selection.isCollapsed() || selection.anchor.getNode().getFormat() !== selection.format) {
1553
1677
  // We insert an empty space, ready for the composition
1554
1678
  // to get inserted into the new node we create. If
1555
1679
  // we don't do this, Safari will fail on us because
@@ -1620,11 +1744,14 @@ function onKeyDown(event, editor) {
1620
1744
  } else if (isMoveDown(keyCode, ctrlKey, shiftKey, altKey, metaKey)) {
1621
1745
  dispatchCommand(editor, KEY_ARROW_DOWN_COMMAND, event);
1622
1746
  } else if (isLineBreak(keyCode, shiftKey)) {
1747
+ isInsertLineBreak = true;
1623
1748
  dispatchCommand(editor, KEY_ENTER_COMMAND, event);
1624
1749
  } else if (isOpenLineBreak(keyCode, ctrlKey)) {
1625
1750
  event.preventDefault();
1751
+ isInsertLineBreak = true;
1626
1752
  dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, true);
1627
1753
  } else if (isParagraph(keyCode, shiftKey)) {
1754
+ isInsertLineBreak = false;
1628
1755
  dispatchCommand(editor, KEY_ENTER_COMMAND, event);
1629
1756
  } else if (isDeleteBackward(keyCode, altKey, metaKey, ctrlKey)) {
1630
1757
  if (isBackspace(keyCode)) {
@@ -1672,6 +1799,10 @@ function onKeyDown(event, editor) {
1672
1799
  event.preventDefault();
1673
1800
  dispatchCommand(editor, REDO_COMMAND);
1674
1801
  }
1802
+
1803
+ if (isModifier(ctrlKey, shiftKey, altKey, metaKey)) {
1804
+ dispatchCommand(editor, KEY_MODIFIER_COMMAND, event);
1805
+ }
1675
1806
  }
1676
1807
 
1677
1808
  function getRootElementRemoveHandles(rootElement) {
@@ -1755,6 +1886,9 @@ function addRootElementEvents(rootElement, editor) {
1755
1886
  case 'dragstart':
1756
1887
  return dispatchCommand(editor, DRAGSTART_COMMAND, event);
1757
1888
 
1889
+ case 'dragend':
1890
+ return dispatchCommand(editor, DRAGEND_COMMAND, event);
1891
+
1758
1892
  case 'focus':
1759
1893
  return dispatchCommand(editor, FOCUS_COMMAND, event);
1760
1894
 
@@ -1821,6 +1955,9 @@ function cleanActiveNestedEditorsMap(editor) {
1821
1955
  function markSelectionChangeFromReconcile() {
1822
1956
  isSelectionChangeFromReconcile = true;
1823
1957
  }
1958
+ function markCollapsedSelectionFormat(format, offset, key, timeStamp) {
1959
+ collapsedSelectionFormat = [format, offset, key, timeStamp];
1960
+ }
1824
1961
 
1825
1962
  /**
1826
1963
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -1888,7 +2025,7 @@ function setTextAlign(domStyle, value) {
1888
2025
  }
1889
2026
 
1890
2027
  function setElementIndent(dom, indent) {
1891
- dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent * 40 + 'px');
2028
+ dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent * 20 + 'px');
1892
2029
  }
1893
2030
 
1894
2031
  function setElementFormat(dom, format) {
@@ -1949,6 +2086,11 @@ function createNode(key, parentDOM, insertDOM) {
1949
2086
  }
1950
2087
 
1951
2088
  reconcileElementTerminatingLineBreak(null, children, dom);
2089
+
2090
+ if ($textContentRequiresDoubleLinebreakAtEnd(node)) {
2091
+ subTreeTextContent += DOUBLE_LINE_BREAK;
2092
+ editorTextContent += DOUBLE_LINE_BREAK;
2093
+ }
1952
2094
  } else {
1953
2095
  const text = node.getTextContent();
1954
2096
 
@@ -2120,12 +2262,12 @@ function reconcileBlockDirection(element, dom) {
2120
2262
  function reconcileChildrenWithDirection(prevChildren, nextChildren, element, dom) {
2121
2263
  const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;
2122
2264
  subTreeDirectionedTextContent = '';
2123
- reconcileChildren(prevChildren, nextChildren, dom);
2265
+ reconcileChildren(element, prevChildren, nextChildren, dom);
2124
2266
  reconcileBlockDirection(element, dom);
2125
2267
  subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;
2126
2268
  }
2127
2269
 
2128
- function reconcileChildren(prevChildren, nextChildren, dom) {
2270
+ function reconcileChildren(element, prevChildren, nextChildren, dom) {
2129
2271
  const previousSubTreeTextContent = subTreeTextContent;
2130
2272
  subTreeTextContent = '';
2131
2273
  const prevChildrenLength = prevChildren.length;
@@ -2160,7 +2302,11 @@ function reconcileChildren(prevChildren, nextChildren, dom) {
2160
2302
  }
2161
2303
  }
2162
2304
  } else {
2163
- reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom);
2305
+ reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom);
2306
+ }
2307
+
2308
+ if ($textContentRequiresDoubleLinebreakAtEnd(element)) {
2309
+ subTreeTextContent += DOUBLE_LINE_BREAK;
2164
2310
  } // $FlowFixMe: internal field
2165
2311
 
2166
2312
 
@@ -2255,6 +2401,11 @@ function reconcileNode(key, parentDOM) {
2255
2401
  reconcileElementTerminatingLineBreak(prevChildren, nextChildren, dom);
2256
2402
  }
2257
2403
  }
2404
+
2405
+ if ($textContentRequiresDoubleLinebreakAtEnd(nextNode)) {
2406
+ subTreeTextContent += DOUBLE_LINE_BREAK;
2407
+ editorTextContent += DOUBLE_LINE_BREAK;
2408
+ }
2258
2409
  } else {
2259
2410
  const text = nextNode.getTextContent();
2260
2411
 
@@ -2264,6 +2415,9 @@ function reconcileNode(key, parentDOM) {
2264
2415
  if (decorator !== null) {
2265
2416
  reconcileDecorator(key, decorator);
2266
2417
  }
2418
+
2419
+ subTreeTextContent += text;
2420
+ editorTextContent += text;
2267
2421
  } else if ($isTextNode(nextNode) && !nextNode.isDirectionless()) {
2268
2422
  // Handle text content, for LTR, LTR cases.
2269
2423
  subTreeDirectionedTextContent += text;
@@ -2312,7 +2466,7 @@ function getNextSibling(element) {
2312
2466
  return element.nextSibling;
2313
2467
  }
2314
2468
 
2315
- function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
2469
+ function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom) {
2316
2470
  const prevEndIndex = prevChildrenLength - 1;
2317
2471
  const nextEndIndex = nextChildrenLength - 1;
2318
2472
  let prevChildrenSet;
@@ -2453,7 +2607,7 @@ function updateEditorState(rootElement, currentEditorState, pendingEditorState,
2453
2607
 
2454
2608
  const domSelection = getDOMSelection();
2455
2609
 
2456
- if (domSelection !== null && (needsUpdate || pendingSelection === null || pendingSelection.dirty)) {
2610
+ if (!editor._readOnly && domSelection !== null && (needsUpdate || pendingSelection === null || pendingSelection.dirty)) {
2457
2611
  reconcileSelection(currentSelection, pendingSelection, editor, domSelection);
2458
2612
  }
2459
2613
 
@@ -2526,11 +2680,15 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
2526
2680
  const focusDOM = getElementByKeyOrThrow(editor, focusKey);
2527
2681
  const nextAnchorOffset = anchor.offset;
2528
2682
  const nextFocusOffset = focus.offset;
2683
+ const nextFormat = nextSelection.format;
2684
+ const isCollapsed = nextSelection.isCollapsed();
2529
2685
  let nextAnchorNode = anchorDOM;
2530
2686
  let nextFocusNode = focusDOM;
2687
+ let anchorFormatChanged = false;
2531
2688
 
2532
2689
  if (anchor.type === 'text') {
2533
2690
  nextAnchorNode = getDOMTextNode(anchorDOM);
2691
+ anchorFormatChanged = anchor.getNode().getFormat() !== nextFormat;
2534
2692
  }
2535
2693
 
2536
2694
  if (focus.type === 'text') {
@@ -2541,20 +2699,31 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
2541
2699
 
2542
2700
  if (nextAnchorNode === null || nextFocusNode === null) {
2543
2701
  return;
2702
+ }
2703
+
2704
+ if (isCollapsed && (prevSelection === null || anchorFormatChanged || prevSelection.format !== nextFormat)) {
2705
+ markCollapsedSelectionFormat(nextFormat, nextAnchorOffset, anchorKey, performance.now());
2544
2706
  } // Diff against the native DOM selection to ensure we don't do
2545
- // an unnecessary selection update.
2707
+ // an unnecessary selection update. We also skip this check if
2708
+ // we're moving selection to within an element, as this can
2709
+ // sometimes be problematic around scrolling.
2546
2710
 
2547
2711
 
2548
2712
  if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482
2549
- !(domSelection.type === 'Range' && nextSelection.isCollapsed())) {
2713
+ !(domSelection.type === 'Range' && isCollapsed)) {
2550
2714
  // If the root element does not have focus, ensure it has focus
2551
2715
  if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
2552
2716
  rootElement.focus({
2553
2717
  preventScroll: true
2554
2718
  });
2555
- }
2719
+ } // In Safari/iOS if we have selection on an element, then we also
2720
+ // need to additionally set the DOM selection, otherwise a selectionchange
2721
+ // event will not fire.
2556
2722
 
2557
- return;
2723
+
2724
+ if (!(IS_IOS || IS_SAFARI) || anchor.type !== 'element') {
2725
+ return;
2726
+ }
2558
2727
  } // Apply the updated selection to the DOM. Note: this will trigger
2559
2728
  // a "selectionchange" event, although it will be asynchronous.
2560
2729
 
@@ -2685,7 +2854,7 @@ function $normalizeAllDirtyTextNodes(editorState, editor) {
2685
2854
  for (const nodeKey of dirtyLeaves) {
2686
2855
  const node = nodeMap.get(nodeKey);
2687
2856
 
2688
- if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
2857
+ if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
2689
2858
  $normalizeTextNode(node);
2690
2859
  }
2691
2860
  }
@@ -2721,7 +2890,7 @@ function $applyAllTransforms(editorState, editor) {
2721
2890
  for (const nodeKey of untransformedDirtyLeaves) {
2722
2891
  const node = nodeMap.get(nodeKey);
2723
2892
 
2724
- if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
2893
+ if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
2725
2894
  $normalizeTextNode(node);
2726
2895
  }
2727
2896
 
@@ -3039,9 +3208,9 @@ function triggerDeferredUpdateCallbacks(editor) {
3039
3208
  }
3040
3209
  }
3041
3210
 
3042
- function processNestedUpdates(editor) {
3211
+ function processNestedUpdates(editor, initialSkipTransforms) {
3043
3212
  const queuedUpdates = editor._updates;
3044
- let skipTransforms = false; // Updates might grow as we process them, we so we'll need
3213
+ let skipTransforms = initialSkipTransforms || false; // Updates might grow as we process them, we so we'll need
3045
3214
  // to handle each update as we go until the updates array is
3046
3215
  // empty.
3047
3216
 
@@ -3119,7 +3288,7 @@ function beginUpdate(editor, updateFn, options) {
3119
3288
 
3120
3289
  const startingCompositionKey = editor._compositionKey;
3121
3290
  updateFn();
3122
- skipTransforms = processNestedUpdates(editor);
3291
+ skipTransforms = processNestedUpdates(editor, skipTransforms);
3123
3292
  applySelectionTransforms(pendingEditorState, editor);
3124
3293
 
3125
3294
  if (editor._dirtyType !== NO_DIRTY_NODES) {
@@ -3480,10 +3649,6 @@ class Point {
3480
3649
  return aNode.isBefore(bNode);
3481
3650
  }
3482
3651
 
3483
- getCharacterOffset() {
3484
- return this.type === 'text' ? this.offset : 0;
3485
- }
3486
-
3487
3652
  getNode() {
3488
3653
  const key = this.key;
3489
3654
  const node = $getNodeByKey(key);
@@ -3665,12 +3830,10 @@ function $isRangeSelection(x) {
3665
3830
  return x instanceof RangeSelection;
3666
3831
  }
3667
3832
  class GridSelection {
3668
- constructor(gridKey, anchorCellKey, focusCellKey) {
3833
+ constructor(gridKey, anchor, focus) {
3669
3834
  this.gridKey = gridKey;
3670
- this.anchorCellKey = anchorCellKey;
3671
- this.anchor = $createPoint(anchorCellKey, 0, 'element');
3672
- this.focusCellKey = focusCellKey;
3673
- this.focus = $createPoint(focusCellKey, 0, 'element');
3835
+ this.anchor = anchor;
3836
+ this.focus = focus;
3674
3837
  this.dirty = false;
3675
3838
  }
3676
3839
 
@@ -3679,18 +3842,18 @@ class GridSelection {
3679
3842
  return false;
3680
3843
  }
3681
3844
 
3682
- return this.gridKey === selection.gridKey && this.anchorCellKey === selection.anchorCellKey && this.focusCellKey === selection.focusCellKey;
3845
+ return this.gridKey === selection.gridKey && this.anchor.is(this.focus);
3683
3846
  }
3684
3847
 
3685
3848
  set(gridKey, anchorCellKey, focusCellKey) {
3686
3849
  this.dirty = true;
3687
3850
  this.gridKey = gridKey;
3688
- this.anchorCellKey = anchorCellKey;
3689
- this.focusCellKey = focusCellKey;
3851
+ this.anchor.key = anchorCellKey;
3852
+ this.focus.key = focusCellKey;
3690
3853
  }
3691
3854
 
3692
3855
  clone() {
3693
- return new GridSelection(this.gridKey, this.anchorCellKey, this.focusCellKey);
3856
+ return new GridSelection(this.gridKey, this.anchor, this.focus);
3694
3857
  }
3695
3858
 
3696
3859
  isCollapsed() {
@@ -3701,6 +3864,10 @@ class GridSelection {
3701
3864
  return this.focus.isBefore(this.anchor);
3702
3865
  }
3703
3866
 
3867
+ getCharacterOffsets() {
3868
+ return getCharacterOffsets(this);
3869
+ }
3870
+
3704
3871
  extract() {
3705
3872
  return this.getNodes();
3706
3873
  }
@@ -3712,7 +3879,7 @@ class GridSelection {
3712
3879
  }
3713
3880
 
3714
3881
  getShape() {
3715
- const anchorCellNode = $getNodeByKey(this.anchorCellKey);
3882
+ const anchorCellNode = $getNodeByKey(this.anchor.key);
3716
3883
 
3717
3884
  if (!anchorCellNode) {
3718
3885
  throw Error(`getNodes: expected to find AnchorNode`);
@@ -3720,7 +3887,7 @@ class GridSelection {
3720
3887
 
3721
3888
  const anchorCellNodeIndex = anchorCellNode.getIndexWithinParent();
3722
3889
  const anchorCelRoweIndex = anchorCellNode.getParentOrThrow().getIndexWithinParent();
3723
- const focusCellNode = $getNodeByKey(this.focusCellKey);
3890
+ const focusCellNode = $getNodeByKey(this.focus.key);
3724
3891
 
3725
3892
  if (!focusCellNode) {
3726
3893
  throw Error(`getNodes: expected to find FocusNode`);
@@ -3851,7 +4018,7 @@ class RangeSelection {
3851
4018
  }
3852
4019
 
3853
4020
  if (firstNode.is(lastNode)) {
3854
- if ($isElementNode(firstNode)) {
4021
+ if ($isElementNode(firstNode) && (firstNode.getChildrenSize() > 0 || firstNode.excludeFromCopy())) {
3855
4022
  return [];
3856
4023
  }
3857
4024
 
@@ -3879,8 +4046,7 @@ class RangeSelection {
3879
4046
  const anchor = this.anchor;
3880
4047
  const focus = this.focus;
3881
4048
  const isBefore = anchor.isBefore(focus);
3882
- const anchorOffset = anchor.getCharacterOffset();
3883
- const focusOffset = focus.getCharacterOffset();
4049
+ const [anchorOffset, focusOffset] = getCharacterOffsets(this);
3884
4050
  let textContent = '';
3885
4051
  let prevWasElement = true;
3886
4052
 
@@ -4008,11 +4174,13 @@ class RangeSelection {
4008
4174
  const firstNodeText = firstNode.getTextContent();
4009
4175
  const firstNodeTextLength = firstNodeText.length;
4010
4176
  const firstNodeParent = firstNode.getParentOrThrow();
4177
+ const lastIndex = selectedNodesLength - 1;
4178
+ let lastNode = selectedNodes[lastIndex];
4011
4179
 
4012
4180
  if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter())) {
4013
4181
  let nextSibling = firstNode.getNextSibling();
4014
4182
 
4015
- if (!$isTextNode(nextSibling) || $isTokenOrInert(nextSibling) || nextSibling.isSegmented()) {
4183
+ if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
4016
4184
  nextSibling = $createTextNode();
4017
4185
 
4018
4186
  if (!firstNodeParent.canInsertTextAfter()) {
@@ -4032,7 +4200,7 @@ class RangeSelection {
4032
4200
  } else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore())) {
4033
4201
  let prevSibling = firstNode.getPreviousSibling();
4034
4202
 
4035
- if (!$isTextNode(prevSibling) || $isTokenOrInert(prevSibling) || prevSibling.isSegmented()) {
4203
+ if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
4036
4204
  prevSibling = $createTextNode();
4037
4205
 
4038
4206
  if (!firstNodeParent.canInsertTextBefore()) {
@@ -4053,6 +4221,19 @@ class RangeSelection {
4053
4221
  const textNode = $createTextNode(firstNode.getTextContent());
4054
4222
  firstNode.replace(textNode);
4055
4223
  firstNode = textNode;
4224
+ } else if (!this.isCollapsed() && text !== '') {
4225
+ // When the firstNode or lastNode parents are elements that
4226
+ // do not allow text to be inserted before or after, we first
4227
+ // clear the content. Then we normalize selection, then insert
4228
+ // the new content.
4229
+ const lastNodeParent = lastNode.getParent();
4230
+
4231
+ if (!firstNodeParent.canInsertTextBefore() || !firstNodeParent.canInsertTextAfter() || $isElementNode(lastNodeParent) && (!lastNodeParent.canInsertTextBefore() || !lastNodeParent.canInsertTextAfter())) {
4232
+ this.insertText('');
4233
+ normalizeSelectionPointsForBoundaries(this.anchor, this.focus, null);
4234
+ this.insertText(text);
4235
+ return;
4236
+ }
4056
4237
  }
4057
4238
 
4058
4239
  if (selectedNodesLength === 1) {
@@ -4101,8 +4282,6 @@ class RangeSelection {
4101
4282
  this.anchor.offset -= text.length;
4102
4283
  }
4103
4284
  } else {
4104
- const lastIndex = selectedNodesLength - 1;
4105
- let lastNode = selectedNodes[lastIndex];
4106
4285
  const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);
4107
4286
  const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
4108
4287
  const lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow(); // Handle mutations to the last node.
@@ -4118,7 +4297,13 @@ class RangeSelection {
4118
4297
  lastNode = lastNode.spliceText(0, endOffset, '');
4119
4298
  markedNodeKeysForKeep.add(lastNode.__key);
4120
4299
  } else {
4121
- lastNode.remove();
4300
+ const lastNodeParent = lastNode.getParentOrThrow();
4301
+
4302
+ if (!lastNodeParent.canBeEmpty() && lastNodeParent.getChildrenSize() === 1) {
4303
+ lastNodeParent.remove();
4304
+ } else {
4305
+ lastNode.remove();
4306
+ }
4122
4307
  }
4123
4308
  } else {
4124
4309
  markedNodeKeysForKeep.add(lastNode.__key);
@@ -4227,10 +4412,9 @@ class RangeSelection {
4227
4412
 
4228
4413
  const anchor = this.anchor;
4229
4414
  const focus = this.focus;
4230
- const firstNodeText = firstNode.getTextContent();
4231
- const firstNodeTextLength = firstNodeText.length;
4232
4415
  const focusOffset = focus.offset;
4233
4416
  let firstNextFormat = 0;
4417
+ let firstNodeTextLength = firstNode.getTextContent().length;
4234
4418
 
4235
4419
  for (let i = 0; i < selectedNodes.length; i++) {
4236
4420
  const selectedNode = selectedNodes[i];
@@ -4257,6 +4441,7 @@ class RangeSelection {
4257
4441
  anchorOffset = 0;
4258
4442
  startOffset = 0;
4259
4443
  firstNode = nextSibling;
4444
+ firstNodeTextLength = nextSibling.getTextContent().length;
4260
4445
  firstNextFormat = firstNode.getFormatFlags(formatType, null);
4261
4446
  }
4262
4447
  } // This is the case where we only selected a single node
@@ -4637,6 +4822,7 @@ class RangeSelection {
4637
4822
 
4638
4823
  if (anchor.type === 'text') {
4639
4824
  const anchorNode = anchor.getNode();
4825
+ nodesToMove = anchorNode.getNextSiblings().reverse();
4640
4826
  currentElement = anchorNode.getParentOrThrow();
4641
4827
  const isInline = currentElement.isInline();
4642
4828
  const textContentLength = isInline ? currentElement.getTextContentSize() : anchorNode.getTextContentSize();
@@ -4652,8 +4838,6 @@ class RangeSelection {
4652
4838
  }
4653
4839
 
4654
4840
  if (anchorOffset !== textContentLength) {
4655
- nodesToMove = anchorNode.getNextSiblings().reverse();
4656
-
4657
4841
  if (!isInline || anchorOffset !== anchorNode.getTextContentSize()) {
4658
4842
  const [, splitNode] = anchorNode.splitText(anchorOffset);
4659
4843
  nodesToMove.push(splitNode);
@@ -4757,6 +4941,10 @@ class RangeSelection {
4757
4941
  }
4758
4942
  }
4759
4943
 
4944
+ getCharacterOffsets() {
4945
+ return getCharacterOffsets(this);
4946
+ }
4947
+
4760
4948
  extract() {
4761
4949
  const selectedNodes = this.getNodes();
4762
4950
  const selectedNodesLength = selectedNodes.length;
@@ -4765,8 +4953,7 @@ class RangeSelection {
4765
4953
  const focus = this.focus;
4766
4954
  let firstNode = selectedNodes[0];
4767
4955
  let lastNode = selectedNodes[lastIndex];
4768
- const anchorOffset = anchor.getCharacterOffset();
4769
- const focusOffset = focus.getCharacterOffset();
4956
+ const [anchorOffset, focusOffset] = getCharacterOffsets(this);
4770
4957
 
4771
4958
  if (selectedNodesLength === 0) {
4772
4959
  return [];
@@ -4844,6 +5031,16 @@ class RangeSelection {
4844
5031
  anchor.set(elementKey, offset, 'element');
4845
5032
  }
4846
5033
 
5034
+ return;
5035
+ } else {
5036
+ const siblingKey = sibling.__key;
5037
+ const offset = isBackward ? sibling.getTextContent().length : 0;
5038
+ focus.set(siblingKey, offset, 'text');
5039
+
5040
+ if (collapse) {
5041
+ anchor.set(siblingKey, offset, 'text');
5042
+ }
5043
+
4847
5044
  return;
4848
5045
  }
4849
5046
  }
@@ -4946,6 +5143,29 @@ function $isNodeSelection(x) {
4946
5143
  return x instanceof NodeSelection;
4947
5144
  }
4948
5145
 
5146
+ function getCharacterOffset(point) {
5147
+ const offset = point.offset;
5148
+
5149
+ if (point.type === 'text') {
5150
+ return offset;
5151
+ } // $FlowFixMe: cast
5152
+
5153
+
5154
+ const parent = point.getNode();
5155
+ return offset === parent.getChildrenSize() ? parent.getTextContent().length : 0;
5156
+ }
5157
+
5158
+ function getCharacterOffsets(selection) {
5159
+ const anchor = selection.anchor;
5160
+ const focus = selection.focus;
5161
+
5162
+ if (anchor.type === 'element' && focus.type === 'element' && anchor.key === focus.key && anchor.offset === focus.offset) {
5163
+ return [0, 0];
5164
+ }
5165
+
5166
+ return [getCharacterOffset(anchor), getCharacterOffset(focus)];
5167
+ }
5168
+
4949
5169
  function $swapPoints(selection) {
4950
5170
  const focus = selection.focus;
4951
5171
  const anchor = selection.anchor;
@@ -5114,6 +5334,78 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
5114
5334
  return $createPoint(resolvedNode.__key, resolvedOffset, 'text');
5115
5335
  }
5116
5336
 
5337
+ function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {
5338
+ const offset = point.offset;
5339
+ const node = point.getNode();
5340
+
5341
+ if (offset === 0) {
5342
+ const prevSibling = node.getPreviousSibling();
5343
+ const parent = node.getParent();
5344
+
5345
+ if (!isBackward) {
5346
+ if ($isElementNode(prevSibling) && !isCollapsed && prevSibling.isInline()) {
5347
+ point.key = prevSibling.__key;
5348
+ point.offset = prevSibling.getChildrenSize(); // $FlowFixMe: intentional
5349
+
5350
+ point.type = 'element';
5351
+ } else if ($isTextNode(prevSibling) && !prevSibling.isInert()) {
5352
+ point.key = prevSibling.__key;
5353
+ point.offset = prevSibling.getTextContent().length;
5354
+ }
5355
+ } else if ((isCollapsed || !isBackward) && prevSibling === null && $isElementNode(parent) && parent.isInline()) {
5356
+ const parentSibling = parent.getPreviousSibling();
5357
+
5358
+ if ($isTextNode(parentSibling)) {
5359
+ point.key = parentSibling.__key;
5360
+ point.offset = parentSibling.getTextContent().length;
5361
+ }
5362
+ }
5363
+ } else if (offset === node.getTextContent().length) {
5364
+ const nextSibling = node.getNextSibling();
5365
+ const parent = node.getParent();
5366
+
5367
+ if (isBackward && $isElementNode(nextSibling) && nextSibling.isInline()) {
5368
+ point.key = nextSibling.__key;
5369
+ point.offset = 0; // $FlowFixMe: intentional
5370
+
5371
+ point.type = 'element';
5372
+ } else if ((isCollapsed || isBackward) && nextSibling === null && $isElementNode(parent) && parent.isInline()) {
5373
+ const parentSibling = parent.getNextSibling();
5374
+
5375
+ if ($isTextNode(parentSibling)) {
5376
+ point.key = parentSibling.__key;
5377
+ point.offset = 0;
5378
+ }
5379
+ }
5380
+ }
5381
+ }
5382
+
5383
+ function normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) {
5384
+ if (anchor.type === 'text' && focus.type === 'text') {
5385
+ const isBackward = anchor.isBefore(focus);
5386
+ const isCollapsed = anchor.is(focus); // Attempt to normalize the offset to the previous sibling if we're at the
5387
+ // start of a text node and the sibling is a text node or inline element.
5388
+
5389
+ resolveSelectionPointOnBoundary(anchor, isBackward, isCollapsed);
5390
+ resolveSelectionPointOnBoundary(focus, !isBackward, isCollapsed);
5391
+
5392
+ if (isCollapsed) {
5393
+ focus.key = anchor.key;
5394
+ focus.offset = anchor.offset;
5395
+ focus.type = anchor.type;
5396
+ }
5397
+
5398
+ const editor = getActiveEditor();
5399
+
5400
+ if (editor.isComposing() && editor._compositionKey !== anchor.key && $isRangeSelection(lastSelection)) {
5401
+ const lastAnchor = lastSelection.anchor;
5402
+ const lastFocus = lastSelection.focus;
5403
+ $setPointValues(anchor, lastAnchor.key, lastAnchor.offset, lastAnchor.type);
5404
+ $setPointValues(focus, lastFocus.key, lastFocus.offset, lastFocus.type);
5405
+ }
5406
+ }
5407
+ }
5408
+
5117
5409
  function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {
5118
5410
  if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
5119
5411
  return null;
@@ -5129,48 +5421,10 @@ function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focus
5129
5421
 
5130
5422
  if (resolvedFocusPoint === null) {
5131
5423
  return null;
5132
- }
5424
+ } // Handle normalization of selection when it is at the boundaries.
5133
5425
 
5134
- if (resolvedAnchorPoint.type === 'text' && resolvedFocusPoint.type === 'text') {
5135
- const resolvedAnchorNode = resolvedAnchorPoint.getNode();
5136
- const resolvedFocusNode = resolvedFocusPoint.getNode(); // Handle normalization of selection when it is at the boundaries.
5137
-
5138
- const textContentSize = resolvedAnchorNode.getTextContentSize();
5139
- const resolvedAnchorOffset = resolvedAnchorPoint.offset;
5140
- const resolvedFocusOffset = resolvedFocusPoint.offset;
5141
-
5142
- if (resolvedAnchorNode === resolvedFocusNode && resolvedAnchorOffset === resolvedFocusOffset) {
5143
- if (anchorOffset === 0) {
5144
- const prevSibling = resolvedAnchorNode.getPreviousSibling();
5145
-
5146
- if ($isTextNode(prevSibling) && !prevSibling.isInert()) {
5147
- const offset = prevSibling.getTextContentSize();
5148
- const key = prevSibling.__key;
5149
- resolvedAnchorPoint.key = key;
5150
- resolvedFocusPoint.key = key;
5151
- resolvedAnchorPoint.offset = offset;
5152
- resolvedFocusPoint.offset = offset;
5153
- }
5154
- }
5155
- } else {
5156
- if (resolvedAnchorOffset === textContentSize) {
5157
- const nextSibling = resolvedAnchorNode.getNextSibling();
5158
-
5159
- if ($isTextNode(nextSibling) && !nextSibling.isInert()) {
5160
- resolvedAnchorPoint.key = nextSibling.__key;
5161
- resolvedAnchorPoint.offset = 0;
5162
- }
5163
- }
5164
- }
5165
-
5166
- if (editor.isComposing() && editor._compositionKey !== resolvedAnchorPoint.key && $isRangeSelection(lastSelection)) {
5167
- const lastAnchor = lastSelection.anchor;
5168
- const lastFocus = lastSelection.focus;
5169
- $setPointValues(resolvedAnchorPoint, lastAnchor.key, lastAnchor.offset, lastAnchor.type);
5170
- $setPointValues(resolvedFocusPoint, lastFocus.key, lastFocus.offset, lastFocus.type);
5171
- }
5172
- }
5173
5426
 
5427
+ normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint, lastSelection);
5174
5428
  return [resolvedAnchorPoint, resolvedFocusPoint];
5175
5429
  } // This is used to make a selection when the existing
5176
5430
  // selection is null, i.e. forcing selection on the editor
@@ -5193,7 +5447,9 @@ function $createEmptyObjectSelection() {
5193
5447
  return new NodeSelection(new Set());
5194
5448
  }
5195
5449
  function $createEmptyGridSelection() {
5196
- return new GridSelection('root', 'root', 'root');
5450
+ const anchor = $createPoint('root', 0, 'element');
5451
+ const focus = $createPoint('root', 0, 'element');
5452
+ return new GridSelection('root', anchor, focus);
5197
5453
  }
5198
5454
 
5199
5455
  function getActiveEventType() {
@@ -5272,7 +5528,7 @@ function internalCreateSelectionFromParse(parsedSelection) {
5272
5528
  } else if (parsedSelection.type === 'node') {
5273
5529
  return new NodeSelection(new Set(parsedSelection.nodes));
5274
5530
  } else if (parsedSelection.type === 'grid') {
5275
- return new GridSelection(parsedSelection.gridKey, parsedSelection.anchorCellKey, parsedSelection.focusCellKey);
5531
+ return new GridSelection(parsedSelection.gridKey, $createPoint(parsedSelection.anchor.key, parsedSelection.anchor.offset, parsedSelection.anchor.type), $createPoint(parsedSelection.focus.key, parsedSelection.focus.offset, parsedSelection.focus.type));
5276
5532
  }
5277
5533
  }
5278
5534
 
@@ -5479,7 +5735,7 @@ function adjustPointOffsetForMergedSibling(point, isBefore, key, target, textLen
5479
5735
  *
5480
5736
  *
5481
5737
  */
5482
- function removeNode(nodeToRemove, restoreSelection) {
5738
+ function removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) {
5483
5739
  errorOnReadOnly();
5484
5740
  const key = nodeToRemove.__key;
5485
5741
  const parent = nodeToRemove.getParent();
@@ -5525,7 +5781,7 @@ function removeNode(nodeToRemove, restoreSelection) {
5525
5781
  $updateElementSelectionOnCreateDeleteNode(selection, parent, index, -1);
5526
5782
  }
5527
5783
 
5528
- if (parent !== null && !$isRootNode(parent) && !parent.canBeEmpty() && parent.isEmpty()) {
5784
+ if (!preserveEmptyParent && parent !== null && !$isRootNode(parent) && !parent.canBeEmpty() && parent.isEmpty()) {
5529
5785
  removeNode(parent, restoreSelection);
5530
5786
  }
5531
5787
 
@@ -6016,10 +6272,12 @@ class LexicalNode {
6016
6272
  mutableNode.__format = latestNode.__format;
6017
6273
  mutableNode.__dir = latestNode.__dir;
6018
6274
  } else if ($isTextNode(latestNode) && $isTextNode(mutableNode)) {
6275
+ const marks = latestNode.__marks;
6019
6276
  mutableNode.__format = latestNode.__format;
6020
6277
  mutableNode.__style = latestNode.__style;
6021
6278
  mutableNode.__mode = latestNode.__mode;
6022
6279
  mutableNode.__detail = latestNode.__detail;
6280
+ mutableNode.__marks = marks === null ? marks : Array.from(marks);
6023
6281
  }
6024
6282
 
6025
6283
  cloneNotNeeded.add(key);
@@ -6040,23 +6298,20 @@ class LexicalNode {
6040
6298
  getTextContentSize(includeInert, includeDirectionless) {
6041
6299
  return this.getTextContent(includeInert, includeDirectionless).length;
6042
6300
  } // View
6043
- // $FlowFixMe: Revise typings for EditorContext
6044
6301
 
6045
6302
 
6046
6303
  createDOM(config, editor) {
6047
6304
  {
6048
6305
  throw Error(`createDOM: base method not extended`);
6049
6306
  }
6050
- } // $FlowFixMe: Revise typings for EditorContext
6051
-
6307
+ }
6052
6308
 
6053
6309
  updateDOM( // $FlowFixMe: TODO
6054
6310
  prevNode, dom, config) {
6055
6311
  {
6056
6312
  throw Error(`updateDOM: base method not extended`);
6057
6313
  }
6058
- } // $FlowFixMe: Revise typings for EditorContext
6059
-
6314
+ }
6060
6315
 
6061
6316
  exportDOM(editor) {
6062
6317
  if ($isDecoratorNode(this)) {
@@ -6077,9 +6332,9 @@ class LexicalNode {
6077
6332
  } // Setters and mutators
6078
6333
 
6079
6334
 
6080
- remove() {
6335
+ remove(preserveEmptyParent) {
6081
6336
  errorOnReadOnly();
6082
- removeNode(this, true);
6337
+ removeNode(this, true, preserveEmptyParent);
6083
6338
  }
6084
6339
 
6085
6340
  replace(replaceWith) {
@@ -6373,6 +6628,12 @@ class ElementNode extends LexicalNode {
6373
6628
  return dirtyElements !== null && dirtyElements.has(this.__key);
6374
6629
  }
6375
6630
 
6631
+ isLastChild() {
6632
+ const self = this.getLatest();
6633
+ const parent = self.getParentOrThrow();
6634
+ return parent.getLastChild() === self;
6635
+ }
6636
+
6376
6637
  getAllTextNodes(includeInert) {
6377
6638
  const textNodes = [];
6378
6639
  const self = this.getLatest();
@@ -6507,7 +6768,7 @@ class ElementNode extends LexicalNode {
6507
6768
  textContent += child.getTextContent(includeInert, includeDirectionless);
6508
6769
 
6509
6770
  if ($isElementNode(child) && i !== childrenLength - 1 && !child.isInline()) {
6510
- textContent += '\n\n';
6771
+ textContent += DOUBLE_LINE_BREAK;
6511
6772
  }
6512
6773
  }
6513
6774
 
@@ -6736,6 +6997,10 @@ class ElementNode extends LexicalNode {
6736
6997
  return false;
6737
6998
  }
6738
6999
 
7000
+ canIndent() {
7001
+ return true;
7002
+ }
7003
+
6739
7004
  collapseAtStart(selection) {
6740
7005
  return false;
6741
7006
  }
@@ -6956,8 +7221,16 @@ class EditorState {
6956
7221
  nodes: Array.from(selection._nodes),
6957
7222
  type: 'node'
6958
7223
  } : $isGridSelection(selection) ? {
6959
- anchorCellKey: selection.anchorCellKey,
6960
- focusCellKey: selection.focusCellKey,
7224
+ anchor: {
7225
+ key: selection.anchor.key,
7226
+ offset: selection.anchor.offset,
7227
+ type: selection.anchor.type
7228
+ },
7229
+ focus: {
7230
+ key: selection.focus.key,
7231
+ offset: selection.focus.offset,
7232
+ type: selection.focus.type
7233
+ },
6961
7234
  gridKey: selection.gridKey,
6962
7235
  type: 'grid'
6963
7236
  } : null
@@ -7023,6 +7296,44 @@ function $isLineBreakNode(node) {
7023
7296
  return node instanceof LineBreakNode;
7024
7297
  }
7025
7298
 
7299
+ /**
7300
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
7301
+ *
7302
+ * This source code is licensed under the MIT license found in the
7303
+ * LICENSE file in the root directory of this source tree.
7304
+ *
7305
+ *
7306
+ */
7307
+ function simpleDiffWithCursor(a, b, cursor) {
7308
+ const aLength = a.length;
7309
+ const bLength = b.length;
7310
+ let left = 0; // number of same characters counting from left
7311
+
7312
+ let right = 0; // number of same characters counting from right
7313
+ // Iterate left to the right until we find a changed character
7314
+ // First iteration considers the current cursor position
7315
+
7316
+ while (left < aLength && left < bLength && a[left] === b[left] && left < cursor) {
7317
+ left++;
7318
+ } // Iterate right to the left until we find a changed character
7319
+
7320
+
7321
+ while (right + left < aLength && right + left < bLength && a[aLength - right - 1] === b[bLength - right - 1]) {
7322
+ right++;
7323
+ } // Try to iterate left further to the right without caring about the current cursor position
7324
+
7325
+
7326
+ while (right + left < aLength && right + left < bLength && a[left] === b[left]) {
7327
+ left++;
7328
+ }
7329
+
7330
+ return {
7331
+ index: left,
7332
+ insert: b.slice(left, bLength - right),
7333
+ remove: aLength - left - right
7334
+ };
7335
+ }
7336
+
7026
7337
  /**
7027
7338
  * Copyright (c) Meta Platforms, Inc. and affiliates.
7028
7339
  *
@@ -7037,6 +7348,14 @@ function getElementOuterTag(node, format) {
7037
7348
  return 'code';
7038
7349
  }
7039
7350
 
7351
+ if (format & IS_SUBSCRIPT) {
7352
+ return 'sub';
7353
+ }
7354
+
7355
+ if (format & IS_SUPERSCRIPT) {
7356
+ return 'sup';
7357
+ }
7358
+
7040
7359
  return null;
7041
7360
  }
7042
7361
 
@@ -7163,6 +7482,42 @@ function createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {
7163
7482
  }
7164
7483
  }
7165
7484
 
7485
+ function updateTextMarks(textNode, marks, offset, delCount, size) {
7486
+ for (let i = 0; i < marks.length; i++) {
7487
+ const {
7488
+ id,
7489
+ start,
7490
+ end
7491
+ } = marks[i];
7492
+ let newStart = start;
7493
+ let newEnd = end;
7494
+
7495
+ if (newStart !== null && newStart >= offset) {
7496
+ if (offset + delCount >= newStart) {
7497
+ newStart = offset + delCount;
7498
+ }
7499
+
7500
+ newStart += size - delCount;
7501
+ }
7502
+
7503
+ if (newEnd !== null && newEnd >= offset) {
7504
+ if (offset + delCount >= newEnd) {
7505
+ newEnd = offset;
7506
+ }
7507
+
7508
+ newEnd += size - delCount;
7509
+ }
7510
+
7511
+ if (newStart !== start || newEnd !== end) {
7512
+ if (newStart === null && newEnd === null || newStart !== null && newEnd !== null && newStart >= newEnd) {
7513
+ textNode.deleteMark(id);
7514
+ } else {
7515
+ textNode.setMark(id, newStart, newEnd);
7516
+ }
7517
+ }
7518
+ }
7519
+ }
7520
+
7166
7521
  class TextNode extends LexicalNode {
7167
7522
  static getType() {
7168
7523
  return 'text';
@@ -7179,6 +7534,7 @@ class TextNode extends LexicalNode {
7179
7534
  this.__style = '';
7180
7535
  this.__mode = 0;
7181
7536
  this.__detail = 0;
7537
+ this.__marks = null;
7182
7538
  }
7183
7539
 
7184
7540
  getFormat() {
@@ -7186,6 +7542,23 @@ class TextNode extends LexicalNode {
7186
7542
  return self.__format;
7187
7543
  }
7188
7544
 
7545
+ getMark(id) {
7546
+ const self = this.getLatest();
7547
+ const marks = self.__marks;
7548
+
7549
+ if (marks !== null) {
7550
+ for (let i = 0; i < marks.length; i++) {
7551
+ const mark = marks[i];
7552
+
7553
+ if (mark.id === id) {
7554
+ return mark;
7555
+ }
7556
+ }
7557
+ }
7558
+
7559
+ return null;
7560
+ }
7561
+
7189
7562
  getStyle() {
7190
7563
  const self = this.getLatest();
7191
7564
  return self.__style;
@@ -7239,7 +7612,6 @@ class TextNode extends LexicalNode {
7239
7612
  const format = self.__format;
7240
7613
  return toggleTextFormatType(format, type, alignWithFormat);
7241
7614
  } // View
7242
- // $FlowFixMe: Revise typings for EditorContext
7243
7615
 
7244
7616
 
7245
7617
  createDOM(config) {
@@ -7264,8 +7636,7 @@ class TextNode extends LexicalNode {
7264
7636
  }
7265
7637
 
7266
7638
  return dom;
7267
- } // $FlowFixMe: Revise typings for EditorContext
7268
-
7639
+ }
7269
7640
 
7270
7641
  updateDOM(prevNode, dom, config) {
7271
7642
  const nextText = this.__text;
@@ -7401,6 +7772,64 @@ class TextNode extends LexicalNode {
7401
7772
  return self;
7402
7773
  }
7403
7774
 
7775
+ setMark(id, start, end) {
7776
+ errorOnReadOnly();
7777
+ const self = this.getWritable();
7778
+ let marks = self.__marks;
7779
+ let found = false;
7780
+
7781
+ if (marks === null) {
7782
+ self.__marks = marks = [];
7783
+ }
7784
+
7785
+ const nextMark = {
7786
+ end,
7787
+ id,
7788
+ start
7789
+ };
7790
+
7791
+ {
7792
+ Object.freeze(nextMark);
7793
+ }
7794
+
7795
+ for (let i = 0; i < marks.length; i++) {
7796
+ const prevMark = marks[i];
7797
+
7798
+ if (prevMark.id === id) {
7799
+ found = true;
7800
+ marks.splice(i, 1, nextMark);
7801
+ break;
7802
+ }
7803
+ }
7804
+
7805
+ if (!found) {
7806
+ marks.push(nextMark);
7807
+ }
7808
+ }
7809
+
7810
+ deleteMark(id) {
7811
+ errorOnReadOnly();
7812
+ const self = this.getWritable();
7813
+ const marks = self.__marks;
7814
+
7815
+ if (marks === null) {
7816
+ return;
7817
+ }
7818
+
7819
+ for (let i = 0; i < marks.length; i++) {
7820
+ const prevMark = marks[i];
7821
+
7822
+ if (prevMark.id === id) {
7823
+ marks.splice(i, 1);
7824
+ break;
7825
+ }
7826
+ }
7827
+
7828
+ if (marks.length === 0) {
7829
+ self.__marks = null;
7830
+ }
7831
+ }
7832
+
7404
7833
  setMode(type) {
7405
7834
  errorOnReadOnly();
7406
7835
  const mode = TEXT_MODE_TO_TYPE[type];
@@ -7412,7 +7841,26 @@ class TextNode extends LexicalNode {
7412
7841
  setTextContent(text) {
7413
7842
  errorOnReadOnly();
7414
7843
  const writableSelf = this.getWritable();
7415
- writableSelf.__text = text;
7844
+ const marks = writableSelf.__marks;
7845
+
7846
+ if (marks !== null) {
7847
+ const selection = $getSelection();
7848
+ let cursorOffset = text.length;
7849
+
7850
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
7851
+ const anchor = selection.anchor;
7852
+
7853
+ if (anchor.key === this.__key) {
7854
+ cursorOffset = anchor.offset;
7855
+ }
7856
+ }
7857
+
7858
+ const diff = simpleDiffWithCursor(writableSelf.__text, text, cursorOffset);
7859
+ this.spliceText(diff.index, diff.remove, diff.insert);
7860
+ } else {
7861
+ writableSelf.__text = text;
7862
+ }
7863
+
7416
7864
  return writableSelf;
7417
7865
  }
7418
7866
 
@@ -7477,7 +7925,14 @@ class TextNode extends LexicalNode {
7477
7925
  }
7478
7926
 
7479
7927
  const updatedText = text.slice(0, index) + newText + text.slice(index + delCount);
7480
- return writableSelf.setTextContent(updatedText);
7928
+ const marks = writableSelf.__marks;
7929
+
7930
+ if (marks !== null) {
7931
+ updateTextMarks(writableSelf, marks, offset, delCount, handledTextLength);
7932
+ }
7933
+
7934
+ writableSelf.__text = updatedText;
7935
+ return writableSelf;
7481
7936
  }
7482
7937
 
7483
7938
  canInsertTextBefore() {
@@ -7527,6 +7982,7 @@ class TextNode extends LexicalNode {
7527
7982
  const format = self.getFormat();
7528
7983
  const style = self.getStyle();
7529
7984
  const detail = self.__detail;
7985
+ const marks = self.__marks;
7530
7986
  let hasReplacedSelf = false;
7531
7987
 
7532
7988
  if (self.isSegmented()) {
@@ -7536,6 +7992,7 @@ class TextNode extends LexicalNode {
7536
7992
  writableNode.__format = format;
7537
7993
  writableNode.__style = style;
7538
7994
  writableNode.__detail = detail;
7995
+ writableNode.__marks = marks;
7539
7996
  hasReplacedSelf = true;
7540
7997
  } else {
7541
7998
  // For the first part, update the existing node
@@ -7583,6 +8040,46 @@ class TextNode extends LexicalNode {
7583
8040
  textSize = nextTextSize;
7584
8041
  sibling.__parent = parentKey;
7585
8042
  splitNodes.push(sibling);
8043
+ }
8044
+
8045
+ if (marks !== null) {
8046
+ for (let i = 0; i < marks.length; i++) {
8047
+ const {
8048
+ id,
8049
+ start,
8050
+ end
8051
+ } = marks[i];
8052
+ let foundStart = false;
8053
+ let foundEnd = false;
8054
+ let partSize = 0;
8055
+
8056
+ for (let s = 0; s < partsLength; s++) {
8057
+ const textNode = splitNodes[s];
8058
+ const nextPartSize = partSize + parts[s].length;
8059
+ const nextStart = !foundStart && start !== null && nextPartSize > start - (start === 0 ? 1 : 0) ? start - partSize : null;
8060
+ const nextEnd = !foundEnd && end !== null && nextPartSize >= end ? end - partSize : null;
8061
+
8062
+ if (nextStart !== null || nextEnd !== null) {
8063
+ if (nextStart !== null) {
8064
+ foundStart = true;
8065
+ }
8066
+
8067
+ if (nextEnd !== null) {
8068
+ foundEnd = true;
8069
+ }
8070
+
8071
+ textNode.setMark(id, nextStart, nextEnd);
8072
+
8073
+ if (foundStart && foundEnd) {
8074
+ break;
8075
+ }
8076
+ } else {
8077
+ textNode.deleteMark(id);
8078
+ }
8079
+
8080
+ partSize = nextPartSize;
8081
+ }
8082
+ }
7586
8083
  } // Insert the nodes into the parent's children
7587
8084
 
7588
8085
 
@@ -7642,10 +8139,20 @@ class TextNode extends LexicalNode {
7642
8139
  }
7643
8140
  }
7644
8141
 
7645
- const newText = isBefore ? target.__text + text : text + target.__text;
8142
+ const targetText = target.__text;
8143
+ const targetTextLength = targetText.length;
8144
+ const newText = isBefore ? targetText + text : text + targetText;
7646
8145
  this.setTextContent(newText);
8146
+ const writableSelf = this.getWritable();
8147
+
8148
+ const marks = target.getLatest().__marks;
8149
+
8150
+ if (marks !== null) {
8151
+ updateTextMarks(writableSelf, marks, isBefore ? targetTextLength : 0, 0, textLength);
8152
+ }
8153
+
7647
8154
  target.remove();
7648
- return this.getLatest();
8155
+ return writableSelf;
7649
8156
  }
7650
8157
 
7651
8158
  isTextEntity() {
@@ -7919,7 +8426,6 @@ function createEditor(editorConfig) {
7919
8426
  const config = editorConfig || {};
7920
8427
  const namespace = config.namespace || createUID();
7921
8428
  const theme = config.theme || {};
7922
- const context = config.context || {};
7923
8429
  const parentEditor = config.parentEditor || null;
7924
8430
  const disableEvents = config.disableEvents || false;
7925
8431
  const editorState = createEmptyEditorState();
@@ -7941,8 +8447,6 @@ function createEditor(editorConfig) {
7941
8447
 
7942
8448
 
7943
8449
  const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {
7944
- // $FlowFixMe: we use our internal type to simpify the generics
7945
- context,
7946
8450
  disableEvents,
7947
8451
  namespace,
7948
8452
  theme
@@ -8301,7 +8805,7 @@ class LexicalEditor {
8301
8805
  *
8302
8806
  *
8303
8807
  */
8304
- const VERSION = '0.2.2';
8808
+ const VERSION = '0.2.5';
8305
8809
 
8306
8810
  /**
8307
8811
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -8347,54 +8851,6 @@ function $isGridRowNode(node) {
8347
8851
  return node instanceof GridRowNode;
8348
8852
  }
8349
8853
 
8350
- /**
8351
- * Copyright (c) Meta Platforms, Inc. and affiliates.
8352
- *
8353
- * This source code is licensed under the MIT license found in the
8354
- * LICENSE file in the root directory of this source tree.
8355
- *
8356
- *
8357
- */
8358
- function createCommand() {
8359
- // $FlowFixMe: avoid freezing the object for perf reasons
8360
- return {};
8361
- }
8362
- const SELECTION_CHANGE_COMMAND = createCommand();
8363
- const CLICK_COMMAND = createCommand();
8364
- const DELETE_CHARACTER_COMMAND = createCommand();
8365
- const INSERT_LINE_BREAK_COMMAND = createCommand();
8366
- const INSERT_PARAGRAPH_COMMAND = createCommand();
8367
- const INSERT_TEXT_COMMAND = createCommand();
8368
- const PASTE_COMMAND = createCommand();
8369
- const REMOVE_TEXT_COMMAND = createCommand();
8370
- const DELETE_WORD_COMMAND = createCommand();
8371
- const DELETE_LINE_COMMAND = createCommand();
8372
- const FORMAT_TEXT_COMMAND = createCommand();
8373
- const UNDO_COMMAND = createCommand();
8374
- const REDO_COMMAND = createCommand();
8375
- const KEY_ARROW_RIGHT_COMMAND = createCommand();
8376
- const KEY_ARROW_LEFT_COMMAND = createCommand();
8377
- const KEY_ARROW_UP_COMMAND = createCommand();
8378
- const KEY_ARROW_DOWN_COMMAND = createCommand();
8379
- const KEY_ENTER_COMMAND = createCommand();
8380
- const KEY_BACKSPACE_COMMAND = createCommand();
8381
- const KEY_ESCAPE_COMMAND = createCommand();
8382
- const KEY_DELETE_COMMAND = createCommand();
8383
- const KEY_TAB_COMMAND = createCommand();
8384
- const INDENT_CONTENT_COMMAND = createCommand();
8385
- const OUTDENT_CONTENT_COMMAND = createCommand();
8386
- const DROP_COMMAND = createCommand();
8387
- const FORMAT_ELEMENT_COMMAND = createCommand();
8388
- const DRAGSTART_COMMAND = createCommand();
8389
- const COPY_COMMAND = createCommand();
8390
- const CUT_COMMAND = createCommand();
8391
- const CLEAR_EDITOR_COMMAND = createCommand();
8392
- const CLEAR_HISTORY_COMMAND = createCommand();
8393
- const CAN_REDO_COMMAND = createCommand();
8394
- const CAN_UNDO_COMMAND = createCommand();
8395
- const FOCUS_COMMAND = createCommand();
8396
- const BLUR_COMMAND = createCommand();
8397
-
8398
8854
  exports.$createGridSelection = $createEmptyGridSelection;
8399
8855
  exports.$createLineBreakNode = $createLineBreakNode;
8400
8856
  exports.$createNodeFromParse = $createNodeFromParse;
@@ -8440,6 +8896,7 @@ exports.CUT_COMMAND = CUT_COMMAND;
8440
8896
  exports.DELETE_CHARACTER_COMMAND = DELETE_CHARACTER_COMMAND;
8441
8897
  exports.DELETE_LINE_COMMAND = DELETE_LINE_COMMAND;
8442
8898
  exports.DELETE_WORD_COMMAND = DELETE_WORD_COMMAND;
8899
+ exports.DRAGEND_COMMAND = DRAGEND_COMMAND;
8443
8900
  exports.DRAGSTART_COMMAND = DRAGSTART_COMMAND;
8444
8901
  exports.DROP_COMMAND = DROP_COMMAND;
8445
8902
  exports.DecoratorNode = DecoratorNode;
@@ -8462,6 +8919,7 @@ exports.KEY_BACKSPACE_COMMAND = KEY_BACKSPACE_COMMAND;
8462
8919
  exports.KEY_DELETE_COMMAND = KEY_DELETE_COMMAND;
8463
8920
  exports.KEY_ENTER_COMMAND = KEY_ENTER_COMMAND;
8464
8921
  exports.KEY_ESCAPE_COMMAND = KEY_ESCAPE_COMMAND;
8922
+ exports.KEY_MODIFIER_COMMAND = KEY_MODIFIER_COMMAND;
8465
8923
  exports.KEY_TAB_COMMAND = KEY_TAB_COMMAND;
8466
8924
  exports.OUTDENT_CONTENT_COMMAND = OUTDENT_CONTENT_COMMAND;
8467
8925
  exports.PASTE_COMMAND = PASTE_COMMAND;