veza/apps/web/src/components/ui/select/SelectDropdownContent.tsx

92 lines
2.5 KiB
TypeScript
Raw Normal View History

import { Input } from '../input';
import { SelectOptionItem } from './SelectOptionItem';
import type { GroupedOptions } from './types';
interface SelectDropdownContentProps {
searchable: boolean;
search: string;
onSearchChange: (v: string) => void;
searchInputRef: React.RefObject<HTMLInputElement | null>;
filteredOptions: GroupedOptions;
multiple: boolean;
isSelected: (value: string) => boolean;
onSelect: (value: string) => void;
ariaLabel?: string;
name?: string;
placeholder?: string;
}
export function SelectDropdownContent({
searchable,
search,
onSearchChange,
searchInputRef,
filteredOptions,
multiple,
isSelected,
onSelect,
ariaLabel,
name,
placeholder,
}: SelectDropdownContentProps) {
const hasOptions =
filteredOptions.ungrouped.length > 0 ||
Object.keys(filteredOptions.groups).length > 0;
return (
<div
className="w-full min-w-48 max-h-72 overflow-y-auto"
role="listbox"
aria-label={ariaLabel || name || placeholder}
>
{searchable && (
<div className="p-2 border-b">
<Input
ref={searchInputRef}
type="text"
placeholder="Search..."
value={search}
onChange={(e) => onSearchChange(e.target.value)}
onClick={(e) => e.stopPropagation()}
className="w-full"
/>
</div>
)}
{filteredOptions.ungrouped.length > 0 && (
<div className="py-1">
{filteredOptions.ungrouped.map((option) => (
<SelectOptionItem
key={option.value}
option={option}
isSelected={isSelected(option.value)}
multiple={multiple}
onSelect={onSelect}
/>
))}
</div>
)}
{Object.entries(filteredOptions.groups).map(([groupLabel, groupOptions]) => (
<div key={groupLabel} className="py-1">
<div className="px-4 py-1.5 text-xs font-semibold text-kodo-content-dim uppercase">
{groupLabel}
</div>
{groupOptions.map((option) => (
<SelectOptionItem
key={option.value}
option={option}
isSelected={isSelected(option.value)}
multiple={multiple}
onSelect={onSelect}
/>
))}
</div>
))}
{!hasOptions && (
<div className="px-4 py-2 text-sm text-kodo-content-dim text-center">
No options found
</div>
)}
</div>
);
}