Skip to content

Commit

Permalink
Merge pull request #7 from icflorescu/next
Browse files Browse the repository at this point in the history
Backport pinning the last column feature
  • Loading branch information
icflorescu committed Nov 7, 2023
2 parents ff4e99b + 2925d3f commit 148aca0
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 74 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
The following is a list of notable changes to the Mantine DataTable component.
Minor versions that are not listed in the changelog are bug fixes and small improvements.

## 6.0.5 (2023-11-07)

- Implement `pinLastColumn` feature

## 6.0.0 (2023-10-01)

- Bump version to 6.0.0 to match the compatible versions of `@mantine/hooks` and `@mantine/core`. From now on, let's keep the major version of `mantine-datatable` in sync with the major version of Mantine core
Expand Down
5 changes: 5 additions & 0 deletions docs/components/AppPartners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const PARTNERS = [
logo: { base: 'markup', ext: 'png', themed: true, scale: 72 },
link: 'https://www.getmarkup.com',
},
{
name: 'InvenTree',
logo: { base: 'inventree', ext: 'png', themed: true, scale: 140, shift: 1 },
link: 'https://inventree.org',
},
{
name: 'BookieBase',
logo: { base: 'bookiebase', ext: 'svg', themed: true, scale: 72, shift: 2 },
Expand Down
5 changes: 5 additions & 0 deletions docs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ export const PAGES: ({ external?: true; title: string; color?: MantineColor; des
title: 'Row actions cell',
description: 'Example: how to implement a row actions cell on Mantine DataTable',
},
{
path: 'pinning-the-last-column',
title: 'Pinning the last column',
description: 'Example: how to pin the last column on Mantine DataTable',
},
{
path: 'links-or-buttons-inside-clickable-rows-or-cells',
title: 'Links or buttons inside clickable rows/cells',
Expand Down
96 changes: 96 additions & 0 deletions docs/examples/PinLastColumnExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { ActionIcon, Box, Button, Grid, Group, Stack, Text } from '@mantine/core';
import { closeModal, openModal } from '@mantine/modals';
import { IconEdit, IconEye, IconTrash } from '@tabler/icons-react';
import { DataTable } from 'mantine-datatable';
import { employees, type Employee } from '~/data';

const records = employees.slice(0, 5);

const showModal = ({ employee, action }: { employee: Employee; action: 'view' | 'edit' | 'delete' }) => {
openModal({
modalId: action,
title:
action === 'view'
? 'Showing company information'
: action === 'edit'
? 'Editing company information'
: 'Deleting company',
children: (
<Stack>
<Text>
{action === 'view'
? 'Here’s where you could show more information...'
: action === 'edit'
? 'Here’s where you could put an edit form...'
: 'Here’s where you could ask for confirmation before deleting...'}
</Text>
<Grid gutter="xs">
<Grid.Col span={2}>ID</Grid.Col>
<Grid.Col span={10}>{employee.id}</Grid.Col>
<Grid.Col span={2}>First name</Grid.Col>
<Grid.Col span={10}>{employee.firstName}</Grid.Col>
<Grid.Col span={2}>Last name</Grid.Col>
<Grid.Col span={10}>{employee.lastName}</Grid.Col>
</Grid>
<Button onClick={() => closeModal(action)}>Close</Button>
</Stack>
),
});
};

export default function PinLastColumnExample() {
// example-start
return (
<DataTable
pinLastColumn // 👈 make sure the last column is always visible
withBorder
columns={[
{ accessor: 'firstName', noWrap: true },
{ accessor: 'lastNameName', noWrap: true },
{ accessor: 'department.name', title: 'Department' },
{ accessor: 'department.company.name', title: 'Company', noWrap: true },
{ accessor: 'department.company.city', title: 'City', noWrap: true },
{ accessor: 'department.company.state', title: 'State' },
{ accessor: 'department.company.streetAddress', title: 'Address', noWrap: true },
{ accessor: 'department.company.missionStatement', title: 'Mission statement', noWrap: true },
{
accessor: 'actions',
title: <Box mr={6}>Row actions</Box>,
textAlignment: 'right',
render: (employee) => (
// example-skip action cells custom rendering
<Group spacing={4} noWrap position="right">
<ActionIcon
size="sm"
variant="subtle"
color="green"
onClick={() => showModal({ employee, action: 'view' })}
>
<IconEye size={16} />
</ActionIcon>
<ActionIcon
size="sm"
variant="subtle"
color="blue"
onClick={() => showModal({ employee, action: 'edit' })}
>
<IconEdit size={16} />
</ActionIcon>
<ActionIcon
size="sm"
variant="subtle"
color="red"
onClick={() => showModal({ employee, action: 'delete' })}
>
<IconTrash size={16} />
</ActionIcon>
</Group>
// example-resume
),
},
]}
records={records}
/>
);
// example-end
}
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mantine-datatable-docs",
"version": "6.0.4",
"version": "6.0.5",
"description": "Docs website for mantine-datatable; see ../package/package.json for more info",
"private": true,
"scripts": {
Expand All @@ -14,7 +14,7 @@
"@emotion/react": "^11.11.1",
"@emotion/server": "^11.11.0",
"@faker-js/faker": "^8.2.0",
"@formkit/auto-animate": "^0.8.0",
"@formkit/auto-animate": "^0.8.1",
"@mantine/core": "^6.0.21",
"@mantine/dates": "^6.0.21",
"@mantine/hooks": "^6.0.21",
Expand Down
49 changes: 49 additions & 0 deletions docs/pages/examples/pinning-the-last-column.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Code, Container } from '@mantine/core';
import { GetStaticProps, InferGetStaticPropsType } from 'next';
import CodeBlock from '~/components/CodeBlock';
import InternalLink from '~/components/InternalLink';
import PageNavigation from '~/components/PageNavigation';
import PageText from '~/components/PageText';
import PageTitle from '~/components/PageTitle';
import PinLastColumnExample from '~/examples/PinLastColumnExample';
import readCodeExample from '~/lib/readCodeExample';

const PATH = 'examples/pinning-the-last-column';

export const getStaticProps: GetStaticProps<{
code: string;
}> = async () => ({
props: { code: (await readCodeExample('examples/PinLastColumnExample.tsx')) as string },
});

export default function Page({ code }: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<Container>
<PageTitle of={PATH} />
<PageText>
You may have noticed that when you are using{' '}
<InternalLink to="/examples/records-selection">row selection</InternalLink> and the table needs to scroll
horizontally, the checkbox column is always visible. This is because the checkbox column is pinned to the left
side of the table.
</PageText>
<PageText>
In the same way, pinning the last column to the right side of the table could be useful when you have a table
with many columns and you want to make sure the last column is always visible, even when the table is scrolled
horizontally. For instance, you could use this feature to ensure that the{' '}
<InternalLink to="/examples/row-actions-cell">row actions</InternalLink> are always visible.
</PageText>
<PageText>
You can achieve this by setting the <Code>pinLastColumn</Code> DataTable prop to <Code>true</Code>:
</PageText>
<PinLastColumnExample />
<PageText>Here is the code:</PageText>
<CodeBlock language="typescript" content={code} />
<PageText warning>
Combining this feature with <InternalLink to="/examples/column-grouping">column grouping</InternalLink> may lead
to minor visual artifacts.
</PageText>
<PageText>Head over to the next example to discover more features.</PageText>
<PageNavigation of={PATH} />
</Container>
);
}
Binary file added docs/public/partners/inventree-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/partners/inventree-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mantine-datatable-turborepo",
"version": "6.0.4",
"version": "6.0.5",
"description": "Monorepo for mantine-datatable; see package/package.json for more info",
"private": true,
"workspaces": [
Expand All @@ -27,8 +27,8 @@
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^14.5.1",
"@types/jest": "^29.5.7",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"babel-jest": "^29.7.0",
"eslint": "^8.53.0",
"eslint-config-next": "^14.0.1",
Expand Down
42 changes: 40 additions & 2 deletions package/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, MantineSize, Portal, Table, createStyles, packSx, type MantineTheme } from '@mantine/core';
import { Box, MantineSize, Portal, Table, createStyles, packSx, px, type MantineTheme } from '@mantine/core';
import { useMergedRef } from '@mantine/hooks';
import {
useCallback,
Expand Down Expand Up @@ -39,6 +39,7 @@ const useStyles = createStyles(
) => {
const borderColorValue = typeof borderColor === 'function' ? borderColor(theme) : borderColor;
const rowBorderColorValue = typeof rowBorderColor === 'function' ? rowBorderColor(theme) : rowBorderColor;
const shadowGradientAlpha = theme.colorScheme === 'dark' ? 0.5 : 0.05;

return {
root: {
Expand Down Expand Up @@ -101,6 +102,40 @@ const useStyles = createStyles(
verticalAlign: 'bottom',
},
},
pinLastColumn: {
'th:last-of-type, td:last-of-type': {
position: 'sticky',
right: 0,
zIndex: 1,
background: 'inherit',
'&::after': {
content: "''",
position: 'absolute',
top: 0,
bottom: 0,
width: theme.spacing.sm,
background: `linear-gradient(to left, ${theme.fn.rgba(theme.black, shadowGradientAlpha)}, ${theme.fn.rgba(
theme.black,
0
)}), linear-gradient(to left, ${theme.fn.rgba(theme.black, shadowGradientAlpha)}, ${theme.fn.rgba(
theme.black,
0
)} 30%)`,
borderRight: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3]}`,
left: -px(theme.spacing.sm),
pointerEvents: 'none',
opacity: 0,
transition: `opacity 0.2s`,
},
},
},
pinnedColumnShadowVisible: {
'th:last-of-type, td:last-of-type': {
'&::after': {
opacity: 1,
},
},
},
};
}
);
Expand All @@ -120,6 +155,7 @@ export default function DataTable<T>({
fetching,
columns,
groups,
pinLastColumn,
defaultColumnProps,
defaultColumnRender,
idAccessor = 'id',
Expand Down Expand Up @@ -332,7 +368,7 @@ export default function DataTable<T>({
viewportRef={useMergedRef(scrollViewportRef, scrollViewportRefProp || null)}
topShadowVisible={!scrolledToTop}
leftShadowVisible={!(selectedRecords || scrolledToLeft)}
rightShadowVisible={!scrolledToRight}
rightShadowVisible={!scrolledToRight && !pinLastColumn}
bottomShadowVisible={!scrolledToBottom}
headerHeight={headerHeight}
footerHeight={footerHeight}
Expand All @@ -349,6 +385,8 @@ export default function DataTable<T>({
[classes.verticalAlignmentTop]: verticalAlignment === 'top',
[classes.verticalAlignmentBottom]: verticalAlignment === 'bottom',
[classes.tableWithColumnBordersAndSelectableRecords]: selectionColumnVisible && withColumnBorders,
[classes.pinLastColumn]: pinLastColumn,
[classes.pinnedColumnShadowVisible]: pinLastColumn && !scrolledToRight,
})}
striped={recordsLength ? striped : false}
{...otherProps}
Expand Down
2 changes: 1 addition & 1 deletion package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mantine-datatable",
"version": "6.0.4",
"version": "6.0.5",
"description": "The dependency-free datatable component for Mantine UI, featuring asynchronous data loading support, pagination, multple rows selection, column sorting, custom cell data rendering, row context menu, row expansion and more",
"keywords": [
"mantine",
Expand Down
5 changes: 5 additions & 0 deletions package/types/DataTableProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export type DataTableProps<T> = {
*/
fetching?: boolean;

/**
* If true, the last column will be pinned to the right side of the table.
*/
pinLastColumn?: boolean;

/**
* Default column props; will be merged with column props provided to each column
*/
Expand Down
Loading

0 comments on commit 148aca0

Please sign in to comment.