There are no notes for this item.
Prop | Required? | Type | Default | Description |
---|---|---|---|---|
className | No | string | ||
currentSort | Yes | { value: string, order: enum } |
||
fields | Yes | [{ label: string, value: string }] |
||
data | Yes | [{ id: union, values: [union], rowClass: string }] |
||
onSort | No | func |
<div id="reactMount" data-tpl="sortabletable">
<table class="va-sortable-table va-table">
<thead>
<tr>
<th><a role="button" tabindex="0">Label 1</a></th>
<th><a role="button" tabindex="0">Label 2</a></th>
<th><a role="button" tabindex="0">Label 3</a></th>
</tr>
</thead>
<tbody>
<tr class="class">
<td></td>
<td></td>
<td></td>
</tr>
<tr class="class">
<td></td>
<td></td>
<td></td>
</tr>
<tr class="class">
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<script>
window.currentProps = {
"package": {
"name": "department-of-veteran-affairs/jean-pants",
"version": "0.1.0"
},
"assetPath": "/design-system/",
"isProduction": true,
"componentSourcePath": "SortableTable.jsx",
"className": "va-table",
"currentSort": {
"value": "String",
"order": "ASC"
},
"fields": [{
"label": "Label 1",
"value": "1"
}, {
"label": "Label 2",
"value": "2"
}, {
"label": "Label 3",
"value": "3"
}],
"data": [{
"id": 1,
"values": [1, 2, 3],
"rowClass": "class"
}, {
"id": 2,
"values": [1, 2, 3],
"rowClass": "class"
}, {
"id": 3,
"values": [1, 2, 3],
"rowClass": "class"
}]
}
</script>
import React from 'react';
import SortableTable from './SortableTable';
export default function SortableTableExample(props) {
return (
<SortableTable
{...props}>
</SortableTable>
);
}
package:
name: department-of-veteran-affairs/jean-pants
version: 0.1.0
assetPath: /design-system/
isProduction: true
componentSourcePath: SortableTable.jsx
className: va-table
currentSort:
value: String
order: ASC
fields:
- label: Label 1
value: '1'
- label: Label 2
value: '2'
- label: Label 3
value: '3'
data:
- id: 1
values:
- 1
- 2
- 3
rowClass: class
- id: 2
values:
- 1
- 2
- 3
rowClass: class
- id: 3
values:
- 1
- 2
- 3
rowClass: class
import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
class SortableTable extends React.Component {
constructor(props) {
super(props);
this.makeHeader = this.makeHeader.bind(this);
this.makeRow = this.makeRow.bind(this);
}
handleSort(value, order) {
return () => this.props.onSort(value, order);
}
makeHeader(field) {
if (field.nonSortable) {
return (
<th key={field.value}>
{field.label}
</th>
);
}
// Determine what sort order the header will yield on the next click.
// By default, clicking this header will sort in ascending order.
// If it’s already ascending, next click will sort it in descending order.
let nextSortOrder = 'ASC';
let sortIcon;
if (this.props.currentSort.value === field.value) {
const iconClass = classNames({
fa: true,
'fa-caret-down': this.props.currentSort.order === 'DESC',
'fa-caret-up': this.props.currentSort.order === 'ASC'
});
sortIcon = <i className={iconClass}></i>;
if (this.props.currentSort.order === 'ASC') {
nextSortOrder = 'DESC';
}
}
return (
<th key={field.value}>
<a role="button" tabIndex="0" onClick={this.handleSort(field.value, nextSortOrder)}>
{field.label}
{sortIcon}
</a>
</th>
);
}
makeRow(item) {
const cells = this.props.fields.map(field => {
return <td key={`${item.id}-${field.value}`}>{item[field.value]}</td>;
});
return <tr key={item.id} className={item.rowClass}>{cells}</tr>;
}
render() {
const headers = this.props.fields.map(this.makeHeader);
const rows = this.props.data.map(this.makeRow);
const tableClass = classNames('va-sortable-table', this.props.className);
return (
<table className={tableClass}>
<thead>
<tr>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
);
}
}
SortableTable.propTypes = {
className: PropTypes.string,
// Field value to sort by in either ascending or descending order.
// The `value` must be one of the values in the `fields` prop.
currentSort: PropTypes.shape({
value: PropTypes.string.isRequired,
order: PropTypes.oneOf(['ASC', 'DESC'])
}).isRequired,
// Mappings of header labels to properties on the objects in `data`.
fields: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired
})).isRequired,
// Each object represents data for a row.
// An optional class may be provided to style specific rows.
data: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string
]).isRequired,
values: PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.number,
PropTypes.string])),
rowClass: PropTypes.string
})).isRequired,
onSort: PropTypes.func
};
export default SortableTable;
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import { axeCheck } from '../../../lib/testing/helpers';
import SortableTable from './SortableTable.jsx';
/* Roll your own! */
const fields = [{ label: 'Label 1', value: '1' }, { label: 'Label 2', value: '2' }, { label: 'Label 3', value: '3' }];
const data = [{ id: 1, rowClass: 'class' }, { id: 2, rowClass: 'class' }, { id: 3, rowClass: 'class' }];
const currentSort = { value: 'String', order: 'ASC' };
describe('<SortableTable>', () => {
it('should render', () => {
const tree = shallow(<SortableTable fields={fields} data={data} currentSort={currentSort}/>);
expect(tree.find('a').first().text()).to.contain('Label 1');
});
it('should pass aXe check', () => {
return axeCheck(<SortableTable fields={fields} data={data} currentSort={currentSort}/>);
});
});