Skip to content

Commit

Permalink
feat(DataTable): allow for pinning columns (#2084)
Browse files Browse the repository at this point in the history
- first column is pinned by default
- allow for other columns to be pinned
- clean up existing stories to fit with design
  • Loading branch information
booc0mtaco authored Nov 5, 2024
1 parent 1894c2d commit 86d7d07
Show file tree
Hide file tree
Showing 4 changed files with 2,107 additions and 172 deletions.
26 changes: 25 additions & 1 deletion src/components/DataTable/DataTable.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@
border-bottom: calc(var(--eds-border-width-sm) * 1px) solid;
position: sticky;
top: -1px;

/* adding to z-index above any of the contents of tbody */
z-index: 2;
}

.data-table__group-row {
Expand All @@ -200,9 +203,30 @@
}
}

.data-table--is-pinned {
.data-table--row-is-pinned {
box-shadow: var(--eds-box-shadow-sm);
}

.data-table--column-is-pinned {
/* When pinning columns, width and offset position are dynamic */

/* inherit the background color from the enclosing row */
background-color: inherit;
position: sticky;
z-index: 1;

&::after {
/* TODO: re-attach to a proper token value if possible */
box-shadow: 1px 0px 0px rgba(0, 0, 0, 0.25), 2px 0 3px 0 rgba(0, 0, 0, 0.25);
display: block;
height: 100%;
content: ' ';

position: absolute;
top: 0;
right: 0;
width: 1px;
}
}

/**
Expand Down
37 changes: 31 additions & 6 deletions src/components/DataTable/DataTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,7 @@ const columnHelper = DataTableUtils.createColumnHelper<Person>();
const columns = [
columnHelper.accessor('firstName', {
header: () => (
<DataTable.HeaderCell
leadingIcon="person-add"
sortDirection="ascending"
sublabel="Given Name"
>
<DataTable.HeaderCell sortDirection="ascending" sublabel="Given Name">
First Name
</DataTable.HeaderCell>
),
Expand Down Expand Up @@ -792,7 +788,36 @@ export const StatusRows: StoryObj<Args> = {
},
};

// TODO: Story for sticky column pinning (https://tanstack.com/table/latest/docs/framework/react/examples/column-pinning-sticky)
/**
* Allow for fixing some columns to not scroll off the screen, like freezing a column
*
* * This first column is sticky by default
* * Subsequent rows can be made sticky as well
*
* See: https://tanstack.com/table/latest/docs/framework/react/examples/column-pinning-sticky
* See: https://tanstack.com/table/latest/docs/guide/column-pinning
*/
export const HorizontalScrolling: StoryObj<Args> = {
args: {
tableStyle: 'border',
size: 'sm',
},
render: (args) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const table = DataTableUtils.useReactTable({
data: [...defaultData, ...defaultData],
columns,
getCoreRowModel: DataTableUtils.getCoreRowModel(),
initialState: {
columnPinning: {
left: ['firstName'],
},
},
});

return <DataTable {...args} className="w-[800px]" table={table} />;
},
};

export const DefaultWithCustomTable: StoryObj<Args> = {
args: {
Expand Down
85 changes: 60 additions & 25 deletions src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ export function DataTable<T>({
...rest
}: DataTableProps<T>) {
const componentClassName = clsx(styles['data-table'], className);

/**
* to handle (sub-)caption, render outside the table, but put the combined text in
* <caption>, and set to hidden in css. that way you can control the layout of the combined
Expand Down Expand Up @@ -237,13 +236,23 @@ export function DataTable<T>({
header.getSize() !== 150
? `${header.getSize()}px`
: undefined;

const headerClassNames = clsx(
styles['data-table__header-cell-container'],
header.column.getIsPinned() === 'left' &&
styles['data-table--column-is-pinned'],
);
return (
<th
className={styles['data-table__header-cell-container']}
className={headerClassNames}
colSpan={header.colSpan}
key={header.id}
style={{
width: columnWidth,
left:
header.column.getIsPinned() === 'left'
? `${header.column.getStart('left')}px`
: undefined,
}}
>
{header.isPlaceholder
Expand All @@ -270,17 +279,30 @@ export function DataTable<T>({
/>
{row.getLeafRows().map((row) => (
<DataTableRow key={row.id}>
{row.getVisibleCells().map((cell) => (
<td
className={styles['data-table__cell-container']}
key={cell.id}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
))}
{row.getVisibleCells().map((cell) => {
const cellClassNames = clsx(
styles['data-table__cell-container'],
cell.column.getIsPinned() === 'left' &&
styles['data-table--column-is-pinned'],
);
return (
<td
className={cellClassNames}
key={cell.id}
style={{
left:
cell.column.getIsPinned() === 'left'
? `${cell.column.getStart('left')}px`
: undefined,
}}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
);
})}
</DataTableRow>
))}
</>
Expand All @@ -292,17 +314,30 @@ export function DataTable<T>({
isStatusEligible ? row.getValue('status') : undefined
}
>
{row.getVisibleCells().map((cell) => (
<td
className={styles['data-table__cell-container']}
key={cell.id}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
))}
{row.getVisibleCells().map((cell) => {
const cellClassNames = clsx(
styles['data-table__cell-container'],
cell.column.getIsPinned() === 'left' &&
styles['data-table--column-is-pinned'],
);
return (
<td
className={cellClassNames}
key={cell.id}
style={{
left:
cell.column.getIsPinned() === 'left'
? `${cell.column.getStart('left')}px`
: undefined,
}}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</td>
);
})}
</DataTableRow>
)}
</React.Fragment>
Expand Down Expand Up @@ -503,7 +538,7 @@ export const DataTableTable = ({
observer = new IntersectionObserver(
([event]) => {
return event.target.classList.toggle(
styles['data-table--is-pinned'],
styles['data-table--row-is-pinned'],
event.intersectionRatio < 1,
);
},
Expand Down
Loading

0 comments on commit 86d7d07

Please sign in to comment.