Skip to content

Commit

Permalink
feat: migrate pricing page table, convert to semantic HTML tags, open…
Browse files Browse the repository at this point in the history
… up structure like Radix
  • Loading branch information
jamiehenson committed Mar 25, 2024
1 parent 501643f commit a21231c
Show file tree
Hide file tree
Showing 9 changed files with 550 additions and 2 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"@storybook/react": "^7.6.4",
"@storybook/react-webpack5": "^7.6.4",
"@storybook/test": "^7.6.4",
"@testing-library/react": "^14.2.2",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"autoprefixer": "^10.0.2",
Expand Down Expand Up @@ -78,6 +80,7 @@
"build-storybook": "storybook build -o preview"
},
"dependencies": {
"@floating-ui/react": "^0.26.9",
"@mrtkrcm/cypress-plugin-snapshots": "https://github.com/mrtkrcm/cypress-plugin-snapshots#v1.13.0",
"addsearch-js-client": "^0.7.0",
"array-flat-polyfill": "^1.0.1",
Expand Down
30 changes: 30 additions & 0 deletions src/core/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { PropsWithChildren, ReactElement, cloneElement } from "react";

type TableProps = {
id?: string;
};

export const Table = ({ id, children }: PropsWithChildren<TableProps>) => (
<table id={id} className="ui-standard-container mb-4 sm:table-fixed">
{children}
</table>
);

export const TableBody = ({ children }: PropsWithChildren) => (
<tbody>{children}</tbody>
);

export const TableHeader = ({ children }: PropsWithChildren) => (
<thead className="sticky bg-white z-10 top-0" key="sticky-block">
{cloneElement(children as ReactElement, { isHeader: true })}
</thead>
);

export const TableRowHeader = ({ children }: PropsWithChildren) => (
<tr
className="-ml-24 mt-8 sm:ml-0 sm:mt-0 ui-text-overline1 !text-cool-black bg-light-grey sm:sticky z-10"
style={{ top: "4rem" }}
>
{cloneElement(children as ReactElement, { isRowHeader: true })}
</tr>
);
57 changes: 57 additions & 0 deletions src/core/Table/TableCell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from "react";
import { render } from "@testing-library/react";

import { Cell } from "./TableCell";

describe("Cell", () => {
it("renders correctly a cell with support", () => {
const { queryAllByTestId } = render(
<Cell packageName="free" support={true} />
);

// Length 2 because mobile & desktop
expect(queryAllByTestId("supported-icon")).toHaveLength(2);
expect(queryAllByTestId("unsupported-icon")).toHaveLength(0);
});

it("renders correctly a cell with no support", () => {
const { queryAllByTestId } = render(<Cell packageName="free" />);

expect(queryAllByTestId("supported-icon")).toHaveLength(0);
expect(queryAllByTestId("unsupported-icon")).toHaveLength(2);
});

it("renders correctly a cell with content", () => {
const content = "3 replicas across 3 regions";
const { queryAllByTestId, queryAllByText } = render(
<Cell packageName="free" support={{ content }} />
);

expect(queryAllByTestId("supported-icon")).toHaveLength(0);
expect(queryAllByTestId("unsupported-icon")).toHaveLength(0);
expect(queryAllByText(content)).toHaveLength(2);
});

it("renders correctly a cell with content and support", () => {
const content = "3 replicas across 3 regions";
const { queryAllByTestId, queryAllByText } = render(
<Cell packageName="free" support={{ content, support: true }} />
);

expect(queryAllByTestId("supported-icon")).toHaveLength(2);
expect(queryAllByTestId("unsupported-icon")).toHaveLength(0);
expect(queryAllByText(content)).toHaveLength(2);
});

it("renders correctly a cell with react content", () => {
const content = "3 replicas across 3 regions";
const node = <span>{content}</span>;
const { queryAllByTestId, queryAllByText } = render(
<Cell packageName="free" support={{ content: node, support: true }} />
);

expect(queryAllByTestId("supported-icon")).toHaveLength(2);
expect(queryAllByTestId("unsupported-icon")).toHaveLength(0);
expect(queryAllByText(content)).toHaveLength(2);
});
});
84 changes: 84 additions & 0 deletions src/core/Table/TableCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { PropsWithChildren } from "react";
import Icon from "../Icon/component.tsx";

type TableCellProps = {
isRowHeader?: boolean;
} & React.TdHTMLAttributes<HTMLTableCellElement>;

const Supported = () => (
<Icon
name="icon-gui-check-circled-fill"
size="1.5rem"
color="text-gui-success"
additionalCSS="flex-grow-0 flex-shrink-0"
data-testid="supported-icon"
/>
);

const Unsupported = () => (
<Icon
name="icon-gui-cross-circled-fill"
size="1.5rem"
color="text-gui-error"
additionalCSS="flex-grow-0 flex-shrink-0"
data-testid="unsupported-icon"
/>
);

const LabelCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => {
const classes = `
ui-text-p1 !font-bold pt-24 pb-8 border-light-grey sm:p-24 sm:relative sm:top-2 flex sm:table-cell ${
rest.className ?? ""
}
`;

return (
<td {...rest} className={classes}>
{children}
</td>
);
};

const TableCell = ({
children,
isRowHeader,
...rest
}: PropsWithChildren<TableCellProps>) => (
<td
{...rest}
className={`
border-light-grey sm:p-24 leading-none flex sm:table-cell
${
isRowHeader
? "rounded-l-none rounded-r sm:rounded-lg py-20 px-24"
: "py-6"
}
${rest.className ?? ""}
`}
>
{children}
</td>
);

const HeaderCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => (
<td {...rest} className="ui-text-h3 px-24 py-24 hidden sm:table-cell">
{children}
</td>
);

const CtaCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => (
<td {...rest} className="pt-24 hidden sm:table-cell">
{children}
</td>
);

export { TableCell, LabelCell, HeaderCell, CtaCell, Supported, Unsupported };
21 changes: 21 additions & 0 deletions src/core/Table/TableRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { PropsWithChildren } from "react";

const CtaRow = ({ children }: PropsWithChildren) => (
<tr>
<td className="hidden sm:block"></td>
{children}
</tr>
);

type RowProps = {
isHeader?: boolean;
};

const TableRow = ({ children, isHeader }: PropsWithChildren<RowProps>) => (
<tr>
{isHeader && <td className="bg-white" />}
{children}
</tr>
);

export { TableRow, CtaRow };
24 changes: 24 additions & 0 deletions src/core/Table/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Table, TableRowHeader, TableHeader, TableBody } from "./Table";
import { TableRow } from "./TableRow";
import {
TableCell,
LabelCell,
HeaderCell,
CtaCell,
Supported,
Unsupported,
} from "./TableCell";

export default {
Root: Table,
Row: TableRow,
Cell: TableCell,
LabelCell,
HeaderCell,
CtaCell,
RowHeader: TableRowHeader,
Body: TableBody,
Header: TableHeader,
Supported,
Unsupported,
};
16 changes: 16 additions & 0 deletions src/core/Table/stories/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import { Table } from "../Table";
import { PricingPageTable } from "./data";

export default {
title: "Components/Table",
component: Table,
tags: ["autodocs"],
parameters: {
layout: "fullscreen",
},
};

export const PricingPage = {
render: () => <PricingPageTable />,
};
Loading

0 comments on commit a21231c

Please sign in to comment.