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 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7a4f19d
chore: add decorator in dataTable
preetibansalui Nov 19, 2024
e5ed412
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Nov 21, 2024
7dd3da9
fix: replace slug with ai-lable
preetibansalui Nov 25, 2024
05f0a99
fix: test cases
preetibansalui Nov 25, 2024
e2515e0
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Nov 29, 2024
fbe8f25
fix: test case
preetibansalui Dec 1, 2024
aa7e98d
fix: test cases
preetibansalui Dec 2, 2024
9db81fc
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 10, 2024
473e0ee
fix: changed const name as per PR suggestions
preetibansalui Dec 10, 2024
6b6179c
Merge branch 'main' into 18005-add-decorator-in-dataTable
tay1orjones Dec 10, 2024
9134a4b
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 11, 2024
fd9b843
fix: css issues
preetibansalui Dec 16, 2024
703ab52
fix: css
preetibansalui Dec 16, 2024
4fa7717
fix: test
preetibansalui Dec 16, 2024
3ae6ca9
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 16, 2024
d4b9d88
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 17, 2024
3a37225
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 23, 2024
a646c18
fix: removed decorator stories
preetibansalui Dec 23, 2024
ea1c8c7
fix: test
preetibansalui Dec 24, 2024
adb1186
Merge branch 'main' into 18005-add-decorator-in-dataTable
preetibansalui Dec 24, 2024
ff2e40c
fix: test
preetibansalui Dec 24, 2024
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
22 changes: 22 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,17 @@ Map {
},
},
},
"TableDecoratorRow": Object {
"displayName": "TableDecoratorRow",
"propTypes": Object {
"className": Object {
"type": "string",
},
"decorator": Object {
"type": "node",
},
},
},
"TableExpandHeader": Object {
"propTypes": Object {
"aria-controls": Object {
Expand Down Expand Up @@ -7998,6 +8009,17 @@ Map {
},
},
},
"TableDecoratorRow" => Object {
"displayName": "TableDecoratorRow",
"propTypes": Object {
"className": Object {
"type": "string",
},
"decorator": Object {
"type": "node",
},
},
},
"TableExpandHeader" => Object {
"propTypes": Object {
"aria-controls": Object {
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ describe('Carbon Components React', () => {
"TableBody",
"TableCell",
"TableContainer",
"TableDecoratorRow",
"TableExpandHeader",
"TableExpandRow",
"TableExpandedRow",
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
66 changes: 66 additions & 0 deletions packages/react/src/components/DataTable/TableDecoratorRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* 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;

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

const TableDecoratorRow = ({
className,
decorator,
}: 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(decorator) ? 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,
};

export default TableDecoratorRow;
27 changes: 18 additions & 9 deletions packages/react/src/components/DataTable/TableExpandRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ const TableExpandRow = React.forwardRef(
) => {
const prefix = usePrefix();

// We need to put the slug before the expansion arrow and all other table cells after the arrow.
let rowHasSlug;
const slug = React.Children.toArray(children).map((child: any) => {
if (child.type?.displayName === 'TableSlugRow') {
if (child.props.slug) {
rowHasSlug = true;
// We need to put the AILabel and Decorator before the expansion arrow and all other table cells after the arrow.
let rowHasAILabel;
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'
) {
rowHasAILabel = true;
}

return child;
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 @@ -98,15 +107,15 @@ const TableExpandRow = React.forwardRef(
[`${prefix}--parent-row`]: true,
[`${prefix}--expandable-row`]: isExpanded,
[`${prefix}--data-table--selected`]: isSelected,
[`${prefix}--data-table--slug-row`]: rowHasSlug,
[`${prefix}--data-table--ai-label-row`]: rowHasAILabel,
Copy link
Member

Choose a reason for hiding this comment

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

I think we need both untill v12... people could be targetting these classes

Suggested change
[`${prefix}--data-table--ai-label-row`]: rowHasAILabel,
[`${prefix}--data-table--slug-row`]: slug && rowHasAILabel,
[`${prefix}--data-table--ai-label-row`]: rowHasAILabel,

Copy link
Contributor Author

@preetibansalui preetibansalui Dec 10, 2024

Choose a reason for hiding this comment

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

Hey Ari, here Slug is just a constant name which I have changed to decorator in line no 78 of this file and added condition for both Slug or decorator. However, yes we can add both the classes [${prefix}--data-table--slug-row] and [${prefix}--data-table--ai-label-row] on same condition keeping in mind if any user is using the [${prefix}--data-table--slug-row] class name.

},
rowClassName
);
const previousValue = isExpanded ? 'collapsed' : undefined;

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
56 changes: 42 additions & 14 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 @@ -145,19 +152,31 @@ const TableHeader = React.forwardRef(function TableHeader(
const prefix = usePrefix();
const uniqueId = useId('table-sort');

// Slug is always size `mini`
const slugRef = useRef<HTMLInputElement>(null);
let normalizedSlug;
if (slug) {
normalizedSlug = React.cloneElement(slug as React.ReactElement<any>, {
size: 'mini',
ref: slugRef,
});
// AILabel is always size `mini`
const AILableRef = useRef<HTMLInputElement>(null);

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

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

if (!isSortable) {
Expand All @@ -172,7 +191,9 @@ const TableHeader = React.forwardRef(function TableHeader(
{children ? (
<div className={headerLabelClassNames}>
{children}
{normalizedSlug}
<div className={`${prefix}--table-header-label--decorator-inner`}>
{normalizedDecorator}
</div>
</div>
) : null}
</th>
Expand All @@ -198,11 +219,16 @@ const TableHeader = React.forwardRef(function TableHeader(
});

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

const handleClick = (evt) => {
if (slug && slugRef.current && slugRef.current.contains(evt.target)) {
if (
colHasAILabel &&
AILableRef.current &&
AILableRef.current.contains(evt.target)
) {
return;
} else if (onClick) {
return onClick(evt);
Expand Down Expand Up @@ -233,7 +259,9 @@ const TableHeader = React.forwardRef(function TableHeader(
size={20}
className={`${prefix}--table-sort__icon-unsorted`}
/>
{normalizedSlug}
<div className={`${prefix}--table-header-label--decorator-inner`}>
{normalizedDecorator}
</div>
</span>
</button>
</th>
Expand Down
16 changes: 11 additions & 5 deletions packages/react/src/components/DataTable/TableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ export interface TableRowProps extends ReactAttr<HTMLTableRowElement> {
const TableRow = (props: TableRowProps) => {
const prefix = usePrefix();

let rowHasSlug;
let rowHasAILabel;
if (props?.children) {
React.Children.toArray(props.children).map((child: any) => {
if (child.type?.displayName === 'TableSlugRow') {
if (child.props.slug) {
rowHasSlug = true;
if (
child.type?.displayName === 'TableSlugRow' ||
child.type?.displayName === 'TableDecoratorRow'
) {
if (
child.props.slug ||
child.props.decorator?.type.displayName === 'AILabel'
) {
rowHasAILabel = true;
}
}
});
Expand All @@ -40,7 +46,7 @@ const TableRow = (props: TableRowProps) => {
// only useful in `TableExpandRow`
const className = cx(props.className, {
[`${prefix}--data-table--selected`]: props.isSelected,
[`${prefix}--data-table--slug-row`]: rowHasSlug,
[`${prefix}--data-table--ai-label-row`]: rowHasAILabel,
preetibansalui marked this conversation as resolved.
Show resolved Hide resolved
});

const cleanProps = {
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
Loading
Loading