lexical 0.2.4 → 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.d.ts +29 -44
- package/Lexical.dev.js +582 -140
- package/Lexical.js.flow +27 -44
- package/Lexical.prod.js +164 -157
- package/package.json +1 -1
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 (
|
|
328
|
-
|
|
330
|
+
if (compositionKey !== previousCompositionKey) {
|
|
331
|
+
editor._compositionKey = compositionKey;
|
|
329
332
|
|
|
330
|
-
if (
|
|
331
|
-
node
|
|
333
|
+
if (previousCompositionKey !== null) {
|
|
334
|
+
const node = $getNodeByKey(previousCompositionKey);
|
|
335
|
+
|
|
336
|
+
if (node !== null) {
|
|
337
|
+
node.getWritable();
|
|
338
|
+
}
|
|
332
339
|
}
|
|
333
|
-
}
|
|
334
340
|
|
|
335
|
-
|
|
336
|
-
|
|
341
|
+
if (compositionKey !== null) {
|
|
342
|
+
const node = $getNodeByKey(compositionKey);
|
|
337
343
|
|
|
338
|
-
|
|
339
|
-
|
|
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.
|
|
553
|
+
if (node.isAttached()) {
|
|
554
|
+
node.remove();
|
|
555
|
+
}
|
|
547
556
|
});
|
|
548
557
|
}, 20);
|
|
549
558
|
} else {
|
|
@@ -852,6 +861,9 @@ function isFirefoxClipboardEvents() {
|
|
|
852
861
|
function dispatchCommand(editor, type, payload) {
|
|
853
862
|
return triggerCommandListeners(editor, type, payload);
|
|
854
863
|
}
|
|
864
|
+
function $textContentRequiresDoubleLinebreakAtEnd(node) {
|
|
865
|
+
return !$isRootNode(node) && !node.isLastChild() && !node.isInline();
|
|
866
|
+
}
|
|
855
867
|
|
|
856
868
|
/**
|
|
857
869
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -1091,6 +1103,7 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
|
|
|
1091
1103
|
node.__style = parsedNode.__style;
|
|
1092
1104
|
node.__mode = parsedNode.__mode;
|
|
1093
1105
|
node.__detail = parsedNode.__detail;
|
|
1106
|
+
node.__marks = parsedNode.__marks;
|
|
1094
1107
|
} // The selection might refer to an old node whose key has changed. Produce a
|
|
1095
1108
|
// new selection record with the old keys mapped to the new ones.
|
|
1096
1109
|
|
|
@@ -1141,8 +1154,8 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
|
|
|
1141
1154
|
}
|
|
1142
1155
|
} else if (originalSelection.type === 'grid') {
|
|
1143
1156
|
const gridKey = originalSelection.gridKey;
|
|
1144
|
-
const anchorCellKey = originalSelection.
|
|
1145
|
-
const focusCellKey = originalSelection.
|
|
1157
|
+
const anchorCellKey = originalSelection.anchor.key;
|
|
1158
|
+
const focusCellKey = originalSelection.focus.key;
|
|
1146
1159
|
|
|
1147
1160
|
if (remappedSelection == null && (gridKey === parsedKey || gridKey === anchorCellKey || gridKey === focusCellKey)) {
|
|
1148
1161
|
state.remappedSelection = remappedSelection = { ...originalSelection,
|
|
@@ -1156,11 +1169,11 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
|
|
|
1156
1169
|
}
|
|
1157
1170
|
|
|
1158
1171
|
if (anchorCellKey === parsedKey) {
|
|
1159
|
-
remappedSelection.
|
|
1172
|
+
remappedSelection.anchor.key = key;
|
|
1160
1173
|
}
|
|
1161
1174
|
|
|
1162
1175
|
if (focusCellKey === parsedKey) {
|
|
1163
|
-
remappedSelection.
|
|
1176
|
+
remappedSelection.focus.key = key;
|
|
1164
1177
|
}
|
|
1165
1178
|
}
|
|
1166
1179
|
}
|
|
@@ -1208,6 +1221,7 @@ const OUTDENT_CONTENT_COMMAND = createCommand();
|
|
|
1208
1221
|
const DROP_COMMAND = createCommand();
|
|
1209
1222
|
const FORMAT_ELEMENT_COMMAND = createCommand();
|
|
1210
1223
|
const DRAGSTART_COMMAND = createCommand();
|
|
1224
|
+
const DRAGEND_COMMAND = createCommand();
|
|
1211
1225
|
const COPY_COMMAND = createCommand();
|
|
1212
1226
|
const CUT_COMMAND = createCommand();
|
|
1213
1227
|
const CLEAR_EDITOR_COMMAND = createCommand();
|
|
@@ -1245,20 +1259,31 @@ if (CAN_USE_BEFORE_INPUT) {
|
|
|
1245
1259
|
let lastKeyDownTimeStamp = 0;
|
|
1246
1260
|
let rootElementsRegistered = 0;
|
|
1247
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
|
+
}
|
|
1248
1268
|
|
|
1249
1269
|
function onSelectionChange(domSelection, editor, isActive) {
|
|
1250
1270
|
if (isSelectionChangeFromReconcile) {
|
|
1251
1271
|
isSelectionChangeFromReconcile = false;
|
|
1252
1272
|
const {
|
|
1253
1273
|
anchorNode,
|
|
1254
|
-
|
|
1274
|
+
anchorOffset,
|
|
1275
|
+
focusNode,
|
|
1276
|
+
focusOffset
|
|
1255
1277
|
} = domSelection; // If native DOM selection is on a DOM element, then
|
|
1256
1278
|
// we should continue as usual, as Lexical's selection
|
|
1257
1279
|
// may have normalized to a better child. If the DOM
|
|
1258
1280
|
// element is a text node, we can safely apply this
|
|
1259
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.
|
|
1260
1285
|
|
|
1261
|
-
if (anchorNode
|
|
1286
|
+
if (shouldSkipSelectionChange(anchorNode, anchorOffset) && shouldSkipSelectionChange(focusNode, focusOffset)) {
|
|
1262
1287
|
return;
|
|
1263
1288
|
}
|
|
1264
1289
|
}
|
|
@@ -1273,19 +1298,45 @@ function onSelectionChange(domSelection, editor, isActive) {
|
|
|
1273
1298
|
|
|
1274
1299
|
const selection = $getSelection(); // Update the selection format
|
|
1275
1300
|
|
|
1276
|
-
if ($isRangeSelection(selection)
|
|
1277
|
-
// Badly interpreted range selection when collapsed - #1482
|
|
1278
|
-
if (domSelection.type === 'Range') {
|
|
1279
|
-
selection.dirty = true;
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1301
|
+
if ($isRangeSelection(selection)) {
|
|
1282
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;
|
|
1283
1330
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
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;
|
|
1289
1340
|
}
|
|
1290
1341
|
}
|
|
1291
1342
|
|
|
@@ -1306,7 +1357,7 @@ function onClick(event, editor) {
|
|
|
1306
1357
|
const anchor = selection.anchor;
|
|
1307
1358
|
|
|
1308
1359
|
if (anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && $getRoot().getChildrenSize() === 1 && anchor.getNode().getTopLevelElementOrThrow().isEmpty()) {
|
|
1309
|
-
const lastSelection =
|
|
1360
|
+
const lastSelection = $getPreviousSelection();
|
|
1310
1361
|
|
|
1311
1362
|
if (lastSelection !== null && selection.is(lastSelection)) {
|
|
1312
1363
|
getDOMSelection().removeAllRanges();
|
|
@@ -1383,12 +1434,19 @@ function onBeforeInput(event, editor) {
|
|
|
1383
1434
|
updateEditor(editor, () => {
|
|
1384
1435
|
const selection = $getSelection();
|
|
1385
1436
|
|
|
1386
|
-
if (!$isRangeSelection(selection)) {
|
|
1387
|
-
return;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
1437
|
if (inputType === 'deleteContentBackward') {
|
|
1391
|
-
|
|
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
|
+
|
|
1392
1450
|
$setCompositionKey(null);
|
|
1393
1451
|
event.preventDefault();
|
|
1394
1452
|
lastKeyDownTimeStamp = 0;
|
|
@@ -1402,6 +1460,10 @@ function onBeforeInput(event, editor) {
|
|
|
1402
1460
|
return;
|
|
1403
1461
|
}
|
|
1404
1462
|
|
|
1463
|
+
if (!$isRangeSelection(selection)) {
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1405
1467
|
const data = event.data;
|
|
1406
1468
|
|
|
1407
1469
|
if (!selection.dirty && selection.isCollapsed() && !$isRootNode(selection.anchor.getNode())) {
|
|
@@ -1417,7 +1479,7 @@ function onBeforeInput(event, editor) {
|
|
|
1417
1479
|
if (data === '\n') {
|
|
1418
1480
|
event.preventDefault();
|
|
1419
1481
|
dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND);
|
|
1420
|
-
} else if (data ===
|
|
1482
|
+
} else if (data === DOUBLE_LINE_BREAK) {
|
|
1421
1483
|
event.preventDefault();
|
|
1422
1484
|
dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
|
|
1423
1485
|
} else if (data == null && event.dataTransfer) {
|
|
@@ -1466,8 +1528,16 @@ function onBeforeInput(event, editor) {
|
|
|
1466
1528
|
case 'insertParagraph':
|
|
1467
1529
|
{
|
|
1468
1530
|
// Used for Android
|
|
1469
|
-
$setCompositionKey(null);
|
|
1470
|
-
|
|
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
|
+
|
|
1471
1541
|
break;
|
|
1472
1542
|
}
|
|
1473
1543
|
|
|
@@ -1601,7 +1671,9 @@ function onCompositionStart(event, editor) {
|
|
|
1601
1671
|
|
|
1602
1672
|
if ( // If it has been 30ms since the last keydown, then we should
|
|
1603
1673
|
// apply the empty space heuristic.
|
|
1604
|
-
event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY ||
|
|
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) {
|
|
1605
1677
|
// We insert an empty space, ready for the composition
|
|
1606
1678
|
// to get inserted into the new node we create. If
|
|
1607
1679
|
// we don't do this, Safari will fail on us because
|
|
@@ -1672,11 +1744,14 @@ function onKeyDown(event, editor) {
|
|
|
1672
1744
|
} else if (isMoveDown(keyCode, ctrlKey, shiftKey, altKey, metaKey)) {
|
|
1673
1745
|
dispatchCommand(editor, KEY_ARROW_DOWN_COMMAND, event);
|
|
1674
1746
|
} else if (isLineBreak(keyCode, shiftKey)) {
|
|
1747
|
+
isInsertLineBreak = true;
|
|
1675
1748
|
dispatchCommand(editor, KEY_ENTER_COMMAND, event);
|
|
1676
1749
|
} else if (isOpenLineBreak(keyCode, ctrlKey)) {
|
|
1677
1750
|
event.preventDefault();
|
|
1751
|
+
isInsertLineBreak = true;
|
|
1678
1752
|
dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, true);
|
|
1679
1753
|
} else if (isParagraph(keyCode, shiftKey)) {
|
|
1754
|
+
isInsertLineBreak = false;
|
|
1680
1755
|
dispatchCommand(editor, KEY_ENTER_COMMAND, event);
|
|
1681
1756
|
} else if (isDeleteBackward(keyCode, altKey, metaKey, ctrlKey)) {
|
|
1682
1757
|
if (isBackspace(keyCode)) {
|
|
@@ -1811,6 +1886,9 @@ function addRootElementEvents(rootElement, editor) {
|
|
|
1811
1886
|
case 'dragstart':
|
|
1812
1887
|
return dispatchCommand(editor, DRAGSTART_COMMAND, event);
|
|
1813
1888
|
|
|
1889
|
+
case 'dragend':
|
|
1890
|
+
return dispatchCommand(editor, DRAGEND_COMMAND, event);
|
|
1891
|
+
|
|
1814
1892
|
case 'focus':
|
|
1815
1893
|
return dispatchCommand(editor, FOCUS_COMMAND, event);
|
|
1816
1894
|
|
|
@@ -1877,6 +1955,9 @@ function cleanActiveNestedEditorsMap(editor) {
|
|
|
1877
1955
|
function markSelectionChangeFromReconcile() {
|
|
1878
1956
|
isSelectionChangeFromReconcile = true;
|
|
1879
1957
|
}
|
|
1958
|
+
function markCollapsedSelectionFormat(format, offset, key, timeStamp) {
|
|
1959
|
+
collapsedSelectionFormat = [format, offset, key, timeStamp];
|
|
1960
|
+
}
|
|
1880
1961
|
|
|
1881
1962
|
/**
|
|
1882
1963
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -1944,7 +2025,7 @@ function setTextAlign(domStyle, value) {
|
|
|
1944
2025
|
}
|
|
1945
2026
|
|
|
1946
2027
|
function setElementIndent(dom, indent) {
|
|
1947
|
-
dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent *
|
|
2028
|
+
dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent * 20 + 'px');
|
|
1948
2029
|
}
|
|
1949
2030
|
|
|
1950
2031
|
function setElementFormat(dom, format) {
|
|
@@ -2005,6 +2086,11 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
2005
2086
|
}
|
|
2006
2087
|
|
|
2007
2088
|
reconcileElementTerminatingLineBreak(null, children, dom);
|
|
2089
|
+
|
|
2090
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(node)) {
|
|
2091
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
2092
|
+
editorTextContent += DOUBLE_LINE_BREAK;
|
|
2093
|
+
}
|
|
2008
2094
|
} else {
|
|
2009
2095
|
const text = node.getTextContent();
|
|
2010
2096
|
|
|
@@ -2176,12 +2262,12 @@ function reconcileBlockDirection(element, dom) {
|
|
|
2176
2262
|
function reconcileChildrenWithDirection(prevChildren, nextChildren, element, dom) {
|
|
2177
2263
|
const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;
|
|
2178
2264
|
subTreeDirectionedTextContent = '';
|
|
2179
|
-
reconcileChildren(prevChildren, nextChildren, dom);
|
|
2265
|
+
reconcileChildren(element, prevChildren, nextChildren, dom);
|
|
2180
2266
|
reconcileBlockDirection(element, dom);
|
|
2181
2267
|
subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;
|
|
2182
2268
|
}
|
|
2183
2269
|
|
|
2184
|
-
function reconcileChildren(prevChildren, nextChildren, dom) {
|
|
2270
|
+
function reconcileChildren(element, prevChildren, nextChildren, dom) {
|
|
2185
2271
|
const previousSubTreeTextContent = subTreeTextContent;
|
|
2186
2272
|
subTreeTextContent = '';
|
|
2187
2273
|
const prevChildrenLength = prevChildren.length;
|
|
@@ -2216,7 +2302,11 @@ function reconcileChildren(prevChildren, nextChildren, dom) {
|
|
|
2216
2302
|
}
|
|
2217
2303
|
}
|
|
2218
2304
|
} else {
|
|
2219
|
-
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;
|
|
2220
2310
|
} // $FlowFixMe: internal field
|
|
2221
2311
|
|
|
2222
2312
|
|
|
@@ -2311,6 +2401,11 @@ function reconcileNode(key, parentDOM) {
|
|
|
2311
2401
|
reconcileElementTerminatingLineBreak(prevChildren, nextChildren, dom);
|
|
2312
2402
|
}
|
|
2313
2403
|
}
|
|
2404
|
+
|
|
2405
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(nextNode)) {
|
|
2406
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
2407
|
+
editorTextContent += DOUBLE_LINE_BREAK;
|
|
2408
|
+
}
|
|
2314
2409
|
} else {
|
|
2315
2410
|
const text = nextNode.getTextContent();
|
|
2316
2411
|
|
|
@@ -2320,6 +2415,9 @@ function reconcileNode(key, parentDOM) {
|
|
|
2320
2415
|
if (decorator !== null) {
|
|
2321
2416
|
reconcileDecorator(key, decorator);
|
|
2322
2417
|
}
|
|
2418
|
+
|
|
2419
|
+
subTreeTextContent += text;
|
|
2420
|
+
editorTextContent += text;
|
|
2323
2421
|
} else if ($isTextNode(nextNode) && !nextNode.isDirectionless()) {
|
|
2324
2422
|
// Handle text content, for LTR, LTR cases.
|
|
2325
2423
|
subTreeDirectionedTextContent += text;
|
|
@@ -2368,7 +2466,7 @@ function getNextSibling(element) {
|
|
|
2368
2466
|
return element.nextSibling;
|
|
2369
2467
|
}
|
|
2370
2468
|
|
|
2371
|
-
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
|
|
2469
|
+
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom) {
|
|
2372
2470
|
const prevEndIndex = prevChildrenLength - 1;
|
|
2373
2471
|
const nextEndIndex = nextChildrenLength - 1;
|
|
2374
2472
|
let prevChildrenSet;
|
|
@@ -2582,11 +2680,15 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
|
|
|
2582
2680
|
const focusDOM = getElementByKeyOrThrow(editor, focusKey);
|
|
2583
2681
|
const nextAnchorOffset = anchor.offset;
|
|
2584
2682
|
const nextFocusOffset = focus.offset;
|
|
2683
|
+
const nextFormat = nextSelection.format;
|
|
2684
|
+
const isCollapsed = nextSelection.isCollapsed();
|
|
2585
2685
|
let nextAnchorNode = anchorDOM;
|
|
2586
2686
|
let nextFocusNode = focusDOM;
|
|
2687
|
+
let anchorFormatChanged = false;
|
|
2587
2688
|
|
|
2588
2689
|
if (anchor.type === 'text') {
|
|
2589
2690
|
nextAnchorNode = getDOMTextNode(anchorDOM);
|
|
2691
|
+
anchorFormatChanged = anchor.getNode().getFormat() !== nextFormat;
|
|
2590
2692
|
}
|
|
2591
2693
|
|
|
2592
2694
|
if (focus.type === 'text') {
|
|
@@ -2597,20 +2699,31 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
|
|
|
2597
2699
|
|
|
2598
2700
|
if (nextAnchorNode === null || nextFocusNode === null) {
|
|
2599
2701
|
return;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
if (isCollapsed && (prevSelection === null || anchorFormatChanged || prevSelection.format !== nextFormat)) {
|
|
2705
|
+
markCollapsedSelectionFormat(nextFormat, nextAnchorOffset, anchorKey, performance.now());
|
|
2600
2706
|
} // Diff against the native DOM selection to ensure we don't do
|
|
2601
|
-
// 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.
|
|
2602
2710
|
|
|
2603
2711
|
|
|
2604
2712
|
if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482
|
|
2605
|
-
!(domSelection.type === 'Range' &&
|
|
2713
|
+
!(domSelection.type === 'Range' && isCollapsed)) {
|
|
2606
2714
|
// If the root element does not have focus, ensure it has focus
|
|
2607
2715
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
2608
2716
|
rootElement.focus({
|
|
2609
2717
|
preventScroll: true
|
|
2610
2718
|
});
|
|
2611
|
-
}
|
|
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.
|
|
2612
2722
|
|
|
2613
|
-
|
|
2723
|
+
|
|
2724
|
+
if (!(IS_IOS || IS_SAFARI) || anchor.type !== 'element') {
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2614
2727
|
} // Apply the updated selection to the DOM. Note: this will trigger
|
|
2615
2728
|
// a "selectionchange" event, although it will be asynchronous.
|
|
2616
2729
|
|
|
@@ -2741,7 +2854,7 @@ function $normalizeAllDirtyTextNodes(editorState, editor) {
|
|
|
2741
2854
|
for (const nodeKey of dirtyLeaves) {
|
|
2742
2855
|
const node = nodeMap.get(nodeKey);
|
|
2743
2856
|
|
|
2744
|
-
if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2857
|
+
if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2745
2858
|
$normalizeTextNode(node);
|
|
2746
2859
|
}
|
|
2747
2860
|
}
|
|
@@ -2777,7 +2890,7 @@ function $applyAllTransforms(editorState, editor) {
|
|
|
2777
2890
|
for (const nodeKey of untransformedDirtyLeaves) {
|
|
2778
2891
|
const node = nodeMap.get(nodeKey);
|
|
2779
2892
|
|
|
2780
|
-
if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2893
|
+
if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2781
2894
|
$normalizeTextNode(node);
|
|
2782
2895
|
}
|
|
2783
2896
|
|
|
@@ -3095,9 +3208,9 @@ function triggerDeferredUpdateCallbacks(editor) {
|
|
|
3095
3208
|
}
|
|
3096
3209
|
}
|
|
3097
3210
|
|
|
3098
|
-
function processNestedUpdates(editor) {
|
|
3211
|
+
function processNestedUpdates(editor, initialSkipTransforms) {
|
|
3099
3212
|
const queuedUpdates = editor._updates;
|
|
3100
|
-
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
|
|
3101
3214
|
// to handle each update as we go until the updates array is
|
|
3102
3215
|
// empty.
|
|
3103
3216
|
|
|
@@ -3175,7 +3288,7 @@ function beginUpdate(editor, updateFn, options) {
|
|
|
3175
3288
|
|
|
3176
3289
|
const startingCompositionKey = editor._compositionKey;
|
|
3177
3290
|
updateFn();
|
|
3178
|
-
skipTransforms = processNestedUpdates(editor);
|
|
3291
|
+
skipTransforms = processNestedUpdates(editor, skipTransforms);
|
|
3179
3292
|
applySelectionTransforms(pendingEditorState, editor);
|
|
3180
3293
|
|
|
3181
3294
|
if (editor._dirtyType !== NO_DIRTY_NODES) {
|
|
@@ -3536,10 +3649,6 @@ class Point {
|
|
|
3536
3649
|
return aNode.isBefore(bNode);
|
|
3537
3650
|
}
|
|
3538
3651
|
|
|
3539
|
-
getCharacterOffset() {
|
|
3540
|
-
return this.type === 'text' ? this.offset : 0;
|
|
3541
|
-
}
|
|
3542
|
-
|
|
3543
3652
|
getNode() {
|
|
3544
3653
|
const key = this.key;
|
|
3545
3654
|
const node = $getNodeByKey(key);
|
|
@@ -3721,12 +3830,10 @@ function $isRangeSelection(x) {
|
|
|
3721
3830
|
return x instanceof RangeSelection;
|
|
3722
3831
|
}
|
|
3723
3832
|
class GridSelection {
|
|
3724
|
-
constructor(gridKey,
|
|
3833
|
+
constructor(gridKey, anchor, focus) {
|
|
3725
3834
|
this.gridKey = gridKey;
|
|
3726
|
-
this.
|
|
3727
|
-
this.
|
|
3728
|
-
this.focusCellKey = focusCellKey;
|
|
3729
|
-
this.focus = $createPoint(focusCellKey, 0, 'element');
|
|
3835
|
+
this.anchor = anchor;
|
|
3836
|
+
this.focus = focus;
|
|
3730
3837
|
this.dirty = false;
|
|
3731
3838
|
}
|
|
3732
3839
|
|
|
@@ -3735,18 +3842,18 @@ class GridSelection {
|
|
|
3735
3842
|
return false;
|
|
3736
3843
|
}
|
|
3737
3844
|
|
|
3738
|
-
return this.gridKey === selection.gridKey && this.
|
|
3845
|
+
return this.gridKey === selection.gridKey && this.anchor.is(this.focus);
|
|
3739
3846
|
}
|
|
3740
3847
|
|
|
3741
3848
|
set(gridKey, anchorCellKey, focusCellKey) {
|
|
3742
3849
|
this.dirty = true;
|
|
3743
3850
|
this.gridKey = gridKey;
|
|
3744
|
-
this.
|
|
3745
|
-
this.
|
|
3851
|
+
this.anchor.key = anchorCellKey;
|
|
3852
|
+
this.focus.key = focusCellKey;
|
|
3746
3853
|
}
|
|
3747
3854
|
|
|
3748
3855
|
clone() {
|
|
3749
|
-
return new GridSelection(this.gridKey, this.
|
|
3856
|
+
return new GridSelection(this.gridKey, this.anchor, this.focus);
|
|
3750
3857
|
}
|
|
3751
3858
|
|
|
3752
3859
|
isCollapsed() {
|
|
@@ -3757,6 +3864,10 @@ class GridSelection {
|
|
|
3757
3864
|
return this.focus.isBefore(this.anchor);
|
|
3758
3865
|
}
|
|
3759
3866
|
|
|
3867
|
+
getCharacterOffsets() {
|
|
3868
|
+
return getCharacterOffsets(this);
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3760
3871
|
extract() {
|
|
3761
3872
|
return this.getNodes();
|
|
3762
3873
|
}
|
|
@@ -3768,7 +3879,7 @@ class GridSelection {
|
|
|
3768
3879
|
}
|
|
3769
3880
|
|
|
3770
3881
|
getShape() {
|
|
3771
|
-
const anchorCellNode = $getNodeByKey(this.
|
|
3882
|
+
const anchorCellNode = $getNodeByKey(this.anchor.key);
|
|
3772
3883
|
|
|
3773
3884
|
if (!anchorCellNode) {
|
|
3774
3885
|
throw Error(`getNodes: expected to find AnchorNode`);
|
|
@@ -3776,7 +3887,7 @@ class GridSelection {
|
|
|
3776
3887
|
|
|
3777
3888
|
const anchorCellNodeIndex = anchorCellNode.getIndexWithinParent();
|
|
3778
3889
|
const anchorCelRoweIndex = anchorCellNode.getParentOrThrow().getIndexWithinParent();
|
|
3779
|
-
const focusCellNode = $getNodeByKey(this.
|
|
3890
|
+
const focusCellNode = $getNodeByKey(this.focus.key);
|
|
3780
3891
|
|
|
3781
3892
|
if (!focusCellNode) {
|
|
3782
3893
|
throw Error(`getNodes: expected to find FocusNode`);
|
|
@@ -3907,7 +4018,7 @@ class RangeSelection {
|
|
|
3907
4018
|
}
|
|
3908
4019
|
|
|
3909
4020
|
if (firstNode.is(lastNode)) {
|
|
3910
|
-
if ($isElementNode(firstNode)) {
|
|
4021
|
+
if ($isElementNode(firstNode) && (firstNode.getChildrenSize() > 0 || firstNode.excludeFromCopy())) {
|
|
3911
4022
|
return [];
|
|
3912
4023
|
}
|
|
3913
4024
|
|
|
@@ -3935,8 +4046,7 @@ class RangeSelection {
|
|
|
3935
4046
|
const anchor = this.anchor;
|
|
3936
4047
|
const focus = this.focus;
|
|
3937
4048
|
const isBefore = anchor.isBefore(focus);
|
|
3938
|
-
const anchorOffset =
|
|
3939
|
-
const focusOffset = focus.getCharacterOffset();
|
|
4049
|
+
const [anchorOffset, focusOffset] = getCharacterOffsets(this);
|
|
3940
4050
|
let textContent = '';
|
|
3941
4051
|
let prevWasElement = true;
|
|
3942
4052
|
|
|
@@ -4064,11 +4174,13 @@ class RangeSelection {
|
|
|
4064
4174
|
const firstNodeText = firstNode.getTextContent();
|
|
4065
4175
|
const firstNodeTextLength = firstNodeText.length;
|
|
4066
4176
|
const firstNodeParent = firstNode.getParentOrThrow();
|
|
4177
|
+
const lastIndex = selectedNodesLength - 1;
|
|
4178
|
+
let lastNode = selectedNodes[lastIndex];
|
|
4067
4179
|
|
|
4068
4180
|
if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter())) {
|
|
4069
4181
|
let nextSibling = firstNode.getNextSibling();
|
|
4070
4182
|
|
|
4071
|
-
if (!$isTextNode(nextSibling) || $
|
|
4183
|
+
if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
|
|
4072
4184
|
nextSibling = $createTextNode();
|
|
4073
4185
|
|
|
4074
4186
|
if (!firstNodeParent.canInsertTextAfter()) {
|
|
@@ -4088,7 +4200,7 @@ class RangeSelection {
|
|
|
4088
4200
|
} else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore())) {
|
|
4089
4201
|
let prevSibling = firstNode.getPreviousSibling();
|
|
4090
4202
|
|
|
4091
|
-
if (!$isTextNode(prevSibling) || $
|
|
4203
|
+
if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
|
|
4092
4204
|
prevSibling = $createTextNode();
|
|
4093
4205
|
|
|
4094
4206
|
if (!firstNodeParent.canInsertTextBefore()) {
|
|
@@ -4109,6 +4221,19 @@ class RangeSelection {
|
|
|
4109
4221
|
const textNode = $createTextNode(firstNode.getTextContent());
|
|
4110
4222
|
firstNode.replace(textNode);
|
|
4111
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
|
+
}
|
|
4112
4237
|
}
|
|
4113
4238
|
|
|
4114
4239
|
if (selectedNodesLength === 1) {
|
|
@@ -4157,8 +4282,6 @@ class RangeSelection {
|
|
|
4157
4282
|
this.anchor.offset -= text.length;
|
|
4158
4283
|
}
|
|
4159
4284
|
} else {
|
|
4160
|
-
const lastIndex = selectedNodesLength - 1;
|
|
4161
|
-
let lastNode = selectedNodes[lastIndex];
|
|
4162
4285
|
const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]);
|
|
4163
4286
|
const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
4164
4287
|
const lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow(); // Handle mutations to the last node.
|
|
@@ -4174,7 +4297,13 @@ class RangeSelection {
|
|
|
4174
4297
|
lastNode = lastNode.spliceText(0, endOffset, '');
|
|
4175
4298
|
markedNodeKeysForKeep.add(lastNode.__key);
|
|
4176
4299
|
} else {
|
|
4177
|
-
lastNode.
|
|
4300
|
+
const lastNodeParent = lastNode.getParentOrThrow();
|
|
4301
|
+
|
|
4302
|
+
if (!lastNodeParent.canBeEmpty() && lastNodeParent.getChildrenSize() === 1) {
|
|
4303
|
+
lastNodeParent.remove();
|
|
4304
|
+
} else {
|
|
4305
|
+
lastNode.remove();
|
|
4306
|
+
}
|
|
4178
4307
|
}
|
|
4179
4308
|
} else {
|
|
4180
4309
|
markedNodeKeysForKeep.add(lastNode.__key);
|
|
@@ -4283,10 +4412,9 @@ class RangeSelection {
|
|
|
4283
4412
|
|
|
4284
4413
|
const anchor = this.anchor;
|
|
4285
4414
|
const focus = this.focus;
|
|
4286
|
-
const firstNodeText = firstNode.getTextContent();
|
|
4287
|
-
const firstNodeTextLength = firstNodeText.length;
|
|
4288
4415
|
const focusOffset = focus.offset;
|
|
4289
4416
|
let firstNextFormat = 0;
|
|
4417
|
+
let firstNodeTextLength = firstNode.getTextContent().length;
|
|
4290
4418
|
|
|
4291
4419
|
for (let i = 0; i < selectedNodes.length; i++) {
|
|
4292
4420
|
const selectedNode = selectedNodes[i];
|
|
@@ -4313,6 +4441,7 @@ class RangeSelection {
|
|
|
4313
4441
|
anchorOffset = 0;
|
|
4314
4442
|
startOffset = 0;
|
|
4315
4443
|
firstNode = nextSibling;
|
|
4444
|
+
firstNodeTextLength = nextSibling.getTextContent().length;
|
|
4316
4445
|
firstNextFormat = firstNode.getFormatFlags(formatType, null);
|
|
4317
4446
|
}
|
|
4318
4447
|
} // This is the case where we only selected a single node
|
|
@@ -4812,6 +4941,10 @@ class RangeSelection {
|
|
|
4812
4941
|
}
|
|
4813
4942
|
}
|
|
4814
4943
|
|
|
4944
|
+
getCharacterOffsets() {
|
|
4945
|
+
return getCharacterOffsets(this);
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4815
4948
|
extract() {
|
|
4816
4949
|
const selectedNodes = this.getNodes();
|
|
4817
4950
|
const selectedNodesLength = selectedNodes.length;
|
|
@@ -4820,8 +4953,7 @@ class RangeSelection {
|
|
|
4820
4953
|
const focus = this.focus;
|
|
4821
4954
|
let firstNode = selectedNodes[0];
|
|
4822
4955
|
let lastNode = selectedNodes[lastIndex];
|
|
4823
|
-
const anchorOffset =
|
|
4824
|
-
const focusOffset = focus.getCharacterOffset();
|
|
4956
|
+
const [anchorOffset, focusOffset] = getCharacterOffsets(this);
|
|
4825
4957
|
|
|
4826
4958
|
if (selectedNodesLength === 0) {
|
|
4827
4959
|
return [];
|
|
@@ -4899,6 +5031,16 @@ class RangeSelection {
|
|
|
4899
5031
|
anchor.set(elementKey, offset, 'element');
|
|
4900
5032
|
}
|
|
4901
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
|
+
|
|
4902
5044
|
return;
|
|
4903
5045
|
}
|
|
4904
5046
|
}
|
|
@@ -5001,6 +5143,29 @@ function $isNodeSelection(x) {
|
|
|
5001
5143
|
return x instanceof NodeSelection;
|
|
5002
5144
|
}
|
|
5003
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
|
+
|
|
5004
5169
|
function $swapPoints(selection) {
|
|
5005
5170
|
const focus = selection.focus;
|
|
5006
5171
|
const anchor = selection.anchor;
|
|
@@ -5169,6 +5334,78 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
|
5169
5334
|
return $createPoint(resolvedNode.__key, resolvedOffset, 'text');
|
|
5170
5335
|
}
|
|
5171
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
|
+
|
|
5172
5409
|
function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {
|
|
5173
5410
|
if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
|
|
5174
5411
|
return null;
|
|
@@ -5184,48 +5421,10 @@ function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focus
|
|
|
5184
5421
|
|
|
5185
5422
|
if (resolvedFocusPoint === null) {
|
|
5186
5423
|
return null;
|
|
5187
|
-
}
|
|
5188
|
-
|
|
5189
|
-
if (resolvedAnchorPoint.type === 'text' && resolvedFocusPoint.type === 'text') {
|
|
5190
|
-
const resolvedAnchorNode = resolvedAnchorPoint.getNode();
|
|
5191
|
-
const resolvedFocusNode = resolvedFocusPoint.getNode(); // Handle normalization of selection when it is at the boundaries.
|
|
5192
|
-
|
|
5193
|
-
const textContentSize = resolvedAnchorNode.getTextContentSize();
|
|
5194
|
-
const resolvedAnchorOffset = resolvedAnchorPoint.offset;
|
|
5195
|
-
const resolvedFocusOffset = resolvedFocusPoint.offset;
|
|
5196
|
-
|
|
5197
|
-
if (resolvedAnchorNode === resolvedFocusNode && resolvedAnchorOffset === resolvedFocusOffset) {
|
|
5198
|
-
if (anchorOffset === 0) {
|
|
5199
|
-
const prevSibling = resolvedAnchorNode.getPreviousSibling();
|
|
5200
|
-
|
|
5201
|
-
if ($isTextNode(prevSibling) && !prevSibling.isInert()) {
|
|
5202
|
-
const offset = prevSibling.getTextContentSize();
|
|
5203
|
-
const key = prevSibling.__key;
|
|
5204
|
-
resolvedAnchorPoint.key = key;
|
|
5205
|
-
resolvedFocusPoint.key = key;
|
|
5206
|
-
resolvedAnchorPoint.offset = offset;
|
|
5207
|
-
resolvedFocusPoint.offset = offset;
|
|
5208
|
-
}
|
|
5209
|
-
}
|
|
5210
|
-
} else {
|
|
5211
|
-
if (resolvedAnchorOffset === textContentSize) {
|
|
5212
|
-
const nextSibling = resolvedAnchorNode.getNextSibling();
|
|
5424
|
+
} // Handle normalization of selection when it is at the boundaries.
|
|
5213
5425
|
|
|
5214
|
-
if ($isTextNode(nextSibling) && !nextSibling.isInert()) {
|
|
5215
|
-
resolvedAnchorPoint.key = nextSibling.__key;
|
|
5216
|
-
resolvedAnchorPoint.offset = 0;
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5219
|
-
}
|
|
5220
|
-
|
|
5221
|
-
if (editor.isComposing() && editor._compositionKey !== resolvedAnchorPoint.key && $isRangeSelection(lastSelection)) {
|
|
5222
|
-
const lastAnchor = lastSelection.anchor;
|
|
5223
|
-
const lastFocus = lastSelection.focus;
|
|
5224
|
-
$setPointValues(resolvedAnchorPoint, lastAnchor.key, lastAnchor.offset, lastAnchor.type);
|
|
5225
|
-
$setPointValues(resolvedFocusPoint, lastFocus.key, lastFocus.offset, lastFocus.type);
|
|
5226
|
-
}
|
|
5227
|
-
}
|
|
5228
5426
|
|
|
5427
|
+
normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint, lastSelection);
|
|
5229
5428
|
return [resolvedAnchorPoint, resolvedFocusPoint];
|
|
5230
5429
|
} // This is used to make a selection when the existing
|
|
5231
5430
|
// selection is null, i.e. forcing selection on the editor
|
|
@@ -5248,7 +5447,9 @@ function $createEmptyObjectSelection() {
|
|
|
5248
5447
|
return new NodeSelection(new Set());
|
|
5249
5448
|
}
|
|
5250
5449
|
function $createEmptyGridSelection() {
|
|
5251
|
-
|
|
5450
|
+
const anchor = $createPoint('root', 0, 'element');
|
|
5451
|
+
const focus = $createPoint('root', 0, 'element');
|
|
5452
|
+
return new GridSelection('root', anchor, focus);
|
|
5252
5453
|
}
|
|
5253
5454
|
|
|
5254
5455
|
function getActiveEventType() {
|
|
@@ -5327,7 +5528,7 @@ function internalCreateSelectionFromParse(parsedSelection) {
|
|
|
5327
5528
|
} else if (parsedSelection.type === 'node') {
|
|
5328
5529
|
return new NodeSelection(new Set(parsedSelection.nodes));
|
|
5329
5530
|
} else if (parsedSelection.type === 'grid') {
|
|
5330
|
-
return new GridSelection(parsedSelection.gridKey, parsedSelection.
|
|
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));
|
|
5331
5532
|
}
|
|
5332
5533
|
}
|
|
5333
5534
|
|
|
@@ -6071,10 +6272,12 @@ class LexicalNode {
|
|
|
6071
6272
|
mutableNode.__format = latestNode.__format;
|
|
6072
6273
|
mutableNode.__dir = latestNode.__dir;
|
|
6073
6274
|
} else if ($isTextNode(latestNode) && $isTextNode(mutableNode)) {
|
|
6275
|
+
const marks = latestNode.__marks;
|
|
6074
6276
|
mutableNode.__format = latestNode.__format;
|
|
6075
6277
|
mutableNode.__style = latestNode.__style;
|
|
6076
6278
|
mutableNode.__mode = latestNode.__mode;
|
|
6077
6279
|
mutableNode.__detail = latestNode.__detail;
|
|
6280
|
+
mutableNode.__marks = marks === null ? marks : Array.from(marks);
|
|
6078
6281
|
}
|
|
6079
6282
|
|
|
6080
6283
|
cloneNotNeeded.add(key);
|
|
@@ -6095,23 +6298,20 @@ class LexicalNode {
|
|
|
6095
6298
|
getTextContentSize(includeInert, includeDirectionless) {
|
|
6096
6299
|
return this.getTextContent(includeInert, includeDirectionless).length;
|
|
6097
6300
|
} // View
|
|
6098
|
-
// $FlowFixMe: Revise typings for EditorContext
|
|
6099
6301
|
|
|
6100
6302
|
|
|
6101
6303
|
createDOM(config, editor) {
|
|
6102
6304
|
{
|
|
6103
6305
|
throw Error(`createDOM: base method not extended`);
|
|
6104
6306
|
}
|
|
6105
|
-
}
|
|
6106
|
-
|
|
6307
|
+
}
|
|
6107
6308
|
|
|
6108
6309
|
updateDOM( // $FlowFixMe: TODO
|
|
6109
6310
|
prevNode, dom, config) {
|
|
6110
6311
|
{
|
|
6111
6312
|
throw Error(`updateDOM: base method not extended`);
|
|
6112
6313
|
}
|
|
6113
|
-
}
|
|
6114
|
-
|
|
6314
|
+
}
|
|
6115
6315
|
|
|
6116
6316
|
exportDOM(editor) {
|
|
6117
6317
|
if ($isDecoratorNode(this)) {
|
|
@@ -6428,6 +6628,12 @@ class ElementNode extends LexicalNode {
|
|
|
6428
6628
|
return dirtyElements !== null && dirtyElements.has(this.__key);
|
|
6429
6629
|
}
|
|
6430
6630
|
|
|
6631
|
+
isLastChild() {
|
|
6632
|
+
const self = this.getLatest();
|
|
6633
|
+
const parent = self.getParentOrThrow();
|
|
6634
|
+
return parent.getLastChild() === self;
|
|
6635
|
+
}
|
|
6636
|
+
|
|
6431
6637
|
getAllTextNodes(includeInert) {
|
|
6432
6638
|
const textNodes = [];
|
|
6433
6639
|
const self = this.getLatest();
|
|
@@ -6562,7 +6768,7 @@ class ElementNode extends LexicalNode {
|
|
|
6562
6768
|
textContent += child.getTextContent(includeInert, includeDirectionless);
|
|
6563
6769
|
|
|
6564
6770
|
if ($isElementNode(child) && i !== childrenLength - 1 && !child.isInline()) {
|
|
6565
|
-
textContent +=
|
|
6771
|
+
textContent += DOUBLE_LINE_BREAK;
|
|
6566
6772
|
}
|
|
6567
6773
|
}
|
|
6568
6774
|
|
|
@@ -6791,6 +6997,10 @@ class ElementNode extends LexicalNode {
|
|
|
6791
6997
|
return false;
|
|
6792
6998
|
}
|
|
6793
6999
|
|
|
7000
|
+
canIndent() {
|
|
7001
|
+
return true;
|
|
7002
|
+
}
|
|
7003
|
+
|
|
6794
7004
|
collapseAtStart(selection) {
|
|
6795
7005
|
return false;
|
|
6796
7006
|
}
|
|
@@ -7011,8 +7221,16 @@ class EditorState {
|
|
|
7011
7221
|
nodes: Array.from(selection._nodes),
|
|
7012
7222
|
type: 'node'
|
|
7013
7223
|
} : $isGridSelection(selection) ? {
|
|
7014
|
-
|
|
7015
|
-
|
|
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
|
+
},
|
|
7016
7234
|
gridKey: selection.gridKey,
|
|
7017
7235
|
type: 'grid'
|
|
7018
7236
|
} : null
|
|
@@ -7078,6 +7296,44 @@ function $isLineBreakNode(node) {
|
|
|
7078
7296
|
return node instanceof LineBreakNode;
|
|
7079
7297
|
}
|
|
7080
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
|
+
|
|
7081
7337
|
/**
|
|
7082
7338
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
7083
7339
|
*
|
|
@@ -7226,6 +7482,42 @@ function createTextInnerDOM(innerDOM, node, innerTag, format, text, config) {
|
|
|
7226
7482
|
}
|
|
7227
7483
|
}
|
|
7228
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
|
+
|
|
7229
7521
|
class TextNode extends LexicalNode {
|
|
7230
7522
|
static getType() {
|
|
7231
7523
|
return 'text';
|
|
@@ -7242,6 +7534,7 @@ class TextNode extends LexicalNode {
|
|
|
7242
7534
|
this.__style = '';
|
|
7243
7535
|
this.__mode = 0;
|
|
7244
7536
|
this.__detail = 0;
|
|
7537
|
+
this.__marks = null;
|
|
7245
7538
|
}
|
|
7246
7539
|
|
|
7247
7540
|
getFormat() {
|
|
@@ -7249,6 +7542,23 @@ class TextNode extends LexicalNode {
|
|
|
7249
7542
|
return self.__format;
|
|
7250
7543
|
}
|
|
7251
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
|
+
|
|
7252
7562
|
getStyle() {
|
|
7253
7563
|
const self = this.getLatest();
|
|
7254
7564
|
return self.__style;
|
|
@@ -7302,7 +7612,6 @@ class TextNode extends LexicalNode {
|
|
|
7302
7612
|
const format = self.__format;
|
|
7303
7613
|
return toggleTextFormatType(format, type, alignWithFormat);
|
|
7304
7614
|
} // View
|
|
7305
|
-
// $FlowFixMe: Revise typings for EditorContext
|
|
7306
7615
|
|
|
7307
7616
|
|
|
7308
7617
|
createDOM(config) {
|
|
@@ -7327,8 +7636,7 @@ class TextNode extends LexicalNode {
|
|
|
7327
7636
|
}
|
|
7328
7637
|
|
|
7329
7638
|
return dom;
|
|
7330
|
-
}
|
|
7331
|
-
|
|
7639
|
+
}
|
|
7332
7640
|
|
|
7333
7641
|
updateDOM(prevNode, dom, config) {
|
|
7334
7642
|
const nextText = this.__text;
|
|
@@ -7464,6 +7772,64 @@ class TextNode extends LexicalNode {
|
|
|
7464
7772
|
return self;
|
|
7465
7773
|
}
|
|
7466
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
|
+
|
|
7467
7833
|
setMode(type) {
|
|
7468
7834
|
errorOnReadOnly();
|
|
7469
7835
|
const mode = TEXT_MODE_TO_TYPE[type];
|
|
@@ -7475,7 +7841,26 @@ class TextNode extends LexicalNode {
|
|
|
7475
7841
|
setTextContent(text) {
|
|
7476
7842
|
errorOnReadOnly();
|
|
7477
7843
|
const writableSelf = this.getWritable();
|
|
7478
|
-
|
|
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
|
+
|
|
7479
7864
|
return writableSelf;
|
|
7480
7865
|
}
|
|
7481
7866
|
|
|
@@ -7540,7 +7925,14 @@ class TextNode extends LexicalNode {
|
|
|
7540
7925
|
}
|
|
7541
7926
|
|
|
7542
7927
|
const updatedText = text.slice(0, index) + newText + text.slice(index + delCount);
|
|
7543
|
-
|
|
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;
|
|
7544
7936
|
}
|
|
7545
7937
|
|
|
7546
7938
|
canInsertTextBefore() {
|
|
@@ -7590,6 +7982,7 @@ class TextNode extends LexicalNode {
|
|
|
7590
7982
|
const format = self.getFormat();
|
|
7591
7983
|
const style = self.getStyle();
|
|
7592
7984
|
const detail = self.__detail;
|
|
7985
|
+
const marks = self.__marks;
|
|
7593
7986
|
let hasReplacedSelf = false;
|
|
7594
7987
|
|
|
7595
7988
|
if (self.isSegmented()) {
|
|
@@ -7599,6 +7992,7 @@ class TextNode extends LexicalNode {
|
|
|
7599
7992
|
writableNode.__format = format;
|
|
7600
7993
|
writableNode.__style = style;
|
|
7601
7994
|
writableNode.__detail = detail;
|
|
7995
|
+
writableNode.__marks = marks;
|
|
7602
7996
|
hasReplacedSelf = true;
|
|
7603
7997
|
} else {
|
|
7604
7998
|
// For the first part, update the existing node
|
|
@@ -7646,6 +8040,46 @@ class TextNode extends LexicalNode {
|
|
|
7646
8040
|
textSize = nextTextSize;
|
|
7647
8041
|
sibling.__parent = parentKey;
|
|
7648
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
|
+
}
|
|
7649
8083
|
} // Insert the nodes into the parent's children
|
|
7650
8084
|
|
|
7651
8085
|
|
|
@@ -7705,10 +8139,20 @@ class TextNode extends LexicalNode {
|
|
|
7705
8139
|
}
|
|
7706
8140
|
}
|
|
7707
8141
|
|
|
7708
|
-
const
|
|
8142
|
+
const targetText = target.__text;
|
|
8143
|
+
const targetTextLength = targetText.length;
|
|
8144
|
+
const newText = isBefore ? targetText + text : text + targetText;
|
|
7709
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
|
+
|
|
7710
8154
|
target.remove();
|
|
7711
|
-
return
|
|
8155
|
+
return writableSelf;
|
|
7712
8156
|
}
|
|
7713
8157
|
|
|
7714
8158
|
isTextEntity() {
|
|
@@ -7982,7 +8426,6 @@ function createEditor(editorConfig) {
|
|
|
7982
8426
|
const config = editorConfig || {};
|
|
7983
8427
|
const namespace = config.namespace || createUID();
|
|
7984
8428
|
const theme = config.theme || {};
|
|
7985
|
-
const context = config.context || {};
|
|
7986
8429
|
const parentEditor = config.parentEditor || null;
|
|
7987
8430
|
const disableEvents = config.disableEvents || false;
|
|
7988
8431
|
const editorState = createEmptyEditorState();
|
|
@@ -8004,8 +8447,6 @@ function createEditor(editorConfig) {
|
|
|
8004
8447
|
|
|
8005
8448
|
|
|
8006
8449
|
const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {
|
|
8007
|
-
// $FlowFixMe: we use our internal type to simpify the generics
|
|
8008
|
-
context,
|
|
8009
8450
|
disableEvents,
|
|
8010
8451
|
namespace,
|
|
8011
8452
|
theme
|
|
@@ -8364,7 +8805,7 @@ class LexicalEditor {
|
|
|
8364
8805
|
*
|
|
8365
8806
|
*
|
|
8366
8807
|
*/
|
|
8367
|
-
const VERSION = '0.2.
|
|
8808
|
+
const VERSION = '0.2.5';
|
|
8368
8809
|
|
|
8369
8810
|
/**
|
|
8370
8811
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -8455,6 +8896,7 @@ exports.CUT_COMMAND = CUT_COMMAND;
|
|
|
8455
8896
|
exports.DELETE_CHARACTER_COMMAND = DELETE_CHARACTER_COMMAND;
|
|
8456
8897
|
exports.DELETE_LINE_COMMAND = DELETE_LINE_COMMAND;
|
|
8457
8898
|
exports.DELETE_WORD_COMMAND = DELETE_WORD_COMMAND;
|
|
8899
|
+
exports.DRAGEND_COMMAND = DRAGEND_COMMAND;
|
|
8458
8900
|
exports.DRAGSTART_COMMAND = DRAGSTART_COMMAND;
|
|
8459
8901
|
exports.DROP_COMMAND = DROP_COMMAND;
|
|
8460
8902
|
exports.DecoratorNode = DecoratorNode;
|