React навигация по кастомному селекту с поиском
Сделал кастомынй селектор с поиском при помощи input и ul. Теперь стоит проблема: как сделать выбор не только при клике мышкой, но и стрелочками + enter. Может можно переделать имеющийся вариант со списка на другой элемент?
export default function SearchingSelect(): JSX.Element {
const values = ['avstria', 'brasile', 'russia', 'USA', 'china']
const [searchValue, setSearchValue] = useState('')
const [selectValues, setSelectValues] = useState(values)
function handleClick(e: React.MouseEvent<HTMLLIElement>) {
setSearchValue(e.currentTarget.innerText)
setSelectValues(values)
}
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setSearchValue(e.target.value)
const newValue = values.filter((el) => (
el.includes(e.target.value)
))
setSelectValues(newValue)
}
return (
<div className='searching-select'>
<input value={searchValue} type="search" className='searching-select__search' onChange={handleChange} />
<ul className="searching-select__values">
{selectValues.map((el) => <li onClick={handleClick}>{el}</li>)}
</ul>
</div>
)
} ```
Ответы (1 шт):
Автор решения: Yuriy Sidorov
→ Ссылка
import { useCallback, useEffect, useState } from "react";
import "./styles.scss";
export default function SearchingSelect(): JSX.Element {
const values = ["avstria", "brasile", "russia", "USA", "china"];
const [searchValue, setSearchValue] = useState("");
const [selectValues, setSelectValues] = useState(values);
const [selectValueIndex, setSelectValueIndex] = useState(0);
function handleClick(e: React.MouseEvent<HTMLLIElement>) {
setSearchValue(e.currentTarget.innerText);
setSelectValues(values);
}
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setSearchValue(e.target.value);
const newValue = values.filter((el) => el.includes(e.target.value));
setSelectValues(newValue);
}
const handleKeyPressArrow = useCallback(
(event: KeyboardEvent) => {
if (event.key === "ArrowDown") {
setSelectValueIndex((prev) =>
prev < selectValues.length - 1 ? prev + 1 : prev
);
} else if (event.key === "ArrowUp") {
setSelectValueIndex((prev) => (!!prev ? prev - 1 : prev));
}
},
[selectValues.length]
);
const handleKeyPressEnter = useCallback(
(event: KeyboardEvent) => {
if (event.key === "Enter" && selectValues.length) {
setSearchValue(selectValues[selectValueIndex]);
}
},
[selectValues, selectValueIndex]
);
useEffect(() => {
if (selectValues.length) {
window.addEventListener("keydown", handleKeyPressArrow);
window.addEventListener("keydown", handleKeyPressEnter);
}
return () => {
window.removeEventListener("keydown", handleKeyPressArrow);
window.removeEventListener("keydown", handleKeyPressEnter);
};
}, [selectValues.length, handleKeyPressArrow, handleKeyPressEnter]);
return (
<div className="searching-select">
<input
value={searchValue}
type="search"
className="searching-select__search"
onChange={handleChange}
/>
<ul className="searching-select__values">
{selectValues.map((el, key) => (
<li
key={el}
className={
key === selectValueIndex
? "searching-select__values_value-selected"
: ""
}
onClick={handleClick}
>
{el}
</li>
))}
</ul>
</div>
);
}