Skip to content

Commit

Permalink
Update Table to support animation
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepinho committed Aug 15, 2024
1 parent 5953b61 commit 5176967
Showing 1 changed file with 65 additions and 31 deletions.
96 changes: 65 additions & 31 deletions packages/ui/src/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { PropsWithChildren, ReactNode } from 'react';
import { ComponentProps, PropsWithChildren, ReactNode } from 'react';
import styled, { css } from 'styled-components';
import { tableHeading, tableItem } from '../utils/typography';
import { Density } from '../types/Density';
import { useDensity } from '../hooks/useDensity';
import { ConditionalWrap } from '../ConditionalWrap';
import { motion } from 'framer-motion';

type AnimationProps = Pick<
ComponentProps<(typeof motion)['table']>,
'layout' | 'layoutId' | 'initial' | 'animate' | 'exit'
>;

const FIVE_PERCENT_OPACITY_IN_HEX = '0d';

// So named to avoid naming conflicts with `<Table />`
const StyledTable = styled.table<{ $layout?: 'fixed' | 'auto' }>`
const StyledTable = styled(motion.table)<{ $tableLayout?: 'fixed' | 'auto' }>`
width: 100%;
background-color: ${props => props.theme.color.neutral.contrast + FIVE_PERCENT_OPACITY_IN_HEX};
padding-left: ${props => props.theme.spacing(3)};
padding-right: ${props => props.theme.spacing(3)};
border-radius: ${props => props.theme.borderRadius.sm};
table-layout: ${props => props.$layout ?? 'auto'};
table-layout: ${props => props.$tableLayout ?? 'auto'};
`;

const TitleAndTableWrapper = styled.div`
Expand All @@ -26,12 +32,12 @@ const TitleWrapper = styled.div`
padding: ${props => props.theme.spacing(3)};
`;

export interface TableProps {
export interface TableProps extends AnimationProps {
/** Content that will appear above the table. */
title?: ReactNode;
children: ReactNode;
/** Which CSS `table-layout` property to use. */
layout?: 'fixed' | 'auto';
tableLayout?: 'fixed' | 'auto';
}

/**
Expand Down Expand Up @@ -75,7 +81,7 @@ export interface TableProps {
* </Table>
* ```
*/
export const Table = ({ title, children, layout }: TableProps) => (
export const Table = ({ title, children, tableLayout }: TableProps) => (
<ConditionalWrap
if={!!title}
then={children => (
Expand All @@ -85,7 +91,7 @@ export const Table = ({ title, children, layout }: TableProps) => (
</TitleAndTableWrapper>
)}
>
<StyledTable cellSpacing={0} cellPadding={0} $layout={layout}>
<StyledTable cellSpacing={0} cellPadding={0} $tableLayout={tableLayout}>
{children}
</StyledTable>
</ConditionalWrap>
Expand All @@ -98,8 +104,12 @@ const StyledTbody = styled.tbody``; // Needs to be a styled component for `Style
const Tbody = ({ children }: PropsWithChildren) => <StyledTbody>{children}</StyledTbody>;
Table.Tbody = Tbody;

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

type HAlign = 'left' | 'center' | 'right';
Expand All @@ -125,7 +135,7 @@ const cell = css<CellStyledProps>`
${props => props.$vAlign && `vertical-align: ${props.$vAlign};`};
`;

const StyledTh = styled.th<CellStyledProps>`
const StyledTh = styled(motion.th)<CellStyledProps>`
border-bottom: 1px solid ${props => props.theme.color.other.tonalStroke};
text-align: left;
color: ${props => props.theme.color.text.secondary};
Expand All @@ -139,26 +149,38 @@ const Th = ({
hAlign,
vAlign,
width,
}: PropsWithChildren<{
colSpan?: number;
/** A CSS `width` value to use for this cell. */
width?: string;
/** Controls the CSS `text-align` property for this cell. */
hAlign?: HAlign;
/** Controls the CSS `vertical-align` property for this cell. */
vAlign?: VAlign;
}>) => {
layout,
layoutId,
}: PropsWithChildren<
{
colSpan?: number;
/** A CSS `width` value to use for this cell. */
width?: string;
/** Controls the CSS `text-align` property for this cell. */
hAlign?: HAlign;
/** Controls the CSS `vertical-align` property for this cell. */
vAlign?: VAlign;
} & AnimationProps
>) => {
const density = useDensity();

return (
<StyledTh colSpan={colSpan} $width={width} $hAlign={hAlign} $vAlign={vAlign} $density={density}>
<StyledTh
colSpan={colSpan}
layout={layout}
layoutId={layoutId}
$width={width}
$hAlign={hAlign}
$vAlign={vAlign}
$density={density}
>
{children}
</StyledTh>
);
};
Table.Th = Th;

const StyledTd = styled.td<CellStyledProps>`
const StyledTd = styled(motion.td)<CellStyledProps>`
border-bottom: 1px solid ${props => props.theme.color.other.tonalStroke};
color: ${props => props.theme.color.text.primary};
Expand All @@ -175,19 +197,31 @@ const Td = ({
hAlign,
vAlign,
width,
}: PropsWithChildren<{
colSpan?: number;
/** A CSS `width` value to use for this cell. */
width?: string;
/** Controls the CSS `text-align` property for this cell. */
hAlign?: HAlign;
/** Controls the CSS `vertical-align` property for this cell. */
vAlign?: VAlign;
}>) => {
layout,
layoutId,
}: PropsWithChildren<
{
colSpan?: number;
/** A CSS `width` value to use for this cell. */
width?: string;
/** Controls the CSS `text-align` property for this cell. */
hAlign?: HAlign;
/** Controls the CSS `vertical-align` property for this cell. */
vAlign?: VAlign;
} & AnimationProps
>) => {
const density = useDensity();

return (
<StyledTd colSpan={colSpan} $width={width} $hAlign={hAlign} $vAlign={vAlign} $density={density}>
<StyledTd
colSpan={colSpan}
layout={layout}
layoutId={layoutId}
$width={width}
$hAlign={hAlign}
$vAlign={vAlign}
$density={density}
>
{children}
</StyledTd>
);
Expand Down

0 comments on commit 5176967

Please sign in to comment.