Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 871 (setCellHeaderProps) and Feature/issue 714 (setTableProps) #889

Merged
merged 11 commits into from
Nov 21, 2019
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ The component accepts the following props:
|**`onColumnViewChange`**|function||Callback function that triggers when a column view has been changed. `function(changedColumn: string, action: string) => void`
|**`onTableChange`**|function||Callback function that triggers when table state has changed. `function(action: string, tableState: object) => void`
|**`onTableInit`**|function||Callback function that triggers when table state has been initialized. `function(action: string, tableState: object) => void`
|**`setRowProps`**|function||Is called for each row and allows to return custom props for this row based on its data. `function(row: array, dataIndex: number) => object`
|**`setRowProps`**|function||Is called for each row and allows you to return custom props for this row based on its data. `function(row: array, dataIndex: number) => object` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-styling/index.js)
|**`setTableProps`**|function||Is called for the table and allows you to return custom props for the table based on its data. `function() => object` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-styling/index.js)

## Customize Columns

Expand Down Expand Up @@ -231,7 +232,8 @@ const columns = [
|**`hint`**|string||Display hint icon with string as tooltip on hover.
|**`customHeadRender`**|function||Function that returns a string or React component. Used as display for column header. `function(columnMeta, handleToggleColumn) => string`|` React Component`
|**`customBodyRender`**|function||Function that returns a string or React component. Used as display data within all table cells of a given column. `function(value, tableMeta, updateValue) => string`|` React Component` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/component/index.js)
|**`setCellProps`**|function||Is called for each cell and allows to return custom props for this cell based on its data. `function(cellValue: string, rowIndex: number, columnIndex: number) => object`
|**`setCellProps`**|function||Is called for each cell and allows to you return custom props for this cell based on its data. `function(cellValue: string, rowIndex: number, columnIndex: number) => object` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-styling/index.js)
|**`setCellHeaderProps`**|function||Is called for each header cell and allows you to return custom props for the header cell based on its data. `function(columnMeta: object) => object` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/customize-styling/index.js)

`customHeadRender` is called with these arguments:

Expand Down
75 changes: 72 additions & 3 deletions examples/customize-styling/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import React from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "../../src/";
import {createMuiTheme, MuiThemeProvider, withStyles} from '@material-ui/core/styles';
import Switch from '@material-ui/core/Switch';
import FormGroup from '@material-ui/core/FormGroup';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import classnames from 'classnames';

const customStyles = {
BusinessAnalystRow: {
'& td': {backgroundColor: "#F00"}
'& td': {backgroundColor: "#FAA"}
},
NameCell: {
fontWeight: 900
Expand All @@ -15,11 +18,19 @@ const customStyles = {

class Example extends React.Component {

constructor(props) {
super(props);
this.state = {
denseTable: false,
stacked: true
};
}

getMuiTheme = () => createMuiTheme({
overrides: {
MUIDataTable: {
root: {
backgroundColor: "#FF000",
backgroundColor: "#AAF",
},
paper: {
boxShadow: "none",
Expand All @@ -33,6 +44,18 @@ class Example extends React.Component {
}
});

toggleDenseTable = (event) => {
this.setState({
denseTable: event.target.checked
});
}

toggleResponsive = (event) => {
this.setState({
stacked: event.target.checked ? true : false
});
}

render() {
const columns = [
{
Expand All @@ -46,13 +69,25 @@ class Example extends React.Component {
[this.props.classes.NameCell]: value === "Mel Brooks"
})
};
},
setCellHeaderProps: (value) => {
return {
className: classnames(
{
[this.props.classes.NameCell]: true
}),
style: {
textDecoration: 'underline'
}
};
}
}
},
{
name: "Title",
options: {
filter: true,
setCellHeaderProps: (value) => ({style:{textDecoration:'underline'}}),
}
},
{
Expand Down Expand Up @@ -112,7 +147,9 @@ class Example extends React.Component {
const options = {
filter: true,
filterType: 'dropdown',
responsive: 'stacked',
responsive: this.state.stacked ? 'stacked' : 'scrollMaxHeight',
fixedHeader: true,
rowHover: false,
setRowProps: (row) => {
return {
className: classnames(
Expand All @@ -121,12 +158,44 @@ class Example extends React.Component {
}),
style: {border: '3px solid blue',}
};
},
setTableProps: () => {
return {
padding: this.state.denseTable ? "none" : "default",

// material ui v4 only
size: this.state.denseTable ? "small" : "medium",
};
}

};

return (
<MuiThemeProvider theme={this.getMuiTheme()}>
<FormGroup row>
<FormControlLabel
control={
<Switch
checked={this.state.denseTable}
onChange={this.toggleDenseTable}
value="denseTable"
color="primary"
/>
}
label="Dense Table"
/>
<FormControlLabel
control={
<Switch
checked={this.state.stacked}
onChange={this.toggleResponsive}
value="stacked"
color="primary"
/>
}
label="Stacked Table"
/>
</FormGroup>
<MUIDataTable title={"ACME Employee list"} data={data} columns={columns} options={options}/>
</MuiThemeProvider>
);
Expand Down
15 changes: 14 additions & 1 deletion src/MUIDataTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class MUIDataTable extends React.Component {
customHeadRender: PropTypes.func,
customBodyRender: PropTypes.func,
customFilterListRender: PropTypes.func,
setCellProps: PropTypes.func,
setCellHeaderProps: PropTypes.func,
}),
}),
]),
Expand Down Expand Up @@ -179,6 +181,8 @@ class MUIDataTable extends React.Component {
}),
}),
onDownload: PropTypes.func,
setTableProps: PropTypes.func,
setRowProps: PropTypes.func,
}),
/** Pass and use className to style MUIDataTable as desired */
className: PropTypes.string,
Expand Down Expand Up @@ -1229,6 +1233,10 @@ class MUIDataTable extends React.Component {
break;
}

