matched-hit-highlight.tsx 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. import React, { FC, useMemo } from 'react'
  2. import { Hit } from '../util/search-snapshot'
  3. export const MatchedHitHighlight: FC<{ text: string; hit: Hit }> = ({
  4. text,
  5. hit,
  6. }) => {
  7. const parts = useMemo(() => {
  8. let before = text.substring(0, hit.matchIndex).trimStart()
  9. const match = text.substring(hit.matchIndex, hit.matchIndex + hit.length)
  10. let after = text.substring(hit.matchIndex + hit.length).trimEnd()
  11. // reduce the prefix to a sensible size before trimming
  12. if (before.length > 250) {
  13. before = before.substring(before.length - 250)
  14. }
  15. while (before.length > 10) {
  16. const replacement = before.replace(/^\S+\s+/, '')
  17. if (before.length === replacement.length) {
  18. break
  19. }
  20. before = replacement
  21. }
  22. // reduce the suffix to a sensible size before trimming
  23. if (after.length > 250) {
  24. after = after.substring(0, 250)
  25. }
  26. while (after.length > 100) {
  27. const replacement = after.replace(/\s+\S+$/, '')
  28. if (after.length === replacement.length) {
  29. break
  30. }
  31. after = replacement
  32. }
  33. return { before, match, after }
  34. }, [hit, text])
  35. return (
  36. <span className="matched-hit-snippet">
  37. {parts.before}
  38. <b className="matched-hit-highlight">{parts.match}</b>
  39. {parts.after}
  40. </span>
  41. )
  42. }