Skip to content

Commit de06f8a

Browse files
Merge pull request #360 from yamadayutaka/feature/filter-tooltip-value-fn
feat: add filterTooltipValueFn option to transform the value of the filter tooltip
2 parents 638088e + 28f0125 commit de06f8a

File tree

4 files changed

+160
-4
lines changed

4 files changed

+160
-4
lines changed

apps/mantine-react-table-docs/components/prop-tables/columnOptions.ts

+10
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,16 @@ export const columnOptions: ColumnOption[] = [
307307
required: false,
308308
type: 'MRT_FilterFn',
309309
},
310+
{
311+
columnOption: 'filterTooltipValueFn',
312+
defaultValue: '',
313+
description: 'Specify to transform tooltip values to a readable format.',
314+
link: '',
315+
linkText: '',
316+
source: 'MRT',
317+
required: false,
318+
type: 'MRT_FilterTooltipValueFn',
319+
},
310320
{
311321
columnOption: 'filterVariant',
312322
defaultValue: "'text'",

packages/mantine-react-table/src/components/head/MRT_TableHeadCellFilterLabel.tsx

+13-3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ export const MRT_TableHeadCellFilterLabel = <TData extends MRT_RowData>({
5454
columnDef._filterFn,
5555
);
5656
const currentFilterOption = columnDef._filterFn;
57+
const filterValueFn =
58+
columnDef.filterTooltipValueFn || ((value) => value as string);
59+
type FilterValueType = Parameters<typeof filterValueFn>[0];
5760
const filterTooltip =
5861
columnFilterDisplayMode === 'popover' && !isFilterActive
5962
? localization.filterByColumn?.replace(
@@ -70,10 +73,17 @@ export const MRT_TableHeadCellFilterLabel = <TData extends MRT_RowData>({
7073
'{filterValue}',
7174
`"${
7275
Array.isArray(column.getFilterValue())
73-
? (column.getFilterValue() as [string, string]).join(
74-
`" ${isRangeFilter ? localization.and : localization.or} "`,
76+
? (
77+
column.getFilterValue() as [
78+
FilterValueType,
79+
FilterValueType,
80+
]
7581
)
76-
: (column.getFilterValue() as string)
82+
.map((v) => filterValueFn(v))
83+
.join(
84+
`" ${isRangeFilter ? localization.and : localization.or} "`,
85+
)
86+
: filterValueFn(column.getFilterValue())
7787
}"`,
7888
)
7989
.replace('" "', '');

packages/mantine-react-table/src/types.ts

+3
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ export type MRT_ColumnDef<TData extends MRT_RowData, TValue = unknown> = Omit<
501501
enableEditing?: ((row: MRT_Row<TData>) => boolean) | boolean;
502502
enableFilterMatchHighlighting?: boolean;
503503
filterFn?: MRT_FilterFn<TData>;
504+
filterTooltipValueFn?: MRT_FilterTooltipValueFn;
504505
filterVariant?:
505506
| 'autocomplete'
506507
| 'checkbox'
@@ -737,6 +738,8 @@ export type MRT_FilterFn<TData extends MRT_RowData> =
737738
| FilterFn<TData>
738739
| MRT_FilterOption;
739740

741+
export type MRT_FilterTooltipValueFn<TValue = any> = (value: TValue) => string;
742+
740743
export type MRT_InternalFilterOption = {
741744
divider: boolean;
742745
label: string;

packages/mantine-react-table/stories/features/Filtering.stories.tsx

+134-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
import { useEffect, useState } from 'react';
2-
import { Button, Flex } from '@mantine/core';
2+
import { Button, Checkbox, Flex, Group, SegmentedControl } from '@mantine/core';
33
import {
44
type MRT_ColumnDef,
55
type MRT_ColumnFiltersState,
6+
type MRT_FilterTooltipValueFn,
67
MantineReactTable,
78
} from '../../src';
89
import { faker } from '@faker-js/faker';
910
import { type Meta } from '@storybook/react';
1011

12+
import { MRT_Localization_EN } from '../../src/locales/en';
13+
import { MRT_Localization_JA } from '../../src/locales/ja';
14+
15+
import dayjs from 'dayjs';
16+
import isBetween from 'dayjs/plugin/isBetween';
17+
import localizedFormat from 'dayjs/plugin/localizedFormat';
18+
dayjs.extend(isBetween);
19+
dayjs.extend(localizedFormat);
20+
import Dayjs_EN from 'dayjs/locale/en';
21+
import Dayjs_JA from 'dayjs/locale/ja';
22+
1123
const meta: Meta = {
1224
title: 'Features/Filtering Examples',
1325
};
@@ -730,3 +742,124 @@ export const ExternalSetFilterValue = () => (
730742
)}
731743
/>
732744
);
745+
746+
export const CustomTooltipValueFn = () => {
747+
const [localization, setLocalization] = useState(MRT_Localization_EN);
748+
const [locale, setLocale] = useState<string | undefined>('en');
749+
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
750+
[],
751+
);
752+
const [isActiveValueFn, setIsActiveValueFn] = useState<
753+
MRT_FilterTooltipValueFn<string> | undefined
754+
>(undefined);
755+
const [dateValueFn, setDateValueFn] = useState<
756+
MRT_FilterTooltipValueFn<Date> | undefined
757+
>(undefined);
758+
const [enableValueFns, setEnableValueFns] = useState(true);
759+
760+
const formatDate = (date: any, format: string) => {
761+
const d = dayjs(date || '');
762+
return d.isValid() ? d.format(format) : '';
763+
};
764+
const formatIsActiveValue = () => (value: string) =>
765+
value === 'true' ? 'Yes' : 'No';
766+
const formatDateValue = () => (value: Date) => formatDate(value, 'L');
767+
768+
useEffect(() => {
769+
switch (locale) {
770+
case 'en':
771+
setLocalization(MRT_Localization_EN);
772+
dayjs.locale(Dayjs_EN);
773+
break;
774+
case 'ja':
775+
setLocalization(MRT_Localization_JA);
776+
dayjs.locale(Dayjs_JA);
777+
break;
778+
}
779+
}, [locale]);
780+
781+
useEffect(() => {
782+
if (enableValueFns) {
783+
setIsActiveValueFn(formatIsActiveValue);
784+
setDateValueFn(formatDateValue);
785+
} else {
786+
setIsActiveValueFn(undefined);
787+
setDateValueFn(undefined);
788+
}
789+
}, [enableValueFns]);
790+
791+
return (
792+
<>
793+
<MantineReactTable
794+
renderTopToolbarCustomActions={() => (
795+
<Group>
796+
<Checkbox
797+
label="Enable Custom Tooltip Value Fn"
798+
checked={enableValueFns}
799+
onChange={(event) =>
800+
setEnableValueFns(event.currentTarget.checked)
801+
}
802+
/>
803+
<SegmentedControl
804+
data={['en', 'ja']}
805+
value={locale}
806+
onChange={setLocale}
807+
/>
808+
</Group>
809+
)}
810+
localization={localization}
811+
columns={[
812+
{
813+
Cell: ({ cell }) => (cell.getValue() === 'true' ? 'Yes' : 'No'),
814+
accessorFn: (originalRow) =>
815+
originalRow.isActive ? 'true' : 'false',
816+
filterVariant: 'checkbox',
817+
filterTooltipValueFn: isActiveValueFn, //transform data to readable format for tooltip
818+
header: 'Is Active',
819+
id: 'isActive',
820+
size: 200,
821+
},
822+
{
823+
accessorKey: 'firstName',
824+
header: 'First Name',
825+
},
826+
{
827+
accessorKey: 'lastName',
828+
header: 'Last Name',
829+
},
830+
{
831+
Cell: ({ cell }) => formatDate(cell.getValue<Date>(), 'L'), //transform data to readable format for cell render
832+
mantineFilterDateInputProps: {
833+
locale: locale,
834+
valueFormat: 'L',
835+
},
836+
accessorFn: (row) => new Date(row.birthDate), //transform data before processing so sorting works
837+
accessorKey: 'birthDate',
838+
filterVariant: 'date',
839+
filterTooltipValueFn: dateValueFn, //transform data to readable format for tooltip
840+
header: 'Birth Date (date)',
841+
sortingFn: 'datetime',
842+
},
843+
{
844+
Cell: ({ cell }) => formatDate(cell.getValue<Date>(), 'L'), //transform data to readable format for cell render
845+
mantineFilterDateInputProps: {
846+
locale: locale,
847+
valueFormat: 'L',
848+
},
849+
accessorFn: (row) => new Date(row.birthDate), //transform data before processing so sorting works
850+
accessorKey: 'birthDateRange',
851+
filterVariant: 'date-range',
852+
filterTooltipValueFn: dateValueFn, //transform data to readable format for tooltip
853+
header: 'Birth Date (date-range)',
854+
sortingFn: 'datetime',
855+
},
856+
]}
857+
data={data}
858+
onColumnFiltersChange={setColumnFilters}
859+
state={{
860+
columnFilters,
861+
}}
862+
/>
863+
</>
864+
);
865+
};

0 commit comments

Comments
 (0)