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

gt - WIP UncontrolledTable #440

Merged
merged 11 commits into from
Aug 31, 2018
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@
"enzyme-adapter-react-16": "^1.1.1",
"fecha": "^2.3.0",
"lodash.flow": "^3.5.0",
"lodash.includes": "^4.3.0",
"lodash.noop": "^3.0.1",
"lodash.range": "^3.2.0",
"lodash.orderby": "^4.6.0",
"lodash.without": "^4.4.0",
"prop-types": "^15.5.10",
"react-fontawesome": "^1.4.0",
"react-onclickoutside": "^6.7.1",
Expand Down
201 changes: 201 additions & 0 deletions src/components/UncontrolledTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import includes from 'lodash.includes';
import orderBy from 'lodash.orderby';
import without from 'lodash.without';
import Button from './Button';
import Icon from './Icon';
import Paginator from './Paginator';
import SortableTable from './SortableTable';

export default class UncontrolledTable extends React.Component {
static propTypes = {
...SortableTable.propTypes,
pageSize: PropTypes.number,
sort: PropTypes.shape({
column: PropTypes.string,
ascending: PropTypes.bool
})
}

static defaultProps = {
...SortableTable.defaultProps,
pageSize: 10,
sort: {
ascending: true
}
}

state = {
sort: this.props.sort,
expanded: [],
selected: [],
page: 0
}

sortedData = (rows, column, ascending) => orderBy(
rows,
[column],
[ascending ? 'asc' : 'desc']
);

sortBy = (column, ascending) => {
if (this.state.sort.column === column) {
this.setState({
sort: {
column,
ascending
}
});
} else {
this.setState({
sort: {
column,
ascending: true
}
});
}
};

get someSelected() {
return this.state.selected.length > 0;
}

get allSelected() {
return this.props.rows.length && (this.state.selected.length === this.props.rows.length);
}

selected(value) {
return includes(this.state.selected, value);
}

toggleSelection = (value) => {
const selected = this.state.selected;
const newSelection = includes(selected, value) ?
without(selected, value) :
[...selected, value];

this.setState({ selected: newSelection },
this.props.onSelect(newSelection)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a callback?

);
};

toggleAll = () => {
const newSelection = this.allSelected ? [] : this.props.rows;

this.setState({ selected: newSelection },
this.props.onSelect(newSelection)
);
};

expanded(value) {
return includes(this.state.expanded, value);
}

toggleExpanded = (value) => {
const expanded = this.state.expanded;
const newExpanded = includes(expanded, value) ?
without(expanded, value) :
[...expanded, value];

this.setState({ expanded: newExpanded });
};

setPage = (page) => {
this.setState({ page });
}

componentWillReceiveProps(nextProps) {
// Clear selection if rows or selectable change
if (nextProps.rows !== this.props.rows ||
nextProps.selectable !== this.props.selectable) {
this.setState({ selected: [] });
}
if (nextProps.rows !== this.props.rows ||
nextProps.expandable !== this.props.expandable) {
this.setState({ expanded: [] });
}
}

render() {
const { page, sort } = this.state;
const { ascending, column } = sort;
const { columns, expandable, pageSize, paginated, rowClassName, rowExpanded, rows, selectable, onSelect, ...props } = this.props;
const cols = columns.map(col => (col.sortable !== false) ?
Copy link
Contributor

Choose a reason for hiding this comment

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

can you just do col.sortable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks odd, but am supporting a "default" of sortable == true, without it actually being set to true. This explicitly checks for false.

{
active: column === col.key,
ascending,
onSort: asc => this.sortBy(col.key, asc),
...col
} : col
);

if (selectable) {
cols.unshift({
align: 'center',
key: 'select',
header: (
<input
type="checkbox"
className="mx-1"
checked={this.allSelected}
onChange={() => this.toggleAll()}
Copy link
Contributor

Choose a reason for hiding this comment

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

this can just be this.toggleAll

/>
),
cell: row => (
<input
type="checkbox"
className="mx-1"
checked={this.selected(row)}
onChange={() => this.toggleSelection(row)}
/>
),
width: '1%'
});
}

if (expandable) {
cols.push({
align: 'center',
key: 'expand',
cell: row => (
<Button
className="px-2 py-0"
color="link"
onClick={() => this.toggleExpanded(row)}
>
<Icon name="ellipsis-v" size="lg" />
</Button>
),
width: '1%'
});
}

const start = page * pageSize;
const end = start + pageSize;
const sortedRows = this.sortedData(rows, column, ascending);
const visibleRows = paginated ? sortedRows.slice(start, end) : sortedRows;

return (
<div>
<SortableTable
{...props}
columns={cols}
rows={visibleRows}
rowClassName={row => classnames({ 'table-info': this.selected(row) }, rowClassName(row))}
rowExpanded={row => expandable && this.expanded(row) && rowExpanded(row)}
/>
{paginated && [
<hr />,
<Paginator
currentPage={page + 1}
onClick={pg => this.setPage(pg - 1)}
perPage={pageSize}
totalItems={rows.length}
/>
]}
</div>
);
}
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import SummaryBoxItem from './components/SummaryBoxItem.js';
import Table from './components/Table.js';
import TimeInput from './components/TimeInput.js';
import Tooltip from './components/Tooltip.js';
import UncontrolledTable from './components/UncontrolledTable.js';
import ValidatedFormGroup from './components/ValidatedFormGroup.js';
import Waiting from './components/Waiting.js';

Expand Down Expand Up @@ -261,6 +262,7 @@ export {
SummaryBoxItem,
TimeInput,
Tooltip,
UncontrolledTable,
ValidatedFormGroup,
Waiting,
};
Loading