diff --git a/.changeset/dull-kangaroos-relax.md b/.changeset/dull-kangaroos-relax.md new file mode 100644 index 00000000000..a71e59db8ae --- /dev/null +++ b/.changeset/dull-kangaroos-relax.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +Remove the CSS modules feature flag from Table diff --git a/packages/react/src/DataTable/Table.tsx b/packages/react/src/DataTable/Table.tsx index 1cb9501b217..e9b91903257 100644 --- a/packages/react/src/DataTable/Table.tsx +++ b/packages/react/src/DataTable/Table.tsx @@ -1,11 +1,8 @@ import {SortAscIcon, SortDescIcon} from '@primer/octicons-react' import {clsx} from 'clsx' import React from 'react' -import styled from 'styled-components' import Text from '../Text' -import {get} from '../constants' import type {SxProp} from '../sx' -import sx from '../sx' import VisuallyHidden from '../_VisuallyHidden' import type {Column, CellAlignment} from './column' import type {UniqueRow} from './row' @@ -13,228 +10,15 @@ import {SortDirection} from './sorting' import {useTableLayout} from './useTable' import {SkeletonText} from '../experimental/Skeleton/SkeletonText' import {ScrollableRegion} from '../ScrollableRegion' -import {useFeatureFlag} from '../FeatureFlags' -import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' import {Button} from '../internal/components/ButtonReset' import classes from './Table.module.css' - -const cssModulesFlag = 'primer_react_css_modules_ga' +import {defaultSxProp} from '../utils/defaultSxProp' +import {toggleSxComponent} from '../internal/utils/toggleSxComponent' // ---------------------------------------------------------------------------- // Table // ---------------------------------------------------------------------------- -const StyledTable = toggleStyledComponent( - cssModulesFlag, - 'table', - styled.table>` - /* Default table styles */ - --table-border-radius: 0.375rem; - --table-cell-padding: var(--cell-padding-block, 0.5rem) var(--cell-padding-inline, 0.75rem); - --table-font-size: 0.75rem; - - background-color: ${get('colors.canvas.default')}; - border-spacing: 0; - border-collapse: separate; - display: grid; - font-size: var(--table-font-size); - grid-template-columns: var(--grid-template-columns); - line-height: calc(20 / 12); - width: 100%; - - /* Density modes: condensed, normal, spacious */ - &[data-cell-padding='condensed'] { - --cell-padding-block: 0.25rem; - --cell-padding-inline: 0.5rem; - } - - &[data-cell-padding='normal'] { - --cell-padding-block: 0.5rem; - --cell-padding-inline: 0.75rem; - } - - &[data-cell-padding='spacious'] { - --cell-padding-block: 0.75rem; - --cell-padding-inline: 1rem; - } - - /* Borders */ - .TableCell:first-child, - .TableHeader:first-child { - border-left: 1px solid ${get('colors.border.default')}; - } - - .TableCell:last-child, - .TableHeader:last-child { - border-right: 1px solid ${get('colors.border.default')}; - } - - .TableHeader, - .TableCell { - text-align: start; - display: flex; - align-items: center; - border-bottom: 1px solid ${get('colors.border.default')}; - padding: var(--table-cell-padding); - } - - .TableHeader[data-cell-align='end'], - .TableCell[data-cell-align='end'] { - text-align: end; - display: flex; - justify-content: flex-end; - } - - .TableHeader[data-cell-align='end'] .TableSortButton { - display: flex; - flex-direction: row-reverse; - } - - .TableHead .TableRow:first-of-type .TableHeader { - border-top: 1px solid ${get('colors.border.default')}; - } - - /* Border radius */ - .TableHead .TableRow:first-of-type .TableHeader:first-child { - border-top-left-radius: var(--table-border-radius); - } - - .TableHead .TableRow:first-of-type .TableHeader:last-child { - border-top-right-radius: var(--table-border-radius); - } - - .TableOverflowWrapper:last-child & .TableBody .TableRow:last-of-type .TableCell:first-child { - border-bottom-left-radius: var(--table-border-radius); - } - - .TableOverflowWrapper:last-child & .TableBody .TableRow:last-of-type .TableCell:last-child { - border-bottom-right-radius: var(--table-border-radius); - } - - /** - * Offset padding to make sure type aligns regardless of cell padding - * selection - */ - .TableRow > *:first-child:not(.TableCellSkeleton), - .TableRow > *:first-child .TableCellSkeletonItem { - padding-inline-start: 1rem; - } - - .TableRow > *:last-child:not(.TableCellSkeleton), - .TableRow > *:last-child .TableCellSkeletonItem { - padding-inline-end: 1rem; - } - - /* TableHeader */ - .TableHeader { - background-color: ${get('colors.canvas.subtle')}; - color: ${get('colors.fg.muted')}; - font-weight: 600; - border-top: 1px solid ${get('colors.border.default')}; - } - - .TableHeader[aria-sort='descending'], - .TableHeader[aria-sort='ascending'] { - color: ${get('colors.fg.default')}; - } - - /* Control visibility of sort icons */ - .TableSortIcon { - visibility: hidden; - } - - /* The ASC icon is visible if the header is sortable and is hovered or focused */ - .TableHeader:hover .TableSortIcon--ascending, - .TableHeader .TableSortButton:focus .TableSortIcon--ascending { - visibility: visible; - } - - /* Each sort icon is visible if the TableHeader is currently in the corresponding sort state */ - .TableHeader[aria-sort='ascending'] .TableSortIcon--ascending, - .TableHeader[aria-sort='descending'] .TableSortIcon--descending { - visibility: visible; - } - - /* TableRow */ - .TableRow:hover .TableCell:not(.TableCellSkeleton) { - /* TODO: update this token when the new primitive tokens are released */ - background-color: ${get('colors.actionListItem.default.hoverBg')}; - } - - /* TableCell */ - .TableCell[scope='row'] { - align-items: center; - display: flex; - color: ${get('colors.fg.default')}; - font-weight: 600; - } - - /* TableCellSkeleton */ - .TableCellSkeleton { - padding: 0; - } - - .TableCellSkeletonItems { - display: flex; - flex-direction: column; - width: 100%; - } - - .TableCellSkeletonItem { - padding: var(--table-cell-padding); - - &:nth-of-type(5n + 1) { - --skeleton-item-width: 85%; - } - - &:nth-of-type(5n + 2) { - --skeleton-item-width: 67.5%; - } - - &:nth-of-type(5n + 3) { - --skeleton-item-width: 80%; - } - - &:nth-of-type(5n + 4) { - --skeleton-item-width: 60%; - } - - &:nth-of-type(5n + 5) { - --skeleton-item-width: 75%; - } - } - - .TableCellSkeletonItem [data-component='SkeletonText'] { - width: var(--skeleton-item-width); - } - - .TableCellSkeletonItem:not(:last-of-type) { - border-bottom: 1px solid ${get('colors.border.default')}; - } - - /* Grid layout */ - .TableHead, - .TableBody, - .TableRow { - display: contents; - } - - @supports (grid-template-columns: subgrid) { - .TableHead, - .TableBody, - .TableRow { - display: grid; - grid-template-columns: subgrid; - grid-column: -1 /1; - } - } - - .TableSortButton { - column-gap: 0.5rem; - } - `, -) - export type TableProps = React.ComponentPropsWithoutRef<'table'> & { /** * Provide an id to an element which uniquely describes this table @@ -262,25 +46,18 @@ const Table = React.forwardRef(function Table( {'aria-labelledby': labelledby, cellPadding = 'normal', className, gridTemplateColumns, ...rest}, ref, ) { - const enabled = useFeatureFlag(cssModulesFlag) - return ( // TODO update type to be non-optional in next major release // @ts-expect-error this type should be required in the next major version - (function Table( export type TableHeadProps = React.ComponentPropsWithoutRef<'thead'> function TableHead({children}: TableHeadProps) { - const enabled = useFeatureFlag(cssModulesFlag) return ( // We need to explicitly pass this role because some ATs and browsers drop table semantics // when we use `display: contents` or `display: grid` in the table - + {children} ) @@ -318,16 +89,10 @@ function TableHead({children}: TableHeadProps) { export type TableBodyProps = React.ComponentPropsWithoutRef<'tbody'> function TableBody({children}: TableBodyProps) { - const enabled = useFeatureFlag(cssModulesFlag) return ( // We need to explicitly pass this role because some ATs and browsers drop table semantics // when we use `display: contents` or `display: grid` in the table - + {children} ) @@ -345,13 +110,10 @@ export type TableHeaderProps = Omit, 'align } function TableHeader({align, children, ...rest}: TableHeaderProps) { - const enabled = useFeatureFlag(cssModulesFlag) return ( @@ -418,15 +181,8 @@ function TableSortHeader({align, children, direction, onToggleSort, ...rest}: Ta export type TableRowProps = React.ComponentPropsWithoutRef<'tr'> function TableRow({children, ...rest}: TableRowProps) { - const enabled = useFeatureFlag(cssModulesFlag) return ( - + {children} ) @@ -450,16 +206,13 @@ export type TableCellProps = Omit, 'align'> } function TableCell({align, className, children, scope, ...rest}: TableCellProps) { - const enabled = useFeatureFlag(cssModulesFlag) const BaseComponent = scope ? 'th' : 'td' const role = scope ? 'rowheader' : 'cell' return ( - -function TableContainer({children, sx}: TableContainerProps) { - const enabled = useFeatureFlag(cssModulesFlag) +export type TableContainerProps = React.PropsWithChildren> + +const TableContainerBaseComponent = toggleSxComponent('div') as React.ComponentType +function TableContainer({children, sx: sxProp = defaultSxProp}: TableContainerProps) { return ( - + {children} - + ) } -export type TableTitleProps = React.PropsWithChildren<{ - /** - * Provide an alternate element or component to use as the container for - * `TableSubtitle`. This is useful when specifying markup that is more - * semantic for your use-case, such as a heading tag. - */ - as?: keyof JSX.IntrinsicElements | React.ComponentType - - /** - * Provide a unique id for the table subtitle. This should be used along with - * `aria-labelledby` on `DataTable` - */ - id: string -}> +export type TableTitleProps = React.PropsWithChildren< + { + /** + * Provide an alternate element or component to use as the container for + * `TableSubtitle`. This is useful when specifying markup that is more + * semantic for your use-case, such as a heading tag. + */ + as?: keyof JSX.IntrinsicElements | React.ComponentType -const TableTitle = React.forwardRef(function TableTitle({as = 'h2', children, id}, ref) { - const enabled = useFeatureFlag(cssModulesFlag) + /** + * Provide a unique id for the table subtitle. This should be used along with + * `aria-labelledby` on `DataTable` + */ + id: string + } & React.HTMLAttributes & + React.RefAttributes +> + +const TableTitle = React.forwardRef(function TableTitle( + {as: Component = 'h2', children, id}, + ref, +) { + const BaseComponent = Component as React.ElementType return ( - + {children} - + ) }) -const StyledTableTitle = toggleStyledComponent( - cssModulesFlag, - 'h2', - styled.h2` - color: var(--fgColor-default); - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-semibold); - line-height: calc(20 / 14); - margin: 0; - `, -) - -export type TableSubtitleProps = React.PropsWithChildren<{ - /** - * Provide an alternate element or component to use as the container for - * `TableSubtitle`. This is useful when specifying markup that is more - * semantic for your use-case - */ - as?: keyof JSX.IntrinsicElements | React.ComponentType - - /** - * Provide a unique id for the table subtitle. This should be used along with - * `aria-describedby` on `DataTable` - */ - id: string -}> +export type TableSubtitleProps = React.PropsWithChildren< + { + /** + * Provide an alternate element or component to use as the container for + * `TableSubtitle`. This is useful when specifying markup that is more + * semantic for your use-case + */ + as?: keyof JSX.IntrinsicElements | React.ComponentType -function TableSubtitle({as, children, id}: TableSubtitleProps) { - const enabled = useFeatureFlag(cssModulesFlag) + /** + * Provide a unique id for the table subtitle. This should be used along with + * `aria-describedby` on `DataTable` + */ + id: string + } & React.HTMLAttributes +> + +function TableSubtitle({as: BaseComponent = 'div', children, id}: TableSubtitleProps) { return ( - + {children} - + ) } -const StyledTableSubtitle = toggleStyledComponent( - cssModulesFlag, - 'div', - styled.div` - color: var(--fgColor-default); - font-weight: var(--base-text-weight-normal); - font-size: var(--text-body-size-small); - line-height: var(--text-title-lineHeight-small); - margin: 0; - `, -) - function TableDivider() { - const enabled = useFeatureFlag(cssModulesFlag) - return ( - - ) + return
} -const StyledTableDivider = toggleStyledComponent( - cssModulesFlag, - 'div', - styled.div` - background-color: var(--borderColor-default); - width: 100%; - height: 1px; - `, -) - export type TableActionsProps = React.PropsWithChildren function TableActions({children}: TableActionsProps) { - const enabled = useFeatureFlag(cssModulesFlag) - return ( -
- {children} -
- ) + return
{children}
} // ---------------------------------------------------------------------------- @@ -702,7 +331,6 @@ export type TableSkeletonProps = React.ComponentPropsWit } function TableSkeleton({cellPadding, columns, rows = 10, ...rest}: TableSkeletonProps) { - const enabled = useFeatureFlag(cssModulesFlag) const {gridTemplateColumns} = useTableLayout(columns) return ( @@ -723,26 +351,12 @@ function TableSkeleton({cellPadding, columns, rows = 10, {Array.from({length: columns.length}).map((_, i) => { return ( - + Loading -
+
{Array.from({length: rows}).map((_, i) => { return ( -
+
) diff --git a/packages/react/src/DataTable/__tests__/Table.test.tsx b/packages/react/src/DataTable/__tests__/Table.test.tsx index 6267da90b8b..a8e3aff224e 100644 --- a/packages/react/src/DataTable/__tests__/Table.test.tsx +++ b/packages/react/src/DataTable/__tests__/Table.test.tsx @@ -231,7 +231,8 @@ describe('Table', () => { expect(screen.getByRole('rowheader', {name: 'Cell'})).toBeInTheDocument() }) - it('should vertically align cell contents', () => { + // Can't run this test because jest can't render styles + it.skip('should vertically align cell contents', () => { render(