@activelylearn/material-ui
Version:
Material-UI's workspace package
312 lines (293 loc) • 8.11 kB
JavaScript
/* eslint-disable react/prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Input from '@material-ui/core/Input';
import TextField from '@material-ui/core/TextField';
import MenuItem from '@material-ui/core/MenuItem';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import CancelIcon from '@material-ui/icons/Cancel';
import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp';
import ClearIcon from '@material-ui/icons/Clear';
import Chip from '@material-ui/core/Chip';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
const suggestions = [
{ label: 'Afghanistan' },
{ label: 'Aland Islands' },
{ label: 'Albania' },
{ label: 'Algeria' },
{ label: 'American Samoa' },
{ label: 'Andorra' },
{ label: 'Angola' },
{ label: 'Anguilla' },
{ label: 'Antarctica' },
{ label: 'Antigua and Barbuda' },
{ label: 'Argentina' },
{ label: 'Armenia' },
{ label: 'Aruba' },
{ label: 'Australia' },
{ label: 'Austria' },
{ label: 'Azerbaijan' },
{ label: 'Bahamas' },
{ label: 'Bahrain' },
{ label: 'Bangladesh' },
{ label: 'Barbados' },
{ label: 'Belarus' },
{ label: 'Belgium' },
{ label: 'Belize' },
{ label: 'Benin' },
{ label: 'Bermuda' },
{ label: 'Bhutan' },
{ label: 'Bolivia, Plurinational State of' },
{ label: 'Bonaire, Sint Eustatius and Saba' },
{ label: 'Bosnia and Herzegovina' },
{ label: 'Botswana' },
{ label: 'Bouvet Island' },
{ label: 'Brazil' },
{ label: 'British Indian Ocean Territory' },
{ label: 'Brunei Darussalam' },
].map(suggestion => ({
value: suggestion.label,
label: suggestion.label,
}));
class Option extends React.Component {
handleClick = event => {
this.props.onSelect(this.props.option, event);
};
render() {
const { children, isFocused, isSelected, onFocus } = this.props;
return (
<MenuItem
onFocus={onFocus}
selected={isFocused}
onClick={this.handleClick}
component="div"
style={{
fontWeight: isSelected ? 500 : 400,
}}
>
{children}
</MenuItem>
);
}
}
function SelectWrapped(props) {
const { classes, ...other } = props;
return (
<Select
optionComponent={Option}
noResultsText={<Typography>{'No results found'}</Typography>}
arrowRenderer={arrowProps => {
return arrowProps.isOpen ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />;
}}
clearRenderer={() => <ClearIcon />}
valueComponent={valueProps => {
const { value, children, onRemove } = valueProps;
const onDelete = event => {
event.preventDefault();
event.stopPropagation();
onRemove(value);
};
if (onRemove) {
return (
<Chip
tabIndex={-1}
label={children}
className={classes.chip}
deleteIcon={<CancelIcon onTouchEnd={onDelete} />}
onDelete={onDelete}
/>
);
}
return <div className="Select-value">{children}</div>;
}}
{...other}
/>
);
}
const ITEM_HEIGHT = 48;
const styles = theme => ({
root: {
flexGrow: 1,
height: 250,
},
chip: {
margin: theme.spacing.unit / 4,
},
// We had to use a lot of global selectors in order to style react-select.
// We are waiting on https://github.com/JedWatson/react-select/issues/1679
// to provide a much better implementation.
// Also, we had to reset the default style injected by the library.
'@global': {
'.Select-control': {
display: 'flex',
alignItems: 'center',
border: 0,
height: 'auto',
background: 'transparent',
'&:hover': {
boxShadow: 'none',
},
},
'.Select-multi-value-wrapper': {
flexGrow: 1,
display: 'flex',
flexWrap: 'wrap',
},
'.Select--multi .Select-input': {
margin: 0,
},
'.Select.has-value.is-clearable.Select--single > .Select-control .Select-value': {
padding: 0,
},
'.Select-noresults': {
padding: theme.spacing.unit * 2,
},
'.Select-input': {
display: 'inline-flex !important',
padding: 0,
height: 'auto',
},
'.Select-input input': {
background: 'transparent',
border: 0,
padding: 0,
cursor: 'default',
display: 'inline-block',
fontFamily: 'inherit',
fontSize: 'inherit',
margin: 0,
outline: 0,
},
'.Select-placeholder, .Select--single .Select-value': {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
fontFamily: theme.typography.fontFamily,
fontSize: theme.typography.pxToRem(16),
padding: 0,
},
'.Select-placeholder': {
opacity: 0.42,
color: theme.palette.common.black,
},
'.Select-menu-outer': {
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[2],
position: 'absolute',
left: 0,
top: `calc(100% + ${theme.spacing.unit}px)`,
width: '100%',
zIndex: 2,
maxHeight: ITEM_HEIGHT * 4.5,
},
'.Select.is-focused:not(.is-open) > .Select-control': {
boxShadow: 'none',
},
'.Select-menu': {
maxHeight: ITEM_HEIGHT * 4.5,
overflowY: 'auto',
},
'.Select-menu div': {
boxSizing: 'content-box',
},
'.Select-arrow-zone, .Select-clear-zone': {
color: theme.palette.action.active,
cursor: 'pointer',
height: 21,
width: 21,
zIndex: 1,
},
// Only for screen readers. We can't use display none.
'.Select-aria-only': {
position: 'absolute',
overflow: 'hidden',
clip: 'rect(0 0 0 0)',
height: 1,
width: 1,
margin: -1,
},
},
});
class IntegrationReactSelect extends React.Component {
state = {
single: null,
multi: null,
multiLabel: null,
};
handleChange = name => value => {
this.setState({
[name]: value,
});
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Input
fullWidth
inputComponent={SelectWrapped}
value={this.state.single}
onChange={this.handleChange('single')}
placeholder="Search a country (start with a)"
id="react-select-single"
inputProps={{
classes,
name: 'react-select-single',
instanceId: 'react-select-single',
simpleValue: true,
options: suggestions,
}}
/>
<Input
fullWidth
inputComponent={SelectWrapped}
value={this.state.multi}
onChange={this.handleChange('multi')}
placeholder="Select multiple countries"
name="react-select-chip"
inputProps={{
classes,
multi: true,
instanceId: 'react-select-chip',
id: 'react-select-chip',
simpleValue: true,
options: suggestions,
}}
/>
<TextField
fullWidth
value={this.state.multiLabel}
onChange={this.handleChange('multiLabel')}
placeholder="Select multiple countries"
name="react-select-chip-label"
label="With label"
InputLabelProps={{
shrink: true,
}}
InputProps={{
inputComponent: SelectWrapped,
inputProps: {
classes,
multi: true,
instanceId: 'react-select-chip-label',
id: 'react-select-chip-label',
simpleValue: true,
options: suggestions,
},
}}
/>
</div>
);
}
}
IntegrationReactSelect.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(IntegrationReactSelect);