mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Fix
This commit is contained in:
parent
89a94b885a
commit
d34f136590
3 changed files with 49 additions and 13 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { type RefObject } from "react"
|
||||
import { Search, X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
|
@ -10,15 +11,24 @@ export interface SettingsSearchInputProps {
|
|||
onFocus?: () => void
|
||||
onBlur?: () => void
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
inputRef?: RefObject<HTMLInputElement>
|
||||
}
|
||||
|
||||
export function SettingsSearchInput({ value, onChange, onFocus, onBlur, onKeyDown }: SettingsSearchInputProps) {
|
||||
export function SettingsSearchInput({
|
||||
value,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onKeyDown,
|
||||
inputRef,
|
||||
}: SettingsSearchInputProps) {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
return (
|
||||
<div className="relative flex justify-end ml-2">
|
||||
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 size-4 text-vscode-descriptionForeground pointer-events-none" />
|
||||
<Input
|
||||
ref={inputRef}
|
||||
data-testid="settings-search-input"
|
||||
type="text"
|
||||
value={value}
|
||||
|
|
@ -28,8 +38,8 @@ export function SettingsSearchInput({ value, onChange, onFocus, onBlur, onKeyDow
|
|||
onKeyDown={onKeyDown}
|
||||
placeholder={t("settings:search.placeholder")}
|
||||
className={cn(
|
||||
"pl-6 w-[0px] border-none focus:border-vscode-input-border focus:pl-8 focus:min-w-[130px] focus:w-full",
|
||||
value && "pr-4 min-w-[150px]",
|
||||
"pl-6 w-[0px] border-none focus:border-vscode-input-border focus:pl-8 focus:min-w-[132px] focus:w-full",
|
||||
value && "pr-4 min-w-[148px]",
|
||||
)}
|
||||
/>
|
||||
{value && (
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
)
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [isSearchFocused, setIsSearchFocused] = useState(false)
|
||||
const searchInputRef = useRef<HTMLInputElement | null>(null)
|
||||
const [highlightedResultId, setHighlightedResultId] = useState<string | undefined>(undefined)
|
||||
|
||||
const scrollPositions = useRef<Record<SectionName, number>>(
|
||||
|
|
@ -590,9 +591,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
const handleSelectResult = useCallback(
|
||||
(result: SearchResult) => {
|
||||
setSearchQuery("")
|
||||
setIsSearchFocused(false)
|
||||
setHighlightedResultId(undefined)
|
||||
handleTabChange(result.tab)
|
||||
// Keep focus in the input so dropdown remains open for follow-up search
|
||||
setIsSearchFocused(true)
|
||||
requestAnimationFrame(() => searchInputRef.current?.focus())
|
||||
// Small delay to allow tab switch and render
|
||||
setTimeout(() => scrollToSetting(result.id), 150)
|
||||
},
|
||||
|
|
@ -683,6 +686,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
onFocus={() => setIsSearchFocused(true)}
|
||||
onBlur={() => setTimeout(() => setIsSearchFocused(false), 200)}
|
||||
onKeyDown={handleSearchKeyDown}
|
||||
inputRef={searchInputRef}
|
||||
/>
|
||||
{searchQuery && isSearchFocused && (
|
||||
<div className="absolute top-full w-full min-w-50 right-0 mt-1 bg-vscode-dropdown-background border border-vscode-dropdown-border rounded shadow-lg z-50">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { forwardRef } from "react"
|
||||
import { fireEvent, render, screen } from "@testing-library/react"
|
||||
import { vi, describe, it, beforeEach } from "vitest"
|
||||
|
||||
|
|
@ -140,15 +141,18 @@ vi.mock("@/components/ui", () => ({
|
|||
</button>
|
||||
),
|
||||
StandardTooltip: ({ children }: any) => <>{children}</>,
|
||||
Input: ({ value, onChange, onFocus, onBlur, onKeyDown, "data-testid": dataTestId }: any) => (
|
||||
<input
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
onKeyDown={onKeyDown}
|
||||
data-testid={dataTestId}
|
||||
/>
|
||||
Input: forwardRef<HTMLInputElement, any>(
|
||||
({ value, onChange, onFocus, onBlur, onKeyDown, "data-testid": dataTestId }, ref) => (
|
||||
<input
|
||||
ref={ref}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
onKeyDown={onKeyDown}
|
||||
data-testid={dataTestId}
|
||||
/>
|
||||
),
|
||||
),
|
||||
AlertDialog: ({ children }: any) => <div>{children}</div>,
|
||||
AlertDialogContent: ({ children }: any) => <div>{children}</div>,
|
||||
|
|
@ -242,4 +246,22 @@ describe("SettingsView search interactions", () => {
|
|||
expect(screen.queryByRole("listbox")).not.toBeInTheDocument()
|
||||
expect(input.value).toBe("")
|
||||
})
|
||||
|
||||
it("keeps input focused after selecting a result to allow immediate follow-up search", async () => {
|
||||
render(<SettingsView onDone={vi.fn()} />)
|
||||
|
||||
const input = screen.getByTestId("settings-search-input") as HTMLInputElement
|
||||
fireEvent.focus(input)
|
||||
fireEvent.change(input, { target: { value: "browser" } })
|
||||
|
||||
await screen.findByRole("listbox")
|
||||
const options = screen.getAllByRole("option")
|
||||
fireEvent.mouseDown(options[0])
|
||||
fireEvent.click(options[0])
|
||||
|
||||
// Second search still produces results
|
||||
fireEvent.change(input, { target: { value: "browser" } })
|
||||
const secondListbox = await screen.findByRole("listbox")
|
||||
expect(secondListbox).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue