From d1887280d99823a55be887d635c1c4b2a9b89785 Mon Sep 17 00:00:00 2001 From: patroswastik Date: Thu, 27 Feb 2025 16:19:31 -0600 Subject: [PATCH 01/26] add specific check for @deprecated tag in router files Signed-off-by: patroswastik --- .../lint-legacy-backend-exports.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts index 6025defe31..0ebc7088e3 100644 --- a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts +++ b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts @@ -46,10 +46,15 @@ function verifyIndex(pkg: string, packageJson?: BackstagePackageJson) { console.log(`Verifying ${pkg}`); const tsPath = path.join(pkg, 'src/index.ts'); const sourceFile = project.getSourceFile(tsPath); + + const tsRouterPath = path.join(pkg, 'src/service/router.ts'); + const routerFile = project.getSourceFile(tsRouterPath); + if (!sourceFile) { console.log(`Could not find ${tsPath}`); process.exit(1); } + const symbols = sourceFile?.getExportSymbols(); const exportCount = symbols?.length || 0; @@ -75,9 +80,23 @@ function verifyIndex(pkg: string, packageJson?: BackstagePackageJson) { .find(tag => tag.getName() === 'deprecated'); } + let routerCreateRouterDeprecated = undefined; + if (routerFile) { + const routerSymbols = routerFile?.getExportSymbols(); + const routerCreateRouterExport = routerSymbols?.find( + symbol => symbol.getName() === 'createRouter', + ); + + if (routerCreateRouterExport) { + routerCreateRouterDeprecated = routerCreateRouterExport + .getJsDocTags() + .find(tag => tag.getName() === 'deprecated'); + } + } + if (createRouterExport) { console.log(' ❌ createRouter is exported'); - if (!createRouterDeprecated) + if (!createRouterDeprecated && !routerCreateRouterDeprecated) console.log(' ❌ createRouter is NOT deprecated'); } From 18ce51c5b6d88720d131dbdbb022ce6bec4506cb Mon Sep 17 00:00:00 2001 From: patroswastik Date: Thu, 27 Feb 2025 17:20:24 -0600 Subject: [PATCH 02/26] Changeset added as per guide Signed-off-by: patroswastik --- .changeset/rich-phones-whisper.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rich-phones-whisper.md diff --git a/.changeset/rich-phones-whisper.md b/.changeset/rich-phones-whisper.md new file mode 100644 index 0000000000..c27b6de2f8 --- /dev/null +++ b/.changeset/rich-phones-whisper.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': minor +--- + +Checking through router.ts files of the packages if they exist and looking for deprecated tag inside it. If exists then only the message will appear From 68b49e34330132daf44f1aeb97b4bb7deba349f4 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 4 Apr 2025 08:02:41 +0100 Subject: [PATCH 03/26] First pass at pagination Signed-off-by: Charles de Dreuille --- packages/canon/package.json | 1 + .../src/components/DataTable/DataTable.tsx | 20 + .../canon/src/components/DataTable/index.ts | 17 + .../src/components/Table/Table.stories.tsx | 184 ++-- packages/canon/src/components/Table/Table.tsx | 34 +- packages/canon/src/components/Table/index.ts | 12 +- .../components/Table/mocked-data/columns.tsx | 71 ++ .../Table/mocked-data/components.ts | 818 ++++++++++++++++++ .../canon/src/components/Table/styles.css | 10 + packages/canon/src/components/Table/types.ts | 50 ++ .../TablePagination/TablePagination.tsx | 81 ++ .../src/components/TablePagination/index.ts | 18 + .../src/components/TablePagination/types.ts | 50 ++ yarn.lock | 20 + 14 files changed, 1265 insertions(+), 121 deletions(-) create mode 100644 packages/canon/src/components/DataTable/DataTable.tsx create mode 100644 packages/canon/src/components/DataTable/index.ts create mode 100644 packages/canon/src/components/Table/mocked-data/columns.tsx create mode 100644 packages/canon/src/components/Table/mocked-data/components.ts create mode 100644 packages/canon/src/components/Table/types.ts create mode 100644 packages/canon/src/components/TablePagination/TablePagination.tsx create mode 100644 packages/canon/src/components/TablePagination/index.ts create mode 100644 packages/canon/src/components/TablePagination/types.ts diff --git a/packages/canon/package.json b/packages/canon/package.json index b5d2d715f6..fc47bd89d4 100644 --- a/packages/canon/package.json +++ b/packages/canon/package.json @@ -56,6 +56,7 @@ "@storybook/react": "^8.6.8", "@storybook/react-webpack5": "^8.6.8", "@storybook/test": "^8.6.8", + "@tanstack/react-table": "^8.21.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "chalk": "^5.4.1", diff --git a/packages/canon/src/components/DataTable/DataTable.tsx b/packages/canon/src/components/DataTable/DataTable.tsx new file mode 100644 index 0000000000..335e4d73e4 --- /dev/null +++ b/packages/canon/src/components/DataTable/DataTable.tsx @@ -0,0 +1,20 @@ +/* + * 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. + */ +import React from 'react'; + +export const DataTable = () => { + return
DataTable
; +}; diff --git a/packages/canon/src/components/DataTable/index.ts b/packages/canon/src/components/DataTable/index.ts new file mode 100644 index 0000000000..cbbb2babe5 --- /dev/null +++ b/packages/canon/src/components/DataTable/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './DataTable'; diff --git a/packages/canon/src/components/Table/Table.stories.tsx b/packages/canon/src/components/Table/Table.stories.tsx index c4c08be527..8c94249a79 100644 --- a/packages/canon/src/components/Table/Table.stories.tsx +++ b/packages/canon/src/components/Table/Table.stories.tsx @@ -14,73 +14,34 @@ * limitations under the License. */ -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', - }, -]; - import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; +import { Table } from '../Table'; +import { components } from './mocked-data/components'; import { - Table, - TableBody, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, -} from '../Table'; + // ColumnFiltersState, + // SortingState, + // VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table'; +import { columns } from './mocked-data/columns'; +import { TablePagination } from '../TablePagination'; const meta = { title: 'Components/Table', - component: Table, + component: Table.Root, subcomponents: { - TableBody: TableBody as React.ComponentType, - TableCell: TableCell as React.ComponentType, - TableFooter: TableFooter as React.ComponentType, - TableHead: TableHead as React.ComponentType, - TableHeader: TableHeader as React.ComponentType, - TableRow: TableRow as React.ComponentType, + 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, }, } satisfies Meta; @@ -88,32 +49,79 @@ export default meta; type Story = StoryObj; export const Default: Story = { - render: () => ( - - - - Invoice - Status - Method - Amount - - - - {invoices.map(invoice => ( - - {invoice.invoice} - {invoice.paymentStatus} - {invoice.paymentMethod} - {invoice.totalAmount} - - ))} - - - - Total - $2,500.00 - - -
- ), + 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)} + /> + + ); + }, }; diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx index efd5181036..f67f74883d 100644 --- a/packages/canon/src/components/Table/Table.tsx +++ b/packages/canon/src/components/Table/Table.tsx @@ -16,7 +16,7 @@ import * as React from 'react'; /** @public */ -const Table = React.forwardRef< +const TableRoot = React.forwardRef< HTMLTableElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( @@ -24,7 +24,7 @@ const Table = React.forwardRef< )); -Table.displayName = 'Table'; +TableRoot.displayName = 'TableRoot'; /** @public */ const TableHeader = React.forwardRef< @@ -48,19 +48,6 @@ const TableBody = React.forwardRef< )); TableBody.displayName = 'TableBody'; -/** @public */ -const TableFooter = React.forwardRef< - HTMLTableSectionElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( - -)); -TableFooter.displayName = 'TableFooter'; - /** @public */ const TableRow = React.forwardRef< HTMLTableRowElement, @@ -103,13 +90,12 @@ const TableCaption = React.forwardRef< )); TableCaption.displayName = 'TableCaption'; -export { - Table, - TableHeader, - TableBody, - TableFooter, - TableHead, - TableRow, - TableCell, - TableCaption, +export const Table = { + Root: TableRoot, + Header: TableHeader, + Body: TableBody, + Head: TableHead, + Row: TableRow, + Cell: TableCell, + Caption: TableCaption, }; diff --git a/packages/canon/src/components/Table/index.ts b/packages/canon/src/components/Table/index.ts index cf88de2b1a..1b13d8b85e 100644 --- a/packages/canon/src/components/Table/index.ts +++ b/packages/canon/src/components/Table/index.ts @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { - Table, - TableHead, - TableRow, - TableHeader, - TableCell, - TableBody, - TableFooter, -} from './Table'; + +export * from './Table'; +export * from './types'; diff --git a/packages/canon/src/components/Table/mocked-data/columns.tsx b/packages/canon/src/components/Table/mocked-data/columns.tsx new file mode 100644 index 0000000000..3ef63c59bb --- /dev/null +++ b/packages/canon/src/components/Table/mocked-data/columns.tsx @@ -0,0 +1,71 @@ +/* + * 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. + */ +import React from 'react'; +import { ColumnDef } from '@tanstack/react-table'; +import { Component } from './components'; +import { Checkbox } from '../../Checkbox'; +import { Text } from '../../Text'; + +export const columns: ColumnDef[] = [ + { + id: 'select', + header: ({ table }) => ( + + table.toggleAllPageRowsSelected(checked) + } + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(checked)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: 'name', + header: 'Name', + cell: ({ row }) => ( +
+ {row.getValue('name')} + + {row.original.description} + +
+ ), + }, + { + accessorKey: 'owner', + header: 'Owner', + cell: ({ row }) => {row.getValue('owner')}, + }, + { + accessorKey: 'type', + header: 'Type', + cell: ({ row }) => {row.getValue('type')}, + }, + { + accessorKey: 'tags', + header: 'Tags', + cell: ({ row }) => {row.getValue('tags')}, + }, +]; diff --git a/packages/canon/src/components/Table/mocked-data/components.ts b/packages/canon/src/components/Table/mocked-data/components.ts new file mode 100644 index 0000000000..f7861023d3 --- /dev/null +++ b/packages/canon/src/components/Table/mocked-data/components.ts @@ -0,0 +1,818 @@ +/* + * 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 Component { + name: string; + owner: string; + type: 'documentation' | 'library' | 'service' | 'website' | 'other'; + description?: string; + tags?: string[]; +} + +export const components: Component[] = [ + { + name: 'authentication-and-authorization-service', + owner: 'security-team', + type: 'service', + description: + 'A comprehensive service handling user authentication and role-based access control across all applications.', + tags: ['security', 'authentication', 'authorization'], + }, + { + name: 'user-interface-dashboard-and-analytics-platform', + owner: 'frontend-team', + type: 'website', + description: + 'Interactive dashboard providing real-time analytics and data visualization for business metrics.', + tags: ['analytics', 'visualization', 'dashboard'], + }, + { + name: 'payment-gateway', + owner: 'finance-team', + type: 'service', + description: + 'Secure payment processing system supporting multiple payment methods and currencies.', + tags: ['payments', 'security', 'finance'], + }, + { + name: 'real-time-analytics-processing-and-visualization-engine', + owner: 'data-team', + type: 'service', + description: + 'High-performance engine for processing and visualizing streaming data analytics.', + tags: ['analytics', 'real-time', 'data-processing'], + }, + { + name: 'notification-center', + owner: 'platform-team', + type: 'service', + description: + 'Centralized system for managing and delivering notifications across multiple channels.', + tags: ['notifications', 'messaging'], + }, + { + name: 'administrative-control-panel-and-user-management-interface', + owner: 'frontend-team', + type: 'website', + description: + 'Admin interface for managing users, permissions, and system configurations.', + tags: ['admin', 'user-management', 'configuration'], + }, + { + name: 'search-indexer', + owner: 'search-team', + type: 'service', + description: + 'Service responsible for indexing and updating searchable content across the platform.', + tags: ['search', 'indexing'], + }, + { + name: 'cross-platform-mobile-application-framework', + owner: 'mobile-team', + type: 'website', + description: + 'Framework enabling development of cross-platform mobile applications with shared codebase.', + tags: ['mobile', 'framework', 'cross-platform'], + }, + { + name: 'database-migration', + owner: 'devops-team', + type: 'other', + description: + 'Tools and scripts for managing database schema migrations and data transformations.', + tags: ['database', 'migration', 'devops'], + }, + { + name: 'api-gateway', + owner: 'platform-team', + type: 'service', + description: + 'Central entry point for all API requests, handling routing, authentication, and rate limiting.', + tags: ['api', 'gateway', 'security', 'routing'], + }, + { + name: 'content-management', + owner: 'content-team', + type: 'service', + description: + 'System for managing and delivering digital content across multiple channels.', + tags: ['content', 'management', 'delivery'], + }, + { + name: 'enterprise-reporting-and-analytics-dashboard', + owner: 'analytics-team', + type: 'website', + description: + 'Comprehensive business intelligence platform for enterprise-wide reporting and analytics.', + tags: ['analytics', 'reporting', 'business-intelligence'], + }, + { + name: 'image-processing-and-optimization-service', + owner: 'media-team', + type: 'service', + description: + 'Service for processing, optimizing, and delivering images across different devices and networks.', + tags: ['media', 'optimization', 'processing'], + }, + { + name: 'customer-portal', + owner: 'frontend-team', + type: 'website', + description: + 'Self-service portal for customers to manage their accounts and access services.', + tags: ['customer', 'self-service'], + }, + { + name: 'log-aggregator', + owner: 'devops-team', + type: 'service', + description: + 'Centralized logging system for collecting, processing, and analyzing application logs.', + tags: ['logging', 'monitoring', 'devops'], + }, + { + name: 'identity-provider', + owner: 'security-team', + type: 'service', + description: + 'Service managing user identities and authentication across the organization.', + tags: ['identity', 'security', 'authentication'], + }, + { + name: 'document-storage', + owner: 'storage-team', + type: 'service', + description: + 'Secure and scalable document storage system with version control and access management.', + tags: ['storage', 'documents', 'version-control'], + }, + { + name: 'workflow-engine', + owner: 'platform-team', + type: 'service', + description: + 'Engine for defining and executing business processes and workflows.', + tags: ['workflow', 'automation'], + }, + { + name: 'mobile-backend', + owner: 'mobile-team', + type: 'service', + description: + 'Backend services supporting mobile applications with optimized APIs and data synchronization.', + tags: ['mobile', 'backend', 'api'], + }, + { + name: 'system-monitoring-and-alerting-dashboard', + owner: 'devops-team', + type: 'website', + description: + 'Real-time monitoring and alerting system for infrastructure and application health.', + tags: ['monitoring', 'alerting', 'devops', 'infrastructure'], + }, + { + name: 'email-service', + owner: 'communication-team', + type: 'service', + description: + 'Reliable email delivery service with templates and tracking capabilities.', + tags: ['email', 'communication'], + }, + { + name: 'data-pipeline', + owner: 'data-team', + type: 'service', + description: + 'ETL pipeline for processing and transforming large volumes of data.', + tags: ['data', 'etl', 'pipeline'], + }, + { + name: 'configuration-manager', + owner: 'platform-team', + type: 'service', + description: + 'Centralized system for managing application configurations across environments.', + tags: ['configuration', 'management'], + }, + { + name: 'testing-framework', + owner: 'qa-team', + type: 'library', + description: + 'Comprehensive testing framework supporting various types of automated tests.', + tags: ['testing', 'automation', 'qa'], + }, + { + name: 'cache-service', + owner: 'platform-team', + type: 'service', + description: + 'Distributed caching service for improving application performance.', + tags: ['caching', 'performance'], + }, + { + name: 'billing-system', + owner: 'finance-team', + type: 'service', + description: + 'System for managing customer billing, invoicing, and payment processing.', + tags: ['billing', 'finance', 'payments'], + }, + { + name: 'comprehensive-product-documentation-and-api-reference', + owner: 'docs-team', + type: 'documentation', + description: + 'Complete documentation covering product features, APIs, and integration guides.', + tags: ['documentation', 'api', 'reference'], + }, + { + name: 'queue-manager', + owner: 'platform-team', + type: 'service', + description: + 'Message queue system for asynchronous processing and event handling.', + tags: ['queue', 'messaging', 'async'], + }, + { + name: 'security-scanner', + owner: 'security-team', + type: 'other', + description: + 'Automated security scanning tool for identifying vulnerabilities in code and infrastructure.', + tags: ['security', 'scanning', 'vulnerability'], + }, + { + name: 'user-profile', + owner: 'frontend-team', + type: 'website', + description: + 'User profile management interface with personalization features.', + tags: ['user', 'profile', 'personalization'], + }, + { + name: 'data-warehouse', + owner: 'data-team', + type: 'service', + description: + 'Centralized data repository for business intelligence and analytics.', + tags: ['data', 'warehouse', 'analytics'], + }, + { + name: 'deployment-automation', + owner: 'devops-team', + type: 'other', + description: + 'Automated deployment pipeline for continuous integration and delivery.', + tags: ['deployment', 'automation', 'ci-cd', 'devops'], + }, + { + name: 'chat-service', + owner: 'communication-team', + type: 'service', + description: + 'Real-time chat service supporting text, file sharing, and group conversations.', + tags: ['chat', 'communication', 'real-time'], + }, + { + name: 'analytics-dashboard', + owner: 'analytics-team', + type: 'website', + description: + 'Interactive dashboard for visualizing and analyzing business metrics.', + tags: ['analytics', 'dashboard', 'visualization'], + }, + { + name: 'file-uploader', + owner: 'storage-team', + type: 'service', + description: + 'Service for handling secure file uploads with progress tracking and validation.', + tags: ['storage', 'upload', 'files'], + }, + { + name: 'search-service', + owner: 'search-team', + type: 'service', + description: + 'Full-text search service with advanced filtering and ranking capabilities.', + tags: ['search', 'full-text'], + }, + { + name: 'mobile-sdk', + owner: 'mobile-team', + type: 'library', + description: + 'Software development kit for building mobile applications with native features.', + tags: ['mobile', 'sdk', 'development'], + }, + { + name: 'performance-monitor', + owner: 'devops-team', + type: 'service', + description: + 'System for monitoring and analyzing application performance metrics.', + tags: ['performance', 'monitoring', 'metrics'], + }, + { + name: 'content-delivery', + owner: 'media-team', + type: 'service', + description: + 'CDN service for optimized content delivery across global networks.', + tags: ['cdn', 'content', 'delivery'], + }, + { + name: 'user-authentication', + owner: 'security-team', + type: 'service', + description: + 'Service handling user login, session management, and authentication flows.', + tags: ['authentication', 'security', 'user'], + }, + { + name: 'data-export', + owner: 'data-team', + type: 'service', + description: + 'Service for exporting data in various formats with scheduling capabilities.', + tags: ['data', 'export', 'scheduling'], + }, + { + name: 'admin-api', + owner: 'platform-team', + type: 'service', + description: + 'API endpoints for administrative functions and system management.', + tags: ['api', 'admin', 'management'], + }, + { + name: 'testing-dashboard', + owner: 'qa-team', + type: 'website', + description: 'Dashboard for monitoring test results and quality metrics.', + tags: ['testing', 'dashboard', 'qa'], + }, + { + name: 'message-broker', + owner: 'platform-team', + type: 'service', + description: + 'Message broker service for reliable event-driven communication between services.', + tags: ['messaging', 'broker', 'event-driven'], + }, + { + name: 'payment-processor', + owner: 'finance-team', + type: 'service', + description: + 'Service for processing financial transactions and payment methods.', + tags: ['payments', 'finance', 'processing'], + }, + { + name: 'document-viewer', + owner: 'frontend-team', + type: 'website', + description: 'Web-based document viewer supporting multiple file formats.', + tags: ['documents', 'viewer'], + }, + { + name: 'load-balancer', + owner: 'devops-team', + type: 'service', + description: + 'Service for distributing network traffic across multiple servers.', + tags: ['load-balancing', 'networking', 'infrastructure'], + }, + { + name: 'security-audit', + owner: 'security-team', + type: 'other', + description: + 'Tools and processes for conducting security audits and compliance checks.', + tags: ['security', 'audit', 'compliance'], + }, + { + name: 'user-settings', + owner: 'frontend-team', + type: 'website', + description: + 'Interface for users to manage their preferences and account settings.', + tags: ['user', 'settings', 'preferences'], + }, + { + name: 'data-import', + owner: 'data-team', + type: 'service', + description: + 'Service for importing and validating data from external sources.', + tags: ['data', 'import', 'validation'], + }, + { + name: 'infrastructure-monitor', + owner: 'devops-team', + type: 'service', + description: + 'Monitoring system for infrastructure components and resources.', + tags: ['monitoring', 'infrastructure', 'devops'], + }, + { + name: 'notification-manager', + owner: 'communication-team', + type: 'service', + description: + 'Service for managing and delivering notifications across multiple channels.', + tags: ['notifications', 'management'], + }, + { + name: 'analytics-processor', + owner: 'analytics-team', + type: 'service', + description: + 'Service for processing and analyzing business data and metrics.', + tags: ['analytics', 'processing', 'metrics'], + }, + { + name: 'file-manager', + owner: 'storage-team', + type: 'website', + description: 'Web interface for managing files and storage resources.', + tags: ['files', 'storage', 'management'], + }, + { + name: 'search-index', + owner: 'search-team', + type: 'service', + description: 'Service for maintaining and updating search indices.', + tags: ['search', 'indexing'], + }, + { + name: 'mobile-authentication', + owner: 'mobile-team', + type: 'service', + description: + 'Authentication service specifically designed for mobile applications.', + tags: ['mobile', 'authentication', 'security'], + }, + { + name: 'system-monitor', + owner: 'devops-team', + type: 'service', + description: + 'Monitoring service for system health and performance metrics.', + tags: ['monitoring', 'system', 'metrics'], + }, + { + name: 'media-processor', + owner: 'media-team', + type: 'service', + description: 'Service for processing and optimizing media files.', + tags: ['media', 'processing', 'optimization'], + }, + { + name: 'user-management', + owner: 'security-team', + type: 'service', + description: 'Service for managing user accounts and permissions.', + tags: ['user', 'management', 'security'], + }, + { + name: 'data-transformer', + owner: 'data-team', + type: 'service', + description: + 'Service for transforming data between different formats and structures.', + tags: ['data', 'transformation'], + }, + { + name: 'admin-dashboard', + owner: 'platform-team', + type: 'website', + description: + 'Administrative interface for system management and monitoring.', + tags: ['admin', 'dashboard', 'management'], + }, + { + name: 'test-automation', + owner: 'qa-team', + type: 'other', + description: 'Tools and frameworks for automating testing processes.', + tags: ['testing', 'automation', 'qa'], + }, + { + name: 'event-bus', + owner: 'platform-team', + type: 'service', + description: 'Event-driven communication system between services.', + tags: ['events', 'messaging', 'communication'], + }, + { + name: 'invoice-generator', + owner: 'finance-team', + type: 'service', + description: 'Service for generating and managing invoices.', + tags: ['invoices', 'finance'], + }, + { + name: 'document-editor', + owner: 'frontend-team', + type: 'website', + description: 'Web-based document editing interface.', + tags: ['documents', 'editor'], + }, + { + name: 'service-discovery', + owner: 'devops-team', + type: 'service', + description: 'Service for discovering and registering available services.', + tags: ['discovery', 'services', 'devops'], + }, + { + name: 'security-monitor', + owner: 'security-team', + type: 'service', + description: 'Service for monitoring security events and threats.', + tags: ['security', 'monitoring', 'threats'], + }, + { + name: 'user-preferences', + owner: 'frontend-team', + type: 'website', + description: 'Interface for managing user preferences and settings.', + tags: ['user', 'preferences'], + }, + { + name: 'data-validator', + owner: 'data-team', + type: 'service', + description: 'Service for validating data integrity and format.', + tags: ['data', 'validation'], + }, + { + name: 'infrastructure-automation', + owner: 'devops-team', + type: 'other', + description: + 'Tools for automating infrastructure provisioning and management.', + tags: ['infrastructure', 'automation', 'devops'], + }, + { + name: 'notification-dispatcher', + owner: 'communication-team', + type: 'service', + description: + 'Service for dispatching notifications to appropriate channels.', + tags: ['notifications', 'dispatch'], + }, + { + name: 'analytics-collector', + owner: 'analytics-team', + type: 'service', + description: 'Service for collecting and aggregating analytics data.', + tags: ['analytics', 'collection', 'aggregation'], + }, + { + name: 'file-processor', + owner: 'storage-team', + type: 'service', + description: 'Service for processing and managing files.', + tags: ['files', 'processing'], + }, + { + name: 'search-analyzer', + owner: 'search-team', + type: 'service', + description: 'Service for analyzing search queries and results.', + tags: ['search', 'analysis'], + }, + { + name: 'mobile-notifications', + owner: 'mobile-team', + type: 'service', + description: 'Service for sending notifications to mobile devices.', + tags: ['mobile', 'notifications'], + }, + { + name: 'system-alerts', + owner: 'devops-team', + type: 'service', + description: 'Service for managing and dispatching system alerts.', + tags: ['alerts', 'system', 'monitoring'], + }, + { + name: 'media-encoder', + owner: 'media-team', + type: 'service', + description: 'Service for encoding and processing media files.', + tags: ['media', 'encoding'], + }, + { + name: 'user-authorization', + owner: 'security-team', + type: 'service', + description: 'Service for managing user permissions and access control.', + tags: ['authorization', 'security', 'user'], + }, + { + name: 'data-aggregator', + owner: 'data-team', + type: 'service', + description: 'Service for aggregating data from multiple sources.', + tags: ['data', 'aggregation'], + }, + { + name: 'admin-authentication', + owner: 'platform-team', + type: 'service', + description: 'Authentication service for administrative access.', + tags: ['admin', 'authentication', 'security'], + }, + { + name: 'test-coverage', + owner: 'qa-team', + type: 'other', + description: 'Tools for measuring and reporting test coverage.', + tags: ['testing', 'coverage', 'qa'], + }, + { + name: 'event-processor', + owner: 'platform-team', + type: 'service', + description: 'Service for processing and handling events.', + tags: ['events', 'processing'], + }, + { + name: 'payment-validator', + owner: 'finance-team', + type: 'service', + description: 'Service for validating payment transactions.', + tags: ['payments', 'validation', 'finance'], + }, + { + name: 'document-converter', + owner: 'frontend-team', + type: 'service', + description: 'Service for converting documents between different formats.', + tags: ['documents', 'conversion'], + }, + { + name: 'service-health', + owner: 'devops-team', + type: 'service', + description: 'Service for monitoring and reporting service health status.', + tags: ['health', 'monitoring', 'services'], + }, + { + name: 'security-logger', + owner: 'security-team', + type: 'service', + description: 'Service for logging security-related events and activities.', + tags: ['security', 'logging'], + }, + { + name: 'user-analytics', + owner: 'frontend-team', + type: 'website', + description: + 'Analytics dashboard for user behavior and engagement metrics.', + tags: ['analytics', 'user', 'metrics'], + }, + { + name: 'data-cleaner', + owner: 'data-team', + type: 'service', + description: 'Service for cleaning and standardizing data.', + tags: ['data', 'cleaning'], + }, + { + name: 'infrastructure-deployer', + owner: 'devops-team', + type: 'other', + description: 'Tools for deploying and managing infrastructure resources.', + tags: ['infrastructure', 'deployment', 'devops'], + }, + { + name: 'notification-queue', + owner: 'communication-team', + type: 'service', + description: 'Queue system for managing notification delivery.', + tags: ['notifications', 'queue'], + }, + { + name: 'analytics-exporter', + owner: 'analytics-team', + type: 'service', + description: 'Service for exporting analytics data in various formats.', + tags: ['analytics', 'export'], + }, + { + name: 'file-validator', + owner: 'storage-team', + type: 'service', + description: 'Service for validating file integrity and format.', + tags: ['files', 'validation'], + }, + { + name: 'search-optimizer', + owner: 'search-team', + type: 'service', + description: 'Service for optimizing search performance and relevance.', + tags: ['search', 'optimization'], + }, + { + name: 'mobile-analytics', + owner: 'mobile-team', + type: 'service', + description: 'Analytics service specifically for mobile applications.', + tags: ['mobile', 'analytics'], + }, + { + name: 'system-logger', + owner: 'devops-team', + type: 'service', + description: 'Service for logging system events and activities.', + tags: ['logging', 'system'], + }, + { + name: 'media-validator', + owner: 'media-team', + type: 'service', + description: 'Service for validating media files and formats.', + tags: ['media', 'validation'], + }, + { + name: 'user-audit', + owner: 'security-team', + type: 'service', + description: 'Service for auditing user activities and access.', + tags: ['audit', 'user', 'security'], + }, + { + name: 'data-normalizer', + owner: 'data-team', + type: 'service', + description: 'Service for normalizing data formats and structures.', + tags: ['data', 'normalization'], + }, + { + name: 'admin-authorization', + owner: 'platform-team', + type: 'service', + description: 'Authorization service for administrative functions.', + tags: ['admin', 'authorization', 'security'], + }, + { + name: 'test-reporting', + owner: 'qa-team', + type: 'other', + description: 'Tools for generating and managing test reports.', + tags: ['testing', 'reporting', 'qa'], + }, + { + name: 'event-aggregator', + owner: 'platform-team', + type: 'service', + description: 'Service for aggregating and processing events.', + tags: ['events', 'aggregation'], + }, + { + name: 'payment-reconciler', + owner: 'finance-team', + type: 'service', + description: 'Service for reconciling payment transactions.', + tags: ['payments', 'reconciliation', 'finance'], + }, + { + name: 'document-validator', + owner: 'frontend-team', + type: 'service', + description: 'Service for validating document formats and content.', + tags: ['documents', 'validation'], + }, + { + name: 'service-monitor', + owner: 'devops-team', + type: 'service', + description: 'Service for monitoring service health and performance.', + tags: ['monitoring', 'services', 'health'], + }, + { + name: 'security-validator', + owner: 'security-team', + type: 'service', + description: 'Service for validating security configurations and policies.', + tags: ['security', 'validation'], + }, +]; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css index 7d3cb35e3d..93a7de3259 100644 --- a/packages/canon/src/components/Table/styles.css +++ b/packages/canon/src/components/Table/styles.css @@ -59,3 +59,13 @@ box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1); } + +.canon-TablePagination { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--canon-space-3); + background-color: var(--canon-bg-surface-1); + border-top: 1px solid var(--canon-border); +} diff --git a/packages/canon/src/components/Table/types.ts b/packages/canon/src/components/Table/types.ts new file mode 100644 index 0000000000..79628de2bd --- /dev/null +++ b/packages/canon/src/components/Table/types.ts @@ -0,0 +1,50 @@ +/* + * 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; +} diff --git a/packages/canon/src/components/TablePagination/TablePagination.tsx b/packages/canon/src/components/TablePagination/TablePagination.tsx new file mode 100644 index 0000000000..b04fd69f28 --- /dev/null +++ b/packages/canon/src/components/TablePagination/TablePagination.tsx @@ -0,0 +1,81 @@ +/* + * 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 * as React from 'react'; +import { Text } from '../Text'; +import { TablePaginationProps } from './types'; +import { Button } from '../Button'; + +/** @public */ +const TablePagination = React.forwardRef( + ({ className, ...props }, ref) => { + const { + pageIndex, + pageSize, + onClickPrevious, + onClickNext, + canPrevious, + canNext, + totalRows, + setPageSize, + } = props; + return ( +
+ +
+ {`${pageIndex * pageSize + 1} - ${ + (pageIndex + 1) * pageSize + } of ${totalRows}`} +
+
+ + +
+
+ ); + }, +); +TablePagination.displayName = 'TablePagination'; + +export { TablePagination }; diff --git a/packages/canon/src/components/TablePagination/index.ts b/packages/canon/src/components/TablePagination/index.ts new file mode 100644 index 0000000000..2a2d462f84 --- /dev/null +++ b/packages/canon/src/components/TablePagination/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export * from './TablePagination'; +export * from './types'; diff --git a/packages/canon/src/components/TablePagination/types.ts b/packages/canon/src/components/TablePagination/types.ts new file mode 100644 index 0000000000..79628de2bd --- /dev/null +++ b/packages/canon/src/components/TablePagination/types.ts @@ -0,0 +1,50 @@ +/* + * 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; +} diff --git a/yarn.lock b/yarn.lock index baf0dd3925..9e19cc722f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3789,6 +3789,7 @@ __metadata: "@storybook/react": ^8.6.8 "@storybook/react-webpack5": ^8.6.8 "@storybook/test": ^8.6.8 + "@tanstack/react-table": ^8.21.2 "@types/react": ^18.0.0 "@types/react-dom": ^18.0.0 chalk: ^5.4.1 @@ -19117,6 +19118,25 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-table@npm:^8.21.2": + version: 8.21.2 + resolution: "@tanstack/react-table@npm:8.21.2" + dependencies: + "@tanstack/table-core": 8.21.2 + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + checksum: 3cda97794c10777d48d01de29d087a33edd8af153b3096ac9798c7ebddd31bd34f2b7838ecf4bddaf469d661a777556bd8021e15a41f692eb2e3dd79dd0e5c3b + languageName: node + linkType: hard + +"@tanstack/table-core@npm:8.21.2": + version: 8.21.2 + resolution: "@tanstack/table-core@npm:8.21.2" + checksum: 21573388b26cef9c6fcabe3785640c470ea072a6d6ec34543e7eaf54ee742bf5fb12f8a04b172d7e08bd828a35afd7133add5adb4729dd4f94eaf4745b1cab14 + languageName: node + linkType: hard + "@techdocs/cli@workspace:*, @techdocs/cli@workspace:packages/techdocs-cli": version: 0.0.0-use.local resolution: "@techdocs/cli@workspace:packages/techdocs-cli" From 2b74f7be4b4dad6932b665a7e22605b9eaca1135 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 4 Apr 2025 21:32:59 +0100 Subject: [PATCH 04/26] Add DataTable Signed-off-by: Charles de Dreuille --- .../DataTablePagination.stories.tsx | 39 ++++++++ .../Pagination/DataTablePagination.styles.css | 21 +++++ .../Pagination/DataTablePagination.tsx | 86 ++++++++++++++++++ .../Pagination}/types.ts | 20 +++-- .../DataTable/Root/DataTableRoot.stories.tsx | 35 ++++++++ .../DataTable/Root/DataTableRoot.styles.css | 5 ++ .../Root/DataTableRoot.tsx} | 21 ++++- .../{DataTable.tsx => Root/types.ts} | 7 +- .../canon/src/components/DataTable/index.ts | 11 ++- .../src/components/Table/Table.stories.tsx | 90 ++++++++++--------- .../canon/src/components/Table/styles.css | 17 ---- .../TablePagination/TablePagination.tsx | 81 ----------------- packages/canon/src/css/components.css | 2 + packages/canon/src/index.ts | 1 + 14 files changed, 281 insertions(+), 155 deletions(-) create mode 100644 packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx create mode 100644 packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css create mode 100644 packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx rename packages/canon/src/components/{TablePagination => DataTable/Pagination}/types.ts (80%) create mode 100644 packages/canon/src/components/DataTable/Root/DataTableRoot.stories.tsx create mode 100644 packages/canon/src/components/DataTable/Root/DataTableRoot.styles.css rename packages/canon/src/components/{TablePagination/index.ts => DataTable/Root/DataTableRoot.tsx} (57%) rename packages/canon/src/components/DataTable/{DataTable.tsx => Root/types.ts} (85%) delete mode 100644 packages/canon/src/components/TablePagination/TablePagination.tsx diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx new file mode 100644 index 0000000000..54563cd98a --- /dev/null +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx @@ -0,0 +1,39 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { DataTablePagination } from './DataTablePagination'; + +const meta = { + title: 'Components/DataTable/Pagination', + component: DataTablePagination, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + pageIndex: 0, + pageSize: 10, + totalRows: 100, + onClickPrevious: () => {}, + onClickNext: () => {}, + canPrevious: true, + canNext: true, + setPageSize: () => {}, + }, +}; diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css new file mode 100644 index 0000000000..460a6a5874 --- /dev/null +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css @@ -0,0 +1,21 @@ +.canon-TablePagination { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: var(--canon-space-3); + border-top: 1px solid var(--canon-border); + margin-top: var(--canon-space-3); +} + +.canon-TablePagination--left { + display: flex; + align-items: center; + justify-content: space-between; +} + +.canon-TablePagination--right { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--canon-space-2); +} diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx new file mode 100644 index 0000000000..3a80ba3270 --- /dev/null +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx @@ -0,0 +1,86 @@ +/* + * 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 * as React from 'react'; +import { Text } from '../../Text'; +import { DataTablePaginationProps } from './types'; +import { IconButton } from '../../IconButton'; +import clsx from 'clsx'; +import { Select } from '../../Select'; + +/** @public */ +const DataTablePagination = React.forwardRef< + HTMLDivElement, + DataTablePaginationProps +>(({ className, ...props }, ref) => { + const { + pageIndex, + pageSize, + onClickPrevious, + onClickNext, + canPrevious, + canNext, + totalRows, + setPageSize, + } = props; + return ( +
+
+ { - setPageSize(Number(e.target.value)); - }} - > - {[10, 20, 30, 40, 50].map(pageSize => ( - - ))} - -
- {`${pageIndex * pageSize + 1} - ${ - (pageIndex + 1) * pageSize - } of ${totalRows}`} -
-
- - -
-
- ); - }, -); -TablePagination.displayName = 'TablePagination'; - -export { TablePagination }; diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index 2480baab14..f6b1db16c5 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -16,6 +16,8 @@ @import '../components/Box/styles.css'; @import '../components/Button/styles.css'; +@import '../components/DataTable/Root/DataTableRoot.styles.css'; +@import '../components/DataTable/Pagination/DataTablePagination.styles.css'; @import '../components/Flex/styles.css'; @import '../components/Grid/styles.css'; @import '../components/Container/styles.css'; diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index 7435b6dd60..a458ac0f4d 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -33,6 +33,7 @@ export * from './components/Heading'; // UI components export * from './components/Button'; +export * from './components/DataTable'; export * from './components/Icon'; export * from './components/IconButton'; export * from './components/Checkbox'; From 4c9a6c94ee0d41a38d7b791618e296ebd64528b5 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 4 Apr 2025 22:15:45 +0100 Subject: [PATCH 05/26] Improve DataTable Signed-off-by: Charles de Dreuille --- packages/canon/css/components.css | 35 +++- packages/canon/css/datatable.css | 21 +++ packages/canon/css/styles.css | 35 +++- packages/canon/css/table.css | 7 - packages/canon/report.api.md | 99 ++++++----- .../DataTable/DataTable.stories.tsx | 113 ++++++++++++ .../canon/src/components/DataTable/index.ts | 4 + .../mocked-columns.tsx} | 6 +- .../mocked-components.ts} | 0 .../src/components/Table/Table.stories.tsx | 167 ++++++++---------- packages/canon/src/components/Table/Table.tsx | 11 +- packages/canon/src/components/Table/index.ts | 1 - packages/canon/src/components/Table/types.ts | 50 ------ 13 files changed, 328 insertions(+), 221 deletions(-) create mode 100644 packages/canon/css/datatable.css create mode 100644 packages/canon/src/components/DataTable/DataTable.stories.tsx rename packages/canon/src/components/{Table/mocked-data/columns.tsx => DataTable/mocked-columns.tsx} (94%) rename packages/canon/src/components/{Table/mocked-data/components.ts => DataTable/mocked-components.ts} (100%) delete mode 100644 packages/canon/src/components/Table/types.ts 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; -} From 9721266532fd00af6a63451d2eeaf38aebd76d95 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 9 Apr 2025 10:00:30 +0200 Subject: [PATCH 06/26] Improve pagination + styles Signed-off-by: Charles de Dreuille --- packages/canon/report.api.md | 95 +++++++++++-------- .../DataTable/DataTable.stories.tsx | 16 +--- .../DataTablePagination.stories.tsx | 29 ++++-- .../Pagination/DataTablePagination.styles.css | 1 - .../Pagination/DataTablePagination.tsx | 50 +++++----- .../components/DataTable/Pagination/types.ts | 36 +------ .../DataTable/Root/DataTableRoot.stories.tsx | 1 - .../components/DataTable/mocked-columns.tsx | 2 +- packages/canon/src/components/Table/Table.tsx | 17 ++-- .../canon/src/components/Table/styles.css | 47 +++------ 10 files changed, 129 insertions(+), 165 deletions(-) diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 0a16c2abcf..a52a83c308 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -10,15 +10,14 @@ import type { CSSProperties } from 'react'; import { FC } from 'react'; import { FocusEvent as FocusEvent_2 } from 'react'; import { ForwardRefExoticComponent } from 'react'; -import { HTMLAttributes } from 'react'; import { JSX as JSX_2 } from 'react/jsx-runtime'; import { Menu as Menu_2 } from '@base-ui-components/react/menu'; +import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { RefAttributes } from 'react'; import type { RemixiconComponentType } from '@remixicon/react'; import { ScrollArea as ScrollArea_2 } from '@base-ui-components/react/scroll-area'; -import { TdHTMLAttributes } from 'react'; -import { ThHTMLAttributes } from 'react'; +import { Table as Table_2 } from '@tanstack/react-table'; import { Tooltip as Tooltip_2 } from '@base-ui-components/react/tooltip'; import type { useRender } from '@base-ui-components/react/use-render'; @@ -219,6 +218,28 @@ export interface ContainerProps { style?: React.CSSProperties; } +// @public +export const DataTable: { + Root: ForwardRefExoticComponent< + DataTableRootProps & RefAttributes + >; + Pagination: ( + props: DataTablePaginationProps & { + ref?: React.ForwardedRef; + }, + ) => React.ReactElement; +}; + +// @public (undocumented) +export interface DataTablePaginationProps + extends React.HTMLAttributes { + table?: Table_2; +} + +// @public (undocumented) +export interface DataTableRootProps + extends React.HTMLAttributes {} + // @public (undocumented) export type Display = 'none' | 'flex' | 'block' | 'inline'; @@ -1028,43 +1049,37 @@ export type StylingPropDef = { parseValue?: (value: string) => string | undefined; }; -// @public (undocumented) -export const Table: ForwardRefExoticComponent< - HTMLAttributes & RefAttributes ->; - -// @public (undocumented) -export const TableBody: ForwardRefExoticComponent< - HTMLAttributes & - RefAttributes ->; - -// @public (undocumented) -export const TableCell: ForwardRefExoticComponent< - TdHTMLAttributes & RefAttributes ->; - -// @public (undocumented) -export const TableFooter: ForwardRefExoticComponent< - HTMLAttributes & - RefAttributes ->; - -// @public (undocumented) -export const TableHead: ForwardRefExoticComponent< - ThHTMLAttributes & RefAttributes ->; - -// @public (undocumented) -export const TableHeader: ForwardRefExoticComponent< - HTMLAttributes & - RefAttributes ->; - -// @public (undocumented) -export const TableRow: ForwardRefExoticComponent< - HTMLAttributes & RefAttributes ->; +// @public +export const Table: { + Root: React_2.ForwardRefExoticComponent< + React_2.HTMLAttributes & + React_2.RefAttributes + >; + Header: React_2.ForwardRefExoticComponent< + React_2.HTMLAttributes & + React_2.RefAttributes + >; + Body: React_2.ForwardRefExoticComponent< + React_2.HTMLAttributes & + React_2.RefAttributes + >; + Head: React_2.ForwardRefExoticComponent< + React_2.ThHTMLAttributes & + React_2.RefAttributes + >; + Row: React_2.ForwardRefExoticComponent< + React_2.HTMLAttributes & + React_2.RefAttributes + >; + Cell: React_2.ForwardRefExoticComponent< + React_2.TdHTMLAttributes & + React_2.RefAttributes + >; + Caption: React_2.ForwardRefExoticComponent< + React_2.HTMLAttributes & + React_2.RefAttributes + >; +}; // @public (undocumented) const Text_2: ForwardRefExoticComponent< diff --git a/packages/canon/src/components/DataTable/DataTable.stories.tsx b/packages/canon/src/components/DataTable/DataTable.stories.tsx index 46bc81d08c..5a7c5dbfbc 100644 --- a/packages/canon/src/components/DataTable/DataTable.stories.tsx +++ b/packages/canon/src/components/DataTable/DataTable.stories.tsx @@ -14,11 +14,10 @@ * 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 { components, Component } from './mocked-components'; import { columns } from './mocked-columns'; import { flexRender, @@ -38,7 +37,7 @@ type Story = StoryObj; export const Default: Story = { render: () => { - const table = useReactTable({ + const table = useReactTable({ data: components, columns, getCoreRowModel: getCoreRowModel(), @@ -97,16 +96,7 @@ export const Default: Story = { )} - table.previousPage()} - onClickNext={() => table.nextPage()} - canPrevious={table.getCanPreviousPage()} - canNext={table.getCanNextPage()} - setPageSize={pageSize => table.setPageSize(pageSize)} - /> + ); }, diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx index 54563cd98a..ce3c8288a7 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx @@ -16,6 +16,15 @@ import type { Meta, StoryObj } from '@storybook/react'; import { DataTablePagination } from './DataTablePagination'; +import { + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table'; +import { components, Component } from '../mocked-components'; +import { columns } from '../mocked-columns'; const meta = { title: 'Components/DataTable/Pagination', @@ -26,14 +35,16 @@ export default meta; type Story = StoryObj; export const Default: Story = { - args: { - pageIndex: 0, - pageSize: 10, - totalRows: 100, - onClickPrevious: () => {}, - onClickNext: () => {}, - canPrevious: true, - canNext: true, - setPageSize: () => {}, + render: () => { + const table = useReactTable({ + data: components, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + }); + + return ; }, }; diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css index 460a6a5874..0117552401 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css @@ -4,7 +4,6 @@ justify-content: space-between; padding-top: var(--canon-space-3); border-top: 1px solid var(--canon-border); - margin-top: var(--canon-space-3); } .canon-TablePagination--left { diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx index 3a80ba3270..51144aa690 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as React from 'react'; + +import { forwardRef } from 'react'; import { Text } from '../../Text'; import { DataTablePaginationProps } from './types'; import { IconButton } from '../../IconButton'; @@ -21,25 +22,19 @@ import clsx from 'clsx'; import { Select } from '../../Select'; /** @public */ -const DataTablePagination = React.forwardRef< - HTMLDivElement, - DataTablePaginationProps ->(({ className, ...props }, ref) => { - const { - pageIndex, - pageSize, - onClickPrevious, - onClickNext, - canPrevious, - canNext, - totalRows, - setPageSize, - } = props; +function DataTablePagination( + props: DataTablePaginationProps, + ref: React.ForwardedRef, +) { + const { className, table, ...rest } = props; + const pageIndex = table?.getState().pagination.pageIndex; + const pageSize = table?.getState().pagination.pageSize; + return (
- +
)); TableRoot.displayName = 'TableRoot'; @@ -31,7 +30,7 @@ const TableHeader = forwardRef< >(({ className, ...props }, ref) => ( )); @@ -41,7 +40,7 @@ const TableBody = forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( - + )); TableBody.displayName = 'TableBody'; @@ -49,7 +48,7 @@ const TableRow = forwardRef< HTMLTableRowElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( - + {props.children} )); @@ -59,7 +58,7 @@ const TableHead = forwardRef< HTMLTableCellElement, React.ThHTMLAttributes >(({ className, ...props }, ref) => ( - ), enableSorting: false, enableHiding: false, @@ -45,27 +47,28 @@ export const columns: ColumnDef[] = [ accessorKey: 'name', header: 'Name', cell: ({ row }) => ( -
- {row.getValue('name')} - - {row.original.description} - -
+ ), }, { accessorKey: 'owner', header: 'Owner', - cell: ({ row }) => {row.getValue('owner')}, + cell: ({ row }) => ( + + ), }, { accessorKey: 'type', header: 'Type', - cell: ({ row }) => {row.getValue('type')}, + cell: ({ row }) => , }, { accessorKey: 'tags', header: 'Tags', - cell: ({ row }) => {row.getValue('tags')}, + cell: ({ row }) => , }, ]; diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx index e3d8a4e859..185c110654 100644 --- a/packages/canon/src/components/Table/Table.tsx +++ b/packages/canon/src/components/Table/Table.tsx @@ -13,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { forwardRef } from 'react'; import clsx from 'clsx'; +import { TableCell } from './TableCell/TableCell'; +import { TableCellText } from './TableCellText/TableCellText'; +import { TableCellLink } from './TableCellLink/TableCellLink'; const TableRoot = forwardRef< HTMLTableElement, @@ -62,14 +66,6 @@ const TableHead = forwardRef< )); TableHead.displayName = 'TableHead'; -const TableCell = forwardRef< - HTMLTableCellElement, - React.TdHTMLAttributes ->(({ className, ...props }, ref) => ( -
+ )); TableHead.displayName = 'TableHead'; @@ -67,7 +66,7 @@ const TableCell = forwardRef< HTMLTableCellElement, React.TdHTMLAttributes >(({ className, ...props }, ref) => ( - + )); TableCell.displayName = 'TableCell'; @@ -77,7 +76,7 @@ const TableCaption = forwardRef< >(({ className, ...props }, ref) => (
)); diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css index 203a0a57b0..325873f690 100644 --- a/packages/canon/src/components/Table/styles.css +++ b/packages/canon/src/components/Table/styles.css @@ -1,54 +1,31 @@ -.table { - position: relative; - overflow: auto; +.canon-TableRoot { width: 100%; - - table { - width: 100%; - caption-side: bottom; - font-size: var(--canon-font-size-sm); - border-collapse: collapse; - } + caption-side: bottom; + border-collapse: collapse; } -.table-head { +.canon-TableHead { text-align: left; padding: var(--canon-space-3); + font-size: var(--canon-font-size-3); } -.table-body { +.canon-TableBody { tr:last-child { border-bottom: none; } } -.table-row { +.canon-TableRow { + border-bottom: 1px solid var(--canon-border); transition: color 0.2s ease-in-out; - &:hover td { - background-color: var(--canon-bg-tint); - } - - & .table-cell:first-child { - border-top-left-radius: var(--canon-radius-2); - border-bottom-left-radius: var(--canon-radius-2); - box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), - inset 4px -2px 0 0 var(--canon-bg-surface-1); - padding-left: var(--canon-space-3); - } - - & .table-cell:last-child { - border-top-right-radius: var(--canon-radius-2); - border-bottom-right-radius: var(--canon-radius-2); - box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), - inset -4px -2px 0 0 var(--canon-bg-surface-1); - padding-right: var(--canon-space-3); + &:hover { + background-color: var(--canon-bg-tint-hover); } } -.table-cell { +.canon-TableCell { padding: var(--canon-space-3); - background-color: var(--canon-bg); - box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), - inset 0px -2px 0 0 var(--canon-bg-surface-1); + font-size: var(--canon-font-size-3); } From 7756cf73fe257b8f6a3d4b6a7aef59fedfa901c5 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Thu, 10 Apr 2025 10:48:03 +0200 Subject: [PATCH 07/26] Fix a few things on DataTable Signed-off-by: Charles de Dreuille --- packages/canon/report.api.md | 42 +++++++++---------- .../DataTable/Root/DataTableRoot.tsx | 4 +- .../src/components/Select/Select.stories.tsx | 2 +- .../src/components/Table/Table.stories.tsx | 12 +++--- .../canon/src/components/Table/styles.css | 6 +-- .../TextField/TextField.stories.tsx | 4 +- 6 files changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index a52a83c308..e03b2dfe1e 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -10,14 +10,16 @@ import type { CSSProperties } from 'react'; import { FC } from 'react'; import { FocusEvent as FocusEvent_2 } from 'react'; import { ForwardRefExoticComponent } from 'react'; +import { HTMLAttributes } from 'react'; import { JSX as JSX_2 } from 'react/jsx-runtime'; import { Menu as Menu_2 } from '@base-ui-components/react/menu'; -import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { RefAttributes } from 'react'; import type { RemixiconComponentType } from '@remixicon/react'; import { ScrollArea as ScrollArea_2 } from '@base-ui-components/react/scroll-area'; import { Table as Table_2 } from '@tanstack/react-table'; +import { TdHTMLAttributes } from 'react'; +import { ThHTMLAttributes } from 'react'; import { Tooltip as Tooltip_2 } from '@base-ui-components/react/tooltip'; import type { useRender } from '@base-ui-components/react/use-render'; @@ -1051,33 +1053,29 @@ export type StylingPropDef = { // @public export const Table: { - Root: React_2.ForwardRefExoticComponent< - React_2.HTMLAttributes & - React_2.RefAttributes + Root: ForwardRefExoticComponent< + HTMLAttributes & RefAttributes >; - Header: React_2.ForwardRefExoticComponent< - React_2.HTMLAttributes & - React_2.RefAttributes + Header: ForwardRefExoticComponent< + HTMLAttributes & + RefAttributes >; - Body: React_2.ForwardRefExoticComponent< - React_2.HTMLAttributes & - React_2.RefAttributes + Body: ForwardRefExoticComponent< + HTMLAttributes & + RefAttributes >; - Head: React_2.ForwardRefExoticComponent< - React_2.ThHTMLAttributes & - React_2.RefAttributes + Head: ForwardRefExoticComponent< + ThHTMLAttributes & RefAttributes >; - Row: React_2.ForwardRefExoticComponent< - React_2.HTMLAttributes & - React_2.RefAttributes + Row: ForwardRefExoticComponent< + HTMLAttributes & RefAttributes >; - Cell: React_2.ForwardRefExoticComponent< - React_2.TdHTMLAttributes & - React_2.RefAttributes + Cell: ForwardRefExoticComponent< + TdHTMLAttributes & RefAttributes >; - Caption: React_2.ForwardRefExoticComponent< - React_2.HTMLAttributes & - React_2.RefAttributes + Caption: ForwardRefExoticComponent< + HTMLAttributes & + RefAttributes >; }; diff --git a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx b/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx index 50cc81b7ab..8ca6db736c 100644 --- a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx +++ b/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ -import * as React from 'react'; +import { forwardRef } from 'react'; import clsx from 'clsx'; import { DataTableRootProps } from './types'; /** @public */ -const DataTableRoot = React.forwardRef( +const DataTableRoot = forwardRef( ({ className, ...props }, ref) => { return (
, - Cell: Table.Cell as React.ComponentType, - Head: Table.Head as React.ComponentType, - Header: Table.Header as React.ComponentType, - Row: Table.Row as React.ComponentType, + 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, }, } satisfies Meta; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css index 325873f690..982b2d1c69 100644 --- a/packages/canon/src/components/Table/styles.css +++ b/packages/canon/src/components/Table/styles.css @@ -19,10 +19,10 @@ .canon-TableRow { border-bottom: 1px solid var(--canon-border); transition: color 0.2s ease-in-out; +} - &:hover { - background-color: var(--canon-bg-tint-hover); - } +.canon-TableBody .canon-TableRow:hover { + background-color: var(--canon-gray-2); } .canon-TableCell { diff --git a/packages/canon/src/components/TextField/TextField.stories.tsx b/packages/canon/src/components/TextField/TextField.stories.tsx index 34f81af4f4..8594a8c650 100644 --- a/packages/canon/src/components/TextField/TextField.stories.tsx +++ b/packages/canon/src/components/TextField/TextField.stories.tsx @@ -95,14 +95,14 @@ export const Responsive: Story = { }, }; -export const withError: Story = { +export const WithError: Story = { args: { ...WithLabel.args, error: 'Invalid URL', }, }; -export const withErrorAndDescription: Story = { +export const WithErrorAndDescription: Story = { args: { ...WithLabel.args, error: 'Invalid URL', From febc78ebd3ec296d163d22cbf55be9f466231f1b Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Thu, 10 Apr 2025 11:03:11 +0200 Subject: [PATCH 08/26] Build CSS Signed-off-by: Charles de Dreuille --- packages/canon/css/components.css | 49 +++++++++---------------------- packages/canon/css/datatable.css | 1 - packages/canon/css/styles.css | 49 +++++++++---------------------- packages/canon/css/table.css | 48 +++++++++--------------------- 4 files changed, 42 insertions(+), 105 deletions(-) diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index b5a81a9586..38a03e9dd1 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -103,7 +103,6 @@ .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; @@ -203,56 +202,36 @@ display: flex; } -.table { +.canon-TableRoot { + caption-side: bottom; + border-collapse: collapse; width: 100%; - position: relative; - overflow: auto; - - & table { - caption-side: bottom; - width: 100%; - font-size: var(--canon-font-size-sm); - border-collapse: collapse; - } } -.table-head { +.canon-TableHead { text-align: left; padding: var(--canon-space-3); + font-size: var(--canon-font-size-3); } -.table-body { +.canon-TableBody { & tr:last-child { border-bottom: none; } } -.table-row { +.canon-TableRow { + border-bottom: 1px solid var(--canon-border); transition: color .2s ease-in-out; - - &:hover td { - background-color: var(--canon-bg-tint); - } - - & .table-cell:first-child { - border-top-left-radius: var(--canon-radius-2); - border-bottom-left-radius: var(--canon-radius-2); - box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), inset 4px -2px 0 0 var(--canon-bg-surface-1); - padding-left: var(--canon-space-3); - } - - & .table-cell:last-child { - border-top-right-radius: var(--canon-radius-2); - border-bottom-right-radius: var(--canon-radius-2); - box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), inset -4px -2px 0 0 var(--canon-bg-surface-1); - padding-right: var(--canon-space-3); - } } -.table-cell { +.canon-TableBody .canon-TableRow:hover { + background-color: var(--canon-gray-2); +} + +.canon-TableCell { padding: var(--canon-space-3); - background-color: var(--canon-bg); - box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1); + font-size: var(--canon-font-size-3); } .canon-Text { diff --git a/packages/canon/css/datatable.css b/packages/canon/css/datatable.css index c33ecce578..1773f6b980 100644 --- a/packages/canon/css/datatable.css +++ b/packages/canon/css/datatable.css @@ -1,7 +1,6 @@ .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; diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index 12097151da..57b4eb4d02 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9327,7 +9327,6 @@ .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; @@ -9427,56 +9426,36 @@ display: flex; } -.table { +.canon-TableRoot { + caption-side: bottom; + border-collapse: collapse; width: 100%; - position: relative; - overflow: auto; - - & table { - caption-side: bottom; - width: 100%; - font-size: var(--canon-font-size-sm); - border-collapse: collapse; - } } -.table-head { +.canon-TableHead { text-align: left; padding: var(--canon-space-3); + font-size: var(--canon-font-size-3); } -.table-body { +.canon-TableBody { & tr:last-child { border-bottom: none; } } -.table-row { +.canon-TableRow { + border-bottom: 1px solid var(--canon-border); transition: color .2s ease-in-out; - - &:hover td { - background-color: var(--canon-bg-tint); - } - - & .table-cell:first-child { - border-top-left-radius: var(--canon-radius-2); - border-bottom-left-radius: var(--canon-radius-2); - box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), inset 4px -2px 0 0 var(--canon-bg-surface-1); - padding-left: var(--canon-space-3); - } - - & .table-cell:last-child { - border-top-right-radius: var(--canon-radius-2); - border-bottom-right-radius: var(--canon-radius-2); - box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), inset -4px -2px 0 0 var(--canon-bg-surface-1); - padding-right: var(--canon-space-3); - } } -.table-cell { +.canon-TableBody .canon-TableRow:hover { + background-color: var(--canon-gray-2); +} + +.canon-TableCell { padding: var(--canon-space-3); - background-color: var(--canon-bg); - box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1); + font-size: var(--canon-font-size-3); } .canon-Text { diff --git a/packages/canon/css/table.css b/packages/canon/css/table.css index a146010779..dd25410a0e 100644 --- a/packages/canon/css/table.css +++ b/packages/canon/css/table.css @@ -1,51 +1,31 @@ -.table { +.canon-TableRoot { + caption-side: bottom; + border-collapse: collapse; width: 100%; - position: relative; - overflow: auto; - - & table { - caption-side: bottom; - width: 100%; - font-size: var(--canon-font-size-sm); - border-collapse: collapse; - } } -.table-head { +.canon-TableHead { text-align: left; padding: var(--canon-space-3); + font-size: var(--canon-font-size-3); } -.table-body { +.canon-TableBody { & tr:last-child { border-bottom: none; } } -.table-row { +.canon-TableRow { + border-bottom: 1px solid var(--canon-border); transition: color .2s ease-in-out; - - &:hover td { - background-color: var(--canon-bg-tint); - } - - & .table-cell:first-child { - border-top-left-radius: var(--canon-radius-2); - border-bottom-left-radius: var(--canon-radius-2); - box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), inset 4px -2px 0 0 var(--canon-bg-surface-1); - padding-left: var(--canon-space-3); - } - - & .table-cell:last-child { - border-top-right-radius: var(--canon-radius-2); - border-bottom-right-radius: var(--canon-radius-2); - box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), inset -4px -2px 0 0 var(--canon-bg-surface-1); - padding-right: var(--canon-space-3); - } } -.table-cell { +.canon-TableBody .canon-TableRow:hover { + background-color: var(--canon-gray-2); +} + +.canon-TableCell { padding: var(--canon-space-3); - background-color: var(--canon-bg); - box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1); + font-size: var(--canon-font-size-3); } From 9806fd8adf4047db465a89819532350e65d5face Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 11 Apr 2025 09:12:35 +0200 Subject: [PATCH 09/26] Update DataTable Signed-off-by: Charles de Dreuille --- packages/canon/report.api.md | 72 +++++++++-- .../DataTable/DataTable.stories.tsx | 49 ++++---- .../src/components/DataTable/DataTable.tsx | 76 ++++++++++++ .../DataTablePagination.stories.tsx | 11 +- .../Pagination/DataTablePagination.tsx | 116 +++++++++--------- .../components/DataTable/Pagination/types.ts | 11 +- .../DataTable/Root/DataTableRoot.stories.tsx | 34 ----- .../DataTable/Root/DataTableRoot.tsx | 43 +++++-- .../src/components/DataTable/Root/types.ts | 11 +- .../canon/src/components/DataTable/index.ts | 13 +- .../components/DataTable/mocked-components.ts | 2 +- .../src/components/Select/Select.stories.tsx | 26 ++++ 12 files changed, 297 insertions(+), 167 deletions(-) create mode 100644 packages/canon/src/components/DataTable/DataTable.tsx delete mode 100644 packages/canon/src/components/DataTable/Root/DataTableRoot.stories.tsx diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index e03b2dfe1e..ec859f34e6 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -222,25 +222,71 @@ export interface ContainerProps { // @public export const DataTable: { - Root: ForwardRefExoticComponent< - DataTableRootProps & RefAttributes + Root: ( + props: { + table: Table_2; + } & React.HTMLAttributes, + ) => JSX.Element; + Pagination: ForwardRefExoticComponent< + DataTablePaginationProps & RefAttributes + >; + Table: ForwardRefExoticComponent< + Omit< + HTMLAttributes & RefAttributes, + 'ref' + > & + RefAttributes + >; + Header: ForwardRefExoticComponent< + Omit< + HTMLAttributes & + RefAttributes, + 'ref' + > & + RefAttributes + >; + Body: ForwardRefExoticComponent< + Omit< + HTMLAttributes & + RefAttributes, + 'ref' + > & + RefAttributes + >; + Row: ForwardRefExoticComponent< + Omit< + HTMLAttributes & RefAttributes, + 'ref' + > & + RefAttributes + >; + Cell: ForwardRefExoticComponent< + Omit< + TdHTMLAttributes & + RefAttributes, + 'ref' + > & + RefAttributes + >; + Head: ForwardRefExoticComponent< + Omit< + ThHTMLAttributes & + RefAttributes, + 'ref' + > & + RefAttributes >; - Pagination: ( - props: DataTablePaginationProps & { - ref?: React.ForwardedRef; - }, - ) => React.ReactElement; }; // @public (undocumented) -export interface DataTablePaginationProps - extends React.HTMLAttributes { - table?: Table_2; -} +export interface DataTablePaginationProps + extends React.HTMLAttributes {} // @public (undocumented) -export interface DataTableRootProps - extends React.HTMLAttributes {} +export interface DataTableRootProps + extends React.HTMLAttributes { + table: Table_2; +} // @public (undocumented) export type Display = 'none' | 'flex' | 'block' | 'inline'; diff --git a/packages/canon/src/components/DataTable/DataTable.stories.tsx b/packages/canon/src/components/DataTable/DataTable.stories.tsx index 5a7c5dbfbc..9bcdc23ad3 100644 --- a/packages/canon/src/components/DataTable/DataTable.stories.tsx +++ b/packages/canon/src/components/DataTable/DataTable.stories.tsx @@ -15,16 +15,13 @@ */ import type { Meta, StoryObj } from '@storybook/react'; -import { Table } from '../Table'; import { DataTable } from '.'; -import { components, Component } from './mocked-components'; +import { data, Component } from './mocked-components'; import { columns } from './mocked-columns'; import { flexRender, getCoreRowModel, - getFilteredRowModel, getPaginationRowModel, - getSortedRowModel, useReactTable, } from '@tanstack/react-table'; @@ -38,65 +35,63 @@ type Story = StoryObj; export const Default: Story = { render: () => { const table = useReactTable({ - data: components, + data, 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. - - + + )} - - - + + + ); }, diff --git a/packages/canon/src/components/DataTable/DataTable.tsx b/packages/canon/src/components/DataTable/DataTable.tsx new file mode 100644 index 0000000000..83251b473b --- /dev/null +++ b/packages/canon/src/components/DataTable/DataTable.tsx @@ -0,0 +1,76 @@ +/* + * 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 { forwardRef } from 'react'; +import { Table } from '../Table'; +import { DataTableRoot } from './Root/DataTableRoot'; +import { DataTablePagination } from './Pagination/DataTablePagination'; +import { Table as TanstackTable } from '@tanstack/react-table'; + +const TableRoot = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableRoot.displayName = Table.Root.displayName; + +const TableHeader = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableHeader.displayName = Table.Header.displayName; + +const TableBody = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableBody.displayName = Table.Body.displayName; + +const TableRow = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableRow.displayName = Table.Row.displayName; + +const TableCell = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableCell.displayName = Table.Cell.displayName; + +const TableHead = forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ); +TableHead.displayName = Table.Head.displayName; + +/** + * DataTable component for displaying tabular data with pagination + * @public + */ +export const DataTable = { + Root: DataTableRoot as ( + props: { + table: TanstackTable; + } & React.HTMLAttributes, + ) => JSX.Element, + Pagination: DataTablePagination, + Table: TableRoot, + Header: TableHeader, + Body: TableBody, + Row: TableRow, + Cell: TableCell, + Head: TableHead, +}; diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx index ce3c8288a7..7a45b111b9 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx @@ -23,8 +23,9 @@ import { getSortedRowModel, useReactTable, } from '@tanstack/react-table'; -import { components, Component } from '../mocked-components'; +import { data, Component } from '../mocked-components'; import { columns } from '../mocked-columns'; +import { DataTable } from '../DataTable'; const meta = { title: 'Components/DataTable/Pagination', @@ -37,7 +38,7 @@ type Story = StoryObj; export const Default: Story = { render: () => { const table = useReactTable({ - data: components, + data, columns, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), @@ -45,6 +46,10 @@ export const Default: Story = { getFilteredRowModel: getFilteredRowModel(), }); - return ; + return ( + + + + ); }, }; diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx index 51144aa690..c85b90f743 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx @@ -20,67 +20,67 @@ import { DataTablePaginationProps } from './types'; import { IconButton } from '../../IconButton'; import clsx from 'clsx'; import { Select } from '../../Select'; +import { useDataTable } from '../Root/DataTableRoot'; /** @public */ -function DataTablePagination( - props: DataTablePaginationProps, - ref: React.ForwardedRef, -) { - const { className, table, ...rest } = props; - const pageIndex = table?.getState().pagination.pageIndex; - const pageSize = table?.getState().pagination.pageSize; +const DataTablePagination = forwardRef( + ( + props: DataTablePaginationProps, + ref: React.ForwardedRef, + ) => { + const { className, ...rest } = props; + const { table } = useDataTable(); + const pageIndex = table?.getState().pagination.pageIndex; + const pageSize = table?.getState().pagination.pageSize; - return ( -
-
- { + table?.setPageSize(Number(value)); + }} + /> +
+
+ {`${(pageIndex ?? 0) * (pageSize ?? 10) + 1} - ${ + ((pageIndex ?? 0) + 1) * (pageSize ?? 10) + } of ${table?.getRowCount()}`} + table?.previousPage()} + disabled={!table?.getCanPreviousPage()} + icon="chevron-left" + /> + table?.nextPage()} + disabled={!table?.getCanNextPage()} + icon="chevron-right" + /> +
-
- {`${(pageIndex ?? 0) * (pageSize ?? 10) + 1} - ${ - ((pageIndex ?? 0) + 1) * (pageSize ?? 10) - } of ${table?.getRowCount()}`} - table?.previousPage()} - disabled={!table?.getCanPreviousPage()} - icon="chevron-left" - /> - table?.nextPage()} - disabled={!table?.getCanNextPage()} - icon="chevron-right" - /> -
-
- ); -} - -const ForwardedDataTablePagination = forwardRef(DataTablePagination) as ( - props: DataTablePaginationProps & { - ref?: React.ForwardedRef; + ); }, -) => React.ReactElement; +); -export { ForwardedDataTablePagination as DataTablePagination }; +DataTablePagination.displayName = 'DataTablePagination'; + +export { DataTablePagination }; diff --git a/packages/canon/src/components/DataTable/Pagination/types.ts b/packages/canon/src/components/DataTable/Pagination/types.ts index d8dbe76582..b2a895c465 100644 --- a/packages/canon/src/components/DataTable/Pagination/types.ts +++ b/packages/canon/src/components/DataTable/Pagination/types.ts @@ -14,13 +14,6 @@ * limitations under the License. */ -import { Table } from '@tanstack/react-table'; - /** @public */ -export interface DataTablePaginationProps - extends React.HTMLAttributes { - /** - * The table instance. - */ - table?: Table; -} +export interface DataTablePaginationProps + extends React.HTMLAttributes {} diff --git a/packages/canon/src/components/DataTable/Root/DataTableRoot.stories.tsx b/packages/canon/src/components/DataTable/Root/DataTableRoot.stories.tsx deleted file mode 100644 index 371183aa7c..0000000000 --- a/packages/canon/src/components/DataTable/Root/DataTableRoot.stories.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 type { Meta, StoryObj } from '@storybook/react'; -import { DataTableRoot } from './DataTableRoot'; -import { DataTablePagination } from '../Pagination/DataTablePagination'; -import { Default as DataTablePaginationDefault } from '../Pagination/DataTablePagination.stories'; - -const meta = { - title: 'Components/DataTable/Root', - component: DataTableRoot, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - children: , - }, -}; diff --git a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx b/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx index 8ca6db736c..8207fe4412 100644 --- a/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx +++ b/packages/canon/src/components/DataTable/Root/DataTableRoot.tsx @@ -14,22 +14,49 @@ * limitations under the License. */ -import { forwardRef } from 'react'; +import { forwardRef, createContext, useContext } from 'react'; import clsx from 'clsx'; import { DataTableRootProps } from './types'; +import { Table } from '@tanstack/react-table'; + +type DataTableContextType = { + table: Table; +}; /** @public */ -const DataTableRoot = forwardRef( - ({ className, ...props }, ref) => { +export const DataTableContext = createContext | null>( + null, +); + +/** @public */ +const DataTableRoot = forwardRef( + ( + props: DataTableRootProps, + ref: React.ForwardedRef, + ) => { + const { className, table, ...rest } = props; + return ( -
+ +
+ ); }, ); + DataTableRoot.displayName = 'DataTableRoot'; export { DataTableRoot }; + +/** @public */ +export function useDataTable() { + const context = useContext(DataTableContext); + if (!context) { + throw new Error('useDataTable must be used within a DataTableRoot'); + } + return context as DataTableContextType; +} diff --git a/packages/canon/src/components/DataTable/Root/types.ts b/packages/canon/src/components/DataTable/Root/types.ts index 420181feaf..0a14f81fb3 100644 --- a/packages/canon/src/components/DataTable/Root/types.ts +++ b/packages/canon/src/components/DataTable/Root/types.ts @@ -14,6 +14,13 @@ * limitations under the License. */ +import { Table } from '@tanstack/react-table'; + /** @public */ -export interface DataTableRootProps - extends React.HTMLAttributes {} +export interface DataTableRootProps + extends React.HTMLAttributes { + /** + * The table instance. + */ + table: Table; +} diff --git a/packages/canon/src/components/DataTable/index.ts b/packages/canon/src/components/DataTable/index.ts index 688df19b90..d684c2b48c 100644 --- a/packages/canon/src/components/DataTable/index.ts +++ b/packages/canon/src/components/DataTable/index.ts @@ -14,17 +14,6 @@ * limitations under the License. */ -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, -}; - +export * from './DataTable'; export * from './Root/types'; export * from './Pagination/types'; diff --git a/packages/canon/src/components/DataTable/mocked-components.ts b/packages/canon/src/components/DataTable/mocked-components.ts index f7861023d3..35b43d887f 100644 --- a/packages/canon/src/components/DataTable/mocked-components.ts +++ b/packages/canon/src/components/DataTable/mocked-components.ts @@ -21,7 +21,7 @@ export interface Component { tags?: string[]; } -export const components: Component[] = [ +export const data: Component[] = [ { name: 'authentication-and-authorization-service', owner: 'security-team', diff --git a/packages/canon/src/components/Select/Select.stories.tsx b/packages/canon/src/components/Select/Select.stories.tsx index dc951a390f..0a621162b5 100644 --- a/packages/canon/src/components/Select/Select.stories.tsx +++ b/packages/canon/src/components/Select/Select.stories.tsx @@ -252,3 +252,29 @@ export const WithErrorAndDescription: Story = { error: 'Invalid font family', }, }; + +export const WithLongLabels: Story = { + args: { + label: 'Document Template', + options: [ + { + value: 'annual-report-2024', + label: + 'Annual Financial Report and Strategic Planning Document for Fiscal Year 2024 with Comprehensive Analysis of Market Trends, Competitive Landscape, Financial Performance Metrics, Revenue Projections, Cost Optimization Strategies, Risk Assessment, and Long-term Growth Initiatives Across All Business Units and Geographical Regions', + }, + { + value: 'product-roadmap', + label: + 'Comprehensive Product Development Roadmap and Feature Implementation Timeline Including Detailed Technical Specifications, Resource Allocation Plans, Cross-functional Team Dependencies, Milestone Tracking, Quality Assurance Procedures, User Acceptance Testing Protocols, and Post-launch Support Strategy for All Product Lines and Service Offerings', + }, + { + value: 'user-guide', + label: + 'Detailed User Guide and Technical Documentation for Advanced System Features Covering Installation Procedures, Configuration Settings, Security Protocols, Troubleshooting Guidelines, Best Practices, Common Use Cases, Performance Optimization Tips, Integration Methods, API Documentation, and Frequently Asked Questions with Step-by-Step Solutions', + }, + ], + placeholder: 'Select a document template', + name: 'template', + style: { maxWidth: 400 }, + }, +}; From 0e654bf4b62e3b7bce793313cb56d92d5bcdc8ef Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Fri, 11 Apr 2025 09:37:20 +0200 Subject: [PATCH 10/26] Improve DataTable Signed-off-by: Charles de Dreuille --- .changeset/quiet-rockets-throw.md | 5 +++++ packages/canon/css/components.css | 10 +++++++--- packages/canon/css/datatable.css | 10 +++++++--- packages/canon/css/styles.css | 10 +++++++--- .../src/components/DataTable/DataTable.stories.tsx | 4 ++-- .../Pagination/DataTablePagination.stories.tsx | 4 ++-- .../Pagination/DataTablePagination.styles.css | 10 +++++++--- .../DataTable/Pagination/DataTablePagination.tsx | 7 ++++--- .../canon/src/components/DataTable/mocked-columns.tsx | 4 ++-- .../src/components/DataTable/mocked-components.ts | 4 ++-- 10 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 .changeset/quiet-rockets-throw.md diff --git a/.changeset/quiet-rockets-throw.md b/.changeset/quiet-rockets-throw.md new file mode 100644 index 0000000000..a73dbeb51b --- /dev/null +++ b/.changeset/quiet-rockets-throw.md @@ -0,0 +1,5 @@ +--- +'@backstage/canon': patch +--- + +Add new DataTable component. diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index d8f289d019..e138c9bdd6 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -100,7 +100,7 @@ display: flex; } -.canon-TablePagination { +.canon-DataTablePagination { padding-top: var(--canon-space-3); border-top: 1px solid var(--canon-border); justify-content: space-between; @@ -108,19 +108,23 @@ display: flex; } -.canon-TablePagination--left { +.canon-DataTablePagination--left { justify-content: space-between; align-items: center; display: flex; } -.canon-TablePagination--right { +.canon-DataTablePagination--right { justify-content: space-between; align-items: center; gap: var(--canon-space-2); display: flex; } +.canon-DataTablePagination--select { + min-width: 168px; +} + .canon-Flex { display: flex; } diff --git a/packages/canon/css/datatable.css b/packages/canon/css/datatable.css index 1773f6b980..081bc11ce9 100644 --- a/packages/canon/css/datatable.css +++ b/packages/canon/css/datatable.css @@ -1,4 +1,4 @@ -.canon-TablePagination { +.canon-DataTablePagination { padding-top: var(--canon-space-3); border-top: 1px solid var(--canon-border); justify-content: space-between; @@ -6,15 +6,19 @@ display: flex; } -.canon-TablePagination--left { +.canon-DataTablePagination--left { justify-content: space-between; align-items: center; display: flex; } -.canon-TablePagination--right { +.canon-DataTablePagination--right { justify-content: space-between; align-items: center; gap: var(--canon-space-2); display: flex; } + +.canon-DataTablePagination--select { + min-width: 168px; +} diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index 395b8ccde8..46fd6f05d1 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9324,7 +9324,7 @@ display: flex; } -.canon-TablePagination { +.canon-DataTablePagination { padding-top: var(--canon-space-3); border-top: 1px solid var(--canon-border); justify-content: space-between; @@ -9332,19 +9332,23 @@ display: flex; } -.canon-TablePagination--left { +.canon-DataTablePagination--left { justify-content: space-between; align-items: center; display: flex; } -.canon-TablePagination--right { +.canon-DataTablePagination--right { justify-content: space-between; align-items: center; gap: var(--canon-space-2); display: flex; } +.canon-DataTablePagination--select { + min-width: 168px; +} + .canon-Flex { display: flex; } diff --git a/packages/canon/src/components/DataTable/DataTable.stories.tsx b/packages/canon/src/components/DataTable/DataTable.stories.tsx index 9bcdc23ad3..3119821d92 100644 --- a/packages/canon/src/components/DataTable/DataTable.stories.tsx +++ b/packages/canon/src/components/DataTable/DataTable.stories.tsx @@ -16,7 +16,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { DataTable } from '.'; -import { data, Component } from './mocked-components'; +import { data, DataProps } from './mocked-components'; import { columns } from './mocked-columns'; import { flexRender, @@ -34,7 +34,7 @@ type Story = StoryObj; export const Default: Story = { render: () => { - const table = useReactTable({ + const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx index 7a45b111b9..a2f931aed6 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.stories.tsx @@ -23,7 +23,7 @@ import { getSortedRowModel, useReactTable, } from '@tanstack/react-table'; -import { data, Component } from '../mocked-components'; +import { data, DataProps } from '../mocked-components'; import { columns } from '../mocked-columns'; import { DataTable } from '../DataTable'; @@ -37,7 +37,7 @@ type Story = StoryObj; export const Default: Story = { render: () => { - const table = useReactTable({ + const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css index 0117552401..ff2e8e232c 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.styles.css @@ -1,4 +1,4 @@ -.canon-TablePagination { +.canon-DataTablePagination { display: flex; align-items: center; justify-content: space-between; @@ -6,15 +6,19 @@ border-top: 1px solid var(--canon-border); } -.canon-TablePagination--left { +.canon-DataTablePagination--left { display: flex; align-items: center; justify-content: space-between; } -.canon-TablePagination--right { +.canon-DataTablePagination--right { display: flex; align-items: center; justify-content: space-between; gap: var(--canon-space-2); } + +.canon-DataTablePagination--select { + min-width: 168px; +} diff --git a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx index c85b90f743..ef74d12db6 100644 --- a/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx +++ b/packages/canon/src/components/DataTable/Pagination/DataTablePagination.tsx @@ -36,10 +36,10 @@ const DataTablePagination = forwardRef( return (
-
+
{ - table?.setPageSize(Number(value)); - }} - className="canon-DataTablePagination--select" - /> + {!table.options.manualPagination && ( + Date: Sat, 12 Apr 2025 15:25:58 +0200 Subject: [PATCH 20/26] Build CSS Signed-off-by: Charles de Dreuille --- packages/canon/css/button.css | 12 ++++----- packages/canon/css/components.css | 44 +++++++++++++++---------------- packages/canon/css/iconbutton.css | 12 ++++----- packages/canon/css/link.css | 12 ++++----- packages/canon/css/select.css | 4 +-- packages/canon/css/styles.css | 44 +++++++++++++++---------------- packages/canon/css/textfield.css | 4 +-- 7 files changed, 66 insertions(+), 66 deletions(-) diff --git a/packages/canon/css/button.css b/packages/canon/css/button.css index 312f58c5e6..ccfc3b48f5 100644 --- a/packages/canon/css/button.css +++ b/packages/canon/css/button.css @@ -16,7 +16,7 @@ } } -.canon-Button--variant-primary { +.canon-Button[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -40,7 +40,7 @@ } } -.canon-Button--variant-secondary { +.canon-Button[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -66,24 +66,24 @@ } } -.canon-Button--size-medium { +.canon-Button[data-size="medium"] { font-size: var(--canon-font-size-4); padding: 0 var(--canon-space-3); height: 40px; } -.canon-Button--size-small { +.canon-Button[data-size="small"] { font-size: var(--canon-font-size-3); padding: 0 var(--canon-space-2); height: 32px; } -.canon-Button--size-small .canon-Button--icon { +.canon-Button[data-size="small"] .canon-Button--icon { width: 1rem; height: 1rem; } -.canon-Button--size-medium .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-Button--icon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index 9a276a3a0a..216f38c968 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -22,7 +22,7 @@ } } -.canon-Button--variant-primary { +.canon-Button[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -46,7 +46,7 @@ } } -.canon-Button--variant-secondary { +.canon-Button[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -72,24 +72,24 @@ } } -.canon-Button--size-medium { +.canon-Button[data-size="medium"] { font-size: var(--canon-font-size-4); padding: 0 var(--canon-space-3); height: 40px; } -.canon-Button--size-small { +.canon-Button[data-size="small"] { font-size: var(--canon-font-size-3); padding: 0 var(--canon-space-2); height: 32px; } -.canon-Button--size-small .canon-Button--icon { +.canon-Button[data-size="small"] .canon-Button--icon { width: 1rem; height: 1rem; } -.canon-Button--size-medium .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-Button--icon { width: 1.5rem; height: 1.5rem; } @@ -348,7 +348,7 @@ } } -.canon-IconButton--variant-primary { +.canon-IconButton[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -372,7 +372,7 @@ } } -.canon-IconButton--variant-secondary { +.canon-IconButton[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -398,24 +398,24 @@ } } -.canon-IconButton--size-medium { +.canon-IconButton[data-size="medium"] { font-size: var(--canon-font-size-4); width: 40px; height: 40px; } -.canon-IconButton--size-small { +.canon-IconButton[data-size="small"] { font-size: var(--canon-font-size-3); width: 32px; height: 32px; } -.canon-IconButton--size-small .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButton--icon { width: 1rem; height: 1rem; } -.canon-IconButton--size-medium .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButton--icon { width: 1.5rem; height: 1.5rem; } @@ -487,11 +487,11 @@ border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input-size-small { +.canon-TextField--input[data-size="small"] { height: 2rem; } -.canon-TextField--input-size-medium { +.canon-TextField--input[data-size="medium"] { height: 2.5rem; } @@ -572,31 +572,31 @@ } } -.canon-Link--variant-body { +.canon-Link[data-variant="body"] { font-size: var(--canon-font-size-3); line-height: 140%; } -.canon-Link--variant-subtitle { +.canon-Link[data-variant="subtitle"] { font-size: var(--canon-font-size-4); line-height: 140%; } -.canon-Link--variant-caption { +.canon-Link[data-variant="caption"] { font-size: var(--canon-font-size-2); line-height: 140%; } -.canon-Link--variant-label { +.canon-Link[data-variant="label"] { font-size: var(--canon-font-size-1); line-height: 140%; } -.canon-Link--weight-regular { +.canon-Link[data-weight="regular"] { font-weight: var(--canon-font-weight-regular); } -.canon-Link--weight-bold { +.canon-Link[data-weight="bold"] { font-weight: var(--canon-font-weight-bold); } @@ -789,11 +789,11 @@ color: var(--canon-fg-disabled); } -.canon-Select--trigger-size-small { +.canon-Select--trigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger-size-medium { +.canon-Select--trigger[data-size="medium"] { height: 3rem; } diff --git a/packages/canon/css/iconbutton.css b/packages/canon/css/iconbutton.css index 7853c59770..da38b40ba1 100644 --- a/packages/canon/css/iconbutton.css +++ b/packages/canon/css/iconbutton.css @@ -16,7 +16,7 @@ } } -.canon-IconButton--variant-primary { +.canon-IconButton[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -40,7 +40,7 @@ } } -.canon-IconButton--variant-secondary { +.canon-IconButton[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -66,24 +66,24 @@ } } -.canon-IconButton--size-medium { +.canon-IconButton[data-size="medium"] { font-size: var(--canon-font-size-4); width: 40px; height: 40px; } -.canon-IconButton--size-small { +.canon-IconButton[data-size="small"] { font-size: var(--canon-font-size-3); width: 32px; height: 32px; } -.canon-IconButton--size-small .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButton--icon { width: 1rem; height: 1rem; } -.canon-IconButton--size-medium .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButton--icon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/css/link.css b/packages/canon/css/link.css index ddc47c5d04..535beb3d9f 100644 --- a/packages/canon/css/link.css +++ b/packages/canon/css/link.css @@ -16,30 +16,30 @@ } } -.canon-Link--variant-body { +.canon-Link[data-variant="body"] { font-size: var(--canon-font-size-3); line-height: 140%; } -.canon-Link--variant-subtitle { +.canon-Link[data-variant="subtitle"] { font-size: var(--canon-font-size-4); line-height: 140%; } -.canon-Link--variant-caption { +.canon-Link[data-variant="caption"] { font-size: var(--canon-font-size-2); line-height: 140%; } -.canon-Link--variant-label { +.canon-Link[data-variant="label"] { font-size: var(--canon-font-size-1); line-height: 140%; } -.canon-Link--weight-regular { +.canon-Link[data-weight="regular"] { font-weight: var(--canon-font-weight-regular); } -.canon-Link--weight-bold { +.canon-Link[data-weight="bold"] { font-weight: var(--canon-font-weight-bold); } diff --git a/packages/canon/css/select.css b/packages/canon/css/select.css index 29494c634a..3c37952afd 100644 --- a/packages/canon/css/select.css +++ b/packages/canon/css/select.css @@ -74,11 +74,11 @@ color: var(--canon-fg-disabled); } -.canon-Select--trigger-size-small { +.canon-Select--trigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger-size-medium { +.canon-Select--trigger[data-size="medium"] { height: 3rem; } diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index d3e61ff556..e4375692f9 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9246,7 +9246,7 @@ } } -.canon-Button--variant-primary { +.canon-Button[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -9270,7 +9270,7 @@ } } -.canon-Button--variant-secondary { +.canon-Button[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -9296,24 +9296,24 @@ } } -.canon-Button--size-medium { +.canon-Button[data-size="medium"] { font-size: var(--canon-font-size-4); padding: 0 var(--canon-space-3); height: 40px; } -.canon-Button--size-small { +.canon-Button[data-size="small"] { font-size: var(--canon-font-size-3); padding: 0 var(--canon-space-2); height: 32px; } -.canon-Button--size-small .canon-Button--icon { +.canon-Button[data-size="small"] .canon-Button--icon { width: 1rem; height: 1rem; } -.canon-Button--size-medium .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-Button--icon { width: 1.5rem; height: 1.5rem; } @@ -9572,7 +9572,7 @@ } } -.canon-IconButton--variant-primary { +.canon-IconButton[data-variant="primary"] { background-color: var(--canon-bg-solid); color: var(--canon-fg-solid); transition: background-color .15s, box-shadow .15s; @@ -9596,7 +9596,7 @@ } } -.canon-IconButton--variant-secondary { +.canon-IconButton[data-variant="secondary"] { background-color: var(--canon-bg-surface-1); box-shadow: inset 0 0 0 1px var(--canon-border); color: var(--canon-fg-primary); @@ -9622,24 +9622,24 @@ } } -.canon-IconButton--size-medium { +.canon-IconButton[data-size="medium"] { font-size: var(--canon-font-size-4); width: 40px; height: 40px; } -.canon-IconButton--size-small { +.canon-IconButton[data-size="small"] { font-size: var(--canon-font-size-3); width: 32px; height: 32px; } -.canon-IconButton--size-small .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButton--icon { width: 1rem; height: 1rem; } -.canon-IconButton--size-medium .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButton--icon { width: 1.5rem; height: 1.5rem; } @@ -9711,11 +9711,11 @@ border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input-size-small { +.canon-TextField--input[data-size="small"] { height: 2rem; } -.canon-TextField--input-size-medium { +.canon-TextField--input[data-size="medium"] { height: 2.5rem; } @@ -9796,31 +9796,31 @@ } } -.canon-Link--variant-body { +.canon-Link[data-variant="body"] { font-size: var(--canon-font-size-3); line-height: 140%; } -.canon-Link--variant-subtitle { +.canon-Link[data-variant="subtitle"] { font-size: var(--canon-font-size-4); line-height: 140%; } -.canon-Link--variant-caption { +.canon-Link[data-variant="caption"] { font-size: var(--canon-font-size-2); line-height: 140%; } -.canon-Link--variant-label { +.canon-Link[data-variant="label"] { font-size: var(--canon-font-size-1); line-height: 140%; } -.canon-Link--weight-regular { +.canon-Link[data-weight="regular"] { font-weight: var(--canon-font-weight-regular); } -.canon-Link--weight-bold { +.canon-Link[data-weight="bold"] { font-weight: var(--canon-font-weight-bold); } @@ -10013,11 +10013,11 @@ color: var(--canon-fg-disabled); } -.canon-Select--trigger-size-small { +.canon-Select--trigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger-size-medium { +.canon-Select--trigger[data-size="medium"] { height: 3rem; } diff --git a/packages/canon/css/textfield.css b/packages/canon/css/textfield.css index a542690580..eb43b1f77f 100644 --- a/packages/canon/css/textfield.css +++ b/packages/canon/css/textfield.css @@ -65,11 +65,11 @@ border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input-size-small { +.canon-TextField--input[data-size="small"] { height: 2rem; } -.canon-TextField--input-size-medium { +.canon-TextField--input[data-size="medium"] { height: 2.5rem; } From 32d5f0e0a512a571f48ac1726189297a0525f54c Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Sun, 13 Apr 2025 08:40:52 +0200 Subject: [PATCH 21/26] Add new TableCells Signed-off-by: Charles de Dreuille --- packages/canon/css/components.css | 6 ++ packages/canon/css/styles.css | 6 ++ packages/canon/css/table.css | 26 -------- packages/canon/report.api.md | 66 +++++++++++-------- .../src/components/DataTable/DataTable.tsx | 42 ++---------- .../components/DataTable/mocked-columns.tsx | 33 +++++----- packages/canon/src/components/Table/Table.tsx | 14 ++-- .../Table/TableCell/TableCell.stories.tsx | 32 +++++++++ .../Table/TableCell/TableCell.styles.css | 20 ++++++ .../components/Table/TableCell/TableCell.tsx | 29 ++++++++ .../TableCellLink/TableCellLink.stories.tsx | 40 +++++++++++ .../TableCellLink/TableCellLink.styles.css | 21 ++++++ .../Table/TableCellLink/TableCellLink.tsx | 46 +++++++++++++ .../components/Table/TableCellLink/types.ts | 26 ++++++++ .../TableCellText/TableCellText.stories.tsx | 39 +++++++++++ .../TableCellText/TableCellText.styles.css | 21 ++++++ .../Table/TableCellText/TableCellText.tsx | 41 ++++++++++++ .../components/Table/TableCellText/types.ts | 22 +++++++ packages/canon/src/components/Table/index.ts | 2 + .../canon/src/components/Table/styles.css | 5 -- packages/canon/src/css/components.css | 3 + 21 files changed, 424 insertions(+), 116 deletions(-) create mode 100644 packages/canon/src/components/Table/TableCell/TableCell.stories.tsx create mode 100644 packages/canon/src/components/Table/TableCell/TableCell.styles.css create mode 100644 packages/canon/src/components/Table/TableCell/TableCell.tsx create mode 100644 packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx create mode 100644 packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css create mode 100644 packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx create mode 100644 packages/canon/src/components/Table/TableCellLink/types.ts create mode 100644 packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx create mode 100644 packages/canon/src/components/Table/TableCellText/TableCellText.styles.css create mode 100644 packages/canon/src/components/Table/TableCellText/TableCellText.tsx create mode 100644 packages/canon/src/components/Table/TableCellText/types.ts diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index 4dae0f5d3a..af4ea8c4f0 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -240,6 +240,12 @@ font-size: var(--canon-font-size-3); } +.canon-TableCellText, .canon-TableCellLink { + gap: var(--canon-space-0_5); + flex-direction: column; + display: flex; +} + .canon-Text { font-family: var(--canon-font-regular); color: var(--canon-fg-primary); diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index a166a67263..2230922917 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9464,6 +9464,12 @@ font-size: var(--canon-font-size-3); } +.canon-TableCellText, .canon-TableCellLink { + gap: var(--canon-space-0_5); + flex-direction: column; + display: flex; +} + .canon-Text { font-family: var(--canon-font-regular); color: var(--canon-fg-primary); diff --git a/packages/canon/css/table.css b/packages/canon/css/table.css index c27fe3235d..f14ee3759e 100644 --- a/packages/canon/css/table.css +++ b/packages/canon/css/table.css @@ -1,29 +1,3 @@ -.canon-TableRoot { - caption-side: bottom; - border-collapse: collapse; - width: 100%; -} - -.canon-TableHead { - text-align: left; - padding: var(--canon-space-3); - font-size: var(--canon-font-size-3); - color: var(--canon-fg-primary); -} - -.canon-TableBody { - color: var(--canon-fg-primary); -} - -.canon-TableRow { - border-bottom: 1px solid var(--canon-border); - transition: color .2s ease-in-out; -} - -.canon-TableBody .canon-TableRow:hover { - background-color: var(--canon-gray-2); -} - .canon-TableCell { padding: var(--canon-space-3); font-size: var(--canon-font-size-3); diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index ec53a49a92..44d6a3dd44 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -241,43 +241,27 @@ export const DataTable: { RefAttributes >; TableHeader: ForwardRefExoticComponent< - Omit< - HTMLAttributes & - RefAttributes, - 'ref' - > & + HTMLAttributes & RefAttributes >; TableBody: ForwardRefExoticComponent< - Omit< - HTMLAttributes & - RefAttributes, - 'ref' - > & + HTMLAttributes & RefAttributes >; TableRow: ForwardRefExoticComponent< - Omit< - HTMLAttributes & RefAttributes, - 'ref' - > & - RefAttributes + HTMLAttributes & RefAttributes >; TableCell: ForwardRefExoticComponent< - Omit< - TdHTMLAttributes & - RefAttributes, - 'ref' - > & - RefAttributes + TdHTMLAttributes & RefAttributes + >; + TableCellText: ForwardRefExoticComponent< + TableCellTextProps & RefAttributes + >; + TableCellLink: ForwardRefExoticComponent< + TableCellLinkProps & RefAttributes >; TableHead: ForwardRefExoticComponent< - Omit< - ThHTMLAttributes & - RefAttributes, - 'ref' - > & - RefAttributes + ThHTMLAttributes & RefAttributes >; }; @@ -1126,12 +1110,40 @@ export const Table: { Cell: ForwardRefExoticComponent< TdHTMLAttributes & RefAttributes >; + CellText: ForwardRefExoticComponent< + TableCellTextProps & RefAttributes + >; + CellLink: ForwardRefExoticComponent< + TableCellLinkProps & RefAttributes + >; Caption: ForwardRefExoticComponent< HTMLAttributes & RefAttributes >; }; +// @public (undocumented) +export interface TableCellLinkProps + extends React.TdHTMLAttributes { + // (undocumented) + description?: string; + // (undocumented) + href: string; + // (undocumented) + render?: useRender.ComponentProps<'a'>['render']; + // (undocumented) + title: string; +} + +// @public (undocumented) +export interface TableCellTextProps + extends React.TdHTMLAttributes { + // (undocumented) + description?: string; + // (undocumented) + title: string; +} + // @public (undocumented) const Text_2: ForwardRefExoticComponent< TextProps & RefAttributes diff --git a/packages/canon/src/components/DataTable/DataTable.tsx b/packages/canon/src/components/DataTable/DataTable.tsx index 44e32fa404..8be9ae174e 100644 --- a/packages/canon/src/components/DataTable/DataTable.tsx +++ b/packages/canon/src/components/DataTable/DataTable.tsx @@ -27,36 +27,6 @@ const TableRoot = forwardRef< >(({ className, ...props }, ref) => ); TableRoot.displayName = Table.Root.displayName; -const TableHeader = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableHeader.displayName = Table.Header.displayName; - -const TableBody = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableBody.displayName = Table.Body.displayName; - -const TableRow = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableRow.displayName = Table.Row.displayName; - -const TableCell = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableCell.displayName = Table.Cell.displayName; - -const TableHead = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ); -TableHead.displayName = Table.Head.displayName; - /** * DataTable component for displaying tabular data with pagination * @public @@ -70,9 +40,11 @@ export const DataTable = { Pagination: DataTablePagination, Table: DataTableTable, TableRoot: TableRoot, - TableHeader: TableHeader, - TableBody: TableBody, - TableRow: TableRow, - TableCell: TableCell, - TableHead: TableHead, + TableHeader: Table.Header, + TableBody: Table.Body, + TableRow: Table.Row, + TableCell: Table.Cell, + TableCellText: Table.CellText, + TableCellLink: Table.CellLink, + TableHead: Table.Head, }; diff --git a/packages/canon/src/components/DataTable/mocked-columns.tsx b/packages/canon/src/components/DataTable/mocked-columns.tsx index e140f41702..9f2ce72378 100644 --- a/packages/canon/src/components/DataTable/mocked-columns.tsx +++ b/packages/canon/src/components/DataTable/mocked-columns.tsx @@ -17,7 +17,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { DataProps } from './mocked-components'; import { Checkbox } from '../Checkbox'; -import { Text } from '../Text'; +import { DataTable } from './DataTable'; export const columns: ColumnDef[] = [ { @@ -32,11 +32,13 @@ export const columns: ColumnDef[] = [ /> ), cell: ({ row }) => ( - row.toggleSelected(checked)} - aria-label="Select row" - /> +
+ row.toggleSelected(checked)} + aria-label="Select row" + /> + -)); -TableCell.displayName = 'TableCell'; - const TableCaption = forwardRef< HTMLTableCaptionElement, React.HTMLAttributes @@ -93,5 +89,7 @@ export const Table = { Head: TableHead, Row: TableRow, Cell: TableCell, + CellText: TableCellText, + CellLink: TableCellLink, Caption: TableCaption, }; diff --git a/packages/canon/src/components/Table/TableCell/TableCell.stories.tsx b/packages/canon/src/components/Table/TableCell/TableCell.stories.tsx new file mode 100644 index 0000000000..123dca6e39 --- /dev/null +++ b/packages/canon/src/components/Table/TableCell/TableCell.stories.tsx @@ -0,0 +1,32 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableCell } from './TableCell'; + +const meta = { + title: 'Components/Table/TableCell', + component: TableCell, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Hello world', + }, +}; diff --git a/packages/canon/src/components/Table/TableCell/TableCell.styles.css b/packages/canon/src/components/Table/TableCell/TableCell.styles.css new file mode 100644 index 0000000000..26d0868b49 --- /dev/null +++ b/packages/canon/src/components/Table/TableCell/TableCell.styles.css @@ -0,0 +1,20 @@ +/* + * 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. + */ + +.canon-TableCell { + padding: var(--canon-space-3); + font-size: var(--canon-font-size-3); +} diff --git a/packages/canon/src/components/Table/TableCell/TableCell.tsx b/packages/canon/src/components/Table/TableCell/TableCell.tsx new file mode 100644 index 0000000000..a8a87ac038 --- /dev/null +++ b/packages/canon/src/components/Table/TableCell/TableCell.tsx @@ -0,0 +1,29 @@ +/* + * 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 { forwardRef } from 'react'; +import clsx from 'clsx'; + +/** @public */ +const TableCell = forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableCell.displayName = 'TableCell'; + +export { TableCell }; diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx b/packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx new file mode 100644 index 0000000000..861f2643b2 --- /dev/null +++ b/packages/canon/src/components/Table/TableCellLink/TableCellLink.stories.tsx @@ -0,0 +1,40 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableCellLink } from './TableCellLink'; + +const meta = { + title: 'Components/Table/TableCellLink', + component: TableCellLink, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + title: 'I am a link', + href: 'https://canon.backstage.io', + }, +}; + +export const WithDescription: Story = { + args: { + ...Default.args, + description: 'This is a description', + }, +}; diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css b/packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css new file mode 100644 index 0000000000..3064bbb791 --- /dev/null +++ b/packages/canon/src/components/Table/TableCellLink/TableCellLink.styles.css @@ -0,0 +1,21 @@ +/* + * 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. + */ + +.canon-TableCellLink { + display: flex; + flex-direction: column; + gap: var(--canon-space-0_5); +} diff --git a/packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx b/packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx new file mode 100644 index 0000000000..cb9d3e69a8 --- /dev/null +++ b/packages/canon/src/components/Table/TableCellLink/TableCellLink.tsx @@ -0,0 +1,46 @@ +/* + * 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 { forwardRef } from 'react'; +import clsx from 'clsx'; +import { TableCellLinkProps } from './types'; +import { Text } from '../../Text/Text'; +import { Link } from '../../Link/Link'; + +/** @public */ +const TableCellLink = forwardRef( + ({ className, title, description, href, render, ...props }, ref) => ( +
+ {title && ( + + {title} + + )} + {description && ( + + {description} + + )} +
+ ), +); +TableCellLink.displayName = 'TableCellLink'; + +export { TableCellLink }; diff --git a/packages/canon/src/components/Table/TableCellLink/types.ts b/packages/canon/src/components/Table/TableCellLink/types.ts new file mode 100644 index 0000000000..50cac9a45a --- /dev/null +++ b/packages/canon/src/components/Table/TableCellLink/types.ts @@ -0,0 +1,26 @@ +/* + * 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 type { useRender } from '@base-ui-components/react/use-render'; + +/** @public */ +export interface TableCellLinkProps + extends React.TdHTMLAttributes { + title: string; + description?: string; + href: string; + render?: useRender.ComponentProps<'a'>['render']; +} diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx b/packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx new file mode 100644 index 0000000000..3756dd2544 --- /dev/null +++ b/packages/canon/src/components/Table/TableCellText/TableCellText.stories.tsx @@ -0,0 +1,39 @@ +/* + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableCellText } from './TableCellText'; + +const meta = { + title: 'Components/Table/TableCellText', + component: TableCellText, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + title: 'Hello world', + }, +}; + +export const WithDescription: Story = { + args: { + ...Default.args, + description: 'This is a description', + }, +}; diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.styles.css b/packages/canon/src/components/Table/TableCellText/TableCellText.styles.css new file mode 100644 index 0000000000..7a645a1fcb --- /dev/null +++ b/packages/canon/src/components/Table/TableCellText/TableCellText.styles.css @@ -0,0 +1,21 @@ +/* + * 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. + */ + +.canon-TableCellText { + display: flex; + flex-direction: column; + gap: var(--canon-space-0_5); +} diff --git a/packages/canon/src/components/Table/TableCellText/TableCellText.tsx b/packages/canon/src/components/Table/TableCellText/TableCellText.tsx new file mode 100644 index 0000000000..d5496d799b --- /dev/null +++ b/packages/canon/src/components/Table/TableCellText/TableCellText.tsx @@ -0,0 +1,41 @@ +/* + * 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 { forwardRef } from 'react'; +import clsx from 'clsx'; +import { TableCellTextProps } from './types'; +import { Text } from '../../Text/Text'; + +/** @public */ +const TableCellText = forwardRef( + ({ className, title, description, ...props }, ref) => ( +
+ {title && {title}} + {description && ( + + {description} + + )} +
+ ), +); +TableCellText.displayName = 'TableCellText'; + +export { TableCellText }; diff --git a/packages/canon/src/components/Table/TableCellText/types.ts b/packages/canon/src/components/Table/TableCellText/types.ts new file mode 100644 index 0000000000..c6f1814966 --- /dev/null +++ b/packages/canon/src/components/Table/TableCellText/types.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** @public */ +export interface TableCellTextProps + extends React.TdHTMLAttributes { + title: string; + description?: string; +} diff --git a/packages/canon/src/components/Table/index.ts b/packages/canon/src/components/Table/index.ts index 4929b2d36a..0422086b45 100644 --- a/packages/canon/src/components/Table/index.ts +++ b/packages/canon/src/components/Table/index.ts @@ -15,3 +15,5 @@ */ export * from './Table'; +export * from './TableCellText/types'; +export * from './TableCellLink/types'; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css index 4234095823..723287babe 100644 --- a/packages/canon/src/components/Table/styles.css +++ b/packages/canon/src/components/Table/styles.css @@ -23,8 +23,3 @@ .canon-TableBody .canon-TableRow:hover { background-color: var(--canon-gray-2); } - -.canon-TableCell { - padding: var(--canon-space-3); - font-size: var(--canon-font-size-3); -} diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index f6b1db16c5..7dee4afb97 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -24,6 +24,9 @@ @import '../components/Icon/styles.css'; @import '../components/Checkbox/styles.css'; @import '../components/Table/styles.css'; +@import '../components/Table/TableCell/TableCell.styles.css'; +@import '../components/Table/TableCellText/TableCellText.styles.css'; +@import '../components/Table/TableCellLink/TableCellLink.styles.css'; @import '../components/Text/styles.css'; @import '../components/Heading/styles.css'; @import '../components/IconButton/styles.css'; From 4b8db95f4f5f97839bbb0246d15c8582f204e5f4 Mon Sep 17 00:00:00 2001 From: patroswastik Date: Sun, 13 Apr 2025 06:08:41 -0500 Subject: [PATCH 22/26] went up the tree to locate createRouter and found deprecated over there Signed-off-by: patroswastik --- .../lint-legacy-backend-exports.ts | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts index 0ebc7088e3..29fb4e7b20 100644 --- a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts +++ b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts @@ -47,9 +47,6 @@ function verifyIndex(pkg: string, packageJson?: BackstagePackageJson) { const tsPath = path.join(pkg, 'src/index.ts'); const sourceFile = project.getSourceFile(tsPath); - const tsRouterPath = path.join(pkg, 'src/service/router.ts'); - const routerFile = project.getSourceFile(tsRouterPath); - if (!sourceFile) { console.log(`Could not find ${tsPath}`); process.exit(1); @@ -74,23 +71,28 @@ function verifyIndex(pkg: string, packageJson?: BackstagePackageJson) { console.log(' ❌ Missing default export'); } let createRouterDeprecated = undefined; + let routerCreateRouterDeprecated = undefined; if (createRouterExport) { createRouterDeprecated = createRouterExport .getJsDocTags() .find(tag => tag.getName() === 'deprecated'); - } - let routerCreateRouterDeprecated = undefined; - if (routerFile) { - const routerSymbols = routerFile?.getExportSymbols(); - const routerCreateRouterExport = routerSymbols?.find( - symbol => symbol.getName() === 'createRouter', - ); - - if (routerCreateRouterExport) { - routerCreateRouterDeprecated = routerCreateRouterExport - .getJsDocTags() - .find(tag => tag.getName() === 'deprecated'); + const declarations = createRouterExport?.getDeclarations(); + const firstDeclaration = declarations?.[0]; + let resolvedSymbol = undefined; + if (firstDeclaration) { + // Try resolving to the definition directly + resolvedSymbol = createRouterExport.getAliasedSymbol(); + if (resolvedSymbol) { + const resolvedDeclarations = resolvedSymbol.getDeclarations(); + const resolvedDeclaration = resolvedDeclarations?.[0]; + if (resolvedDeclaration) { + routerCreateRouterDeprecated = resolvedDeclaration + .getSymbol() + ?.getJsDocTags() + .find(tag => tag.getName() === 'deprecated'); + } + } } } From 7d0bd52f7ac6ede005fc57edd23e33fea564f5f4 Mon Sep 17 00:00:00 2001 From: patroswastik Date: Sun, 13 Apr 2025 06:43:39 -0500 Subject: [PATCH 23/26] Changeset updated with relevant description of the fix Signed-off-by: patroswastik --- .changeset/rich-phones-whisper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rich-phones-whisper.md b/.changeset/rich-phones-whisper.md index c27b6de2f8..31d4bdb57f 100644 --- a/.changeset/rich-phones-whisper.md +++ b/.changeset/rich-phones-whisper.md @@ -2,4 +2,4 @@ '@backstage/repo-tools': minor --- -Checking through router.ts files of the packages if they exist and looking for deprecated tag inside it. If exists then only the message will appear +Checking up the files where createRouter has been declared and check if @deprecated tag exists. If it does not exist then only the message will appear. From 06aa4bdc69e0958215f668f66058f1815cdfd636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 14 Apr 2025 10:59:36 +0200 Subject: [PATCH 24/26] Update .changeset/rich-phones-whisper.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/rich-phones-whisper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rich-phones-whisper.md b/.changeset/rich-phones-whisper.md index 31d4bdb57f..3f3c226690 100644 --- a/.changeset/rich-phones-whisper.md +++ b/.changeset/rich-phones-whisper.md @@ -2,4 +2,4 @@ '@backstage/repo-tools': minor --- -Checking up the files where createRouter has been declared and check if @deprecated tag exists. If it does not exist then only the message will appear. +Checking up the files where `createRouter` has been declared and check if `@deprecated` tag exists. If it does not exist then only the message will appear. From 9663a04fcde1cb9bc05ef06f7239f85c6fb4625d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 14 Apr 2025 10:59:41 +0200 Subject: [PATCH 25/26] Update .changeset/rich-phones-whisper.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/rich-phones-whisper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rich-phones-whisper.md b/.changeset/rich-phones-whisper.md index 3f3c226690..75f0fc0c35 100644 --- a/.changeset/rich-phones-whisper.md +++ b/.changeset/rich-phones-whisper.md @@ -1,5 +1,5 @@ --- -'@backstage/repo-tools': minor +'@backstage/repo-tools': patch --- Checking up the files where `createRouter` has been declared and check if `@deprecated` tag exists. If it does not exist then only the message will appear. From 62443c60e819a49ba55e25ed681db25730f117e0 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 14 Apr 2025 11:42:38 +0200 Subject: [PATCH 26/26] Update sub components naming Signed-off-by: Charles de Dreuille --- packages/canon/css/button.css | 4 +- packages/canon/css/components.css | 80 +++++++++---------- packages/canon/css/iconbutton.css | 4 +- packages/canon/css/select.css | 48 +++++------ packages/canon/css/styles.css | 80 +++++++++---------- packages/canon/css/textfield.css | 24 +++--- .../canon/src/components/Button/Button.tsx | 4 +- .../canon/src/components/Button/styles.css | 4 +- .../src/components/IconButton/IconButton.tsx | 2 +- .../src/components/IconButton/styles.css | 4 +- .../src/components/Select/Select.styles.css | 52 ++++++------ .../canon/src/components/Select/Select.tsx | 22 ++--- .../components/TextField/TextField.styles.css | 24 +++--- .../src/components/TextField/TextField.tsx | 10 +-- 14 files changed, 181 insertions(+), 181 deletions(-) diff --git a/packages/canon/css/button.css b/packages/canon/css/button.css index ccfc3b48f5..eb0c44ce1b 100644 --- a/packages/canon/css/button.css +++ b/packages/canon/css/button.css @@ -78,12 +78,12 @@ height: 32px; } -.canon-Button[data-size="small"] .canon-Button--icon { +.canon-Button[data-size="small"] .canon-ButtonIcon { width: 1rem; height: 1rem; } -.canon-Button[data-size="medium"] .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-ButtonIcon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/css/components.css b/packages/canon/css/components.css index 216f38c968..5139e45c22 100644 --- a/packages/canon/css/components.css +++ b/packages/canon/css/components.css @@ -84,12 +84,12 @@ height: 32px; } -.canon-Button[data-size="small"] .canon-Button--icon { +.canon-Button[data-size="small"] .canon-ButtonIcon { width: 1rem; height: 1rem; } -.canon-Button[data-size="medium"] .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-ButtonIcon { width: 1.5rem; height: 1.5rem; } @@ -410,12 +410,12 @@ height: 32px; } -.canon-IconButton[data-size="small"] .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButtonIcon { width: 1rem; height: 1rem; } -.canon-IconButton[data-size="medium"] .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButtonIcon { width: 1.5rem; height: 1.5rem; } @@ -427,14 +427,14 @@ display: flex; } -.canon-TextField--label { +.canon-TextFieldLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-TextField--description { +.canon-TextFieldDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -442,7 +442,7 @@ margin: 0; } -.canon-TextField--error { +.canon-TextFieldError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -450,7 +450,7 @@ margin: 0; } -.canon-TextField--input { +.canon-TextFieldInput { border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); padding: 0 var(--canon-space-4); @@ -463,39 +463,39 @@ transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; } -.canon-TextField--input::placeholder { +.canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } -.canon-TextField--input:hover { +.canon-TextFieldInput:hover { border-color: var(--canon-border-hover); } -.canon-TextField--input:focus-visible { +.canon-TextFieldInput:focus-visible { outline-color: var(--canon-border-pressed); border-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextField--input[data-invalid] { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField--input[data-disabled] { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input[data-size="small"] { +.canon-TextFieldInput[data-size="small"] { height: 2rem; } -.canon-TextField--input[data-size="medium"] { +.canon-TextFieldInput[data-size="medium"] { height: 2.5rem; } -.canon-TextField--required { +.canon-TextFieldRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); @@ -720,14 +720,14 @@ display: flex; } -.canon-Select--label { +.canon-SelectLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-Select--description { +.canon-SelectDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -735,7 +735,7 @@ margin: 0; } -.canon-Select--error { +.canon-SelectError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -743,7 +743,7 @@ margin: 0; } -.canon-Select--trigger { +.canon-SelectTrigger { box-sizing: border-box; border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); @@ -762,38 +762,38 @@ display: flex; } -.canon-Select--trigger::placeholder { +.canon-SelectTrigger::placeholder { color: var(--canon-fg-secondary); } -.canon-Select--trigger:hover { +.canon-SelectTrigger:hover { border-color: var(--canon-border-hover); } -.canon-Select--trigger:focus-visible { +.canon-SelectTrigger:focus-visible { border-color: var(--canon-border-pressed); outline: 0; } -.canon-Select--trigger[data-invalid] { +.canon-SelectTrigger[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-Select--trigger[data-invalid]:hover, .canon-Select--trigger[data-invalid]:focus-visible { +.canon-SelectTrigger[data-invalid]:hover, .canon-SelectTrigger[data-invalid]:focus-visible { border-width: 2px; } -.canon-Select--trigger[data-disabled] { +.canon-SelectTrigger[data-disabled] { cursor: not-allowed; border-color: var(--canon-border-disabled); color: var(--canon-fg-disabled); } -.canon-Select--trigger[data-size="small"] { +.canon-SelectTrigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger[data-size="medium"] { +.canon-SelectTrigger[data-size="medium"] { height: 3rem; } @@ -802,11 +802,11 @@ transition: transform .2s; } -.canon-Select--trigger[data-popup-open] .canon-SelectIcon { +.canon-SelectTrigger[data-popup-open] .canon-SelectIcon { transform: rotate(180deg); } -.canon-Select--popup { +.canon-SelectPopup { box-sizing: border-box; max-height: var(--available-height); background-color: var(--canon-bg-surface-1); @@ -821,12 +821,12 @@ box-shadow: 0 4px 12px #0003; } -.canon-Select--popup[data-starting-style], .canon-Select--popup[data-ending-style] { +.canon-SelectPopup[data-starting-style], .canon-SelectPopup[data-ending-style] { opacity: 0; transform: scale(.9); } -.canon-Select--item { +.canon-SelectItem { width: var(--anchor-width); padding-block: var(--canon-space-2); padding-inline: var(--canon-space-4); @@ -844,13 +844,13 @@ position: relative; } -.canon-Select--item[data-highlighted] { +.canon-SelectItem[data-highlighted] { z-index: 0; color: var(--canon-fg-primary); position: relative; } -.canon-Select--item[data-highlighted]:before { +.canon-SelectItem[data-highlighted]:before { content: ""; z-index: -1; background-color: var(--canon-bg-tint-hover); @@ -860,37 +860,37 @@ inset-inline: .25rem; } -.canon-Select--item[data-disabled] { +.canon-SelectItem[data-disabled] { cursor: not-allowed; color: var(--canon-fg-disabled); } -.canon-Select--item-indicator { +.canon-SelectItemIndicator { grid-area: icon; justify-content: center; align-items: center; display: flex; } -.canon-Select--item-text { +.canon-SelectItemText { flex: 1; grid-area: text; } -.canon-Select--required { +.canon-SelectRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); margin-left: var(--canon-space-1); } -.canon-Select--icon { +.canon-SelectIcon { justify-content: center; align-items: center; display: flex; } -.canon-Select--value { +.canon-SelectValue { text-overflow: ellipsis; white-space: nowrap; width: 100%; diff --git a/packages/canon/css/iconbutton.css b/packages/canon/css/iconbutton.css index da38b40ba1..e867a1848e 100644 --- a/packages/canon/css/iconbutton.css +++ b/packages/canon/css/iconbutton.css @@ -78,12 +78,12 @@ height: 32px; } -.canon-IconButton[data-size="small"] .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButtonIcon { width: 1rem; height: 1rem; } -.canon-IconButton[data-size="medium"] .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButtonIcon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/css/select.css b/packages/canon/css/select.css index 3c37952afd..cf8c05622b 100644 --- a/packages/canon/css/select.css +++ b/packages/canon/css/select.css @@ -5,14 +5,14 @@ display: flex; } -.canon-Select--label { +.canon-SelectLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-Select--description { +.canon-SelectDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -20,7 +20,7 @@ margin: 0; } -.canon-Select--error { +.canon-SelectError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -28,7 +28,7 @@ margin: 0; } -.canon-Select--trigger { +.canon-SelectTrigger { box-sizing: border-box; border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); @@ -47,38 +47,38 @@ display: flex; } -.canon-Select--trigger::placeholder { +.canon-SelectTrigger::placeholder { color: var(--canon-fg-secondary); } -.canon-Select--trigger:hover { +.canon-SelectTrigger:hover { border-color: var(--canon-border-hover); } -.canon-Select--trigger:focus-visible { +.canon-SelectTrigger:focus-visible { border-color: var(--canon-border-pressed); outline: 0; } -.canon-Select--trigger[data-invalid] { +.canon-SelectTrigger[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-Select--trigger[data-invalid]:hover, .canon-Select--trigger[data-invalid]:focus-visible { +.canon-SelectTrigger[data-invalid]:hover, .canon-SelectTrigger[data-invalid]:focus-visible { border-width: 2px; } -.canon-Select--trigger[data-disabled] { +.canon-SelectTrigger[data-disabled] { cursor: not-allowed; border-color: var(--canon-border-disabled); color: var(--canon-fg-disabled); } -.canon-Select--trigger[data-size="small"] { +.canon-SelectTrigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger[data-size="medium"] { +.canon-SelectTrigger[data-size="medium"] { height: 3rem; } @@ -87,11 +87,11 @@ transition: transform .2s; } -.canon-Select--trigger[data-popup-open] .canon-SelectIcon { +.canon-SelectTrigger[data-popup-open] .canon-SelectIcon { transform: rotate(180deg); } -.canon-Select--popup { +.canon-SelectPopup { box-sizing: border-box; max-height: var(--available-height); background-color: var(--canon-bg-surface-1); @@ -106,12 +106,12 @@ box-shadow: 0 4px 12px #0003; } -.canon-Select--popup[data-starting-style], .canon-Select--popup[data-ending-style] { +.canon-SelectPopup[data-starting-style], .canon-SelectPopup[data-ending-style] { opacity: 0; transform: scale(.9); } -.canon-Select--item { +.canon-SelectItem { width: var(--anchor-width); padding-block: var(--canon-space-2); padding-inline: var(--canon-space-4); @@ -129,13 +129,13 @@ position: relative; } -.canon-Select--item[data-highlighted] { +.canon-SelectItem[data-highlighted] { z-index: 0; color: var(--canon-fg-primary); position: relative; } -.canon-Select--item[data-highlighted]:before { +.canon-SelectItem[data-highlighted]:before { content: ""; z-index: -1; background-color: var(--canon-bg-tint-hover); @@ -145,37 +145,37 @@ inset-inline: .25rem; } -.canon-Select--item[data-disabled] { +.canon-SelectItem[data-disabled] { cursor: not-allowed; color: var(--canon-fg-disabled); } -.canon-Select--item-indicator { +.canon-SelectItemIndicator { grid-area: icon; justify-content: center; align-items: center; display: flex; } -.canon-Select--item-text { +.canon-SelectItemText { flex: 1; grid-area: text; } -.canon-Select--required { +.canon-SelectRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); margin-left: var(--canon-space-1); } -.canon-Select--icon { +.canon-SelectIcon { justify-content: center; align-items: center; display: flex; } -.canon-Select--value { +.canon-SelectValue { text-overflow: ellipsis; white-space: nowrap; width: 100%; diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index e4375692f9..8af66d68fa 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9308,12 +9308,12 @@ height: 32px; } -.canon-Button[data-size="small"] .canon-Button--icon { +.canon-Button[data-size="small"] .canon-ButtonIcon { width: 1rem; height: 1rem; } -.canon-Button[data-size="medium"] .canon-Button--icon { +.canon-Button[data-size="medium"] .canon-ButtonIcon { width: 1.5rem; height: 1.5rem; } @@ -9634,12 +9634,12 @@ height: 32px; } -.canon-IconButton[data-size="small"] .canon-IconButton--icon { +.canon-IconButton[data-size="small"] .canon-IconButtonIcon { width: 1rem; height: 1rem; } -.canon-IconButton[data-size="medium"] .canon-IconButton--icon { +.canon-IconButton[data-size="medium"] .canon-IconButtonIcon { width: 1.5rem; height: 1.5rem; } @@ -9651,14 +9651,14 @@ display: flex; } -.canon-TextField--label { +.canon-TextFieldLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-TextField--description { +.canon-TextFieldDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -9666,7 +9666,7 @@ margin: 0; } -.canon-TextField--error { +.canon-TextFieldError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -9674,7 +9674,7 @@ margin: 0; } -.canon-TextField--input { +.canon-TextFieldInput { border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); padding: 0 var(--canon-space-4); @@ -9687,39 +9687,39 @@ transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; } -.canon-TextField--input::placeholder { +.canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } -.canon-TextField--input:hover { +.canon-TextFieldInput:hover { border-color: var(--canon-border-hover); } -.canon-TextField--input:focus-visible { +.canon-TextFieldInput:focus-visible { outline-color: var(--canon-border-pressed); border-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextField--input[data-invalid] { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField--input[data-disabled] { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input[data-size="small"] { +.canon-TextFieldInput[data-size="small"] { height: 2rem; } -.canon-TextField--input[data-size="medium"] { +.canon-TextFieldInput[data-size="medium"] { height: 2.5rem; } -.canon-TextField--required { +.canon-TextFieldRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); @@ -9944,14 +9944,14 @@ display: flex; } -.canon-Select--label { +.canon-SelectLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-Select--description { +.canon-SelectDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -9959,7 +9959,7 @@ margin: 0; } -.canon-Select--error { +.canon-SelectError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -9967,7 +9967,7 @@ margin: 0; } -.canon-Select--trigger { +.canon-SelectTrigger { box-sizing: border-box; border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); @@ -9986,38 +9986,38 @@ display: flex; } -.canon-Select--trigger::placeholder { +.canon-SelectTrigger::placeholder { color: var(--canon-fg-secondary); } -.canon-Select--trigger:hover { +.canon-SelectTrigger:hover { border-color: var(--canon-border-hover); } -.canon-Select--trigger:focus-visible { +.canon-SelectTrigger:focus-visible { border-color: var(--canon-border-pressed); outline: 0; } -.canon-Select--trigger[data-invalid] { +.canon-SelectTrigger[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-Select--trigger[data-invalid]:hover, .canon-Select--trigger[data-invalid]:focus-visible { +.canon-SelectTrigger[data-invalid]:hover, .canon-SelectTrigger[data-invalid]:focus-visible { border-width: 2px; } -.canon-Select--trigger[data-disabled] { +.canon-SelectTrigger[data-disabled] { cursor: not-allowed; border-color: var(--canon-border-disabled); color: var(--canon-fg-disabled); } -.canon-Select--trigger[data-size="small"] { +.canon-SelectTrigger[data-size="small"] { height: 2rem; } -.canon-Select--trigger[data-size="medium"] { +.canon-SelectTrigger[data-size="medium"] { height: 3rem; } @@ -10026,11 +10026,11 @@ transition: transform .2s; } -.canon-Select--trigger[data-popup-open] .canon-SelectIcon { +.canon-SelectTrigger[data-popup-open] .canon-SelectIcon { transform: rotate(180deg); } -.canon-Select--popup { +.canon-SelectPopup { box-sizing: border-box; max-height: var(--available-height); background-color: var(--canon-bg-surface-1); @@ -10045,12 +10045,12 @@ box-shadow: 0 4px 12px #0003; } -.canon-Select--popup[data-starting-style], .canon-Select--popup[data-ending-style] { +.canon-SelectPopup[data-starting-style], .canon-SelectPopup[data-ending-style] { opacity: 0; transform: scale(.9); } -.canon-Select--item { +.canon-SelectItem { width: var(--anchor-width); padding-block: var(--canon-space-2); padding-inline: var(--canon-space-4); @@ -10068,13 +10068,13 @@ position: relative; } -.canon-Select--item[data-highlighted] { +.canon-SelectItem[data-highlighted] { z-index: 0; color: var(--canon-fg-primary); position: relative; } -.canon-Select--item[data-highlighted]:before { +.canon-SelectItem[data-highlighted]:before { content: ""; z-index: -1; background-color: var(--canon-bg-tint-hover); @@ -10084,37 +10084,37 @@ inset-inline: .25rem; } -.canon-Select--item[data-disabled] { +.canon-SelectItem[data-disabled] { cursor: not-allowed; color: var(--canon-fg-disabled); } -.canon-Select--item-indicator { +.canon-SelectItemIndicator { grid-area: icon; justify-content: center; align-items: center; display: flex; } -.canon-Select--item-text { +.canon-SelectItemText { flex: 1; grid-area: text; } -.canon-Select--required { +.canon-SelectRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); margin-left: var(--canon-space-1); } -.canon-Select--icon { +.canon-SelectIcon { justify-content: center; align-items: center; display: flex; } -.canon-Select--value { +.canon-SelectValue { text-overflow: ellipsis; white-space: nowrap; width: 100%; diff --git a/packages/canon/css/textfield.css b/packages/canon/css/textfield.css index eb43b1f77f..bf21b3bd74 100644 --- a/packages/canon/css/textfield.css +++ b/packages/canon/css/textfield.css @@ -5,14 +5,14 @@ display: flex; } -.canon-TextField--label { +.canon-TextFieldLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-TextField--description { +.canon-TextFieldDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -20,7 +20,7 @@ margin: 0; } -.canon-TextField--error { +.canon-TextFieldError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -28,7 +28,7 @@ margin: 0; } -.canon-TextField--input { +.canon-TextFieldInput { border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); padding: 0 var(--canon-space-4); @@ -41,39 +41,39 @@ transition: border-color .2s ease-in-out, outline-color .2s ease-in-out; } -.canon-TextField--input::placeholder { +.canon-TextFieldInput::placeholder { color: var(--canon-fg-secondary); } -.canon-TextField--input:hover { +.canon-TextFieldInput:hover { border-color: var(--canon-border-hover); } -.canon-TextField--input:focus-visible { +.canon-TextFieldInput:focus-visible { outline-color: var(--canon-border-pressed); border-color: var(--canon-border-pressed); outline-width: 0; } -.canon-TextField--input[data-invalid] { +.canon-TextFieldInput[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-TextField--input[data-disabled] { +.canon-TextFieldInput[data-disabled] { opacity: .5; cursor: not-allowed; border: 1px solid var(--canon-border-disabled); } -.canon-TextField--input[data-size="small"] { +.canon-TextFieldInput[data-size="small"] { height: 2rem; } -.canon-TextField--input[data-size="medium"] { +.canon-TextFieldInput[data-size="medium"] { height: 2.5rem; } -.canon-TextField--required { +.canon-TextFieldRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); diff --git a/packages/canon/src/components/Button/Button.tsx b/packages/canon/src/components/Button/Button.tsx index b9a1229fbd..ca652013b4 100644 --- a/packages/canon/src/components/Button/Button.tsx +++ b/packages/canon/src/components/Button/Button.tsx @@ -50,9 +50,9 @@ export const Button = forwardRef( style={style} {...rest} > - {iconStart && } + {iconStart && } {children} - {iconEnd && } + {iconEnd && } ); }, diff --git a/packages/canon/src/components/Button/styles.css b/packages/canon/src/components/Button/styles.css index a05a0b3a4f..785fbf3b88 100644 --- a/packages/canon/src/components/Button/styles.css +++ b/packages/canon/src/components/Button/styles.css @@ -94,12 +94,12 @@ height: 32px; } -.canon-Button[data-size='small'] .canon-Button--icon { +.canon-Button[data-size='small'] .canon-ButtonIcon { width: 1rem; height: 1rem; } -.canon-Button[data-size='medium'] .canon-Button--icon { +.canon-Button[data-size='medium'] .canon-ButtonIcon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/src/components/IconButton/IconButton.tsx b/packages/canon/src/components/IconButton/IconButton.tsx index 7e7f94d22e..b2581844bc 100644 --- a/packages/canon/src/components/IconButton/IconButton.tsx +++ b/packages/canon/src/components/IconButton/IconButton.tsx @@ -45,7 +45,7 @@ export const IconButton = forwardRef( style={style} {...rest} > - + ); }, diff --git a/packages/canon/src/components/IconButton/styles.css b/packages/canon/src/components/IconButton/styles.css index 089dd1fcda..859c512fd6 100644 --- a/packages/canon/src/components/IconButton/styles.css +++ b/packages/canon/src/components/IconButton/styles.css @@ -94,12 +94,12 @@ width: 32px; } -.canon-IconButton[data-size='small'] .canon-IconButton--icon { +.canon-IconButton[data-size='small'] .canon-IconButtonIcon { width: 1rem; height: 1rem; } -.canon-IconButton[data-size='medium'] .canon-IconButton--icon { +.canon-IconButton[data-size='medium'] .canon-IconButtonIcon { width: 1.5rem; height: 1.5rem; } diff --git a/packages/canon/src/components/Select/Select.styles.css b/packages/canon/src/components/Select/Select.styles.css index 718636d954..fa00d81302 100644 --- a/packages/canon/src/components/Select/Select.styles.css +++ b/packages/canon/src/components/Select/Select.styles.css @@ -21,14 +21,14 @@ width: 100%; } -.canon-Select--label { +.canon-SelectLabel { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-primary); margin-bottom: var(--canon-space-1_5); } -.canon-Select--description { +.canon-SelectDescription { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-secondary); @@ -36,7 +36,7 @@ padding-top: var(--canon-space-1_5); } -.canon-Select--error { +.canon-SelectError { font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); color: var(--canon-fg-danger); @@ -44,7 +44,7 @@ padding-top: var(--canon-space-1_5); } -.canon-Select--trigger { +.canon-SelectTrigger { box-sizing: border-box; border-radius: var(--canon-radius-3); border: 1px solid var(--canon-border); @@ -63,41 +63,41 @@ gap: var(--canon-space-2); } -.canon-Select--trigger::placeholder { +.canon-SelectTrigger::placeholder { color: var(--canon-fg-secondary); } -.canon-Select--trigger:hover { +.canon-SelectTrigger:hover { border-color: var(--canon-border-hover); } -.canon-Select--trigger:focus-visible { +.canon-SelectTrigger:focus-visible { border-color: var(--canon-border-pressed); outline: 0; } -.canon-Select--trigger[data-invalid] { +.canon-SelectTrigger[data-invalid] { border-color: var(--canon-fg-danger); } -.canon-Select--trigger[data-invalid]:hover { +.canon-SelectTrigger[data-invalid]:hover { border-width: 2px; } -.canon-Select--trigger[data-invalid]:focus-visible { +.canon-SelectTrigger[data-invalid]:focus-visible { border-width: 2px; } -.canon-Select--trigger[data-disabled] { +.canon-SelectTrigger[data-disabled] { cursor: not-allowed; border-color: var(--canon-border-disabled); color: var(--canon-fg-disabled); } -.canon-Select--trigger[data-size='small'] { +.canon-SelectTrigger[data-size='small'] { height: 2rem; } -.canon-Select--trigger[data-size='medium'] { +.canon-SelectTrigger[data-size='medium'] { height: 3rem; } @@ -106,11 +106,11 @@ transition: transform 0.2s ease; } -.canon-Select--trigger[data-popup-open] .canon-SelectIcon { +.canon-SelectTrigger[data-popup-open] .canon-SelectIcon { transform: rotate(180deg); } -.canon-Select--popup { +.canon-SelectPopup { box-sizing: border-box; max-height: var(--available-height); overflow-y: auto; @@ -125,13 +125,13 @@ transition: transform 150ms, opacity 150ms; } -.canon-Select--popup[data-starting-style], -.canon-Select--popup[data-ending-style] { +.canon-SelectPopup[data-starting-style], +.canon-SelectPopup[data-ending-style] { opacity: 0; transform: scale(0.9); } -.canon-Select--item { +.canon-SelectItem { position: relative; width: var(--anchor-width); display: grid; @@ -149,13 +149,13 @@ outline: none; } -.canon-Select--item[data-highlighted] { +.canon-SelectItem[data-highlighted] { z-index: 0; position: relative; color: var(--canon-fg-primary); } -.canon-Select--item[data-highlighted]::before { +.canon-SelectItem[data-highlighted]::before { content: ''; z-index: -1; position: absolute; @@ -165,37 +165,37 @@ background-color: var(--canon-bg-tint-hover); } -.canon-Select--item[data-disabled] { +.canon-SelectItem[data-disabled] { cursor: not-allowed; color: var(--canon-fg-disabled); } -.canon-Select--item-indicator { +.canon-SelectItemIndicator { grid-area: icon; display: flex; align-items: center; justify-content: center; } -.canon-Select--item-text { +.canon-SelectItemText { flex: 1; grid-area: text; } -.canon-Select--required { +.canon-SelectRequired { color: var(--canon-fg-secondary); font-size: var(--canon-font-size-2); font-weight: var(--canon-font-weight-regular); margin-left: var(--canon-space-1); } -.canon-Select--icon { +.canon-SelectIcon { display: flex; align-items: center; justify-content: center; } -.canon-Select--value { +.canon-SelectValue { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; diff --git a/packages/canon/src/components/Select/Select.tsx b/packages/canon/src/components/Select/Select.tsx index d8760fc1ea..be8047ca02 100644 --- a/packages/canon/src/components/Select/Select.tsx +++ b/packages/canon/src/components/Select/Select.tsx @@ -48,10 +48,10 @@ export const Select = forwardRef((props, ref) => { return (
{label && ( -