Improve Table components

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-07-25 07:52:31 +01:00
parent 67d3698100
commit 660a378678
6 changed files with 103 additions and 93 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2024 The Backstage Authors
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,17 +15,26 @@
*/
import { forwardRef } from 'react';
import { Table } from '../Table';
import {
Table,
TableBody,
TableCell,
TableHead,
TableCellProfile,
TableCellText,
TableHeader,
TableRow,
} from '../Table';
import { DataTableRoot } from './Root/DataTableRoot';
import { DataTablePagination } from './Pagination/DataTablePagination';
import { Table as TanstackTable } from '@tanstack/react-table';
import { DataTableTable } from './Table/DataTableTable';
const TableRoot = forwardRef<
React.ElementRef<typeof Table.Root>,
React.ComponentPropsWithoutRef<typeof Table.Root>
>(({ className, ...props }, ref) => <Table.Root ref={ref} {...props} />);
TableRoot.displayName = Table.Root.displayName;
React.ElementRef<typeof Table>,
React.ComponentPropsWithoutRef<typeof Table>
>(({ className, ...props }, ref) => <Table ref={ref} {...props} />);
TableRoot.displayName = Table.displayName;
/**
* DataTable component for displaying tabular data with pagination
@@ -40,12 +49,11 @@ export const DataTable = {
Pagination: DataTablePagination,
Table: DataTableTable,
TableRoot: TableRoot,
TableHeader: Table.Header,
TableBody: Table.Body,
TableRow: Table.Row,
TableCell: Table.Cell,
TableCellText: Table.CellText,
TableCellLink: Table.CellLink,
TableCellProfile: Table.CellProfile,
TableHead: Table.Head,
TableHeader: TableHeader,
TableBody: TableBody,
TableRow: TableRow,
TableCell: TableCell,
TableCellText: TableCellText,
TableCellProfile: TableCellProfile,
TableHead: TableHead,
};
@@ -17,7 +17,14 @@
import { forwardRef } from 'react';
import clsx from 'clsx';
import { DataTableTableProps } from './types';
import { Table } from '../../Table';
import {
Table,
TableRow,
TableHeader,
TableHead,
TableBody,
TableCell,
} from '../../Table';
import { useDataTable } from '../Root/DataTableRoot';
import { flexRender } from '@tanstack/react-table';
@@ -28,18 +35,18 @@ const DataTableTable = forwardRef(
const { table } = useDataTable();
return (
<Table.Root
<Table
ref={ref}
style={{ minWidth: table.getTotalSize() }}
className={clsx(className)}
{...rest}
>
<Table.Header>
<TableHeader>
{table.getHeaderGroups().map(headerGroup => (
<Table.Row key={headerGroup.id}>
<TableRow key={headerGroup.id}>
{headerGroup.headers.map(header => {
return (
<Table.Head
<TableHead
key={header.id}
style={{ width: header.getSize() }}
>
@@ -49,42 +56,42 @@ const DataTableTable = forwardRef(
header.column.columnDef.header,
header.getContext(),
)}
</Table.Head>
</TableHead>
);
})}
</Table.Row>
</TableRow>
))}
</Table.Header>
<Table.Body>
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map(row => (
<Table.Row
<TableRow
key={row.id}
data-state={row.getIsSelected() && 'selected'}
>
{row.getVisibleCells().map(cell => (
<Table.Cell
<TableCell
key={cell.id}
style={{ width: cell.column.getSize() }}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Table.Cell>
</TableCell>
))}
</Table.Row>
</TableRow>
))
) : (
<Table.Row>
<Table.Cell
<TableRow>
<TableCell
colSpan={table.getAllColumns().length}
className="h-24 text-center"
style={{ width: table.getTotalSize() }}
>
No results.
</Table.Cell>
</Table.Row>
</TableCell>
</TableRow>
)}
</Table.Body>
</Table.Root>
</TableBody>
</Table>
);
},
);
@@ -48,7 +48,7 @@ export const columns: ColumnDef<DataProps>[] = [
accessorKey: 'name',
header: 'Name',
cell: ({ row }) => (
<DataTable.TableCellLink
<DataTable.TableCellText
title={row.getValue('name')}
description={row.original.description}
href="/"
@@ -98,7 +98,7 @@ export const columns2: ColumnDef<DataProps>[] = [
accessorKey: 'name',
header: 'Name',
cell: ({ row }) => (
<DataTable.TableCellLink title={row.getValue('name')} href="/" />
<DataTable.TableCellText title={row.getValue('name')} href="/" />
),
size: 450,
},
@@ -16,7 +16,14 @@
import { ComponentType } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Table } from '.';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '.';
const invoices = [
{
@@ -65,13 +72,13 @@ const invoices = [
const meta = {
title: 'Components/Table',
component: Table.Root,
component: Table,
subcomponents: {
Body: Table.Body as ComponentType<unknown>,
Cell: Table.Cell as ComponentType<unknown>,
Head: Table.Head as ComponentType<unknown>,
Header: Table.Header as ComponentType<unknown>,
Row: Table.Row as ComponentType<unknown>,
Body: TableBody as ComponentType<unknown>,
Cell: TableCell as ComponentType<unknown>,
Head: TableHead as ComponentType<unknown>,
Header: TableHeader as ComponentType<unknown>,
Row: TableRow as ComponentType<unknown>,
},
} satisfies Meta<typeof Table>;
@@ -80,27 +87,25 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<Table.Root>
<Table.Header>
<Table.Row>
<Table.Head className="w-[100px]">Invoice</Table.Head>
<Table.Head>Status</Table.Head>
<Table.Head>Method</Table.Head>
<Table.Head className="text-right">Amount</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map(invoice => (
<Table.Row key={invoice.invoice}>
<Table.Cell className="font-medium">{invoice.invoice}</Table.Cell>
<Table.Cell>{invoice.paymentStatus}</Table.Cell>
<Table.Cell>{invoice.paymentMethod}</Table.Cell>
<Table.Cell className="text-right">
{invoice.totalAmount}
</Table.Cell>
</Table.Row>
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</Table.Body>
</Table.Root>
</TableBody>
</Table>
),
};
+14 -27
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2024 The Backstage Authors
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,10 @@
import { forwardRef } from 'react';
import clsx from 'clsx';
import { TableCell } from './TableCell/TableCell';
import { TableCellText } from './TableCellText/TableCellText';
import { TableCellProfile } from './TableCellProfile/TableCellProfile';
import { useStyles } from '../../hooks/useStyles';
const TableRoot = forwardRef<
/** @public */
export const Table = forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => {
@@ -31,9 +29,10 @@ const TableRoot = forwardRef<
<table ref={ref} className={clsx(classNames.root, className)} {...props} />
);
});
TableRoot.displayName = 'TableRoot';
Table.displayName = 'Table';
const TableHeader = forwardRef<
/** @public */
export const TableHeader = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => {
@@ -49,7 +48,8 @@ const TableHeader = forwardRef<
});
TableHeader.displayName = 'TableHeader';
const TableBody = forwardRef<
/** @public */
export const TableBody = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => {
@@ -61,7 +61,8 @@ const TableBody = forwardRef<
});
TableBody.displayName = 'TableBody';
const TableRow = forwardRef<
/** @public */
export const TableRow = forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => {
@@ -75,7 +76,8 @@ const TableRow = forwardRef<
});
TableRow.displayName = 'TableRow';
const TableHead = forwardRef<
/** @public */
export const TableHead = forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => {
@@ -87,7 +89,8 @@ const TableHead = forwardRef<
});
TableHead.displayName = 'TableHead';
const TableCaption = forwardRef<
/** @public */
export const TableCaption = forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => {
@@ -102,19 +105,3 @@ const TableCaption = forwardRef<
);
});
TableCaption.displayName = 'TableCaption';
/**
* Table component for displaying tabular data
* @public
*/
export const Table = {
Root: TableRoot,
Header: TableHeader,
Body: TableBody,
Head: TableHead,
Row: TableRow,
Cell: TableCell,
CellText: TableCellText,
CellProfile: TableCellProfile,
Caption: TableCaption,
};
+7 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2024 The Backstage Authors
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,9 @@
* limitations under the License.
*/
export * from './Table';
export * from './TableCellText/types';
export * from './TableCellProfile/types';
export { Table, TableBody, TableHead, TableHeader, TableRow } from './Table';
export { TableCell } from './TableCell/TableCell';
export { TableCellText } from './TableCellText/TableCellText';
export { TableCellProfile } from './TableCellProfile/TableCellProfile';
export type { TableCellTextProps } from './TableCellText/types';
export type { TableCellProfileProps } from './TableCellProfile/types';