From 660a378678c5a8f99f1f013da4a3da60ca751a3b Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 25 Jul 2025 07:52:31 +0100 Subject: [PATCH] Improve Table components Signed-off-by: Charles de Dreuille --- .../ui/src/components/DataTable/DataTable.tsx | 36 ++++++----- .../DataTable/Table/DataTableTable.tsx | 45 ++++++++------ .../components/DataTable/mocked-columns.tsx | 4 +- .../ui/src/components/Table/Table.stories.tsx | 59 ++++++++++--------- packages/ui/src/components/Table/Table.tsx | 41 +++++-------- packages/ui/src/components/Table/index.ts | 11 ++-- 6 files changed, 103 insertions(+), 93 deletions(-) diff --git a/packages/ui/src/components/DataTable/DataTable.tsx b/packages/ui/src/components/DataTable/DataTable.tsx index 5a587df56f..1f2270bd28 100644 --- a/packages/ui/src/components/DataTable/DataTable.tsx +++ b/packages/ui/src/components/DataTable/DataTable.tsx @@ -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, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableRoot.displayName = Table.Root.displayName; + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +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, }; diff --git a/packages/ui/src/components/DataTable/Table/DataTableTable.tsx b/packages/ui/src/components/DataTable/Table/DataTableTable.tsx index 954cf9f703..368d31e78b 100644 --- a/packages/ui/src/components/DataTable/Table/DataTableTable.tsx +++ b/packages/ui/src/components/DataTable/Table/DataTableTable.tsx @@ -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.getHeaderGroups().map(headerGroup => ( - + {headerGroup.headers.map(header => { return ( - @@ -49,42 +56,42 @@ const DataTableTable = forwardRef( header.column.columnDef.header, header.getContext(), )} - + ); })} - + ))} - - + + {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map(row => ( - {row.getVisibleCells().map(cell => ( - {flexRender(cell.column.columnDef.cell, cell.getContext())} - + ))} - + )) ) : ( - - + No results. - - + + )} - - + +
); }, ); diff --git a/packages/ui/src/components/DataTable/mocked-columns.tsx b/packages/ui/src/components/DataTable/mocked-columns.tsx index 4b06bbfaa1..600065bdf5 100644 --- a/packages/ui/src/components/DataTable/mocked-columns.tsx +++ b/packages/ui/src/components/DataTable/mocked-columns.tsx @@ -48,7 +48,7 @@ export const columns: ColumnDef[] = [ accessorKey: 'name', header: 'Name', cell: ({ row }) => ( - [] = [ accessorKey: 'name', header: 'Name', cell: ({ row }) => ( - + ), size: 450, }, diff --git a/packages/ui/src/components/Table/Table.stories.tsx b/packages/ui/src/components/Table/Table.stories.tsx index f008e73bae..c8279e5a83 100644 --- a/packages/ui/src/components/Table/Table.stories.tsx +++ b/packages/ui/src/components/Table/Table.stories.tsx @@ -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, - Cell: Table.Cell as ComponentType, - Head: Table.Head as ComponentType, - Header: Table.Header as ComponentType, - Row: Table.Row as ComponentType, + Body: TableBody as ComponentType, + Cell: TableCell as ComponentType, + Head: TableHead as ComponentType, + Header: TableHeader as ComponentType, + Row: TableRow as ComponentType, }, } satisfies Meta; @@ -80,27 +87,25 @@ type Story = StoryObj; export const Default: Story = { render: () => ( - - - - Invoice - Status - Method - Amount - - - + + + + Invoice + Status + Method + Amount + + + {invoices.map(invoice => ( - - {invoice.invoice} - {invoice.paymentStatus} - {invoice.paymentMethod} - - {invoice.totalAmount} - - + + {invoice.invoice} + {invoice.paymentStatus} + {invoice.paymentMethod} + {invoice.totalAmount} + ))} - - + +
), }; diff --git a/packages/ui/src/components/Table/Table.tsx b/packages/ui/src/components/Table/Table.tsx index 4c2597ba79..e82885d318 100644 --- a/packages/ui/src/components/Table/Table.tsx +++ b/packages/ui/src/components/Table/Table.tsx @@ -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 >(({ className, ...props }, ref) => { @@ -31,9 +29,10 @@ const TableRoot = forwardRef< ); }); -TableRoot.displayName = 'TableRoot'; +Table.displayName = 'Table'; -const TableHeader = forwardRef< +/** @public */ +export const TableHeader = forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => { @@ -49,7 +48,8 @@ const TableHeader = forwardRef< }); TableHeader.displayName = 'TableHeader'; -const TableBody = forwardRef< +/** @public */ +export const TableBody = forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => { @@ -61,7 +61,8 @@ const TableBody = forwardRef< }); TableBody.displayName = 'TableBody'; -const TableRow = forwardRef< +/** @public */ +export const TableRow = forwardRef< HTMLTableRowElement, React.HTMLAttributes >(({ className, ...props }, ref) => { @@ -75,7 +76,8 @@ const TableRow = forwardRef< }); TableRow.displayName = 'TableRow'; -const TableHead = forwardRef< +/** @public */ +export const TableHead = forwardRef< HTMLTableCellElement, React.ThHTMLAttributes >(({ className, ...props }, ref) => { @@ -87,7 +89,8 @@ const TableHead = forwardRef< }); TableHead.displayName = 'TableHead'; -const TableCaption = forwardRef< +/** @public */ +export const TableCaption = forwardRef< HTMLTableCaptionElement, React.HTMLAttributes >(({ 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, -}; diff --git a/packages/ui/src/components/Table/index.ts b/packages/ui/src/components/Table/index.ts index ecf1cd7b18..aa9bd105cd 100644 --- a/packages/ui/src/components/Table/index.ts +++ b/packages/ui/src/components/Table/index.ts @@ -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';