Skip to content

Commit

Permalink
feat(component): allow state override of table select all checkbox
Browse files Browse the repository at this point in the history
  • Loading branch information
deini committed Oct 24, 2019
1 parent 9237d31 commit 5ed1dba
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 44 deletions.
60 changes: 51 additions & 9 deletions packages/big-design/src/components/Table/Actions/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import { TableItem, TablePagination, TableSelectable } from '../types';
import { StyledActions } from './styled';

export interface ActionsProps<T> {
itemName?: string;
items: T[];
pagination?: TablePagination;
selectable?: TableSelectable<T>;
tableId: string;
}

export const Actions = memo(
<T extends TableItem>({ selectable, pagination, tableId, items = [], ...props }: ActionsProps<T>) => {
<T extends TableItem>({ selectable, pagination, tableId, itemName, items = [], ...props }: ActionsProps<T>) => {
const totalItems = pagination ? pagination.totalItems : items.length;

const handleSelectAll = () => {
if (!selectable) {
return;
Expand All @@ -31,20 +34,48 @@ export const Actions = memo(
}
};

const renderSelectAllAction = ({ itemType, selectedItems }: TableSelectable<T>) => {
const getSelectAllChecked = () => {
if (!selectable) {
return false;
}

const { selectAllState, selectedItems } = selectable;

switch (selectAllState) {
case 'ALL':
return true;

case 'PARTIAL':
case 'NONE':
return false;

default:
const totalSelectedItems = selectedItems.length;
const totalItemsInPage = items.length;

return totalSelectedItems === totalItemsInPage && totalItemsInPage > 0;
}
};

const renderSelectAllAction = () => {
if (!selectable) {
return null;
}

const { selectAllState, selectedItems } = selectable;
const totalSelectedItems = selectedItems.length;
const totalItemsInPage = items.length;
const isChecked = totalSelectedItems === totalItemsInPage && totalItemsInPage > 0;
const isIndeterminate = totalSelectedItems > 0 && totalSelectedItems !== totalItemsInPage;

const isChecked = getSelectAllChecked();
const isIndeterminate =
selectAllState === 'PARTIAL' || (totalSelectedItems > 0 && totalSelectedItems !== totalItemsInPage);

return (
<Flex.Item flexGrow={2}>
<Flex.Item marginRight="xxSmall">
<Flex flexDirection="row">
<Checkbox isIndeterminate={isIndeterminate} checked={isChecked} onChange={handleSelectAll} />
<Text marginLeft="small">
{totalSelectedItems === 0
? `${totalItemsInPage} ${itemType}`
: `${totalSelectedItems}/${totalItemsInPage} ${itemType}`}
{totalSelectedItems === 0 ? `${totalItems}` : `${totalSelectedItems}/${totalItems}`}
</Text>
</Flex>
</Flex.Item>
Expand All @@ -61,6 +92,16 @@ export const Actions = memo(
[pagination],
);

const renderItemName = () => {
if (typeof itemName !== 'string') {
return null;
}

const text = Boolean(selectable) ? itemName : `${totalItems} ${itemName}`;

return <Text margin="none">{text}</Text>;
};

return (
<StyledActions
alignItems="center"
Expand All @@ -70,7 +111,8 @@ export const Actions = memo(
padding="small"
{...props}
>
{selectable && renderSelectAllAction(selectable)}
{renderSelectAllAction()}
{renderItemName()}
{renderPagination}
</StyledActions>
);
Expand Down
11 changes: 9 additions & 2 deletions packages/big-design/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const InternalTable = <T extends TableItem>(props: TableProps<T>): React.ReactEl
className,
columns,
id,
itemName,
items,
keyField = 'id',
pagination,
Expand Down Expand Up @@ -62,7 +63,7 @@ const InternalTable = <T extends TableItem>(props: TableProps<T>): React.ReactEl
};

const shouldRenderActions = () => {
return Boolean(pagination) || Boolean(selectable);
return Boolean(pagination) || Boolean(selectable) || Boolean(itemName);
};

const getItemKey = (item: T, index: number): string | number => {
Expand Down Expand Up @@ -129,7 +130,13 @@ const InternalTable = <T extends TableItem>(props: TableProps<T>): React.ReactEl
return (
<>
{shouldRenderActions() && (
<Actions pagination={pagination} selectable={selectable} items={items} tableId={tableIdRef.current} />
<Actions
pagination={pagination}
selectable={selectable}
items={items}
itemName={itemName}
tableId={tableIdRef.current}
/>
)}
<StyledTable {...rest} id={tableIdRef.current}>
{renderHeaders()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -751,13 +751,26 @@ exports[`renders a simple table 1`] = `
`;

exports[`selectable renders selectable actions and checkboxes 1`] = `
.c9 {
.c10 {
vertical-align: middle;
height: 1.5rem;
width: 1.5rem;
}
.c10 {
.c12 {
color: #313440;
margin: 0 0 1rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5rem;
margin: 0;
}
.c12:last-child {
margin-bottom: 0;
}
.c11 {
color: #313440;
margin: 0 0 1rem;
font-size: 1rem;
Expand All @@ -766,11 +779,11 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
margin-left: 0.75rem;
}
.c10:last-child {
.c11:last-child {
margin-bottom: 0;
}
.c5 {
.c6 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
Expand All @@ -781,7 +794,7 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
display: flex;
}
.c7 {
.c8 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
Expand All @@ -796,7 +809,7 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
width: 1px;
}
.c8 {
.c9 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
Expand Down Expand Up @@ -824,15 +837,15 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
width: 1.25rem;
}
.c6:focus + .c8 {
.c7:focus + .c9 {
box-shadow: 0 0 0 0.25rem #DBE3FE;
}
.c8 svg {
.c9 svg {
visibility: hidden;
}
.c3 {
.c5 {
box-sizing: border-box;
}
Expand All @@ -841,6 +854,11 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
box-sizing: border-box;
}
.c3 {
margin-right: 0.25rem;
box-sizing: border-box;
}
.c0 {
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
Expand Down Expand Up @@ -896,10 +914,6 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
-webkit-flex-basis: auto;
-ms-flex-preferred-size: auto;
flex-basis: auto;
-webkit-box-flex: 2;
-webkit-flex-grow: 2;
-ms-flex-positive: 2;
flex-grow: 2;
-webkit-flex-shrink: 1;
-ms-flex-negative: 1;
flex-shrink: 1;
Expand All @@ -913,24 +927,24 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
class="c2 c3"
>
<div
class="c4 c3"
class="c4 c5"
>
<div
class="c5"
class="c6"
>
<input
aria-labelledby="checkBox_label_2"
class="c6 c7"
class="c7 c8"
id="checkBox_1"
type="checkbox"
/>
<label
aria-hidden="true"
class="c8"
class="c9"
for="checkBox_1"
>
<svg
class="c9"
class="c10"
fill="currentColor"
height="24"
stroke="currentColor"
Expand All @@ -950,11 +964,16 @@ exports[`selectable renders selectable actions and checkboxes 1`] = `
</label>
</div>
<p
class="c10"
class="c11"
>
5 Product
5
</p>
</div>
</div>
<p
class="c12"
>
Product
</p>
</div>
`;
45 changes: 37 additions & 8 deletions packages/big-design/src/components/Table/spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import { Table } from './Table';

interface SimpleTableOptions {
className?: string;
columns?: any[];
dataTestId?: string;
id?: string;
itemName?: string;
style?: CSSProperties;
columns?: any[];
}

const getSimpleTable = ({ className, columns, dataTestId, id, style }: SimpleTableOptions = {}) => (
const getSimpleTable = ({ className, columns, dataTestId, id, itemName, style }: SimpleTableOptions = {}) => (
<Table
id={id}
data-testid={dataTestId}
className={className}
data-testid={dataTestId}
id={id}
itemName={itemName}
style={style}
columns={
columns || [
Expand Down Expand Up @@ -126,6 +128,14 @@ test('tweaks column styles with props', () => {
`);
});

test('renders the total number of items + item name', () => {
const { getByText } = render(getSimpleTable({ itemName: 'Test Items' }));

const itemNameNode = getByText(`5 Test Items`);

expect(itemNameNode).toBeInTheDocument();
});

test('renders a pagination component', () => {
const onItemsPerPageChange = jest.fn();
const onPageChange = jest.fn();
Expand Down Expand Up @@ -165,7 +175,7 @@ describe('selectable', () => {
let columns: any;
let items: any;
let onSelectionChange: jest.Mock;
const itemType = 'Product';
const itemName = 'Product';

beforeEach(() => {
onSelectionChange = jest.fn();
Expand All @@ -187,9 +197,9 @@ describe('selectable', () => {
const { container, getAllByRole } = render(
<Table
columns={columns}
itemName={itemName}
items={items}
selectable={{
itemType,
onSelectionChange,
selectedItems: [],
}}
Expand All @@ -205,9 +215,9 @@ describe('selectable', () => {
const { getAllByRole } = render(
<Table
columns={columns}
itemName={itemName}
items={items}
selectable={{
itemType,
onSelectionChange,
selectedItems: [],
}}
Expand All @@ -226,9 +236,9 @@ describe('selectable', () => {
const { getAllByRole } = render(
<Table
columns={columns}
itemName={itemName}
items={items}
selectable={{
itemType,
onSelectionChange,
selectedItems: items,
}}
Expand All @@ -242,6 +252,25 @@ describe('selectable', () => {
fireEvent.click(selectAllCheckbox);
expect(onSelectionChange).toHaveBeenCalledWith([]);
});

test('passing a selectAllState overrides the checkbox state', () => {
const { getAllByRole } = render(
<Table
columns={columns}
itemName={itemName}
items={items}
selectable={{
selectAllState: 'ALL',
onSelectionChange,
selectedItems: [],
}}
/>,
);

const [selectAllCheckbox] = getAllByRole('checkbox') as HTMLInputElement[];

expect(selectAllCheckbox.checked).toBe(true);
});
});

describe('sortable', () => {
Expand Down
Loading

0 comments on commit 5ed1dba

Please sign in to comment.