Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(store-ui): Table Molecule #987

Merged
merged 22 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0887370
Create Table molecule along with its children
victorhmp Oct 12, 2021
365af22
Add first story for Table component
victorhmp Oct 12, 2021
c7bbbcd
Add test plan for Table component
victorhmp Oct 12, 2021
edff926
Add missing default values for 'testId' prop to Table components
victorhmp Oct 13, 2021
fe5a339
Implement unit tests for Table component
victorhmp Oct 13, 2021
2cae7e7
Add CSS for Table molecule
victorhmp Oct 13, 2021
2b4750d
Add simple Table story
victorhmp Oct 13, 2021
49b4992
Update Table docs for Storybook
victorhmp Oct 13, 2021
58c6ae1
Fix typo on Table.mdx
victorhmp Oct 13, 2021
148ab9a
Remove unnecessary `return` from Table story
victorhmp Oct 13, 2021
f1bce00
Fix CSS selectors section on Table.mdx
victorhmp Oct 14, 2021
9c1eb70
Add extra `describe` to improve test readability
victorhmp Oct 15, 2021
8c7d08c
Add missing prop descriptions to Table components
victorhmp Oct 15, 2021
f26d743
Update Table.mdx
victorhmp Oct 15, 2021
9a9e556
Update Table.mdx
victorhmp Oct 15, 2021
10f1a94
Add TableFooter to Table story example
victorhmp Oct 15, 2021
7742c72
Export Table components from store-ui's index
victorhmp Oct 18, 2021
bece558
Add missing props description to TableCell component
victorhmp Oct 18, 2021
a8a2c61
Update exports from Accordion components
victorhmp Oct 18, 2021
bf7a155
Add styles for TableFooter
victorhmp Oct 18, 2021
6a26200
Update Table docs
victorhmp Oct 18, 2021
35a85ac
Change props spreading pattern from `...rest` to `...otherProps` on T…
victorhmp Oct 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 29 additions & 11 deletions packages/store-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,35 @@ export type { IconButtonProps } from './molecules/IconButton'
export { default as Modal } from './molecules/Modal'
export type { ModalProps } from './molecules/Modal'

export { default as Accordion } from './molecules/Accordion'
export type { AccordionProps } from './molecules/Accordion'

export { AccordionItem } from './molecules/Accordion'
export type { AccordionItemProps } from './molecules/Accordion'

export { AccordionButton } from './molecules/Accordion'
export type { AccordionButtonProps } from './molecules/Accordion'

export { AccordionPanel } from './molecules/Accordion'
export type { AccordionPanelProps } from './molecules/Accordion'
export {
default as Accordion,
AccordionItem,
AccordionButton,
AccordionPanel,
} from './molecules/Accordion'
export type {
AccordionProps,
AccordionItemProps,
AccordionButtonProps,
AccordionPanelProps,
} from './molecules/Accordion'

export {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableRow,
} from './molecules/Table'
export type {
TableProps,
TableBodyProps,
TableCellProps,
TableFooterProps,
TableHeadProps,
TableRowProps,
} from './molecules/Table'

// Hooks
export { default as useSlider } from './hooks/useSlider'
Expand Down
237 changes: 237 additions & 0 deletions packages/store-ui/src/molecules/Table/Table.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
import React from 'react'
import { render } from '@testing-library/react'
import { axe } from 'jest-axe'

import Table from './Table'
import TableHead from './TableHead'
import TableRow from './TableRow'
import TableBody from './TableBody'
import TableCell from './TableCell'
import TableFooter from './TableFooter'

