fix: escape key was closing modal instead of only combobox and remove arrow left/righ closing combobox

This commit is contained in:
lugnicca 2025-08-24 00:40:02 +02:00
parent 6c0e6dce06
commit 1a6a37c003
3 changed files with 19 additions and 32 deletions

View File

@ -182,8 +182,9 @@ function useKeyboardNavigation(
onModelSelect(filteredModels[highlightedIndex]) onModelSelect(filteredModels[highlightedIndex])
} }
break break
case 'ArrowRight': case 'Escape':
case 'ArrowLeft': e.preventDefault()
e.stopPropagation()
setOpen(false) setOpen(false)
setHighlightedIndex(-1) setHighlightedIndex(-1)
break break
@ -195,11 +196,6 @@ function useKeyboardNavigation(
e.preventDefault() e.preventDefault()
setHighlightedIndex(filteredModels.length - 1) setHighlightedIndex(filteredModels.length - 1)
break break
case 'Escape':
e.preventDefault()
setOpen(false)
setHighlightedIndex(-1)
break
} }
}, [open, setOpen, models.length, filteredModels, highlightedIndex, setHighlightedIndex, onModelSelect]) }, [open, setOpen, models.length, filteredModels, highlightedIndex, setHighlightedIndex, onModelSelect])
@ -216,6 +212,7 @@ type ModelComboboxProps = {
placeholder?: string placeholder?: string
disabled?: boolean disabled?: boolean
className?: string className?: string
onOpenChange?: (open: boolean) => void
} }
export function ModelCombobox({ export function ModelCombobox({
@ -228,6 +225,7 @@ export function ModelCombobox({
placeholder = 'Type or select a model...', placeholder = 'Type or select a model...',
disabled = false, disabled = false,
className, className,
onOpenChange,
}: ModelComboboxProps) { }: ModelComboboxProps) {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [inputValue, setInputValue] = useState(value) const [inputValue, setInputValue] = useState(value)
@ -242,6 +240,11 @@ export function ModelCombobox({
setInputValue(value) setInputValue(value)
}, [value]) }, [value])
// Notify parent when open state changes
useEffect(() => {
onOpenChange?.(open)
}, [open, onOpenChange])
// Hook for the dropdown position // Hook for the dropdown position
const { dropdownPosition } = useDropdownPosition(open, containerRef) const { dropdownPosition } = useDropdownPosition(open, containerRef)

View File

@ -487,28 +487,4 @@ describe('ModelCombobox', () => {
expect(localMockOnChange).toHaveBeenCalledWith('gpt-3.5-turbo') expect(localMockOnChange).toHaveBeenCalledWith('gpt-3.5-turbo')
}) })
it('closes dropdown with ArrowLeft key', async () => {
const user = userEvent.setup()
render(<ModelCombobox {...defaultProps} />)
const input = screen.getByRole('textbox')
input.focus()
// ArrowDown should open dropdown
await user.keyboard('{ArrowDown}')
await waitFor(() => {
const dropdown = document.querySelector('[data-dropdown="model-combobox"]')
expect(dropdown).toBeInTheDocument()
})
// ArrowLeft should close dropdown
await user.keyboard('{ArrowLeft}')
await waitFor(() => {
const dropdown = document.querySelector('[data-dropdown="model-combobox"]')
expect(dropdown).not.toBeInTheDocument()
})
})
}) })

View File

@ -26,6 +26,7 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
const { updateProvider } = useModelProvider() const { updateProvider } = useModelProvider()
const [modelId, setModelId] = useState<string>('') const [modelId, setModelId] = useState<string>('')
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [isComboboxOpen, setIsComboboxOpen] = useState(false)
// Fetch models from provider API (API key is optional) // Fetch models from provider API (API key is optional)
const { models, loading, error, refetch } = useProviderModels( const { models, loading, error, refetch } = useProviderModels(
@ -68,7 +69,13 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
</div> </div>
)} )}
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent
onEscapeKeyDown={(e: KeyboardEvent) => {
if (isComboboxOpen) {
e.preventDefault()
}
}}
>
<DialogHeader> <DialogHeader>
<DialogTitle>{t('providers:addModel.title')}</DialogTitle> <DialogTitle>{t('providers:addModel.title')}</DialogTitle>
<DialogDescription> <DialogDescription>
@ -95,6 +102,7 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
error={error} error={error}
onRefresh={refetch} onRefresh={refetch}
placeholder={t('providers:addModel.enterModelId')} placeholder={t('providers:addModel.enterModelId')}
onOpenChange={setIsComboboxOpen}
/> />
</div> </div>