mui-datatables-updated 1.0.2 → 1.0.3

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.
@@ -1 +0,0 @@
1
- export declare const Table: () => import("react/jsx-runtime").JSX.Element;
@@ -1,11 +0,0 @@
1
- import { HeadCell } from "./TableHead";
2
- export interface Data {
3
- id: number;
4
- calories: number;
5
- carbs: number;
6
- fat: number;
7
- name: string;
8
- protein: number;
9
- }
10
- export declare const rows: Data[];
11
- export declare const headCells: HeadCell<typeof rows[0]>[];
package/rollup.config.mjs DELETED
@@ -1,23 +0,0 @@
1
- import typescript from 'rollup-plugin-typescript2';
2
- import peerDepsExternal from 'rollup-plugin-peer-deps-external';
3
-
4
- export default {
5
- input: 'src/index.ts',
6
- output: [
7
- {
8
- file: 'dist/index.js',
9
- format: 'cjs',
10
- sourcemap: true,
11
- },
12
- {
13
- file: 'dist/index.esm.js',
14
- format: 'esm',
15
- sourcemap: true,
16
- },
17
- ],
18
- plugins: [
19
- peerDepsExternal({ includeDependencies: true }),
20
- typescript(),
21
- ],
22
- external: ['react', 'react-dom', '@mui/material'],
23
- };
@@ -1,344 +0,0 @@
1
- import Checkbox from '@mui/material/Checkbox';
2
- import Paper from '@mui/material/Paper';
3
- import Table from '@mui/material/Table';
4
- import TableBody from '@mui/material/TableBody';
5
- import TableCell from '@mui/material/TableCell';
6
- import TableContainer from '@mui/material/TableContainer';
7
- import TablePagination from '@mui/material/TablePagination';
8
- import TableRow from '@mui/material/TableRow';
9
- import React, { useCallback, useRef } from 'react';
10
- import { useReactToPrint } from "react-to-print";
11
- import { EnhancedTableHead } from './TableHead';
12
- import { CustomSelectedToolbarProps, EnhancedTableToolbar } from './Toolbar';
13
- import { getComparator, Order } from './utils';
14
- import { LabelDisplayedRowsArgs } from '@mui/material/TablePagination';
15
-
16
- export interface Column {
17
- name: string;
18
- label?: string;
19
- options?: {
20
- customBodyRender?: (value: any) => React.ReactNode;
21
- filter?: boolean;
22
- sort?: boolean;
23
- }
24
- }
25
-
26
- export interface Options {
27
- translations?: {
28
- filterTooltip?: string;
29
- searchTooltip?: string;
30
- downloadTooltip?: string;
31
- printTooltip?: string;
32
- filtersTitle?: string;
33
- resetButtonText?: string;
34
- rowsPerPageText?: string;
35
- searchPlaceholder?: string;
36
- selectedTextRenderer?: (selected: number) => string;
37
- labelDisplayedRows?: ({ from, to, count }: LabelDisplayedRowsArgs) => string;
38
- }
39
- }
40
-
41
- export interface EnhancedTableProps<T extends object> extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
42
- title: string;
43
- data: T[];
44
- deactivateSelect?: boolean;
45
- defaultOrderBy?: string;
46
- defaultOrder?: Order;
47
- excludedColumns?: (keyof T)[];
48
- columns?: Column[];
49
- options?: Options;
50
- CustomToolbar?: React.FC;
51
- CustomSelectedToolbar?: React.FC<CustomSelectedToolbarProps<T>>;
52
- }
53
-
54
- interface EnhancedTableState<T> {
55
- order: Order;
56
- orderBy: keyof T;
57
- selected: readonly T[];
58
- page: number;
59
- rowsPerPage: number;
60
- searchQuery: string;
61
- filterFunc: (row: T) => boolean;
62
- currentData: T[];
63
- visibleRows: T[];
64
- emptyRows: number;
65
- }
66
-
67
- export const MUITable = <T extends object>({
68
- title,
69
- data,
70
- deactivateSelect,
71
- defaultOrderBy,
72
- defaultOrder,
73
- excludedColumns,
74
- columns: passedColumns,
75
- CustomToolbar,
76
- CustomSelectedToolbar,
77
- options,
78
- ...rest
79
- }: EnhancedTableProps<T>) => {
80
- const tableRef = useRef<HTMLDivElement>(null);
81
- const reactToPrintFn = useReactToPrint({ contentRef: tableRef });
82
-
83
- const getDefaultOrderByKey = React.useCallback((): keyof T => {
84
- if (data.length === 0) return "id" as keyof T;
85
-
86
- const keys = data.length > 0 ? (Object.keys(data[0]) as (keyof T)[]) : [];
87
-
88
- if (defaultOrderBy) {
89
- if (keys.includes(defaultOrderBy as keyof T)) {
90
- return defaultOrderBy as keyof T;
91
- } else {
92
- console.warn(`{defaultOrderBy}: "${defaultOrderBy}" not found among the object keys. Falling back to automatic key detection.`);
93
- }
94
- }
95
-
96
- return (keys.includes("id" as keyof T) ? "id" : keys[0]) as keyof T;
97
- }, [data, defaultOrderBy]);
98
-
99
- const [state, setState] = React.useState<EnhancedTableState<T>>(() => {
100
- const orderByKey = getDefaultOrderByKey();
101
- return {
102
- order: defaultOrder || 'asc',
103
- orderBy: orderByKey,
104
- selected: [] as readonly T[],
105
- page: 0,
106
- rowsPerPage: 5,
107
- searchQuery: "",
108
- filterFunc: () => true,
109
- currentData: data,
110
- visibleRows: data,
111
- emptyRows: 0,
112
- };
113
- });
114
-
115
- const generateColumns = React.useCallback((): Column[] => {
116
- if (data.length === 0) return [];
117
- return Object.keys(data[0] as object)
118
- .filter((key) => !(excludedColumns || []).includes(key as keyof T))
119
- .map((key) => ({
120
- name: key,
121
- label: key.charAt(0).toUpperCase() + key.slice(1),
122
- }));
123
- }, [data, excludedColumns]);
124
-
125
- const columns = passedColumns || generateColumns();
126
-
127
- const handleSearch = (query: string) => {
128
- setState((prevState) => ({ ...prevState, searchQuery: query.toLowerCase() }));
129
- };
130
-
131
- React.useEffect(() => {
132
- const orderByKey = getDefaultOrderByKey();
133
- setState((prevState) => ({ ...prevState, orderBy: orderByKey }));
134
- }, [data, getDefaultOrderByKey]);
135
-
136
- // Data sorting, filtering, and pagination
137
- React.useEffect(() => {
138
- // Apply filters, search query, and sort data
139
- const sortedData = [...data]
140
- .filter(state.filterFunc)
141
- .filter((row) =>
142
- Object.values(row as Record<string, unknown>).some((value) =>
143
- typeof value === "string" &&
144
- value.toLowerCase().includes(state.searchQuery)
145
- )
146
- )
147
- .sort(getComparator<T, keyof T>(state.order, state.orderBy));
148
-
149
- // Paginate the processed data
150
- const startIndex = state.page * state.rowsPerPage;
151
- const paginatedData = sortedData.slice(
152
- startIndex,
153
- startIndex + state.rowsPerPage
154
- );
155
-
156
- const calculatedEmptyRows = Math.max(
157
- 0,
158
- (1 + state.page) * state.rowsPerPage - sortedData.length
159
- );
160
-
161
- setState((prevState) => ({
162
- ...prevState,
163
- visibleRows: paginatedData,
164
- emptyRows: calculatedEmptyRows,
165
- selected: prevState.selected.filter((selectedRow) =>
166
- data.includes(selectedRow)
167
- ),
168
- }));
169
- }, [
170
- state.filterFunc,
171
- state.order,
172
- state.orderBy,
173
- state.page,
174
- state.rowsPerPage,
175
- state.searchQuery,
176
- data,
177
- ]);
178
-
179
-
180
- // Remove selected rows deleted from the data to prevent stale selected state
181
- React.useEffect(() => {
182
- setState((prevState) => ({
183
- ...prevState,
184
- selected: prevState.selected.filter((selectedRow) =>
185
- data.some((row) => row === selectedRow)
186
- ),
187
- }));
188
- }, [data]);
189
-
190
-
191
- const handleRequestSort = (_event: React.MouseEvent<unknown>, property: keyof T) => {
192
- const isAsc = state.orderBy === property && state.order === 'asc';
193
- setState((prevState) => ({
194
- ...prevState,
195
- order: isAsc ? 'desc' : 'asc',
196
- orderBy: property,
197
- }));
198
- };
199
-
200
- const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {
201
- if (event.target.checked) {
202
- setState((prevState) => ({ ...prevState, selected: [...state.currentData] }));
203
- } else {
204
- setState((prevState) => ({ ...prevState, selected: [] }));
205
- }
206
- };
207
-
208
- const handleClick = (_event: React.MouseEvent<unknown>, row: T) => {
209
- const selectedIndex = state.selected.findIndex((selectedRow) => selectedRow === row);
210
- let newSelected: readonly T[] = [];
211
-
212
- if (selectedIndex === -1) {
213
- newSelected = [...state.selected, row];
214
- } else if (selectedIndex === 0) {
215
- newSelected = state.selected.slice(1);
216
- } else if (selectedIndex === state.selected.length - 1) {
217
- newSelected = state.selected.slice(0, -1);
218
- } else if (selectedIndex > 0) {
219
- newSelected = [
220
- ...state.selected.slice(0, selectedIndex),
221
- ...state.selected.slice(selectedIndex + 1),
222
- ];
223
- }
224
- setState((prevState) => ({ ...prevState, selected: newSelected }));
225
- };
226
-
227
- const handleChangePage = (_event: unknown, newPage: number) => {
228
- setState((prevState) => ({ ...prevState, page: newPage }));
229
- };
230
-
231
- const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
232
- setState((prevState) => ({
233
- ...prevState,
234
- rowsPerPage: parseInt(event.target.value, 10),
235
- page: 0,
236
- }));
237
- };
238
-
239
- const handleFilterChange = useCallback((filterFunc: (row: T) => boolean) => {
240
- setState((prevState) => ({ ...prevState, filterFunc }));
241
- }, []);
242
-
243
- return (
244
- <div {...rest} ref={tableRef}>
245
- <Paper sx={{ width: '100%', mb: 2 }}>
246
- <EnhancedTableToolbar
247
- title={title}
248
- numSelected={state.selected.length}
249
- selected={state.selected}
250
- onFilterChange={handleFilterChange}
251
- onSearch={handleSearch}
252
- printFn={reactToPrintFn}
253
- columns={columns}
254
- CustomToolbar={CustomToolbar}
255
- CustomSelectedToolbar={CustomSelectedToolbar}
256
- data={data}
257
- options={options}
258
- />
259
- <TableContainer>
260
- <Table
261
- sx={{ minWidth: 750 }}
262
- aria-labelledby="tableTitle"
263
- size="small"
264
- >
265
- <EnhancedTableHead
266
- columns={columns}
267
- numSelected={state.selected.length}
268
- order={state.order}
269
- orderBy={state.orderBy}
270
- onSelectAllClick={deactivateSelect ? undefined : handleSelectAllClick}
271
- onRequestSort={handleRequestSort}
272
- rowCount={state.currentData.length}
273
- deactivateSelectAll={deactivateSelect}
274
- />
275
- <TableBody>
276
- {state.visibleRows.map((row, index) => {
277
- const isItemSelected = state.selected.some((selectedRow) => selectedRow === row);
278
- const labelId = `enhanced-table-checkbox-${index}`;
279
-
280
- return (
281
- <TableRow
282
- hover
283
- onClick={deactivateSelect ? undefined : (event) => handleClick(event, row)}
284
- role="checkbox"
285
- aria-checked={isItemSelected}
286
- tabIndex={-1}
287
- key={index}
288
- selected={isItemSelected}
289
- sx={{ cursor: 'pointer' }}
290
- >
291
- {!deactivateSelect && (
292
- <TableCell padding="checkbox">
293
- <Checkbox
294
- color="primary"
295
- checked={isItemSelected}
296
- inputProps={{
297
- 'aria-labelledby': labelId,
298
- }}
299
- />
300
- </TableCell>
301
- )}
302
- {columns.map((column, cellIndex) => (
303
- <TableCell
304
- key={String(column.name)}
305
- component={cellIndex === 0 ? "th" : undefined}
306
- id={cellIndex === 0 ? labelId : undefined}
307
- scope={cellIndex === 0 ? "row" : undefined}
308
- padding="normal"
309
- >
310
- {column.options?.customBodyRender
311
- ? column.options.customBodyRender((row as Record<string, any>)[column.name])
312
- : String((row as Record<string, any>)[column.name])}
313
- </TableCell>
314
- ))}
315
- </TableRow>
316
- );
317
- })}
318
- {state.emptyRows > 0 && (
319
- <TableRow
320
- style={{
321
- height: 33 * state.emptyRows,
322
- }}
323
- >
324
- <TableCell colSpan={columns.length + 1} />
325
- </TableRow>
326
- )}
327
- </TableBody>
328
- </Table>
329
- </TableContainer>
330
- <TablePagination
331
- rowsPerPageOptions={[5, 10, 25]}
332
- component="div"
333
- count={state.currentData.length}
334
- rowsPerPage={state.rowsPerPage}
335
- page={state.page}
336
- onPageChange={handleChangePage}
337
- onRowsPerPageChange={handleChangeRowsPerPage}
338
- labelRowsPerPage={options?.translations?.rowsPerPageText || "Rows per page"}
339
- labelDisplayedRows={options?.translations?.labelDisplayedRows || (({ from, to, count }) => `${from}-${to} of ${count}`)}
340
- />
341
- </Paper>
342
- </div>
343
- );
344
- };
@@ -1,81 +0,0 @@
1
- import Box from '@mui/material/Box';
2
- import Checkbox from '@mui/material/Checkbox';
3
- import TableCell from '@mui/material/TableCell';
4
- import TableHead from '@mui/material/TableHead';
5
- import TableRow from '@mui/material/TableRow';
6
- import TableSortLabel from '@mui/material/TableSortLabel';
7
- import { visuallyHidden } from '@mui/utils';
8
- import { Column } from './MUITable';
9
- import { Order } from './utils';
10
-
11
- interface EnhancedTableProps<T> {
12
- numSelected: number;
13
- onRequestSort: (event: React.MouseEvent<unknown>, property: keyof T) => void;
14
- onSelectAllClick?: (event: React.ChangeEvent<HTMLInputElement>) => void;
15
- order: Order;
16
- orderBy: keyof T;
17
- rowCount: number;
18
- columns: Column[];
19
- deactivateSelectAll?: boolean;
20
- }
21
-
22
- export function EnhancedTableHead<T>({
23
- onSelectAllClick,
24
- order,
25
- orderBy,
26
- numSelected,
27
- rowCount,
28
- onRequestSort,
29
- columns,
30
- deactivateSelectAll,
31
- }: EnhancedTableProps<T>) {
32
- const createSortHandler =
33
- (property: keyof T) => (event: React.MouseEvent<unknown>) => {
34
- onRequestSort(event, property);
35
- };
36
-
37
- return (
38
- <TableHead>
39
- <TableRow>
40
- {!deactivateSelectAll &&
41
- <TableCell padding="checkbox">
42
- <Checkbox
43
- color="primary"
44
- indeterminate={numSelected > 0 && numSelected < rowCount}
45
- checked={rowCount > 0 && numSelected === rowCount}
46
- onChange={onSelectAllClick}
47
- inputProps={{
48
- 'aria-label': 'select all items',
49
- }}
50
- />
51
- </TableCell>
52
- }
53
- {columns.map((column) => (
54
- <TableCell
55
- key={String(column.name)}
56
- padding='normal'
57
- sortDirection={orderBy === column.name ? order : false}
58
- >
59
- {column.options?.sort !== false ? (
60
- <TableSortLabel
61
- active={orderBy === column.name}
62
- direction={orderBy === column.name ? order : 'asc'}
63
- onClick={createSortHandler(column.name as keyof T)}
64
- sx={{ fontWeight: 'bold' }}
65
- >
66
- {column.label}
67
- {orderBy === column.name ? (
68
- <Box component="span" sx={visuallyHidden}>
69
- {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
70
- </Box>
71
- ) : null}
72
- </TableSortLabel>
73
- ) : (
74
- <span style={{ fontWeight: 700 }}>{column.label}</span>
75
- )}
76
- </TableCell>
77
- ))}
78
- </TableRow>
79
- </TableHead>
80
- );
81
- }