Я сделал свой (dropdown\select) с поиском, поиск работает у меня пока что только для заголовков, подскажите как сделать поиск для заголовков и для вложенных пунктов. ( после чего ещё буду пытаться обводить цветом текст который был найден, но это не самая важная задача... )
import React, { FC, useEffect, useState } from 'react';
import { Disclosure } from '@headlessui/react';
import Style from './Select.module.scss';
import Icon from '../icon/Icon';
interface ISelectItem {
name: string;
categories: [];
}
interface ISelect {
placeholder?: string;
lists: any;
}
const SelectItem: FC<ISelectItem> = ({ name, categories }) => {
return (
<Disclosure as="li" className={Style.Item}>
{({ open }) => (
<>
<Disclosure.Button
className={`${Style.ItemName} ${open ? Style.open : ''}`}
as="div"
>
<span>{name}</span>
<Icon id="angle-right" width={8} height={8} />
</Disclosure.Button>
<ul className={Style.ItemList}>
{categories.map((category: any) => (
<Disclosure.Panel key={category.id} as="li">
<span>{category.name}</span>
<Icon id="angle-right" width={8} height={8} />
</Disclosure.Panel>
))}
</ul>
</>
)}
</Disclosure>
);
};
const filterList = (searchText: string, list: any[]) => {
if (!searchText) return list;
return list.filter(({ name }) =>
name.toLowerCase().includes(searchText.toLowerCase())
);
};
const Select: FC<ISelect> = ({ placeholder, lists }) => {
const [searchInput, setSearchInput] = useState('');
const [filteredList, setFilteredList] = useState<any>();
useEffect(() => {
const Debounce = setTimeout(() => {
const sortedList = filterList(searchInput, lists);
setFilteredList(sortedList);
}, 300);
return () => clearTimeout(Debounce);
}, [searchInput]);
return (
<div className={Style.wrapper}>
<label className={Style.Input}>
<input
type="text"
placeholder={placeholder}
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
/>
{/*<Icon id="search" width={14} height={14} />*/}
</label>
<ul className={Style.list}>
{filteredList &&
filteredList.map((item: any) => (
<SelectItem
key={item.id}
name={item.name}
categories={item.categories}
/>
))}
</ul>
</div>
);
};
export default Select;
@use '../../styles/variables';
.wrapper {
max-width: variables.rem(350px);
background-color: white;
box-shadow: 0 0 variables.rem(6px) #becadb;
border-radius: variables.rem(4px);
ul {
margin: 0;
list-style: none;
}
}
.Input {
display: flex;
align-items: center;
padding: variables.rem(15px) variables.rem(10px);
input {
width: 100%;
padding: variables.rem(5px) variables.rem(10px) variables.rem(5px);
font-size: variables.rem(14px);
line-height: variables.rem(14px);
letter-spacing: .02em;
color: variables.$blue-800;
border: none;
&::placeholder {
font-size: inherit;
line-height: inherit;
letter-spacing: inherit;
color: inherit;
}
}
}
.list {
padding: 0 variables.rem(10px) variables.rem(20px);
max-height: variables.rem(350px);
overflow: auto;
}
.Item {
padding: variables.rem(16px) variables.rem(10px);
cursor: pointer;
span {
font-size: variables.rem(14px);
font-weight: 600;
line-height: variables.rem(19px);
letter-spacing: .01em;
color: variables.$blue;
}
:global .icon-angle-right {
transition: 200ms;
}
& .open :global .icon-angle-right {
transform: rotate(90deg);
}
&Name {
display: flex;
align-items: center;
justify-content: space-between;
}
}
.ItemList {
padding: 0;
li {
display: flex;
align-items: center;
justify-content: space-between;
padding: variables.rem(16px) variables.rem(10px);
transition: 200ms;
border-radius: 4px;
&:first-child {
margin-top: variables.rem(16px);
}
:global .icon-angle-right {
stroke-width: 0.5px;
stroke: variables.$blue-800;
}
span {
font-size: variables.rem(14px);
font-weight: 400;
line-height: variables.rem(19px);
letter-spacing: .04em;
}
&:hover {
background-color: #f5f6fa;
}
}
}
Скрины того что сейчас есть, и то как оно работает
Вот в таком видео приходят данные, сначала name\id общего списка, и потом массив категорий где тоже name\id. И нужно сделать поиск который будет включать и общее названию списка и названия в самих категориях...
codesandbox