Skip to content

Commit d6cfce2

Browse files
committed
fix(global-search): remove focus on clicked element when virtual focus change
1 parent 6756b6c commit d6cfce2

3 files changed

Lines changed: 10 additions & 1 deletion

File tree

plugins/global-search/src/components/SearchInput.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IconSearch } from "./ui/IconSearch"
77
type SearchInputProps = DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
88

99
export function SearchInput({ className, ...props }: SearchInputProps) {
10-
const { inputFocusProps, activeId } = useSelection()
10+
const { inputFocusProps, activeId, inputRef } = useSelection()
1111
const activeDescendant = activeId && !isHeader(activeId) ? activeId : undefined
1212

1313
return (
@@ -19,6 +19,7 @@ export function SearchInput({ className, ...props }: SearchInputProps) {
1919
className="flex-1 h-[18px] bg-transparent border-none outline-none focus:outline-none focus:ring-0 text-xs p-0 text-primary-light dark:text-primary-dark placeholder:text-tertiary-light dark:placeholder:text-tertiary-dark"
2020
placeholder="Search..."
2121
autoFocus
22+
ref={inputRef}
2223
aria-activedescendant={activeDescendant}
2324
onKeyDown={e => {
2425
inputFocusProps.onKeyDown(e)

plugins/global-search/src/utils/selection/SelectionProvider.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SelectionContext } from "./context"
55
export function SelectionProvider({ children }: { children: React.ReactNode }) {
66
const [activeId, setActiveId] = useState<string | null>(null)
77
const idsRef = useRef<readonly string[]>([])
8+
const inputRef = useRef<HTMLInputElement | null>(null)
89

910
// scroll to active id
1011
useLayoutEffect(() => {
@@ -49,6 +50,8 @@ export function SelectionProvider({ children }: { children: React.ReactNode }) {
4950
(event: React.KeyboardEvent<HTMLElement>) => {
5051
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
5152
event.preventDefault()
53+
// Ensure the search input retains focus while navigating, prevents other elements from being focused
54+
inputRef.current?.focus()
5255
const currentIndex = activeId ? idsRef.current.indexOf(activeId) : null
5356
const direction = event.key === "ArrowDown" ? NavigationDirection.Down : NavigationDirection.Up
5457
const nextId = findNextSelectable(currentIndex, direction)
@@ -75,6 +78,9 @@ export function SelectionProvider({ children }: { children: React.ReactNode }) {
7578
onKeyDown: handleKeyDown,
7679
}),
7780
inputFocusProps: { onKeyDown: handleKeyDown },
81+
inputRef: (el: HTMLInputElement | null) => {
82+
inputRef.current = el
83+
},
7884
}),
7985
[activeId, setItems, handleKeyDown]
8086
)

plugins/global-search/src/utils/selection/context.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export interface SelectionContextValue {
1212
}
1313
/** Focus props for the input. */
1414
readonly inputFocusProps: { onKeyDown: KeyboardEventHandler<HTMLElement> }
15+
/** Register the search input element so provider can control focus. */
16+
readonly inputRef: (el: HTMLInputElement | null) => void
1517
}
1618

1719
export const SelectionContext = createContext<SelectionContextValue | null>(null)

0 commit comments

Comments
 (0)