UNPKG

react-cm-ui

Version:
1,086 lines (1,034 loc) 36.8 kB
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;