describe('Table', () => {
describe('Data attributes', () => {
it('should render a simple table with all expected data-attributes', () => {
const { getByTestId, queryAllByTestId } = render(
<Table>
<TableHead>
<TableRow>
<TableCell variant="header">Name</TableCell>
<TableCell variant="header">Age</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>John</TableCell>
<TableCell>25</TableCell>
</TableRow>
<TableRow>
<TableCell>Carter</TableCell>
<TableCell>25</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Age</TableCell>
</TableRow>
</TableFooter>
</Table>
)

const table = getByTestId('store-table')

expect(table).toHaveAttribute('data-store-table')

const tableHead = getByTestId('store-table-head')

expect(tableHead).toHaveAttribute('data-store-table-head')

const tableBody = getByTestId('store-table-body')

expect(tableBody).toHaveAttribute('data-store-table-body')

const tableFooter = getByTestId('store-table-footer')

expect(tableFooter).toHaveAttribute('data-store-table-footer')

const tableRows = queryAllByTestId('store-table-row')

expect(tableRows).toHaveLength(4)
tableRows.forEach((row) => {
expect(row).toHaveAttribute('data-store-table-row')
})

const tableCells = queryAllByTestId('store-table-cell')

// Make sure 8 cells were rendered and all contain the
// data-store-table-cell attribute.
expect(tableCells).toHaveLength(8)
tableCells.forEach((row) => {
expect(row).toHaveAttribute('data-store-table-cell')
})

// Make sure that 2 header cells and 6 data cells were rendered, with their
// corresponding attributes.
expect(
table.querySelectorAll('[data-store-table-cell=header]')
).toHaveLength(2)
expect(
table.querySelectorAll('[data-store-table-cell=data]')
).toHaveLength(6)
})
})

// WAI-ARIA tests
// https://www.w3.org/WAI/tutorials/tables/
describe('Table WAI-ARIA Specifications', () => {
describe('Tables with one header', () => {
it('should have no violations on a table with header cells in the top row only', async () => {
const { container } = render(
<Table>
<TableHead>
<TableRow>
<TableCell variant="header">Name</TableCell>
<TableCell variant="header">Age</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>John</TableCell>
<TableCell>25</TableCell>
</TableRow>
<TableRow>
<TableCell>Carter</TableCell>
<TableCell>25</TableCell>
</TableRow>
</TableBody>
</Table>
)

expect(await axe(container)).toHaveNoViolations()
})

it('should have no violations on a table with header cells in the first column only', async () => {
const { container } = render(
<Table>
<TableBody>
<TableRow>
<TableCell variant="header">Date</TableCell>
<TableCell>12 February</TableCell>
<TableCell>24 March</TableCell>
<TableCell>14 April</TableCell>
</TableRow>
<TableRow>
<TableCell variant="header">Event</TableCell>
<TableCell>Waltz with Strauss</TableCell>
<TableCell>The Obelisks</TableCell>
<TableCell>The What</TableCell>
</TableRow>
<TableRow>
<TableCell variant="header">Venue</TableCell>
<TableCell>Main Hall</TableCell>
<TableCell>West Wing</TableCell>
<TableCell>Main Hall</TableCell>
</TableRow>
</TableBody>
</Table>
)

expect(await axe(container)).toHaveNoViolations()
})

// https://www.w3.org/WAI/WCAG21/Techniques/html/H63
it('should have no violations on a table with ambiguous data, where scope should be used', async () => {
const { container } = render(
<Table>
<TableHead>
<TableRow>
<TableCell variant="header" scope="col">
Last Name
</TableCell>
<TableCell variant="header" scope="col">
First Name
</TableCell>
<TableCell variant="header" scope="col">
City
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>Phoenix</TableCell>
<TableCell>Imari</TableCell>
<TableCell>Henry</TableCell>
</TableRow>
<TableRow>
<TableCell>Zeki</TableCell>
<TableCell>Rome</TableCell>
<TableCell>Min</TableCell>
</TableRow>
<TableRow>
<TableCell>Apirka</TableCell>
<TableCell>Kelly</TableCell>
<TableCell>Brynn</TableCell>
</TableRow>
</TableBody>
</Table>
)

expect(await axe(container)).toHaveNoViolations()
})
})

describe('Tables with two headers', () => {
it('should have no violations on a table with header cells in the top row and first column', async () => {
const { container } = render(
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell variant="header" scope="col">
Monday
</TableCell>
<TableCell variant="header" scope="col">
Tuesday
</TableCell>
<TableCell variant="header" scope="col">
Wednesday
</TableCell>
<TableCell variant="header" scope="col">
Thursday
</TableCell>
<TableCell variant="header" scope="col">
Friday
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell variant="header" scope="row">
09:00 - 11:00
</TableCell>
<TableCell>Closed</TableCell>
<TableCell>Open</TableCell>
<TableCell>Open</TableCell>
<TableCell>Closed</TableCell>
<TableCell>Closed</TableCell>
</TableRow>
<TableRow>
<TableCell variant="header" scope="row">
11:00 - 13:00
</TableCell>
<TableCell>Open</TableCell>
<TableCell>Open</TableCell>
<TableCell>Closed</TableCell>
<TableCell>Closed</TableCell>
<TableCell>Closed</TableCell>
</TableRow>
</TableBody>
</Table>
)

expect(await axe(container)).toHaveNoViolations()
})
})
})
})
23 changes: 23 additions & 0 deletions packages/store-ui/src/molecules/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

export interface TableProps extends HTMLAttributes<HTMLTableElement> {
/**
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
*/
testId?: string
victorhmp marked this conversation as resolved.
Show resolved Hide resolved
children: React.ReactNode
igorbrasileiro marked this conversation as resolved.
Show resolved Hide resolved
}

const Table = forwardRef<HTMLTableElement, TableProps>(function Table(
{ testId = 'store-table', children, ...otherProps },
ref
) {
return (
<table ref={ref} data-store-table data-testid={testId} {...otherProps}>
{children}
</table>
)
})

export default Table
31 changes: 31 additions & 0 deletions packages/store-ui/src/molecules/Table/TableBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

export interface TableBodyProps
extends HTMLAttributes<HTMLTableSectionElement> {
/**
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
*/
testId?: string
children: React.ReactNode
igorbrasileiro marked this conversation as resolved.
Show resolved Hide resolved
}

const TableBody = forwardRef<HTMLTableSectionElement, TableBodyProps>(
function TableBody(
{ children, testId = 'store-table-body', ...otherProps },
ref
) {
return (
<tbody
ref={ref}
data-testid={testId}
data-store-table-body
{...otherProps}
>
{children}
</tbody>
)
}
)

export default TableBody
49 changes: 49 additions & 0 deletions packages/store-ui/src/molecules/Table/TableCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

type TableCellVariant = 'data' | 'header'
victorhmp marked this conversation as resolved.
Show resolved Hide resolved

export interface TableCellProps extends HTMLAttributes<HTMLTableCellElement> {
/**
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
*/
testId?: string
/**
* Specify if this component should be rendered as a header (`<th>`) or as a data cell (`<td>`).
*/
variant?: TableCellVariant
victorhmp marked this conversation as resolved.
Show resolved Hide resolved
/**
* Defines the cells that the header element (`<th>`) relates to.
* @see scope https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th#attr-scope
*/
scope?: 'col' | 'row' | 'rowgroup' | 'colgroup'
}

const TableCell = forwardRef<HTMLTableCellElement, TableCellProps>(
function TableCell(
{
testId = 'store-table-cell',
children,
variant = 'data',
scope,
...otherProps
},
ref
) {
const Cell = variant === 'header' ? 'th' : 'td'

return (
<Cell
ref={ref}
data-store-table-cell={variant}
data-testid={testId}
scope={scope}
{...otherProps}
>
{children}
</Cell>
)
}
)

export default TableCell