All files / Rindu/components/TextHighlighter TextHighlighter.tsx

85.71% Statements 12/14
100% Branches 6/6
100% Functions 3/3
85.71% Lines 12/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69              20x       20x           6x       10x             12x 8x 8x   8x 22x                                 4x 4x 4x                                
import {
  Children,
  cloneElement,
  isValidElement,
  PropsWithChildren,
  ReactElement,
  ReactNode,
} from "react";
 
import { escapeRegExp } from "lodash";
 
import { getElementProps } from "utils";
 
interface TextHighlighterProps {
  text: string;
}
 
export default function TextHighlighter({
  text,
  children,
}: PropsWithChildren<TextHighlighterProps>): ReactElement {
  if (!text) {
    return <>{children}</>;
  }
 
  return (
    <>
      {Children.map(children, (child: ReactNode) => {
        if (typeof child === "string") {
          const escapedText = escapeRegExp(text);
          const parts = child.split(new RegExp(`(${escapedText})`, "gi"));
 
          return parts.map((part, index) =>
            part.toLowerCase() === text.toLowerCase() ? (
              <mark key={`highlight-${index}`}>
                {part}
                <style jsx>{`
                  mark {
                    background-color: #2e77d0;
                    border-radius: 4px;
                    color: #fff;
                  }
                `}</style>
              </mark>
            ) : (
              part
            )
          );
        }
 
        if (isValidElement(child)) {
          const props = getElementProps(child);
          if (props.children) {
            return cloneElement(
              child,
              props,
              <TextHighlighter text={text}>{props.children}</TextHighlighter>
            );
          }
 
          return child;
        }
 
        return child;
      })}
    </>
  );
}