@6thquake/react-material
Version:
React components that implement Google's Material Design.
336 lines (310 loc) • 7.41 kB
JavaScript
/**
* @ignore - internal component.
*/
import PropTypes from 'prop-types';
import React from 'react';
import Button from '../Button';
import withStyles from '../styles/withStyles';
import Typography from '../Typography';
import cloneDeep from 'lodash/cloneDeep';
import { compose } from 'recompose';
const tagStyle = theme => {
return {
root: {
display: 'flex',
padding: `${theme.spacing(0.25)}px ${theme.spacing(1)}px`,
justifyContent: 'center',
alignItems: 'center'
}
};
};
let Tag = function ({
classes,
color,
theme,
children
}) {
const paletteColor = theme.palette[color];
const c = paletteColor ? paletteColor.main : theme.palette.grey[200];
const style = {
borderRadius: `${theme.shape.borderRadius / 2}px`,
border: `1px solid ${c}`
};
return React.createElement(Typography, {
className: classes.root,
color: color,
style: style
}, children);
};
Tag = withStyles(tagStyle, {
withTheme: true
})(Tag);
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'stretch',
position: 'relative',
height: '100vh',
minHeight: '100vh',
width: '100%',
flex: 1,
// paddingLeft: theme.spacing(2),
// paddingRight: theme.spacing(2),
boxSizing: 'border-box'
},
filters: {
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
overflow: 'auto',
flex: 1,
padding: `${theme.spacing(2)}px`
},
options: {
paddingBottom: theme.spacing(1.5),
paddingTop: theme.spacing(1.5),
'&:not(:first-child)': {
borderTop: `1px solid ${theme.palette.grey[200]}`
}
},
tags: {
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingBottom: theme.spacing(1.5),
paddingTop: theme.spacing(1.5)
},
spacing: {
flex: 1,
minWidth: '31%',
maxWidth: '31%'
},
tag: {
flex: 1,
minWidth: '31%',
maxWidth: '31%',
paddingBottom: theme.spacing(1),
paddingTop: theme.spacing(1)
},
actions: {
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center'
},
buttonBox: {
width: '50%',
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
justifyContent: 'flex-end',
'&.primary': {
background: theme.palette.primary.main
}
},
button: {
width: '100%',
boxShadow: 'none',
borderRadius: '0px',
height: theme.spacing(6)
}
});
class ActionFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.handleOkClick = () => {
const {
data: options
} = this.state;
const {
onOk
} = this.props;
const selections = options.map(item => {
const {
label,
value,
data
} = item;
const activeTag = data.filter(d => d.active);
return {
label,
value,
data: cloneDeep(activeTag)
};
}).filter(item => item.data.length > 0);
onOk(selections);
};
this.handleResetClick = () => {
const {
data,
onReset,
onChange
} = this.props;
const _data = cloneDeep(data);
const selections = _data.map(item => {
const {
label,
value
} = item;
const activeTag = item.data.filter(d => d.active);
return {
label,
value,
data: cloneDeep(activeTag)
};
}).filter(item => item.data.length > 0);
this.setState({
data: _data
}, () => {
onChange(cloneDeep(_data));
onReset(selections);
});
};
this.state.data = props.data;
}
componentWillReceiveProps(nextProps) {
const {
data
} = this.props;
if (nextProps.data !== data) {
this.setState({
data: nextProps.data
});
}
}
handleClick(i, j, immediately) {
const {
onChange
} = this.props;
const {
data
} = this.state;
const options = cloneDeep(data);
const option = options[i];
if (option.single) {
option.data.forEach((item, index) => {
if (index !== j) {
item.active = false;
}
});
}
const tag = option.data[j];
tag.active = !tag.active;
if (option.required) {
const ops = option.data.filter(item => item.active);
if (ops.length <= 0) {
tag.active = true;
}
}
this.setState({
data: options
}, () => {
onChange(cloneDeep(options));
immediately && this.handleOkClick();
});
}
render() {
const {
classes,
width
} = this.props;
const {
data: options
} = this.state;
const filtersStyle = {
width
};
return React.createElement("div", {
className: classes.root
}, React.createElement("div", {
style: filtersStyle,
className: classes.filters
}, React.createElement("div", {
className: classes.box
}, options && options.map((option, i) => {
const {
label,
value,
data
} = option;
return React.createElement("div", {
key: value,
className: classes.option
}, React.createElement("div", {
className: classes.title
}, React.createElement(Typography, {
variant: "body2"
}, label)), React.createElement("div", {
className: classes.tags
}, data.map((item, j) => React.createElement("div", {
onClick: this.handleClick.bind(this, i, j, false),
key: item.value,
className: classes.tag
}, React.createElement(Tag, {
color: item.active ? 'primary' : 'default'
}, React.createElement(Typography, {
color: "inherit",
variant: "body1"
}, item.label)))), React.createElement("div", {
className: classes.spacing
})));
}))), React.createElement("div", {
className: classes.actions
}, React.createElement("div", {
className: classes.buttonBox
}, React.createElement(Button, {
className: classes.button,
color: "default",
variant: "text",
onClick: this.handleResetClick,
size: "normal"
}, "\u91CD\u7F6E")), React.createElement("div", {
className: classes.buttonBox
}, React.createElement(Button, {
className: classes.button,
color: "primary",
variant: "contained",
onClick: this.handleOkClick,
size: "normal"
}, "\u786E\u5B9A"))));
}
}
process.env.NODE_ENV !== "production" ? ActionFilter.propTypes = {
/**
* data of action filter
*/
data: PropTypes.array,
/**
* Callback fired when the selected value to be changed.
*/
onChange: PropTypes.func,
/**
* Callback fired when the confirm button to be clicked.
*/
onOk: PropTypes.func,
/**
* Callback fired when the reset button to be clicked.
*/
onReset: PropTypes.func,
/**
* the width of action filter.
*/
width: PropTypes.width
} : void 0;
ActionFilter.defaultProps = {
onOk: () => {},
onChange: () => {},
onReset: () => {},
data: [],
width: 300
};
export default compose(withStyles(styles, {
name: 'RMActionFilter',
withTheme: true
}))(ActionFilter);