mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
fixes
This commit is contained in:
parent
36451071f4
commit
419d865811
@ -1,6 +1,20 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
// Search field names used by SearchInput across different list views:
|
||||
// - 'name': AlbumList, ArtistList, LibraryList, PlayerList, RadioList, UserList
|
||||
// - 'title': SongList
|
||||
// - 'q': PlaylistList
|
||||
// If a new list view uses a different source field, add it here.
|
||||
const SEARCH_FIELDS = ['name', 'title', 'q']
|
||||
|
||||
const getSearchValue = (filter) => {
|
||||
for (const field of SEARCH_FIELDS) {
|
||||
if (filter[field]) return filter[field]
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export const useSearchRefocus = () => {
|
||||
const location = useLocation()
|
||||
const prevSearchValue = useRef(null)
|
||||
@ -16,15 +30,19 @@ export const useSearchRefocus = () => {
|
||||
// Invalid JSON, ignore
|
||||
}
|
||||
|
||||
const searchValue = filter.name || filter.title || filter.q || ''
|
||||
const searchValue = getSearchValue(filter)
|
||||
|
||||
if (prevSearchValue.current && !searchValue) {
|
||||
setTimeout(() => {
|
||||
// Use requestAnimationFrame to wait for React to finish re-rendering
|
||||
// after the URL change before focusing the input
|
||||
requestAnimationFrame(() => {
|
||||
// Selector depends on react-admin's internal class naming.
|
||||
// If react-admin changes these class names, this will need updating.
|
||||
const input = document.querySelector('[class*="RaSearchInput"] input')
|
||||
if (input) {
|
||||
input.focus()
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
prevSearchValue.current = searchValue
|
||||
|
||||
@ -9,9 +9,15 @@ vi.mock('react-router-dom', () => ({
|
||||
|
||||
describe('useSearchRefocus', () => {
|
||||
let container
|
||||
let rafCallbacks
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
rafCallbacks = []
|
||||
vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
|
||||
rafCallbacks.push(cb)
|
||||
return rafCallbacks.length
|
||||
})
|
||||
|
||||
container = document.createElement('div')
|
||||
container.innerHTML = `
|
||||
<div class="RaSearchInput-input">
|
||||
@ -23,10 +29,15 @@ describe('useSearchRefocus', () => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
vi.restoreAllMocks()
|
||||
document.body.removeChild(container)
|
||||
})
|
||||
|
||||
const flushRAF = () => {
|
||||
rafCallbacks.forEach((cb) => cb())
|
||||
rafCallbacks = []
|
||||
}
|
||||
|
||||
it('focuses the input when search filter is cleared', () => {
|
||||
const input = container.querySelector('input')
|
||||
const focusSpy = vi.spyOn(input, 'focus')
|
||||
@ -38,8 +49,7 @@ describe('useSearchRefocus', () => {
|
||||
|
||||
mockLocation.search = '?filter={}'
|
||||
rerender()
|
||||
|
||||
vi.advanceTimersByTime(100)
|
||||
flushRAF()
|
||||
|
||||
expect(focusSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -53,8 +63,7 @@ describe('useSearchRefocus', () => {
|
||||
|
||||
mockLocation.search = '?filter={}'
|
||||
rerender()
|
||||
|
||||
vi.advanceTimersByTime(100)
|
||||
flushRAF()
|
||||
|
||||
expect(focusSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -68,8 +77,7 @@ describe('useSearchRefocus', () => {
|
||||
|
||||
mockLocation.search = '?filter={"name":"other"}'
|
||||
rerender()
|
||||
|
||||
vi.advanceTimersByTime(100)
|
||||
flushRAF()
|
||||
|
||||
expect(focusSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user