Fixed the keyboard stealing issue
This commit is contained in:
parent
237267ff3a
commit
9ae4b54155
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useRef } from "react";
|
import React, { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
export interface SelectableListProps<T> {
|
export interface SelectableListProps<T> {
|
||||||
items: T[];
|
items: T[];
|
||||||
@ -12,10 +12,17 @@ export const SelectableList = <T,>(
|
|||||||
): JSX.Element => {
|
): JSX.Element => {
|
||||||
const { items, selectedValue, renderLabel, onSelect } = props;
|
const { items, selectedValue, renderLabel, onSelect } = props;
|
||||||
|
|
||||||
|
// Track focus state of the list itself
|
||||||
const listRef = useRef<HTMLUListElement | null>(null);
|
const listRef = useRef<HTMLUListElement | null>(null);
|
||||||
|
const isFocusedRef = useRef(false);
|
||||||
|
|
||||||
|
// One ref per item so we can focus + scroll it
|
||||||
|
const itemRefs = useRef<(HTMLLIElement | null)[]>([]);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(e: React.KeyboardEvent<HTMLUListElement>) => {
|
(e: React.KeyboardEvent<HTMLUListElement>) => {
|
||||||
|
// Ignore keyboard input unless the list itself is focused
|
||||||
|
if (!isFocusedRef.current) return;
|
||||||
if (!items.length) return;
|
if (!items.length) return;
|
||||||
|
|
||||||
const currentIndex = selectedValue ? items.indexOf(selectedValue) : -1;
|
const currentIndex = selectedValue ? items.indexOf(selectedValue) : -1;
|
||||||
@ -37,11 +44,28 @@ export const SelectableList = <T,>(
|
|||||||
[items, selectedValue, onSelect],
|
[items, selectedValue, onSelect],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Only focus the selected item if the list itself already has focus
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isFocusedRef.current) return; // Do NOT steal focus
|
||||||
|
if (!selectedValue) return;
|
||||||
|
|
||||||
|
const index = items.indexOf(selectedValue);
|
||||||
|
if (index < 0) return;
|
||||||
|
|
||||||
|
const el = itemRefs.current[index];
|
||||||
|
if (el) {
|
||||||
|
el.focus({ preventScroll: false });
|
||||||
|
el.scrollIntoView({ block: "nearest" });
|
||||||
|
}
|
||||||
|
}, [items, selectedValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul
|
<ul
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
className="selectable-list"
|
className="selectable-list"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
onFocus={() => (isFocusedRef.current = true)}
|
||||||
|
onBlur={() => (isFocusedRef.current = false)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
{items.map((item, index) => {
|
{items.map((item, index) => {
|
||||||
@ -49,7 +73,13 @@ export const SelectableList = <T,>(
|
|||||||
const className = isSelected ? "selected" : "";
|
const className = isSelected ? "selected" : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={index} onClick={() => onSelect(item)} className={className}>
|
<li
|
||||||
|
key={index}
|
||||||
|
ref={(el) => (itemRefs.current[index] = el)}
|
||||||
|
tabIndex={isSelected ? 0 : -1}
|
||||||
|
onClick={() => onSelect(item)}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
{renderLabel(item)}
|
{renderLabel(item)}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user