UNPKG

@6thquake/react-material

Version:

React components that implement Google's Material Design.

383 lines (337 loc) 10.6 kB
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; import _extends from "@babel/runtime/helpers/extends"; /** * @ignore - do not document. */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import SelectRoot from './SyncSelect'; import Pagination from '../Pagination'; import AsyncSelectFilter from './AsyncSelectFilter'; import Divider from '../Divider'; import withStyles from '../styles/withStyles'; import ArrowDropDownIcon from '../internal/svg-icons/ArrowDropDown'; import Input from '../Input'; import yellow from '../colors/yellow'; const styles = theme => ({ selectMenu: { whiteSpace: 'pre-wrap' }, root: { width: '100%' }, icon: { color: theme.palette.grey[300] }, inputText: { color: theme.palette.common.white, '&$disabled': { color: theme.palette.grey[200] } }, underline: { '&:after': { borderBottomColor: yellow[500] }, '&:before': { borderBottomColor: theme.palette.grey[300] } // '&$disabled:before': { // borderBottomColor: theme.palette.grey[200], // }, // '&:hover:not($disabled):not($focused):not($error):before': { // borderBottomColor: 'red', // }, } }); var _ref = React.createElement(Input, null); var _ref2 = React.createElement(Divider, null); class Select extends Component { constructor(props) { super(props); this.state = { paginationProps: { page: 0, rowsPerPage: 5, count: 0 }, text: '', optionsArray: [] }; } onChangePage(i) { this.setState({ paginationProps: _extends({}, this.state.paginationProps, { page: i }) }, () => { const op = this.menuItems(this.state.text); const start = this.state.paginationProps.page * this.state.paginationProps.rowsPerPage; const end = (this.state.paginationProps.page + 1) * this.state.paginationProps.rowsPerPage > op.length ? undefined : (this.state.paginationProps.page + 1) * this.state.paginationProps.rowsPerPage; this.setState({ optionsArray: op.slice(start, end) }); }); } onfilter(e) { const op = this.menuItems(e.target.value); this.setState({ text: e.target.value, paginationProps: _extends({}, this.state.paginationProps, { page: 0, count: op.length }) }, () => { const op = this.menuItems(this.state.text); const start = this.state.paginationProps.page * this.state.paginationProps.rowsPerPage; const end = (this.state.paginationProps.page + 1) * this.state.paginationProps.rowsPerPage > op.length ? undefined : (this.state.paginationProps.page + 1) * this.state.paginationProps.rowsPerPage; this.setState({ optionsArray: op.slice(start, end) }); }); } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps !== prevState.preProps) { if (nextProps.showPagination) { return { paginationProps: _extends({}, prevState.paginationProps, { rowsPerPage: nextProps.rowsPerPage, count: nextProps.children.length }), preProps: nextProps }; } return { optionsArray: nextProps.children, preProps: nextProps }; } return null; } menuItems(text) { const { children } = this.props; let filterData = []; if (children) { filterData = React.Children.toArray(children).filter(child => { return !text || child.props.children.toLowerCase().indexOf(text.toLowerCase()) !== -1 || child.props.value.toLowerCase().indexOf(text.toLowerCase()) !== -1; }); return filterData; } return null; } render() { const _this$props = this.props, { isDark, children, placeholder, multiple, classes, disabled, htmlFor, onChange, renderValue, value, showPagination, showFilter, displayEmpty, IconComponent } = _this$props, other = _objectWithoutPropertiesLoose(_this$props, ["isDark", "children", "placeholder", "multiple", "classes", "disabled", "htmlFor", "onChange", "renderValue", "value", "showPagination", "showFilter", "displayEmpty", "IconComponent"]); const input = isDark ? React.createElement(Input, { classes: { root: classes.inputText, underline: classes.underline } }) : _ref; const { text, paginationProps, optionsArray } = this.state; return React.createElement(SelectRoot, _extends({}, other, { input: input, multiple: multiple, value: value, displayEmpty: displayEmpty, onChange: onChange, classes: _extends({}, classes, { root: classes.root, selectMenu: classes.selectMenu, icon: isDark && classes.icon }), inputProps: { IconComponent, placeholder, id: htmlFor }, disabled: disabled, renderValue: selected => { if (renderValue) { return renderValue(selected); } let displaySingle = ''; const displayMultiple = []; React.Children.map(children, child => { if (!React.isValidElement(child)) { return null; } let selected; if (multiple) { if (!Array.isArray(value)) { throw new Error('React-Material: the `value` property must be an array ' + 'when using the `Select` component with `multiple`.'); } selected = value.indexOf(child.props.value) !== -1; if (selected) { displayMultiple.push(child.props.children); } } else { selected = value === child.props.value; if (selected) { displaySingle = child.props.children; } } }); return multiple ? displayMultiple.join(', ') : displaySingle; } }), showFilter ? React.createElement(AsyncSelectFilter, { fullWidth: true, autoFocus: true, text: text, placeholder: placeholder, onChange: this.onfilter.bind(this) }) : null, optionsArray, showPagination ? _ref2 : null, showPagination ? React.createElement(Pagination, _extends({}, paginationProps, { onChangePage: this.onChangePage.bind(this) })) : null); } } process.env.NODE_ENV !== "production" ? Select.propTypes = { /** * If true, the width of the popover will automatically be set according to the items inside the * menu, otherwise it will be at least the width of the select input. */ autoWidth: PropTypes.bool, /** * The option elements to populate the select with. Can be some MenuItem when native is false and option when native is true. * ⚠️The MenuItem elements must be direct descendants when native is false. */ children: PropTypes.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css-api) below for more details. */ classes: PropTypes.object.isRequired, /** * Whether disabled the select */ disabled: PropTypes.bool, /** * If true, a value is displayed even if no items are selected. * In order to display a meaningful value, a function should be passed to the renderValue prop which returns the value to be displayed when no items are selected. You can only use it when the native prop is false (default). */ displayEmpty: PropTypes.bool, /** * The icon that displays the arrow. */ IconComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.object]), /** * An Input element; does not have to be a material-ui specific Input. */ input: PropTypes.element, /** * Attributes applied to the input element. When native is true, the attributes are applied on the select element. */ inputProps: PropTypes.object, /** * isDark */ isDark: PropTypes.bool, /** * Props applied to the Menu element. */ MenuProps: PropTypes.object, /** * If true, value must be an array and the menu will support multiple selections. */ multiple: PropTypes.bool, /** * If true, the component will be using a native select element. */ native: PropTypes.bool, /** * Callback function fired when a menu item is selected. * * Signature: * function(event: object, child?: object) => void * event: The event source of the callback. You can pull out the new value by accessing event.target.value. * child: The react element that was selected when native is false (default). */ onChange: PropTypes.func, /** * Callback fired when the component requests to be closed. Use in controlled mode (see open). * * Signature: * function(event: object) => void * event: The event source of the callback */ onClose: PropTypes.func, /** * Callback fired when the component requests to be opened. Use in controlled mode (see open). * * Signature: * function(event: object) => void * event: The event source of the callback */ onOpen: PropTypes.func, /** * Control select open state. You can only use it when the native prop is false (default). */ open: PropTypes.bool, /** * placeholder */ placeholder: PropTypes.string, /** * Render the selected value. You can only use it when the native prop is false (default). * * Signature: * function(value: any) => ReactElement * value: The value provided to the component. */ renderValue: PropTypes.func, /** * row per page. */ rowsPerPage: PropTypes.number, /** * Props applied to the clickable div element. */ SelectDisplayProps: PropTypes.object, /** * If true, show the filter box */ showFilter: PropTypes.bool, /** * If true, show the pagination box */ showPagination: PropTypes.bool, /** * The input value. This prop is required when the native prop is false (default). */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]) } : void 0; Select.defaultProps = { autoWidth: false, displayEmpty: false, rowsPerPage: 5, IconComponent: ArrowDropDownIcon, input: React.createElement(Input, null), multiple: false, native: false, placeholder: 'please input something', showFilter: false, showPagination: false, isDark: false }; export default withStyles(styles)(Select);