24 lines
836 B
TypeScript
24 lines
836 B
TypeScript
|
|
import { Fragment, type ReactNode } from "react";
|
||
|
|
|
||
|
|
export default function HighlightText({ text, query }: { text: unknown; query: string }): ReactNode {
|
||
|
|
const value = String(text ?? "");
|
||
|
|
if (!query) return value;
|
||
|
|
|
||
|
|
const haystack = value.toLocaleLowerCase();
|
||
|
|
const needle = query.toLocaleLowerCase();
|
||
|
|
if (!needle) return value;
|
||
|
|
|
||
|
|
const parts: ReactNode[] = [];
|
||
|
|
let start = 0;
|
||
|
|
let match = haystack.indexOf(needle, start);
|
||
|
|
while (match !== -1) {
|
||
|
|
if (match > start) parts.push(value.slice(start, match));
|
||
|
|
parts.push(<mark key={`${match}-${parts.length}`}>{value.slice(match, match + query.length)}</mark>);
|
||
|
|
start = match + query.length;
|
||
|
|
match = haystack.indexOf(needle, start);
|
||
|
|
}
|
||
|
|
if (start < value.length) parts.push(value.slice(start));
|
||
|
|
|
||
|
|
return <Fragment>{parts.length ? parts : value}</Fragment>;
|
||
|
|
}
|