@6thquake/react-material
Version:
React components that implement Google's Material Design.
448 lines (389 loc) • 11 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
/**
* @ignore - do not document.
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import TextField from '../TextField';
import Paper from '../Paper';
import Chip from '../Chip';
import Pagination from '../Pagination';
import Divider from '../Divider';
import MenuItem from '../MenuItem';
import { debounce } from '../utils/throttle';
import withStyles from '../styles/withStyles';
const styles = theme => ({
root: {
flexGrow: 1
},
container: {
flexGrow: 1,
position: 'relative'
},
textarea: {
width: '100%'
},
modal: {
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
overflow: 'hidden',
outline: 0,
backgroundColor: 'rgb(0, 0, 0)',
opacity: 0,
zIndex: 1
},
paper: {
position: 'absolute',
zIndex: 200,
marginTop: theme.spacing(1),
left: 0,
right: 0,
padding: '10px'
},
chip: {
margin: `${theme.spacing(0.5)}px ${theme.spacing(0.25)}px`
},
inputRoot: {
flexGrow: 1,
flexWrap: 'wrap'
},
inputHold: {
padding: '10px 0 7px'
}
});
var _ref = React.createElement(Divider, null);
class AsyncAutoComplete extends Component {
constructor(props) {
super(props);
this.handleDelete = item => event => {
if (this.props.disabled) {
return;
}
const value = [...this.props.value];
value.splice(value.indexOf(item), 1);
let target;
if (event.target) {
target = event.target;
}
event.persist();
event.target = _extends({}, target, {
value
});
this.props.onChange(event);
};
this.handleItemClick = child => event => {
this.setState({
inputValue: ''
});
if (!this.props.multiple) {
this.setState({
open: false
});
}
const {
onChange
} = this.props;
if (onChange) {
let value;
let target;
if (event.target) {
target = event.target;
}
const selecttext = child ? child.props.value : event.target.textContent;
if (this.props.multiple) {
value = Array.isArray(this.props.value) ? [...this.props.value] : [];
const itemIndex = value.indexOf(selecttext);
if (itemIndex === -1) {
value.push(selecttext);
} else {
value.splice(itemIndex, 1);
}
} else {
value = selecttext;
this.setState({
inputValue: value
});
}
event.persist();
event.target = _extends({}, target, {
value
});
onChange(event, child);
}
};
this.handleBlur = event => {
if (this.props.onBlur) {
this.props.onBlur(event);
} else {
const {
onChange
} = this.props;
if (onChange) {
let value;
let target;
if (event.target) {
target = event.target;
}
const selecttext = this.state.inputValue;
if (this.props.multiple) {
value = Array.isArray(this.props.value) ? [...this.props.value] : [];
const itemIndex = value.indexOf(selecttext);
if (itemIndex === -1) {
if (selecttext) {
value.push(selecttext);
}
}
this.setState({
open: false,
inputValue: ''
});
} else {
value = selecttext;
this.setState({
open: false,
inputValue: value
});
}
event.persist();
event.target = _extends({}, target, {
value
});
onChange(event);
}
}
};
this.throttlingtem = debounce(props.onChangeInput, props.debounceProps.wait);
this.state = {
open: false,
inputValue: '',
selectedItem: [],
page: 0
};
}
componentDidMount() {
if (!this.props.multiple) {
this.setState({
inputValue: this.props.value
});
}
}
onFocus(e) {
if (this.props.select) {
this.setState({
open: true
});
}
}
handleChange(event) {
this.setState({
open: true,
inputValue: event.target.value
});
if (this.props.debounceAble) {
event.persist();
this.throttlingtem(event);
} else {
this.props.onChangeInput(event);
}
}
render() {
const {
PaginationProps,
onChangePage,
classes,
placeholder,
children,
multiple,
value,
options,
mapper,
disabled
} = this.props;
const {
open,
inputValue
} = this.state;
let items;
if (options) {
items = options ? options.map((item, index) => {
let selected = false;
switch (typeof item) {
case 'string':
if (multiple) {
if (!Array.isArray(value)) {
throw new Error('React-Material: the `value` property must be an array ' + 'when using the `AsyncAutoComplete` component with `multiple`.');
}
selected = value.indexOf(item) !== -1;
} else {
selected = value === item;
}
return React.createElement(MenuItem, {
key: index,
value: item,
selected: selected,
onClick: this.handleItemClick(null)
}, item);
case 'object':
if (multiple) {
if (!Array.isArray(value)) {
throw new Error('React-Material: the `value` property must be an array ' + 'when using the `AsyncAutoComplete` component with `multiple`.');
}
selected = value.indexOf(typeof mapper.value === 'function' ? mapper.value(item, index) : item[mapper.value]) !== -1;
} else {
selected = value === (typeof mapper.value === 'function' ? mapper.value(item, index) : item[mapper.value]);
}
return React.createElement(MenuItem, {
key: index,
value: item[mapper.value],
selected: selected,
onClick: this.handleItemClick(null)
}, typeof mapper.label === 'function' ? mapper.label(item, index) : item[mapper.label]);
default:
throw new Error('AsyncAutoComplete[options] only supports type `string[] | Object[]`.');
}
}) : [];
} else {
items = React.Children.map(children, child => {
if (!React.isValidElement(child)) {
return null;
}
let selected = false;
if (multiple) {
if (!Array.isArray(value)) {
throw new Error('React-Material: the `value` property must be an array ' + 'when using the `AsyncAutoComplete` component with `multiple`.');
}
selected = value.indexOf(child.props.value) !== -1;
} else {
selected = value === child.props.value;
}
return React.cloneElement(child, {
onClick: this.handleItemClick(child),
role: 'option',
selected,
value: undefined,
// The value is most likely not a valid HTML attribute.
'data-value': child.props.value // Instead, we provide it as a data attribute.
});
});
}
return React.createElement("div", {
className: classes.root
}, open ? React.createElement("div", {
onClick: this.handleBlur,
className: classes.modal
}) : null, React.createElement("div", {
className: classes.container
}, multiple ? React.createElement(TextField, {
disabled: disabled,
className: classes.textarea,
onChange: this.handleChange.bind(this),
value: inputValue,
multiline: true,
onFocus: this.onFocus.bind(this),
rows: "1",
InputProps: {
classes: {
root: classes.inputRoot,
input: classes.inputHold
},
startAdornment: value.map(item => React.createElement(Chip, {
key: item,
label: item,
className: classes.chip,
onDelete: this.handleDelete(item)
})),
placeholder: value.length > 0 ? '' : placeholder
}
}) : React.createElement(TextField, {
disabled: disabled,
onFocus: this.onFocus.bind(this),
className: classes.textarea,
onChange: this.handleChange.bind(this),
value: inputValue,
placeholder: placeholder
}), open ? React.createElement(Paper, {
className: classes.paper,
square: true
}, items, _ref, React.createElement(Pagination, _extends({}, PaginationProps, {
onChangePage: onChangePage
}))) : null));
}
}
process.env.NODE_ENV !== "production" ? AsyncAutoComplete.propTypes = {
/**
* If true, autocomplete will add debounce when filter options by input value.
*/
debounceAble: PropTypes.bool,
/**
* If debounceAble true, config debounce wait and max continue time, the unit is milliseconds.
*/
debounceProps: PropTypes.shape({
wait: PropTypes.number
}),
/**
* Decided autocomplete is disabled
*/
disabled: PropTypes.bool,
/**
* option item label and value, when assignment option by options
*/
mapper: PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
}),
/**
* Decided multiple select. If true, value must be an array and the menu will support multiple selections.
*/
multiple: PropTypes.bool,
/**
* Callback function fired when a menu item is selected.
*/
onChange: PropTypes.func.isRequired,
/**
* Callback fired when the input value is changed.
*/
onChangeInput: PropTypes.func,
/**
* Callback fired when the current page of pagination is changed.
*/
onChangePage: PropTypes.func,
/**
* autocomplete options,
*/
options: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.number])),
/**
* Pagination component config
*/
PaginationProps: PropTypes.object,
/**
* placeholder
*/
placeholder: PropTypes.string,
/**
* If true, autocomplete performance is like a select, when focus, option open.
*/
select: PropTypes.bool,
/**
* The value of the Input element, required for a controlled component.
*/
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))])
} : void 0;
AsyncAutoComplete.defaultProps = {
PaginationProps: {
page: 0,
rowsPerPage: 5,
count: 0
},
multiple: false,
disabled: false,
select: false,
debounceProps: {
wait: 1000
}
};
export default withStyles(styles, {
name: 'RMAsyncAutoComplete'
})(AsyncAutoComplete);