Skip to content

Commit

Permalink
#252 DataTable - add possibility of conditionally rendering the expan…
Browse files Browse the repository at this point in the history
…der (#258)

* #252 DataTable - add possibility of conditionally rendering the expander

* Rename customComponent -> predicateFallback

---------

Co-authored-by: Felix Beceic <[email protected]>
  • Loading branch information
fbeceic and Felix Beceic authored Jun 5, 2024
1 parent 6715027 commit d7484e6
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 24 deletions.
70 changes: 46 additions & 24 deletions libs/data-display/src/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,7 @@ import * as React from "react";

import { every, find, flatMap, identity, isEqual, pickBy, sum } from "lodash";
import _ from "lodash";
import {
Cell,
Column,
HeaderProps,
Row,
useExpanded,
UseExpandedRowProps,
useRowSelect,
useSortBy,
useTable,
} from "react-table";
import { Cell, Column, HeaderProps, Row, useExpanded, useRowSelect, useSortBy, useTable } from "react-table";

import { Card, CardHeaderProps } from "@tiller-ds/core";
import { Checkbox } from "@tiller-ds/form-elements";
Expand Down Expand Up @@ -217,8 +207,35 @@ type DataTableColumnProps<T extends object> = {
) &
TokenProps<"DataTable">;

type DataTableExpanderProps<T> = {
children: (item: T) => React.ReactNode;
type DataTableExpanderProps<T extends object> = {
/**
* Defines whether a given row should be expandable.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {boolean} - Returns true if the row is expandable, otherwise false.
*/
predicate?: (item: T, index: number) => boolean;
/**
* The component rendered when the predicate prop is not satisfied.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {React.ReactNode} - The custom component to render.
*/
predicateFallback?: (item: T, index: number) => React.ReactNode;
/**
* Expander content displayed when the expander is clicked.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {React.ReactNode} - The content to display in the expanded row.
*/
children: (item: T, index: number) => React.ReactNode;
/**
* Optional class name for the expander column.
*/
className?: string;
};

type DataTableSelectorProps<T extends object> = {
Expand Down Expand Up @@ -910,9 +927,8 @@ function DataTableCardHeaderSelector({ children }: DataTableCardHeaderSelectorPr
return <>{selectorTitle}</>;
}

function ExpanderCell({ row, ...props }: Cell & TokenProps<"DataTable">) {
function ExpanderCell<T extends object>({ row, ...props }: Pick<Cell<T>, "row"> & TokenProps<"DataTable">) {
const tokens = useTokens("DataTable", props.tokens);
const expandedRow = row as unknown as UseExpandedRowProps<{}>;

const openExpanderIcon = useIcon("openExpander", undefined, {
size: 3,
Expand All @@ -924,12 +940,8 @@ function ExpanderCell({ row, ...props }: Cell & TokenProps<"DataTable">) {
});

return (
<button
{...expandedRow.getToggleRowExpandedProps()}
type="button"
className="focus:outline-none select-none h-4 w-4"
>
{expandedRow.isExpanded ? closeExpanderIcon : openExpanderIcon}
<button {...row.getToggleRowExpandedProps()} type="button" className="focus:outline-none select-none h-4 w-4">
{row.isExpanded ? closeExpanderIcon : openExpanderIcon}
</button>
);
}
Expand Down Expand Up @@ -1059,11 +1071,21 @@ function extractColumns<T extends object>(
}

if (child.props.type === "DataTableExpander") {
const predicate = child.props.predicate ?? (() => false);
const Cell = child.props.predicate
? ({ row }: { row: Row<T> }) =>
predicate(row.original, row.index) ? (
child.props.predicateFallback && child.props.predicateFallback(row.original, row.index)
) : (
<ExpanderCell row={row} />
)
: ExpanderCell;

const column = {
Header: () => null,
id: "expander",
className: "w-px",
Cell: ExpanderCell,
className: child.props.className || "w-px",
Cell: Cell,
};

return [column as unknown as Column<T>];
Expand Down Expand Up @@ -1114,7 +1136,7 @@ DataTableColumn.defaultProps = {
canSort: false,
};

function DataTableExpander<T>(_: DataTableExpanderProps<T>) {
function DataTableExpander<T extends object>(_: DataTableExpanderProps<T>) {
return <></>;
}

Expand Down
29 changes: 29 additions & 0 deletions storybook/src/data-display/DataTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,35 @@ export const WithCustomExpander = (args) => (
</DataTable>
);

export const WithConditionalExpanderAtEnd = (args) => (
<DataTable data={smallData}>
<DataTable.Column header="ID" accessor="id" />
<DataTable.Column header="Name" accessor="name" />
<DataTable.Expander
predicate={(_: Item, index: number) => index % 2 === 1}
predicateFallback={(item: Item, _: number) => <p>{item.name}'s details not specified</p>}
className="w-[500px] text-right"
>
{(item: Item) => (
<span className="flex flex-col items-end">
<div>
<b>Age: </b>
{item.age}
</div>
<div>
<b>Applied for: </b>
{item.appliedFor}
</div>
<div>
<b>Annual Salary: </b>
{item.salary.annual}
</div>
</span>
)}
</DataTable.Expander>
</DataTable>
);

export const WithSelectorAtBeginning = () => {
// incl-code
const [, dataTableHook] = useDataTable();
Expand Down

0 comments on commit d7484e6

Please sign in to comment.