diff --git a/.storybook/data/tokens.json b/.storybook/data/tokens.json index 3910b55aa..034fba7b8 100644 --- a/.storybook/data/tokens.json +++ b/.storybook/data/tokens.json @@ -811,6 +811,7 @@ "eds-size-20": "160", "eds-size-24": "192", "eds-size-32": "256", + "eds-size-34": "272", "eds-size-40": "320", "eds-size-base-unit": "8", "eds-size-half": "4", diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index ccd9cc76a..6afd608e5 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -84,6 +84,7 @@ export const parameters: Preview['parameters'] = { ...createInitialReleaseConfig('1.2'), ...createInitialReleaseConfig('1.1'), ...createInitialReleaseConfig('1.0'), + ...createCurrentReleaseConfig('1.0'), ...createCurrentReleaseConfig('1.3'), ...createCurrentReleaseConfig('2.0'), ...createCurrentReleaseConfig('2.1'), diff --git a/package.json b/package.json index ddcdb5aa9..f927b8569 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "dependencies": { "@headlessui/react": "^1.7.19", "@popperjs/core": "^2.11.8", + "@tanstack/react-table": "^8.20.5", "@tippyjs/react": "^4.2.6", "chalk": "^4.1.2", "clsx": "^2.1.1", diff --git a/src/components/DataTable/DataTable.module.css b/src/components/DataTable/DataTable.module.css new file mode 100644 index 000000000..2c22fa87b --- /dev/null +++ b/src/components/DataTable/DataTable.module.css @@ -0,0 +1,291 @@ +/*------------------------------------*\ + # DATA TABLE +\*------------------------------------*/ + +/* Visible table caption */ + +/* TODO: make it so that we have the search bar and actions wrap together instead of separately */ +.data-table__caption-container { + display: flex; + align-items: flex-end; + flex-wrap: wrap; + justify-content: space-between; + gap: calc(var(--eds-size-3) / 16 * 1rem) calc(var(--eds-size-6) / 16 * 1rem); + + text-align: start; + margin: 0 calc(var(--eds-size-3) / 16 * 1rem) + calc(var(--eds-size-4) / 16 * 1rem); +} + +.data-table__caption-text { + flex-grow: 1; +} + +/* Invisible table caption (a11y) */ +.data-table__aria-caption { + display: none; +} + +.data-table__caption { + caption-side: top; + font: var(--eds-theme-typography-headline-md-bold); +} + +.data-table__subcaption { + font: var(--eds-theme-typography-headline-sm); +} + +.data-table__table { + table-layout: fixed; + width: 100%; + + /* add class instead of tag for styles? */ + th, + td { + padding: 0; + vertical-align: top; + /** + * inherit height from 1px size of table rows. This allows height: 100% on cells containers + * to affect full height of cell + */ + height: inherit; + } + + .data-table__caption + &, + .data-table__subcaption + & { + margin-top: calc(var(--eds-size-4) / 16 * 1rem); + } +} + +.data-table__search { + width: calc(var(--eds-size-34) / 16 * 1rem); +} + +.data-table--tableStyle-border { + border: calc(var(--eds-border-width-sm) * 1px) solid; +} + +.data-table__cell-text { + text-align: start; + + .data-table__cell--alignment-leading & { + text-align: start; + } + + .data-table__cell--alignment-trailing & { + text-align: end; + } +} + +.data-table__cell--alignment-leading { + justify-content: flex-start; +} + +.data-table__cell--alignment-trailing { + justify-content: flex-end; +} + +.data-table__cell-sublabel { + display: block; + font: var(--eds-theme-typography-body-sm); +} + +.data-table__header-cell { + display: flex; + gap: calc(var(--eds-size-1) / 16 * 1rem); + align-items: flex-start; + font: var(--eds-theme-typography-title-md); + height: 100%; + + border-right: calc(var(--eds-border-width-sm) * 1px) solid transparent; + + &.data-table__cell--has-horizontal-divider { + border-right-color: var( + --eds-theme-color-border-utility-default-low-emphasis + ); + } + + .data-table--size-sm & { + font: var(--eds-theme-typography-title-sm); + /* TODO(bug): we want to use top-/bottom-padding of 5px (instead of 4px) to give overall height divisible by 8 (32px) */ + padding: calc(var(--eds-size-half) / 16 * 1rem) + calc(var(--eds-size-1) / 16 * 1rem); + } + + .data-table--size-md & { + padding: calc(var(--eds-size-2) / 16 * 1rem) + calc(var(--eds-size-3) / 16 * 1rem); + } + + .data-cell__cell--icon { + margin-top: calc(var(--eds-size-1) / 16 * 1rem); + flex-shrink: 0; + + .data-table--size-sm & { + margin-top: calc(var(--eds-size-half) / 16 * 1rem); + } + } +} + +.data-table__cell { + display: flex; + gap: calc(var(--eds-size-1) / 16 * 1rem); + align-items: flex-start; + font: var(--eds-theme-typography-body-md); + height: 100%; + + border-right: calc(var(--eds-border-width-sm) * 1px) solid transparent; + + &.data-table__cell--has-horizontal-divider { + border-right-color: var( + --eds-theme-color-border-utility-default-low-emphasis + ); + } + + .data-table--size-sm & { + font: var(--eds-theme-typography-body-sm); + padding: calc(var(--eds-size-half) / 16 * 1rem) + calc(var(--eds-size-1) / 16 * 1rem); + } + + .data-table--size-md & { + padding: calc(var(--eds-size-2) / 16 * 1rem) + calc(var(--eds-size-3) / 16 * 1rem); + } + + .data-cell__cell--icon { + margin-top: calc(var(--eds-size-half) / 16 * 1rem); + flex-shrink: 0; + } +} + +.data-table__header-row { + border-bottom: calc(var(--eds-border-width-sm) * 1px) solid; + position: sticky; + top: -1px; +} + +.data-table__group-row { + font: var(--eds-theme-typography-label-sm); + position: sticky; + top: -1px; + + pointer-events: none; + + .data-table--size-sm & { + padding: calc(var(--eds-size-half) / 16 * 1rem) + calc(var(--eds-size-1) / 16 * 1rem); + } + + .data-table--size-md & { + padding: calc(var(--eds-size-2) / 16 * 1rem) + calc(var(--eds-size-3) / 16 * 1rem); + } +} + +.data-table--is-pinned { + box-shadow: var(--eds-box-shadow-sm); + +} + +/** + * Color Tokens + */ + +.data-table__row { + /* setting the height to 1px so that later, table cell containers can take up 100% of height */ + height: 1px; + + &.data-table__row--is-selected { + background-color: var(--eds-theme-color-background-table-row-selected); + } + + .data-table--rowStyle-lined & { + border-bottom: calc(var(--eds-border-width-sm) * 1px) solid; + + &.data-table__row--is-selected { + background-color: var(--eds-theme-color-background-table-row-selected); + } + } + + .data-table--rowStyle-striped &:nth-child(even) { + background-color: var(--eds-theme-color-background-table-row-stripe-2); + + &.data-table__row--is-selected { + background-color: var(--eds-theme-color-background-table-row-selected); + } + } + + .data-table--rowStyle-striped &:nth-child(odd) { + background-color: var(--eds-theme-color-background-table-row-stripe-1); + + &.data-table__row--is-selected { + background-color: var(--eds-theme-color-background-table-row-selected); + } + } +} + +.data-table { + display: block; + position: relative; + + .data-table__table { + background-color: var(--eds-theme-color-background-utility-base-1); + + th { + background-color: var(--eds-theme-color-background-utility-base-1); + } + } + + .data-table__caption { + color: var(--eds-theme-color-text-utility-default-primary); + } + + .data-table__subcaption { + color: var(--eds-theme-color-text-utility-default-secondary); + } + + .data-table--tableStyle-border, + .data-table__header-row { + border-color: var(--eds-theme-color-border-utility-default-low-emphasis); + } + + .data-table__header-cell { + color: var(--eds-theme-color-text-utility-default-primary); + } + + .data-table__cell { + color: var(--eds-theme-color-text-utility-default-primary); + } + + .data-table--rowStyle-lined { + color: var(--eds-theme-color-border-utility-default-low-emphasis); + } + + .data-table__cell-sublabel, + .data-table__header-cell-sublabel { + color: var(--eds-theme-color-text-utility-default-secondary); + } + + .data-table__row--is-interactive { + /** + * TODO: Add in handling for when focused (i dont think you can do?) + */ + &:hover { + box-shadow: var(--eds-box-shadow-sm); + position: relative; + z-index: 1; + } + + &:hover:active { + box-shadow: var(--eds-box-shadow-md); + position: relative; + z-index: 1; + } + } + + .data-table__group-row { + color: var(--eds-theme-color-text-utility-default-primary); + background-color: var(--eds-theme-color-background-utility-interactive-low-emphasis); + } +} diff --git a/src/components/DataTable/DataTable.stories.tsx b/src/components/DataTable/DataTable.stories.tsx new file mode 100644 index 000000000..e232c5e4e --- /dev/null +++ b/src/components/DataTable/DataTable.stories.tsx @@ -0,0 +1,829 @@ +import { BADGE } from '@geometricpanda/storybook-addon-badges'; +import type { StoryObj, Meta } from '@storybook/react'; + +import React from 'react'; + +import { + DataTable, + DataTableTable, + DataTableDataCell, + DataTableHeaderCell, + DataTableRow, + DataTableHeader, + type DataTableProps, +} from './DataTable'; + +// We import all of the utilities from tanstack here, and this can contain other custom utilities +import { Button, Menu, Checkbox, DataTableUtils } from '../..'; + +import { chromaticViewports } from '../../util/viewports'; + +export default { + title: 'Components/DataTable', + component: DataTable, + // TODO(bug): generate documentation argTypes for sub-components + // @see https://storybook.js.org/docs/writing-stories/stories-for-multiple-components + subcomponents: { + 'DataTable.Table': DataTableTable, + 'DataTable.Row': DataTableRow, + 'DataTable.Header': DataTableHeader, + 'DataTable.HeaderCell': DataTableHeaderCell, + 'DataTable.DataCell': DataTableDataCell, + }, + parameters: { + badges: [BADGE.BETA, 'intro-1.0', 'current-1.0'], + chromatic: { + viewports: [ + chromaticViewports.ipadMini, + chromaticViewports.chromebook, + chromaticViewports.googlePixel2, + ], + }, + }, + argTypes: { + actions: { + control: false, + }, + children: { + control: false, + }, + }, +} as Meta; + +type Args = DataTableProps; + +// Specifying an example data type for the rows of a table +type Person = { + firstName: string; + lastName: string; + age: number; + visits: number; + progress: number; +}; + +// Specifying the example (static) data for the table to use with tanstack primitives +const defaultData: Person[] = [ + { + firstName: 'Joe', + lastName: 'Dirte', + age: 45, + visits: 20, + progress: 10, + }, + { + firstName: 'Tandy', + lastName: 'Miller', + age: 40, + visits: 40, + progress: 80, + }, + { + firstName: 'Tanner', + lastName: 'Lindsey', + age: 24, + visits: 100, + progress: 50, + }, + { + firstName: 'Joe', + lastName: 'Dirte', + age: 45, + visits: 20, + progress: 10, + }, + { + firstName: 'Tandy', + lastName: 'Miller', + age: 40, + visits: 40, + progress: 80, + }, + { + firstName: 'Tanner', + lastName: 'Lindsey', + age: 24, + visits: 100, + progress: 50, + }, + { + firstName: 'Joe', + lastName: 'Dirte', + age: 45, + visits: 20, + progress: 10, + }, + { + firstName: 'Tandy', + lastName: 'Miller', + age: 40, + visits: 40, + progress: 80, + }, + { + firstName: 'Tanner', + lastName: 'Lindsey', + age: 24, + visits: 100, + progress: 50, + }, + { + firstName: 'Joe', + lastName: 'Dirte', + age: 45, + visits: 20, + progress: 10, + }, + { + firstName: 'Tandy', + lastName: 'Miller', + age: 40, + visits: 40, + progress: 80, + }, + { + firstName: 'Tanner', + lastName: 'Lindsey', + age: 24, + visits: 100, + progress: 50, + }, +]; + +// We generate a helper object to generate the display columns and use the type for the structure +const columnHelper = DataTableUtils.createColumnHelper(); + +// TODO: how to make the data type apply the correct alignment and other UI props +const columns = [ + columnHelper.accessor('firstName', { + header: () => ( + + First Name + + ), + cell: (info) => {info.getValue()}, + }), + columnHelper.accessor((row) => row.lastName, { + id: 'lastName', + header: () => ( + Last Name + ), + cell: (info) => {info.getValue()}, + }), + columnHelper.accessor('age', { + header: () => ( + Age + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('visits', { + header: () => ( + Visits + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('progress', { + header: () => ( + + Profile Progress + + ), + cell: (info) => ( + = 80 ? 'Complete' : 'Incomplete'} + > + {info.renderValue()} + + ), + }), +]; + +/** + * Using the hooks provided by Tanstack's Table, you can control the dimensions and contents of the table. + * + * When specifying the cells, you can use `className` to control content controls like truncation or other customizations. + */ +export const Default: StoryObj = { + args: { + caption: 'Test table', + subcaption: 'Additional Subcaption', + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: defaultData, + columns, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +export const TableStyleBorder: StoryObj = { + args: { + tableStyle: 'border', + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [data] = React.useState(() => [...defaultData]); + + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data, + columns, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +/** + * When using table size small, we have less padding on the cells and header + * + * **Note**: using `sublabel`s when `size` = `'sm'` is not allowed. + */ +export const TableSizeSm: StoryObj = { + args: { + tableStyle: 'border', + size: 'sm', + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: defaultData, + columns, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +export const RowStyleLined: StoryObj = { + args: { + tableStyle: 'border', + rowStyle: 'lined', + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: defaultData, + columns, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +/** + * Implementation example of how to build selectable rows. + * + * For more information: https://tanstack.com/table/latest/docs/framework/react/examples/row-selection + */ +export const Selectable: StoryObj = { + args: { + caption: 'Test table', + subcaption: 'Additional Subcaption', + isInteractive: true, + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [rowSelection, setRowSelection] = React.useState({}); // TODO: demonstrate one is selected + + // TODO(docs): Why must `any` be passed as second type param to avoid `unknown`? + // eslint-disable-next-line react-hooks/rules-of-hooks + const selectableColumns = React.useMemo< + DataTableUtils.ColumnDef[] + >( + () => [ + { + id: 'select', + header: ({ table }) => ( + + + + ), + cell: ({ row }) => ( + + + + ), + // Widths can be set on header cells (using pixels) + // More information: https://tanstack.com/table/latest/docs/guide/column-sizing#column-widths + // TODO(design): what is the column size for the selectable column + size: 32, + }, + columnHelper.accessor('firstName', { + header: () => ( + + First Name + + ), + cell: (info) => ( + + {info.getValue()} + + ), + }), + columnHelper.accessor((row) => row.lastName, { + id: 'lastName', + header: () => ( + + Last Name + + ), + cell: (info) => ( + {info.getValue()} + ), + }), + columnHelper.accessor('age', { + header: () => ( + + Age + + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('visits', { + header: () => ( + + Visits + + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('progress', { + header: () => ( + + Profile Progress + + ), + cell: (info) => ( + = 80 ? 'Complete' : 'Incomplete' + } + > + {info.renderValue()} + + ), + }), + ], + [], + ); + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: defaultData, + columns: selectableColumns, + state: { + rowSelection, + }, + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +/** + * Implementation example of how to build selectable rows. + * + * TODO: verify if selection will interfere with row groupings + * + * For more information: https://tanstack.com/table/latest/docs/framework/react/examples/row-selection + */ +export const VerticalDivider: StoryObj = { + args: { + caption: 'Test table', + subcaption: 'Additional Subcaption', + isInteractive: true, + }, + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [rowSelection, setRowSelection] = React.useState({}); // TODO: demonstrate one is selected + + // TODO(docs): Why must `any` be passed as second type param to avoid `unknown`? + // eslint-disable-next-line react-hooks/rules-of-hooks + const selectableColumns = React.useMemo< + DataTableUtils.ColumnDef[] + >( + () => [ + { + id: 'select', + header: ({ table }) => ( + + + + ), + cell: ({ row }) => ( + + + + ), + // Widths can be set on header cells (using pixels) + // More information: https://tanstack.com/table/latest/docs/guide/column-sizing#column-widths + // TODO(design): what is the column size for the selectable column + size: 32, + }, + columnHelper.accessor('firstName', { + header: () => ( + + First Name + + ), + cell: (info) => ( + + {info.getValue()} + + ), + }), + columnHelper.accessor((row) => row.lastName, { + id: 'lastName', + header: () => ( + + Last Name + + ), + cell: (info) => ( + + {info.getValue()} + + ), + }), + columnHelper.accessor('age', { + header: () => ( + + Age + + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('visits', { + header: () => ( + + Visits + + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + columnHelper.accessor('progress', { + header: () => ( + + Profile Progress + + ), + cell: (info) => ( + = 80 ? 'Complete' : 'Incomplete' + } + > + {info.renderValue()} + + ), + }), + ], + [], + ); + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: defaultData, + columns: selectableColumns, + state: { + rowSelection, + }, + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + }); + + return ; + }, +}; + +/** + * Implementation example showing how you can achieve grouping by creating a nested data object, + * and specify that grouping should be enabled in the data models. + * + * See: + * - https://tanstack.com/table/latest/docs/guide/expanding + * - https://tanstack.com/table/latest/docs/api/core/row#getleafrows + */ +export const Grouping: StoryObj = { + args: { + caption: 'Types of Wine', + tableStyle: 'border', + rowStyle: 'lined', + }, + render: (args) => { + type Wine = { + name: string; + country?: string; + year?: number; + }; + type GroupedWine = Wine & { wines?: Wine[] }; + const wineData: GroupedWine[] = [ + { + name: 'Reds', + wines: [ + { + name: 'Merlot', + country: 'France', + year: 2016, + }, + { + name: 'Pinot Noir', + country: 'France', + year: 2018, + }, + { + name: 'Chianti', + country: 'Italy', + year: 2018, + }, + ], + }, + { + name: 'Whites', + wines: [ + { + name: 'Chardonnay', + country: 'France', + year: 2016, + }, + { + name: 'Riesling', + country: 'Germany', + year: 2018, + }, + ], + }, + { + name: 'Rosés', + wines: [ + { + name: 'Rosado', + country: 'Spain', + year: 2021, + }, + { + name: 'Rosato', + country: 'Italy', + year: 2024, + }, + ], + }, + ]; + + const columnHelper = DataTableUtils.createColumnHelper(); + + const wineColumns = [ + columnHelper.accessor('name', { + header: () => Name, + cell: (info) => ( + {info.getValue()} + ), + }), + columnHelper.accessor('country', { + id: 'lastName', + header: () => ( + Country of Origin + ), + cell: (info) => ( + {info.getValue()} + ), + }), + columnHelper.accessor('year', { + header: () => ( + Year + ), + cell: (info) => ( + + {info.renderValue()} + + ), + }), + ]; + + // eslint-disable-next-line react-hooks/rules-of-hooks + const table = DataTableUtils.useReactTable({ + data: wineData, + columns: wineColumns, + getSubRows: (row) => row.wines, + getCoreRowModel: DataTableUtils.getCoreRowModel(), + getExpandedRowModel: DataTableUtils.getExpandedRowModel(), + }); + + return ; + }, +}; + +// TODO: Story for sticky column pinning (https://tanstack.com/table/latest/docs/framework/react/examples/column-pinning-sticky) + +export const DefaultWithCustomTable: StoryObj = { + args: { + children: ( + + + + + + +
TODO: Custom table rows/cells here
+ ), + }, +}; + +export const WithBasicCaption: StoryObj = { + args: { + ...DefaultWithCustomTable.args, + caption: 'Fruits of the world', + }, +}; + +export const WithFullCaption: StoryObj = { + ...DefaultWithCustomTable, + args: { + ...DefaultWithCustomTable.args, + caption: 'Fruits of the world', + subcaption: "Aren't they all so delicious?", + }, +}; + +export const WithSearch: StoryObj = { + args: { + ...DefaultWithCustomTable.args, + caption: 'Fruits of the world', + subcaption: "Aren't they all so delicious?", + onSearchChange: () => {}, + }, +}; + +export const WithOnlyActions: StoryObj = { + args: { + ...DefaultWithCustomTable.args, + actions: ( + + + + + + + ), + }, +}; + +export const WithLongCaption: StoryObj = { + args: { + ...DefaultWithCustomTable.args, + caption: + 'This is a really long title that really should not be this long and it just keeps going and going and going', + subcaption: 'Seriously, who let this happen?', + onSearchChange: () => {}, + actions: ( + + + + + + + + + + + +
+ TODO: Custom table rows/cells here +
+ +`; + +exports[` WithOnlyActions story renders snapshot 1`] = ` +
+
+
+
+ + + +
+
+
+ + + + + + +
+ TODO: Custom table rows/cells here +
+
+`; + +exports[` WithSearch story renders snapshot 1`] = ` +
+
+
+ + +
+ +
+ + + + + + +
+ TODO: Custom table rows/cells here +
+
+`; + +exports[` WithSearchAndActions story renders snapshot 1`] = ` +
+
+
+ + +
+ +
+
+ + + +
+
+
+ + + + + + +
+ TODO: Custom table rows/cells here +
+
+`; + +exports[` WithSearchAndCustomActions story renders snapshot 1`] = ` +
+
+
+ + +
+ +
+
+ + + +
+
+
+ + + + + + +
+ TODO: Custom table rows/cells here +
+
+`; diff --git a/src/components/DataTable/index.ts b/src/components/DataTable/index.ts new file mode 100644 index 000000000..86bf952c7 --- /dev/null +++ b/src/components/DataTable/index.ts @@ -0,0 +1,6 @@ +export { DataTable as default } from './DataTable'; +export type { DataTableProps } from './DataTable'; + +// Re-export Tanstack hooks and functions to consumers +// https://tanstack.com/table/latest +export * as utils from '@tanstack/react-table'; diff --git a/src/components/PopoverContainer/index.ts b/src/components/PopoverContainer/index.ts index 2d1758bd2..8e40e54f5 100644 --- a/src/components/PopoverContainer/index.ts +++ b/src/components/PopoverContainer/index.ts @@ -2,7 +2,7 @@ export { PopoverContainer as default, defaultPopoverModifiers, } from './PopoverContainer'; -// TODO: remove V2 export +// TODO(next-major): remove V2 export export { PopoverContainer as PopoverContainerV2, defaultPopoverModifiers as defaultPopoverModifiersV2, diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index ac425018a..082993fa1 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -294,6 +294,7 @@ export const TableRow = ({ */ export const Table = ({ children, className, ...other }: TableProps) => { const componentClassName = clsx(styles['table'], className); + // TODO(next-major): decide if we should warn when used return ( {children} diff --git a/src/design-tokens/primitives.json b/src/design-tokens/primitives.json index b6e1733d5..8a9f7d5af 100644 --- a/src/design-tokens/primitives.json +++ b/src/design-tokens/primitives.json @@ -655,6 +655,11 @@ "group": "size", "comment": "Relative EMs (rem)" }, + "34": { + "value": "272", + "group": "size", + "comment": "Relative EMs (rem)" + }, "40": { "value": "320", "group": "size", diff --git a/src/index.ts b/src/index.ts index 47b2912b0..beadb701b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,6 +29,8 @@ export { default as Button } from './components/Button'; export { default as ButtonGroup } from './components/ButtonGroup'; export { default as Card } from './components/Card'; export { default as Checkbox } from './components/Checkbox'; +export { default as DataTable } from './components/DataTable'; +export { utils as DataTableUtils } from './components/DataTable'; export { default as FieldLabel } from './components/FieldLabel'; export { default as FieldNote } from './components/FieldNote'; export { default as Fieldset } from './components/Fieldset'; @@ -60,6 +62,6 @@ export type { LinkProps } from './components/Link'; export type { PageNotificationProps } from './components/PageNotification'; export type { AppNotificationProps } from './components/AppNotification'; -// TODO: Remove the below types at the next major release +// TODO(next-major): Remove the below types at the next major release export type { PageNotificationProps as PageNotificationV2Props } from './components/PageNotification'; export type { AppNotificationProps as AppNotificationV2Props } from './components/AppNotification'; diff --git a/src/tokens-dist/css/variables.css b/src/tokens-dist/css/variables.css index 4778c90d2..229db7bf8 100644 --- a/src/tokens-dist/css/variables.css +++ b/src/tokens-dist/css/variables.css @@ -13,6 +13,7 @@ --eds-size-half: 4; /* Relative EMs (rem) */ --eds-size-base-unit: 8; /* Relative EMs (rem) @deprecated This should not be used in code or design. It will be removed in a future version of EDS. */ --eds-size-40: 320; /* Relative EMs (rem) */ + --eds-size-34: 272; /* Relative EMs (rem) */ --eds-size-32: 256; /* Relative EMs (rem) */ --eds-size-24: 192; /* Relative EMs (rem) */ --eds-size-20: 160; /* Relative EMs (rem) */ diff --git a/src/tokens-dist/json/variables-nested.json b/src/tokens-dist/json/variables-nested.json index a7af61bb3..ed6350f8b 100644 --- a/src/tokens-dist/json/variables-nested.json +++ b/src/tokens-dist/json/variables-nested.json @@ -1465,6 +1465,7 @@ "20": "160", "24": "192", "32": "256", + "34": "272", "40": "320", "base-unit": "8", "half": "4", diff --git a/src/util/variant-types.ts b/src/util/variant-types.ts index 1ffd404ca..959ee6b7b 100644 --- a/src/util/variant-types.ts +++ b/src/util/variant-types.ts @@ -1,5 +1,6 @@ /** * This contains the broad types of the common programmatic variants: e.g., + * - base component props * - size * - align * - preset @@ -7,6 +8,20 @@ * use Extract to trim any unsupported variants */ +/** + * Component props used by any/every cmoponent in the system. Pick<> to grab any subset + */ +export type EDSBase = { + /** + * Sub-components and other elements appropriate for this parent component (See Sub-components if applicable) + */ + children?: React.ReactNode; + /** + * CSS class names that can be appended to the component. + */ + className?: string; +}; + /** * Size range for components, set at named intervals. Sizes need not be precisely * some distant or multiple apart; they can be defined as a set that increases with @@ -16,8 +31,9 @@ export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl'; /** * Alignment variants, for horizontal components and sub-components + * TODO(next-major): warn on using left/right */ -export type Align = 'left' | 'center' | 'right'; +export type Align = 'leading' | 'trailing' | 'left' | 'center' | 'right'; /** * Hints are form field directions on how to use the field and whether it requires a value. diff --git a/yarn.lock b/yarn.lock index 90bb16ef3..7e7ef3194 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2296,6 +2296,7 @@ __metadata: "@storybook/test": "npm:^8.3.2" "@storybook/testing-library": "npm:^0.2.2" "@storybook/theming": "npm:^8.3.2" + "@tanstack/react-table": "npm:^8.20.5" "@testing-library/jest-dom": "npm:^6.5.0" "@testing-library/react": "npm:^16.0.1" "@testing-library/user-event": "npm:^14.5.2" @@ -5397,6 +5398,18 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-table@npm:^8.20.5": + version: 8.20.5 + resolution: "@tanstack/react-table@npm:8.20.5" + dependencies: + "@tanstack/table-core": "npm:8.20.5" + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + checksum: 10/df67094795a0b7e4b34f73abe346443c2e806c572fea31b58759aa8ec5274f613e5e6941090eb16f861bda10d3088731bc6e7f15e5f90326db273bc55b9141ce + languageName: node + linkType: hard + "@tanstack/react-virtual@npm:^3.0.0-beta.60": version: 3.0.1 resolution: "@tanstack/react-virtual@npm:3.0.1" @@ -5409,6 +5422,13 @@ __metadata: languageName: node linkType: hard +"@tanstack/table-core@npm:8.20.5": + version: 8.20.5 + resolution: "@tanstack/table-core@npm:8.20.5" + checksum: 10/5408237920d5796951e925278edbbe76f71006627a4e3da248a810970256f75d973538fe7ae75a32155d4a25a95abc4fffaea337b5120f7940d7e664dc9da87f + languageName: node + linkType: hard + "@tanstack/virtual-core@npm:3.0.0": version: 3.0.0 resolution: "@tanstack/virtual-core@npm:3.0.0"