/* eslint-disable no-nested-ternary */ import React from 'react'; import Select, { components, GroupBase, OnChangeValue, Options, } from 'react-select'; import AsyncSelect from 'react-select/async'; import CreatableSelect from 'react-select/creatable'; import { DefaultTheme, useTheme } from 'styled-components'; import { WidthProps } from 'styled-system'; import { MaterialClear, MaterialExpandMore } from '@t3n/icons'; import { Theme } from '@t3n/theme'; import Box from '../Box'; import Icon from '../Icon'; import Text from '../Text'; export interface SelectBoxProps extends WidthProps { autoFocus?: boolean; closeMenuOnSelect?: boolean; defaultValue?: Options; disabled?: boolean; error?: boolean; hideReset?: boolean; id?: string; inputValue?: string; loading?: boolean; multiSelect?: boolean; name?: string; noOptionsMessage?: string; options: Options; defaultOptions?: Options; placeholder?: string; searchable?: boolean; creatable?: boolean; tabIndex?: string | number; value?: Options; onBlur?: () => void; onChange?: (value: Options) => void; onFocus?: () => void; onKeyDown?: () => void; onToggleOpen?: () => void; async?: boolean; loadOptions?: ( inputValue: string, callback: (options: Options) => void, ) => void; loadingMessage?: (obj: { inputValue: string }) => string; onInputChange?: (newValue: string) => string; } const getCustomStyles = (error: boolean, theme: Theme & DefaultTheme) => ({ container: (provided: any, state: any) => ({ ...provided, outline: '0', pointerEvents: state.isDisabled && 'all', '*': { cursor: state.isDisabled && 'not-allowed !important', }, }), control: (provided: any, state: any) => { return { ...provided, color: theme.colors.text.primary, backgroundColor: theme.colors.background.primary, boxShadow: state.isFocused ? `0 0 0 2px ${theme.colors.brand.black}` : 0, borderRadius: theme.border.radii[1], borderColor: error ? theme.colors.feedback.error : state.isDisabled ? theme.colors.shades.grey204 : state.isFocused ? theme.colors.shades.grey42 : theme.colors.shades.grey95, ':hover': { borderColor: error ? theme.colors.feedback.error : state.isDisabled ? theme.colors.shades.grey204 : state.isFocused ? theme.colors.shades.grey42 : theme.colors.shades.grey95, }, }; }, placeholder: (provided: any) => ({ ...provided, opacity: '0.6', }), indicatorSeparator: (provided: any, state: any) => ({ ...provided, margin: 0, backgroundColor: error ? theme.colors.feedback.error : state.isDisabled ? theme.colors.shades.grey204 : state.isFocused ? theme.colors.shades.grey42 : theme.colors.shades.grey95, }), multiValue: (provided: any) => ({ ...provided, backgroundColor: theme.colors.background.secondary, borderRadius: '30px', }), multiValueRemove: (provided: any) => ({ ...provided, ':hover': { background: 'inherit', borderRadius: 'inherit', cursor: 'pointer', }, }), valueContainer: (provided: any) => ({ ...provided, cursor: 'text' }), clearIndicator: (provided: any) => ({ ...provided, cursor: 'pointer' }), dropdownIndicator: (provided: any) => ({ ...provided, cursor: 'pointer' }), option: (provided: any, state: any) => ({ ...provided, backgroundColor: state.isDisabled ? null : state.isSelected ? theme.colors.shades.grey232 : state.isFocused ? theme.colors.shades.grey244 : null, color: state.isDisabled ? theme.colors.shades.grey232 : null, cursor: state.isDisabled ? 'not-allowed' : 'default', ':active': { backgroundColor: !state.isDisabled && (state.isSelected ? theme.colors.shades.grey232 : state.isFocused ? theme.colors.shades.grey244 : null), }, }), noOptionsMessage: (provided: any) => ({ ...provided, textAlign: 'left' }), group: (provided: any) => ({ ...provided, ':not(:last-child)': { borderBottom: '1px solid', borderBottomColor: theme.colors.shades.grey232, marginBottom: theme.space[2], }, }), }); const ClearIndicator = (props: any) => { const theme = useTheme() as Theme; return ( ); }; const createDropdownIndicator = // eslint-disable-next-line react/function-component-definition (error: boolean, theme: Theme & DefaultTheme) => (props: any) => { return ( ); }; const MultiValueRemove = (props: any) => { const theme = useTheme() as Theme; return ( ); }; const GroupLabel = ({ label }: { label: string }) => ( {label} ); const CreateLabel = ({ label }: { label: string }) => ( {label} {' '} hinzufügen ); const SelectBox = ({ error, noOptionsMessage = 'Keine Auswahl gefunden.', creatable, onChange, disabled, loading = false, hideReset, multiSelect = false, searchable = false, placeholder = 'Auswählen', async, loadOptions, ...props }: SelectBoxProps): JSX.Element => { const theme = useTheme(); const commonProps = { ...props, tabIndex: typeof props.tabIndex === 'string' ? parseInt(props.tabIndex, 10) : props.tabIndex, isDisabled: disabled || loading, isClearable: !hideReset, isLoading: loading, isMulti: multiSelect, placeholder, // TODO: Fix lint issue // eslint-disable-next-line react/no-unstable-nested-components formatGroupLabel: ({ label }: GroupBase) => ( ), noOptionsMessage: () => noOptionsMessage || null, onChange: (values: OnChangeValue) => onChange?.( (Array.isArray(values) ? values : values === null ? [] : [values]) as Options, ), styles: getCustomStyles(!!error, theme as Theme), components: { ClearIndicator, DropdownIndicator: createDropdownIndicator(!!error, theme as Theme), MultiValueRemove, }, }; if (async) { const { options, ...rest } = commonProps; return ; } if (creatable) { return ( } /> ); } return