Improve Table components
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -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>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user