Skip to content

Instantly share code, notes, and snippets.

@ErikGMatos
Created December 31, 2019 18:23
Show Gist options
  • Save ErikGMatos/fb23d97c66eb7e40b31c857c5182cdb6 to your computer and use it in GitHub Desktop.
Save ErikGMatos/fb23d97c66eb7e40b31c857c5182cdb6 to your computer and use it in GitHub Desktop.
SELECT do unform
import React, { useRef, useEffect } from 'react';
import { FaCaretDown } from 'react-icons/fa';
import Select, { components } from 'react-select';
import { useField } from '@rocketseat/unform';
import PropTypes from 'prop-types';
import { Container, Label } from './styles';
export default function ReactSelect({
name,
label,
options,
multiple,
placeholder,
full,
...rest
}) {
const ref = useRef(null);
const { fieldName, registerField, defaultValue, error } = useField(name);
function parseSelectValue(selectRef) {
const selectValue = selectRef.state.value;
if (!multiple) {
return selectValue ? selectValue.id : '';
}
return selectValue ? selectValue.map(option => option.id) : [];
}
useEffect(() => {
registerField({
name: fieldName,
ref: ref.current,
path: 'state.value',
parseValue: parseSelectValue,
clearValue: selectRef => {
selectRef.select.clearValue();
},
});
}, [ref.current, fieldName]); // eslint-disable-line
function getDefaultValue() {
if (!defaultValue) return null;
if (!multiple) {
return options.find(option => option.id === defaultValue);
}
return options.filter(option => defaultValue.includes(option.id));
}
const colourStyles = {
control: styles => ({
...styles,
border: 'none',
fontSize: '1.2rem',
lineHeight: '20px',
minHeight: '30px',
color: '#4d4c59',
fontWeight: 500,
padding: '0 0 0 5px',
borderRadius: '100px',
backgroundColor: '#fff',
boxShadow: '1px 2px 8px 0 rgba(0,0,0,.1)',
cursor: 'pointer',
width: full ? '100%' : '150px',
}),
indicatorSeparator: styles => ({ ...styles, display: 'none' }),
valueContainer: styles => ({
...styles,
minHeight: '30px',
height: '30px',
}),
menuList: styles => ({
...styles,
padding: '8px',
}),
menu: provided => ({
...provided,
width: full ? '-webkit-fill-available' : 'max-content',
}),
placeholder: styles => ({
...styles,
color: '#4d4c59',
fontWeight: 500,
}),
dropdownIndicator: (base, state) => ({
...base,
transition: 'transform .4s ease-in-out',
transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : null,
}),
// estilos das options
option: styles => ({
...styles,
backgroundColor: '#fff',
color: '#858585',
padding: 7,
cursor: 'pointer',
'&:hover': {
backgroundColor: '#ecedf2',
borderRadius: '2px',
},
}),
};
const DropdownIndicator = props => (
<components.DropdownIndicator {...props}>
<FaCaretDown color="#43bccd" size={16} />
</components.DropdownIndicator>
);
return (
<Container isFocused={colourStyles}>
{label && <Label htmlFor={fieldName}>{label}</Label>}
<Select
components={{ DropdownIndicator }}
styles={colourStyles}
name={fieldName}
aria-label={fieldName}
options={options}
isMulti={multiple}
defaultValue={getDefaultValue()}
ref={ref}
placeholder={placeholder || 'Selecione'}
getOptionValue={option => option.id}
getOptionLabel={option => option.title}
{...rest}
/>
{error && <span>{error}</span>}
</Container>
);
}
ReactSelect.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string,
placeholder: PropTypes.string,
full: PropTypes.bool,
options: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
title: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
})
).isRequired,
multiple: PropTypes.bool,
};
ReactSelect.defaultProps = {
full: false,
label: '',
placeholder: '',
multiple: false,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment