Skip to content

Commit

Permalink
feat(component): add sort functionality to Table component
Browse files Browse the repository at this point in the history
  • Loading branch information
deini committed Oct 22, 2019
1 parent c34203f commit 2d30461
Show file tree
Hide file tree
Showing 20 changed files with 560 additions and 257 deletions.
8 changes: 1 addition & 7 deletions packages/big-design/src/components/Table/Body/Body.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React, { memo } from 'react';

import { TableSectionContext } from '../context';

import { StyledTableBody } from './styled';

export interface BodyProps extends React.TableHTMLAttributes<HTMLTableSectionElement> {}

export const Body: React.FC<BodyProps> = memo(({ className, style, ...props }) => (
<TableSectionContext.Provider value="tbody">
<StyledTableBody {...props} />
</TableSectionContext.Provider>
));
export const Body: React.FC<BodyProps> = memo(({ className, style, ...props }) => <StyledTableBody {...props} />);
46 changes: 0 additions & 46 deletions packages/big-design/src/components/Table/Cell/Cell.tsx

This file was deleted.

1 change: 0 additions & 1 deletion packages/big-design/src/components/Table/Cell/index.ts

This file was deleted.

25 changes: 25 additions & 0 deletions packages/big-design/src/components/Table/DataCell/DataCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { memo } from 'react';

import { StyledTableDataCell, StyledTableDataCheckbox } from './styled';

export interface DataCellProps extends React.TableHTMLAttributes<HTMLTableCellElement> {
align?: 'left' | 'center' | 'right';
isCheckbox?: boolean;
verticalAlign?: 'top' | 'center';
width?: number | string;
withPadding?: boolean;
}

export const DataCell: React.FC<DataCellProps> = memo(
({ align, children, isCheckbox, verticalAlign, width, withPadding = true }: DataCellProps) => {
return isCheckbox ? (
<StyledTableDataCheckbox align={align} width={width}>
{children}
</StyledTableDataCheckbox>
) : (
<StyledTableDataCell align={align} verticalAlign={verticalAlign} width={width} withPadding={withPadding}>
{children}
</StyledTableDataCell>
);
},
);
1 change: 1 addition & 0 deletions packages/big-design/src/components/Table/DataCell/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DataCell, DataCellProps } from './DataCell';
43 changes: 43 additions & 0 deletions packages/big-design/src/components/Table/DataCell/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { theme as defaultTheme } from '@bigcommerce/big-design-theme';
import styled, { css } from 'styled-components';

import { DataCellProps } from './DataCell';

export const StyledTableDataCell = styled.td<DataCellProps>`
box-sizing: border-box;
color: ${({ theme }) => theme.colors.secondary70};
font-size: ${({ theme }) => theme.typography.fontSize.medium};
padding: ${({ theme, withPadding }) => (withPadding ? theme.spacing.small : 0)};
${({ align }) =>
align &&
css`
text-align: ${align};
`};
${({ verticalAlign }) =>
verticalAlign &&
css`
vertical-align: ${verticalAlign};
`};
${({ width }) =>
width !== undefined &&
css`
width: ${typeof width === 'string' ? width : width + 'px'};
`};
`;

export const StyledTableDataCheckbox = styled(StyledTableDataCell)`
padding: ${({ theme }) => `0 ${theme.spacing.small}`};
${props =>
props.isCheckbox &&
css`
width: ${({ theme }) => theme.helpers.addValues(theme.spacing.xLarge, theme.spacing.small)};
white-space: nowrap;
`};
`;

StyledTableDataCell.defaultProps = { theme: defaultTheme };
StyledTableDataCheckbox.defaultProps = { theme: defaultTheme };
8 changes: 1 addition & 7 deletions packages/big-design/src/components/Table/Head/Head.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React, { memo } from 'react';

import { TableSectionContext } from '../context';

import { StyledTableHead } from './styled';

export type HeadProps = React.TableHTMLAttributes<HTMLTableSectionElement>;

export const Head: React.FC<HeadProps> = memo(({ className, style, ...props }) => (
<TableSectionContext.Provider value="thead">
<StyledTableHead {...props} />
</TableSectionContext.Provider>
));
export const Head: React.FC<HeadProps> = memo(({ className, style, ...props }) => <StyledTableHead {...props} />);
68 changes: 68 additions & 0 deletions packages/big-design/src/components/Table/HeaderCell/HeaderCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { ArrowDownwardIcon, ArrowUpwardIcon } from '@bigcommerce/big-design-icons';
import React, { memo } from 'react';

import { Flex } from '../../Flex';

import { StyledTableHeaderCell, StyledTableHeaderCheckbox } from './styled';

export interface HeaderCellProps extends React.TableHTMLAttributes<HTMLTableCellElement> {
align?: 'left' | 'center' | 'right';
isCheckbox?: boolean;
isSortable?: boolean;
isSorted?: boolean;
sortDirection?: 'ASC' | 'DESC';
stickyHeader?: boolean;
width?: number | string;
onSortClick?(): void;
}

