Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add decorator in dataTable #18114

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,18 @@ Map {
},
},
},
"TableDecoratorRow": Object {
"displayName": "TableDecoratorRow",
"propTypes": Object {
"className": Object {
"type": "string",
},
"decorator": Object {
"type": "node",
},
"slug": [Function],
},
},
"TableExpandHeader": Object {
"propTypes": Object {
"aria-controls": Object {
Expand Down Expand Up @@ -7987,6 +7999,18 @@ Map {
},
},
},
"TableDecoratorRow" => Object {
"displayName": "TableDecoratorRow",
"propTypes": Object {
"className": Object {
"type": "string",
},
"decorator": Object {
"type": "node",
},
"slug": [Function],
},
},
"TableExpandHeader" => Object {
"propTypes": Object {
"aria-controls": Object {
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import TableBatchActions from './TableBatchActions';
import TableBody from './TableBody';
import TableCell from './TableCell';
import TableContainer from './TableContainer';
import TableDecoratorRow from './TableDecoratorRow';
import TableExpandHeader from './TableExpandHeader';
import TableExpandRow from './TableExpandRow';
import TableExpandedRow from './TableExpandedRow';
Expand Down Expand Up @@ -99,6 +100,7 @@ export interface DataTableHeader {
key: string;
header: React.ReactNode;
slug?: React.ReactElement;
decorator?: React.ReactElement;
}

export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
Expand Down Expand Up @@ -204,6 +206,7 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
getCellProps: (getCellPropsArgs: { cell: DataTableCell<ColTypes> }) => {
[key: string]: unknown;
hasSlugHeader?: boolean;
hasDecoratorHeader?: boolean;
};

// Custom event handlers
Expand Down Expand Up @@ -390,6 +393,7 @@ class DataTable<RowType, ColTypes extends any[]> extends React.Component<
static TableBody: typeof TableBody;
static TableCell: typeof TableCell;
static TableContainer: typeof TableContainer;
static TableDecoratorRow: typeof TableDecoratorRow;
static TableExpandHeader: typeof TableExpandHeader;
static TableExpandRow: typeof TableExpandRow;
static TableExpandedRow: typeof TableExpandedRow;
Expand Down Expand Up @@ -473,6 +477,7 @@ class DataTable<RowType, ColTypes extends any[]> extends React.Component<
isSortable,
isSortHeader: sortHeaderKey === header.key,
slug: header.slug,
decorator: header.decorator,
onClick: (event) => {
const nextSortState = getNextSortState(this.props, this.state, {
key: header.key,
Expand Down Expand Up @@ -748,6 +753,7 @@ class DataTable<RowType, ColTypes extends any[]> extends React.Component<
return {
...rest,
hasSlugHeader: cell.hasSlugHeader,
hasDecoratorHeader: cell.hasDecoratorHeader,
};
};

Expand Down Expand Up @@ -1035,6 +1041,7 @@ DataTable.TableBatchActions = TableBatchActions;
DataTable.TableBody = TableBody;
DataTable.TableCell = TableCell;
DataTable.TableContainer = TableContainer;
DataTable.TableDecoratorRow = TableDecoratorRow;
DataTable.TableExpandHeader = TableExpandHeader;
DataTable.TableExpandRow = TableExpandRow;
DataTable.TableExpandedRow = TableExpandedRow;
Expand Down
80 changes: 80 additions & 0 deletions packages/react/src/components/DataTable/TableDecoratorRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
import React, { ReactNode } from 'react';
import classNames from 'classnames';
import { usePrefix } from '../../internal/usePrefix';
import deprecate from '../../prop-types/deprecate';

export interface TableDecoratorRowProps {
/**
* The CSS class names of the cell that wraps the underlying input control
*/
className?: string;

/**
* @deprecated please use decorator instead.
* Provide a `Slug` component to be rendered inside the `TableSlugRow` component
*/
slug?: ReactNode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the deprecated slug if we are introducing a new component?


/**
* **Experimental**: Provide a `decorator` component to be rendered inside the `TableDecoratorRow` component
*/
decorator?: ReactNode;
}

const TableDecoratorRow = ({
className,
decorator,
slug,
}: TableDecoratorRowProps) => {
const prefix = usePrefix();
const TableDecoratorRowClasses = classNames({
...(className && { [className]: true }),
[`${prefix}--table-column-decorator`]: true,
[`${prefix}--table-column-decorator--active`]: decorator,
});

let normalizedDecorator = React.isValidElement(slug ?? decorator)
? slug ?? decorator
: null;
if (
normalizedDecorator &&
normalizedDecorator['type']?.displayName === 'AILabel'
) {
normalizedDecorator = React.cloneElement(
normalizedDecorator as React.ReactElement<any>,
{
size: 'mini',
}
);
}

return <td className={TableDecoratorRowClasses}>{normalizedDecorator}</td>;
};

TableDecoratorRow.displayName = 'TableDecoratorRow';
TableDecoratorRow.propTypes = {
/**
* The CSS class names of the cell that wraps the underlying input control
*/
className: PropTypes.string,

/**
* **Experimental**: Provide a `decorator` component to be rendered inside the `TableDecoratorRow` component
*/
decorator: PropTypes.node,

slug: deprecate(
PropTypes.node,
'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'
),
};

export default TableDecoratorRow;
19 changes: 14 additions & 5 deletions packages/react/src/components/DataTable/TableExpandRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,15 @@ const TableExpandRow = React.forwardRef(

// We need to put the slug before the expansion arrow and all other table cells after the arrow.
let rowHasSlug;
preetibansalui marked this conversation as resolved.
Show resolved Hide resolved
const slug = React.Children.toArray(children).map((child: any) => {
if (child.type?.displayName === 'TableSlugRow') {
if (child.props.slug) {
const decorator = React.Children.toArray(children).map((child: any) => {
if (
child.type?.displayName === 'TableSlugRow' ||
child.type?.displayName === 'TableDecoratorRow'
) {
if (
child.props.slug ||
child.props.decorator?.type.displayName === 'AILabel'
) {
rowHasSlug = true;
}

Expand All @@ -87,7 +93,10 @@ const TableExpandRow = React.forwardRef(

const normalizedChildren = React.Children.toArray(children).map(
(child: any) => {
if (child.type?.displayName !== 'TableSlugRow') {
if (
child.type?.displayName !== 'TableSlugRow' &&
child.type?.displayName !== 'TableDecoratorRow'
) {
return child;
}
}
Expand All @@ -106,7 +115,7 @@ const TableExpandRow = React.forwardRef(

return (
<tr {...rest} ref={ref as never} className={className} data-parent-row>
{slug}
{decorator}
preetibansalui marked this conversation as resolved.
Show resolved Hide resolved
<TableCell
className={`${prefix}--table-expand`}
data-previous-value={previousValue}
Expand Down
44 changes: 32 additions & 12 deletions packages/react/src/components/DataTable/TableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,16 @@ interface TableHeaderProps
scope?: string;

/**
* **Experimental**: Provide a `Slug` component to be rendered inside the `TableSlugRow` component
* @deprecated please use decorator instead.
* Provide a `Slug` component to be rendered inside the `TableSlugRow` component
*/
slug?: ReactNode;

/**
* **Experimental**: Provide a `decorator` component to be rendered inside the `TableDecoratorRow` component
*/
decorator?: ReactNode;

/**
* Specify which direction we are currently sorting by, should be one of DESC,
* NONE, or ASC.
Expand All @@ -130,6 +136,7 @@ const TableHeader = React.forwardRef(function TableHeader(
className: headerClassName,
children,
colSpan,
decorator,
isSortable = false,
isSortHeader,
onClick,
Expand All @@ -147,17 +154,29 @@ const TableHeader = React.forwardRef(function TableHeader(

// Slug is always size `mini`
const slugRef = useRef<HTMLInputElement>(null);
preetibansalui marked this conversation as resolved.
Show resolved Hide resolved
let normalizedSlug;
if (slug) {
normalizedSlug = React.cloneElement(slug as React.ReactElement<any>, {
size: 'mini',
ref: slugRef,
});

let colHasSlug;
let normalizedDecorator = React.isValidElement(slug ?? decorator)
? slug ?? decorator
: null;
if (
normalizedDecorator &&
normalizedDecorator['type']?.displayName === 'AILabel'
) {
colHasSlug = true;
normalizedDecorator = React.cloneElement(
normalizedDecorator as React.ReactElement<any>,
{
size: 'mini',
ref: slugRef,
}
);
}

const headerLabelClassNames = classNames({
[`${prefix}--table-header-label`]: true,
[`${prefix}--table-header-label--slug`]: slug,
[`${prefix}--table-header-label--slug`]: colHasSlug,
preetibansalui marked this conversation as resolved.
Show resolved Hide resolved
[`${prefix}--table-header-label--decorator`]: decorator,
});

if (!isSortable) {
Expand All @@ -172,7 +191,7 @@ const TableHeader = React.forwardRef(function TableHeader(
{children ? (
<div className={headerLabelClassNames}>
{children}
{normalizedSlug}
{normalizedDecorator}
</div>
) : null}
</th>
Expand All @@ -198,11 +217,12 @@ const TableHeader = React.forwardRef(function TableHeader(
});

const headerClasses = cx(headerClassName, `${prefix}--table-sort__header`, {
[`${prefix}--table-sort__header--slug`]: slug,
[`${prefix}--table-sort__header--slug`]: colHasSlug,
[`${prefix}--table-sort__header--decorator`]: decorator,
});

const handleClick = (evt) => {
if (slug && slugRef.current && slugRef.current.contains(evt.target)) {
if (colHasSlug && slugRef.current && slugRef.current.contains(evt.target)) {
return;
} else if (onClick) {
return onClick(evt);
Expand Down Expand Up @@ -233,7 +253,7 @@ const TableHeader = React.forwardRef(function TableHeader(
size={20}
className={`${prefix}--table-sort__icon-unsorted`}
/>
{normalizedSlug}
{normalizedDecorator}
</span>
</button>
</th>
Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/components/DataTable/TableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,14 @@ const TableRow = (props: TableRowProps) => {
let rowHasSlug;
if (props?.children) {
React.Children.toArray(props.children).map((child: any) => {
if (child.type?.displayName === 'TableSlugRow') {
if (child.props.slug) {
if (
child.type?.displayName === 'TableSlugRow' ||
child.type?.displayName === 'TableDecoratorRow'
) {
if (
child.props.slug ||
child.props.decorator?.type.displayName === 'AILabel'
) {
rowHasSlug = true;
}
}
Expand Down
10 changes: 9 additions & 1 deletion packages/react/src/components/DataTable/TableSlugRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
*/

import PropTypes from 'prop-types';
import React, { ReactNode } from 'react';
import React, { ReactNode, useEffect } from 'react';
import classNames from 'classnames';
import { usePrefix } from '../../internal/usePrefix';
import deprecateComponent from '../../prop-types/deprecateComponent';

export interface TableSlugRowProps {
/**
Expand All @@ -23,6 +24,13 @@ export interface TableSlugRowProps {
}

const TableSlugRow = ({ className, slug }: TableSlugRowProps) => {
useEffect(() => {
deprecateComponent(
'TableSlugRow',
'The `TableSlugRow` component has been deprecated and will be removed in the next major version. Use the TableDecoratorRow component instead.'
);
}, []);

const prefix = usePrefix();
const TableSlugRowClasses = classNames({
...(className && { [className]: true }),
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/components/DataTable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import TableBody from './TableBody';
import TableCell from './TableCell';
import TableContainer from './TableContainer';
import TableExpandHeader from './TableExpandHeader';
import TableDecoratorRow from './TableDecoratorRow';
import TableExpandRow from './TableExpandRow';
import TableExpandedRow from './TableExpandedRow';
import TableHead from './TableHead';
Expand All @@ -46,6 +47,7 @@ DataTable.TableBatchActions = TableBatchActions;
DataTable.TableBody = TableBody;
DataTable.TableCell = TableCell;
DataTable.TableContainer = TableContainer;
DataTable.TableDecoratorRow = TableDecoratorRow;
DataTable.TableExpandHeader = TableExpandHeader;
DataTable.TableExpandRow = TableExpandRow;
DataTable.TableExpandedRow = TableExpandedRow;
Expand Down Expand Up @@ -77,6 +79,7 @@ export {
TableBody,
TableCell,
TableContainer,
TableDecoratorRow,
TableExpandHeader,
TableExpandRow,
TableExpandedRow,
Expand Down
Loading
Loading