mirror of
https://github.com/facebook/lexical.git
synced 2025-05-17 23:26:16 +08:00
feature: expose forEachSelectedTextNode (#6981)
Co-authored-by: Bob Ippolito <bob@redivi.com>
This commit is contained in:
@ -8,6 +8,7 @@
|
||||
|
||||
import {
|
||||
$addNodeStyle,
|
||||
$forEachSelectedTextNode,
|
||||
$isAtNodeEnd,
|
||||
$patchStyleText,
|
||||
$sliceSelectedTextNodeContent,
|
||||
@ -36,6 +37,7 @@ export {
|
||||
|
||||
export {
|
||||
$addNodeStyle,
|
||||
$forEachSelectedTextNode,
|
||||
$isAtNodeEnd,
|
||||
$patchStyleText,
|
||||
$sliceSelectedTextNodeContent,
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
$getCharacterOffsets,
|
||||
$getNodeByKey,
|
||||
$getPreviousSelection,
|
||||
$getSelection,
|
||||
$isElementNode,
|
||||
$isRangeSelection,
|
||||
$isRootNode,
|
||||
@ -288,23 +289,30 @@ export function $patchStyleText(
|
||||
) => string)
|
||||
>,
|
||||
): void {
|
||||
const selectedNodes = selection.getNodes();
|
||||
const selectedNodesLength = selectedNodes.length;
|
||||
const anchorAndFocus = selection.getStartEndPoints();
|
||||
if (anchorAndFocus === null) {
|
||||
if (selection.isCollapsed() && $isRangeSelection(selection)) {
|
||||
$patchStyle(selection, patch);
|
||||
} else {
|
||||
$forEachSelectedTextNode((textNode) => {
|
||||
$patchStyle(textNode, patch);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function $forEachSelectedTextNode(
|
||||
fn: (textNode: TextNode) => void,
|
||||
): void {
|
||||
const selection = $getSelection();
|
||||
if (!$isRangeSelection(selection)) {
|
||||
return;
|
||||
}
|
||||
const [anchor, focus] = anchorAndFocus;
|
||||
const selectedNodes = selection.getNodes();
|
||||
const selectedNodesLength = selectedNodes.length;
|
||||
const {anchor, focus} = selection;
|
||||
|
||||
const lastIndex = selectedNodesLength - 1;
|
||||
let firstNode = selectedNodes[0];
|
||||
let lastNode = selectedNodes[lastIndex];
|
||||
|
||||
if (selection.isCollapsed() && $isRangeSelection(selection)) {
|
||||
$patchStyle(selection, patch);
|
||||
return;
|
||||
}
|
||||
|
||||
const firstNodeText = firstNode.getTextContent();
|
||||
const firstNodeTextLength = firstNodeText.length;
|
||||
const focusOffset = focus.offset;
|
||||
@ -355,14 +363,14 @@ export function $patchStyleText(
|
||||
$isTokenOrSegmented(firstNode) ||
|
||||
(startOffset === 0 && endOffset === firstNodeTextLength)
|
||||
) {
|
||||
$patchStyle(firstNode, patch);
|
||||
fn(firstNode);
|
||||
firstNode.select(startOffset, endOffset);
|
||||
} else {
|
||||
// The node is partially selected, so split it into two nodes
|
||||
// and style the selected one.
|
||||
const splitNodes = firstNode.splitText(startOffset, endOffset);
|
||||
const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
|
||||
$patchStyle(replacement, patch);
|
||||
fn(replacement);
|
||||
replacement.select(0, endOffset - startOffset);
|
||||
}
|
||||
} // multiple nodes selected.
|
||||
@ -383,7 +391,7 @@ export function $patchStyleText(
|
||||
}
|
||||
}
|
||||
|
||||
$patchStyle(firstNode as TextNode, patch);
|
||||
fn(firstNode as TextNode);
|
||||
}
|
||||
|
||||
if ($isTextNode(lastNode) && lastNode.canHaveFormat()) {
|
||||
@ -404,7 +412,7 @@ export function $patchStyleText(
|
||||
}
|
||||
|
||||
if (endOffset !== 0 || endType === 'element') {
|
||||
$patchStyle(lastNode as TextNode, patch);
|
||||
fn(lastNode as TextNode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +428,7 @@ export function $patchStyleText(
|
||||
selectedNodeKey !== lastNode.getKey() &&
|
||||
!selectedNode.isToken()
|
||||
) {
|
||||
$patchStyle(selectedNode, patch);
|
||||
fn(selectedNode as TextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1180,6 +1180,7 @@ export class RangeSelection implements BaseSelection {
|
||||
}
|
||||
}
|
||||
|
||||
// TO-DO: Migrate this method to the new utility function $forEachSelectedTextNode (share similar logic)
|
||||
/**
|
||||
* Applies the provided format to the TextNodes in the Selection, splitting or
|
||||
* merging nodes as necessary.
|
||||
|
Reference in New Issue
Block a user