import React, { useMemo } from 'react'; import { Field, FieldProps } from '../field'; import { FieldHint } from '../field-hint'; import { Select, SelectSeparator, SelectButton, SelectOptions, SelectOption, SelectContainer, SelectLabel, type SelectProps, } from '../select'; /*-- Types --*/ export type SelectFieldOption = { type?: 'item'; value: string | number; label: string; data?: unknown; }; export type SelectFieldOptionSeparator = { type: 'separator' }; type SelectFieldFlattenOptions = Array< SelectFieldOption | SelectFieldOptionSeparator >; export type SelectFieldOptionGroup = { type: 'group'; options: SelectFieldFlattenOptions; }; export type SelectFieldOptions = Array< SelectFieldOption | SelectFieldOptionSeparator | SelectFieldOptionGroup >; export interface SelectFieldProps extends Omit { value: SelectFieldOption['value']; options: SelectFieldOptions; label?: React.ReactNode; error?: boolean | React.ReactNode; hint?: React.ReactNode; /** * If `true`, it adds some space below the select so a layout doesn't jump * when a helper text (`error`, `hint`) appears. */ hasHelperTextSpace?: boolean; width?: FieldProps['width']; } /*-- Main --*/ export const SelectField = React.forwardRef( function SelectField( { label, error, hint, hasHelperTextSpace, options = [], value, width = 'full', ...rest }, ref, ) { const isInvalid = !!error; const hintText = error && typeof error !== 'boolean' ? error : hint; const flatOptions = useMemo(() => flattenOptions(options), [options]); const selectedOption = useMemo( () => getOptionByValue(flatOptions, value), [flatOptions, value], ); return ( ); }, ); /*-- Utils --*/ function flattenOptions( options: SelectFieldOptions, ): SelectFieldFlattenOptions { const result: SelectFieldFlattenOptions = []; for (const option of options) { if (option.type === 'group') { const isLastItem = options.indexOf(option) === options.length - 1; result.push(...flattenOptions(option.options)); if (!isLastItem) { result.push({ type: 'separator' }); } continue; } result.push(option); } return result; } function getOptionByValue( options: SelectFieldFlattenOptions, value: SelectFieldOption['value'], ) { return options.find(option => option.type === 'separator' ? false : option.value === value, ) as SelectFieldOption | undefined; }