export const HeaderCell: React.FC<HeaderCellProps> = memo(
({
align,
children,
isCheckbox,
isSortable,
isSorted,
onSortClick,
sortDirection,
stickyHeader,
width,
}: HeaderCellProps) => {
const renderSortIcon = () => {
if (!isSorted) {
return null;
}

return sortDirection === 'ASC' ? (
<ArrowUpwardIcon size="medium" data-testid="asc-icon" title="Ascending order" />
) : (
<ArrowDownwardIcon size="medium" data-testid="desc-icon" title="Descending order" />
);
};

const handleClick = (e: React.MouseEvent) => {
e.preventDefault();

if (isSortable && typeof onSortClick === 'function') {
onSortClick();
}
};

return isCheckbox ? (
<StyledTableHeaderCheckbox stickyHeader={stickyHeader} align={align} width={width} />
) : (
<StyledTableHeaderCell
align={align}
isSortable={isSortable}
stickyHeader={stickyHeader}
onClick={handleClick}
width={width}
>
<Flex alignItems="center" flexDirection="row">
{children}
{renderSortIcon()}
</Flex>
</StyledTableHeaderCell>
);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { HeaderCell, HeaderCellProps } from './HeaderCell';
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { theme as defaultTheme } from '@bigcommerce/big-design-theme';
import styled, { css } from 'styled-components';

import { CellProps } from './Cell';
import { HeaderCellProps } from './HeaderCell';

interface SharedCellProps extends CellProps {
stickyHeader?: boolean;
}

const SharedCellStyles = css<SharedCellProps>`
export const StyledTableHeaderCell = styled.th<HeaderCellProps>`
background-color: ${({ theme }) => theme.colors.secondary10};
box-shadow: ${({ theme }) =>
`inset 0px -1px 0px ${theme.colors.secondary30}, inset 0px 1px 0px ${theme.colors.secondary30}`};
box-sizing: border-box;
color: ${({ theme }) => theme.colors.secondary60};
font-size: ${({ theme }) => theme.typography.fontSize.medium};
padding: ${({ theme }) => theme.spacing.small};
white-space: nowrap;
${({ align }) =>
align &&
css`
text-align: ${align};
`};
${({ verticalAlign }) =>
verticalAlign &&
${({ isSortable }) =>
isSortable &&
css`
vertical-align: ${verticalAlign};
cursor: pointer;
`};
${({ width }) =>
Expand All @@ -30,23 +31,6 @@ const SharedCellStyles = css<SharedCellProps>`
width: ${typeof width === 'string' ? width : width + 'px'};
`};
${props =>
props.isCheckbox &&
css`
width: ${({ theme }) => theme.helpers.addValues(theme.spacing.xLarge, theme.spacing.small)};
white-space: nowrap;
`};
`;

export const StyledTableHeader = styled.th<SharedCellProps>`
${SharedCellStyles}
background-color: ${({ theme }) => theme.colors.secondary10};
box-shadow: ${({ theme }) =>
`inset 0px -1px 0px ${theme.colors.secondary30}, inset 0px 1px 0px ${theme.colors.secondary30}`};
color: ${({ theme }) => theme.colors.secondary60};
white-space: nowrap;
${({ stickyHeader }) =>
stickyHeader &&
css`
Expand All @@ -55,12 +39,14 @@ export const StyledTableHeader = styled.th<SharedCellProps>`
`}
`;

export const StyledTableData = styled.td<SharedCellProps>`
${SharedCellStyles}
color: ${({ theme }) => theme.colors.secondary70};
padding: ${({ theme, withPadding }) => (withPadding ? theme.spacing.small : 0)};
export const StyledTableHeaderCheckbox = styled(StyledTableHeaderCell)`
${props =>
props.isCheckbox &&
css`
width: ${({ theme }) => theme.helpers.addValues(theme.spacing.xLarge, theme.spacing.small)};
white-space: nowrap;
`};
`;

StyledTableHeader.defaultProps = { theme: defaultTheme };
StyledTableData.defaultProps = { theme: defaultTheme };
StyledTableHeaderCell.defaultProps = { theme: defaultTheme };
StyledTableHeaderCheckbox.defaultProps = { theme: defaultTheme };
29 changes: 3 additions & 26 deletions packages/big-design/src/components/Table/Row/Row.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
import React, { memo, useContext } from 'react';

import { Checkbox } from '../../Checkbox';
import { TableSectionContext } from '../context';
import { Cell } from '../Cell/Cell';
import React, { memo } from 'react';

import { StyledTableRow } from './styled';

export interface RowProps extends React.TableHTMLAttributes<HTMLTableRowElement> {
isSelectable: boolean;
selected?: boolean;
onItemSelect?(nextValue: boolean): void;
}

export const Row: React.FC<RowProps> = memo(({ children, isSelectable, selected = false, onItemSelect }) => {
const tableSectionContext = useContext(TableSectionContext);

const handleSelect = () => {
if (typeof onItemSelect === 'function') {
onItemSelect(!selected);
}
};

return (
<StyledTableRow selected={selected}>
{isSelectable ? (
<Cell isCheckbox>
{tableSectionContext === 'tbody' ? <Checkbox checked={selected} onChange={handleSelect} /> : null}
</Cell>
) : null}
{children}
</StyledTableRow>
);
export const Row: React.FC<RowProps> = memo(({ children, selected = false }) => {
return <StyledTableRow selected={selected}>{children}</StyledTableRow>;
});
Loading

0 comments on commit 2d30461

Please sign in to comment.