Skip to content

Commit

Permalink
Rework how tables are constructed
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepinho committed Jul 24, 2024
1 parent 2d26cd7 commit a01ec70
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 99 deletions.
39 changes: 17 additions & 22 deletions packages/ui/src/Table/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import type { Meta, StoryObj } from '@storybook/react';

import { Table } from '.';
import { Text } from '../Text';

const meta: Meta<typeof Table> = {
component: Table,
tags: ['autodocs', '!dev'],
argTypes: {
thead: { control: false },
tbody: { control: false },
tfoot: { control: false },
tr: { control: false },
th: { control: false },
td: { control: false },
},
};
export default meta;

Expand All @@ -31,22 +24,24 @@ export const Basic: Story = {
render: function Render() {
return (
<Table>
<Table thead>
<Table tr>
<Table th>Block height</Table>
<Table th>Description</Table>
<Table th>Transaction hash</Table>
</Table>
</Table>
<Table tbody>
<Table.Thead>
<Table.Tr>
<Table.Th>Block height</Table.Th>
<Table.Th>Description</Table.Th>
<Table.Th>Transaction hash</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{DATA.map(([blockHeight, description, hash]) => (
<Table tr key={hash}>
<Table td>{blockHeight}</Table>
<Table td>{description}</Table>
<Table td>{hash}</Table>
</Table>
<Table.Tr key={hash}>
<Table.Td>{blockHeight}</Table.Td>
<Table.Td>{description}</Table.Td>
<Table.Td>
<Text technical>{hash}</Text>
</Table.Td>
</Table.Tr>
))}
</Table>
</Table.Tbody>
</Table>
);
},
Expand Down
105 changes: 28 additions & 77 deletions packages/ui/src/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode } from 'react';
import { PropsWithChildren, ReactNode } from 'react';
import styled, { css } from 'styled-components';
import { tableHeading, tableItem } from '../utils/typography';

Expand All @@ -13,9 +13,27 @@ const StyledTable = styled.table`
border-radius: ${props => props.theme.borderRadius.lg};
`;

const Tbody = styled.tbody``;
export interface TableProps {
children: ReactNode;
}

export const Table = (props: TableProps) => {
return <StyledTable cellSpacing={0} cellPadding={0} {...props} />;
};

const Thead = ({ children }: PropsWithChildren) => <thead>{children}</thead>;
Table.Thead = Thead;

const Tr = styled.tr``;
const StyledTbody = styled.tbody``; // Needs to be a styled component for `StyledTd` below
const Tbody = ({ children }: PropsWithChildren) => <StyledTbody>{children}</StyledTbody>;
Table.Tbody = Tbody;

const Tfoot = ({ children }: PropsWithChildren) => <tfoot>{children}</tfoot>;
Table.Tfoot = Tfoot;

const StyledTr = styled.tr``; // Needs to be a styled component for `StyledTd` below
const Tr = ({ children }: PropsWithChildren) => <StyledTr>{children}</StyledTr>;
Table.Tr = Tr;

const cell = css`
padding-left: ${props => props.theme.spacing(3)};
Expand All @@ -25,94 +43,27 @@ const cell = css`
padding-bottom: ${props => props.theme.spacing(4)};
`;

const Th = styled.th`
const StyledTh = styled.th`
border-bottom: 1px solid ${props => props.theme.color.other.tonalStroke};
text-align: left;
color: ${props => props.theme.color.text.secondary};
${tableHeading}
${cell}
`;
const Th = ({ children }: PropsWithChildren) => <StyledTh>{children}</StyledTh>;
Table.Th = Th;

const Td = styled.td`
const StyledTd = styled.td`
border-bottom: 1px solid ${props => props.theme.color.other.tonalStroke};
color: ${props => props.theme.color.text.primary};
tbody > ${Tr}:last-child > & {
${StyledTbody} > ${StyledTr}:last-child > & {
border-bottom: none;
}
${tableItem}
${cell}
`;

/**
* Utility interface to be used below to ensure that only one table element is
* used on a component at a time.
*/
interface NeverTableTypes {
thead?: never;
tbody?: never;
tfoot?: never;
tr?: never;
th?: never;
td?: never;
}

type TableType =
| (Omit<NeverTableTypes, 'thead'> & {
/** Renders a `<thead />` element. */
thead: true;
children: ReactNode;
})
| (Omit<NeverTableTypes, 'tbody'> & {
/** Renders a `<tbody />` element. */
tbody: true;
children: ReactNode;
})
| (Omit<NeverTableTypes, 'tfoot'> & {
/** Renders a `<tfoot />` element. */
tfoot: true;
children: ReactNode;
})
| (Omit<NeverTableTypes, 'tr'> & {
/** Renders a `<tr />` element. */
tr: true;
children: ReactNode;
})
| (Omit<NeverTableTypes, 'th'> & {
/** Renders a `<th />` element. */
th: true;
children?: ReactNode;
})
| (Omit<NeverTableTypes, 'td'> & {
/** Renders a `<td />` element. */
td: true;
children?: ReactNode;
})
| (NeverTableTypes & { children: ReactNode }); // <table> component

export type TableProps = TableType;

export const Table = (props: TableProps) => {
if (props.thead) {
return <thead {...props} />;
}
if (props.tbody) {
return <Tbody {...props} />;
}
if (props.tfoot) {
return <tfoot {...props} />;
}
if (props.tr) {
return <Tr {...props} />;
}
if (props.th) {
return <Th {...props} />;
}
if (props.td) {
return <Td {...props} />;
}

return <StyledTable cellSpacing={0} cellPadding={0} {...props} />;
};
const Td = ({ children }: PropsWithChildren) => <StyledTd>{children}</StyledTd>;
Table.Td = Td;

0 comments on commit a01ec70

Please sign in to comment.