Skip to content

Commit

Permalink
Merge pull request #604 from icflorescu/next
Browse files Browse the repository at this point in the history
Fix #596
  • Loading branch information
icflorescu authored Jun 18, 2024
2 parents 56776f6 + 8b08876 commit 63b9766
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 78 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
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.

## 7.10.3 (2024-06-18)

- Fix issue [#596](https://github.com/icflorescu/mantine-datatable/issues/596) (new columns don't appear when added to `useDataTableColumns`), thanks to [@gfazioli](https://github.com/gfazioli) for PR [#603](https://github.com/icflorescu/mantine-datatable/pull/603)
- Update dev dependencies

## 7.10.2 (2024-06-15)

- Update dev dependencies to ensure compatibility with Mantine 7.10.2 and Next.js 14.2.4
Expand Down
109 changes: 109 additions & 0 deletions app/examples/column-dragging-and-toggling/DynamicColumnExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
'use client';

import { Button, Group, Stack, Text } from '@mantine/core';
import { IconBuildingCommunity, IconBuildingSkyscraper, IconMap, IconRoadSign } from '@tabler/icons-react';
import { DataTable, useDataTableColumns } from '__PACKAGE__';
import { useState } from 'react';
import { companies } from '~/data';
import { DataTableColumn } from '~/dist';

export default function DynamicColumnExample() {
const key = 'dynamic-column-example';

const [columns, setColumns] = useState<DataTableColumn[]>([
{
accessor: 'name',
title: (
<Group gap={4} mt={-1}>
<IconBuildingSkyscraper size={16} />
<Text inherit mt={1}>
Company
</Text>
</Group>
),
width: '40%',
toggleable: true,
defaultToggle: false,
},
{
accessor: 'streetAddress',
title: (
<Group gap={4} mt={-1}>
<IconRoadSign size={16} />
<Text inherit mt={1}>
Street Address
</Text>
</Group>
),
width: '60%',
toggleable: true,
},
{
accessor: 'city',
title: (
<Group gap={4} mt={-1}>
<IconBuildingCommunity size={16} />
<Text inherit mt={1}>
City
</Text>
</Group>
),
width: 160,
toggleable: true,
},
{
accessor: 'state',
textAlign: 'right',
title: (
<Group justify="right">
<IconMap size={16} />
</Group>
),
},
]);

const { effectiveColumns, resetColumnsToggle } = useDataTableColumns({
key,
columns,
});

// add or remove the whole record with missionStatement accessor
function toggleColumnMissionStatement() {
const newColumns = columns.filter((col) => col.accessor !== 'missionStatement');
if (columns.length === newColumns.length) {
newColumns.push({
accessor: 'missionStatement',
title: (
<Group gap={4} mt={-1} wrap="nowrap">
<IconBuildingSkyscraper size={16} />
<Text inherit mt={1}>
Mission Statement
</Text>
</Group>
),
width: '40%',
toggleable: true,
defaultToggle: true,
});
}
setColumns(newColumns);
}

return (
<Stack>
<Group>
<Button onClick={toggleColumnMissionStatement}>Toggle Mission Statement column</Button>
</Group>
<DataTable
withTableBorder
withColumnBorders
storeColumnsKey={key}
records={companies}
columns={effectiveColumns}
/>
<Group justify="right">
<Button onClick={resetColumnsToggle}>Reset toggled columns</Button>
</Group>
</Stack>
);
}
12 changes: 12 additions & 0 deletions app/examples/column-dragging-and-toggling/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { allPromiseProps, getRouteMetadata } from '~/lib/utils';
import DraggingExample from './DraggingExample';
import DraggingTogglingComplexExample from './DraggingTogglingComplexExample';
import DraggingTogglingResetExample from './DraggingTogglingResetExample';
import DynamicColumnExample from './DynamicColumnExample';
import TogglingExample from './TogglingExample';

const PATH: Route = '/examples/column-dragging-and-toggling';
Expand All @@ -24,6 +25,7 @@ export default async function DraggingExamplePage() {
'DraggingExample.tsx': readCodeFile<string>(`${PATH}/DraggingExample.tsx`),
'DraggingTogglingResetExample.tsx': readCodeFile<string>(`${PATH}/DraggingTogglingResetExample.tsx`),
'TogglingExample.tsx': readCodeFile<string>(`${PATH}/TogglingExample.tsx`),
'DynamicColumnExample.tsx': readCodeFile<string>(`${PATH}/DynamicColumnExample.tsx`),
'DraggingTogglingComplexExample.tsx': readCodeFile<string>(`${PATH}/DraggingTogglingComplexExample.tsx`),
});

