Skip to content

Commit

Permalink
feat(DataTable): add support for actions and different layouts (#2953)
Browse files Browse the repository at this point in the history
* feat: add DataTable and Table to drafts

* refactor(DataTable): change interface to type alias

* test: update exports and DataTable test

* chore: add changeset

* feat(DataTable): add support for actions and different layouts

* Update generated/components.json

* chore: remove props for TableDivider

* fix: add center vertical alignment for title

* feat: add TableActionProps to drafts

* chore: add changeset

* chore: remove default story from features

---------

Co-authored-by: Josh Black <joshblack@users.noreply.github.com>
  • Loading branch information
joshblack and joshblack authored Mar 1, 2023
1 parent 4b08828 commit 91688a4
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 37 deletions.
5 changes: 5 additions & 0 deletions .changeset/khaki-readers-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Add Table.Divider and Table.Actions components for Table
7 changes: 6 additions & 1 deletion generated/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -2428,7 +2428,12 @@
"name": "DataTable",
"status": "draft",
"a11yReviewed": false,
"stories": [],
"stories": [
{
"id": "components-datatable--default",
"code": "() => (\n <Table.Container>\n <Table.Title as=\"h2\" id=\"repositories\">\n Repositories\n </Table.Title>\n <Table.Subtitle as=\"p\" id=\"repositories-subtitle\">\n A subtitle could appear here to give extra context to the data.\n </Table.Subtitle>\n <DataTable\n aria-labelledby=\"repositories\"\n aria-describedby=\"repositories-subtitle\"\n data={data}\n columns={[\n {\n header: 'Repository',\n field: 'name',\n rowHeader: true,\n },\n {\n header: 'Type',\n field: 'type',\n renderCell: (row) => {\n return <Label>{uppercase(row.type)}</Label>\n },\n },\n {\n header: 'Updated',\n field: 'updatedAt',\n renderCell: (row) => {\n return <RelativeTime date={new Date(row.updatedAt)} />\n },\n },\n {\n header: 'Dependabot',\n field: 'securityFeatures.dependabot',\n renderCell: (row) => {\n return row.securityFeatures.dependabot.length > 0 ? (\n <LabelGroup>\n {row.securityFeatures.dependabot.map((feature) => {\n return <Label key={feature}>{uppercase(feature)}</Label>\n })}\n </LabelGroup>\n ) : null\n },\n },\n {\n header: 'Code scanning',\n field: 'securityFeatures.codeScanning',\n renderCell: (row) => {\n return row.securityFeatures.codeScanning.length > 0 ? (\n <LabelGroup>\n {row.securityFeatures.codeScanning.map((feature) => {\n return <Label key={feature}>{uppercase(feature)}</Label>\n })}\n </LabelGroup>\n ) : null\n },\n },\n ]}\n />\n </Table.Container>\n)"
}
],
"props": [
{
"name": "aria-describedby",
Expand Down
250 changes: 227 additions & 23 deletions src/DataTable/DataTable.features.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {DownloadIcon, PlusIcon} from '@primer/octicons-react'
import {Meta} from '@storybook/react'
import React from 'react'
import {Button, IconButton} from '../Button'
import {DataTable, Table} from '../DataTable'
import Heading from '../Heading'
import Label from '../Label'
import LabelGroup from '../LabelGroup'
import RelativeTime from '../RelativeTime'
Expand Down Expand Up @@ -116,7 +119,67 @@ function uppercase(input: string): string {
return input[0].toUpperCase() + input.slice(1)
}

export const Default = () => (
export const WithTitle = () => (
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
</Table.Title>
<DataTable
aria-labelledby="repositories"
aria-describedby="repositories-subtitle"
data={data}
columns={[
{
header: 'Repository',
field: 'name',
rowHeader: true,
},
{
header: 'Type',
field: 'type',
renderCell: row => {
return <Label>{uppercase(row.type)}</Label>
},
},
{
header: 'Updated',
field: 'updatedAt',
renderCell: row => {
return <RelativeTime date={new Date(row.updatedAt)} />
},
},
{
header: 'Dependabot',
field: 'securityFeatures.dependabot',
renderCell: row => {
return row.securityFeatures.dependabot.length > 0 ? (
<LabelGroup>
{row.securityFeatures.dependabot.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
{
header: 'Code scanning',
field: 'securityFeatures.codeScanning',
renderCell: row => {
return row.securityFeatures.codeScanning.length > 0 ? (
<LabelGroup>
{row.securityFeatures.codeScanning.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
]}
/>
</Table.Container>
)

export const WithTitleAndSubtitle = () => (
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
Expand Down Expand Up @@ -179,11 +242,90 @@ export const Default = () => (
</Table.Container>
)

export const WithTitle = () => (
export const WithSorting = () => {
const rows = Array.from(data).sort((a, b) => {
return b.updatedAt - a.updatedAt
})
return (
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
</Table.Title>
<Table.Subtitle as="p" id="repositories-subtitle">
A subtitle could appear here to give extra context to the data.
</Table.Subtitle>
<DataTable
aria-labelledby="repositories"
aria-describedby="repositories-subtitle"
data={rows}
columns={[
{
header: 'Repository',
field: 'name',
rowHeader: true,
sortBy: true,
},
{
header: 'Type',
field: 'type',
renderCell: row => {
return <Label>{uppercase(row.type)}</Label>
},
},
{
header: 'Updated',
field: 'updatedAt',
sortBy: true,
renderCell: row => {
return <RelativeTime date={new Date(row.updatedAt)} />
},
},
{
header: 'Dependabot',
field: 'securityFeatures.dependabot',
renderCell: row => {
return row.securityFeatures.dependabot.length > 0 ? (
<LabelGroup>
{row.securityFeatures.dependabot.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
{
header: 'Code scanning',
field: 'securityFeatures.codeScanning',
renderCell: row => {
return row.securityFeatures.codeScanning.length > 0 ? (
<LabelGroup>
{row.securityFeatures.codeScanning.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
]}
initialSortColumn="updatedAt"
initialSortDirection="DESC"
/>
</Table.Container>
)
}

export const WithAction = () => (
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
</Table.Title>
<Table.Actions>
<Button>Action</Button>
</Table.Actions>
<Table.Divider />
<Table.Subtitle as="p" id="repositories-subtitle">
A subtitle could appear here to give extra context to the data.
</Table.Subtitle>
<DataTable
aria-labelledby="repositories"
aria-describedby="repositories-subtitle"
Expand Down Expand Up @@ -239,11 +381,80 @@ export const WithTitle = () => (
</Table.Container>
)

export const WithTitleAndSubtitle = () => (
export const WithActionOnly = () => (
<>
<Heading as="h2" id="table-title">
Repositories
</Heading>
<Table.Container>
<Table.Actions>
<Button>Action</Button>
</Table.Actions>
<DataTable
aria-labelledby="table-title"
data={data}
columns={[
{
header: 'Repository',
field: 'name',
rowHeader: true,
},
{
header: 'Type',
field: 'type',
renderCell: row => {
return <Label>{uppercase(row.type)}</Label>
},
},
{
header: 'Updated',
field: 'updatedAt',
renderCell: row => {
return <RelativeTime date={new Date(row.updatedAt)} />
},
},
{
header: 'Dependabot',
field: 'securityFeatures.dependabot',
renderCell: row => {
return row.securityFeatures.dependabot.length > 0 ? (
<LabelGroup>
{row.securityFeatures.dependabot.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
{
header: 'Code scanning',
field: 'securityFeatures.codeScanning',
renderCell: row => {
return row.securityFeatures.codeScanning.length > 0 ? (
<LabelGroup>
{row.securityFeatures.codeScanning.map(feature => {
return <Label key={feature}>{uppercase(feature)}</Label>
})}
</LabelGroup>
) : null
},
},
]}
/>
</Table.Container>
</>
)

export const WithActions = () => (
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
</Table.Title>
<Table.Actions>
<IconButton aria-label="Download" icon={DownloadIcon} variant="invisible" />
<IconButton aria-label="Add row" icon={PlusIcon} variant="invisible" />
</Table.Actions>
<Table.Divider />
<Table.Subtitle as="p" id="repositories-subtitle">
A subtitle could appear here to give extra context to the data.
</Table.Subtitle>
Expand Down Expand Up @@ -302,28 +513,24 @@ export const WithTitleAndSubtitle = () => (
</Table.Container>
)

export const WithSorting = () => {
const rows = Array.from(data).sort((a, b) => {
return b.updatedAt - a.updatedAt
})
return (
export const WithActionsOnly = () => (
<>
<Heading as="h2" id="table-title">
Repositories
</Heading>
<Table.Container>
<Table.Title as="h2" id="repositories">
Repositories
</Table.Title>
<Table.Subtitle as="p" id="repositories-subtitle">
A subtitle could appear here to give extra context to the data.
</Table.Subtitle>
<Table.Actions>
<IconButton aria-label="Download" icon={DownloadIcon} variant="invisible" />
<IconButton aria-label="Add row" icon={PlusIcon} variant="invisible" />
</Table.Actions>
<DataTable
aria-labelledby="repositories"
aria-describedby="repositories-subtitle"
data={rows}
aria-labelledby="table-title"
data={data}
columns={[
{
header: 'Repository',
field: 'name',
rowHeader: true,
sortBy: true,
},
{
header: 'Type',
Expand All @@ -335,7 +542,6 @@ export const WithSorting = () => {
{
header: 'Updated',
field: 'updatedAt',
sortBy: true,
renderCell: row => {
return <RelativeTime date={new Date(row.updatedAt)} />
},
Expand Down Expand Up @@ -367,9 +573,7 @@ export const WithSorting = () => {
},
},
]}
initialSortColumn="updatedAt"
initialSortDirection="DESC"
/>
</Table.Container>
)
}
</>
)
Loading

0 comments on commit 91688a4

Please sign in to comment.