I want to find text* in Lexical JS and apply a highlight style to all matches.
import {useLexicalComposerContext} from "@lexical/react/LexicalComposerContext";
import {$createRangeSelection, $getRoot, $isParagraphNode, ParagraphNode} from "lexical";
const HighlightSearchButton = () => {
const [editor] = useLexicalComposerContext();
const handleClick = async () => {
editor.update(() => {
const searchStr = 'Hello';
const regex = new RegExp(searchStr, 'gi')
const children = $getRoot().getChildren();
for (const child of children) {
if (!$isParagraphNode(child)) continue;
const paragraphNode = child as ParagraphNode;
const text = child.getTextContent();
const indexes = [];
let result;
while (result = regex.exec(text)) {
indexes.push(result.index);
}
for (const index of indexes) {
const selection = $createRangeSelection();
selection.anchor.key = paragraphNode.getKey(),
selection.anchor.offset = index,
selection.focus.key = paragraphNode.getKey(),
selection.focus.offset = index + searchStr.length
// Note: This makes the entire paragraph bold
selection.formatText('bold'); // Note: actually want to apply a css style
}
}
});
};
return <button onClick={handleClick}>Highlight Search</button>
};
export default HighlightSearchButton;
I'm trying to use $createRangeSelection
, but if I give it a paragraph node key I don't seem to have access to the anchor/focus offsets of the text.
As I've pulled out the full text with getTextContent()
I don't know what text nodes the selection range would apply to. Also If there are multiple text nodes already in the paragraph, ie bold and italics etc., I'm not sure how to manage keeping track of those.
I did have a quick look at using node transforms, again I'm not sure that'll work for what I need. It looks like you'd just get the text node that's being edited. If the node is split with existing formatting, I don't know if it'd provide all the text I need.
* I actually want to find grammatical errors with write-good
but this is a simpler example to demonstrate.