import styled from '@emotion/styled'; import { MouseEvent, useMemo, useRef, useState } from 'react'; import { IconComponent, MenuItem, MenuItemSelect } from 'twenty-ui'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { SelectControl } from '@/ui/input/components/SelectControl'; import { SelectHotkeyScope } from '../types/SelectHotkeyScope'; import { isDefined } from 'twenty-shared/utils'; export type SelectOption = { value: Value; label: string; Icon?: IconComponent; }; export type SelectSizeVariant = 'small' | 'default'; type CallToActionButton = { text: string; onClick: (event: MouseEvent) => void; Icon?: IconComponent; }; export type SelectValue = string | number | boolean | null; export type SelectProps = { className?: string; disabled?: boolean; selectSizeVariant?: SelectSizeVariant; dropdownId: string; dropdownWidth?: `${string}px` | 'auto' | number; dropdownWidthAuto?: boolean; emptyOption?: SelectOption; fullWidth?: boolean; label?: string; onChange?: (value: Value) => void; onBlur?: () => void; options: SelectOption[]; value?: Value; withSearchInput?: boolean; needIconCheck?: boolean; callToActionButton?: CallToActionButton; }; const StyledContainer = styled.div<{ fullWidth?: boolean }>` width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')}; `; const StyledLabel = styled.span` color: ${({ theme }) => theme.font.color.light}; display: block; font-size: ${({ theme }) => theme.font.size.xs}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; margin-bottom: ${({ theme }) => theme.spacing(1)}; `; export const Select = ({ className, disabled: disabledFromProps, selectSizeVariant, dropdownId, dropdownWidth = 176, dropdownWidthAuto = false, emptyOption, fullWidth, label, onChange, onBlur, options, value, withSearchInput, needIconCheck, callToActionButton, }: SelectProps) => { const selectContainerRef = useRef(null); const [searchInputValue, setSearchInputValue] = useState(''); const selectedOption = options.find(({ value: key }) => key === value) || emptyOption || options[0]; const filteredOptions = useMemo( () => searchInputValue ? options.filter(({ label }) => label.toLowerCase().includes(searchInputValue.toLowerCase()), ) : options, [options, searchInputValue], ); const isDisabled = disabledFromProps || (options.length <= 1 && !isDefined(callToActionButton) && (!isDefined(emptyOption) || selectedOption !== emptyOption)); const { closeDropdown } = useDropdown(dropdownId); const dropDownMenuWidth = dropdownWidthAuto && selectContainerRef.current?.clientWidth ? selectContainerRef.current?.clientWidth : dropdownWidth; return ( {!!label && {label}} {isDisabled ? ( ) : ( } dropdownComponents={ <> {!!withSearchInput && ( setSearchInputValue(event.target.value)} /> )} {!!withSearchInput && !!filteredOptions.length && ( )} {!!filteredOptions.length && ( {filteredOptions.map((option) => ( { onChange?.(option.value); onBlur?.(); closeDropdown(); }} /> ))} )} {!!callToActionButton && !!filteredOptions.length && ( )} {!!callToActionButton && ( )} } dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }} /> )} ); };