Skip to content

Instantly share code, notes, and snippets.

@alanfoandrade
Created August 31, 2021 00:00
Show Gist options
  • Save alanfoandrade/62f1c3b7546472ecd059a36f437c67f3 to your computer and use it in GitHub Desktop.
Save alanfoandrade/62f1c3b7546472ecd059a36f437c67f3 to your computer and use it in GitHub Desktop.
import {
FormLabel,
FormControl,
FormErrorMessage,
useTheme,
} from '@chakra-ui/react';
import { Control, Controller, FieldError } from 'react-hook-form';
import { OptionTypeBase, StylesConfig } from 'react-select';
import ReactAsyncSelect, { AsyncProps } from 'react-select/async';
interface ISelectProps extends AsyncProps<OptionTypeBase> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
control: Control<any>;
name: string;
label?: string;
error?: FieldError;
loadOptions: (inputValue: string) => void;
}
export const AsyncSelect = ({
name,
control,
loadOptions,
label,
error,
...rest
}: ISelectProps): JSX.Element => {
const theme = useTheme();
const customStyles: StylesConfig<OptionTypeBase, false> = {
menu: (provided) => ({
...provided,
borderRadius: theme.radii.md,
padding: 15,
}),
control: (provided, state) => {
let shadow = provided.boxShadow;
if (state.isFocused || state.menuIsOpen) {
shadow = `0 0 0 1px ${theme.colors.blue[300]}`;
} else if (error) {
shadow = `0 0 0 1px ${theme.colors.red[500]}`;
}
let border = provided.borderColor;
if (state.isFocused || state.menuIsOpen) {
border = `${theme.colors.blue[300]}`;
} else if (error) {
border = `${theme.colors.red[500]}`;
}
return {
...provided,
backgroundColor: theme.colors.gray[100],
borderRadius: theme.radii.md,
borderColor: border,
boxShadow: shadow,
height: 48,
padding: '0 4px',
':hover': {
borderColor: border,
},
};
},
dropdownIndicator: (provided) => ({
...provided,
color: theme.colors.gray[700],
}),
indicatorSeparator: (provided) => ({
...provided,
display: 'none',
}),
option: (provided, state: { isSelected: boolean }) => ({
...provided,
borderRadius: theme.radii.md,
color: state.isSelected ? 'white' : theme.colors.gray[700],
padding: '10px 20px',
marginBottom: 4,
cursor: 'pointer',
}),
};
return (
<FormControl isInvalid={!!error}>
{!!label && <FormLabel htmlFor={name}>{label}</FormLabel>}
<Controller
name={name}
control={control}
render={({ field: { onChange, onBlur } }) => (
<ReactAsyncSelect
cacheOptions
onChange={(e) => onChange(e?.value)}
onBlur={onBlur}
loadOptions={loadOptions}
getOptionValue={(option) => option.value}
getOptionLabel={(option) => option.label}
styles={customStyles}
placeholder=""
loadingMessage={() => 'Carregando...'}
noOptionsMessage={({ inputValue }) =>
!inputValue ? 'Começe a digitar...' : 'Nenhum encontrado'
}
{...rest}
/>
)}
/>
{!!error && (
<FormErrorMessage position="absolute">{error.message}</FormErrorMessage>
)}
</FormControl>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment