@lexical/selection 0.24.0 → 0.24.1-nightly.20250211.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/LexicalSelection.dev.js +129 -133
- package/LexicalSelection.dev.mjs +129 -135
- package/LexicalSelection.mjs +2 -0
- package/LexicalSelection.node.mjs +2 -0
- package/LexicalSelection.prod.js +1 -1
- package/LexicalSelection.prod.mjs +1 -1
- package/index.d.ts +6 -8
- package/lexical-node.d.ts +19 -0
- package/package.json +2 -2
- package/range-selection.d.ts +4 -2
package/LexicalSelection.dev.js
CHANGED
|
@@ -380,8 +380,20 @@ function $addNodeStyle(node) {
|
|
|
380
380
|
const styles = getStyleObjectFromRawCSS(CSSText);
|
|
381
381
|
CSS_TO_STYLES.set(CSSText, styles);
|
|
382
382
|
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Applies the provided styles to the given TextNodes or collapsed RangeSelection.
|
|
386
|
+
* Will update partially selected TextNodes by splitting the TextNode and applying
|
|
387
|
+
* the styles to the appropriate one.
|
|
388
|
+
*
|
|
389
|
+
* @param target - The TextNode or collapsed RangeSelection to apply the styles to
|
|
390
|
+
* @param patch - The patch to apply, which can include multiple styles. \\{CSSProperty: value\\} . Can also accept a function that returns the new property value.
|
|
391
|
+
*/
|
|
383
392
|
function $patchStyle(target, patch) {
|
|
384
|
-
|
|
393
|
+
if (!(target instanceof lexical.TextNode || target.isCollapsed())) {
|
|
394
|
+
throw Error(`$patchStyle must only be called with a TextNode or collapsed RangeSelection`);
|
|
395
|
+
}
|
|
396
|
+
const prevStyles = getStyleObjectFromCSS(target instanceof lexical.TextNode ? target.getStyle() : target.style);
|
|
385
397
|
const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {
|
|
386
398
|
if (typeof value === 'function') {
|
|
387
399
|
styles[key] = value(prevStyles[key], target);
|
|
@@ -393,7 +405,7 @@ function $patchStyle(target, patch) {
|
|
|
393
405
|
return styles;
|
|
394
406
|
}, {
|
|
395
407
|
...prevStyles
|
|
396
|
-
}
|
|
408
|
+
});
|
|
397
409
|
const newCSSText = getCSSFromStyleObject(newStyles);
|
|
398
410
|
target.setStyle(newCSSText);
|
|
399
411
|
CSS_TO_STYLES.set(newCSSText, newStyles);
|
|
@@ -407,119 +419,81 @@ function $patchStyle(target, patch) {
|
|
|
407
419
|
* @param patch - The patch to apply, which can include multiple styles. \\{CSSProperty: value\\} . Can also accept a function that returns the new property value.
|
|
408
420
|
*/
|
|
409
421
|
function $patchStyleText(selection, patch) {
|
|
410
|
-
if (selection
|
|
411
|
-
$patchStyle(selection, patch);
|
|
412
|
-
} else {
|
|
413
|
-
$forEachSelectedTextNode(textNode => {
|
|
414
|
-
$patchStyle(textNode, patch);
|
|
415
|
-
});
|
|
422
|
+
if (lexical.$isRangeSelection(selection) && selection.isCollapsed()) {
|
|
423
|
+
return $patchStyle(selection, patch);
|
|
416
424
|
}
|
|
425
|
+
$forEachSelectedTextNode(textNode => {
|
|
426
|
+
$patchStyle(textNode, patch);
|
|
427
|
+
});
|
|
417
428
|
}
|
|
418
429
|
function $forEachSelectedTextNode(fn) {
|
|
419
430
|
const selection = lexical.$getSelection();
|
|
420
|
-
if (!
|
|
431
|
+
if (!selection) {
|
|
421
432
|
return;
|
|
422
433
|
}
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const lastIndex = selectedNodesLength - 1;
|
|
430
|
-
let firstNode = selectedNodes[0];
|
|
431
|
-
let lastNode = selectedNodes[lastIndex];
|
|
432
|
-
const firstNodeText = firstNode.getTextContent();
|
|
433
|
-
const firstNodeTextLength = firstNodeText.length;
|
|
434
|
-
const focusOffset = focus.offset;
|
|
435
|
-
let anchorOffset = anchor.offset;
|
|
436
|
-
const isBefore = anchor.isBefore(focus);
|
|
437
|
-
let startOffset = isBefore ? anchorOffset : focusOffset;
|
|
438
|
-
let endOffset = isBefore ? focusOffset : anchorOffset;
|
|
439
|
-
const startType = isBefore ? anchor.type : focus.type;
|
|
440
|
-
const endType = isBefore ? focus.type : anchor.type;
|
|
441
|
-
const endKey = isBefore ? focus.key : anchor.key;
|
|
442
|
-
|
|
443
|
-
// This is the case where the user only selected the very end of the
|
|
444
|
-
// first node so we don't want to include it in the formatting change.
|
|
445
|
-
if (lexical.$isTextNode(firstNode) && startOffset === firstNodeTextLength) {
|
|
446
|
-
const nextSibling = firstNode.getNextSibling();
|
|
447
|
-
if (lexical.$isTextNode(nextSibling)) {
|
|
448
|
-
// we basically make the second node the firstNode, changing offsets accordingly
|
|
449
|
-
anchorOffset = 0;
|
|
450
|
-
startOffset = 0;
|
|
451
|
-
firstNode = nextSibling;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// This is the case where we only selected a single node
|
|
456
|
-
if (selectedNodes.length === 1) {
|
|
457
|
-
if (lexical.$isTextNode(firstNode) && firstNode.canHaveFormat()) {
|
|
458
|
-
startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
459
|
-
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
460
|
-
|
|
461
|
-
// No actual text is selected, so do nothing.
|
|
462
|
-
if (startOffset === endOffset) {
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// The entire node is selected or a token/segment, so just format it
|
|
467
|
-
if (lexical.$isTokenOrSegmented(firstNode) || startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
468
|
-
fn(firstNode);
|
|
469
|
-
firstNode.select(startOffset, endOffset);
|
|
470
|
-
} else {
|
|
471
|
-
// The node is partially selected, so split it into two nodes
|
|
472
|
-
// and style the selected one.
|
|
473
|
-
const splitNodes = firstNode.splitText(startOffset, endOffset);
|
|
474
|
-
const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
|
|
475
|
-
fn(replacement);
|
|
476
|
-
replacement.select(0, endOffset - startOffset);
|
|
477
|
-
}
|
|
478
|
-
} // multiple nodes selected.
|
|
479
|
-
} else {
|
|
480
|
-
if (lexical.$isTextNode(firstNode) && startOffset < firstNode.getTextContentSize() && firstNode.canHaveFormat()) {
|
|
481
|
-
if (startOffset !== 0 && !lexical.$isTokenOrSegmented(firstNode)) {
|
|
482
|
-
// the entire first node isn't selected and it isn't a token or segmented, so split it
|
|
483
|
-
firstNode = firstNode.splitText(startOffset)[1];
|
|
484
|
-
startOffset = 0;
|
|
485
|
-
if (isBefore) {
|
|
486
|
-
anchor.set(firstNode.getKey(), startOffset, 'text');
|
|
487
|
-
} else {
|
|
488
|
-
focus.set(firstNode.getKey(), startOffset, 'text');
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
fn(firstNode);
|
|
492
|
-
}
|
|
493
|
-
if (lexical.$isTextNode(lastNode) && lastNode.canHaveFormat()) {
|
|
494
|
-
const lastNodeText = lastNode.getTextContent();
|
|
495
|
-
const lastNodeTextLength = lastNodeText.length;
|
|
496
|
-
|
|
497
|
-
// The last node might not actually be the end node
|
|
498
|
-
//
|
|
499
|
-
// If not, assume the last node is fully-selected unless the end offset is
|
|
500
|
-
// zero.
|
|
501
|
-
if (lastNode.__key !== endKey && endOffset !== 0) {
|
|
502
|
-
endOffset = lastNodeTextLength;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// if the entire last node isn't selected and it isn't a token or segmented, split it
|
|
506
|
-
if (endOffset !== lastNodeTextLength && !lexical.$isTokenOrSegmented(lastNode)) {
|
|
507
|
-
[lastNode] = lastNode.splitText(endOffset);
|
|
508
|
-
}
|
|
509
|
-
if (endOffset !== 0 || endType === 'element') {
|
|
510
|
-
fn(lastNode);
|
|
434
|
+
const slicedTextNodes = new Map();
|
|
435
|
+
const getSliceIndices = node => slicedTextNodes.get(node.getKey()) || [0, node.getTextContentSize()];
|
|
436
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
437
|
+
for (const slice of lexical.$caretRangeFromSelection(selection).getTextSlices()) {
|
|
438
|
+
if (slice) {
|
|
439
|
+
slicedTextNodes.set(slice.caret.origin.getKey(), slice.getSliceIndices());
|
|
511
440
|
}
|
|
512
441
|
}
|
|
442
|
+
}
|
|
443
|
+
const selectedNodes = selection.getNodes();
|
|
444
|
+
for (const selectedNode of selectedNodes) {
|
|
445
|
+
if (!(lexical.$isTextNode(selectedNode) && selectedNode.canHaveFormat())) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
const [startOffset, endOffset] = getSliceIndices(selectedNode);
|
|
449
|
+
// No actual text is selected, so do nothing.
|
|
450
|
+
if (endOffset === startOffset) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
513
453
|
|
|
514
|
-
//
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
454
|
+
// The entire node is selected or a token/segment, so just format it
|
|
455
|
+
if (lexical.$isTokenOrSegmented(selectedNode) || startOffset === 0 && endOffset === selectedNode.getTextContentSize()) {
|
|
456
|
+
fn(selectedNode);
|
|
457
|
+
} else {
|
|
458
|
+
// The node is partially selected, so split it into two or three nodes
|
|
459
|
+
// and style the selected one.
|
|
460
|
+
const splitNodes = selectedNode.splitText(startOffset, endOffset);
|
|
461
|
+
const replacement = splitNodes[startOffset === 0 ? 0 : 1];
|
|
462
|
+
fn(replacement);
|
|
521
463
|
}
|
|
522
464
|
}
|
|
465
|
+
// Prior to NodeCaret #7046 this would have been a side-effect
|
|
466
|
+
// so we do this for test compatibility.
|
|
467
|
+
// TODO: we may want to consider simplifying by removing this
|
|
468
|
+
if (lexical.$isRangeSelection(selection) && selection.anchor.type === 'text' && selection.focus.type === 'text' && selection.anchor.key === selection.focus.key) {
|
|
469
|
+
$ensureForwardRangeSelection(selection);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Ensure that the given RangeSelection is not backwards. If it
|
|
475
|
+
* is backwards, then the anchor and focus points will be swapped
|
|
476
|
+
* in-place. Ensuring that the selection is a writable RangeSelection
|
|
477
|
+
* is the responsibility of the caller (e.g. in a read-only context
|
|
478
|
+
* you will want to clone $getSelection() before using this).
|
|
479
|
+
*
|
|
480
|
+
* @param selection a writable RangeSelection
|
|
481
|
+
*/
|
|
482
|
+
function $ensureForwardRangeSelection(selection) {
|
|
483
|
+
if (selection.isBackward()) {
|
|
484
|
+
const {
|
|
485
|
+
anchor,
|
|
486
|
+
focus
|
|
487
|
+
} = selection;
|
|
488
|
+
// stash for the in-place swap
|
|
489
|
+
const {
|
|
490
|
+
key,
|
|
491
|
+
offset,
|
|
492
|
+
type
|
|
493
|
+
} = anchor;
|
|
494
|
+
anchor.set(focus.key, focus.offset, focus.type);
|
|
495
|
+
focus.set(key, offset, type);
|
|
496
|
+
}
|
|
523
497
|
}
|
|
524
498
|
|
|
525
499
|
/**
|
|
@@ -530,46 +504,66 @@ function $forEachSelectedTextNode(fn) {
|
|
|
530
504
|
*
|
|
531
505
|
*/
|
|
532
506
|
|
|
507
|
+
function $copyBlockFormatIndent(srcNode, destNode) {
|
|
508
|
+
const format = srcNode.getFormatType();
|
|
509
|
+
const indent = srcNode.getIndent();
|
|
510
|
+
if (format !== destNode.getFormatType()) {
|
|
511
|
+
destNode.setFormat(format);
|
|
512
|
+
}
|
|
513
|
+
if (indent !== destNode.getIndent()) {
|
|
514
|
+
destNode.setIndent(indent);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
533
517
|
|
|
534
518
|
/**
|
|
535
519
|
* Converts all nodes in the selection that are of one block type to another.
|
|
536
520
|
* @param selection - The selected blocks to be converted.
|
|
537
|
-
* @param createElement - The function that creates the node. eg. $createParagraphNode.
|
|
521
|
+
* @param $createElement - The function that creates the node. eg. $createParagraphNode.
|
|
522
|
+
* @param $afterCreateElement - The function that updates the new node based on the previous one ($copyBlockFormatIndent by default)
|
|
538
523
|
*/
|
|
539
|
-
function $setBlocksType(selection, createElement) {
|
|
524
|
+
function $setBlocksType(selection, $createElement, $afterCreateElement = $copyBlockFormatIndent) {
|
|
540
525
|
if (selection === null) {
|
|
541
526
|
return;
|
|
542
527
|
}
|
|
528
|
+
// Selections tend to not include their containing blocks so we effectively
|
|
529
|
+
// expand it here
|
|
543
530
|
const anchorAndFocus = selection.getStartEndPoints();
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
if (
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
531
|
+
const blockMap = new Map();
|
|
532
|
+
let newSelection = null;
|
|
533
|
+
if (anchorAndFocus) {
|
|
534
|
+
const [anchor, focus] = anchorAndFocus;
|
|
535
|
+
newSelection = lexical.$createRangeSelection();
|
|
536
|
+
newSelection.anchor.set(anchor.key, anchor.offset, anchor.type);
|
|
537
|
+
newSelection.focus.set(focus.key, focus.offset, focus.type);
|
|
538
|
+
const anchorBlock = $getAncestor(anchor.getNode(), lexical.INTERNAL_$isBlock);
|
|
539
|
+
const focusBlock = $getAncestor(focus.getNode(), lexical.INTERNAL_$isBlock);
|
|
540
|
+
if (lexical.$isElementNode(anchorBlock)) {
|
|
541
|
+
blockMap.set(anchorBlock.getKey(), anchorBlock);
|
|
542
|
+
}
|
|
543
|
+
if (lexical.$isElementNode(focusBlock)) {
|
|
544
|
+
blockMap.set(focusBlock.getKey(), focusBlock);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
for (const node of selection.getNodes()) {
|
|
548
|
+
if (lexical.$isElementNode(node) && lexical.INTERNAL_$isBlock(node)) {
|
|
549
|
+
blockMap.set(node.getKey(), node);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
for (const [key, prevNode] of blockMap) {
|
|
553
|
+
const element = $createElement();
|
|
554
|
+
$afterCreateElement(prevNode, element);
|
|
555
|
+
prevNode.replace(element, true);
|
|
556
|
+
if (newSelection) {
|
|
557
|
+
if (key === newSelection.anchor.key) {
|
|
558
|
+
newSelection.anchor.key = element.getKey();
|
|
559
|
+
}
|
|
560
|
+
if (key === newSelection.focus.key) {
|
|
561
|
+
newSelection.focus.key = element.getKey();
|
|
562
|
+
}
|
|
557
563
|
}
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
const nodes = selection.getNodes().filter(lexical.INTERNAL_$isBlock).filter(lexical.$isElementNode);
|
|
561
|
-
const firstSelectedBlock = anchor ? $getAncestor(anchor.getNode(), lexical.INTERNAL_$isBlock) : null;
|
|
562
|
-
if (lexical.$isElementNode(firstSelectedBlock) && !nodes.find(node => node.is(firstSelectedBlock))) {
|
|
563
|
-
nodes.push(firstSelectedBlock);
|
|
564
564
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
targetElement.setFormat(node.getFormatType());
|
|
568
|
-
targetElement.setIndent(node.getIndent());
|
|
569
|
-
node.replace(targetElement, true);
|
|
570
|
-
if (node.is(firstSelectedBlock) && isCollapsedSelection) {
|
|
571
|
-
targetElement.select();
|
|
572
|
-
}
|
|
565
|
+
if (newSelection && selection.is(lexical.$getSelection())) {
|
|
566
|
+
lexical.$setSelection(newSelection);
|
|
573
567
|
}
|
|
574
568
|
}
|
|
575
569
|
function isPointAttached(point) {
|
|
@@ -918,6 +912,8 @@ const trimTextContentFromAnchor = $trimTextContentFromAnchor;
|
|
|
918
912
|
exports.$cloneWithProperties = lexical.$cloneWithProperties;
|
|
919
913
|
exports.$selectAll = lexical.$selectAll;
|
|
920
914
|
exports.$addNodeStyle = $addNodeStyle;
|
|
915
|
+
exports.$copyBlockFormatIndent = $copyBlockFormatIndent;
|
|
916
|
+
exports.$ensureForwardRangeSelection = $ensureForwardRangeSelection;
|
|
921
917
|
exports.$forEachSelectedTextNode = $forEachSelectedTextNode;
|
|
922
918
|
exports.$getSelectionStyleValueForProperty = $getSelectionStyleValueForProperty;
|
|
923
919
|
exports.$isAtNodeEnd = $isAtNodeEnd;
|
package/LexicalSelection.dev.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { $isTextNode, $getCharacterOffsets, $isElementNode, $isRootNode, $getNodeByKey, $getPreviousSelection, $createTextNode, $isRangeSelection, $getSelection, $isTokenOrSegmented, $
|
|
9
|
+
import { $isTextNode, $getCharacterOffsets, $isElementNode, $isRootNode, $getNodeByKey, $getPreviousSelection, $createTextNode, $isRangeSelection, $getSelection, $caretRangeFromSelection, $isTokenOrSegmented, TextNode, $createRangeSelection, INTERNAL_$isBlock, $setSelection, $isRootOrShadowRoot, $hasAncestor, $isLeafNode, $getAdjacentNode, $isDecoratorNode } from 'lexical';
|
|
10
10
|
export { $cloneWithProperties, $selectAll } from 'lexical';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -379,8 +379,20 @@ function $addNodeStyle(node) {
|
|
|
379
379
|
const styles = getStyleObjectFromRawCSS(CSSText);
|
|
380
380
|
CSS_TO_STYLES.set(CSSText, styles);
|
|
381
381
|
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Applies the provided styles to the given TextNodes or collapsed RangeSelection.
|
|
385
|
+
* Will update partially selected TextNodes by splitting the TextNode and applying
|
|
386
|
+
* the styles to the appropriate one.
|
|
387
|
+
*
|
|
388
|
+
* @param target - The TextNode or collapsed RangeSelection to apply the styles to
|
|
389
|
+
* @param patch - The patch to apply, which can include multiple styles. \\{CSSProperty: value\\} . Can also accept a function that returns the new property value.
|
|
390
|
+
*/
|
|
382
391
|
function $patchStyle(target, patch) {
|
|
383
|
-
|
|
392
|
+
if (!(target instanceof TextNode || target.isCollapsed())) {
|
|
393
|
+
throw Error(`$patchStyle must only be called with a TextNode or collapsed RangeSelection`);
|
|
394
|
+
}
|
|
395
|
+
const prevStyles = getStyleObjectFromCSS(target instanceof TextNode ? target.getStyle() : target.style);
|
|
384
396
|
const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {
|
|
385
397
|
if (typeof value === 'function') {
|
|
386
398
|
styles[key] = value(prevStyles[key], target);
|
|
@@ -392,7 +404,7 @@ function $patchStyle(target, patch) {
|
|
|
392
404
|
return styles;
|
|
393
405
|
}, {
|
|
394
406
|
...prevStyles
|
|
395
|
-
}
|
|
407
|
+
});
|
|
396
408
|
const newCSSText = getCSSFromStyleObject(newStyles);
|
|
397
409
|
target.setStyle(newCSSText);
|
|
398
410
|
CSS_TO_STYLES.set(newCSSText, newStyles);
|
|
@@ -406,119 +418,81 @@ function $patchStyle(target, patch) {
|
|
|
406
418
|
* @param patch - The patch to apply, which can include multiple styles. \\{CSSProperty: value\\} . Can also accept a function that returns the new property value.
|
|
407
419
|
*/
|
|
408
420
|
function $patchStyleText(selection, patch) {
|
|
409
|
-
if (selection
|
|
410
|
-
$patchStyle(selection, patch);
|
|
411
|
-
} else {
|
|
412
|
-
$forEachSelectedTextNode(textNode => {
|
|
413
|
-
$patchStyle(textNode, patch);
|
|
414
|
-
});
|
|
421
|
+
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
|
422
|
+
return $patchStyle(selection, patch);
|
|
415
423
|
}
|
|
424
|
+
$forEachSelectedTextNode(textNode => {
|
|
425
|
+
$patchStyle(textNode, patch);
|
|
426
|
+
});
|
|
416
427
|
}
|
|
417
428
|
function $forEachSelectedTextNode(fn) {
|
|
418
429
|
const selection = $getSelection();
|
|
419
|
-
if (
|
|
430
|
+
if (!selection) {
|
|
420
431
|
return;
|
|
421
432
|
}
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const lastIndex = selectedNodesLength - 1;
|
|
429
|
-
let firstNode = selectedNodes[0];
|
|
430
|
-
let lastNode = selectedNodes[lastIndex];
|
|
431
|
-
const firstNodeText = firstNode.getTextContent();
|
|
432
|
-
const firstNodeTextLength = firstNodeText.length;
|
|
433
|
-
const focusOffset = focus.offset;
|
|
434
|
-
let anchorOffset = anchor.offset;
|
|
435
|
-
const isBefore = anchor.isBefore(focus);
|
|
436
|
-
let startOffset = isBefore ? anchorOffset : focusOffset;
|
|
437
|
-
let endOffset = isBefore ? focusOffset : anchorOffset;
|
|
438
|
-
const startType = isBefore ? anchor.type : focus.type;
|
|
439
|
-
const endType = isBefore ? focus.type : anchor.type;
|
|
440
|
-
const endKey = isBefore ? focus.key : anchor.key;
|
|
441
|
-
|
|
442
|
-
// This is the case where the user only selected the very end of the
|
|
443
|
-
// first node so we don't want to include it in the formatting change.
|
|
444
|
-
if ($isTextNode(firstNode) && startOffset === firstNodeTextLength) {
|
|
445
|
-
const nextSibling = firstNode.getNextSibling();
|
|
446
|
-
if ($isTextNode(nextSibling)) {
|
|
447
|
-
// we basically make the second node the firstNode, changing offsets accordingly
|
|
448
|
-
anchorOffset = 0;
|
|
449
|
-
startOffset = 0;
|
|
450
|
-
firstNode = nextSibling;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// This is the case where we only selected a single node
|
|
455
|
-
if (selectedNodes.length === 1) {
|
|
456
|
-
if ($isTextNode(firstNode) && firstNode.canHaveFormat()) {
|
|
457
|
-
startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
458
|
-
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
459
|
-
|
|
460
|
-
// No actual text is selected, so do nothing.
|
|
461
|
-
if (startOffset === endOffset) {
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// The entire node is selected or a token/segment, so just format it
|
|
466
|
-
if ($isTokenOrSegmented(firstNode) || startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
467
|
-
fn(firstNode);
|
|
468
|
-
firstNode.select(startOffset, endOffset);
|
|
469
|
-
} else {
|
|
470
|
-
// The node is partially selected, so split it into two nodes
|
|
471
|
-
// and style the selected one.
|
|
472
|
-
const splitNodes = firstNode.splitText(startOffset, endOffset);
|
|
473
|
-
const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
|
|
474
|
-
fn(replacement);
|
|
475
|
-
replacement.select(0, endOffset - startOffset);
|
|
476
|
-
}
|
|
477
|
-
} // multiple nodes selected.
|
|
478
|
-
} else {
|
|
479
|
-
if ($isTextNode(firstNode) && startOffset < firstNode.getTextContentSize() && firstNode.canHaveFormat()) {
|
|
480
|
-
if (startOffset !== 0 && !$isTokenOrSegmented(firstNode)) {
|
|
481
|
-
// the entire first node isn't selected and it isn't a token or segmented, so split it
|
|
482
|
-
firstNode = firstNode.splitText(startOffset)[1];
|
|
483
|
-
startOffset = 0;
|
|
484
|
-
if (isBefore) {
|
|
485
|
-
anchor.set(firstNode.getKey(), startOffset, 'text');
|
|
486
|
-
} else {
|
|
487
|
-
focus.set(firstNode.getKey(), startOffset, 'text');
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
fn(firstNode);
|
|
491
|
-
}
|
|
492
|
-
if ($isTextNode(lastNode) && lastNode.canHaveFormat()) {
|
|
493
|
-
const lastNodeText = lastNode.getTextContent();
|
|
494
|
-
const lastNodeTextLength = lastNodeText.length;
|
|
495
|
-
|
|
496
|
-
// The last node might not actually be the end node
|
|
497
|
-
//
|
|
498
|
-
// If not, assume the last node is fully-selected unless the end offset is
|
|
499
|
-
// zero.
|
|
500
|
-
if (lastNode.__key !== endKey && endOffset !== 0) {
|
|
501
|
-
endOffset = lastNodeTextLength;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// if the entire last node isn't selected and it isn't a token or segmented, split it
|
|
505
|
-
if (endOffset !== lastNodeTextLength && !$isTokenOrSegmented(lastNode)) {
|
|
506
|
-
[lastNode] = lastNode.splitText(endOffset);
|
|
507
|
-
}
|
|
508
|
-
if (endOffset !== 0 || endType === 'element') {
|
|
509
|
-
fn(lastNode);
|
|
433
|
+
const slicedTextNodes = new Map();
|
|
434
|
+
const getSliceIndices = node => slicedTextNodes.get(node.getKey()) || [0, node.getTextContentSize()];
|
|
435
|
+
if ($isRangeSelection(selection)) {
|
|
436
|
+
for (const slice of $caretRangeFromSelection(selection).getTextSlices()) {
|
|
437
|
+
if (slice) {
|
|
438
|
+
slicedTextNodes.set(slice.caret.origin.getKey(), slice.getSliceIndices());
|
|
510
439
|
}
|
|
511
440
|
}
|
|
441
|
+
}
|
|
442
|
+
const selectedNodes = selection.getNodes();
|
|
443
|
+
for (const selectedNode of selectedNodes) {
|
|
444
|
+
if (!($isTextNode(selectedNode) && selectedNode.canHaveFormat())) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const [startOffset, endOffset] = getSliceIndices(selectedNode);
|
|
448
|
+
// No actual text is selected, so do nothing.
|
|
449
|
+
if (endOffset === startOffset) {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
512
452
|
|
|
513
|
-
//
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
453
|
+
// The entire node is selected or a token/segment, so just format it
|
|
454
|
+
if ($isTokenOrSegmented(selectedNode) || startOffset === 0 && endOffset === selectedNode.getTextContentSize()) {
|
|
455
|
+
fn(selectedNode);
|
|
456
|
+
} else {
|
|
457
|
+
// The node is partially selected, so split it into two or three nodes
|
|
458
|
+
// and style the selected one.
|
|
459
|
+
const splitNodes = selectedNode.splitText(startOffset, endOffset);
|
|
460
|
+
const replacement = splitNodes[startOffset === 0 ? 0 : 1];
|
|
461
|
+
fn(replacement);
|
|
520
462
|
}
|
|
521
463
|
}
|
|
464
|
+
// Prior to NodeCaret #7046 this would have been a side-effect
|
|
465
|
+
// so we do this for test compatibility.
|
|
466
|
+
// TODO: we may want to consider simplifying by removing this
|
|
467
|
+
if ($isRangeSelection(selection) && selection.anchor.type === 'text' && selection.focus.type === 'text' && selection.anchor.key === selection.focus.key) {
|
|
468
|
+
$ensureForwardRangeSelection(selection);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Ensure that the given RangeSelection is not backwards. If it
|
|
474
|
+
* is backwards, then the anchor and focus points will be swapped
|
|
475
|
+
* in-place. Ensuring that the selection is a writable RangeSelection
|
|
476
|
+
* is the responsibility of the caller (e.g. in a read-only context
|
|
477
|
+
* you will want to clone $getSelection() before using this).
|
|
478
|
+
*
|
|
479
|
+
* @param selection a writable RangeSelection
|
|
480
|
+
*/
|
|
481
|
+
function $ensureForwardRangeSelection(selection) {
|
|
482
|
+
if (selection.isBackward()) {
|
|
483
|
+
const {
|
|
484
|
+
anchor,
|
|
485
|
+
focus
|
|
486
|
+
} = selection;
|
|
487
|
+
// stash for the in-place swap
|
|
488
|
+
const {
|
|
489
|
+
key,
|
|
490
|
+
offset,
|
|
491
|
+
type
|
|
492
|
+
} = anchor;
|
|
493
|
+
anchor.set(focus.key, focus.offset, focus.type);
|
|
494
|
+
focus.set(key, offset, type);
|
|
495
|
+
}
|
|
522
496
|
}
|
|
523
497
|
|
|
524
498
|
/**
|
|
@@ -529,46 +503,66 @@ function $forEachSelectedTextNode(fn) {
|
|
|
529
503
|
*
|
|
530
504
|
*/
|
|
531
505
|
|
|
506
|
+
function $copyBlockFormatIndent(srcNode, destNode) {
|
|
507
|
+
const format = srcNode.getFormatType();
|
|
508
|
+
const indent = srcNode.getIndent();
|
|
509
|
+
if (format !== destNode.getFormatType()) {
|
|
510
|
+
destNode.setFormat(format);
|
|
511
|
+
}
|
|
512
|
+
if (indent !== destNode.getIndent()) {
|
|
513
|
+
destNode.setIndent(indent);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
532
516
|
|
|
533
517
|
/**
|
|
534
518
|
* Converts all nodes in the selection that are of one block type to another.
|
|
535
519
|
* @param selection - The selected blocks to be converted.
|
|
536
|
-
* @param createElement - The function that creates the node. eg. $createParagraphNode.
|
|
520
|
+
* @param $createElement - The function that creates the node. eg. $createParagraphNode.
|
|
521
|
+
* @param $afterCreateElement - The function that updates the new node based on the previous one ($copyBlockFormatIndent by default)
|
|
537
522
|
*/
|
|
538
|
-
function $setBlocksType(selection, createElement) {
|
|
523
|
+
function $setBlocksType(selection, $createElement, $afterCreateElement = $copyBlockFormatIndent) {
|
|
539
524
|
if (selection === null) {
|
|
540
525
|
return;
|
|
541
526
|
}
|
|
527
|
+
// Selections tend to not include their containing blocks so we effectively
|
|
528
|
+
// expand it here
|
|
542
529
|
const anchorAndFocus = selection.getStartEndPoints();
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
if (
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
530
|
+
const blockMap = new Map();
|
|
531
|
+
let newSelection = null;
|
|
532
|
+
if (anchorAndFocus) {
|
|
533
|
+
const [anchor, focus] = anchorAndFocus;
|
|
534
|
+
newSelection = $createRangeSelection();
|
|
535
|
+
newSelection.anchor.set(anchor.key, anchor.offset, anchor.type);
|
|
536
|
+
newSelection.focus.set(focus.key, focus.offset, focus.type);
|
|
537
|
+
const anchorBlock = $getAncestor(anchor.getNode(), INTERNAL_$isBlock);
|
|
538
|
+
const focusBlock = $getAncestor(focus.getNode(), INTERNAL_$isBlock);
|
|
539
|
+
if ($isElementNode(anchorBlock)) {
|
|
540
|
+
blockMap.set(anchorBlock.getKey(), anchorBlock);
|
|
541
|
+
}
|
|
542
|
+
if ($isElementNode(focusBlock)) {
|
|
543
|
+
blockMap.set(focusBlock.getKey(), focusBlock);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
for (const node of selection.getNodes()) {
|
|
547
|
+
if ($isElementNode(node) && INTERNAL_$isBlock(node)) {
|
|
548
|
+
blockMap.set(node.getKey(), node);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
for (const [key, prevNode] of blockMap) {
|
|
552
|
+
const element = $createElement();
|
|
553
|
+
$afterCreateElement(prevNode, element);
|
|
554
|
+
prevNode.replace(element, true);
|
|
555
|
+
if (newSelection) {
|
|
556
|
+
if (key === newSelection.anchor.key) {
|
|
557
|
+
newSelection.anchor.key = element.getKey();
|
|
558
|
+
}
|
|
559
|
+
if (key === newSelection.focus.key) {
|
|
560
|
+
newSelection.focus.key = element.getKey();
|
|
561
|
+
}
|
|
556
562
|
}
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
const nodes = selection.getNodes().filter(INTERNAL_$isBlock).filter($isElementNode);
|
|
560
|
-
const firstSelectedBlock = anchor ? $getAncestor(anchor.getNode(), INTERNAL_$isBlock) : null;
|
|
561
|
-
if ($isElementNode(firstSelectedBlock) && !nodes.find(node => node.is(firstSelectedBlock))) {
|
|
562
|
-
nodes.push(firstSelectedBlock);
|
|
563
563
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
targetElement.setFormat(node.getFormatType());
|
|
567
|
-
targetElement.setIndent(node.getIndent());
|
|
568
|
-
node.replace(targetElement, true);
|
|
569
|
-
if (node.is(firstSelectedBlock) && isCollapsedSelection) {
|
|
570
|
-
targetElement.select();
|
|
571
|
-
}
|
|
564
|
+
if (newSelection && selection.is($getSelection())) {
|
|
565
|
+
$setSelection(newSelection);
|
|
572
566
|
}
|
|
573
567
|
}
|
|
574
568
|
function isPointAttached(point) {
|
|
@@ -914,4 +908,4 @@ function $getAncestor(node, predicate) {
|
|
|
914
908
|
/** @deprecated renamed to {@link $trimTextContentFromAnchor} by @lexical/eslint-plugin rules-of-lexical */
|
|
915
909
|
const trimTextContentFromAnchor = $trimTextContentFromAnchor;
|
|
916
910
|
|
|
917
|
-
export { $addNodeStyle, $forEachSelectedTextNode, $getSelectionStyleValueForProperty, $isAtNodeEnd, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $patchStyleText, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor, $wrapNodes, createDOMRange, createRectsFromDOMRange, getCSSFromStyleObject, getStyleObjectFromCSS, trimTextContentFromAnchor };
|
|
911
|
+
export { $addNodeStyle, $copyBlockFormatIndent, $ensureForwardRangeSelection, $forEachSelectedTextNode, $getSelectionStyleValueForProperty, $isAtNodeEnd, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $patchStyleText, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor, $wrapNodes, createDOMRange, createRectsFromDOMRange, getCSSFromStyleObject, getStyleObjectFromCSS, trimTextContentFromAnchor };
|
package/LexicalSelection.mjs
CHANGED
|
@@ -11,6 +11,8 @@ import * as modProd from './LexicalSelection.prod.mjs';
|
|
|
11
11
|
const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;
|
|
12
12
|
export const $addNodeStyle = mod.$addNodeStyle;
|
|
13
13
|
export const $cloneWithProperties = mod.$cloneWithProperties;
|
|
14
|
+
export const $copyBlockFormatIndent = mod.$copyBlockFormatIndent;
|
|
15
|
+
export const $ensureForwardRangeSelection = mod.$ensureForwardRangeSelection;
|
|
14
16
|
export const $forEachSelectedTextNode = mod.$forEachSelectedTextNode;
|
|
15
17
|
export const $getSelectionStyleValueForProperty = mod.$getSelectionStyleValueForProperty;
|
|
16
18
|
export const $isAtNodeEnd = mod.$isAtNodeEnd;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
const mod = await (process.env.NODE_ENV !== 'production' ? import('./LexicalSelection.dev.mjs') : import('./LexicalSelection.prod.mjs'));
|
|
10
10
|
export const $addNodeStyle = mod.$addNodeStyle;
|
|
11
11
|
export const $cloneWithProperties = mod.$cloneWithProperties;
|
|
12
|
+
export const $copyBlockFormatIndent = mod.$copyBlockFormatIndent;
|
|
13
|
+
export const $ensureForwardRangeSelection = mod.$ensureForwardRangeSelection;
|
|
12
14
|
export const $forEachSelectedTextNode = mod.$forEachSelectedTextNode;
|
|
13
15
|
export const $getSelectionStyleValueForProperty = mod.$getSelectionStyleValueForProperty;
|
|
14
16
|
export const $isAtNodeEnd = mod.$isAtNodeEnd;
|
package/LexicalSelection.prod.js
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
"use strict";var e=require("lexical");function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var n=t((function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;e<arguments.length;e++)t.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${t} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));const o=new Map;function l(e){let t=e;for(;null!=t;){if(t.nodeType===Node.TEXT_NODE)return t;t=t.firstChild}return null}function s(e){const t=e.parentNode;if(null==t)throw new Error("Should never happen");return[t,Array.from(t.childNodes).indexOf(e)]}function r(e){const t={};if(!e)return t;const n=e.split(";");for(const e of n)if(""!==e){const[n,o]=e.split(/:([^]+)/);n&&o&&(t[n.trim()]=o.trim())}return t}function i(e){let t=o.get(e);return void 0===t&&(t=r(e),o.set(e,t)),t}function c(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function d(t,n,o){let l=n.getNode(),s=o;if(e.$isElementNode(l)){const e=l.getDescendantByIndex(n.offset);null!==e&&(l=e)}for(;s>0&&null!==l;){if(e.$isElementNode(l)){const e=l.getLastDescendant();null!==e&&(l=e)}let o=l.getPreviousSibling(),r=0;if(null===o){let e=l.getParentOrThrow(),t=e.getPreviousSibling();for(;null===t;){if(e=e.getParent(),null===e){o=null;break}t=e.getPreviousSibling()}null!==e&&(r=e.isInline()?0:2,o=t)}let i=l.getTextContent();""===i&&e.$isElementNode(l)&&!l.isInline()&&(i="\n\n");const c=i.length;if(!e.$isTextNode(l)||s>=c){const t=l.getParent();l.remove(),null==t||0!==t.getChildrenSize()||e.$isRootNode(t)||t.remove(),s-=c+r,l=o}else{const o=l.getKey(),r=t.getEditorState().read((()=>{const t=e.$getNodeByKey(o);return e.$isTextNode(t)&&t.isSimpleText()?t.getTextContent():null})),d=c-s,f=i.slice(0,d);if(null!==r&&r!==i){const t=e.$getPreviousSelection();let n=l;if(l.isSimpleText())l.setTextContent(r);else{const t=e.$createTextNode(r);l.replace(t),n=t}if(e.$isRangeSelection(t)&&t.isCollapsed()){const e=t.anchor.offset;n.select(e,e)}}else if(l.isSimpleText()){const e=n.key===o;let t=n.offset;t<s&&(t=c);const r=e?t-s:0,i=e?t:d;if(e&&0===r){const[e]=l.splitText(r,i);e.remove()}else{const[,e]=l.splitText(r,i);e.remove()}}else{const t=e.$createTextNode(f);l.replace(t)}s=0}}}function f(e,t){const n=i("getStyle"in e?e.getStyle():e.style),l=Object.entries(t).reduce(((t,[o,l])=>("function"==typeof l?t[o]=l(n[o],e):null===l?delete t[o]:t[o]=l,t)),{...n}||{}),s=c(l);e.setStyle(s),o.set(s,l)}function a(t){const n=e.$getSelection();if(!e.$isRangeSelection(n))return;const o=n.getNodes(),l=o.length,{anchor:s,focus:r}=n,i=l-1;let c=o[0],d=o[i];const f=c.getTextContent().length,a=r.offset;let g=s.offset;const u=s.isBefore(r);let p=u?g:a,h=u?a:g;const $=u?s.type:r.type,m=u?r.type:s.type,x=u?r.key:s.key;if(e.$isTextNode(c)&&p===f){const t=c.getNextSibling();e.$isTextNode(t)&&(g=0,p=0,c=t)}if(1===o.length){if(e.$isTextNode(c)&&c.canHaveFormat()){if(p="element"===$?0:g>a?a:g,h="element"===m?f:g>a?g:a,p===h)return;if(e.$isTokenOrSegmented(c)||0===p&&h===f)t(c),c.select(p,h);else{const e=c.splitText(p,h),n=0===p?e[0]:e[1];t(n),n.select(0,h-p)}}}else{if(e.$isTextNode(c)&&p<c.getTextContentSize()&&c.canHaveFormat()&&(0===p||e.$isTokenOrSegmented(c)||(c=c.splitText(p)[1],p=0,u?s.set(c.getKey(),p,"text"):r.set(c.getKey(),p,"text")),t(c)),e.$isTextNode(d)&&d.canHaveFormat()){const n=d.getTextContent().length;d.__key!==x&&0!==h&&(h=n),h===n||e.$isTokenOrSegmented(d)||([d]=d.splitText(h)),0===h&&"element"!==m||t(d)}for(let n=1;n<i;n++){const l=o[n],s=l.getKey();e.$isTextNode(l)&&l.canHaveFormat()&&s!==c.getKey()&&s!==d.getKey()&&!l.isToken()&&t(l)}}}function g(e){return e.getNode().isAttached()}function u(t){let n=t;for(;null!==n&&!e.$isRootOrShadowRoot(n);){const e=n.getLatest(),t=n.getParent();0===e.getChildrenSize()&&n.remove(!0),n=t}}function p(t,o,l,s,r=null){if(0===o.length)return;const i=o[0],c=new Map,d=[];let f=e.$isElementNode(i)?i:i.getParentOrThrow();f.isInline()&&(f=f.getParentOrThrow());let a=!1;for(;null!==f;){const t=f.getPreviousSibling();if(null!==t){f=t,a=!0;break}if(f=f.getParentOrThrow(),e.$isRootOrShadowRoot(f))break}const p=new Set;for(let t=0;t<l;t++){const n=o[t];e.$isElementNode(n)&&0===n.getChildrenSize()&&p.add(n.getKey())}const h=new Set;for(let t=0;t<l;t++){const l=o[t];let r=l.getParent();if(null!==r&&r.isInline()&&(r=r.getParent()),null!==r&&e.$isLeafNode(l)&&!h.has(l.getKey())){const t=r.getKey();if(void 0===c.get(t)){const n=s();n.setFormat(r.getFormatType()),n.setIndent(r.getIndent()),d.push(n),c.set(t,n),r.getChildren().forEach((t=>{n.append(t),h.add(t.getKey()),e.$isElementNode(t)&&t.getChildrenKeys().forEach((e=>h.add(e)))})),u(r)}}else if(p.has(l.getKey())){e.$isElementNode(l)||n(179);const t=s();t.setFormat(l.getFormatType()),t.setIndent(l.getIndent()),d.push(t),l.remove(!0)}}if(null!==r)for(let e=0;e<d.length;e++){const t=d[e];r.append(t)}let $=null;if(e.$isRootOrShadowRoot(f))if(a)if(null!==r)f.insertAfter(r);else for(let e=d.length-1;e>=0;e--){const t=d[e];f.insertAfter(t)}else{const t=f.getFirstChild();if(e.$isElementNode(t)&&(f=t),null===t)if(r)f.append(r);else for(let e=0;e<d.length;e++){const t=d[e];f.append(t),$=t}else if(null!==r)t.insertBefore(r);else for(let e=0;e<d.length;e++){const n=d[e];t.insertBefore(n),$=n}}else if(r)f.insertAfter(r);else for(let e=d.length-1;e>=0;e--){const t=d[e];f.insertAfter(t),$=t}const m=e.$getPreviousSelection();e.$isRangeSelection(m)&&g(m.anchor)&&g(m.focus)?e.$setSelection(m.clone()):null!==$?$.selectEnd():t.dirty=!0}function h(e,t,n,o){e.modify(t?"extend":"move",n,o)}function $(t){const n=t.anchor.getNode();return"rtl"===(e.$isRootNode(n)?n:n.getParentOrThrow()).getDirection()}function m(e,t,n){const o=i(e.getStyle());return null!==o&&o[t]||n}const x=d;exports.$cloneWithProperties=e.$cloneWithProperties,exports.$selectAll=e.$selectAll,exports.$addNodeStyle=function(e){const t=e.getStyle(),n=r(t);o.set(t,n)},exports.$forEachSelectedTextNode=a,exports.$getSelectionStyleValueForProperty=function(t,n,o=""){let l=null;const s=t.getNodes(),r=t.anchor,c=t.focus,d=t.isBackward(),f=d?c.offset:r.offset,a=d?c.getNode():r.getNode();if(e.$isRangeSelection(t)&&t.isCollapsed()&&""!==t.style){const e=i(t.style);if(null!==e&&n in e)return e[n]}for(let t=0;t<s.length;t++){const r=s[t];if((0===t||0!==f||!r.is(a))&&e.$isTextNode(r)){const e=m(r,n,o);if(null===l)l=e;else if(l!==e){l="";break}}}return null===l?o:l},exports.$isAtNodeEnd=function(t){if("text"===t.type)return t.offset===t.getNode().getTextContentSize();const o=t.getNode();return e.$isElementNode(o)||n(177),t.offset===o.getChildrenSize()},exports.$isParentElementRTL=$,exports.$moveCaretSelection=h,exports.$moveCharacter=function(e,t,n){const o=$(e);h(e,t,n?!o:o,"character")},exports.$patchStyleText=function(t,n){t.isCollapsed()&&e.$isRangeSelection(t)?f(t,n):a((e=>{f(e,n)}))},exports.$setBlocksType=function(t,n){if(null===t)return;const o=t.getStartEndPoints(),l=o?o[0]:null,s=t.is(e.$getSelection())&&t.isCollapsed();if(null!==l&&"root"===l.key){const t=n(),o=e.$getRoot(),l=o.getFirstChild();return l?l.replace(t,!0):o.append(t),void(s&&t.select())}const r=t.getNodes().filter(e.INTERNAL_$isBlock).filter(e.$isElementNode),i=l?function(e,t){let n=e;for(;null!==n&&null!==n.getParent()&&!t(n);)n=n.getParentOrThrow();return t(n)?n:null}(l.getNode(),e.INTERNAL_$isBlock):null;e.$isElementNode(i)&&!r.find((e=>e.is(i)))&&r.push(i);for(const e of r){const t=n();t.setFormat(e.getFormatType()),t.setIndent(e.getIndent()),e.replace(t,!0),e.is(i)&&s&&t.select()}},exports.$shouldOverrideDefaultCharacterSelection=function(t,n){const o=e.$getAdjacentNode(t.focus,n);return e.$isDecoratorNode(o)&&!o.isIsolated()||e.$isElementNode(o)&&!o.isInline()&&!o.canBeEmpty()},exports.$sliceSelectedTextNodeContent=function(t,n){const o=t.getStartEndPoints();if(n.isSelected(t)&&!n.isSegmented()&&!n.isToken()&&null!==o){const[l,s]=o,r=t.isBackward(),i=l.getNode(),c=s.getNode(),d=n.is(i),f=n.is(c);if(d||f){const[o,l]=e.$getCharacterOffsets(t),s=i.is(c),d=n.is(r?c:i),f=n.is(r?i:c);let a,g=0;if(s)g=o>l?l:o,a=o>l?o:l;else if(d){g=r?l:o,a=void 0}else if(f){g=0,a=r?o:l}return n.__text=n.__text.slice(g,a),n}}return n},exports.$trimTextContentFromAnchor=d,exports.$wrapNodes=function(t,n,o=null){const l=t.getStartEndPoints(),s=l?l[0]:null,r=t.getNodes(),i=r.length;if(null!==s&&(0===i||1===i&&"element"===s.type&&0===s.getNode().getChildrenSize())){const e="text"===s.type?s.getNode().getParentOrThrow():s.getNode(),t=e.getChildren();let l=n();return l.setFormat(e.getFormatType()),l.setIndent(e.getIndent()),t.forEach((e=>l.append(e))),o&&(l=o.append(l)),void e.replace(l)}let c=null,d=[];for(let l=0;l<i;l++){const s=r[l];e.$isRootOrShadowRoot(s)?(p(t,d,d.length,n,o),d=[],c=s):null===c||null!==c&&e.$hasAncestor(s,c)?d.push(s):(p(t,d,d.length,n,o),d=[s])}p(t,d,d.length,n,o)},exports.createDOMRange=function(t,n,o,r,i){const c=n.getKey(),d=r.getKey(),f=document.createRange();let a=t.getElementByKey(c),g=t.getElementByKey(d),u=o,p=i;if(e.$isTextNode(n)&&(a=l(a)),e.$isTextNode(r)&&(g=l(g)),void 0===n||void 0===r||null===a||null===g)return null;"BR"===a.nodeName&&([a,u]=s(a)),"BR"===g.nodeName&&([g,p]=s(g));const h=a.firstChild;a===g&&null!=h&&"BR"===h.nodeName&&0===u&&0===p&&(p=1);try{f.setStart(a,u),f.setEnd(g,p)}catch(e){return null}return!f.collapsed||u===p&&c===d||(f.setStart(g,p),f.setEnd(a,u)),f},exports.createRectsFromDOMRange=function(e,t){const n=e.getRootElement();if(null===n)return[];const o=n.getBoundingClientRect(),l=getComputedStyle(n),s=parseFloat(l.paddingLeft)+parseFloat(l.paddingRight),r=Array.from(t.getClientRects());let i,c=r.length;r.sort(((e,t)=>{const n=e.top-t.top;return Math.abs(n)<=3?e.left-t.left:n}));for(let e=0;e<c;e++){const t=r[e],n=i&&i.top<=t.top&&i.top+i.height>t.top&&i.left+i.width>t.left,l=t.width+s===o.width;n||l?(r.splice(e--,1),c--):i=t}return r},exports.getCSSFromStyleObject=c,exports.getStyleObjectFromCSS=i,exports.trimTextContentFromAnchor=x;
|
|
9
|
+
"use strict";var e=require("lexical");function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var n=t((function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;e<arguments.length;e++)t.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${t} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));const o=new Map;function s(e){let t=e;for(;null!=t;){if(t.nodeType===Node.TEXT_NODE)return t;t=t.firstChild}return null}function r(e){const t=e.parentNode;if(null==t)throw new Error("Should never happen");return[t,Array.from(t.childNodes).indexOf(e)]}function l(e){const t={};if(!e)return t;const n=e.split(";");for(const e of n)if(""!==e){const[n,o]=e.split(/:([^]+)/);n&&o&&(t[n.trim()]=o.trim())}return t}function i(e){let t=o.get(e);return void 0===t&&(t=l(e),o.set(e,t)),t}function c(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function f(t,n,o){let s=n.getNode(),r=o;if(e.$isElementNode(s)){const e=s.getDescendantByIndex(n.offset);null!==e&&(s=e)}for(;r>0&&null!==s;){if(e.$isElementNode(s)){const e=s.getLastDescendant();null!==e&&(s=e)}let o=s.getPreviousSibling(),l=0;if(null===o){let e=s.getParentOrThrow(),t=e.getPreviousSibling();for(;null===t;){if(e=e.getParent(),null===e){o=null;break}t=e.getPreviousSibling()}null!==e&&(l=e.isInline()?0:2,o=t)}let i=s.getTextContent();""===i&&e.$isElementNode(s)&&!s.isInline()&&(i="\n\n");const c=i.length;if(!e.$isTextNode(s)||r>=c){const t=s.getParent();s.remove(),null==t||0!==t.getChildrenSize()||e.$isRootNode(t)||t.remove(),r-=c+l,s=o}else{const o=s.getKey(),l=t.getEditorState().read((()=>{const t=e.$getNodeByKey(o);return e.$isTextNode(t)&&t.isSimpleText()?t.getTextContent():null})),f=c-r,a=i.slice(0,f);if(null!==l&&l!==i){const t=e.$getPreviousSelection();let n=s;if(s.isSimpleText())s.setTextContent(l);else{const t=e.$createTextNode(l);s.replace(t),n=t}if(e.$isRangeSelection(t)&&t.isCollapsed()){const e=t.anchor.offset;n.select(e,e)}}else if(s.isSimpleText()){const e=n.key===o;let t=n.offset;t<r&&(t=c);const l=e?t-r:0,i=e?t:f;if(e&&0===l){const[e]=s.splitText(l,i);e.remove()}else{const[,e]=s.splitText(l,i);e.remove()}}else{const t=e.$createTextNode(a);s.replace(t)}r=0}}}function a(t,s){t instanceof e.TextNode||t.isCollapsed()||n(269);const r=i(t instanceof e.TextNode?t.getStyle():t.style),l=Object.entries(s).reduce(((e,[n,o])=>("function"==typeof o?e[n]=o(r[n],t):null===o?delete e[n]:e[n]=o,e)),{...r}),f=c(l);t.setStyle(f),o.set(f,l)}function d(t){const n=e.$getSelection();if(!n)return;const o=new Map;if(e.$isRangeSelection(n))for(const t of e.$caretRangeFromSelection(n).getTextSlices())t&&o.set(t.caret.origin.getKey(),t.getSliceIndices());const s=n.getNodes();for(const n of s){if(!e.$isTextNode(n)||!n.canHaveFormat())continue;const[s,l]=(r=n,o.get(r.getKey())||[0,r.getTextContentSize()]);if(l!==s)if(e.$isTokenOrSegmented(n)||0===s&&l===n.getTextContentSize())t(n);else{t(n.splitText(s,l)[0===s?0:1])}}var r;e.$isRangeSelection(n)&&"text"===n.anchor.type&&"text"===n.focus.type&&n.anchor.key===n.focus.key&&u(n)}function u(e){if(e.isBackward()){const{anchor:t,focus:n}=e,{key:o,offset:s,type:r}=t;t.set(n.key,n.offset,n.type),n.set(o,s,r)}}function g(e,t){const n=e.getFormatType(),o=e.getIndent();n!==t.getFormatType()&&t.setFormat(n),o!==t.getIndent()&&t.setIndent(o)}function p(e){return e.getNode().isAttached()}function h(t){let n=t;for(;null!==n&&!e.$isRootOrShadowRoot(n);){const e=n.getLatest(),t=n.getParent();0===e.getChildrenSize()&&n.remove(!0),n=t}}function y(t,o,s,r,l=null){if(0===o.length)return;const i=o[0],c=new Map,f=[];let a=e.$isElementNode(i)?i:i.getParentOrThrow();a.isInline()&&(a=a.getParentOrThrow());let d=!1;for(;null!==a;){const t=a.getPreviousSibling();if(null!==t){a=t,d=!0;break}if(a=a.getParentOrThrow(),e.$isRootOrShadowRoot(a))break}const u=new Set;for(let t=0;t<s;t++){const n=o[t];e.$isElementNode(n)&&0===n.getChildrenSize()&&u.add(n.getKey())}const g=new Set;for(let t=0;t<s;t++){const s=o[t];let l=s.getParent();if(null!==l&&l.isInline()&&(l=l.getParent()),null!==l&&e.$isLeafNode(s)&&!g.has(s.getKey())){const t=l.getKey();if(void 0===c.get(t)){const n=r();n.setFormat(l.getFormatType()),n.setIndent(l.getIndent()),f.push(n),c.set(t,n),l.getChildren().forEach((t=>{n.append(t),g.add(t.getKey()),e.$isElementNode(t)&&t.getChildrenKeys().forEach((e=>g.add(e)))})),h(l)}}else if(u.has(s.getKey())){e.$isElementNode(s)||n(179);const t=r();t.setFormat(s.getFormatType()),t.setIndent(s.getIndent()),f.push(t),s.remove(!0)}}if(null!==l)for(let e=0;e<f.length;e++){const t=f[e];l.append(t)}let y=null;if(e.$isRootOrShadowRoot(a))if(d)if(null!==l)a.insertAfter(l);else for(let e=f.length-1;e>=0;e--){const t=f[e];a.insertAfter(t)}else{const t=a.getFirstChild();if(e.$isElementNode(t)&&(a=t),null===t)if(l)a.append(l);else for(let e=0;e<f.length;e++){const t=f[e];a.append(t),y=t}else if(null!==l)t.insertBefore(l);else for(let e=0;e<f.length;e++){const n=f[e];t.insertBefore(n),y=n}}else if(l)a.insertAfter(l);else for(let e=f.length-1;e>=0;e--){const t=f[e];a.insertAfter(t),y=t}const $=e.$getPreviousSelection();e.$isRangeSelection($)&&p($.anchor)&&p($.focus)?e.$setSelection($.clone()):null!==y?y.selectEnd():t.dirty=!0}function $(e,t,n,o){e.modify(t?"extend":"move",n,o)}function S(t){const n=t.anchor.getNode();return"rtl"===(e.$isRootNode(n)?n:n.getParentOrThrow()).getDirection()}function m(e,t,n){const o=i(e.getStyle());return null!==o&&o[t]||n}function N(e,t){let n=e;for(;null!==n&&null!==n.getParent()&&!t(n);)n=n.getParentOrThrow();return t(n)?n:null}const x=f;exports.$cloneWithProperties=e.$cloneWithProperties,exports.$selectAll=e.$selectAll,exports.$addNodeStyle=function(e){const t=e.getStyle(),n=l(t);o.set(t,n)},exports.$copyBlockFormatIndent=g,exports.$ensureForwardRangeSelection=u,exports.$forEachSelectedTextNode=d,exports.$getSelectionStyleValueForProperty=function(t,n,o=""){let s=null;const r=t.getNodes(),l=t.anchor,c=t.focus,f=t.isBackward(),a=f?c.offset:l.offset,d=f?c.getNode():l.getNode();if(e.$isRangeSelection(t)&&t.isCollapsed()&&""!==t.style){const e=i(t.style);if(null!==e&&n in e)return e[n]}for(let t=0;t<r.length;t++){const l=r[t];if((0===t||0!==a||!l.is(d))&&e.$isTextNode(l)){const e=m(l,n,o);if(null===s)s=e;else if(s!==e){s="";break}}}return null===s?o:s},exports.$isAtNodeEnd=function(t){if("text"===t.type)return t.offset===t.getNode().getTextContentSize();const o=t.getNode();return e.$isElementNode(o)||n(177),t.offset===o.getChildrenSize()},exports.$isParentElementRTL=S,exports.$moveCaretSelection=$,exports.$moveCharacter=function(e,t,n){const o=S(e);$(e,t,n?!o:o,"character")},exports.$patchStyleText=function(t,n){if(e.$isRangeSelection(t)&&t.isCollapsed())return a(t,n);d((e=>{a(e,n)}))},exports.$setBlocksType=function(t,n,o=g){if(null===t)return;const s=t.getStartEndPoints(),r=new Map;let l=null;if(s){const[t,n]=s;l=e.$createRangeSelection(),l.anchor.set(t.key,t.offset,t.type),l.focus.set(n.key,n.offset,n.type);const o=N(t.getNode(),e.INTERNAL_$isBlock),i=N(n.getNode(),e.INTERNAL_$isBlock);e.$isElementNode(o)&&r.set(o.getKey(),o),e.$isElementNode(i)&&r.set(i.getKey(),i)}for(const n of t.getNodes())e.$isElementNode(n)&&e.INTERNAL_$isBlock(n)&&r.set(n.getKey(),n);for(const[e,t]of r){const s=n();o(t,s),t.replace(s,!0),l&&(e===l.anchor.key&&(l.anchor.key=s.getKey()),e===l.focus.key&&(l.focus.key=s.getKey()))}l&&t.is(e.$getSelection())&&e.$setSelection(l)},exports.$shouldOverrideDefaultCharacterSelection=function(t,n){const o=e.$getAdjacentNode(t.focus,n);return e.$isDecoratorNode(o)&&!o.isIsolated()||e.$isElementNode(o)&&!o.isInline()&&!o.canBeEmpty()},exports.$sliceSelectedTextNodeContent=function(t,n){const o=t.getStartEndPoints();if(n.isSelected(t)&&!n.isSegmented()&&!n.isToken()&&null!==o){const[s,r]=o,l=t.isBackward(),i=s.getNode(),c=r.getNode(),f=n.is(i),a=n.is(c);if(f||a){const[o,s]=e.$getCharacterOffsets(t),r=i.is(c),f=n.is(l?c:i),a=n.is(l?i:c);let d,u=0;if(r)u=o>s?s:o,d=o>s?o:s;else if(f){u=l?s:o,d=void 0}else if(a){u=0,d=l?o:s}return n.__text=n.__text.slice(u,d),n}}return n},exports.$trimTextContentFromAnchor=f,exports.$wrapNodes=function(t,n,o=null){const s=t.getStartEndPoints(),r=s?s[0]:null,l=t.getNodes(),i=l.length;if(null!==r&&(0===i||1===i&&"element"===r.type&&0===r.getNode().getChildrenSize())){const e="text"===r.type?r.getNode().getParentOrThrow():r.getNode(),t=e.getChildren();let s=n();return s.setFormat(e.getFormatType()),s.setIndent(e.getIndent()),t.forEach((e=>s.append(e))),o&&(s=o.append(s)),void e.replace(s)}let c=null,f=[];for(let s=0;s<i;s++){const r=l[s];e.$isRootOrShadowRoot(r)?(y(t,f,f.length,n,o),f=[],c=r):null===c||null!==c&&e.$hasAncestor(r,c)?f.push(r):(y(t,f,f.length,n,o),f=[r])}y(t,f,f.length,n,o)},exports.createDOMRange=function(t,n,o,l,i){const c=n.getKey(),f=l.getKey(),a=document.createRange();let d=t.getElementByKey(c),u=t.getElementByKey(f),g=o,p=i;if(e.$isTextNode(n)&&(d=s(d)),e.$isTextNode(l)&&(u=s(u)),void 0===n||void 0===l||null===d||null===u)return null;"BR"===d.nodeName&&([d,g]=r(d)),"BR"===u.nodeName&&([u,p]=r(u));const h=d.firstChild;d===u&&null!=h&&"BR"===h.nodeName&&0===g&&0===p&&(p=1);try{a.setStart(d,g),a.setEnd(u,p)}catch(e){return null}return!a.collapsed||g===p&&c===f||(a.setStart(u,p),a.setEnd(d,g)),a},exports.createRectsFromDOMRange=function(e,t){const n=e.getRootElement();if(null===n)return[];const o=n.getBoundingClientRect(),s=getComputedStyle(n),r=parseFloat(s.paddingLeft)+parseFloat(s.paddingRight),l=Array.from(t.getClientRects());let i,c=l.length;l.sort(((e,t)=>{const n=e.top-t.top;return Math.abs(n)<=3?e.left-t.left:n}));for(let e=0;e<c;e++){const t=l[e],n=i&&i.top<=t.top&&i.top+i.height>t.top&&i.left+i.width>t.left,s=t.width+r===o.width;n||s?(l.splice(e--,1),c--):i=t}return l},exports.getCSSFromStyleObject=c,exports.getStyleObjectFromCSS=i,exports.trimTextContentFromAnchor=x;
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import{$isTextNode as e,$getCharacterOffsets as t,$isElementNode as n,$isRootNode as
|
|
9
|
+
import{$isTextNode as e,$getCharacterOffsets as t,$isElementNode as n,$isRootNode as o,$getNodeByKey as l,$getPreviousSelection as r,$createTextNode as s,$isRangeSelection as i,$getSelection as c,$caretRangeFromSelection as f,$isTokenOrSegmented as u,TextNode as a,$createRangeSelection as g,INTERNAL_$isBlock as d,$setSelection as p,$isRootOrShadowRoot as h,$hasAncestor as y,$isLeafNode as m,$getAdjacentNode as S,$isDecoratorNode as T}from"lexical";export{$cloneWithProperties,$selectAll}from"lexical";function x(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var v=x((function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;e<arguments.length;e++)t.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${t} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));const w=new Map;function N(e){let t=e;for(;null!=t;){if(t.nodeType===Node.TEXT_NODE)return t;t=t.firstChild}return null}function C(e){const t=e.parentNode;if(null==t)throw new Error("Should never happen");return[t,Array.from(t.childNodes).indexOf(e)]}function P(t,n,o,l,r){const s=n.getKey(),i=l.getKey(),c=document.createRange();let f=t.getElementByKey(s),u=t.getElementByKey(i),a=o,g=r;if(e(n)&&(f=N(f)),e(l)&&(u=N(u)),void 0===n||void 0===l||null===f||null===u)return null;"BR"===f.nodeName&&([f,a]=C(f)),"BR"===u.nodeName&&([u,g]=C(u));const d=f.firstChild;f===u&&null!=d&&"BR"===d.nodeName&&0===a&&0===g&&(g=1);try{c.setStart(f,a),c.setEnd(u,g)}catch(e){return null}return!c.collapsed||a===g&&s===i||(c.setStart(u,g),c.setEnd(f,a)),c}function k(e,t){const n=e.getRootElement();if(null===n)return[];const o=n.getBoundingClientRect(),l=getComputedStyle(n),r=parseFloat(l.paddingLeft)+parseFloat(l.paddingRight),s=Array.from(t.getClientRects());let i,c=s.length;s.sort(((e,t)=>{const n=e.top-t.top;return Math.abs(n)<=3?e.left-t.left:n}));for(let e=0;e<c;e++){const t=s[e],n=i&&i.top<=t.top&&i.top+i.height>t.top&&i.left+i.width>t.left,l=t.width+r===o.width;n||l?(s.splice(e--,1),c--):i=t}return s}function E(e){const t={};if(!e)return t;const n=e.split(";");for(const e of n)if(""!==e){const[n,o]=e.split(/:([^]+)/);n&&o&&(t[n.trim()]=o.trim())}return t}function K(e){let t=w.get(e);return void 0===t&&(t=E(e),w.set(e,t)),t}function I(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function B(e,n){const o=e.getStartEndPoints();if(n.isSelected(e)&&!n.isSegmented()&&!n.isToken()&&null!==o){const[l,r]=o,s=e.isBackward(),i=l.getNode(),c=r.getNode(),f=n.is(i),u=n.is(c);if(f||u){const[o,l]=t(e),r=i.is(c),f=n.is(s?c:i),u=n.is(s?i:c);let a,g=0;if(r)g=o>l?l:o,a=o>l?o:l;else if(f){g=s?l:o,a=void 0}else if(u){g=0,a=s?o:l}return n.__text=n.__text.slice(g,a),n}}return n}function F(e){if("text"===e.type)return e.offset===e.getNode().getTextContentSize();const t=e.getNode();return n(t)||v(177),e.offset===t.getChildrenSize()}function O(t,c,f){let u=c.getNode(),a=f;if(n(u)){const e=u.getDescendantByIndex(c.offset);null!==e&&(u=e)}for(;a>0&&null!==u;){if(n(u)){const e=u.getLastDescendant();null!==e&&(u=e)}let f=u.getPreviousSibling(),g=0;if(null===f){let e=u.getParentOrThrow(),t=e.getPreviousSibling();for(;null===t;){if(e=e.getParent(),null===e){f=null;break}t=e.getPreviousSibling()}null!==e&&(g=e.isInline()?0:2,f=t)}let d=u.getTextContent();""===d&&n(u)&&!u.isInline()&&(d="\n\n");const p=d.length;if(!e(u)||a>=p){const e=u.getParent();u.remove(),null==e||0!==e.getChildrenSize()||o(e)||e.remove(),a-=p+g,u=f}else{const n=u.getKey(),o=t.getEditorState().read((()=>{const t=l(n);return e(t)&&t.isSimpleText()?t.getTextContent():null})),f=p-a,g=d.slice(0,f);if(null!==o&&o!==d){const e=r();let t=u;if(u.isSimpleText())u.setTextContent(o);else{const e=s(o);u.replace(e),t=e}if(i(e)&&e.isCollapsed()){const n=e.anchor.offset;t.select(n,n)}}else if(u.isSimpleText()){const e=c.key===n;let t=c.offset;t<a&&(t=p);const o=e?t-a:0,l=e?t:f;if(e&&0===o){const[e]=u.splitText(o,l);e.remove()}else{const[,e]=u.splitText(o,l);e.remove()}}else{const e=s(g);u.replace(e)}a=0}}}function b(e){const t=e.getStyle(),n=E(t);w.set(t,n)}function R(e,t){e instanceof a||e.isCollapsed()||v(269);const n=K(e instanceof a?e.getStyle():e.style),o=Object.entries(t).reduce(((t,[o,l])=>("function"==typeof l?t[o]=l(n[o],e):null===l?delete t[o]:t[o]=l,t)),{...n}),l=I(o);e.setStyle(l),w.set(l,o)}function z(e,t){if(i(e)&&e.isCollapsed())return R(e,t);A((e=>{R(e,t)}))}function A(t){const n=c();if(!n)return;const o=new Map;if(i(n))for(const e of f(n).getTextSlices())e&&o.set(e.caret.origin.getKey(),e.getSliceIndices());const l=n.getNodes();for(const n of l){if(!e(n)||!n.canHaveFormat())continue;const[l,s]=(r=n,o.get(r.getKey())||[0,r.getTextContentSize()]);if(s!==l)if(u(n)||0===l&&s===n.getTextContentSize())t(n);else{t(n.splitText(l,s)[0===l?0:1])}}var r;i(n)&&"text"===n.anchor.type&&"text"===n.focus.type&&n.anchor.key===n.focus.key&&M(n)}function M(e){if(e.isBackward()){const{anchor:t,focus:n}=e,{key:o,offset:l,type:r}=t;t.set(n.key,n.offset,n.type),n.set(o,l,r)}}function _(e,t){const n=e.getFormatType(),o=e.getIndent();n!==t.getFormatType()&&t.setFormat(n),o!==t.getIndent()&&t.setIndent(o)}function $(e,t,o=_){if(null===e)return;const l=e.getStartEndPoints(),r=new Map;let s=null;if(l){const[e,t]=l;s=g(),s.anchor.set(e.key,e.offset,e.type),s.focus.set(t.key,t.offset,t.type);const o=Q(e.getNode(),d),i=Q(t.getNode(),d);n(o)&&r.set(o.getKey(),o),n(i)&&r.set(i.getKey(),i)}for(const t of e.getNodes())n(t)&&d(t)&&r.set(t.getKey(),t);for(const[e,n]of r){const l=t();o(n,l),n.replace(l,!0),s&&(e===s.anchor.key&&(s.anchor.key=l.getKey()),e===s.focus.key&&(s.focus.key=l.getKey()))}s&&e.is(c())&&p(s)}function L(e){return e.getNode().isAttached()}function D(e){let t=e;for(;null!==t&&!h(t);){const e=t.getLatest(),n=t.getParent();0===e.getChildrenSize()&&t.remove(!0),t=n}}function j(e,t,n=null){const o=e.getStartEndPoints(),l=o?o[0]:null,r=e.getNodes(),s=r.length;if(null!==l&&(0===s||1===s&&"element"===l.type&&0===l.getNode().getChildrenSize())){const e="text"===l.type?l.getNode().getParentOrThrow():l.getNode(),o=e.getChildren();let r=t();return r.setFormat(e.getFormatType()),r.setIndent(e.getIndent()),o.forEach((e=>r.append(e))),n&&(r=n.append(r)),void e.replace(r)}let i=null,c=[];for(let o=0;o<s;o++){const l=r[o];h(l)?(H(e,c,c.length,t,n),c=[],i=l):null===i||null!==i&&y(l,i)?c.push(l):(H(e,c,c.length,t,n),c=[l])}H(e,c,c.length,t,n)}function H(e,t,o,l,s=null){if(0===t.length)return;const c=t[0],f=new Map,u=[];let a=n(c)?c:c.getParentOrThrow();a.isInline()&&(a=a.getParentOrThrow());let g=!1;for(;null!==a;){const e=a.getPreviousSibling();if(null!==e){a=e,g=!0;break}if(a=a.getParentOrThrow(),h(a))break}const d=new Set;for(let e=0;e<o;e++){const o=t[e];n(o)&&0===o.getChildrenSize()&&d.add(o.getKey())}const y=new Set;for(let e=0;e<o;e++){const o=t[e];let r=o.getParent();if(null!==r&&r.isInline()&&(r=r.getParent()),null!==r&&m(o)&&!y.has(o.getKey())){const e=r.getKey();if(void 0===f.get(e)){const t=l();t.setFormat(r.getFormatType()),t.setIndent(r.getIndent()),u.push(t),f.set(e,t),r.getChildren().forEach((e=>{t.append(e),y.add(e.getKey()),n(e)&&e.getChildrenKeys().forEach((e=>y.add(e)))})),D(r)}}else if(d.has(o.getKey())){n(o)||v(179);const e=l();e.setFormat(o.getFormatType()),e.setIndent(o.getIndent()),u.push(e),o.remove(!0)}}if(null!==s)for(let e=0;e<u.length;e++){const t=u[e];s.append(t)}let S=null;if(h(a))if(g)if(null!==s)a.insertAfter(s);else for(let e=u.length-1;e>=0;e--){const t=u[e];a.insertAfter(t)}else{const e=a.getFirstChild();if(n(e)&&(a=e),null===e)if(s)a.append(s);else for(let e=0;e<u.length;e++){const t=u[e];a.append(t),S=t}else if(null!==s)e.insertBefore(s);else for(let t=0;t<u.length;t++){const n=u[t];e.insertBefore(n),S=n}}else if(s)a.insertAfter(s);else for(let e=u.length-1;e>=0;e--){const t=u[e];a.insertAfter(t),S=t}const T=r();i(T)&&L(T.anchor)&&L(T.focus)?p(T.clone()):null!==S?S.selectEnd():e.dirty=!0}function U(e,t){const o=S(e.focus,t);return T(o)&&!o.isIsolated()||n(o)&&!o.isInline()&&!o.canBeEmpty()}function W(e,t,n,o){e.modify(t?"extend":"move",n,o)}function X(e){const t=e.anchor.getNode();return"rtl"===(o(t)?t:t.getParentOrThrow()).getDirection()}function q(e,t,n){const o=X(e);W(e,t,n?!o:o,"character")}function G(e,t,n){const o=K(e.getStyle());return null!==o&&o[t]||n}function J(t,n,o=""){let l=null;const r=t.getNodes(),s=t.anchor,c=t.focus,f=t.isBackward(),u=f?c.offset:s.offset,a=f?c.getNode():s.getNode();if(i(t)&&t.isCollapsed()&&""!==t.style){const e=K(t.style);if(null!==e&&n in e)return e[n]}for(let t=0;t<r.length;t++){const s=r[t];if((0===t||0!==u||!s.is(a))&&e(s)){const e=G(s,n,o);if(null===l)l=e;else if(l!==e){l="";break}}}return null===l?o:l}function Q(e,t){let n=e;for(;null!==n&&null!==n.getParent()&&!t(n);)n=n.getParentOrThrow();return t(n)?n:null}const V=O;export{b as $addNodeStyle,_ as $copyBlockFormatIndent,M as $ensureForwardRangeSelection,A as $forEachSelectedTextNode,J as $getSelectionStyleValueForProperty,F as $isAtNodeEnd,X as $isParentElementRTL,W as $moveCaretSelection,q as $moveCharacter,z as $patchStyleText,$ as $setBlocksType,U as $shouldOverrideDefaultCharacterSelection,B as $sliceSelectedTextNodeContent,O as $trimTextContentFromAnchor,j as $wrapNodes,P as createDOMRange,k as createRectsFromDOMRange,I as getCSSFromStyleObject,K as getStyleObjectFromCSS,V as trimTextContentFromAnchor};
|
package/index.d.ts
CHANGED
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
import { $
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { $trimTextContentFromAnchor } from './lexical-node';
|
|
9
|
+
export { $addNodeStyle, $ensureForwardRangeSelection, $forEachSelectedTextNode, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor, } from './lexical-node';
|
|
10
|
+
export { $copyBlockFormatIndent, $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $wrapNodes, } from './range-selection';
|
|
11
|
+
export { createDOMRange, createRectsFromDOMRange, getCSSFromStyleObject, getStyleObjectFromCSS, } from './utils';
|
|
12
|
+
/** @deprecated renamed to {@link $trimTextContentFromAnchor} by @lexical/eslint-plugin rules-of-lexical */
|
|
13
|
+
export declare const trimTextContentFromAnchor: typeof $trimTextContentFromAnchor;
|
|
11
14
|
export {
|
|
12
15
|
/** @deprecated moved to the lexical package */ $cloneWithProperties,
|
|
13
16
|
/** @deprecated moved to the lexical package */ $selectAll, } from 'lexical';
|
|
14
|
-
export { $addNodeStyle, $forEachSelectedTextNode, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor, };
|
|
15
|
-
/** @deprecated renamed to {@link $trimTextContentFromAnchor} by @lexical/eslint-plugin rules-of-lexical */
|
|
16
|
-
export declare const trimTextContentFromAnchor: typeof $trimTextContentFromAnchor;
|
|
17
|
-
export { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $wrapNodes, };
|
|
18
|
-
export { createDOMRange, createRectsFromDOMRange, getCSSFromStyleObject, getStyleObjectFromCSS, };
|
package/lexical-node.d.ts
CHANGED
|
@@ -34,6 +34,15 @@ export declare function $trimTextContentFromAnchor(editor: LexicalEditor, anchor
|
|
|
34
34
|
* @param node - The TextNode to add styles to.
|
|
35
35
|
*/
|
|
36
36
|
export declare function $addNodeStyle(node: TextNode): void;
|
|
37
|
+
/**
|
|
38
|
+
* Applies the provided styles to the given TextNodes or collapsed RangeSelection.
|
|
39
|
+
* Will update partially selected TextNodes by splitting the TextNode and applying
|
|
40
|
+
* the styles to the appropriate one.
|
|
41
|
+
*
|
|
42
|
+
* @param target - The TextNode or collapsed RangeSelection to apply the styles to
|
|
43
|
+
* @param patch - The patch to apply, which can include multiple styles. \\{CSSProperty: value\\} . Can also accept a function that returns the new property value.
|
|
44
|
+
*/
|
|
45
|
+
export declare function $patchStyle(target: TextNode | RangeSelection, patch: Record<string, string | null | ((currentStyleValue: string | null, _target: typeof target) => string)>): void;
|
|
37
46
|
/**
|
|
38
47
|
* Applies the provided styles to the TextNodes in the provided Selection.
|
|
39
48
|
* Will update partially selected TextNodes by splitting the TextNode and applying
|
|
@@ -43,3 +52,13 @@ export declare function $addNodeStyle(node: TextNode): void;
|
|
|
43
52
|
*/
|
|
44
53
|
export declare function $patchStyleText(selection: BaseSelection, patch: Record<string, string | null | ((currentStyleValue: string | null, target: TextNode | RangeSelection) => string)>): void;
|
|
45
54
|
export declare function $forEachSelectedTextNode(fn: (textNode: TextNode) => void): void;
|
|
55
|
+
/**
|
|
56
|
+
* Ensure that the given RangeSelection is not backwards. If it
|
|
57
|
+
* is backwards, then the anchor and focus points will be swapped
|
|
58
|
+
* in-place. Ensuring that the selection is a writable RangeSelection
|
|
59
|
+
* is the responsibility of the caller (e.g. in a read-only context
|
|
60
|
+
* you will want to clone $getSelection() before using this).
|
|
61
|
+
*
|
|
62
|
+
* @param selection a writable RangeSelection
|
|
63
|
+
*/
|
|
64
|
+
export declare function $ensureForwardRangeSelection(selection: RangeSelection): void;
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"selection"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "0.24.0",
|
|
12
|
+
"version": "0.24.1-nightly.20250211.0",
|
|
13
13
|
"main": "LexicalSelection.js",
|
|
14
14
|
"types": "index.d.ts",
|
|
15
15
|
"repository": {
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"lexical": "0.24.0"
|
|
40
|
+
"lexical": "0.24.1-nightly.20250211.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/range-selection.d.ts
CHANGED
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { BaseSelection, ElementNode, LexicalNode, RangeSelection } from 'lexical';
|
|
9
9
|
import { TableSelection } from '@lexical/table';
|
|
10
|
+
export declare function $copyBlockFormatIndent(srcNode: ElementNode, destNode: ElementNode): void;
|
|
10
11
|
/**
|
|
11
12
|
* Converts all nodes in the selection that are of one block type to another.
|
|
12
13
|
* @param selection - The selected blocks to be converted.
|
|
13
|
-
* @param createElement - The function that creates the node. eg. $createParagraphNode.
|
|
14
|
+
* @param $createElement - The function that creates the node. eg. $createParagraphNode.
|
|
15
|
+
* @param $afterCreateElement - The function that updates the new node based on the previous one ($copyBlockFormatIndent by default)
|
|
14
16
|
*/
|
|
15
|
-
export declare function $setBlocksType(selection: BaseSelection | null, createElement: () => ElementNode): void;
|
|
17
|
+
export declare function $setBlocksType<T extends ElementNode>(selection: BaseSelection | null, $createElement: () => T, $afterCreateElement?: (prevNodeSrc: ElementNode, newNodeDest: T) => void): void;
|
|
16
18
|
/**
|
|
17
19
|
* @deprecated
|
|
18
20
|
* Wraps all nodes in the selection into another node of the type returned by createElement.
|