matched-hit.tsx 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { FC, useCallback, useLayoutEffect, useRef } from 'react'
  2. import { Hit, MatchedFile } from '../util/search-snapshot'
  3. import { MatchedHitHighlight } from './matched-hit-highlight'
  4. import classnames from 'classnames'
  5. export const MatchedHit: FC<{
  6. matchedFile: MatchedFile
  7. hit: Hit
  8. selected?: boolean
  9. setSelectedHit(hit?: Hit): void
  10. tabIndex: 0 | -1
  11. }> = ({ matchedFile, hit, selected = false, setSelectedHit, tabIndex }) => {
  12. const containerRef = useRef<HTMLButtonElement>(null)
  13. useLayoutEffect(() => {
  14. if (selected) {
  15. containerRef.current?.focus()
  16. }
  17. }, [selected])
  18. const handleSelect: React.MouseEventHandler = useCallback(
  19. event => {
  20. event.preventDefault()
  21. setSelectedHit(hit)
  22. },
  23. [hit, setSelectedHit]
  24. )
  25. return (
  26. <button
  27. className={classnames('list-group-item matched-file-hit', {
  28. 'matched-file-hit-selected': selected,
  29. })}
  30. ref={containerRef}
  31. tabIndex={tabIndex}
  32. onMouseDown={handleSelect}
  33. aria-selected={selected}
  34. role="option"
  35. >
  36. <span className="matched-line-number">{hit.lineIndex + 1}</span>
  37. <MatchedHitHighlight text={matchedFile.lines[hit.lineIndex]} hit={hit} />
  38. </button>
  39. )
  40. }