@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.
@@ -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
- const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);
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.isCollapsed() && lexical.$isRangeSelection(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 (!lexical.$isRangeSelection(selection)) {
431
+ if (!selection) {
421
432
  return;
422
433
  }
423
- const selectedNodes = selection.getNodes();
424
- const selectedNodesLength = selectedNodes.length;
425
- const {
426
- anchor,
427
- focus
428
- } = selection;
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
- // style all the text nodes in between
515
- for (let i = 1; i < lastIndex; i++) {
516
- const selectedNode = selectedNodes[i];
517
- const selectedNodeKey = selectedNode.getKey();
518
- if (lexical.$isTextNode(selectedNode) && selectedNode.canHaveFormat() && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
519
- fn(selectedNode);
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 anchor = anchorAndFocus ? anchorAndFocus[0] : null;
545
- const isCollapsedSelection = selection.is(lexical.$getSelection()) && selection.isCollapsed();
546
- if (anchor !== null && anchor.key === 'root') {
547
- const element = createElement();
548
- const root = lexical.$getRoot();
549
- const firstChild = root.getFirstChild();
550
- if (firstChild) {
551
- firstChild.replace(element, true);
552
- } else {
553
- root.append(element);
554
- }
555
- if (isCollapsedSelection) {
556
- element.select();
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
- for (const node of nodes) {
566
- const targetElement = createElement();
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;
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import { $isTextNode, $getCharacterOffsets, $isElementNode, $isRootNode, $getNodeByKey, $getPreviousSelection, $createTextNode, $isRangeSelection, $getSelection, $isTokenOrSegmented, $getRoot, INTERNAL_$isBlock, $isRootOrShadowRoot, $hasAncestor, $isLeafNode, $setSelection, $getAdjacentNode, $isDecoratorNode } from 'lexical';
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
- const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);
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.isCollapsed() && $isRangeSelection(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 (!$isRangeSelection(selection)) {
430
+ if (!selection) {
420
431
  return;
421
432
  }
422
- const selectedNodes = selection.getNodes();
423
- const selectedNodesLength = selectedNodes.length;
424
- const {
425
- anchor,
426
- focus
427
- } = selection;
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
- // style all the text nodes in between
514
- for (let i = 1; i < lastIndex; i++) {
515
- const selectedNode = selectedNodes[i];
516
- const selectedNodeKey = selectedNode.getKey();
517
- if ($isTextNode(selectedNode) && selectedNode.canHaveFormat() && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
518
- fn(selectedNode);
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 anchor = anchorAndFocus ? anchorAndFocus[0] : null;
544
- const isCollapsedSelection = selection.is($getSelection()) && selection.isCollapsed();
545
- if (anchor !== null && anchor.key === 'root') {
546
- const element = createElement();
547
- const root = $getRoot();
548
- const firstChild = root.getFirstChild();
549
- if (firstChild) {
550
- firstChild.replace(element, true);
551
- } else {
552
- root.append(element);
553
- }
554
- if (isCollapsedSelection) {
555
- element.select();
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
- for (const node of nodes) {
565
- const targetElement = createElement();
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 };
@@ -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;
@@ -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 l,$getNodeByKey as o,$getPreviousSelection as r,$createTextNode as s,$isRangeSelection as i,$getSelection as c,$isTokenOrSegmented as f,$getRoot as u,INTERNAL_$isBlock as a,$isRootOrShadowRoot as g,$hasAncestor as d,$isLeafNode as p,$setSelection as h,$getAdjacentNode as y,$isDecoratorNode as m}from"lexical";export{$cloneWithProperties,$selectAll}from"lexical";function S(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var x=S((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 T=new Map;function v(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 N(t,n,l,o,r){const s=n.getKey(),i=o.getKey(),c=document.createRange();let f=t.getElementByKey(s),u=t.getElementByKey(i),a=l,g=r;if(e(n)&&(f=v(f)),e(o)&&(u=v(u)),void 0===n||void 0===o||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 P(e,t){const n=e.getRootElement();if(null===n)return[];const l=n.getBoundingClientRect(),o=getComputedStyle(n),r=parseFloat(o.paddingLeft)+parseFloat(o.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,o=t.width+r===l.width;n||o?(s.splice(e--,1),c--):i=t}return s}function w(e){const t={};if(!e)return t;const n=e.split(";");for(const e of n)if(""!==e){const[n,l]=e.split(/:([^]+)/);n&&l&&(t[n.trim()]=l.trim())}return t}function E(e){let t=T.get(e);return void 0===t&&(t=w(e),T.set(e,t)),t}function F(e){let t="";for(const n in e)n&&(t+=`${n}: ${e[n]};`);return t}function K(e,n){const l=e.getStartEndPoints();if(n.isSelected(e)&&!n.isSegmented()&&!n.isToken()&&null!==l){const[o,r]=l,s=e.isBackward(),i=o.getNode(),c=r.getNode(),f=n.is(i),u=n.is(c);if(f||u){const[l,o]=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=l>o?o:l,a=l>o?l:o;else if(f){g=s?o:l,a=void 0}else if(u){g=0,a=s?l:o}return n.__text=n.__text.slice(g,a),n}}return n}function I(e){if("text"===e.type)return e.offset===e.getNode().getTextContentSize();const t=e.getNode();return n(t)||x(177),e.offset===t.getChildrenSize()}function k(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()||l(e)||e.remove(),a-=p+g,u=f}else{const n=u.getKey(),l=t.getEditorState().read((()=>{const t=o(n);return e(t)&&t.isSimpleText()?t.getTextContent():null})),f=p-a,g=d.slice(0,f);if(null!==l&&l!==d){const e=r();let t=u;if(u.isSimpleText())u.setTextContent(l);else{const e=s(l);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 l=e?t-a:0,o=e?t:f;if(e&&0===l){const[e]=u.splitText(l,o);e.remove()}else{const[,e]=u.splitText(l,o);e.remove()}}else{const e=s(g);u.replace(e)}a=0}}}function B(e){const t=e.getStyle(),n=w(t);T.set(t,n)}function b(e,t){const n=E("getStyle"in e?e.getStyle():e.style),l=Object.entries(t).reduce(((t,[l,o])=>("function"==typeof o?t[l]=o(n[l],e):null===o?delete t[l]:t[l]=o,t)),{...n}||{}),o=F(l);e.setStyle(o),T.set(o,l)}function O(e,t){e.isCollapsed()&&i(e)?b(e,t):R((e=>{b(e,t)}))}function R(t){const n=c();if(!i(n))return;const l=n.getNodes(),o=l.length,{anchor:r,focus:s}=n,u=o-1;let a=l[0],g=l[u];const d=a.getTextContent().length,p=s.offset;let h=r.offset;const y=r.isBefore(s);let m=y?h:p,S=y?p:h;const x=y?r.type:s.type,T=y?s.type:r.type,v=y?s.key:r.key;if(e(a)&&m===d){const t=a.getNextSibling();e(t)&&(h=0,m=0,a=t)}if(1===l.length){if(e(a)&&a.canHaveFormat()){if(m="element"===x?0:h>p?p:h,S="element"===T?d:h>p?h:p,m===S)return;if(f(a)||0===m&&S===d)t(a),a.select(m,S);else{const e=a.splitText(m,S),n=0===m?e[0]:e[1];t(n),n.select(0,S-m)}}}else{if(e(a)&&m<a.getTextContentSize()&&a.canHaveFormat()&&(0===m||f(a)||(a=a.splitText(m)[1],m=0,y?r.set(a.getKey(),m,"text"):s.set(a.getKey(),m,"text")),t(a)),e(g)&&g.canHaveFormat()){const e=g.getTextContent().length;g.__key!==v&&0!==S&&(S=e),S===e||f(g)||([g]=g.splitText(S)),0===S&&"element"!==T||t(g)}for(let n=1;n<u;n++){const o=l[n],r=o.getKey();e(o)&&o.canHaveFormat()&&r!==a.getKey()&&r!==g.getKey()&&!o.isToken()&&t(o)}}}function _(e,t){if(null===e)return;const l=e.getStartEndPoints(),o=l?l[0]:null,r=e.is(c())&&e.isCollapsed();if(null!==o&&"root"===o.key){const e=t(),n=u(),l=n.getFirstChild();return l?l.replace(e,!0):n.append(e),void(r&&e.select())}const s=e.getNodes().filter(a).filter(n),i=o?function(e,t){let n=e;for(;null!==n&&null!==n.getParent()&&!t(n);)n=n.getParentOrThrow();return t(n)?n:null}(o.getNode(),a):null;n(i)&&!s.find((e=>e.is(i)))&&s.push(i);for(const e of s){const n=t();n.setFormat(e.getFormatType()),n.setIndent(e.getIndent()),e.replace(n,!0),e.is(i)&&r&&n.select()}}function A(e){return e.getNode().isAttached()}function z(e){let t=e;for(;null!==t&&!g(t);){const e=t.getLatest(),n=t.getParent();0===e.getChildrenSize()&&t.remove(!0),t=n}}function $(e,t,n=null){const l=e.getStartEndPoints(),o=l?l[0]:null,r=e.getNodes(),s=r.length;if(null!==o&&(0===s||1===s&&"element"===o.type&&0===o.getNode().getChildrenSize())){const e="text"===o.type?o.getNode().getParentOrThrow():o.getNode(),l=e.getChildren();let r=t();return r.setFormat(e.getFormatType()),r.setIndent(e.getIndent()),l.forEach((e=>r.append(e))),n&&(r=n.append(r)),void e.replace(r)}let i=null,c=[];for(let l=0;l<s;l++){const o=r[l];g(o)?(L(e,c,c.length,t,n),c=[],i=o):null===i||null!==i&&d(o,i)?c.push(o):(L(e,c,c.length,t,n),c=[o])}L(e,c,c.length,t,n)}function L(e,t,l,o,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 d=!1;for(;null!==a;){const e=a.getPreviousSibling();if(null!==e){a=e,d=!0;break}if(a=a.getParentOrThrow(),g(a))break}const y=new Set;for(let e=0;e<l;e++){const l=t[e];n(l)&&0===l.getChildrenSize()&&y.add(l.getKey())}const m=new Set;for(let e=0;e<l;e++){const l=t[e];let r=l.getParent();if(null!==r&&r.isInline()&&(r=r.getParent()),null!==r&&p(l)&&!m.has(l.getKey())){const e=r.getKey();if(void 0===f.get(e)){const t=o();t.setFormat(r.getFormatType()),t.setIndent(r.getIndent()),u.push(t),f.set(e,t),r.getChildren().forEach((e=>{t.append(e),m.add(e.getKey()),n(e)&&e.getChildrenKeys().forEach((e=>m.add(e)))})),z(r)}}else if(y.has(l.getKey())){n(l)||x(179);const e=o();e.setFormat(l.getFormatType()),e.setIndent(l.getIndent()),u.push(e),l.remove(!0)}}if(null!==s)for(let e=0;e<u.length;e++){const t=u[e];s.append(t)}let S=null;if(g(a))if(d)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)&&A(T.anchor)&&A(T.focus)?h(T.clone()):null!==S?S.selectEnd():e.dirty=!0}function M(e,t){const l=y(e.focus,t);return m(l)&&!l.isIsolated()||n(l)&&!l.isInline()&&!l.canBeEmpty()}function D(e,t,n,l){e.modify(t?"extend":"move",n,l)}function H(e){const t=e.anchor.getNode();return"rtl"===(l(t)?t:t.getParentOrThrow()).getDirection()}function j(e,t,n){const l=H(e);D(e,t,n?!l:l,"character")}function U(e,t,n){const l=E(e.getStyle());return null!==l&&l[t]||n}function W(t,n,l=""){let o=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=E(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=U(s,n,l);if(null===o)o=e;else if(o!==e){o="";break}}}return null===o?l:o}const X=k;export{B as $addNodeStyle,R as $forEachSelectedTextNode,W as $getSelectionStyleValueForProperty,I as $isAtNodeEnd,H as $isParentElementRTL,D as $moveCaretSelection,j as $moveCharacter,O as $patchStyleText,_ as $setBlocksType,M as $shouldOverrideDefaultCharacterSelection,K as $sliceSelectedTextNodeContent,k as $trimTextContentFromAnchor,$ as $wrapNodes,N as createDOMRange,P as createRectsFromDOMRange,F as getCSSFromStyleObject,E as getStyleObjectFromCSS,X as trimTextContentFromAnchor};
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 { $addNodeStyle, $forEachSelectedTextNode, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, $trimTextContentFromAnchor } from './lexical-node';
9
- import { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $wrapNodes } from './range-selection';
10
- import { createDOMRange, createRectsFromDOMRange, getCSSFromStyleObject, getStyleObjectFromCSS } from './utils';
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
  }
@@ -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.