From dc062af8f514a570dcbacaa7a61dfb05a21a4b96 Mon Sep 17 00:00:00 2001 From: GermanVor Date: Wed, 17 Jan 2024 11:27:47 +0100 Subject: [PATCH] feat(table): add getRowDescriptor property --- src/components/Table/README.md | 9 +++ src/components/Table/Table.tsx | 58 +++++++++++++++++-- .../Table/__stories__/Table.stories.tsx | 4 +- .../withTableSelection/withTableSelection.tsx | 20 +++++++ 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/components/Table/README.md b/src/components/Table/README.md index 9f5a1c8b63..baa846e322 100644 --- a/src/components/Table/README.md +++ b/src/components/Table/README.md @@ -29,6 +29,7 @@ Additional functionality is enabled via HOCs: | data | Data | `any[]` | | | columns | Column parameters | `TableColumnConfig[]` | | | verticalAlign | Vertical alignment of contents | `"top"` `"middle"` | | +| getRowDescriptor | Row mouseleave handler | `(item: any, index: number) => DescriptorType` | | | getRowId | The row ID, used when selecting and sorting rows. If you skip a row, its ID will be the value of the field in the row data with the same name as the column ID | `string` `((item: any, index: number) => string)` | | | getRowClassNames | Row CSS classes | `(item: any, index: number) => string[]` | | | isRowDisabled | Condition for disabling columns | `(item: any, index: number) => boolean` | | @@ -41,6 +42,14 @@ Additional functionality is enabled via HOCs: | stickyHorizontalScroll | A horizontal sticky scroll in a table. NB: A table cannot have a fixed height and a sticky scroll at the same time. A sticky scroll will not work if the table has an overflow. | `boolean` | `false` | | stickyHorizontalScrollBreakpoint | The threshold that the parent block should reach before making a scroll sticky. This is useful in the console, for example, when the groupActions bar closes the scroll. | `number` | `0` | +### DescriptorType + +| Name | Description | Type | Default | +| :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------: | :---------: | +| id | The row ID, used when selecting and sorting rows. If you skip a row, its ID will be the value of the field in the row data with the same name as the column ID | `string` `undefined` | `undefined` | +| disabled | Column ID | `boolean` `undefined` | `undefined` | +| classNames | Row CSS classes | ` string[]` `undefined` | `undefined` | + ### TableColumnConfig | Name | Description | Type | Default | diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index a462982e3e..2bf73c7f1a 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -50,6 +50,25 @@ export interface TableColumnConfig { meta?: Record; } +export interface DescriptorType { + /** + * Row ID. + * Used when selecting and sorting rows. If you pass a row, + * its ID will be the value of the field in the row data named the same as the column ID. + */ + id?: string; + + /** + * Row CSS classes. + */ + classNames?: string[]; + + /** + * Condition for disabling columns. + */ + disabled?: boolean; +} + // TODO: Replace @default in props description with defaultProps in order to work with Storybook. export interface TableProps extends QAProps { /** Data */ @@ -75,15 +94,32 @@ export interface TableProps extends QAProps { */ stickyHorizontalScrollBreakpoint?: number; /** + * @deprecated Use getRowDescriptor instead + * * Row ID. * Used when selecting and sorting rows. If you pass a row, * its ID will be the value of the field in the row data named the same as the column ID. */ getRowId?: string | ((item: I, index: number) => string); - /** Row CSS classes. */ + /** + * @deprecated Use getRowDescriptor instead + * + * Row CSS classes. + * */ getRowClassNames?: (item: I, index: number) => string[]; - /** Condition for disabling columns. */ + /** + * @deprecated Use getRowDescriptor instead + * + * Condition for disabling columns. + * */ isRowDisabled?: (item: I, index: number) => boolean; + + /** + * + * @returns {DescriptorType} {@link DescriptorType} + */ + getRowDescriptor?: (item: I, index: number) => DescriptorType; + /** Row click handler. When passed row's hover is visible. */ onRowClick?: (item: I, index: number, event: React.MouseEvent) => void; /** Row mouseenter handler. */ @@ -124,9 +160,15 @@ export class Table> extends Rea // Static methods may be used by HOCs static getRowId(props: TableProps, item: I, rowIndex?: number) { - const {data, getRowId} = props; + const {data, getRowId, getRowDescriptor} = props; const index = rowIndex ?? data.indexOf(item); + const descriptor = getRowDescriptor?.(item, index); + + if (descriptor?.id !== undefined) { + return descriptor.id; + } + if (typeof getRowId === 'function') { return getRowId(item, index); } @@ -404,12 +446,18 @@ export class Table> extends Rea verticalAlign, edgePadding, wordWrap, + getRowDescriptor, } = this.props; const {columnsStyles} = this.state; - const disabled = isRowDisabled ? isRowDisabled(item, rowIndex) : false; + const descriptor = getRowDescriptor?.(item, rowIndex); + + const disabled = descriptor?.disabled || isRowDisabled?.(item, rowIndex) || false; + + const additionalClassNames = + descriptor?.classNames || getRowClassNames?.(item, rowIndex) || []; + const interactive = Boolean(!disabled && onRowClick); - const additionalClassNames = getRowClassNames ? getRowClassNames(item, rowIndex) : []; return ( >; -const DefaultTemplate: StoryFn> = (args) => ; +const DefaultTemplate: StoryFn> = (args) => { + return
; +}; export const Default = DefaultTemplate.bind({}); const EmptyDefaultTemplate: StoryFn> = (args) =>
; diff --git a/src/components/Table/hoc/withTableSelection/withTableSelection.tsx b/src/components/Table/hoc/withTableSelection/withTableSelection.tsx index 2cce5bb006..a0d58f0991 100644 --- a/src/components/Table/hoc/withTableSelection/withTableSelection.tsx +++ b/src/components/Table/hoc/withTableSelection/withTableSelection.tsx @@ -41,6 +41,7 @@ export function withTableSelection( columns, onRowClick, getRowClassNames, + getRowDescriptor, ...restTableProps } = this.props; @@ -50,6 +51,7 @@ export function withTableSelection( columns={this.enhanceColumns(columns)} onRowClick={this.enhanceOnRowClick(onRowClick)} getRowClassNames={this.enhanceGetRowClassNames(getRowClassNames)} + getRowDescriptor={this.enhanceGetRowDescriptor(getRowDescriptor)} /> ); } @@ -208,6 +210,24 @@ export function withTableSelection( const classNames = getRowClassNames ? getRowClassNames(item, index).slice() : []; + + const id = Table.getRowId(this.props, item, index); + const selected = selectedIds.includes(id); + + classNames.push(b('row', {selected})); + + return classNames; + }; + }, + ); + + // eslint-disable-next-line @typescript-eslint/member-ordering + private enhanceGetRowDescriptor = _memoize( + (getRowDescriptor?: TableProps['getRowDescriptor']) => { + return (item: I, index: number) => { + const {selectedIds} = this.props; + const classNames = getRowDescriptor?.(item, index).classNames?.slice() || []; + const id = Table.getRowId(this.props, item, index); const selected = selectedIds.includes(id);