UNPKG

@6thquake/react-material

Version:

React components that implement Google's Material Design.

524 lines (485 loc) 12.1 kB
import _extends from "@babel/runtime/helpers/extends"; import React from 'react'; import PropTypes from 'prop-types'; import withStyles from '../styles/withStyles'; import AppBar from '../AppBar'; import MenuItem from '../MenuItem'; import MenuList from '../MenuList'; import Typography from '../Typography'; import Paper from '../Paper'; import isEqual from 'lodash/isEqual'; import cloneDeep from 'lodash/cloneDeep'; import KeyboardArrowDown from '@material-ui/icons/KeyboardArrowDown'; import KeyboardArrowUp from '@material-ui/icons/KeyboardArrowUp'; import FilterList from '@material-ui/icons/FilterList'; import SwipeableDrawer from '../SwipeableDrawer'; import ActionFilter from './ActionFilter'; const dropDownStyle = theme => ({ root: { position: 'absolute', width: '100%', top: 0, backgroundColor: 'inherit', boxSizing: 'content-box', zIndex: theme.zIndex.appBar - 1 }, menuList: { zIndex: theme.zIndex.appBar, position: 'relative' }, menuItem: { backgroundColor: theme.palette.primary.main, '& $primary, & $icon': { color: theme.palette.common.white } }, mask: { width: '100vh', height: '100vh', position: 'fixed', opacity: 0, background: 'black', left: 0, top: 0, zIndex: theme.zIndex.appBar - 1 } }); function DropDown({ theme, onClose, onChange, classes, value, options = [] }) { return React.createElement(Paper, { square: true, elevation: 1, className: classes.root }, React.createElement(MenuList, { className: classes.menuList }, options.map(item => { const active = item.value === value; return React.createElement(MenuItem, { onClick: () => { onChange(item.value); }, key: item.value, className: active ? classes.menuItem : '' }, React.createElement(Typography, { style: { color: active ? theme.palette.common.white : '' }, variant: 'body1' }, item.label)); })), React.createElement("div", { className: classes.mask, onClick: onClose })); } const StyledDropDown = withStyles(dropDownStyle, { name: 'RMDropDown', withTheme: true })(DropDown); export const styles = theme => ({ root: { position: 'relative', 'box-sizing': 'border-box', backgroundColor: theme.palette.background.paper }, bar: { display: 'flex', flex: 1, justifyContent: 'space-between', alignItems: 'center', padding: `${theme.spacing(1.5)}px ${theme.spacing(1)}px`, zIndex: theme.zIndex.appBar }, leftBox: { display: 'flex' }, left: { display: 'flex', alignItems: 'center', paddingRight: theme.spacing(0.5) }, label: { paddingLeft: theme.spacing(1) }, leftPriority: { display: 'flex', alignItems: 'center' }, slots: { display: 'flex', flex: 1, alignItems: 'center' }, rightBox: { display: 'flex', alignItems: 'center', paddingLeft: theme.spacing(0.5), justifyContent: 'flex-end' }, right: { alignItems: 'center', display: 'flex' }, rightPriority: { alignItems: 'center', display: 'flex' }, item: { marginRight: theme.spacing(1) }, menuBox: { position: 'relative', backgroundColor: 'inherit', width: '100%' } }); class ActionBar extends React.Component { constructor(_props) { super(_props); this.init = props => { const { filters, sorts } = props; const _filters = cloneDeep(filters); const _sorts = cloneDeep(sorts); const priorityFilters = []; const selectedFilters = []; _filters.forEach((filter, i) => { const { label, value, data } = filter; const datas = []; data.forEach((item, j) => { if (item.priority) { item.i = i; item.j = j; priorityFilters.push(item); } if (item.active) { datas.push(item); } }); if (datas.length > 0) { selectedFilters.push({ label, value, data: datas }); } }); const prioritySorts = []; const normalSorts = []; let value = ''; _sorts.forEach(item => { if (item.priority) { prioritySorts.push(item); } else { normalSorts.push(item); } if (item.active) { value = item.value; } }); this.setState({ value, prioritySorts, normalSorts, priorityFilters, selectedFilters }); }; this.filter = null; this.refFilter = node => this.filter = node; this.handleTitleClick = e => { const { expanded } = this.state; this.setState({ expanded: !expanded }); }; this.handleChange = value => { const { normalSorts, prioritySorts } = this.state; normalSorts.forEach(item => { if (item.value === value) { item.active = true; } else { item.active = false; } }); prioritySorts.forEach(item => { item.active = false; }); this.setState({ value, expanded: false }, () => { this.onChange(); }); }; this.handleSiftingClick = () => { this.setState({ open: true, expanded: false }); }; this.handleFilterChange = e => { const priorityFilters = []; e.forEach((filter, i) => { filter.data.forEach((item, j) => { if (item.priority) { item.i = i; item.j = j; priorityFilters.push(item); } }); }); this.setState({ priorityFilters }); }; this.handleFilterOk = e => { this.setState({ selectedFilters: e, open: false }, () => { this.onChange(); }); }; this.handleFilterReset = e => { this.setState({ selectedFilters: e }, () => { this.onChange(); }); }; this.onChange = () => { const { onChange, sorts } = this.props; const { selectedFilters, value } = this.state; const data = { sort: sorts.filter(item => item.value === value)[0], filters: selectedFilters }; onChange(data); }; this.handleDrawerClose = () => { this.setState({ open: false }); }; this.handleDropDownClose = () => { this.setState({ expanded: false }); }; this.handleDrawerClose = () => { this.setState({ open: false }); }; this.domRef = React.createRef(); this.state = { expanded: false, open: false, value: '' }; } componentDidMount() { this.init(this.props); } componentWillReceiveProps(nextProps) { const { filter, sorts } = this.props; if (!isEqual(nextProps.filter, filter) || !isEqual(nextProps.sorts, sorts)) { this.init(nextProps); } } handlePriorities(index) { const { normalSorts, prioritySorts } = this.state; let value = null; prioritySorts.forEach((item, i) => { if (i === index) { item.active = true; value = item.value; } else { item.active = false; } }); normalSorts.forEach(item => { item.active = false; }); this.setState({ value, expanded: false }, () => { this.onChange(); }); } handleFilters(i, j) { this.filter.handleClick(i, j, true); } render() { const { classes, theme, filters, AppBarProps, children } = this.props; const iOS = process.browser && /iPad|iPhone|iPod/.test(navigator.userAgent); const { expanded, value, open } = this.state; const { selectedFilters = [], priorityFilters = [], normalSorts = [], prioritySorts = [] } = this.state; const multiLength = selectedFilters.reduce((r, next) => r + next.data.length, 0); const selectedSort = normalSorts.filter(item => item.value === value)[0] || { label: '排序', active: false, value }; const ArrowIcon = expanded ? KeyboardArrowDown : KeyboardArrowUp; return React.createElement(AppBar, _extends({ elevation: 1, position: "static", color: "default", className: classes.root }, AppBarProps), React.createElement("div", { className: classes.bar }, React.createElement("div", { className: classes.leftBox }, React.createElement("div", { onClick: this.handleTitleClick, className: classes.left }, React.createElement(Typography, { style: { color: selectedSort.active ? theme.palette.primary.main : '' }, className: classes.label, variant: "body1" }, selectedSort.label), React.createElement(ArrowIcon, { color: selectedSort.active ? 'primary' : 'inherit' })), React.createElement("div", { className: classes.leftPriority }, prioritySorts.map((item, index) => { const color = item.active ? theme.palette.primary.main : ''; const className = item.active ? 'body2' : 'body1'; return React.createElement("div", { key: item.value, className: classes.item, onClick: this.handlePriorities.bind(this, index) }, React.createElement(Typography, { style: { color }, variant: className }, item.label)); }))), React.createElement("div", { className: classes.slots }, children), React.createElement("div", { className: classes.rightBox }, React.createElement("div", { className: classes.rightPriority }, priorityFilters.map((item, index) => { const color = item.active ? theme.palette.primary.main : ''; const className = item.active ? 'body2' : 'body1'; return React.createElement("div", { key: item.value, className: classes.item, onClick: this.handleFilters.bind(this, item.i, item.j) }, React.createElement(Typography, { style: { color }, variant: className }, item.label)); })), React.createElement("div", { className: classes.right }, React.createElement("div", { onClick: this.handleSiftingClick, className: classes.left }, React.createElement(Typography, { color: multiLength ? 'primary' : '', className: classes.label, variant: multiLength > 0 ? 'body2' : 'body1' }, "\u7B5B\u9009", multiLength ? `(${multiLength})` : ''), React.createElement(FilterList, { color: multiLength > 0 ? 'primary' : 'inherit' }))))), expanded && React.createElement("div", { className: classes.menuBox }, React.createElement(StyledDropDown, { onClose: this.handleDropDownClose, onChange: this.handleChange, options: normalSorts, value: value })), React.createElement(SwipeableDrawer, { variant: "persistent", disableBackdropTransition: !iOS, disableDiscovery: iOS, onClose: this.handleDrawerClose, anchor: "right", open: open }, React.createElement(ActionFilter, { data: filters, onOk: this.handleFilterOk, onReset: this.handleFilterReset, onChange: this.handleFilterChange, innerRef: this.refFilter }))); } } process.env.NODE_ENV !== "production" ? ActionBar.propTypes = { /** * items of filters */ filters: PropTypes.array, /** * data of sort bar */ sorts: PropTypes.array, /** * Callback fired when the selected data to be changed. */ onChange: PropTypes.func, /** * Props of AppBar */ AppBarProps: PropTypes.object } : void 0; ActionBar.defaultProps = { onChange: () => {}, filters: [], sorts: [], AppBarProps: {} }; export default withStyles(styles, { name: 'RMActionBar', withTheme: true })(ActionBar);