@@ -13,7 +13,7 @@ import { Scrollbar } from "@radix-ui/react-scroll-area";
1313import CodeMirror , { Decoration , DecorationSet , EditorState , EditorView , ReactCodeMirrorRef , StateField , Transaction } from '@uiw/react-codemirror' ;
1414import clsx from "clsx" ;
1515import Image from "next/image" ;
16- import { useMemo , useRef , useState } from "react" ;
16+ import { useCallback , useMemo , useRef , useState } from "react" ;
1717
1818const MAX_MATCHES_TO_PREVIEW = 3 ;
1919
@@ -38,9 +38,11 @@ export const SearchResultsPanel = ({
3838 }
3939
4040 return (
41- < ScrollArea className = "h-full" >
41+ < ScrollArea
42+ className = "h-full"
43+ >
4244 { fileMatches . map ( ( fileMatch , index ) => (
43- < FilePreview
45+ < FileMatchContainer
4446 key = { index }
4547 file = { fileMatch }
4648 onOpenFile = { ( ) => {
@@ -56,17 +58,17 @@ export const SearchResultsPanel = ({
5658 )
5759}
5860
59- interface FilePreviewProps {
61+ interface FileMatchContainerProps {
6062 file : SearchResultFile ;
6163 onOpenFile : ( ) => void ;
6264 onMatchIndexChanged : ( matchIndex : number ) => void ;
6365}
6466
65- const FilePreview = ( {
67+ const FileMatchContainer = ( {
6668 file,
6769 onOpenFile,
6870 onMatchIndexChanged,
69- } : FilePreviewProps ) => {
71+ } : FileMatchContainerProps ) => {
7072
7173 const [ showAll , setShowAll ] = useState ( false ) ;
7274 const matchCount = useMemo ( ( ) => {
@@ -124,6 +126,19 @@ const FilePreview = ({
124126 return matchCount > MAX_MATCHES_TO_PREVIEW ;
125127 } , [ matchCount ] ) ;
126128
129+ const onShowMoreMatches = useCallback ( ( ) => {
130+ setShowAll ( ! showAll ) ;
131+ } , [ showAll ] ) ;
132+
133+ const onOpenMatch = useCallback ( ( index : number ) => {
134+ const matchIndex = matches . slice ( 0 , index ) . reduce ( ( acc , match ) => {
135+ return acc + match . Ranges . length ;
136+ } , 0 ) ;
137+ onOpenFile ( ) ;
138+ onMatchIndexChanged ( matchIndex ) ;
139+ } , [ matches , onMatchIndexChanged , onOpenFile ] ) ;
140+
141+
127142 return (
128143 < div >
129144 < div
@@ -148,7 +163,7 @@ const FilePreview = ({
148163 </ span >
149164 < span > ·</ span >
150165 { ! fileNameRange ? (
151- < span > { file . FileName } </ span >
166+ < span > { file . FileName } </ span >
152167 ) : (
153168 < span >
154169 { file . FileName . slice ( 0 , fileNameRange . from ) }
@@ -173,31 +188,45 @@ const FilePreview = ({
173188 return (
174189 < div
175190 key = { index }
176- className = "cursor-pointer"
177- onClick = { ( ) => {
178- const matchIndex = matches . slice ( 0 , index ) . reduce ( ( acc , match ) => {
179- return acc + match . Ranges . length ;
180- } , 0 ) ;
181- onOpenFile ( ) ;
182- onMatchIndexChanged ( matchIndex ) ;
183- } }
184191 >
185- < CodePreview
186- content = { content }
187- language = { file . Language }
188- ranges = { match . Ranges }
189- lineOffset = { lineOffset }
190- />
192+ < div
193+ tabIndex = { 0 }
194+ className = "cursor-pointer p-1 focus:ring-inset focus:ring-4 bg-white dark:bg-[#282c34]"
195+ onKeyDown = { ( e ) => {
196+ if ( e . key !== "Enter" ) {
197+ return ;
198+ }
199+ onOpenMatch ( index ) ;
200+ } }
201+ onClick = { ( ) => onOpenMatch ( index ) }
202+ >
203+ < CodePreview
204+ content = { content }
205+ language = { file . Language }
206+ ranges = { match . Ranges }
207+ lineOffset = { lineOffset }
208+ />
209+ </ div >
210+
191211 { ( index !== matches . length - 1 || isMoreContentButtonVisible ) && (
192212 < Separator className = "dark:bg-gray-400" />
193213 ) }
194214 </ div >
195215 ) ;
196216 } ) }
197217 { isMoreContentButtonVisible && (
198- < div className = "px-4 bg-accent" >
218+ < div
219+ tabIndex = { 0 }
220+ className = "px-4 bg-accent p-0.5"
221+ onKeyDown = { ( e ) => {
222+ if ( e . key !== "Enter" ) {
223+ return ;
224+ }
225+ onShowMoreMatches ( ) ;
226+ } }
227+ onClick = { onShowMoreMatches }
228+ >
199229 < p
200- onClick = { ( ) => setShowAll ( ! showAll ) }
201230 className = "text-blue-500 cursor-pointer text-sm flex flex-row items-center gap-2"
202231 >
203232 { showAll ? < DoubleArrowUpIcon className = "w-3 h-3" /> : < DoubleArrowDownIcon className = "w-3 h-3" /> }
@@ -222,17 +251,19 @@ const cmTheme = EditorView.baseTheme({
222251 } ,
223252} ) ;
224253
254+ interface CodePreviewProps {
255+ content : string ,
256+ language : string ,
257+ ranges : SearchResultRange [ ] ,
258+ lineOffset : number ,
259+ }
260+
225261const CodePreview = ( {
226262 content,
227263 language,
228264 ranges,
229265 lineOffset,
230- } : {
231- content : string ,
232- language : string ,
233- ranges : SearchResultRange [ ] ,
234- lineOffset : number ,
235- } ) => {
266+ } : CodePreviewProps ) => {
236267 const editorRef = useRef < ReactCodeMirrorRef > ( null ) ;
237268 const { theme } = useThemeNormalized ( ) ;
238269
@@ -251,7 +282,7 @@ const CodePreview = ({
251282 . filter ( ( { Start, End } ) => {
252283 const startLine = Start . LineNumber - lineOffset ;
253284 const endLine = End . LineNumber - lineOffset ;
254-
285+
255286 if (
256287 startLine < 1 ||
257288 endLine < 1 ||
0 commit comments