veza/apps/web/src/components/ui/select/Select.tsx
senke 1ca1130dcf refactor(ui): decompose Select into select module
- Add select/ with useSelect, types, SelectTrigger, SelectDropdownContent,
  SelectOptionItem; min-w-48 max-h-72 (no arbitrary values)
- Remove monolithic select.tsx; entry point is select/index.ts
- Backward compatible: imports from './select' resolve to module

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 21:16:19 +01:00

76 lines
1.8 KiB
TypeScript

import { Dropdown } from '../dropdown';
import { SelectTrigger } from './SelectTrigger';
import { SelectDropdownContent } from './SelectDropdownContent';
import { useSelect } from './useSelect';
import type { SelectProps } from './types';
export function Select({
placeholder = 'Select an option...',
name,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
className,
...props
}: SelectProps) {
const {
open,
setOpen,
search,
setSearch,
searchInputRef,
filteredOptions,
displayValue,
isSelected,
handleSelect,
handleClear,
} = useSelect({ ...props, placeholder });
const trigger = (
<SelectTrigger
displayValue={displayValue}
placeholder={placeholder}
value={props.value}
multiple={props.multiple ?? false}
disabled={props.disabled ?? false}
open={open}
className={className}
ariaLabel={ariaLabel}
ariaLabelledBy={ariaLabelledBy}
onClear={handleClear}
/>
);
return (
<>
<Dropdown
trigger={trigger}
align="left"
onOpenChange={setOpen}
className="w-full"
>
<SelectDropdownContent
searchable={props.searchable ?? false}
search={search}
onSearchChange={setSearch}
searchInputRef={searchInputRef}
filteredOptions={filteredOptions}
multiple={props.multiple ?? false}
isSelected={isSelected}
onSelect={handleSelect}
ariaLabel={ariaLabel}
name={name}
placeholder={placeholder}
/>
</Dropdown>
{name && (
<input
type="hidden"
name={name}
value={
Array.isArray(props.value) ? props.value.join(',') : props.value ?? ''
}
/>
)}
</>
);
}