blog.hangerthem.com/lib/react-node-text.ts

58 lines
No EOL
2.1 KiB
TypeScript

import { cloneElement, isValidElement, type ReactNode } from "react";
/**
* Recursively traverses a ReactNode tree and extracts the text content.
* @param node - The ReactNode to process.
* @returns A string containing the concatenated text content of the ReactNode tree.
*/
export function getTextContent(node: ReactNode): string {
if (node === null || typeof node === "boolean") return "";
if (typeof node === "string" || typeof node === "number") return String(node);
if (Array.isArray(node)) return node.map(getTextContent).join("");
if (isValidElement(node)) {
const props = node.props as { children?: ReactNode };
return getTextContent(props.children);
}
return "";
}
/**
* Recursively traverses a ReactNode tree and removes leading whitespace and a specified pattern from the beginning of text nodes.
* @param node - The ReactNode to process.
* @param pattern - The regular expression pattern to match and remove from the beginning of text nodes.
* @returns A new ReactNode with the leading whitespace and specified pattern removed from text nodes.
*/
export function stripLeadingMatch(node: ReactNode, pattern: RegExp): ReactNode {
if (typeof node === "string") {
const trimmed = node.replace(/^\s+/, "");
if (pattern.test(trimmed)) {
return trimmed.replace(pattern, "").replace(/^\s+/, "");
}
return node;
}
if (Array.isArray(node)) {
let stripped = false;
return node.map((child) => {
if (stripped) return child;
if (typeof child === "string" && child.trim() === "") return child; // skip whitespace nodes
if (typeof child === "string") {
const trimmed = child.replace(/^\s+/, "");
if (pattern.test(trimmed)) {
stripped = true;
return trimmed.replace(pattern, "").replace(/^\s+/, "");
}
return child;
}
if (isValidElement(child)) {
stripped = true;
return stripLeadingMatch(child, pattern);
}
return child;
});
}
if (isValidElement(node)) {
const props = node.props as { children?: ReactNode };
return cloneElement(node, {}, stripLeadingMatch(props.children, pattern));
}
return node;
}