react-cm-ui
Version:
React UI for Healthy Church
1,086 lines (1,034 loc) • 36.8 kB
JSX
import {
findIndex,
has,
isEmpty,
isFunction,
isString,
map,
noop,
size,
} from 'lodash';
import ClassNames from 'classnames';
import PropTypes from 'prop-types';
import React, { useRef } from 'react';
import ReactSelect from 'react-select';
import ScrollBar from 'react-custom-scrollbars';
import {
BEM_SELECT,
UI_CLASS_NAME,
} from '../../global/constants';
import Icon from '../../dataDisplay/icon';
import makeStyles from '../../styles/makeStyles';
const propTypes = {
/**
* Override or extend the styles applied to Select.
*/
classes: PropTypes.shape({
root: PropTypes.string,
}),
/**
* Assign additional class names to Select.
*/
className: PropTypes.string,
/**
* A Select can clear its value using close icon
*/
clearable: PropTypes.bool,
/**
* A Select can create custom options
*/
creatable: PropTypes.bool,
/**
* Deprecated prop. Please use `disabled` instead.
*/
disable: PropTypes.bool,
/**
* A Select can be disabled
*/
disabled: PropTypes.bool,
/**
* Supply style to dropdown menu container
*/
dropdownMenuContainerStyle: PropTypes.shape({}),
/**
* Supply dropdown menu maximum height
*/
dropdownMenuMaxHeight: PropTypes.number,
/**
* Supply dropdown menu minimum height
*/
dropdownMenuMinHeight: PropTypes.number,
/**
* Supply dropdown menu style
*/
dropdownMenuStyle: PropTypes.shape({}),
/**
* Indicates that the Select has an error.
*/
error: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string,
]),
/**
* A Select will be resized to its parent container's width.
*/
fluid: PropTypes.bool,
/**
* The `id` of the Select.
*/
id: PropTypes.string,
/**
* The label for the Select.
*/
label: PropTypes.string,
/**
* Whether to match the value, label or both values of each selection option when filtering.
* enums:any, label, value
*/
matchProp: PropTypes.oneOf(['any', 'label', 'value']),
/**
* A Select can have multiple values
*/
multiple: PropTypes.bool,
/**
* Placeholder displayed when there are no matching search results or a falsy value to hide it
* (can also be a react component)
*/
noResultsText: PropTypes.oneOfType([
PropTypes.node,
PropTypes.string,
]),
/**
* The onChange event handler.
*/
onChange: PropTypes.func,
/**
* The onClose event handler.
*/
onClose: PropTypes.func,
/**
* The onOpen event handler.
*/
onOpen: PropTypes.func,
/**
* A Select can have custom option component
*/
optionComponent: PropTypes.func,
/**
* Supply a list of options that the user can select from.
*/
options: PropTypes.arrayOf(PropTypes.shape({})),
/**
* Supply a placeholder text for the best UX.
*/
placeholder: PropTypes.string,
/**
* Supply a custom label option, when creatable is true
*/
promptTextCreator: PropTypes.func,
/**
* A Select can be required
*/
required: PropTypes.bool,
/**
* A Select can enable option search
*/
searchable: PropTypes.bool,
/**
* Indicates whether or not the Select can be focused.
*/
tabIndex: PropTypes.number,
/**
* Underlined Select selection.
*/
underline: PropTypes.bool,
value: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.shape({})),
PropTypes.shape({}),
PropTypes.string,
]),
valueComponent: PropTypes.func,
};
const defaultProps = {
classes: null,
className: null,
clearable: false,
creatable: false,
error: null,
disable: false,
disabled: false,
dropdownMenuContainerStyle: null,
dropdownMenuMaxHeight: 180,
dropdownMenuMinHeight: null,
dropdownMenuStyle: null,
fluid: false,
id: null,
label: null,
matchProp: 'any',
multiple: false,
noResultsText: 'No results found',
onChange: null,
onClose: undefined,
onOpen: undefined,
optionComponent: null,
options: [],
promptTextCreator: undefined,
placeholder: null,
required: false,
searchable: false,
tabIndex: -1,
underline: false,
value: {},
valueComponent: undefined,
};
class CustomReactSelect extends ReactSelect {
renderHiddenField(valueArray) {
const {
menuContainerStyle,
menuStyle,
multi,
removeSelected,
} = this.props;
const options = this.filterOptions(
multi && removeSelected ? valueArray : null,
);
// eslint-disable-next-line no-underscore-dangle
this._visibleOptions = options;
const menu = this.renderMenu(options, valueArray);
const styles = {
...menuContainerStyle,
visibility: 'hidden',
};
return (
<div className="Select-menu-outer" style={styles}>
<div
role="listbox"
tabIndex={-1}
className="Select-menu"
// eslint-disable-next-line no-underscore-dangle
id={`${this._instancePrefix}-list`}
style={menuStyle}
>
{menu}
</div>
</div>
);
}
}
const CustomCreatableSelect = (props) => (
<CustomReactSelect
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
);
const useStyles = makeStyles((theme) => {
const {
palette: p,
spacing,
typography,
} = theme;
const darkThemeBoxShadow = '0 4px 4px 0 rgba(0, 0, 0, 0.43)';
// Control Options
const selectInputBg = p.background.primary;
const selectInputBgFocus = p.background.contrastPrimary;
const selectInputBgDisabled = p.background.secondary;
const selectInputBorderColor = p.border.primary;
const selectInputBorderRadius = '3px';
const selectInputBorderFocus = p.cyan[500];
const selectInputBorderWidth = 1;
const selectInputArrowColorFocus = p.text.contrastText;
const selectInputHeight = 44;
const selectInputInternalHeight = (selectInputHeight - (selectInputBorderWidth * 2));
const selectInputPlaceholder = p.text.secondary;
const selectTextColor = p.text.primary;
const selectTextColorFocus = p.text.contrastText;
const selectLinkHoverColor = selectInputBgFocus;
const selectPaddingHorizontal = 11;
// Menu Options
const selectMenuBg = p.grey[500];
const selectMenuBorderRadius = 3;
const selectMenuMarginTop = 4;
const selectMenuPaddingVertical = 11;
const selectMenuZindex = 1000;
const selectOptionBg = selectMenuBg;
const selectOptionColor = p.text.contrastText;
const selectOptionFocusedColor = p.text.primary;
const selectOptionFocusedBg = p.background.primary;
const selectOptionSelectedColor = p.text.primary;
const selectOptionSelectedBg = p.background.primary;
const selectOptionDisabledColor = p.text.secondary;
const selectOptionMarginVertical = 4;
const selectOptionPaddingHorizontal = 22;
const selectOptionPaddingVertical = 7;
const selectNoresultsColor = p.text.contrastText;
// clear "x" button
const selectClearSize = `floor((${selectInputHeight} / 2))`;
const selectClearColor = '#999';
const selectClearHoverColor = '#D0021B';
const selectClearWidth = 16;
// arrow indicator
const selectArrowColor = '#999';
const selectArrowColorHover = '#666';
const selectArrowWidth = 16;
// loading indicator
const selectLoadingSize = 16;
const selectLoadingColor = selectTextColor;
const selectLoadingColorBg = selectInputBorderColor;
// multi-select item
const selectItemBorderRadius = 2;
const selectItemGutter = 5;
const selectItemFontSize = '.9em';
const selectItemColor = '#08c';
const selectItemBg = '#f2f9fc';
const selectItemBorderColor = selectItemBg;
const selectItemDisabledBg = '#fcfcfc';
const selectItemDisabledBorderColor = selectItemDisabledBg;
return {
'@keyframes selectAnimationSpin': {
to: {
transform: 'rotate(1turn)',
},
},
'@keyframes selectAnimationFadeIn': {
from: {
opacity: 0,
},
to: {
opacity: 1,
},
},
errorMessage: {
color: p.error.main,
fontSize: typography.pxToRem(14),
marginTop: spacing(0.5),
},
hasError: {},
isFluid: {},
isUnderlined: {},
label: {
marginBottom: 8,
},
requiredIndicator: {
color: p.error.main,
display: 'inline-block',
fontSize: typography.pxToRem(14),
marginLeft: 3,
},
root: {
display: 'inline-block',
minWidth: 200,
position: 'relative',
'&$isFluid': {
display: 'block',
},
'& .Select': {
position: 'relative',
'&, & div, & input, & span': {
boxSizing: 'border-box',
},
'&.is-disabled': {
'& > .Select-control': {
backgroundColor: selectInputBgDisabled,
'&:hover': {
boxShadow: 'none',
},
},
'& .Select-arrow-zone': {
cursor: 'default',
pointerEvents: 'none',
'& .ui.icon .icon-use-path': {
fill: p.grey[400],
},
},
},
},
'& .Select-control': {
backgroundColor: selectInputBg,
border: `${selectInputBorderWidth}px solid ${selectInputBorderColor}`,
borderCollapse: 'separate',
borderColor: `${selectInputBorderColor} ${selectInputBorderColor} ${selectInputBorderColor}`,
borderRadius: selectInputBorderRadius,
borderSpacing: 0,
color: selectTextColor,
cursor: 'default',
display: 'table',
height: selectInputHeight,
outline: 'none',
position: 'relative',
width: '100%',
'&:hover': {
boxShadow: '0 1px 0 rgba(0, 0, 0, 0.06)',
},
'& .Select-input:focus': {
outline: 'none',
},
},
'&$hasError .Select-control': {
borderColor: p.error.main,
},
'& .is-searchable.is-open > .Select-control': {
cursor: 'text',
},
'& .is-open:not(.Select--multi) > .Select-control': {
backgroundColor: selectInputBgFocus,
borderColor: `${selectInputBorderColor} ${selectInputBorderColor} ${selectInputBorderColor}`,
color: selectTextColorFocus,
'& .Select-arrow': {
borderColor: `transparent transparent ${selectArrowColor}`,
borderWidth: `0 ${selectArrowWidth} ${selectArrowWidth}`,
top: -2,
},
'& .Select-value-label': {
color: `${p.text.contrastText} !important`,
},
'& .Select-arrow-zone, & .Select-clear-zone': {
'& .ui.icon .icon-use-path': {
fill: selectInputArrowColorFocus,
},
},
},
'& .is-searchable.is-focused:not(.is-open) > .Select-control': {
cursor: 'text',
},
'& .is-focused:not(.is-open) > .Select-control': {
borderColor: `${selectInputBorderFocus} ${selectInputBorderFocus} ${selectInputBorderFocus}`,
boxShadow: [
[
'inset 0 1px 2px rgba(0, 0, 0, 0.1)',
],
[
`0 0 5px -1px rgba(${selectInputBorderFocus}, 50%)`,
],
],
},
'& .Select-placeholder, & .Select--single > .Select-control .Select-value': {
bottom: 0,
color: selectInputPlaceholder,
left: 0,
lineHeight: `${selectInputInternalHeight}px`,
maxWidth: '100%',
overflow: 'hidden',
paddingLeft: selectPaddingHorizontal,
paddingRight: selectPaddingHorizontal,
position: 'absolute',
right: 0,
textOverflow: 'ellipsis',
top: 0,
whiteSpace: 'nowrap',
},
'& .has-value.Select--single > .Select-control .Select-value, & .has-value.is-pseudo-focused.Select--single > .Select-control .Select-value': {
'& .Select-value-label': {
color: selectTextColor,
},
'& a.Select-value-label': {
cursor: 'pointer',
textDecoration: 'none',
'&:hover, &:focus': {
color: selectLinkHoverColor,
outline: 'none',
textDecoration: 'underline',
},
},
},
'& .Select-input': {
height: `${selectInputInternalHeight}px`,
paddingLeft: selectPaddingHorizontal,
paddingRight: selectPaddingHorizontal,
verticalAlign: 'middle',
'& > input': {
background: 'none transparent',
border: '0 none',
boxShadow: 'none',
cursor: 'default',
display: 'inline-block',
fontFamily: 'inherit',
fontSize: 'inherit',
margin: 0,
outline: 'none',
lineHeight: '14px',
padding: `${((selectInputInternalHeight - 14) / 2 - 2)}px 0 ${((selectInputInternalHeight - 14) / 2 + 2)}px`,
WebkitAppearance: 'none',
'& .is-focused &': {
cursor: 'text',
},
},
},
'& .has-value.is-pseudo-focused .Select-input': {
opacity: 0,
},
'& .Select-control:not(.is-searchable) > .Select-input': {
outline: 'none',
},
'& .Select-loading-zone': {
cursor: 'pointer',
display: 'table-cell',
position: 'relative',
textAlign: 'center',
verticalAlign: 'middle',
width: selectLoadingSize,
},
'& .Select-loading': {
animation: '$selectAnimationSpin 400ms infinite linear',
border: `floor((${selectLoadingSize / 8})) solid ${selectLoadingColorBg}`,
borderRadius: '50%',
borderRightColor: selectLoadingColor,
boxSizing: 'border-box',
display: 'inline-block',
height: selectLoadingSize,
position: 'relative',
width: selectLoadingSize,
verticalAlign: 'middle',
},
'& .Select-clear-zone': {
animation: '$selectAnimationFadeIn 200ms',
color: selectClearColor,
cursor: 'pointer',
display: 'table-cell',
paddingRight: 11,
position: 'relative',
textAlign: 'center',
verticalAlign: 'middle',
width: selectClearWidth,
'& > div': {
alignItems: 'center',
display: 'flex',
justifyContent: 'center',
},
'&:hover': {
color: selectClearHoverColor,
},
},
'& .Select-clear': {
display: 'inline-block',
fontSize: selectClearSize,
lineHeight: 1,
},
'& .Select--multi .Select-clear-zone': {
width: selectClearWidth,
},
'& .Select-multi-value-wrapper': {
position: 'relative',
},
'& .Select .Select-aria-only': {
display: 'inline-block',
height: 1,
width: 1,
margin: '-1px',
clip: 'rect(0,0,0,0)',
overflow: 'hidden',
},
'& .Select-arrow-zone': {
cursor: 'pointer',
display: 'table-cell',
paddingBottom: 0,
paddingRight: 11,
position: 'relative',
textAlign: 'center',
verticalAlign: 'middle',
width: selectArrowWidth,
'& > div': {
alignItems: 'center',
display: 'flex',
justifyContent: 'center',
},
},
'& .Select-arrow': {
borderColor: `${selectArrowColor} transparent transparent`,
borderStyle: 'solid',
borderWidth: `${selectArrowWidth} ${selectArrowWidth} (${selectArrowWidth} / 2)`,
display: 'inline-block',
height: 0,
position: 'relative',
width: 0,
},
'& .is-open .Select-arrow, & .Select-arrow-zone:hover > .Select-arrow': {
borderTopColor: selectArrowColorHover,
},
'& .Select-menu-outer': {
backgroundColor: selectMenuBg,
borderRadius: selectMenuBorderRadius,
boxShadow: darkThemeBoxShadow,
boxSizing: 'border-box',
marginTop: selectMenuMarginTop,
WebkitOverflowScrolling: 'touch',
paddingBottom: selectMenuPaddingVertical,
paddingTop: selectMenuPaddingVertical,
position: 'absolute',
top: '100%',
width: '100%',
zIndex: selectMenuZindex,
},
'& .Select-option': {
backgroundColor: selectOptionBg,
boxSizing: 'border-box',
color: selectOptionColor,
cursor: 'pointer',
display: 'block',
fontSize: '14px',
fontWeight: theme.typography.fontWeightMedium,
margin: `${selectOptionMarginVertical}px 0`,
padding: `${selectOptionPaddingVertical}px ${selectOptionPaddingHorizontal}px`,
whiteSpace: 'nowrap',
'&.is-selected': {
backgroundColor: selectOptionSelectedBg,
color: selectOptionSelectedColor,
},
'&.is-focused, &:hover': {
backgroundColor: selectOptionFocusedBg,
color: selectOptionFocusedColor,
},
'&.is-disabled': {
backgroundColor: theme.palette.grey[500],
color: selectOptionDisabledColor,
cursor: 'not-allowed',
},
},
'& .Select-noresults': {
boxSizing: 'border-box',
color: selectNoresultsColor,
cursor: 'default',
display: 'block',
padding: `${selectOptionPaddingVertical}px ${selectOptionPaddingHorizontal}px`,
},
'& .Select.Select--multi': {
'& .Select-control': {
backgroundColor: selectInputBg,
},
'& .Select-input': {
marginLeft: selectPaddingHorizontal,
padding: 0,
verticalAlign: 'middle',
},
'&.has-value .Select-input': {
marginLeft: selectItemGutter,
},
'& .Select-value': {
alignItems: 'flex-start',
backgroundColor: theme.palette.grey[100],
border: `1px solid ${theme.palette.border.primary}`,
borderRadius: selectItemBorderRadius,
color: 'p.text.primary',
display: 'inline-flex',
flexDirection: 'row-reverse',
fontSize: selectItemFontSize,
height: 30,
justifyContent: 'flex-start',
marginLeft: 6,
marginTop: 6,
verticalAlign: 'top',
},
'& .Select-value-label, & .Select-value-icon': {
alignItems: 'center',
alignSelf: 'stretch',
display: 'inline-flex',
flex: '0 1 auto',
justifyContent: 'center',
verticalAlign: 'middle',
},
'& .Select-value-label': {
borderBottomLeftRadius: selectItemBorderRadius,
borderTopLeftRadius: selectItemBorderRadius,
cursor: 'default',
fontSize: 14,
padding: '0 11px',
},
'& a.Select-value-label': {
color: selectItemColor,
cursor: 'pointer',
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
},
},
'& .Select-value-icon': {
border: `1px solid ${p.border.primary}`,
borderBottomRightRadius: selectItemBorderRadius,
borderRightRadius: selectItemBorderRadius,
borderTopRightRadius: selectItemBorderRadius,
color: p.text.secondary,
cursor: 'pointer',
lineHeight: 1,
margin: '-1px -1px -1px 0',
padding: '0 9px',
position: 'relative',
speak: 'none',
textTransform: 'none',
transition: [
[
'background-color 150ms linear',
],
[
'border-color 150ms linear',
],
[
'color 150ms linear',
],
],
'&:hover, &:focus': {
backgroundColor: p.grey[400],
borderColor: p.grey[400],
color: p.text.contrastText,
},
'&:active': {
backgroundColor: selectItemBorderColor,
},
},
'&.is-open > .Select-control .Select-arrow-zone .ui.icon .icon-use-path': {
fill: p.cyan,
},
},
'& .Select--multi.is-disabled': {
'& > .Select-control': {
backgroundColor: selectInputBgDisabled,
'&:hover': {
boxShadow: 'none',
},
},
'& .Select-value-icon': {
cursor: 'not-allowed',
borderRight: `1px solid ${selectItemDisabledBorderColor}`,
'&:hover, &:focus, &:active': {
backgroundColor: selectItemDisabledBg,
},
},
},
'&$isUnderlined': {
'& .Select--single .Select-control': {
borderLeft: 0,
borderRadius: 0,
borderRight: 0,
borderTop: 0,
fontSize: '14px',
height: 32,
'&:hover': {
boxShadow: 'none',
},
'& .Select-placeholder': {
lineHeight: '33px',
paddingLeft: 0,
paddingRight: 0,
},
'& .Select-value': {
lineHeight: '33px',
paddingLeft: 0,
},
'& .Select-input': {
height: 32,
paddingLeft: 0,
'& > input': {
color: p.text.primary,
padding: '7px 0 11px',
},
},
'& .Select-arrow-zone': {
paddingRight: 0,
width: 10,
},
'& .ui.icon-times': {
height: 10,
width: 10,
},
},
'& .is-open:not(.Select--multi).Select--single > .Select-control': {
backgroundColor: p.background.primary,
borderBottomColor: selectInputBorderColor,
boxShadow: 'none',
color: p.text.primary,
'& .Select-arrow-zone .icon-use-path': {
fill: `${p.cyan[500]} !important`,
},
},
},
},
};
});
/**
* The Select component represents a control that provides a menu of options.
*/
// eslint-disable-next-line prefer-arrow-callback
const Select = React.forwardRef(function Select(props, ref) {
const {
className,
clearable: isClearable,
creatable: isCreatable,
disable: disableProp,
disabled: disabledProp,
dropdownMenuContainerStyle,
dropdownMenuStyle,
dropdownMenuMaxHeight,
dropdownMenuMinHeight,
error,
fluid: isFluid,
id,
label,
matchProp,
multiple,
noResultsText,
onChange: onChangeProp,
onClose,
onOpen: onOpenProp,
optionComponent,
options,
placeholder,
promptTextCreator,
required,
searchable: isSearchable,
tabIndex,
underline: isUnderlined,
value,
valueComponent,
...otherProps
} = props;
const classes = useStyles(props);
const innerMenuRef = useRef();
const menuScrollBarRef = useRef();
const focusedOptionRef = useRef();
const [scrollToFocusedOption, setScrollToFocusedOption] = React.useState(false);
React.useEffect(() => {
if (
scrollToFocusedOption &&
focusedOptionRef && focusedOptionRef.current &&
innerMenuRef && innerMenuRef.current &&
menuScrollBarRef && menuScrollBarRef.current
) {
const focusedDOM = focusedOptionRef.current;
const focusedRect = focusedDOM.getBoundingClientRect();
const innerMenuDOM = innerMenuRef.current;
const innerMenuRect = innerMenuDOM.getBoundingClientRect();
if (focusedRect.bottom > innerMenuRect.bottom) {
menuScrollBarRef.current.scrollTop(
focusedDOM.offsetTop + focusedDOM.clientHeight - innerMenuDOM.offsetHeight,
);
} else if (focusedRect.top < innerMenuRect.top) {
menuScrollBarRef.current.scrollTop(focusedDOM.offsetTop);
}
setScrollToFocusedOption(false);
}
}, [scrollToFocusedOption]);
const onChange = (selectedOption) => {
if (isFunction(onChangeProp)) {
onChangeProp(selectedOption);
}
};
const menuRenderer = (params) => {
const items = map(params.options, (o, i) => {
const isFocused = o === params.focusedOption;
const isSelected = params.valueArray && params.valueArray.some((x) => (
x[params.valueKey] === o[params.valueKey]
));
const optionClass = ClassNames(
'Select-option',
params.optionClassName,
{
'is-disabled': o.disabled,
'is-focused': isFocused,
'is-selected': isSelected,
},
);
if (optionComponent) {
const OptionComponent = optionComponent;
return (
<OptionComponent
className={optionClass}
focusOption={params.focusOption}
isDisabled={o.disabled}
isFocused={isFocused}
isSelected={isSelected}
key={`select-option-key-${i}`}
onFocus={params.onFocus}
onSelect={params.selectValue}
option={o}
ref={isFocused ? focusedOptionRef : undefined}
/>
);
}
return (
<div
aria-selected={isSelected}
className={optionClass}
key={`select-option-key-${i}`}
onClick={() => params.selectValue(o)}
onFocus={noop}
onKeyDown={noop}
onMouseOver={() => params.focusOption(o)}
ref={isFocused ? focusedOptionRef : undefined}
role="option"
tabIndex={0}
>
{o.label}
</div>
);
});
return (
<div
ref={innerMenuRef}
>
<ScrollBar
autoHeight
autoHeightMax={dropdownMenuMaxHeight || 180}
autoHeightMin={dropdownMenuMinHeight}
autoHide
className="select-menu-scrollbar"
ref={menuScrollBarRef}
>
{items}
</ScrollBar>
</div>
);
};
const onInputKeyDown = (event) => {
switch (event.keyCode) {
case 38: // up
case 40: // down
setScrollToFocusedOption(true);
break;
default:
}
};
const onOpen = () => {
if (isFunction(onOpenProp)) {
onOpenProp();
}
if (menuScrollBarRef && menuScrollBarRef.current && value) {
const itemHeight = menuScrollBarRef.current.getScrollHeight() / size(options);
const pageSize = menuScrollBarRef.current.getClientHeight() / itemHeight;
const selectionIndex = findIndex(options, (o) => {
if (matchProp === 'any') {
const hasValue = has(o, 'value');
const hasLabel = has(o, 'label');
if (!hasValue && !hasLabel) {
return false;
}
return (
(
hasValue && o.value === value.value
) || o.value === value
) || (
(
hasLabel && o.label === value.label
) || o.label === value
);
}
return o[matchProp] === value[matchProp];
});
const scrollRatio = selectionIndex / pageSize;
if (scrollRatio >= 1) {
menuScrollBarRef.current.scrollTop(scrollRatio * pageSize * itemHeight);
}
}
};
const rootClasses = ClassNames(
UI_CLASS_NAME,
BEM_SELECT,
classes.root,
className,
{
[classes.hasError]: !!error,
[classes.isFluid]: isFluid,
[classes.isUnderlined]: isUnderlined,
},
);
const showRequiredIndicator = required && isEmpty(value);
const ReactSelectComponent = isCreatable ? ReactSelect.Creatable : CustomReactSelect;
return (
<div
// eslint-disable-next-line react/jsx-props-no-spreading
{...otherProps}
className={rootClasses}
id={id}
ref={ref}
>
{label && (
// eslint-disable-next-line jsx-a11y/label-has-associated-control
<label
className={ClassNames(
'label',
classes.label,
)}
>
{label}
{required && showRequiredIndicator ? (
<span className={classes.requiredIndicator}>*</span>
) : null}
</label>
)}
<ReactSelectComponent
arrowRenderer={() => {
if (isCreatable) {
return (
<div>
<Icon
compact
size={16}
title="Select"
type="plus"
/>
</div>
);
}
if (isUnderlined) {
return (
<Icon
compact
size={10}
title="Select"
type="caret-down"
/>
);
}
return (
<div>
<Icon
compact
size={16}
title="Select"
type="chevron-down"
/>
</div>
);
}}
clearRenderer={() => (
<div>
<Icon
compact
size={16}
title="Clear Selection"
type="times"
/>
</div>
)}
clearable={isClearable}
disabled={disabledProp || disableProp}
matchProp={!isCreatable ? matchProp : null}
menuContainerStyle={dropdownMenuContainerStyle}
menuRenderer={menuRenderer}
menuStyle={dropdownMenuStyle}
multi={multiple}
noResultsText={noResultsText}
onClose={onClose}
onInputKeyDown={onInputKeyDown}
onOpen={onOpen}
name="firstSelect"
onChange={onChange}
optionComponent={optionComponent}
options={options}
promptTextCreator={isCreatable && promptTextCreator}
placeholder={placeholder}
searchable={isSearchable}
tabIndex={tabIndex}
value={value}
valueComponent={valueComponent}
>
{isCreatable && CustomCreatableSelect}
</ReactSelectComponent>
{isString(error) && !!error && (
<p className={classes.errorMessage}>
{error}
</p>
)}
</div>
);
});
Select.propTypes = propTypes;
Select.defaultProps = defaultProps;
export default Select;