Expand Down Expand Up @@ -85,9 +87,19 @@ export default async function DraggingExamplePage() {
You may define which columns will be toggled by default by setting the <Code>defaultToggle</Code> property to{' '}
<Code>false</Code>.
</Txt>

<PageSubtitle value="Add & Remove column at run-time" />
<Txt>
Of course, you may need to add or remove columns at run-time. In this case, you can directly modify the array of
columns without needing to perform any operations.
</Txt>
<DynamicColumnExample />
<CodeBlock code={code['DynamicColumnExample.tsx']} />

<PageSubtitle value="Dragging and toggling with context menu reset" />
<DraggingTogglingResetExample />
<CodeBlock code={code['DraggingTogglingResetExample.tsx']} />

<PageSubtitle value="Complex usage" />
<DraggingTogglingComplexExample />
<CodeBlock code={code['DraggingTogglingComplexExample.tsx']} />
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mantine-datatable",
"version": "7.10.2",
"version": "7.10.3",
"description": "The lightweight, dependency-free, dark-theme aware table component for your Mantine UI data-rich applications, featuring asynchronous data loading support, pagination, intuitive Gmail-style additive batch rows selection, column sorting, custom cell data rendering, row expansion, nesting, context menus, and much more",
"keywords": [
"mantine",
Expand Down Expand Up @@ -82,13 +82,13 @@
"@mantine/modals": "^7.10.2",
"@mantine/notifications": "^7.10.2",
"@tabler/icons-react": "^3.6.0",
"@tanstack/react-query": "^5.45.0",
"@tanstack/react-query": "^5.45.1",
"@types/lodash": "^4.17.5",
"@types/node": "^20.14.2",
"@types/node": "^20.14.5",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"clsx": "^2.1.1",
"cssnano": "^7.0.2",
"dayjs": "^1.11.11",
Expand Down
133 changes: 118 additions & 15 deletions package/hooks/useDataTableColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,121 @@ export const useDataTableColumns = <T>({
*/
getInitialValueInEffect?: boolean;
}) => {
// align order
function alignColumnsOrder<T>(columnsOrder: string[], columns: DataTableColumn<T>[]) {
const updatedColumnsOrder: string[] = [];
columnsOrder.forEach((col) => {
if (columns.find((c) => c.accessor === col)) {
updatedColumnsOrder.push(col);
}
});
columns.forEach((col) => {
if (!updatedColumnsOrder.includes(col.accessor as string)) {
updatedColumnsOrder.push(col.accessor as string);
}
});
return updatedColumnsOrder;
}

// align toggle
function alignColumnsToggle<T>(columnsToggle: DataTableColumnToggle[], columns: DataTableColumn<T>[]) {
const updatedColumnsToggle: DataTableColumnToggle[] = [];
columnsToggle.forEach((col) => {
if (columns.find((c) => c.accessor === col.accessor)) {
updatedColumnsToggle.push(col);
}
});
columns.forEach((col) => {
if (!updatedColumnsToggle.find((c) => c.accessor === col.accessor)) {
updatedColumnsToggle.push({
accessor: col.accessor as string,
defaultToggle: col.defaultToggle || true,
toggleable: col.toggleable as boolean,
toggled: col.defaultToggle === undefined ? true : col.defaultToggle,
});
}
});
return updatedColumnsToggle as DataTableColumnToggle[];
}

// align width
function alignColumnsWidth<T>(columnsWidth: DataTableColumnWidth[], columns: DataTableColumn<T>[]) {
const updatedColumnsWidth: DataTableColumnWidth[] = [];

columnsWidth.forEach((col) => {
const accessor = Object.keys(col)[0];
if (columns.find((c) => c.accessor === accessor)) {
updatedColumnsWidth.push(col);
}
});

columns.forEach((col) => {
const accessor = col.accessor;
if (!updatedColumnsWidth.find((c) => Object.keys(c)[0] === accessor)) {
const widthObj: DataTableColumnWidth = {};
widthObj[accessor as string] = '';
updatedColumnsWidth.push(widthObj);
}
});

return updatedColumnsWidth;
}

// align order
function useAlignColumnsOrder() {
const [columnsOrder, setColumnsOrder] = useLocalStorage<string[]>({
key: `${key}-columns-order`,
defaultValue: defaultColumnsOrder as string[],
getInitialValueInEffect,
});

const alignedColumnsOrder = alignColumnsOrder(columnsOrder, columns);

const prevColumnsOrder = JSON.stringify(columnsOrder);

if (JSON.stringify(alignedColumnsOrder) !== prevColumnsOrder) {
setColumnsOrder(alignedColumnsOrder);
}

return [alignedColumnsOrder, setColumnsOrder] as const;
}

function useAlignColumnsToggle() {
const [columnsToggle, setColumnsToggle] = useLocalStorage<DataTableColumnToggle[]>({
key: `${key}-columns-toggle`,
defaultValue: defaultColumnsToggle as DataTableColumnToggle[],
getInitialValueInEffect,
});

const alignedColumnsToggle = alignColumnsToggle(columnsToggle, columns);

const prevColumnsToggle = JSON.stringify(columnsToggle);

if (JSON.stringify(alignedColumnsToggle) !== prevColumnsToggle) {
setColumnsToggle(alignedColumnsToggle);
}

return [alignColumnsToggle(columnsToggle, columns), setColumnsToggle] as const;
}

function useAlignColumnsWidth() {
const [columnsWidth, setColumnsWidth] = useLocalStorage<DataTableColumnWidth[]>({
key: `${key}-columns-width`,
defaultValue: defaultColumnsWidth as DataTableColumnWidth[],
getInitialValueInEffect,
});

const alignedColumnsWidth = alignColumnsWidth(columnsWidth, columns);

const prevColumnsWidth = JSON.stringify(columnsWidth);

if (JSON.stringify(alignedColumnsWidth) !== prevColumnsWidth) {
setColumnsWidth(alignedColumnsWidth);
}

return [alignColumnsWidth(columnsWidth, columns), setColumnsWidth] as const;
}

// Default columns id ordered is the order of the columns in the array
const defaultColumnsOrder = (columns && columns.map((column) => column.accessor)) || [];

Expand All @@ -55,25 +170,13 @@ export const useDataTableColumns = <T>({
}));

// Store the columns order in localStorage
const [columnsOrder, setColumnsOrder] = useLocalStorage<string[]>({
key: `${key}-columns-order`,
defaultValue: defaultColumnsOrder as string[],
getInitialValueInEffect,
});
const [columnsOrder, setColumnsOrder] = useAlignColumnsOrder();

// Store the columns toggle in localStorage
const [columnsToggle, setColumnsToggle] = useLocalStorage<DataTableColumnToggle[]>({
key: `${key}-columns-toggle`,
defaultValue: defaultColumnsToggle as DataTableColumnToggle[],
getInitialValueInEffect,
});
const [columnsToggle, setColumnsToggle] = useAlignColumnsToggle();

// Store the columns widths in localStorage
const [columnsWidth, setColumnsWidth] = useLocalStorage<DataTableColumnWidth[]>({
key: `${key}-columns-width`,
defaultValue: defaultColumnsWidth as DataTableColumnWidth[],
getInitialValueInEffect,
});
const [columnsWidth, setColumnsWidth] = useAlignColumnsWidth();

// we won't use the "remove" function from useLocalStorage() because
// we got issue with rendering
Expand Down
Loading

0 comments on commit 63b9766

Please sign in to comment.