diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index bc473d2006..9314abed7c 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -94,6 +94,34 @@ height: 1.5rem; } +.canon-DataTableRoot { + gap: var(--canon-space-3); + flex-direction: column; + display: flex; +} + +.canon-TablePagination { + padding-top: var(--canon-space-3); + border-top: 1px solid var(--canon-border); + margin-top: var(--canon-space-3); + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--left { + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--right { + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + display: flex; +} + .canon-Flex { display: flex; } @@ -163,14 +191,7 @@ } .table { - background-color: var(--canon-bg-surface-1); - border-radius: var(--canon-radius-2); width: 100%; - padding-bottom: var(--canon-space-0_5); - padding-top: var(--canon-space-0_5); - font-size: var(--canon-font-size-3); - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-regular); position: relative; overflow: auto; diff --git a/packages/canon/css/datatable.css b/packages/canon/css/datatable.css new file mode 100644 index 0000000000..c33ecce578 --- /dev/null +++ b/packages/canon/css/datatable.css @@ -0,0 +1,21 @@ +.canon-TablePagination { + padding-top: var(--canon-space-3); + border-top: 1px solid var(--canon-border); + margin-top: var(--canon-space-3); + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--left { + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--right { + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + display: flex; +} diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index b5093e217c..db668eb1b9 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9300,6 +9300,34 @@ height: 1.5rem; } +.canon-DataTableRoot { + gap: var(--canon-space-3); + flex-direction: column; + display: flex; +} + +.canon-TablePagination { + padding-top: var(--canon-space-3); + border-top: 1px solid var(--canon-border); + margin-top: var(--canon-space-3); + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--left { + justify-content: space-between; + align-items: center; + display: flex; +} + +.canon-TablePagination--right { + justify-content: space-between; + align-items: center; + gap: var(--canon-space-2); + display: flex; +} + .canon-Flex { display: flex; } @@ -9369,14 +9397,7 @@ } .table { - background-color: var(--canon-bg-surface-1); - border-radius: var(--canon-radius-2); width: 100%; - padding-bottom: var(--canon-space-0_5); - padding-top: var(--canon-space-0_5); - font-size: var(--canon-font-size-3); - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-regular); position: relative; overflow: auto; diff --git a/packages/canon/css/table.css b/packages/canon/css/table.css index a8e904d7ce..a146010779 100644 --- a/packages/canon/css/table.css +++ b/packages/canon/css/table.css @@ -1,12 +1,5 @@ .table { - background-color: var(--canon-bg-surface-1); - border-radius: var(--canon-radius-2); width: 100%; - padding-bottom: var(--canon-space-0_5); - padding-top: var(--canon-space-0_5); - font-size: var(--canon-font-size-3); - font-family: var(--canon-font-regular); - font-weight: var(--canon-font-weight-regular); position: relative; overflow: auto; diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 766b40febd..29bf979040 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -213,6 +213,33 @@ export interface ContainerProps { style?: React.CSSProperties; } +// @public +export const DataTable: { + Root: ForwardRefExoticComponent< + DataTableRootProps & RefAttributes + >; + Pagination: ForwardRefExoticComponent< + DataTablePaginationProps & RefAttributes + >; +}; + +// @public (undocumented) +export interface DataTablePaginationProps + extends React.HTMLAttributes { + canNext?: boolean; + canPrevious?: boolean; + onClickNext?: () => void; + onClickPrevious?: () => void; + pageIndex?: number; + pageSize?: number; + setPageSize?: (pageSize: number) => void; + totalRows?: number; +} + +// @public (undocumented) +export interface DataTableRootProps + extends React.HTMLAttributes {} + // @public (undocumented) export type Display = 'none' | 'flex' | 'block' | 'inline'; @@ -1005,47 +1032,37 @@ export type StylingPropDef = { parseValue?: (value: string) => string | undefined; }; -// @public (undocumented) -export const Table: React_3.ForwardRefExoticComponent< - React_3.HTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableBody: React_3.ForwardRefExoticComponent< - React_3.HTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableCell: React_3.ForwardRefExoticComponent< - React_3.TdHTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableFooter: React_3.ForwardRefExoticComponent< - React_3.HTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableHead: React_3.ForwardRefExoticComponent< - React_3.ThHTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableHeader: React_3.ForwardRefExoticComponent< - React_3.HTMLAttributes & - React_3.RefAttributes ->; - -// @public (undocumented) -export const TableRow: React_3.ForwardRefExoticComponent< - React_3.HTMLAttributes & - React_3.RefAttributes ->; +// @public +export const Table: { + Root: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes + >; + Header: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes + >; + Body: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes + >; + Head: React_3.ForwardRefExoticComponent< + React_3.ThHTMLAttributes & + React_3.RefAttributes + >; + Row: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes + >; + Cell: React_3.ForwardRefExoticComponent< + React_3.TdHTMLAttributes & + React_3.RefAttributes + >; + Caption: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes + >; +}; // @public (undocumented) const Text_2: React_2.ForwardRefExoticComponent< diff --git a/packages/canon/src/components/DataTable/DataTable.stories.tsx b/packages/canon/src/components/DataTable/DataTable.stories.tsx new file mode 100644 index 0000000000..46bc81d08c --- /dev/null +++ b/packages/canon/src/components/DataTable/DataTable.stories.tsx @@ -0,0 +1,113 @@ +/* + * Copyright 2024 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Table } from '../Table'; +import { DataTable } from '.'; +import { components } from './mocked-components'; +import { columns } from './mocked-columns'; +import { + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table'; + +const meta = { + title: 'Components/DataTable', +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => { + const table = useReactTable({ + data: components, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + }); + + return ( + + + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + 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. + + + )} + + + table.previousPage()} + onClickNext={() => table.nextPage()} + canPrevious={table.getCanPreviousPage()} + canNext={table.getCanNextPage()} + setPageSize={pageSize => table.setPageSize(pageSize)} + /> + + ); + }, +}; diff --git a/packages/canon/src/components/DataTable/index.ts b/packages/canon/src/components/DataTable/index.ts index dc377403a8..688df19b90 100644 --- a/packages/canon/src/components/DataTable/index.ts +++ b/packages/canon/src/components/DataTable/index.ts @@ -17,6 +17,10 @@ import { DataTableRoot } from './Root/DataTableRoot'; import { DataTablePagination } from './Pagination/DataTablePagination'; +/** + * DataTable component for displaying tabular data with pagination + * @public + */ export const DataTable = { Root: DataTableRoot, Pagination: DataTablePagination, diff --git a/packages/canon/src/components/Table/mocked-data/columns.tsx b/packages/canon/src/components/DataTable/mocked-columns.tsx similarity index 94% rename from packages/canon/src/components/Table/mocked-data/columns.tsx rename to packages/canon/src/components/DataTable/mocked-columns.tsx index 3ef63c59bb..0c730af3ab 100644 --- a/packages/canon/src/components/Table/mocked-data/columns.tsx +++ b/packages/canon/src/components/DataTable/mocked-columns.tsx @@ -15,9 +15,9 @@ */ import React from 'react'; import { ColumnDef } from '@tanstack/react-table'; -import { Component } from './components'; -import { Checkbox } from '../../Checkbox'; -import { Text } from '../../Text'; +import { Component } from './mocked-components'; +import { Checkbox } from '../Checkbox'; +import { Text } from '../Text'; export const columns: ColumnDef[] = [ { diff --git a/packages/canon/src/components/Table/mocked-data/components.ts b/packages/canon/src/components/DataTable/mocked-components.ts similarity index 100% rename from packages/canon/src/components/Table/mocked-data/components.ts rename to packages/canon/src/components/DataTable/mocked-components.ts diff --git a/packages/canon/src/components/Table/Table.stories.tsx b/packages/canon/src/components/Table/Table.stories.tsx index 6dcdf748a1..ff1993235a 100644 --- a/packages/canon/src/components/Table/Table.stories.tsx +++ b/packages/canon/src/components/Table/Table.stories.tsx @@ -17,20 +17,51 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Table } from '../Table'; -import { components } from './mocked-data/components'; -import { - // ColumnFiltersState, - // SortingState, - // VisibilityState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from '@tanstack/react-table'; -import { columns } from './mocked-data/columns'; -import { TablePagination } from '../TablePagination'; + +const invoices = [ + { + invoice: 'INV001', + paymentStatus: 'Paid', + totalAmount: '$250.00', + paymentMethod: 'Credit Card', + }, + { + invoice: 'INV002', + paymentStatus: 'Pending', + totalAmount: '$150.00', + paymentMethod: 'PayPal', + }, + { + invoice: 'INV003', + paymentStatus: 'Unpaid', + totalAmount: '$350.00', + paymentMethod: 'Bank Transfer', + }, + { + invoice: 'INV004', + paymentStatus: 'Paid', + totalAmount: '$450.00', + paymentMethod: 'Credit Card', + }, + { + invoice: 'INV005', + paymentStatus: 'Paid', + totalAmount: '$550.00', + paymentMethod: 'PayPal', + }, + { + invoice: 'INV006', + paymentStatus: 'Pending', + totalAmount: '$200.00', + paymentMethod: 'Bank Transfer', + }, + { + invoice: 'INV007', + paymentStatus: 'Unpaid', + totalAmount: '$300.00', + paymentMethod: 'Credit Card', + }, +]; const meta = { title: 'Components/Table', @@ -38,7 +69,6 @@ const meta = { subcomponents: { Body: Table.Body as React.ComponentType, Cell: Table.Cell as React.ComponentType, - Pagination: TablePagination as React.ComponentType, Head: Table.Head as React.ComponentType, Header: Table.Header as React.ComponentType, Row: Table.Row as React.ComponentType, @@ -49,87 +79,28 @@ export default meta; type Story = StoryObj; export const Default: Story = { - render: () => { - const table = useReactTable({ - data: components, - columns, - // onSortingChange: setSorting, - // onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - // onColumnVisibilityChange: setColumnVisibility, - // onRowSelectionChange: setRowSelection, - // state: { - // sorting, - // columnFilters, - // columnVisibility, - // rowSelection, - // }, - }); - - return ( - <> - - - {table.getHeaderGroups().map(headerGroup => ( - - {headerGroup.headers.map(header => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - 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. - - - )} - - - table.previousPage()} - onClickNext={() => table.nextPage()} - canPrevious={table.getCanPreviousPage()} - canNext={table.getCanNextPage()} - setPageSize={pageSize => table.setPageSize(pageSize)} - /> - - ); - }, + render: () => ( + + + + Invoice + Status + Method + Amount + + + + {invoices.map(invoice => ( + + {invoice.invoice} + {invoice.paymentStatus} + {invoice.paymentMethod} + + {invoice.totalAmount} + + + ))} + + + ), }; diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx index f67f74883d..99fb181e3d 100644 --- a/packages/canon/src/components/Table/Table.tsx +++ b/packages/canon/src/components/Table/Table.tsx @@ -15,7 +15,6 @@ */ import * as React from 'react'; -/** @public */ const TableRoot = React.forwardRef< HTMLTableElement, React.HTMLAttributes @@ -26,7 +25,6 @@ const TableRoot = React.forwardRef< )); TableRoot.displayName = 'TableRoot'; -/** @public */ const TableHeader = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes @@ -39,7 +37,6 @@ const TableHeader = React.forwardRef< )); TableHeader.displayName = 'TableHeader'; -/** @public */ const TableBody = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes @@ -48,7 +45,6 @@ const TableBody = React.forwardRef< )); TableBody.displayName = 'TableBody'; -/** @public */ const TableRow = React.forwardRef< HTMLTableRowElement, React.HTMLAttributes @@ -59,7 +55,6 @@ const TableRow = React.forwardRef< )); TableRow.displayName = 'TableRow'; -/** @public */ const TableHead = React.forwardRef< HTMLTableCellElement, React.ThHTMLAttributes @@ -68,7 +63,6 @@ const TableHead = React.forwardRef< )); TableHead.displayName = 'TableHead'; -/** @public */ const TableCell = React.forwardRef< HTMLTableCellElement, React.TdHTMLAttributes @@ -77,7 +71,6 @@ const TableCell = React.forwardRef< )); TableCell.displayName = 'TableCell'; -/** @public */ const TableCaption = React.forwardRef< HTMLTableCaptionElement, React.HTMLAttributes @@ -90,6 +83,10 @@ const TableCaption = React.forwardRef< )); TableCaption.displayName = 'TableCaption'; +/** + * Table component for displaying tabular data + * @public + */ export const Table = { Root: TableRoot, Header: TableHeader, diff --git a/packages/canon/src/components/Table/index.ts b/packages/canon/src/components/Table/index.ts index 1b13d8b85e..4929b2d36a 100644 --- a/packages/canon/src/components/Table/index.ts +++ b/packages/canon/src/components/Table/index.ts @@ -15,4 +15,3 @@ */ export * from './Table'; -export * from './types'; diff --git a/packages/canon/src/components/Table/types.ts b/packages/canon/src/components/Table/types.ts deleted file mode 100644 index 79628de2bd..0000000000 --- a/packages/canon/src/components/Table/types.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export interface TablePaginationProps - extends React.HTMLAttributes { - /** - * The current page index. - */ - pageIndex: number; - /** - * The current page size. - */ - pageSize: number; - /** - * The total number of rows. - */ - totalRows: number; - /** - * The function to call when the previous button is clicked. - */ - onClickPrevious: () => void; - /** - * The function to call when the next button is clicked. - */ - onClickNext: () => void; - /** - * Whether the previous button is disabled. - */ - canPrevious: boolean; - /** - * Whether the next button is disabled. - */ - canNext: boolean; - /** - * The function to call when the page size is changed. - */ - setPageSize: (pageSize: number) => void; -}