Openstatus
www.openstatus.dev
1"use client";
2
3import { useSearchParams } from "next/navigation";
4import { useEffect, useRef } from "react";
5
6function highlight(root: HTMLElement, query: string) {
7 if (!query) return;
8
9 const regex = new RegExp(`(${query})`, "gi");
10 const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);
11
12 const textNodes: Text[] = [];
13 let node = walker.nextNode();
14
15 while (node) {
16 if (node instanceof Text) {
17 textNodes.push(node);
18 }
19 node = walker.nextNode();
20 }
21
22 for (const textNode of textNodes) {
23 const nodeValue = textNode.nodeValue;
24 if (!nodeValue || !regex.test(nodeValue)) continue;
25
26 const span = document.createElement("span");
27 span.innerHTML = nodeValue.replace(regex, "<mark>$1</mark>");
28
29 textNode.parentNode?.replaceChild(span, textNode);
30 }
31}
32
33export function HighlightText({ children }: { children: React.ReactNode }) {
34 const ref = useRef<HTMLDivElement>(null);
35 const searchParams = useSearchParams();
36 const q = searchParams.get("q");
37
38 useEffect(() => {
39 if (ref.current && q) {
40 highlight(ref.current, q);
41 }
42 }, [q]);
43
44 return <div ref={ref}>{children}</div>;
45}