lexical 0.33.2-nightly.20250724.0 → 0.33.2-nightly.20250728.0
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 +38 -20
- package/Lexical.dev.mjs +38 -20
- package/Lexical.prod.js +1 -1
- package/Lexical.prod.mjs +1 -1
- package/LexicalUtils.d.ts +0 -1
- package/caret/LexicalCaret.d.ts +2 -1
- package/package.json +1 -1
package/Lexical.dev.js
CHANGED
|
@@ -369,7 +369,11 @@ function flushMutations(editor, mutations, observer) {
|
|
|
369
369
|
if (type === 'characterData') {
|
|
370
370
|
// Text mutations are deferred and passed to mutation listeners to be
|
|
371
371
|
// processed outside of the Lexical engine.
|
|
372
|
-
if (
|
|
372
|
+
if (
|
|
373
|
+
// TODO there is an edge case here if a mutation happens too quickly
|
|
374
|
+
// after text input, it may never be handled since we do not
|
|
375
|
+
// track the ignored mutations in any way
|
|
376
|
+
shouldFlushTextMutations && $isTextNode(targetNode) && isDOMTextNode(targetDOM) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)) {
|
|
373
377
|
$handleTextMutation(targetDOM, targetNode, editor);
|
|
374
378
|
}
|
|
375
379
|
} else if (type === 'childList') {
|
|
@@ -7196,7 +7200,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7196
7200
|
}
|
|
7197
7201
|
resolvedNode = $getNodeFromDOM(childDOM);
|
|
7198
7202
|
if ($isTextNode(resolvedNode)) {
|
|
7199
|
-
resolvedOffset = getTextNodeOffset(resolvedNode, moveSelectionToEnd);
|
|
7203
|
+
resolvedOffset = $getTextNodeOffset(resolvedNode, moveSelectionToEnd ? 'next' : 'previous');
|
|
7200
7204
|
} else {
|
|
7201
7205
|
let resolvedElement = $getNodeFromDOM(dom);
|
|
7202
7206
|
// Ensure resolvedElement is actually a element.
|
|
@@ -7231,7 +7235,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7231
7235
|
if ($isTextNode(child)) {
|
|
7232
7236
|
resolvedNode = child;
|
|
7233
7237
|
resolvedElement = null;
|
|
7234
|
-
resolvedOffset = getTextNodeOffset(child, moveSelectionToEnd);
|
|
7238
|
+
resolvedOffset = $getTextNodeOffset(child, moveSelectionToEnd ? 'next' : 'previous');
|
|
7235
7239
|
} else if (child !== resolvedElement && moveSelectionToEnd && !hasBlockCursor) {
|
|
7236
7240
|
if (!$isElementNode(resolvedElement)) {
|
|
7237
7241
|
formatDevErrorMessage(`invariant`);
|
|
@@ -7260,7 +7264,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7260
7264
|
if (!$isTextNode(resolvedNode)) {
|
|
7261
7265
|
return null;
|
|
7262
7266
|
}
|
|
7263
|
-
return $createPoint(resolvedNode.__key, resolvedOffset, 'text');
|
|
7267
|
+
return $createPoint(resolvedNode.__key, $getTextNodeOffset(resolvedNode, resolvedOffset, 'clamp'), 'text');
|
|
7264
7268
|
}
|
|
7265
7269
|
function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {
|
|
7266
7270
|
const offset = point.offset;
|
|
@@ -7327,8 +7331,8 @@ function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focu
|
|
|
7327
7331
|
return null;
|
|
7328
7332
|
}
|
|
7329
7333
|
{
|
|
7330
|
-
$validatePoint(
|
|
7331
|
-
$validatePoint(
|
|
7334
|
+
$validatePoint('anchor', resolvedAnchorPoint);
|
|
7335
|
+
$validatePoint('focus', resolvedFocusPoint);
|
|
7332
7336
|
}
|
|
7333
7337
|
if (resolvedAnchorPoint.type === 'element' && resolvedFocusPoint.type === 'element') {
|
|
7334
7338
|
const anchorNode = $getNodeFromDOM(anchorDOM);
|
|
@@ -7427,7 +7431,7 @@ function $internalCreateRangeSelection(lastSelection, domSelection, editor, even
|
|
|
7427
7431
|
const [resolvedAnchorPoint, resolvedFocusPoint] = resolvedSelectionPoints;
|
|
7428
7432
|
return new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, !$isRangeSelection(lastSelection) ? 0 : lastSelection.format, !$isRangeSelection(lastSelection) ? '' : lastSelection.style);
|
|
7429
7433
|
}
|
|
7430
|
-
function $validatePoint(
|
|
7434
|
+
function $validatePoint(name, point) {
|
|
7431
7435
|
const node = $getNodeByKey(point.key);
|
|
7432
7436
|
if (!(node !== undefined)) {
|
|
7433
7437
|
formatDevErrorMessage(`$validatePoint: ${name} key ${point.key} not found in current editorState`);
|
|
@@ -8507,7 +8511,7 @@ function triggerDeferredUpdateCallbacks(editor, deferred) {
|
|
|
8507
8511
|
}
|
|
8508
8512
|
}
|
|
8509
8513
|
}
|
|
8510
|
-
function processNestedUpdates(editor, initialSkipTransforms) {
|
|
8514
|
+
function $processNestedUpdates(editor, initialSkipTransforms) {
|
|
8511
8515
|
const queuedUpdates = editor._updates;
|
|
8512
8516
|
let skipTransforms = initialSkipTransforms || false;
|
|
8513
8517
|
|
|
@@ -8518,6 +8522,7 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8518
8522
|
const queuedUpdate = queuedUpdates.shift();
|
|
8519
8523
|
if (queuedUpdate) {
|
|
8520
8524
|
const [nextUpdateFn, options] = queuedUpdate;
|
|
8525
|
+
const pendingEditorState = editor._pendingEditorState;
|
|
8521
8526
|
let onUpdate;
|
|
8522
8527
|
if (options !== undefined) {
|
|
8523
8528
|
onUpdate = options.onUpdate;
|
|
@@ -8525,7 +8530,6 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8525
8530
|
skipTransforms = true;
|
|
8526
8531
|
}
|
|
8527
8532
|
if (options.discrete) {
|
|
8528
|
-
const pendingEditorState = editor._pendingEditorState;
|
|
8529
8533
|
if (!(pendingEditorState !== null)) {
|
|
8530
8534
|
formatDevErrorMessage(`Unexpected empty pending editor state on discrete nested update`);
|
|
8531
8535
|
}
|
|
@@ -8536,7 +8540,11 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8536
8540
|
}
|
|
8537
8541
|
addTags(editor, options.tag);
|
|
8538
8542
|
}
|
|
8539
|
-
|
|
8543
|
+
if (pendingEditorState == null) {
|
|
8544
|
+
$beginUpdate(editor, nextUpdateFn, options);
|
|
8545
|
+
} else {
|
|
8546
|
+
nextUpdateFn();
|
|
8547
|
+
}
|
|
8540
8548
|
}
|
|
8541
8549
|
}
|
|
8542
8550
|
return skipTransforms;
|
|
@@ -8585,7 +8593,7 @@ function $beginUpdate(editor, updateFn, options) {
|
|
|
8585
8593
|
}
|
|
8586
8594
|
const startingCompositionKey = editor._compositionKey;
|
|
8587
8595
|
updateFn();
|
|
8588
|
-
skipTransforms = processNestedUpdates(editor, skipTransforms);
|
|
8596
|
+
skipTransforms = $processNestedUpdates(editor, skipTransforms);
|
|
8589
8597
|
applySelectionTransforms(pendingEditorState, editor);
|
|
8590
8598
|
if (editor._dirtyType !== NO_DIRTY_NODES) {
|
|
8591
8599
|
if (skipTransforms) {
|
|
@@ -8593,7 +8601,7 @@ function $beginUpdate(editor, updateFn, options) {
|
|
|
8593
8601
|
} else {
|
|
8594
8602
|
$applyAllTransforms(pendingEditorState, editor);
|
|
8595
8603
|
}
|
|
8596
|
-
processNestedUpdates(editor);
|
|
8604
|
+
$processNestedUpdates(editor);
|
|
8597
8605
|
$garbageCollectDetachedNodes(currentEditorState, pendingEditorState, editor._dirtyLeaves, editor._dirtyElements);
|
|
8598
8606
|
}
|
|
8599
8607
|
const endingCompositionKey = editor._compositionKey;
|
|
@@ -10763,7 +10771,7 @@ class LexicalEditor {
|
|
|
10763
10771
|
};
|
|
10764
10772
|
}
|
|
10765
10773
|
}
|
|
10766
|
-
LexicalEditor.version = "0.33.2-nightly.
|
|
10774
|
+
LexicalEditor.version = "0.33.2-nightly.20250728.0+dev.cjs";
|
|
10767
10775
|
|
|
10768
10776
|
let pendingNodeToClone = null;
|
|
10769
10777
|
function setPendingNodeToClone(pendingNode) {
|
|
@@ -11213,9 +11221,6 @@ function $getNodeFromDOM(dom) {
|
|
|
11213
11221
|
}
|
|
11214
11222
|
return $getNodeByKey(nodeKey);
|
|
11215
11223
|
}
|
|
11216
|
-
function getTextNodeOffset(node, moveSelectionToEnd) {
|
|
11217
|
-
return moveSelectionToEnd ? node.getTextContentSize() : 0;
|
|
11218
|
-
}
|
|
11219
11224
|
function getNodeKeyFromDOMTree(
|
|
11220
11225
|
// Note that node here refers to a DOM Node, not an Lexical Node
|
|
11221
11226
|
dom, editor) {
|
|
@@ -11323,7 +11328,7 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
11323
11328
|
}
|
|
11324
11329
|
const selection = $getSelection();
|
|
11325
11330
|
if (!$isRangeSelection(selection) || anchorOffset === null || focusOffset === null) {
|
|
11326
|
-
node
|
|
11331
|
+
$setTextContentWithSelection(node, normalizedTextContent, selection);
|
|
11327
11332
|
return;
|
|
11328
11333
|
}
|
|
11329
11334
|
selection.setTextNodeRange(node, anchorOffset, node, focusOffset);
|
|
@@ -11333,7 +11338,19 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
11333
11338
|
node.replace(replacement);
|
|
11334
11339
|
node = replacement;
|
|
11335
11340
|
}
|
|
11336
|
-
node
|
|
11341
|
+
$setTextContentWithSelection(node, normalizedTextContent, selection);
|
|
11342
|
+
}
|
|
11343
|
+
}
|
|
11344
|
+
}
|
|
11345
|
+
function $setTextContentWithSelection(node, textContent, selection) {
|
|
11346
|
+
node.setTextContent(textContent);
|
|
11347
|
+
if ($isRangeSelection(selection)) {
|
|
11348
|
+
const key = node.getKey();
|
|
11349
|
+
for (const k of ['anchor', 'focus']) {
|
|
11350
|
+
const pt = selection[k];
|
|
11351
|
+
if (pt.type === 'text' && pt.key === key) {
|
|
11352
|
+
pt.offset = $getTextNodeOffset(node, pt.offset, 'clamp');
|
|
11353
|
+
}
|
|
11337
11354
|
}
|
|
11338
11355
|
}
|
|
11339
11356
|
}
|
|
@@ -12762,13 +12779,14 @@ function $getTextPointCaret(origin, direction, offset) {
|
|
|
12762
12779
|
*
|
|
12763
12780
|
* @param origin a TextNode
|
|
12764
12781
|
* @param offset An absolute offset into the TextNode string, or a direction for which end to use as the offset
|
|
12782
|
+
* @param mode If 'error' (the default) out of bounds offsets will be an error in dev. Otherwise it will clamp to a valid offset.
|
|
12765
12783
|
* @returns An absolute offset into the TextNode string
|
|
12766
12784
|
*/
|
|
12767
|
-
function $getTextNodeOffset(origin, offset) {
|
|
12785
|
+
function $getTextNodeOffset(origin, offset, mode = 'error') {
|
|
12768
12786
|
const size = origin.getTextContentSize();
|
|
12769
12787
|
let numericOffset = offset === 'next' ? size : offset === 'previous' ? 0 : offset;
|
|
12770
12788
|
if (numericOffset < 0 || numericOffset > size) {
|
|
12771
|
-
{
|
|
12789
|
+
if (!(mode === 'clamp')) {
|
|
12772
12790
|
formatDevErrorMessage(`$getTextNodeOffset: invalid offset ${String(offset)} for size ${String(size)} at key ${origin.getKey()}`);
|
|
12773
12791
|
} // Clamp invalid offsets in prod
|
|
12774
12792
|
numericOffset = numericOffset < 0 ? 0 : size;
|
package/Lexical.dev.mjs
CHANGED
|
@@ -367,7 +367,11 @@ function flushMutations(editor, mutations, observer) {
|
|
|
367
367
|
if (type === 'characterData') {
|
|
368
368
|
// Text mutations are deferred and passed to mutation listeners to be
|
|
369
369
|
// processed outside of the Lexical engine.
|
|
370
|
-
if (
|
|
370
|
+
if (
|
|
371
|
+
// TODO there is an edge case here if a mutation happens too quickly
|
|
372
|
+
// after text input, it may never be handled since we do not
|
|
373
|
+
// track the ignored mutations in any way
|
|
374
|
+
shouldFlushTextMutations && $isTextNode(targetNode) && isDOMTextNode(targetDOM) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode)) {
|
|
371
375
|
$handleTextMutation(targetDOM, targetNode, editor);
|
|
372
376
|
}
|
|
373
377
|
} else if (type === 'childList') {
|
|
@@ -7194,7 +7198,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7194
7198
|
}
|
|
7195
7199
|
resolvedNode = $getNodeFromDOM(childDOM);
|
|
7196
7200
|
if ($isTextNode(resolvedNode)) {
|
|
7197
|
-
resolvedOffset = getTextNodeOffset(resolvedNode, moveSelectionToEnd);
|
|
7201
|
+
resolvedOffset = $getTextNodeOffset(resolvedNode, moveSelectionToEnd ? 'next' : 'previous');
|
|
7198
7202
|
} else {
|
|
7199
7203
|
let resolvedElement = $getNodeFromDOM(dom);
|
|
7200
7204
|
// Ensure resolvedElement is actually a element.
|
|
@@ -7229,7 +7233,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7229
7233
|
if ($isTextNode(child)) {
|
|
7230
7234
|
resolvedNode = child;
|
|
7231
7235
|
resolvedElement = null;
|
|
7232
|
-
resolvedOffset = getTextNodeOffset(child, moveSelectionToEnd);
|
|
7236
|
+
resolvedOffset = $getTextNodeOffset(child, moveSelectionToEnd ? 'next' : 'previous');
|
|
7233
7237
|
} else if (child !== resolvedElement && moveSelectionToEnd && !hasBlockCursor) {
|
|
7234
7238
|
if (!$isElementNode(resolvedElement)) {
|
|
7235
7239
|
formatDevErrorMessage(`invariant`);
|
|
@@ -7258,7 +7262,7 @@ function $internalResolveSelectionPoint(dom, offset, lastPoint, editor) {
|
|
|
7258
7262
|
if (!$isTextNode(resolvedNode)) {
|
|
7259
7263
|
return null;
|
|
7260
7264
|
}
|
|
7261
|
-
return $createPoint(resolvedNode.__key, resolvedOffset, 'text');
|
|
7265
|
+
return $createPoint(resolvedNode.__key, $getTextNodeOffset(resolvedNode, resolvedOffset, 'clamp'), 'text');
|
|
7262
7266
|
}
|
|
7263
7267
|
function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {
|
|
7264
7268
|
const offset = point.offset;
|
|
@@ -7325,8 +7329,8 @@ function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focu
|
|
|
7325
7329
|
return null;
|
|
7326
7330
|
}
|
|
7327
7331
|
{
|
|
7328
|
-
$validatePoint(
|
|
7329
|
-
$validatePoint(
|
|
7332
|
+
$validatePoint('anchor', resolvedAnchorPoint);
|
|
7333
|
+
$validatePoint('focus', resolvedFocusPoint);
|
|
7330
7334
|
}
|
|
7331
7335
|
if (resolvedAnchorPoint.type === 'element' && resolvedFocusPoint.type === 'element') {
|
|
7332
7336
|
const anchorNode = $getNodeFromDOM(anchorDOM);
|
|
@@ -7425,7 +7429,7 @@ function $internalCreateRangeSelection(lastSelection, domSelection, editor, even
|
|
|
7425
7429
|
const [resolvedAnchorPoint, resolvedFocusPoint] = resolvedSelectionPoints;
|
|
7426
7430
|
return new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, !$isRangeSelection(lastSelection) ? 0 : lastSelection.format, !$isRangeSelection(lastSelection) ? '' : lastSelection.style);
|
|
7427
7431
|
}
|
|
7428
|
-
function $validatePoint(
|
|
7432
|
+
function $validatePoint(name, point) {
|
|
7429
7433
|
const node = $getNodeByKey(point.key);
|
|
7430
7434
|
if (!(node !== undefined)) {
|
|
7431
7435
|
formatDevErrorMessage(`$validatePoint: ${name} key ${point.key} not found in current editorState`);
|
|
@@ -8505,7 +8509,7 @@ function triggerDeferredUpdateCallbacks(editor, deferred) {
|
|
|
8505
8509
|
}
|
|
8506
8510
|
}
|
|
8507
8511
|
}
|
|
8508
|
-
function processNestedUpdates(editor, initialSkipTransforms) {
|
|
8512
|
+
function $processNestedUpdates(editor, initialSkipTransforms) {
|
|
8509
8513
|
const queuedUpdates = editor._updates;
|
|
8510
8514
|
let skipTransforms = initialSkipTransforms || false;
|
|
8511
8515
|
|
|
@@ -8516,6 +8520,7 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8516
8520
|
const queuedUpdate = queuedUpdates.shift();
|
|
8517
8521
|
if (queuedUpdate) {
|
|
8518
8522
|
const [nextUpdateFn, options] = queuedUpdate;
|
|
8523
|
+
const pendingEditorState = editor._pendingEditorState;
|
|
8519
8524
|
let onUpdate;
|
|
8520
8525
|
if (options !== undefined) {
|
|
8521
8526
|
onUpdate = options.onUpdate;
|
|
@@ -8523,7 +8528,6 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8523
8528
|
skipTransforms = true;
|
|
8524
8529
|
}
|
|
8525
8530
|
if (options.discrete) {
|
|
8526
|
-
const pendingEditorState = editor._pendingEditorState;
|
|
8527
8531
|
if (!(pendingEditorState !== null)) {
|
|
8528
8532
|
formatDevErrorMessage(`Unexpected empty pending editor state on discrete nested update`);
|
|
8529
8533
|
}
|
|
@@ -8534,7 +8538,11 @@ function processNestedUpdates(editor, initialSkipTransforms) {
|
|
|
8534
8538
|
}
|
|
8535
8539
|
addTags(editor, options.tag);
|
|
8536
8540
|
}
|
|
8537
|
-
|
|
8541
|
+
if (pendingEditorState == null) {
|
|
8542
|
+
$beginUpdate(editor, nextUpdateFn, options);
|
|
8543
|
+
} else {
|
|
8544
|
+
nextUpdateFn();
|
|
8545
|
+
}
|
|
8538
8546
|
}
|
|
8539
8547
|
}
|
|
8540
8548
|
return skipTransforms;
|
|
@@ -8583,7 +8591,7 @@ function $beginUpdate(editor, updateFn, options) {
|
|
|
8583
8591
|
}
|
|
8584
8592
|
const startingCompositionKey = editor._compositionKey;
|
|
8585
8593
|
updateFn();
|
|
8586
|
-
skipTransforms = processNestedUpdates(editor, skipTransforms);
|
|
8594
|
+
skipTransforms = $processNestedUpdates(editor, skipTransforms);
|
|
8587
8595
|
applySelectionTransforms(pendingEditorState, editor);
|
|
8588
8596
|
if (editor._dirtyType !== NO_DIRTY_NODES) {
|
|
8589
8597
|
if (skipTransforms) {
|
|
@@ -8591,7 +8599,7 @@ function $beginUpdate(editor, updateFn, options) {
|
|
|
8591
8599
|
} else {
|
|
8592
8600
|
$applyAllTransforms(pendingEditorState, editor);
|
|
8593
8601
|
}
|
|
8594
|
-
processNestedUpdates(editor);
|
|
8602
|
+
$processNestedUpdates(editor);
|
|
8595
8603
|
$garbageCollectDetachedNodes(currentEditorState, pendingEditorState, editor._dirtyLeaves, editor._dirtyElements);
|
|
8596
8604
|
}
|
|
8597
8605
|
const endingCompositionKey = editor._compositionKey;
|
|
@@ -10761,7 +10769,7 @@ class LexicalEditor {
|
|
|
10761
10769
|
};
|
|
10762
10770
|
}
|
|
10763
10771
|
}
|
|
10764
|
-
LexicalEditor.version = "0.33.2-nightly.
|
|
10772
|
+
LexicalEditor.version = "0.33.2-nightly.20250728.0+dev.esm";
|
|
10765
10773
|
|
|
10766
10774
|
let pendingNodeToClone = null;
|
|
10767
10775
|
function setPendingNodeToClone(pendingNode) {
|
|
@@ -11211,9 +11219,6 @@ function $getNodeFromDOM(dom) {
|
|
|
11211
11219
|
}
|
|
11212
11220
|
return $getNodeByKey(nodeKey);
|
|
11213
11221
|
}
|
|
11214
|
-
function getTextNodeOffset(node, moveSelectionToEnd) {
|
|
11215
|
-
return moveSelectionToEnd ? node.getTextContentSize() : 0;
|
|
11216
|
-
}
|
|
11217
11222
|
function getNodeKeyFromDOMTree(
|
|
11218
11223
|
// Note that node here refers to a DOM Node, not an Lexical Node
|
|
11219
11224
|
dom, editor) {
|
|
@@ -11321,7 +11326,7 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
11321
11326
|
}
|
|
11322
11327
|
const selection = $getSelection();
|
|
11323
11328
|
if (!$isRangeSelection(selection) || anchorOffset === null || focusOffset === null) {
|
|
11324
|
-
node
|
|
11329
|
+
$setTextContentWithSelection(node, normalizedTextContent, selection);
|
|
11325
11330
|
return;
|
|
11326
11331
|
}
|
|
11327
11332
|
selection.setTextNodeRange(node, anchorOffset, node, focusOffset);
|
|
@@ -11331,7 +11336,19 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
11331
11336
|
node.replace(replacement);
|
|
11332
11337
|
node = replacement;
|
|
11333
11338
|
}
|
|
11334
|
-
node
|
|
11339
|
+
$setTextContentWithSelection(node, normalizedTextContent, selection);
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11342
|
+
}
|
|
11343
|
+
function $setTextContentWithSelection(node, textContent, selection) {
|
|
11344
|
+
node.setTextContent(textContent);
|
|
11345
|
+
if ($isRangeSelection(selection)) {
|
|
11346
|
+
const key = node.getKey();
|
|
11347
|
+
for (const k of ['anchor', 'focus']) {
|
|
11348
|
+
const pt = selection[k];
|
|
11349
|
+
if (pt.type === 'text' && pt.key === key) {
|
|
11350
|
+
pt.offset = $getTextNodeOffset(node, pt.offset, 'clamp');
|
|
11351
|
+
}
|
|
11335
11352
|
}
|
|
11336
11353
|
}
|
|
11337
11354
|
}
|
|
@@ -12760,13 +12777,14 @@ function $getTextPointCaret(origin, direction, offset) {
|
|
|
12760
12777
|
*
|
|
12761
12778
|
* @param origin a TextNode
|
|
12762
12779
|
* @param offset An absolute offset into the TextNode string, or a direction for which end to use as the offset
|
|
12780
|
+
* @param mode If 'error' (the default) out of bounds offsets will be an error in dev. Otherwise it will clamp to a valid offset.
|
|
12763
12781
|
* @returns An absolute offset into the TextNode string
|
|
12764
12782
|
*/
|
|
12765
|
-
function $getTextNodeOffset(origin, offset) {
|
|
12783
|
+
function $getTextNodeOffset(origin, offset, mode = 'error') {
|
|
12766
12784
|
const size = origin.getTextContentSize();
|
|
12767
12785
|
let numericOffset = offset === 'next' ? size : offset === 'previous' ? 0 : offset;
|
|
12768
12786
|
if (numericOffset < 0 || numericOffset > size) {
|
|
12769
|
-
{
|
|
12787
|
+
if (!(mode === 'clamp')) {
|
|
12770
12788
|
formatDevErrorMessage(`$getTextNodeOffset: invalid offset ${String(offset)} for size ${String(size)} at key ${origin.getKey()}`);
|
|
12771
12789
|
} // Clamp invalid offsets in prod
|
|
12772
12790
|
numericOffset = numericOffset < 0 ? 0 : size;
|