Skip to content

Commit

Permalink
Add emptyItemsMessage prop to Table
Browse files Browse the repository at this point in the history
Allow the ability to render a message if `items` is empty (and the
`Table` is not in a loading state). This obviates the need for parent
components to wrangle the message quite as much and simplifies and
standardizes styling/position of the message.

Fixes #191
  • Loading branch information
lyzadanger committed Sep 14, 2021
1 parent bba12b3 commit 9bb75f7
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/components/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { Scrollbox } from './containers';
* @prop {string} [classes] - Extra CSS classes to apply to the <table>
* @prop {string} [containerClasses] - Extra CSS classes to apply to the outermost
* element, which is a <Scrollbox> div
* @prop {string|Object} [emptyItemsMessage] - Optional message to display if
* there are no `items`. Will only display when the Table is not loading.
* @prop {TableHeader[]} tableHeaders - The columns to display in this table
* @prop {boolean} [isLoading] - Show an indicator that data for the table is
* currently being fetched
Expand Down Expand Up @@ -73,6 +75,7 @@ export function Table({
accessibleLabel,
classes,
containerClasses,
emptyItemsMessage,
isLoading = false,
items,
onSelectItem,
Expand Down Expand Up @@ -209,6 +212,14 @@ export function Table({
<Spinner size="large" />
</div>
)}
{!isLoading && items.length === 0 && emptyItemsMessage && (
<div
className="Hyp-Table-Scrollbox__message"
data-testid="empty-items-message"
>
{emptyItemsMessage}
</div>
)}
</Scrollbox>
);
}
22 changes: 22 additions & 0 deletions src/components/test/Table-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ describe('Table', () => {
const columns = wrapper.find('thead th').map(col => col.text());
assert.deepEqual(columns, ['Name', 'Size']);
});

it('does not show an empty items message', () => {
const wrapper = createComponent({
isLoading: true,
tableHeaders: [{ label: 'Name' }, { label: 'Size' }],
items: [],
emptyItemsMessage: 'There is nothing here',
});

assert.isFalse(
wrapper.find('[data-testid="empty-items-message"]').exists()
);
});
});

it('renders column headings', () => {
Expand All @@ -91,6 +104,15 @@ describe('Table', () => {
assert.isTrue(wrapper.contains(<td>Three</td>));
});

it('shows provided empty message if there are no items', () => {
const wrapper = createComponent({
items: [],
emptyItemsMessage: 'There is nothing here',
});

assert.isTrue(wrapper.find('[data-testid="empty-items-message"]').exists());
});

['click', 'mousedown'].forEach(event => {
it(`selects item on ${event}`, () => {
const onSelectItem = sinon.stub();
Expand Down
44 changes: 44 additions & 0 deletions src/pattern-library/components/patterns/TableComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,56 @@ function ScrollboxTableExample() {
);
}

function EmptyTableExample() {
const [isLoading, setIsLoading] = useState(false);
const items = [];
const [selectedFile, setSelectedFile] = useState(
/** @type {null|object} */ (items[items.length - 1])
);

const emptyItemsMessage = (
<p>
There are no files available to show.{' '}
<a href="https://www.example.com">Learn more.</a>
</p>
);

return (
<Library.Example title="Constrained Table" variant="wide">
<p>
This Table has no items (it is empty). When not in loading state, the
provided <code>emptyItemsMessage</code> will render centered in the
table.
</p>
<Library.Demo withSource>
<div className="hyp-u-padding--5">
<LabeledButton onClick={() => setIsLoading(!isLoading)}>
Toggle Loading
</LabeledButton>
</div>

<Table
accessibleLabel="File list"
emptyItemsMessage={emptyItemsMessage}
isLoading={isLoading}
items={items}
selectedItem={selectedFile}
onSelectItem={file => setSelectedFile(file)}
onUseItem={file => alert(`Selected ${file.displayName}`)}
renderItem={file => renderCallback(file)}
tableHeaders={tableHeaders}
/>
</Library.Demo>
</Library.Example>
);
}
export default function TableComponents() {
return (
<Library.Page title="Table">
<Library.Pattern title="Table">
<TableExample />
<ScrollboxTableExample />
<EmptyTableExample />
</Library.Pattern>
</Library.Page>
);
Expand Down
5 changes: 5 additions & 0 deletions styles/components/Table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ $-row-height: var.$touch-target-size;
// Adjust vertical position to account for header, which takes up one "row"
margin-top: math.div($-row-height, 2);
}

&__message {
@include layout.absolute-centered;
top: $-row-height * 2;
}
}

.Hyp-Table {
Expand Down

0 comments on commit 9bb75f7

Please sign in to comment.