react-mdl
Version:
React Components for Material Design Lite
165 lines (146 loc) • 6.18 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import isEqual from 'lodash.isequal';
import TableHeader from './TableHeader';
import Checkbox from '../Checkbox';
const propTypes = {
columns: (props, propName, componentName) => (
props[propName] && new Error(`${componentName}: \`${propName}\` is deprecated, please use the component \`TableHeader\` instead.`)
),
data: (props, propName, componentName) => (
props[propName] && new Error(`${componentName}: \`${propName}\` is deprecated, please use \`rows\` instead. \`${propName}\` will be removed in the next major release.`)
),
onSelectionChanged: PropTypes.func,
rowKeyColumn: PropTypes.string,
rows: PropTypes.arrayOf(
PropTypes.object
).isRequired,
selectable: PropTypes.bool,
selectedRows: PropTypes.array
};
const defaultProps = {
onSelectionChanged: () => {
// do nothing
}
};
export default Component => {
class Selectable extends React.Component {
// eslint-disable-next-line react/sort-comp
constructor(props) {
super(props);
this.handleChangeHeaderCheckbox = this.handleChangeHeaderCheckbox.bind(this);
this.handleChangeRowCheckbox = this.handleChangeRowCheckbox.bind(this);
this.builRowCheckbox = this.builRowCheckbox.bind(this);
this.state = {
headerSelected: false,
selectedRows: props.selectedRows || []
};
}
static getDerivedStateFromProps(nextProps, state) {
const { rows, data, rowKeyColumn } = nextProps;
const rrows = rows || data;
if (nextProps.selectable) {
const selectedRows = (nextProps.selectedRows || state.selectedRows)
.filter(k => rrows
.map((row, i) => row[rowKeyColumn] || row.key || i)
.indexOf(k) > -1
);
const headerSelected = selectedRows.length === rrows.length;
const update = { };
if (headerSelected !== state.headerSelected) {
update.headerSelected = headerSelected;
}
if (!nextProps.selectedRows) {
if (!isEqual(state.selectedRows, selectedRows)) {
update.selectedRows = selectedRows;
nextProps.onSelectionChanged(selectedRows);
}
}
if (Object.keys(update).length) {
return update;
}
}
return null;
}
handleChangeHeaderCheckbox(e) {
const { rowKeyColumn, rows, data } = this.props;
const selected = e.target.checked;
const selectedRows = selected
? (rows || data).map((row, idx) => row[rowKeyColumn] || row.key || idx)
: [];
this.setState({
headerSelected: selected,
selectedRows
});
this.props.onSelectionChanged(selectedRows);
}
handleChangeRowCheckbox(e) {
const { rows, data } = this.props;
const rowId = JSON.parse(e.target.dataset
? e.target.dataset.reactmdl
: e.target.getAttribute('data-reactmdl')
).id;
const rowChecked = e.target.checked;
const selectedRows = this.props.selectedRows || this.state.selectedRows;
if (rowChecked) {
selectedRows.push(rowId);
} else {
const idx = selectedRows.indexOf(rowId);
selectedRows.splice(idx, 1);
}
this.setState({
headerSelected: (rows || data).length === selectedRows.length,
selectedRows
});
this.props.onSelectionChanged(selectedRows);
}
builRowCheckbox(content, row, idx) {
const rowKey = row[this.props.rowKeyColumn] || row.key || idx;
const isSelected = (this.props.selectedRows || this.state.selectedRows).indexOf(rowKey) > -1;
return (
<Checkbox
className="mdl-data-table__select"
data-reactmdl={JSON.stringify({ id: rowKey })}
checked={isSelected}
onChange={this.handleChangeRowCheckbox}
/>
);
}
render() {
const { rows, data, selectable, children, rowKeyColumn, ...otherProps } = this.props;
// remove unwatned props
// see https://github.com/Hacker0x01/react-datepicker/issues/517#issuecomment-230171426
delete otherProps.onSelectionChanged;
delete otherProps.selectedRows;
const realRows = selectable
? (rows || data).map((row, idx) => {
const rowKey = row[rowKeyColumn] || row.key || idx;
return {
...row,
className: classNames({
'is-selected': (this.props.selectedRows || this.state.selectedRows).indexOf(rowKey) > -1
}, row.className)
};
})
: (rows || data);
return (
<Component rows={realRows} {...otherProps}>
{selectable && (
<TableHeader name="mdl-header-select" cellFormatter={this.builRowCheckbox}>
<Checkbox
className="mdl-data-table__select"
checked={this.state.headerSelected}
onChange={this.handleChangeHeaderCheckbox}
/>
</TableHeader>
)}
{children}
</Component>
);
}
}
Selectable.propTypes = propTypes;
Selectable.defaultProps = defaultProps;
return Selectable;
};