fix(web): stabilize document picker search focus (#36525)

This commit is contained in:
yyh 2026-05-22 17:24:37 +08:00 committed by GitHub
parent 24bab5fb2a
commit a698c60b29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 14 deletions

View File

@ -148,6 +148,30 @@ describe('DocumentPicker', () => {
expect(trigger).not.toHaveFocus()
})
it('should keep focus in the search input when deleting from an empty result', async () => {
const user = userEvent.setup()
mockUseDocumentList.mockImplementation(({ query }) => ({
data: query.keyword === 'missing'
? { data: [] }
: mockDocumentListData,
}))
renderDocumentPicker()
const trigger = screen.getByRole('combobox', { name: 'Document 1' })
await user.click(trigger)
const searchInput = screen.getByPlaceholderText('common.operation.search')
await user.type(searchInput, 'missing')
expect(await screen.findByText('common.noData')).toBeInTheDocument()
await user.keyboard('{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}{Backspace}')
expect(trigger).toHaveAttribute('aria-expanded', 'true')
expect(searchInput).toHaveFocus()
expect(trigger).not.toHaveFocus()
})
it('should keep focus in the search input while typing quickly', async () => {
const user = userEvent.setup()
renderDocumentPicker()

View File

@ -13,7 +13,8 @@ import {
ComboboxValue,
} from '@langgenius/dify-ui/combobox'
import { RiArrowDownSLine } from '@remixicon/react'
import { useDeferredValue, useState } from 'react'
import { useDebounce } from 'ahooks'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { GeneralChunk, ParentChildChunk } from '@/app/components/base/icons/src/vender/knowledge'
import Loading from '@/app/components/base/loading'
@ -106,12 +107,12 @@ export function DocumentPicker({
}: Props) {
const { t } = useTranslation()
const [searchValue, setSearchValue] = useState('')
const deferredSearchValue = useDeferredValue(searchValue)
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
const { data } = useDocumentList({
datasetId,
query: {
keyword: deferredSearchValue,
keyword: debouncedSearchValue,
page: 1,
limit: 20,
},
@ -175,19 +176,16 @@ export function DocumentPicker({
className="block h-4.5 grow px-1 py-0 text-[13px] text-text-primary"
/>
</ComboboxInputGroup>
<DocumentList
className="mt-2 data-empty:mt-0"
/>
{data
? (
documentsList.length > 0
? (
<DocumentList
className="mt-2"
/>
)
: (
<ComboboxEmpty className="mt-2 flex h-[100px] w-full items-center justify-center">
{t('noData', { ns: 'common' })}
</ComboboxEmpty>
)
<ComboboxEmpty className="p-0">
<div className="mt-2 flex h-[100px] w-full items-center justify-center px-3 py-2 system-sm-regular text-text-tertiary">
{t('noData', { ns: 'common' })}
</div>
</ComboboxEmpty>
)
: (
<ComboboxStatus className="mt-2 flex h-[100px] w-full items-center justify-center">