material-react-table 0.27.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MaterialReactTable.d.ts +8 -4
- package/dist/column.utils.d.ts +1 -0
- package/dist/inputs/MRT_FilterTextField.d.ts +1 -1
- package/dist/localization.d.ts +9 -0
- package/dist/material-react-table.cjs.development.js +196 -129
- package/dist/material-react-table.cjs.development.js.map +1 -1
- package/dist/material-react-table.cjs.production.min.js +1 -1
- package/dist/material-react-table.cjs.production.min.js.map +1 -1
- package/dist/material-react-table.esm.js +197 -130
- package/dist/material-react-table.esm.js.map +1 -1
- package/dist/menus/MRT_FilterOptionMenu.d.ts +7 -0
- package/package.json +4 -4
- package/src/MaterialReactTable.tsx +10 -2
- package/src/body/MRT_TableBody.tsx +12 -12
- package/src/column.utils.ts +13 -0
- package/src/head/MRT_TableHeadCellFilterContainer.tsx +3 -1
- package/src/head/MRT_TableHeadCellFilterLabel.tsx +8 -3
- package/src/inputs/MRT_FilterRangeFields.tsx +2 -2
- package/src/inputs/MRT_FilterTextField.tsx +125 -82
- package/src/localization.ts +18 -0
- package/src/menus/MRT_FilterOptionMenu.tsx +101 -99
- package/src/table/MRT_TableRoot.tsx +2 -1
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import type { MRT_Header, MRT_TableInstance } from '..';
|
|
3
|
+
import { MRT_Localization } from '../localization';
|
|
4
|
+
export declare const internalFilterOptions: (localization: MRT_Localization) => {
|
|
5
|
+
option: string;
|
|
6
|
+
symbol: string;
|
|
7
|
+
label: string;
|
|
8
|
+
divider: boolean;
|
|
9
|
+
}[];
|
|
3
10
|
interface Props {
|
|
4
11
|
anchorEl: HTMLElement | null;
|
|
5
12
|
header?: MRT_Header;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.29.1",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "material-react-table",
|
|
5
|
-
"description": "A fully featured Material UI implementation of TanStack React Table
|
|
5
|
+
"description": "A fully featured Material UI V5 implementation of TanStack React Table V8, written from the ground up in TypeScript.",
|
|
6
6
|
"author": "Kevin Vandy",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"react-table",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@emotion/styled": "^11.9.3",
|
|
63
63
|
"@faker-js/faker": "^7.3.0",
|
|
64
64
|
"@mui/icons-material": "^5.8.4",
|
|
65
|
-
"@mui/material": "^5.9.
|
|
65
|
+
"@mui/material": "^5.9.2",
|
|
66
66
|
"@size-limit/preset-small-lib": "^7.0.8",
|
|
67
67
|
"@storybook/addon-a11y": "^6.5.9",
|
|
68
68
|
"@storybook/addon-actions": "^6.5.9",
|
|
@@ -101,6 +101,6 @@
|
|
|
101
101
|
"dependencies": {
|
|
102
102
|
"@tanstack/match-sorter-utils": "8.1.1",
|
|
103
103
|
"@tanstack/react-table": "8.2.6",
|
|
104
|
-
"react-virtual": "^
|
|
104
|
+
"@tanstack/react-virtual": "^3.0.0-beta.13"
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -40,7 +40,7 @@ import type {
|
|
|
40
40
|
TableOptions,
|
|
41
41
|
TableState,
|
|
42
42
|
} from '@tanstack/react-table';
|
|
43
|
-
import type {
|
|
43
|
+
import type { VirtualizerOptions } from '@tanstack/react-virtual';
|
|
44
44
|
import { MRT_Localization, MRT_DefaultLocalization_EN } from './localization';
|
|
45
45
|
import { MRT_Default_Icons, MRT_Icons } from './icons';
|
|
46
46
|
import { MRT_TableRoot } from './table/MRT_TableRoot';
|
|
@@ -225,6 +225,7 @@ export type MRT_ColumnDef<TData extends Record<string, any> = {}> = Omit<
|
|
|
225
225
|
enableEditing?: boolean;
|
|
226
226
|
filterFn?: MRT_FilterFn<TData>;
|
|
227
227
|
filterSelectOptions?: (string | { text: string; value: string })[];
|
|
228
|
+
filterVariant?: 'text' | 'select' | 'multi-select' | 'range';
|
|
228
229
|
/**
|
|
229
230
|
* footer must be a string. If you want custom JSX to render the footer, you can also specify a `Footer` option. (Capital F)
|
|
230
231
|
*/
|
|
@@ -302,9 +303,11 @@ export type MRT_ColumnDef<TData extends Record<string, any> = {}> = Omit<
|
|
|
302
303
|
| (({
|
|
303
304
|
table,
|
|
304
305
|
column,
|
|
306
|
+
rangeFilterIndex,
|
|
305
307
|
}: {
|
|
306
308
|
table: MRT_TableInstance<TData>;
|
|
307
309
|
column: MRT_Column<TData>;
|
|
310
|
+
rangeFilterIndex?: number;
|
|
308
311
|
}) => TextFieldProps);
|
|
309
312
|
muiTableHeadCellProps?:
|
|
310
313
|
| TableCellProps
|
|
@@ -341,6 +344,7 @@ export type MRT_DefinedColumnDef<TData extends Record<string, any> = {}> = Omit<
|
|
|
341
344
|
'id'
|
|
342
345
|
> & {
|
|
343
346
|
id: string;
|
|
347
|
+
_filterFn: MRT_FilterOption;
|
|
344
348
|
};
|
|
345
349
|
|
|
346
350
|
export type MRT_Column<TData extends Record<string, any> = {}> = Omit<
|
|
@@ -607,9 +611,11 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
|
|
|
607
611
|
| (({
|
|
608
612
|
table,
|
|
609
613
|
column,
|
|
614
|
+
rangeFilterIndex,
|
|
610
615
|
}: {
|
|
611
616
|
table: MRT_TableInstance<TData>;
|
|
612
617
|
column: MRT_Column<TData>;
|
|
618
|
+
rangeFilterIndex?: number;
|
|
613
619
|
}) => TextFieldProps);
|
|
614
620
|
muiTableHeadCellProps?:
|
|
615
621
|
| TableCellProps
|
|
@@ -779,7 +785,9 @@ export type MaterialReactTableProps<TData extends Record<string, any> = {}> =
|
|
|
779
785
|
selectAllMode?: 'all' | 'page';
|
|
780
786
|
state?: Partial<MRT_TableState<TData>>;
|
|
781
787
|
tableId?: string;
|
|
782
|
-
virtualizerProps?: Partial<
|
|
788
|
+
virtualizerProps?: Partial<
|
|
789
|
+
VirtualizerOptions<HTMLDivElement, HTMLTableRowElement>
|
|
790
|
+
>;
|
|
783
791
|
};
|
|
784
792
|
|
|
785
793
|
export default <TData extends Record<string, any> = {}>({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { FC, RefObject, useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useVirtualizer, Virtualizer } from '@tanstack/react-virtual';
|
|
3
3
|
import { TableBody } from '@mui/material';
|
|
4
4
|
import { MRT_TableBodyRow } from './MRT_TableBodyRow';
|
|
5
5
|
import { rankGlobalFuzzy } from '../sortingFns';
|
|
@@ -60,28 +60,27 @@ export const MRT_TableBody: FC<Props> = ({ table, tableContainerRef }) => {
|
|
|
60
60
|
globalFilter,
|
|
61
61
|
]);
|
|
62
62
|
|
|
63
|
-
const rowVirtualizer = enableRowVirtualization
|
|
64
|
-
?
|
|
65
|
-
|
|
63
|
+
const rowVirtualizer: Virtualizer = enableRowVirtualization
|
|
64
|
+
? useVirtualizer({
|
|
65
|
+
estimateSize: () => (density === 'compact' ? 25 : 50),
|
|
66
66
|
overscan: density === 'compact' ? 30 : 10,
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
getScrollElement: () => tableContainerRef.current as HTMLDivElement,
|
|
68
|
+
count: rows.length,
|
|
69
69
|
...virtualizerProps,
|
|
70
70
|
})
|
|
71
71
|
: ({} as any);
|
|
72
72
|
|
|
73
73
|
const virtualRows = enableRowVirtualization
|
|
74
|
-
? rowVirtualizer.
|
|
74
|
+
? rowVirtualizer.getVirtualItems()
|
|
75
75
|
: [];
|
|
76
76
|
|
|
77
77
|
let paddingTop = 0;
|
|
78
78
|
let paddingBottom = 0;
|
|
79
79
|
if (enableRowVirtualization) {
|
|
80
|
-
paddingTop = virtualRows.length
|
|
81
|
-
paddingBottom =
|
|
82
|
-
virtualRows.length
|
|
83
|
-
|
|
84
|
-
: 0;
|
|
80
|
+
paddingTop = !!virtualRows.length ? virtualRows[0].start : 0;
|
|
81
|
+
paddingBottom = !!virtualRows.length
|
|
82
|
+
? rowVirtualizer.getTotalSize() - virtualRows[virtualRows.length - 1].end
|
|
83
|
+
: 0;
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
return (
|
|
@@ -91,6 +90,7 @@ export const MRT_TableBody: FC<Props> = ({ table, tableContainerRef }) => {
|
|
|
91
90
|
<td style={{ height: `${paddingTop}px` }} />
|
|
92
91
|
</tr>
|
|
93
92
|
)}
|
|
93
|
+
{/* @ts-ignore */}
|
|
94
94
|
{(enableRowVirtualization ? virtualRows : rows).map(
|
|
95
95
|
(rowOrVirtualRow: any, rowIndex: number) => {
|
|
96
96
|
const row = enableRowVirtualization
|
package/src/column.utils.ts
CHANGED
|
@@ -52,6 +52,8 @@ export const prepareColumns = <TData extends Record<string, any> = {}>(
|
|
|
52
52
|
if (Object.keys(MRT_FilterFns).includes(currentFilterFns[columnDef.id])) {
|
|
53
53
|
columnDef.filterFn =
|
|
54
54
|
MRT_FilterFns[currentFilterFns[columnDef.id]] ?? MRT_FilterFns.fuzzy;
|
|
55
|
+
//@ts-ignore
|
|
56
|
+
columnDef._filterFn = currentFilterFns[columnDef.id];
|
|
55
57
|
}
|
|
56
58
|
if (Object.keys(MRT_SortingFns).includes(columnDef.sortingFn as string)) {
|
|
57
59
|
// @ts-ignore
|
|
@@ -123,3 +125,14 @@ export const getDefaultColumnOrderIds = <
|
|
|
123
125
|
),
|
|
124
126
|
...getTrailingDisplayColumnIds(props),
|
|
125
127
|
].filter(Boolean) as string[];
|
|
128
|
+
|
|
129
|
+
export const getDefaultColumnFilterFn = <
|
|
130
|
+
TData extends Record<string, any> = {},
|
|
131
|
+
>(
|
|
132
|
+
columnDef: MRT_ColumnDef<TData>,
|
|
133
|
+
): MRT_FilterOption => {
|
|
134
|
+
if (columnDef.filterVariant === 'multi-select') return 'arrIncludesSome';
|
|
135
|
+
if (columnDef.filterVariant === 'select') return 'equals';
|
|
136
|
+
if (columnDef.filterVariant === 'range') return 'betweenInclusive';
|
|
137
|
+
return 'fuzzy';
|
|
138
|
+
};
|
|
@@ -19,7 +19,9 @@ export const MRT_TableHeadCellFilterContainer: FC<Props> = ({
|
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
21
|
<Collapse in={showColumnFilters} mountOnEnter unmountOnExit>
|
|
22
|
-
{
|
|
22
|
+
{['between', 'betweenInclusive', 'inNumberRange'].includes(
|
|
23
|
+
currentFilterFns[column.id],
|
|
24
|
+
) ? (
|
|
23
25
|
<MRT_FilterRangeFields header={header} table={table} />
|
|
24
26
|
) : (
|
|
25
27
|
<MRT_FilterTextField header={header} table={table} />
|
|
@@ -19,6 +19,11 @@ export const MRT_TableHeadCellFilterLabel: FC<Props> = ({ header, table }) => {
|
|
|
19
19
|
const { column } = header;
|
|
20
20
|
const { columnDef } = column;
|
|
21
21
|
|
|
22
|
+
const isRangeFilter = [
|
|
23
|
+
'between',
|
|
24
|
+
'betweenInclusive',
|
|
25
|
+
'inNumberRange',
|
|
26
|
+
].includes(columnDef._filterFn);
|
|
22
27
|
const currentFilterOption = currentFilterFns?.[header.id];
|
|
23
28
|
const filterTooltip = localization.filteringByColumn
|
|
24
29
|
.replace('{column}', String(columnDef.header))
|
|
@@ -37,7 +42,7 @@ export const MRT_TableHeadCellFilterLabel: FC<Props> = ({ header, table }) => {
|
|
|
37
42
|
`"${
|
|
38
43
|
Array.isArray(column.getFilterValue())
|
|
39
44
|
? (column.getFilterValue() as [string, string]).join(
|
|
40
|
-
`" ${localization.and} "`,
|
|
45
|
+
`" ${isRangeFilter ? localization.and : localization.or} "`,
|
|
41
46
|
)
|
|
42
47
|
: (column.getFilterValue() as string)
|
|
43
48
|
}"`,
|
|
@@ -48,8 +53,8 @@ export const MRT_TableHeadCellFilterLabel: FC<Props> = ({ header, table }) => {
|
|
|
48
53
|
<Grow
|
|
49
54
|
unmountOnExit
|
|
50
55
|
in={
|
|
51
|
-
(!!column.getFilterValue() &&
|
|
52
|
-
(
|
|
56
|
+
(!!column.getFilterValue() && isRangeFilter) ||
|
|
57
|
+
(!isRangeFilter && // @ts-ignore
|
|
53
58
|
(!!column.getFilterValue()?.[0] || !!column.getFilterValue()?.[1]))
|
|
54
59
|
}
|
|
55
60
|
>
|
|
@@ -11,8 +11,8 @@ interface Props {
|
|
|
11
11
|
export const MRT_FilterRangeFields: FC<Props> = ({ header, table }) => {
|
|
12
12
|
return (
|
|
13
13
|
<Box sx={{ display: 'grid', gridTemplateColumns: '6fr 6fr', gap: '1rem' }}>
|
|
14
|
-
<MRT_FilterTextField header={header}
|
|
15
|
-
<MRT_FilterTextField header={header}
|
|
14
|
+
<MRT_FilterTextField header={header} rangeFilterIndex={0} table={table} />
|
|
15
|
+
<MRT_FilterTextField header={header} rangeFilterIndex={1} table={table} />
|
|
16
16
|
</Box>
|
|
17
17
|
);
|
|
18
18
|
};
|
|
@@ -6,10 +6,13 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
+
Box,
|
|
10
|
+
Checkbox,
|
|
9
11
|
Chip,
|
|
10
12
|
debounce,
|
|
11
13
|
IconButton,
|
|
12
14
|
InputAdornment,
|
|
15
|
+
ListItemText,
|
|
13
16
|
MenuItem,
|
|
14
17
|
TextField,
|
|
15
18
|
TextFieldProps,
|
|
@@ -20,13 +23,13 @@ import type { MRT_Header, MRT_TableInstance } from '..';
|
|
|
20
23
|
|
|
21
24
|
interface Props {
|
|
22
25
|
header: MRT_Header;
|
|
23
|
-
|
|
26
|
+
rangeFilterIndex?: number;
|
|
24
27
|
table: MRT_TableInstance;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export const MRT_FilterTextField: FC<Props> = ({
|
|
28
31
|
header,
|
|
29
|
-
|
|
32
|
+
rangeFilterIndex,
|
|
30
33
|
table,
|
|
31
34
|
}) => {
|
|
32
35
|
const {
|
|
@@ -45,11 +48,13 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
45
48
|
const { columnDef } = column;
|
|
46
49
|
const { currentFilterFns } = getState();
|
|
47
50
|
|
|
48
|
-
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
49
|
-
|
|
50
51
|
const mTableHeadCellFilterTextFieldProps =
|
|
51
52
|
muiTableHeadCellFilterTextFieldProps instanceof Function
|
|
52
|
-
? muiTableHeadCellFilterTextFieldProps({
|
|
53
|
+
? muiTableHeadCellFilterTextFieldProps({
|
|
54
|
+
column,
|
|
55
|
+
table,
|
|
56
|
+
rangeFilterIndex,
|
|
57
|
+
})
|
|
53
58
|
: muiTableHeadCellFilterTextFieldProps;
|
|
54
59
|
|
|
55
60
|
const mcTableHeadCellFilterTextFieldProps =
|
|
@@ -57,6 +62,7 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
57
62
|
? columnDef.muiTableHeadCellFilterTextFieldProps({
|
|
58
63
|
column,
|
|
59
64
|
table,
|
|
65
|
+
rangeFilterIndex,
|
|
60
66
|
})
|
|
61
67
|
: columnDef.muiTableHeadCellFilterTextFieldProps;
|
|
62
68
|
|
|
@@ -65,28 +71,73 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
65
71
|
...mcTableHeadCellFilterTextFieldProps,
|
|
66
72
|
} as TextFieldProps;
|
|
67
73
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
const isRangeFilter =
|
|
75
|
+
columnDef.filterVariant === 'range' || rangeFilterIndex !== undefined;
|
|
76
|
+
const isSelectFilter = columnDef.filterVariant === 'select';
|
|
77
|
+
const isMultiSelectFilter = columnDef.filterVariant === 'multi-select';
|
|
78
|
+
const isTextboxFilter =
|
|
79
|
+
columnDef.filterVariant === 'text' ||
|
|
80
|
+
(!isSelectFilter && !isMultiSelectFilter);
|
|
81
|
+
|
|
82
|
+
const currentFilterOption = currentFilterFns?.[header.id];
|
|
83
|
+
const filterId = `mrt-${tableId}-${header.id}-filter-text-field${
|
|
84
|
+
rangeFilterIndex ?? ''
|
|
85
|
+
}`;
|
|
86
|
+
const filterChipLabel = ['empty', 'notEmpty'].includes(currentFilterOption)
|
|
87
|
+
? //@ts-ignore
|
|
88
|
+
localization[
|
|
89
|
+
`filter${
|
|
90
|
+
currentFilterOption?.charAt?.(0)?.toUpperCase() +
|
|
91
|
+
currentFilterOption?.slice(1)
|
|
92
|
+
}`
|
|
93
|
+
]
|
|
94
|
+
: '';
|
|
95
|
+
const filterPlaceholder = !isRangeFilter
|
|
96
|
+
? localization.filterByColumn?.replace('{column}', String(columnDef.header))
|
|
97
|
+
: rangeFilterIndex === 0
|
|
98
|
+
? localization.min
|
|
99
|
+
: rangeFilterIndex === 1
|
|
100
|
+
? localization.max
|
|
101
|
+
: '';
|
|
102
|
+
const allowedColumnFilterOptions =
|
|
103
|
+
columnDef?.columnFilterModeOptions ?? columnFilterModeOptions;
|
|
104
|
+
const showChangeModeButton =
|
|
105
|
+
enableColumnFilterChangeMode &&
|
|
106
|
+
columnDef.enableColumnFilterChangeMode !== false &&
|
|
107
|
+
!rangeFilterIndex &&
|
|
108
|
+
(allowedColumnFilterOptions === undefined ||
|
|
109
|
+
!!allowedColumnFilterOptions?.length);
|
|
110
|
+
|
|
111
|
+
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
112
|
+
const [filterValue, setFilterValue] = useState<string | string[]>(() =>
|
|
113
|
+
isMultiSelectFilter
|
|
114
|
+
? (column.getFilterValue() as string[]) || []
|
|
115
|
+
: isRangeFilter
|
|
116
|
+
? (column.getFilterValue() as [string, string])?.[
|
|
117
|
+
rangeFilterIndex as number
|
|
118
|
+
] || []
|
|
71
119
|
: (column.getFilterValue() as string) ?? '',
|
|
72
120
|
);
|
|
73
121
|
|
|
74
122
|
const handleChangeDebounced = useCallback(
|
|
75
|
-
debounce(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
123
|
+
debounce(
|
|
124
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
125
|
+
let value =
|
|
126
|
+
textFieldProps.type === 'date'
|
|
127
|
+
? new Date(event.target.value)
|
|
128
|
+
: event.target.value;
|
|
129
|
+
if (isRangeFilter) {
|
|
130
|
+
column.setFilterValue((old: [string, string | Date]) => {
|
|
131
|
+
const newFilterValues = old ?? ['', ''];
|
|
132
|
+
newFilterValues[rangeFilterIndex as number] = value;
|
|
133
|
+
return newFilterValues;
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
column.setFilterValue(value ?? undefined);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
isTextboxFilter ? 200 : 1,
|
|
140
|
+
),
|
|
90
141
|
[],
|
|
91
142
|
);
|
|
92
143
|
|
|
@@ -95,24 +146,24 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
95
146
|
handleChangeDebounced(event);
|
|
96
147
|
};
|
|
97
148
|
|
|
98
|
-
const handleFilterMenuOpen = (event: MouseEvent<HTMLElement>) => {
|
|
99
|
-
setAnchorEl(event.currentTarget);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
149
|
const handleClear = () => {
|
|
103
|
-
|
|
104
|
-
|
|
150
|
+
if (isMultiSelectFilter) {
|
|
151
|
+
setFilterValue([]);
|
|
152
|
+
column.setFilterValue([]);
|
|
153
|
+
} else if (isRangeFilter) {
|
|
154
|
+
setFilterValue('');
|
|
105
155
|
column.setFilterValue((old: [string | undefined, string | undefined]) => {
|
|
106
156
|
const newFilterValues = old ?? ['', ''];
|
|
107
|
-
newFilterValues[
|
|
157
|
+
newFilterValues[rangeFilterIndex as number] = undefined;
|
|
108
158
|
return newFilterValues;
|
|
109
159
|
});
|
|
110
160
|
} else {
|
|
161
|
+
setFilterValue('');
|
|
111
162
|
column.setFilterValue(undefined);
|
|
112
163
|
}
|
|
113
164
|
};
|
|
114
165
|
|
|
115
|
-
const
|
|
166
|
+
const handleClearEmptyFilterChip = () => {
|
|
116
167
|
setFilterValue('');
|
|
117
168
|
column.setFilterValue(undefined);
|
|
118
169
|
setCurrentFilterFns((prev) => ({
|
|
@@ -121,47 +172,14 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
121
172
|
}));
|
|
122
173
|
};
|
|
123
174
|
|
|
175
|
+
const handleFilterMenuOpen = (event: MouseEvent<HTMLElement>) => {
|
|
176
|
+
setAnchorEl(event.currentTarget);
|
|
177
|
+
};
|
|
178
|
+
|
|
124
179
|
if (columnDef.Filter) {
|
|
125
180
|
return <>{columnDef.Filter?.({ header, table })}</>;
|
|
126
181
|
}
|
|
127
182
|
|
|
128
|
-
const filterId = `mrt-${tableId}-${header.id}-filter-text-field${
|
|
129
|
-
inputIndex ?? ''
|
|
130
|
-
}`;
|
|
131
|
-
const currentFilterOption = currentFilterFns?.[header.id];
|
|
132
|
-
const isSelectFilter = !!columnDef.filterSelectOptions;
|
|
133
|
-
const filterChipLabel = ['empty', 'notEmpty'].includes(currentFilterOption)
|
|
134
|
-
? //@ts-ignore
|
|
135
|
-
localization[
|
|
136
|
-
`filter${
|
|
137
|
-
currentFilterOption?.charAt(0)?.toUpperCase() +
|
|
138
|
-
currentFilterOption?.slice(1)
|
|
139
|
-
}`
|
|
140
|
-
]
|
|
141
|
-
: '';
|
|
142
|
-
const filterPlaceholder =
|
|
143
|
-
inputIndex === undefined
|
|
144
|
-
? localization.filterByColumn?.replace(
|
|
145
|
-
'{column}',
|
|
146
|
-
String(columnDef.header),
|
|
147
|
-
)
|
|
148
|
-
: inputIndex === 0
|
|
149
|
-
? localization.min
|
|
150
|
-
: inputIndex === 1
|
|
151
|
-
? localization.max
|
|
152
|
-
: '';
|
|
153
|
-
|
|
154
|
-
const allowedColumnFilterOptions =
|
|
155
|
-
columnDef?.columnFilterModeOptions ?? columnFilterModeOptions;
|
|
156
|
-
|
|
157
|
-
const showChangeModeButton =
|
|
158
|
-
enableColumnFilterChangeMode &&
|
|
159
|
-
columnDef.enableColumnFilterChangeMode !== false &&
|
|
160
|
-
!isSelectFilter &&
|
|
161
|
-
!inputIndex &&
|
|
162
|
-
(allowedColumnFilterOptions === undefined ||
|
|
163
|
-
!!allowedColumnFilterOptions?.length);
|
|
164
|
-
|
|
165
183
|
return (
|
|
166
184
|
<>
|
|
167
185
|
<TextField
|
|
@@ -200,12 +218,14 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
200
218
|
}}
|
|
201
219
|
margin="none"
|
|
202
220
|
placeholder={
|
|
203
|
-
filterChipLabel || isSelectFilter
|
|
221
|
+
filterChipLabel || isSelectFilter || isMultiSelectFilter
|
|
222
|
+
? undefined
|
|
223
|
+
: filterPlaceholder
|
|
204
224
|
}
|
|
205
225
|
onChange={handleChange}
|
|
206
226
|
onClick={(e: MouseEvent<HTMLInputElement>) => e.stopPropagation()}
|
|
207
|
-
select={isSelectFilter}
|
|
208
|
-
value={filterValue
|
|
227
|
+
select={isSelectFilter || isMultiSelectFilter}
|
|
228
|
+
value={filterValue}
|
|
209
229
|
variant="standard"
|
|
210
230
|
InputProps={{
|
|
211
231
|
startAdornment: showChangeModeButton ? (
|
|
@@ -224,7 +244,7 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
224
244
|
</Tooltip>
|
|
225
245
|
{filterChipLabel && (
|
|
226
246
|
<Chip
|
|
227
|
-
onDelete={
|
|
247
|
+
onDelete={handleClearEmptyFilterChip}
|
|
228
248
|
label={filterChipLabel}
|
|
229
249
|
/>
|
|
230
250
|
)}
|
|
@@ -236,7 +256,6 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
236
256
|
<InputAdornment position="end">
|
|
237
257
|
<Tooltip
|
|
238
258
|
arrow
|
|
239
|
-
disableHoverListener={isSelectFilter}
|
|
240
259
|
placement="right"
|
|
241
260
|
title={localization.clearFilter ?? ''}
|
|
242
261
|
>
|
|
@@ -258,10 +277,26 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
258
277
|
</InputAdornment>
|
|
259
278
|
),
|
|
260
279
|
}}
|
|
280
|
+
SelectProps={{
|
|
281
|
+
displayEmpty: true,
|
|
282
|
+
multiple: isMultiSelectFilter,
|
|
283
|
+
renderValue: isMultiSelectFilter
|
|
284
|
+
? (selected: any) =>
|
|
285
|
+
!selected?.length ? (
|
|
286
|
+
<Box sx={{ opacity: 0.5 }}>{filterPlaceholder}</Box>
|
|
287
|
+
) : (
|
|
288
|
+
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: '2px' }}>
|
|
289
|
+
{(selected as string[])?.map((value) => (
|
|
290
|
+
<Chip key={value} label={value} />
|
|
291
|
+
))}
|
|
292
|
+
</Box>
|
|
293
|
+
)
|
|
294
|
+
: undefined,
|
|
295
|
+
}}
|
|
261
296
|
{...textFieldProps}
|
|
262
297
|
sx={(theme) => ({
|
|
263
298
|
p: 0,
|
|
264
|
-
minWidth: !filterChipLabel ? '
|
|
299
|
+
minWidth: !filterChipLabel ? '6rem' : 'auto',
|
|
265
300
|
width: 'calc(100% + 0.5rem)',
|
|
266
301
|
'& .MuiSelect-icon': {
|
|
267
302
|
mr: '1.5rem',
|
|
@@ -271,24 +306,32 @@ export const MRT_FilterTextField: FC<Props> = ({
|
|
|
271
306
|
: (textFieldProps?.sx as any)),
|
|
272
307
|
})}
|
|
273
308
|
>
|
|
274
|
-
{isSelectFilter && (
|
|
275
|
-
<MenuItem divider disabled
|
|
276
|
-
{
|
|
309
|
+
{(isSelectFilter || isMultiSelectFilter) && (
|
|
310
|
+
<MenuItem divider disabled hidden value="">
|
|
311
|
+
<Box sx={{ opacity: 0.5 }}>{filterPlaceholder}</Box>
|
|
277
312
|
</MenuItem>
|
|
278
313
|
)}
|
|
279
314
|
{columnDef?.filterSelectOptions?.map((option) => {
|
|
280
|
-
let value;
|
|
281
|
-
let text;
|
|
282
|
-
if (typeof option
|
|
315
|
+
let value: string;
|
|
316
|
+
let text: string;
|
|
317
|
+
if (typeof option !== 'object') {
|
|
283
318
|
value = option;
|
|
284
319
|
text = option;
|
|
285
|
-
} else
|
|
320
|
+
} else {
|
|
286
321
|
value = option.value;
|
|
287
322
|
text = option.text;
|
|
288
323
|
}
|
|
289
324
|
return (
|
|
290
325
|
<MenuItem key={value} value={value}>
|
|
291
|
-
{
|
|
326
|
+
{isMultiSelectFilter && (
|
|
327
|
+
<Checkbox
|
|
328
|
+
checked={(
|
|
329
|
+
(column.getFilterValue() ?? []) as string[]
|
|
330
|
+
).includes(value)}
|
|
331
|
+
sx={{ mr: '0.5rem' }}
|
|
332
|
+
/>
|
|
333
|
+
)}
|
|
334
|
+
<ListItemText>{text}</ListItemText>
|
|
292
335
|
</MenuItem>
|
|
293
336
|
);
|
|
294
337
|
})}
|
package/src/localization.ts
CHANGED
|
@@ -13,6 +13,9 @@ export interface MRT_Localization {
|
|
|
13
13
|
edit: string;
|
|
14
14
|
expand: string;
|
|
15
15
|
expandAll: string;
|
|
16
|
+
filterArrIncludes: string;
|
|
17
|
+
filterArrIncludesAll: string;
|
|
18
|
+
filterArrIncludesSome: string;
|
|
16
19
|
filterBetween: string;
|
|
17
20
|
filterBetweenInclusive: string;
|
|
18
21
|
filterByColumn: string;
|
|
@@ -20,15 +23,20 @@ export interface MRT_Localization {
|
|
|
20
23
|
filterEmpty: string;
|
|
21
24
|
filterEndsWith: string;
|
|
22
25
|
filterEquals: string;
|
|
26
|
+
filterEqualsString: string;
|
|
23
27
|
filterFuzzy: string;
|
|
24
28
|
filterGreaterThan: string;
|
|
25
29
|
filterGreaterThanOrEqualTo: string;
|
|
30
|
+
filterInNumberRange: string;
|
|
31
|
+
filterIncludesString: string;
|
|
32
|
+
filterIncludesStringSensitive: string;
|
|
26
33
|
filterLessThan: string;
|
|
27
34
|
filterLessThanOrEqualTo: string;
|
|
28
35
|
filterMode: string;
|
|
29
36
|
filterNotEmpty: string;
|
|
30
37
|
filterNotEquals: string;
|
|
31
38
|
filterStartsWith: string;
|
|
39
|
+
filterWeakEquals: string;
|
|
32
40
|
filteringByColumn: string;
|
|
33
41
|
grab: string;
|
|
34
42
|
groupByColumn: string;
|
|
@@ -38,6 +46,7 @@ export interface MRT_Localization {
|
|
|
38
46
|
max: string;
|
|
39
47
|
min: string;
|
|
40
48
|
move: string;
|
|
49
|
+
or: string;
|
|
41
50
|
pinToLeft: string;
|
|
42
51
|
pinToRight: string;
|
|
43
52
|
resetColumnSize: string;
|
|
@@ -85,6 +94,9 @@ export const MRT_DefaultLocalization_EN: MRT_Localization = {
|
|
|
85
94
|
edit: 'Edit',
|
|
86
95
|
expand: 'Expand',
|
|
87
96
|
expandAll: 'Expand all',
|
|
97
|
+
filterArrIncludes: 'Includes',
|
|
98
|
+
filterArrIncludesAll: 'Includes all',
|
|
99
|
+
filterArrIncludesSome: 'Includes',
|
|
88
100
|
filterBetween: 'Between',
|
|
89
101
|
filterBetweenInclusive: 'Between Inclusive',
|
|
90
102
|
filterByColumn: 'Filter by {column}',
|
|
@@ -92,15 +104,20 @@ export const MRT_DefaultLocalization_EN: MRT_Localization = {
|
|
|
92
104
|
filterEmpty: 'Empty',
|
|
93
105
|
filterEndsWith: 'Ends With',
|
|
94
106
|
filterEquals: 'Equals',
|
|
107
|
+
filterEqualsString: 'Equals',
|
|
95
108
|
filterFuzzy: 'Fuzzy',
|
|
96
109
|
filterGreaterThan: 'Greater Than',
|
|
97
110
|
filterGreaterThanOrEqualTo: 'Greater Than Or Equal To',
|
|
111
|
+
filterInNumberRange: 'Between',
|
|
112
|
+
filterIncludesString: 'Contains',
|
|
113
|
+
filterIncludesStringSensitive: 'Contains',
|
|
98
114
|
filterLessThan: 'Less Than',
|
|
99
115
|
filterLessThanOrEqualTo: 'Less Than Or Equal To',
|
|
100
116
|
filterMode: 'Filter Mode: {filterType}',
|
|
101
117
|
filterNotEmpty: 'Not Empty',
|
|
102
118
|
filterNotEquals: 'Not Equals',
|
|
103
119
|
filterStartsWith: 'Starts With',
|
|
120
|
+
filterWeakEquals: 'Equals',
|
|
104
121
|
filteringByColumn: 'Filtering by {column} - {filterType} {filterValue}',
|
|
105
122
|
grab: 'Grab',
|
|
106
123
|
groupByColumn: 'Group by {column}',
|
|
@@ -110,6 +127,7 @@ export const MRT_DefaultLocalization_EN: MRT_Localization = {
|
|
|
110
127
|
max: 'Max',
|
|
111
128
|
min: 'Min',
|
|
112
129
|
move: 'Move',
|
|
130
|
+
or: 'or',
|
|
113
131
|
pinToLeft: 'Pin to left',
|
|
114
132
|
pinToRight: 'Pin to right',
|
|
115
133
|
resetColumnSize: 'Reset column size',
|