let tableProps = this.options.setTableProps ? this.options.setTableProps() : {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should be more defensive here. In case the function doesn't return an object, it will error out below. What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, that's not how the existing setCellProps and setRowProps functions work. Trying out other return values in the console, it doesn't look like anything breaks with the spread operator, they just wouldn't be setting any fields if they had the function return a non-object (with the exception of a "string" type, where they'd set numerical fields on the component).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The others don't work this way because they aren't checking an object for a specific property. The new functions you added are checking to see if classNames appears on the object, and this will error for non-objects, where the others won't, with the exception of strings.

let tableClassNames = classnames(classes.tableRoot, tableProps.className);
delete tableProps.className; // remove className from props to avoid the className being applied twice

return (
<Paper
elevation={this.options.elevation}
Expand Down Expand Up @@ -1279,7 +1287,12 @@ class MUIDataTable extends React.Component {
setResizeable={fn => (this.setHeadResizeable = fn)}
/>
)}
<MuiTable ref={el => (this.tableRef = el)} tabIndex={'0'} role={'grid'} className={classes.tableRoot}>
<MuiTable
ref={el => (this.tableRef = el)}
tabIndex={'0'}
role={'grid'}
className={tableClassNames}
{...tableProps}>
<caption className={classes.caption}>{title}</caption>
<TableHead
columns={columns}
Expand Down
16 changes: 12 additions & 4 deletions src/components/TableBodyCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@ const defaultBodyCellStyles = theme => ({
[theme.breakpoints.down('sm')]: {
display: 'inline-block',
fontSize: '16px',
height: '24px',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we hold off on the stylistic changes here or put in another PR? I believe there were some modifications here since you opened this that might have solved some of the style issues, but also, if we keep them separate, then we can discuss them separately and then they won't hold up the other work here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're tied to the functionality a setTableProps method would add (ie, "dense table"). Without these changes, applying a dense table breaks stacked mode. There's actually bugs in the existing code, if you view the Customize Styling example you'll see one of them:

https://codesandbox.io/s/github/gregnb/mui-datatables/

The CSS solution I wound up with is simple. Initially I tried to be fancy, but it wasn't needed and didn't cover certain edge cases (basically a height parameter is needed for causes when cell values are empty or just a space).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so the problem is just that the PR is a two-for-one deal. In the future, I'd prefer to have them kept separate as this makes reviewing easier, but it's also much easier to trace back any future issues or regressions to a specific commit (since we squash merges) and enables us to rollback specific sets of functionality without losing others that work well, if need be.

width: 'calc(50% - 80px)',
width: '50%',
whiteSpace: 'nowrap',
boxSizing: 'border-box',
height: '32px',
'&:nth-last-child(2)': {
borderBottom: 'none'
},
},
},
responsiveStacked: {
[theme.breakpoints.down('sm')]: {
display: 'inline-block',
fontSize: '16px',
width: 'calc(50% - 80px)',
width: '50%',
whiteSpace: 'nowrap',
height: '24px',
boxSizing: 'border-box',
height: '32px',
'&:last-child': {
borderBottom: 'none'
},
},
},
});
Expand Down
1 change: 1 addition & 0 deletions src/components/TableHead.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class TableHead extends React.Component {
column.customHeadRender({ index, ...column }, this.handleToggleColumn)
) : (
<TableHeadCell
cellHeaderProps={columns[index].setCellHeaderProps ? columns[index].setCellHeaderProps({ index, ...column }) : {}}
key={index}
index={index}
type={'cell'}
Expand Down
18 changes: 11 additions & 7 deletions src/components/TableHeadCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ class TableHeadCell extends React.Component {

render() {
const { isSortTooltipOpen, isHintTooltipOpen } = this.state;
const { children, classes, options, sortDirection, sort, hint, print } = this.props;
const { children, classes, options, sortDirection, sort, hint, print, cellHeaderProps } = this.props;
const { className, ...otherProps } = cellHeaderProps;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the other comment about checking for the className property, as the dev will get an unhelpful error if they return the wrong type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow. Check that it's set to a string?

const sortActive = sortDirection !== 'none' && sortDirection !== undefined ? true : false;
const ariaSortDirection = sortDirection === 'none' ? false : sortDirection;

Expand All @@ -100,14 +101,17 @@ class TableHeadCell extends React.Component {
...(ariaSortDirection ? { direction: sortDirection } : {}),
};

const cellClass = classNames({
[classes.root]: true,
[classes.fixedHeader]: options.fixedHeader,
'datatables-noprint': !print,
});
const cellClass = classNames(
{
[classes.root]: true,
[classes.fixedHeader]: options.fixedHeader,
'datatables-noprint': !print,
},
className,
);

return (
<TableCell className={cellClass} scope={'col'} sortDirection={ariaSortDirection}>
<TableCell className={cellClass} scope={'col'} sortDirection={ariaSortDirection} {...otherProps}>
{options.sort && sort ? (
<Tooltip
title={options.textLabels.body.toolTip}
Expand Down