Skip to content

Commit

Permalink
Merge branch 'release/1.17.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
shannonhochkins committed Jul 6, 2023
2 parents fcc1362 + 97d8370 commit bde3f79
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# GumDrops Changelog

# 1.16.1

- Introduce TableFooter component for tables
- Fixed bug with ImagePreview component

# 1.16.0

- Upgrade Storybook version to 7 - requires react and react-dom be added as dev dependencies
Expand Down
66 changes: 64 additions & 2 deletions _tests/molecules/Table.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import React from 'react';
import Table from '../../components/molecules/Table';
import TableBody from '../../components/molecules/TableBody';
import TableData from '../../components/molecules/TableData';
import TableFooter from '../../components/molecules/TableFooter';
import TableRow from '../../components/molecules/TableRow';

const defaultProps = {
data: [
Expand Down Expand Up @@ -193,11 +195,71 @@ test('Expect <Table> to expand the row when the chevron is clicked', () => {
}
]
};
const { queryByTestId, debug } = render(<Table {...props} />);
debug();
const { queryByTestId } = render(<Table {...props} />);
const expandableRow = queryByTestId('expandable-row-Foo');
expect(expandableRow.querySelector('.gds-table--collapsible').style.height).toEqual('0px');
fireEvent.click(queryByTestId('row-Foo-key-1'));
expect(queryByTestId('row-Foo-key-1')).toBeInTheDocument();
expect(expandableRow.querySelector('.gds-table--collapsible').style.height).toEqual('100px');
});


test('Expect <Table> to render the table footer component as an object', () => {
const props = {
...defaultProps,
customRowKey: 'foo',
columns: [
{
key: 'foo',
children: 'Foo',
headingProps: { style: { width: 100, onClick: jest.fn() } }
},
{
key: 'bar',
children: 'Bar',
renderExpandableColumn(cellData) {
return <div>Expandable - {cellData}</div>;
}
}
],
footer: {
foo: 'Bar Footer',
bar: 'Foo Footer'
}
};
const { queryByTestId, debug } = render(<Table {...props} />);
debug();
const footer = queryByTestId('table-footer');
expect(footer).toBeInTheDocument();
expect(footer).toMatchSnapshot();
});

