Skip to content

Commit

Permalink
#182 - Enable Multi-column sorting in DataTable
Browse files Browse the repository at this point in the history
  • Loading branch information
imikulec committed Jan 23, 2024
1 parent 1df5d56 commit 0dc2e9b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 1 deletion.
12 changes: 11 additions & 1 deletion libs/data-display/src/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ export type DataTableProps<T extends object> = {
* Content to be displayed when the dataset is empty.
*/
emptyState?: React.ReactNode;

/**
* Enable or disable multi-column sorting.
* When set to true, users can sort by multiple columns simultaneously.
*/
enableMultiSort?: boolean;
} & DataTableTokensProps;

type DataTableTokensProps = {
Expand Down Expand Up @@ -463,6 +469,7 @@ function DataTable<T extends object>({
firstColumnFixed,
lastColumnFixed,
className,
enableMultiSort = false,
...props
}: DataTableProps<T>) {
const primaryRow = findChild("DataTablePrimaryRow", children);
Expand Down Expand Up @@ -500,7 +507,7 @@ function DataTable<T extends object>({
[getItemId]
);
const tokens = useTokens("DataTable", props.tokens);
const { getTableProps, getTableBodyProps, headerGroups, footerGroups, rows, prepareRow, visibleColumns, state } =
const { getTableProps, getTableBodyProps, headerGroups, footerGroups, rows, prepareRow, visibleColumns, state, toggleSortBy } =
useTable(
{
columns,
Expand Down Expand Up @@ -614,6 +621,9 @@ function DataTable<T extends object>({
{...column.getHeaderProps(column.getSortByToggleProps())}
className={tableHeaderClassName}
title={column.title}
onClick={() => {
toggleSortBy(column.id, undefined, enableMultiSort);
}}
>
<DataTableHeader alignHeader={alignHeader} {...column}>
{column.render("Header")}
Expand Down
61 changes: 61 additions & 0 deletions storybook/src/data-display/DataTable.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,67 @@ Here is an example utilizing the `useMemo` hook. This specific logic is applied

Now you have a DataTable component with sorting enabled for the specified column, and you can implement your own sorting logic based on your application requirements.

## Multi-column Sorting in DataTable

The `DataTable` component in `@tiller-ds` empowers you to implement **multi-column sorting**, allowing users to sort data across multiple columns simultaneously.
This enhanced functionality is achieved through the `toggleSortBy` method provided by the `useTable` hook.

To enable multi-column sorting, follow these steps:

**1.** Ensure that the columns for which you want to implement sorting have the `canSort` prop set to `true`:
```tsx
<DataTable.Column header="Name" accessor="name" canSort={true} />
<DataTable.Column header="Surname" accessor="surname" canSort={true} />
```

**2.** For multi-column sorting, apply sorting logic based on the priority of columns specified in the sort state:
```tsx
const [dataTableState, dataTableHook] = useDataTable({
defaultSortBy: [
{
column: "name",
sortDirection: "ASCENDING",
},
],
});

const columnMapping = {
name: "name",
surname: "surname",
};

const sortedData = React.useMemo(() => {
const sortInstructions = dataTableState.sortBy;

if (!sortInstructions || sortInstructions.length === 0) {
return [...allData];
}

return [...allData].sort((a, b) =>
sortInstructions.reduce((result, sortInfo) => {
const columnKey = columnMapping[sortInfo.column];

if (result === 0 && a[columnKey] !== undefined && b[columnKey] !== undefined) {
const result = a[columnKey].localeCompare(b[columnKey]);
return sortInfo.sortDirection === "DESCENDING" ? -result : result;
}

return result;
}, 0)
);
}, [dataTableState.sortBy]);
```

**3.** Set the `enableMultiSort` prop to `true` in the DataTable component to enable multi-column sorting:
```tsx
<DataTable data={sortedData} hook={dataTableHook} defaultSortBy={dataTableState.sortBy} enableMultiSort>
<DataTable.Column header="ID" accessor="id" canSort={false} />
<DataTable.Column header="Name" accessor="name" canSort={true} />
<DataTable.Column header="Surname" accessor="surname" canSort={true} />
</DataTable>

```

## Best Practices

Data Tables should:
Expand Down
50 changes: 50 additions & 0 deletions storybook/src/data-display/DataTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,55 @@ export const WithDefaultAscendingSortByName = () => {
)
};

export const WithDefaultAscendingMultiSort = () => {
const [dataTableState, dataTableHook] = useDataTable({
defaultSortBy: [
{
column: "name",
sortDirection: "ASCENDING",
},
{
column: "surname",
sortDirection: "ASCENDING",
},
],
});

const columnMapping = {
name: "name",
surname: "surname",
};

const sortedData = React.useMemo(() => {
const sortInstructions = dataTableState.sortBy;

if (!sortInstructions || sortInstructions.length === 0) {
return [...allData];
}

return [...allData].sort((a, b) =>
sortInstructions.reduce((result, sortInfo) => {
const columnKey = columnMapping[sortInfo.column];

if (result === 0 && a[columnKey] !== undefined && b[columnKey] !== undefined) {
const result = a[columnKey].localeCompare(b[columnKey]);
return sortInfo.sortDirection === "DESCENDING" ? -result : result;
}

return result;
}, 0)
);
}, [dataTableState.sortBy]);

return (
<DataTable data={sortedData} hook={dataTableHook} defaultSortBy={dataTableState.sortBy} enableMultiSort>
<DataTable.Column header="ID" accessor="id" canSort={false}/>
<DataTable.Column header="Name" accessor="name" canSort={true}/>
<DataTable.Column header="Surname" accessor="surname" canSort={true}/>
</DataTable>
)
};

export const WithIconButtons = () => (
<DataTable data={smallData}>
<DataTable.Column header="ID" accessor="id" />
Expand Down Expand Up @@ -995,6 +1044,7 @@ WithHorizontalScroll.argTypes = HideControls;
WithHorizontalScrollAndFirstColumnFixed.argTypes = HideControls;
WithHorizontalScrollAndLastColumnFixed.argTypes = HideControls;
WithDefaultAscendingSortByName.argTypes = HideControls;
WithDefaultAscendingMultiSort.argTypes = HideControls;
WithIconButtons.argTypes = HideControls;
WithPrimaryAndSecondaryRows.argTypes = HideControls;
WithPrimaryAndSecondaryRowsAndComplexValues.argTypes = HideControls;
Expand Down

0 comments on commit 0dc2e9b

Please sign in to comment.