test('Expect <Table> to render the table footer component as a JSX.Element', () => {
const props = {
...defaultProps,
customRowKey: 'foo',
columns: [
{
key: 'foo',
children: 'Foo',
headingProps: { style: { width: 100, onClick: jest.fn() } }
},
{
key: 'bar',
children: 'Bar',
renderExpandableColumn(cellData) {
return <div>Expandable - {cellData}</div>;
}
}
],
footer: <TableFooter data-testid="table-footer-manual">
<TableRow>
<TableData colspan={2}>Footer!</TableData>
</TableRow>
</TableFooter>
};
const { queryByTestId } = render(<Table {...props} />);
const footer = queryByTestId('table-footer-manual');
expect(footer).toBeInTheDocument();
expect(footer).toMatchSnapshot();
});
40 changes: 40 additions & 0 deletions _tests/molecules/__snapshots__/Table.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,46 @@ exports[`Expect <Table> to render properly 1`] = `
</table>
`;
exports[`Expect <Table> to render the table footer component as a JSX.Element 1`] = `
<tfoot
class=""
data-testid="table-footer-manual"
>
<tr
class="gds-table__row"
>
<td
class=""
colspan="2"
>
Footer!
</td>
</tr>
</tfoot>
`;
exports[`Expect <Table> to render the table footer component as an object 1`] = `
<tfoot
class=""
data-testid="table-footer"
>
<tr
class="gds-table__row"
>
<td
class=""
>
Bar Footer
</td>
<td
class=""
>
Foo Footer
</td>
</tr>
</tfoot>
`;
exports[`Expect <Table> to render using advanced configs 1`] = `
<table
className="gds-table custom-class gds-table--lg"
Expand Down
6 changes: 2 additions & 4 deletions components/atoms/ImagePreview.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,8 @@ function ImagePreview({
break;
}
if (
typeof tooltipX === 'number' &&
typeof tooltipY === 'number' &&
!isNaN(tooltipY) &&
!isNaN(tooltipX)
isFinite(tooltipY) &&
isFinite(tooltipX)
) {
return {
left: tooltipX,
Expand Down
30 changes: 30 additions & 0 deletions components/molecules/Table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Heading from './TableHeading';
import Body from './TableBody';
import Row from './TableRow';
import Data from './TableData';
import Footer from './TableFooter';
import Icon from '../atoms/Icon';
import { deprecateLog } from '../utils/deprecate';

Expand Down Expand Up @@ -153,6 +154,7 @@ class Table extends Component {
hasHeader,
onRowClick,
isSecondary,
footer,
}) {
const { sortBy, data } = this.state;
return (
Expand Down Expand Up @@ -297,6 +299,17 @@ class Table extends Component {
);
})}
</Body>
{typeof footer === 'undefined' ? null : typeof footer === 'object' && !React.isValidElement(footer) ? <Footer data-testid="table-footer">
<Row>
{columns.map((column, k) => {
const rowKey = this._getRowKey(footer, k);
// generate a column key based on the row key
const columnKey = this._getColumnKey(rowKey, k);
const [columnData] = this._getColumnData(column, footer, columnKey);
return <Data key={`${columnKey}--footer`}>{columnData}</Data>
})}
</Row>
</Footer> : React.isValidElement(footer) ? footer : null}
</Fragment>
);
}
Expand Down Expand Up @@ -328,6 +341,23 @@ class Table extends Component {
}

Table.propTypes = {
/** An `Object` matching the column keys or JSX element */
footer: function(props, propName, componentName) {
const propValue = props[propName];
// not a required value so if undefined, don't throw an error
// If undefined, don't throw an error
if (typeof propValue === 'undefined') {
return;
}
const isObject = typeof propValue === 'object';
// Validate the prop value
if (!React.isValidElement(propValue) || !isObject) {
return new Error(
`Invalid prop ${propName} supplied to ${componentName}.
Expected undefined, a JSX element, or an object matching keys of columns.`
);
}
},
// necessary for controlled tables
/** An `Array` of `Objects` with simple key/value pairs. */
data: function(props, propName, componentName) {
Expand Down
12 changes: 12 additions & 0 deletions components/molecules/TableFooter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

const TableFooter = ({ className, children, ...rest }) => <tfoot className={cx(className)} {...rest}>{children}</tfoot>;

TableFooter.propTypes = {
className: PropTypes.string,
children: PropTypes.node
};

export default TableFooter;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gumdrops",
"version": "1.17.2",
"version": "1.17.3",
"description": "GumGum's React Components Library",
"license": "MIT",
"files": [
Expand Down
64 changes: 64 additions & 0 deletions stories/molecules/Table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,62 @@ const columns = [{
const People = () => <Table columns={columns} data={data} customRowKey="id" />;
```
### Table Footer
The table footer can be used to display totals or other summary information. The footer is rendered as a `<tfoot>` element.
The footer will allow you to have a "static" row at the bottom of the table that will not be affected by sorting.
The footer prop can accept JSX or an object containing a key/value pair object where the "keys" are the column keys.
The following example will create a table with a footer that will display the total age of all the people in the table.
```jsx
const columns = [
{ key: 'name', children: 'First Name' },
{ key: 'age', children: 'Age (years)' },
];
const data = [
{ name: 'Alice', age: 20, id: 'x123' },
{ name: 'Bob', age: 24, id: 'y456' }
];
const footer = {
name: 'Total Age',
age: data.reduce((acc, row) => acc + row.age, 0) // -> 44
}
const People = () => <Table columns={columns} data={data} footer={footer} customRowKey="id" />;
```
### Custom Table Footer
We can also include JSX to render a custom table footer by importing the components manually.
```jsx
import TableFooter from 'gumdrops/TableFooter';
import TableRow from 'gumdrops/TableRow';
import TableData from 'gumdrops/TableData';
const columns = [
{ key: 'name', children: 'First Name' },
{ key: 'age', children: 'Age (years)' },
];
const data = [
{ name: 'Alice', age: 20, id: 'x123' },
{ name: 'Bob', age: 24, id: 'y456' }
];
function CustomFooter() {
return <TableFooter>
<TableRow>
<TableData colspan={2}>
The average age is {data.reduce((acc, row) => acc + row.age, 0) / data.length}
</TableData>
</TableRow>
</TableFooter>
}
const People = () => <Table columns={columns} data={data} footer={CustomFooter} customRowKey="id" />;
```
## Component Example Simple
Expand Down Expand Up @@ -225,6 +281,14 @@ const People = () => <Table columns={columns} data={data} customRowKey="id" />;
<Source of={TableStories.Expandable} />
## Component Example Footer
<Canvas of={TableStories.Footer} />
## Component Example Source Footer
<Source of={TableStories.Footer} />
## Table Props
<ArgsTable of={Table} />
Expand Down
18 changes: 17 additions & 1 deletion stories/molecules/Table.stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Table from '../../components/molecules/Table';
import TableData from '../../components/molecules/TableData';
import TableFooter from '../../components/molecules/TableFooter';
import ToolTip from '../../components/atoms/Tooltip';

const columnsSimple = ['id', 'name', 'title', 'age', 'height'];
Expand Down Expand Up @@ -179,6 +180,7 @@ const Template = args => {
);
};


export const Simple = Template.bind({});
Simple.args = {
columns: columnsSimple,
Expand All @@ -196,7 +198,7 @@ Custom.parameters = { controls: { exclude: ['children', 'data'] } };
export const Advanced = Template.bind({});
Advanced.args = {
columns: columnsAdvanced,
numOfRows: 10
numOfRows: 10,
};
Advanced.parameters = { controls: { exclude: ['children', 'data'] } };

Expand All @@ -207,3 +209,17 @@ Expandable.args = {
customRowKey: 'id'
};
Expandable.parameters = { controls: { exclude: ['children', 'data'] } };

export const Footer = Template.bind({});

Footer.args = {
columns: columnsAdvanced,
numOfRows: 5,
footer: {
id: '123',
name: '',
title: '',
age: 'Average Age: 30',
height: 'Average Height: 5\'8"',
}
}

0 comments on commit bde3f79

Please sign in to comment.