mui-table-2026 1.0.0

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.
@@ -0,0 +1,2107 @@
1
+ import { Paper } from '@mui/material';
2
+ import { Table as MuiTable } from '@mui/material';
3
+ import { Tooltip as MuiTooltip } from '@mui/material';
4
+ import { withStyles } from 'tss-react/mui';
5
+ import clsx from 'clsx';
6
+ import assignwith from 'lodash.assignwith';
7
+ import cloneDeep from 'lodash.clonedeep';
8
+ import find from 'lodash.find';
9
+ import isEqual from 'lodash.isequal';
10
+ import isUndefined from 'lodash.isundefined';
11
+ import merge from 'lodash.merge';
12
+ import PropTypes from 'prop-types';
13
+ import React from 'react';
14
+ import DefaultTableBody from './components/TableBody';
15
+ import DefaultTableFilter from './components/TableFilter';
16
+ import DefaultTableFilterList from './components/TableFilterList';
17
+ import DefaultTableFooter from './components/TableFooter';
18
+ import DefaultTableHead from './components/TableHead';
19
+ import DefaultTableResize from './components/TableResize';
20
+ import DefaultTableToolbar from './components/TableToolbar';
21
+ import DefaultTableToolbarSelect from './components/TableToolbarSelect';
22
+ import getTextLabels from './textLabels';
23
+ import { buildMap, getCollatorComparator, getPageValue, sortCompare, warnDeprecated, warnInfo } from './utils';
24
+ import { DndProvider } from 'react-dnd';
25
+ import { HTML5Backend } from 'react-dnd-html5-backend';
26
+ import { load, save } from './localStorage';
27
+
28
+ const defaultTableStyles = (theme) => ({
29
+ root: {
30
+ '& .datatables-noprint': {
31
+ '@media print': {
32
+ display: 'none',
33
+ },
34
+ },
35
+ // Modern table styling
36
+ borderRadius: '8px',
37
+ overflow: 'hidden',
38
+ boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
39
+
40
+ backgroundColor: '#ffffff',
41
+ // Z-index management
42
+ '& .MuiPopper-root': {
43
+ zIndex: 9999,
44
+ },
45
+ },
46
+ paper: {
47
+ isolation: 'auto',
48
+ // Modern paper styling
49
+ borderRadius: '8px',
50
+ boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
51
+ border: '1px solid #e5e7eb',
52
+ overflow: 'hidden',
53
+ },
54
+ paperResponsiveScrollFullHeightFullWidth: {
55
+ position: 'absolute',
56
+ },
57
+ tableRoot: {
58
+ outline: 'none',
59
+ borderTop: '2px solid #e5e7eb',
60
+ },
61
+ responsiveBase: {
62
+ overflow: 'auto',
63
+ '@media print': {
64
+ height: 'auto !important',
65
+ },
66
+ },
67
+
68
+ // deprecated, but continuing support through v3.x
69
+ responsiveScroll: {
70
+ overflow: 'auto',
71
+ height: '100%',
72
+ },
73
+ // deprecated, but continuing support through v3.x
74
+ responsiveScrollMaxHeight: {
75
+ overflow: 'auto',
76
+ height: '100%',
77
+ },
78
+ // deprecated, but continuing support through v3.x
79
+ responsiveScrollFullHeight: {
80
+ height: '100%',
81
+ },
82
+ // deprecated, but continuing support through v3.x
83
+ responsiveStacked: {
84
+ overflow: 'auto',
85
+ [theme.breakpoints.down('md')]: {
86
+ overflow: 'hidden',
87
+ },
88
+ },
89
+ // deprecated, but continuing support through v3.x
90
+ responsiveStackedFullWidth: {},
91
+ caption: {
92
+ position: 'absolute',
93
+ left: '-3000px',
94
+ },
95
+
96
+ liveAnnounce: {
97
+ border: '0',
98
+ clip: 'rect(0 0 0 0)',
99
+ height: '1px',
100
+ margin: '-1px',
101
+ overflow: 'hidden',
102
+ padding: '0',
103
+ position: 'absolute',
104
+ width: '1px',
105
+ },
106
+ });
107
+
108
+ const TABLE_LOAD = {
109
+ INITIAL: 1,
110
+ UPDATE: 2,
111
+ };
112
+
113
+ // Populate this list with anything that might render in the toolbar to determine if we hide the toolbar
114
+ const TOOLBAR_ITEMS = ['title', 'filter', 'search', 'print', 'download', 'viewColumns', 'customToolbar'];
115
+
116
+ const hasToolbarItem = (options, title) => {
117
+ options.title = title;
118
+
119
+ return !isUndefined(find(TOOLBAR_ITEMS, (i) => options[i]));
120
+ };
121
+
122
+ // Select Toolbar Placement options
123
+ const STP = {
124
+ REPLACE: 'replace',
125
+ ABOVE: 'above',
126
+ NONE: 'none',
127
+ ALWAYS: 'always',
128
+ };
129
+
130
+ class MUIDataTable extends React.Component {
131
+ static propTypes = {
132
+ /** Title of the table */
133
+ title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
134
+ /** Data used to describe table */
135
+ data: PropTypes.array.isRequired,
136
+ /** Columns used to describe table */
137
+ columns: PropTypes.PropTypes.arrayOf(
138
+ PropTypes.oneOfType([
139
+ PropTypes.string,
140
+ PropTypes.shape({
141
+ label: PropTypes.string,
142
+ name: PropTypes.string.isRequired,
143
+ options: PropTypes.shape({
144
+ display: PropTypes.oneOf(['true', 'false', 'excluded', 'always', true, false]),
145
+ empty: PropTypes.bool,
146
+ filter: PropTypes.bool,
147
+ sort: PropTypes.bool,
148
+ print: PropTypes.bool,
149
+ searchable: PropTypes.bool,
150
+ download: PropTypes.bool,
151
+ viewColumns: PropTypes.bool,
152
+ filterList: PropTypes.array,
153
+ filterOptions: PropTypes.oneOfType([
154
+ PropTypes.array,
155
+ PropTypes.shape({
156
+ names: PropTypes.array,
157
+ logic: PropTypes.func,
158
+ display: PropTypes.func,
159
+ }),
160
+ ]),
161
+ filterType: PropTypes.oneOf(['dropdown', 'checkbox', 'multiselect', 'textField', 'custom']),
162
+ customHeadRender: PropTypes.func,
163
+ customBodyRender: PropTypes.func,
164
+ customBodyRenderLite: PropTypes.func,
165
+ customHeadLabelRender: PropTypes.func,
166
+ customFilterListOptions: PropTypes.oneOfType([
167
+ PropTypes.shape({
168
+ render: PropTypes.func,
169
+ update: PropTypes.func,
170
+ }),
171
+ ]),
172
+ customFilterListRender: PropTypes.func,
173
+ setCellProps: PropTypes.func,
174
+ setCellHeaderProps: PropTypes.func,
175
+ sortThirdClickReset: PropTypes.bool,
176
+ sortDescFirst: PropTypes.bool,
177
+ }),
178
+ }),
179
+ ]),
180
+ ).isRequired,
181
+ /** Options used to describe table */
182
+ options: PropTypes.shape({
183
+ caseSensitive: PropTypes.bool,
184
+ columnOrder: PropTypes.array,
185
+ count: PropTypes.number,
186
+ confirmFilters: PropTypes.bool,
187
+ consoleWarnings: PropTypes.bool,
188
+ customFilterDialogFooter: PropTypes.func,
189
+ customFooter: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
190
+ customRowRender: PropTypes.func,
191
+ customSearch: PropTypes.func,
192
+ customSearchRender: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
193
+ customSort: PropTypes.func,
194
+ customToolbar: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
195
+ customToolbarSelect: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
196
+ draggableColumns: PropTypes.object,
197
+ enableNestedDataAccess: PropTypes.string,
198
+ expandableRows: PropTypes.bool,
199
+ expandableRowsHeader: PropTypes.bool,
200
+ expandableRowsOnClick: PropTypes.bool,
201
+ disableToolbarSelect: PropTypes.bool,
202
+ download: PropTypes.oneOf([true, false, 'true', 'false', 'disabled']),
203
+ downloadOptions: PropTypes.shape({
204
+ filename: PropTypes.string,
205
+ separator: PropTypes.string,
206
+ filterOptions: PropTypes.shape({
207
+ useDisplayedColumnsOnly: PropTypes.bool,
208
+ useDisplayedRowsOnly: PropTypes.bool,
209
+ }),
210
+ }),
211
+ filter: PropTypes.oneOf([true, false, 'true', 'false', 'disabled']),
212
+ filterArrayFullMatch: PropTypes.bool,
213
+ filterType: PropTypes.oneOf(['dropdown', 'checkbox', 'multiselect', 'textField', 'custom']),
214
+ fixedHeader: PropTypes.bool,
215
+ fixedSelectColumn: PropTypes.bool,
216
+ getTextLabels: PropTypes.func,
217
+ isRowExpandable: PropTypes.func,
218
+ isRowSelectable: PropTypes.func,
219
+ jumpToPage: PropTypes.bool,
220
+ onDownload: PropTypes.func,
221
+ onFilterChange: PropTypes.func,
222
+ onFilterChipClose: PropTypes.func,
223
+ onFilterConfirm: PropTypes.func,
224
+ onFilterDialogOpen: PropTypes.func,
225
+ onFilterDialogClose: PropTypes.func,
226
+ onRowClick: PropTypes.func,
227
+ onRowsExpand: PropTypes.func,
228
+ onRowExpansionChange: PropTypes.func,
229
+ onRowsSelect: PropTypes.func,
230
+ onRowSelectionChange: PropTypes.func,
231
+ onTableChange: PropTypes.func,
232
+ onTableInit: PropTypes.func,
233
+ page: PropTypes.number,
234
+ pagination: PropTypes.bool,
235
+ print: PropTypes.oneOf([true, false, 'true', 'false', 'disabled']),
236
+ searchProps: PropTypes.object,
237
+ selectableRows: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['none', 'single', 'multiple'])]),
238
+ selectableRowsHeader: PropTypes.bool,
239
+ selectableRowsHideCheckboxes: PropTypes.bool,
240
+ selectableRowsOnClick: PropTypes.bool,
241
+ serverSide: PropTypes.bool,
242
+ tableId: PropTypes.string,
243
+ tableBodyHeight: PropTypes.string,
244
+ tableBodyMaxHeight: PropTypes.string,
245
+ renderExpandableRow: PropTypes.func,
246
+ resizableColumns: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
247
+ responsive: PropTypes.oneOf(['standard', 'vertical', 'verticalAlways', 'simple']),
248
+ rowHover: PropTypes.bool,
249
+ rowsExpanded: PropTypes.array,
250
+ rowsPerPage: PropTypes.number,
251
+ rowsPerPageOptions: PropTypes.array,
252
+ rowsSelected: PropTypes.array,
253
+ search: PropTypes.oneOf([true, false, 'true', 'false', 'disabled']),
254
+ searchOpen: PropTypes.bool,
255
+ searchAlwaysOpen: PropTypes.bool,
256
+ searchPlaceholder: PropTypes.string,
257
+ searchText: PropTypes.string,
258
+ setFilterChipProps: PropTypes.func,
259
+ setRowProps: PropTypes.func,
260
+ selectToolbarPlacement: PropTypes.oneOfType([
261
+ PropTypes.bool,
262
+ PropTypes.oneOf([STP.REPLACE, STP.ABOVE, STP.NONE, STP.ALWAYS]),
263
+ ]),
264
+ setTableProps: PropTypes.func,
265
+ sort: PropTypes.bool,
266
+ sortOrder: PropTypes.object,
267
+ storageKey: PropTypes.string,
268
+ viewColumns: PropTypes.oneOf([true, false, 'true', 'false', 'disabled']),
269
+ }),
270
+ /** Pass and use className to style MUIDataTable as desired */
271
+ className: PropTypes.string,
272
+ components: PropTypes.objectOf(PropTypes.any),
273
+ };
274
+
275
+ static defaultProps = {
276
+ title: '',
277
+ options: {},
278
+ data: [],
279
+ columns: [],
280
+ components: {
281
+ TableBody: DefaultTableBody,
282
+ TableFilter: DefaultTableFilter,
283
+ TableFilterList: DefaultTableFilterList,
284
+ TableFooter: DefaultTableFooter,
285
+ TableHead: DefaultTableHead,
286
+ TableResize: DefaultTableResize,
287
+ TableToolbar: DefaultTableToolbar,
288
+ TableToolbarSelect: DefaultTableToolbarSelect,
289
+ Tooltip: MuiTooltip,
290
+ icons: {},
291
+ },
292
+ };
293
+
294
+ constructor(props) {
295
+ super(props);
296
+ this.tableRef = React.createRef();
297
+ this.tableContent = React.createRef();
298
+ this.draggableHeadCellRefs = {};
299
+ this.resizeHeadCellRefs = {};
300
+ this.timers = {};
301
+ this.setHeadResizeable = () => {};
302
+ this.updateDividers = () => {};
303
+
304
+ let defaultState = {
305
+ activeColumn: null,
306
+ announceText: null,
307
+ count: 0,
308
+ columns: [],
309
+ expandedRows: {
310
+ data: [],
311
+ lookup: {},
312
+ },
313
+ data: [],
314
+ displayData: [],
315
+ filterData: [],
316
+ filterList: [],
317
+ page: 0,
318
+ previousSelectedRow: null,
319
+ rowsPerPage: 10,
320
+ searchProps: {},
321
+ searchText: null,
322
+ selectedRows: {
323
+ data: [],
324
+ lookup: {},
325
+ },
326
+ showResponsive: false,
327
+ sortOrder: {},
328
+ };
329
+
330
+ this.mergeDefaultOptions(props);
331
+
332
+ const restoredState = load(props.options.storageKey);
333
+ this.state = Object.assign(defaultState, restoredState ? restoredState : this.getInitTableOptions());
334
+
335
+ this.setTableData = this.setTableData.bind(this);
336
+
337
+ this.setTableData(props, TABLE_LOAD.INITIAL, true, null, true);
338
+ }
339
+
340
+ componentDidMount() {
341
+ this.setHeadResizeable(this.resizeHeadCellRefs, this.tableRef);
342
+
343
+ // When we have a search, we must reset page to view it unless on serverSide since paging is handled by the user.
344
+ if (this.props.options.searchText && !this.props.options.serverSide) this.setState({ page: 0 });
345
+
346
+ this.setTableInit('tableInitialized');
347
+ }
348
+
349
+ componentDidUpdate(prevProps) {
350
+ if (
351
+ this.props.data !== prevProps.data ||
352
+ this.props.columns !== prevProps.columns ||
353
+ this.props.options !== prevProps.options
354
+ ) {
355
+ this.updateOptions(this.options, this.props);
356
+
357
+ var didDataUpdate = this.props.data !== prevProps.data;
358
+ if (this.props.data && prevProps.data) {
359
+ didDataUpdate = didDataUpdate && this.props.data.length === prevProps.data.length;
360
+ }
361
+
362
+ this.setTableData(this.props, TABLE_LOAD.INITIAL, didDataUpdate, () => {
363
+ this.setTableAction('propsUpdate');
364
+ });
365
+ }
366
+
367
+ if (this.props.options.searchText !== prevProps.options.searchText && !this.props.options.serverSide) {
368
+ // When we have a search, we must reset page to view it unless on serverSide since paging is handled by the user.
369
+ this.setState({ page: 0 });
370
+ }
371
+
372
+ if (
373
+ this.options.resizableColumns === true ||
374
+ (this.options.resizableColumns && this.options.resizableColumns.enabled)
375
+ ) {
376
+ this.setHeadResizeable(this.resizeHeadCellRefs, this.tableRef);
377
+ this.updateDividers();
378
+ }
379
+ }
380
+
381
+ updateOptions(options, props) {
382
+ // set backwards compatibility options
383
+ if (props.options.disableToolbarSelect === true && props.options.selectToolbarPlacement === undefined) {
384
+ // if deprecated option disableToolbarSelect is set and selectToolbarPlacement is default then use it
385
+ props.options.selectToolbarPlacement = STP.NONE;
386
+ }
387
+
388
+ // provide default tableId when no tableId has been passed as prop
389
+ if (!props.options.tableId) {
390
+ props.options.tableId = (Math.random() + '').replace(/\./, '');
391
+ }
392
+
393
+ this.options = assignwith(options, props.options, (objValue, srcValue, key) => {
394
+ // Merge any default options that are objects, as they will be overwritten otherwise
395
+ if (key === 'textLabels' || key === 'downloadOptions') return merge(objValue, srcValue);
396
+ return;
397
+ });
398
+
399
+ this.handleOptionDeprecation(props);
400
+ }
401
+
402
+ getDefaultOptions = () => ({
403
+ caseSensitive: false,
404
+ consoleWarnings: true,
405
+ disableToolbarSelect: false,
406
+ download: true,
407
+ downloadOptions: {
408
+ filename: 'tableDownload.csv',
409
+ separator: ',',
410
+ },
411
+ draggableColumns: {
412
+ enabled: false,
413
+ transitionTime: 300,
414
+ },
415
+ elevation: 4,
416
+ enableNestedDataAccess: '',
417
+ expandableRows: false,
418
+ expandableRowsHeader: true,
419
+ expandableRowsOnClick: false,
420
+ filter: true,
421
+ filterArrayFullMatch: true,
422
+ filterType: 'dropdown',
423
+ fixedHeader: true,
424
+ fixedSelectColumn: true,
425
+ pagination: true,
426
+ print: true,
427
+ resizableColumns: false,
428
+ responsive: 'vertical',
429
+ rowHover: true,
430
+ //rowsPerPage: 10,
431
+ rowsPerPageOptions: [10, 15, 100],
432
+ search: true,
433
+ selectableRows: 'multiple',
434
+ selectableRowsHideCheckboxes: false,
435
+ selectableRowsOnClick: false,
436
+ selectableRowsHeader: true,
437
+ serverSide: false,
438
+ serverSideFilterList: null,
439
+ setTableProps: () => ({}),
440
+ sort: true,
441
+ sortFilterList: true,
442
+ tableBodyHeight: 'auto',
443
+ tableBodyMaxHeight: null, // if set, it will override tableBodyHeight
444
+ sortOrder: {},
445
+ textLabels: getTextLabels(),
446
+ viewColumns: true,
447
+ selectToolbarPlacement: STP.REPLACE,
448
+ });
449
+
450
+ warnDep = (msg, consoleWarnings) => {
451
+ warnDeprecated(msg, this.options.consoleWarnings);
452
+ };
453
+
454
+ warnInfo = (msg, consoleWarnings) => {
455
+ warnInfo(msg, this.options.consoleWarnings);
456
+ };
457
+
458
+ handleOptionDeprecation = (props) => {
459
+ if (typeof this.options.selectableRows === 'boolean') {
460
+ this.warnDep(
461
+ 'Using a boolean for selectableRows has been deprecated. Please use string option: multiple | single | none',
462
+ );
463
+ this.options.selectableRows = this.options.selectableRows ? 'multiple' : 'none';
464
+ }
465
+ if (['standard', 'vertical', 'verticalAlways', 'simple'].indexOf(this.options.responsive) === -1) {
466
+ if (
467
+ [
468
+ 'scrollMaxHeight',
469
+ 'scrollFullHeight',
470
+ 'stacked',
471
+ 'stackedFullWidth',
472
+ 'scrollFullHeightFullWidth',
473
+ 'scroll',
474
+ ].indexOf(this.options.responsive) !== -1
475
+ ) {
476
+ this.warnDep(
477
+ this.options.responsive +
478
+ ' has been deprecated, but will still work in version 3.x. Please use string option: standard | vertical | simple. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
479
+ );
480
+ } else {
481
+ this.warnInfo(
482
+ this.options.responsive +
483
+ ' is not recognized as a valid input for responsive option. Please use string option: standard | vertical | simple. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
484
+ );
485
+ }
486
+ }
487
+ if (this.options.onRowsSelect) {
488
+ this.warnDep(
489
+ 'onRowsSelect has been renamed onRowSelectionChange. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
490
+ );
491
+ }
492
+ if (this.options.onRowsExpand) {
493
+ this.warnDep(
494
+ 'onRowsExpand has been renamed onRowExpansionChange. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
495
+ );
496
+ }
497
+ if (this.options.fixedHeaderOptions) {
498
+ if (
499
+ typeof this.options.fixedHeaderOptions.yAxis !== 'undefined' &&
500
+ typeof this.options.fixedHeader === 'undefined'
501
+ ) {
502
+ this.options.fixedHeader = this.options.fixedHeaderOptions.yAxis;
503
+ }
504
+ if (
505
+ typeof this.options.fixedHeaderOptions.xAxis !== 'undefined' &&
506
+ typeof this.options.fixedSelectColumn === 'undefined'
507
+ ) {
508
+ this.options.fixedSelectColumn = this.options.fixedHeaderOptions.xAxis;
509
+ }
510
+ this.warnDep(
511
+ 'fixedHeaderOptions will still work but has been deprecated in favor of fixedHeader and fixedSelectColumn. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
512
+ );
513
+ }
514
+ if (this.options.serverSideFilterList) {
515
+ this.warnDep(
516
+ 'serverSideFilterList will still work but has been deprecated in favor of the confirmFilters option. See this example for details: https://github.com/gregnb/mui-datatables/blob/master/examples/serverside-filters/index.js More info here: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
517
+ );
518
+ }
519
+
520
+ props.columns.map((c) => {
521
+ if (c.options && c.options.customFilterListRender) {
522
+ this.warnDep(
523
+ 'The customFilterListRender option has been deprecated. It is being replaced by customFilterListOptions.render (Specify customFilterListOptions: { render: Function } in column options.)',
524
+ );
525
+ }
526
+ });
527
+
528
+ if (this.options.disableToolbarSelect === true) {
529
+ this.warnDep(
530
+ 'disableToolbarSelect has been deprecated but will still work in version 3.x. It is being replaced by "selectToolbarPlacement"="none". More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
531
+ );
532
+ }
533
+
534
+ // only give this warning message in newer browsers
535
+ if (Object.values) {
536
+ if (Object.values(STP).indexOf(this.options.selectToolbarPlacement) === -1) {
537
+ this.warnDep(
538
+ 'Invalid option value for selectToolbarPlacement. Please check the documentation: https://github.com/gregnb/mui-datatables#options',
539
+ );
540
+ }
541
+ }
542
+ };
543
+
544
+ /*
545
+ * React currently does not support deep merge for defaultProps. Objects are overwritten
546
+ */
547
+ mergeDefaultOptions(props) {
548
+ const defaultOptions = this.getDefaultOptions();
549
+ const theProps = Object.assign({}, props);
550
+ theProps.options = theProps.options || {};
551
+
552
+ this.updateOptions(defaultOptions, theProps);
553
+ }
554
+
555
+ validateOptions(options) {
556
+ if (options.serverSide && options.onTableChange === undefined) {
557
+ throw Error('onTableChange callback must be provided when using serverSide option');
558
+ }
559
+ if (options.expandableRows && options.renderExpandableRow === undefined) {
560
+ throw Error('renderExpandableRow must be provided when using expandableRows option');
561
+ }
562
+ if (options.rowsSelected && Array.isArray(options.rowsSelected) && options.rowsSelected.some(isNaN)) {
563
+ warnInfo('When using the rowsSelected option, must be provided an array of numbers only.');
564
+ }
565
+ }
566
+
567
+ setTableAction = (action) => {
568
+ if (typeof this.options.onTableChange === 'function') {
569
+ this.options.onTableChange(action, this.state);
570
+ }
571
+ if (this.options.storageKey) {
572
+ save(this.options.storageKey, this.state);
573
+ }
574
+ };
575
+
576
+ setTableInit = (action) => {
577
+ if (typeof this.options.onTableInit === 'function') {
578
+ this.options.onTableInit(action, this.state);
579
+ }
580
+ };
581
+
582
+ getInitTableOptions() {
583
+ const optionNames = ['rowsPerPage', 'page', 'rowsSelected', 'rowsPerPageOptions'];
584
+ const optState = optionNames.reduce((acc, cur) => {
585
+ if (this.options[cur] !== undefined) {
586
+ acc[cur] = this.options[cur];
587
+ }
588
+ return acc;
589
+ }, {});
590
+
591
+ this.validateOptions(optState);
592
+ return optState;
593
+ }
594
+
595
+ setHeadCellRef = (index, pos, el) => {
596
+ this.draggableHeadCellRefs[index] = el;
597
+ this.resizeHeadCellRefs[pos] = el;
598
+ };
599
+
600
+ // must be arrow function on local field to refer to the correct instance when passed around
601
+ // assigning it as arrow function in the JSX would cause hard to track re-render errors
602
+ getTableContentRef = () => this.tableContent.current;
603
+
604
+ /*
605
+ *  Build the source table data
606
+ *
607
+ * newColumns - columns from the options object.
608
+ * prevColumns - columns object saved onto ths state.
609
+ * newColumnOrder - columnOrder from the options object.
610
+ * prevColumnOrder - columnOrder object saved onto the state.
611
+ */
612
+
613
+ buildColumns = (newColumns, prevColumns = [], newColumnOrder, prevColumnOrder = []) => {
614
+ let columnData = [];
615
+ let filterData = [];
616
+ let filterList = [];
617
+ let columnOrder = [];
618
+
619
+ newColumns.forEach((column, colIndex) => {
620
+ let columnOptions = {
621
+ display: 'true',
622
+ empty: false,
623
+ filter: true,
624
+ sort: true,
625
+ print: true,
626
+ searchable: true,
627
+ download: true,
628
+ viewColumns: true,
629
+ sortCompare: null,
630
+ sortThirdClickReset: false,
631
+ sortDescFirst: false,
632
+ };
633
+
634
+ columnOrder.push(colIndex);
635
+ const options = { ...column.options };
636
+
637
+ if (typeof column === 'object') {
638
+ if (options) {
639
+ if (options.display !== undefined) {
640
+ options.display = options.display.toString();
641
+ }
642
+
643
+ if (options.sortDirection === null || options.sortDirection) {
644
+ this.warnDep(
645
+ 'The sortDirection column field has been deprecated. Please use the sortOrder option on the options object. More info: https://github.com/gregnb/mui-datatables/tree/master/docs/v2_to_v3_guide.md',
646
+ );
647
+ }
648
+ }
649
+
650
+ // remember stored version of display if not overwritten
651
+ if (
652
+ typeof options.display === 'undefined' &&
653
+ prevColumns[colIndex] &&
654
+ prevColumns[colIndex].name === column.name &&
655
+ prevColumns[colIndex].display
656
+ ) {
657
+ options.display = prevColumns[colIndex].display;
658
+ }
659
+
660
+ columnOptions = {
661
+ name: column.name,
662
+ label: column.label ? column.label : column.name,
663
+ ...columnOptions,
664
+ ...options,
665
+ };
666
+ } else {
667
+ // remember stored version of display if not overwritten
668
+ if (prevColumns[colIndex] && prevColumns[colIndex].display) {
669
+ options.display = prevColumns[colIndex].display;
670
+ }
671
+
672
+ columnOptions = { ...columnOptions, ...options, name: column, label: column };
673
+ }
674
+
675
+ columnData.push(columnOptions);
676
+
677
+ filterData[colIndex] = [];
678
+ filterList[colIndex] = [];
679
+ });
680
+
681
+ if (Array.isArray(newColumnOrder)) {
682
+ columnOrder = newColumnOrder;
683
+ } else if (
684
+ Array.isArray(prevColumnOrder) &&
685
+ Array.isArray(newColumns) &&
686
+ Array.isArray(prevColumns) &&
687
+ newColumns.length === prevColumns.length
688
+ ) {
689
+ columnOrder = prevColumnOrder;
690
+ }
691
+
692
+ return { columns: columnData, filterData, filterList, columnOrder };
693
+ };
694
+
695
+ transformData = (columns, data) => {
696
+ const { enableNestedDataAccess } = this.options;
697
+ const leaf = (obj, path) =>
698
+ (enableNestedDataAccess ? path.split(enableNestedDataAccess) : path.split()).reduce(
699
+ (value, el) => (value ? value[el] : undefined),
700
+ obj,
701
+ );
702
+
703
+ const transformedData = Array.isArray(data[0])
704
+ ? data.map((row) => {
705
+ let i = -1;
706
+
707
+ return columns.map((col) => {
708
+ if (!col.empty) i++;
709
+ return col.empty ? undefined : row[i];
710
+ });
711
+ })
712
+ : data.map((row) => columns.map((col) => leaf(row, col.name)));
713
+
714
+ return transformedData;
715
+ };
716
+
717
+ setTableData(props, status, dataUpdated, callback = () => {}, fromConstructor = false) {
718
+ let tableData = [];
719
+ let { columns, filterData, filterList, columnOrder } = this.buildColumns(
720
+ props.columns,
721
+ this.state.columns,
722
+ this.options.columnOrder,
723
+ this.state.columnOrder,
724
+ );
725
+
726
+ let sortIndex = null;
727
+ let sortDirection = 'none';
728
+ let tableMeta;
729
+
730
+ let sortOrder;
731
+ if (this.options.sortOrder && this.options.sortOrder.direction && this.options.sortOrder.name) {
732
+ sortOrder = Object.assign({}, this.options.sortOrder);
733
+ } else {
734
+ sortOrder = Object.assign({}, this.state.sortOrder);
735
+
736
+ // if no sortOrder, check and see if there's a sortDirection on one of the columns (deprecation notice for this is given above)
737
+ if (!sortOrder.direction) {
738
+ props.columns.forEach((column, colIndex) => {
739
+ if (column.options && (column.options.sortDirection === 'asc' || column.options.sortDirection === 'desc')) {
740
+ sortOrder.name = column.name;
741
+ sortOrder.sortDirection = column.sortDirection;
742
+ }
743
+ });
744
+ }
745
+ }
746
+
747
+ const data = status === TABLE_LOAD.INITIAL ? this.transformData(columns, props.data) : props.data;
748
+ let searchText = status === TABLE_LOAD.INITIAL ? this.options.searchText : null;
749
+
750
+ if (typeof this.options.searchText === 'undefined' && typeof this.state.searchText !== 'undefined') {
751
+ searchText = this.state.searchText;
752
+ }
753
+
754
+ let rowsPerPage = this.state.rowsPerPage;
755
+ if (typeof this.options.rowsPerPage === 'number') {
756
+ rowsPerPage = this.options.rowsPerPage;
757
+ }
758
+
759
+ let page = this.state.page;
760
+ if (typeof this.options.page === 'number') {
761
+ page = this.options.page;
762
+ }
763
+
764
+ columns.forEach((column, colIndex) => {
765
+ for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
766
+ let value = status === TABLE_LOAD.INITIAL ? data[rowIndex][colIndex] : data[rowIndex].data[colIndex];
767
+
768
+ if (typeof tableData[rowIndex] === 'undefined') {
769
+ tableData.push({
770
+ index: status === TABLE_LOAD.INITIAL ? rowIndex : data[rowIndex].index,
771
+ data: status === TABLE_LOAD.INITIAL ? data[rowIndex] : data[rowIndex].data,
772
+ });
773
+ }
774
+
775
+ if (column.filter !== false) {
776
+ if (typeof column.customBodyRender === 'function') {
777
+ const rowData = tableData[rowIndex].data;
778
+ tableMeta = this.getTableMeta(rowIndex, colIndex, rowData, column, data, this.state, tableData);
779
+ const funcResult = column.customBodyRender(value, tableMeta);
780
+
781
+ if (React.isValidElement(funcResult) && funcResult.props.value) {
782
+ value = funcResult.props.value;
783
+ } else if (typeof funcResult === 'string') {
784
+ value = funcResult;
785
+ }
786
+ }
787
+
788
+ if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
789
+ // it's extremely rare but possible to create an object without a toString method, ex: var x = Object.create(null);
790
+ // so this check has to be made
791
+ value = value.toString ? value.toString() : '';
792
+ }
793
+
794
+ if (filterData[colIndex].indexOf(value) < 0 && !Array.isArray(value)) {
795
+ filterData[colIndex].push(value);
796
+ } else if (Array.isArray(value)) {
797
+ value.forEach((element) => {
798
+ let elmVal;
799
+ if ((typeof element === 'object' && element !== null) || typeof element === 'function') {
800
+ elmVal = element.toString ? element.toString() : '';
801
+ } else {
802
+ elmVal = element;
803
+ }
804
+
805
+ if (filterData[colIndex].indexOf(elmVal) < 0) {
806
+ filterData[colIndex].push(elmVal);
807
+ }
808
+ });
809
+ }
810
+ }
811
+ }
812
+
813
+ if (column.filterOptions) {
814
+ if (Array.isArray(column.filterOptions)) {
815
+ filterData[colIndex] = cloneDeep(column.filterOptions);
816
+ this.warnDep(
817
+ 'filterOptions must now be an object. see https://github.com/gregnb/mui-datatables/tree/master/examples/customize-filter example',
818
+ );
819
+ } else if (Array.isArray(column.filterOptions.names)) {
820
+ filterData[colIndex] = cloneDeep(column.filterOptions.names);
821
+ }
822
+ }
823
+
824
+ if (column.filterList) {
825
+ filterList[colIndex] = cloneDeep(column.filterList);
826
+ } else if (
827
+ this.state.filterList &&
828
+ this.state.filterList[colIndex] &&
829
+ this.state.filterList[colIndex].length > 0
830
+ ) {
831
+ filterList[colIndex] = cloneDeep(this.state.filterList[colIndex]);
832
+ }
833
+
834
+ if (this.options.sortFilterList) {
835
+ const comparator = getCollatorComparator();
836
+ filterData[colIndex].sort(comparator);
837
+ }
838
+
839
+ if (column.name === sortOrder.name) {
840
+ sortDirection = sortOrder.direction;
841
+ sortIndex = colIndex;
842
+ }
843
+ });
844
+
845
+ let selectedRowsData = {
846
+ data: [],
847
+ lookup: {},
848
+ };
849
+
850
+ let expandedRowsData = {
851
+ data: [],
852
+ lookup: {},
853
+ };
854
+
855
+ if (TABLE_LOAD.INITIAL) {
856
+ // Multiple row selection customization
857
+ if (this.options.rowsSelected && this.options.rowsSelected.length && this.options.selectableRows === 'multiple') {
858
+ this.options.rowsSelected
859
+ .filter((selectedRowIndex) => selectedRowIndex === 0 || (Number(selectedRowIndex) && selectedRowIndex > 0))
860
+ .forEach((row) => {
861
+ let rowPos = row;
862
+
863
+ for (let cIndex = 0; cIndex < this.state.displayData.length; cIndex++) {
864
+ if (this.state.displayData[cIndex].dataIndex === row) {
865
+ rowPos = cIndex;
866
+ break;
867
+ }
868
+ }
869
+
870
+ selectedRowsData.data.push({ index: rowPos, dataIndex: row });
871
+ selectedRowsData.lookup[row] = true;
872
+ });
873
+
874
+ // Single row selection customization
875
+ } else if (
876
+ this.options.rowsSelected &&
877
+ this.options.rowsSelected.length === 1 &&
878
+ this.options.selectableRows === 'single'
879
+ ) {
880
+ let rowPos = this.options.rowsSelected[0];
881
+
882
+ for (let cIndex = 0; cIndex < this.state.displayData.length; cIndex++) {
883
+ if (this.state.displayData[cIndex].dataIndex === this.options.rowsSelected[0]) {
884
+ rowPos = cIndex;
885
+ break;
886
+ }
887
+ }
888
+
889
+ selectedRowsData.data.push({ index: rowPos, dataIndex: this.options.rowsSelected[0] });
890
+ selectedRowsData.lookup[this.options.rowsSelected[0]] = true;
891
+ } else if (
892
+ this.options.rowsSelected &&
893
+ this.options.rowsSelected.length > 1 &&
894
+ this.options.selectableRows === 'single'
895
+ ) {
896
+ console.error(
897
+ 'Multiple values provided for selectableRows, but selectableRows set to "single". Either supply only a single value or use "multiple".',
898
+ );
899
+ } else if (typeof this.options.rowsSelected === 'undefined' && dataUpdated === false) {
900
+ if (this.state.selectedRows) {
901
+ selectedRowsData = Object.assign({}, this.state.selectedRows);
902
+ }
903
+ }
904
+
905
+ if (this.options.rowsExpanded && this.options.rowsExpanded.length && this.options.expandableRows) {
906
+ this.options.rowsExpanded.forEach((row) => {
907
+ let rowPos = row;
908
+
909
+ for (let cIndex = 0; cIndex < this.state.displayData.length; cIndex++) {
910
+ if (this.state.displayData[cIndex].dataIndex === row) {
911
+ rowPos = cIndex;
912
+ break;
913
+ }
914
+ }
915
+
916
+ expandedRowsData.data.push({ index: rowPos, dataIndex: row });
917
+ expandedRowsData.lookup[row] = true;
918
+ });
919
+ } else if (typeof this.options.rowsExpanded === 'undefined' && dataUpdated === false && this.state.expandedRows) {
920
+ expandedRowsData = Object.assign({}, this.state.expandedRows);
921
+ }
922
+ }
923
+
924
+ if (!this.options.serverSide && sortIndex !== null) {
925
+ const sortedData = this.sortTable(tableData, sortIndex, sortDirection, columns[sortIndex].sortCompare);
926
+ tableData = sortedData.data;
927
+ }
928
+
929
+ /* set source data and display Data set source set */
930
+ let stateUpdates = {
931
+ columns: columns,
932
+ filterData: filterData,
933
+ filterList: filterList,
934
+ searchText: searchText,
935
+ selectedRows: selectedRowsData,
936
+ expandedRows: expandedRowsData,
937
+ count: this.options.count,
938
+ data: tableData,
939
+ sortOrder: sortOrder,
940
+ rowsPerPage,
941
+ page,
942
+ displayData: this.getDisplayData(columns, tableData, filterList, searchText, tableMeta, props),
943
+ columnOrder,
944
+ };
945
+
946
+ if (fromConstructor) {
947
+ this.state = Object.assign({}, this.state, stateUpdates);
948
+ } else {
949
+ this.setState(stateUpdates, callback);
950
+ }
951
+ }
952
+
953
+ /*
954
+ * Build the table data used to display to the user (ie: after filter/search applied)
955
+ */
956
+ computeDisplayRow(
957
+ columns,
958
+ row,
959
+ rowIndex,
960
+ filterList,
961
+ searchText,
962
+ dataForTableMeta,
963
+ options,
964
+ props,
965
+ currentTableData,
966
+ ) {
967
+ let isFiltered = false;
968
+ let isSearchFound = false;
969
+ let displayRow = [];
970
+
971
+ for (let index = 0; index < row.length; index++) {
972
+ let columnDisplay = row[index];
973
+ let columnValue = row[index];
974
+ let column = columns[index];
975
+
976
+ if (column.customBodyRenderLite) {
977
+ displayRow.push(column.customBodyRenderLite);
978
+ } else if (column.customBodyRender) {
979
+ const tableMeta = this.getTableMeta(
980
+ rowIndex,
981
+ index,
982
+ row,
983
+ column,
984
+ dataForTableMeta,
985
+ {
986
+ ...this.state,
987
+ filterList: filterList,
988
+ searchText: searchText,
989
+ },
990
+ currentTableData,
991
+ );
992
+
993
+ const funcResult = column.customBodyRender(
994
+ columnValue,
995
+ tableMeta,
996
+ this.updateDataCol.bind(null, rowIndex, index),
997
+ );
998
+ columnDisplay = funcResult;
999
+
1000
+ /* drill down to get the value of a cell */
1001
+ columnValue =
1002
+ typeof funcResult === 'string' || !funcResult
1003
+ ? funcResult
1004
+ : funcResult.props && funcResult.props.value
1005
+ ? funcResult.props.value
1006
+ : columnValue;
1007
+
1008
+ displayRow.push(columnDisplay);
1009
+ } else {
1010
+ displayRow.push(columnDisplay);
1011
+ }
1012
+
1013
+ const columnVal = columnValue === null || columnValue === undefined ? '' : columnValue.toString();
1014
+
1015
+ const filterVal = filterList[index];
1016
+ const caseSensitive = options.caseSensitive;
1017
+ const filterType = column.filterType || options.filterType;
1018
+ if (filterVal.length || filterType === 'custom') {
1019
+ if (column.filterOptions && column.filterOptions.logic) {
1020
+ if (column.filterOptions.logic(columnValue, filterVal, row)) isFiltered = true;
1021
+ } else if (filterType === 'textField' && !this.hasSearchText(columnVal, filterVal, caseSensitive)) {
1022
+ isFiltered = true;
1023
+ } else if (
1024
+ filterType !== 'textField' &&
1025
+ Array.isArray(columnValue) === false &&
1026
+ filterVal.indexOf(columnValue) < 0
1027
+ ) {
1028
+ isFiltered = true;
1029
+ } else if (filterType !== 'textField' && Array.isArray(columnValue)) {
1030
+ if (options.filterArrayFullMatch) {
1031
+ //true if every filterVal exists in columnVal, false otherwise
1032
+ const isFullMatch = filterVal.every((el) => {
1033
+ return columnValue.indexOf(el) >= 0;
1034
+ });
1035
+ //if it is not a fullMatch, filter row out
1036
+ if (!isFullMatch) {
1037
+ isFiltered = true;
1038
+ }
1039
+ } else {
1040
+ const isAnyMatch = filterVal.some((el) => {
1041
+ return columnValue.indexOf(el) >= 0;
1042
+ });
1043
+ //if no value matches, filter row out
1044
+ if (!isAnyMatch) {
1045
+ isFiltered = true;
1046
+ }
1047
+ }
1048
+ }
1049
+ }
1050
+
1051
+ if (
1052
+ searchText &&
1053
+ column.display !== 'excluded' &&
1054
+ this.hasSearchText(columnVal, searchText, caseSensitive) &&
1055
+ column.display !== 'false' &&
1056
+ column.searchable
1057
+ ) {
1058
+ isSearchFound = true;
1059
+ }
1060
+ }
1061
+
1062
+ const { customSearch } = props.options;
1063
+
1064
+ if (searchText && customSearch) {
1065
+ const customSearchResult = customSearch(searchText, row, columns);
1066
+ if (typeof customSearchResult !== 'boolean') {
1067
+ console.error('customSearch must return a boolean');
1068
+ } else {
1069
+ isSearchFound = customSearchResult;
1070
+ }
1071
+ }
1072
+
1073
+ if (options.serverSide) {
1074
+ if (customSearch) {
1075
+ console.warn('Server-side filtering is enabled, hence custom search will be ignored.');
1076
+ }
1077
+
1078
+ return displayRow;
1079
+ }
1080
+
1081
+ if (isFiltered || (searchText && !isSearchFound)) return null;
1082
+ else return displayRow;
1083
+ }
1084
+
1085
+ hasSearchText = (toSearch, toFind, caseSensitive) => {
1086
+ let stack = toSearch.toString();
1087
+ let needle = toFind.toString();
1088
+
1089
+ if (!caseSensitive) {
1090
+ needle = needle.toLowerCase();
1091
+ stack = stack.toLowerCase();
1092
+ }
1093
+
1094
+ return stack.indexOf(needle) >= 0;
1095
+ };
1096
+
1097
+ updateDataCol = (row, index, value) => {
1098
+ this.setState((prevState) => {
1099
+ let changedData = cloneDeep(prevState.data);
1100
+ let filterData = cloneDeep(prevState.filterData);
1101
+
1102
+ const tableMeta = this.getTableMeta(
1103
+ row,
1104
+ index,
1105
+ row,
1106
+ prevState.columns[index],
1107
+ prevState.data,
1108
+ prevState,
1109
+ prevState.data,
1110
+ );
1111
+ const funcResult = prevState.columns[index].customBodyRender(value, tableMeta);
1112
+
1113
+ const filterValue =
1114
+ React.isValidElement(funcResult) && funcResult.props.value
1115
+ ? funcResult.props.value
1116
+ : prevState['data'][row][index];
1117
+
1118
+ const prevFilterIndex = filterData[index].indexOf(filterValue);
1119
+ filterData[index].splice(prevFilterIndex, 1, filterValue);
1120
+
1121
+ changedData[row].data[index] = value;
1122
+
1123
+ if (this.options.sortFilterList) {
1124
+ const comparator = getCollatorComparator();
1125
+ filterData[index].sort(comparator);
1126
+ }
1127
+
1128
+ return {
1129
+ data: changedData,
1130
+ filterData: filterData,
1131
+ displayData: this.getDisplayData(
1132
+ prevState.columns,
1133
+ changedData,
1134
+ prevState.filterList,
1135
+ prevState.searchText,
1136
+ null,
1137
+ this.props,
1138
+ ),
1139
+ };
1140
+ });
1141
+ };
1142
+
1143
+ getTableMeta = (rowIndex, colIndex, rowData, columnData, tableData, curState, currentTableData) => {
1144
+ const { columns, data, displayData, filterData, ...tableState } = curState;
1145
+
1146
+ return {
1147
+ rowIndex: rowIndex,
1148
+ columnIndex: colIndex,
1149
+ columnData: columnData,
1150
+ rowData: rowData,
1151
+ tableData: tableData,
1152
+ tableState: tableState,
1153
+ currentTableData: currentTableData,
1154
+ };
1155
+ };
1156
+
1157
+ getDisplayData(columns, data, filterList, searchText, tableMeta, props) {
1158
+ let newRows = [];
1159
+ const dataForTableMeta = tableMeta ? tableMeta.tableData : props.data;
1160
+
1161
+ for (let index = 0; index < data.length; index++) {
1162
+ const value = data[index].data;
1163
+ const displayRow = this.computeDisplayRow(
1164
+ columns,
1165
+ value,
1166
+ index,
1167
+ filterList,
1168
+ searchText,
1169
+ dataForTableMeta,
1170
+ this.options,
1171
+ props,
1172
+ data,
1173
+ );
1174
+
1175
+ if (displayRow) {
1176
+ newRows.push({
1177
+ data: displayRow,
1178
+ dataIndex: data[index].index,
1179
+ });
1180
+ }
1181
+ }
1182
+ return newRows;
1183
+ }
1184
+
1185
+ toggleViewColumn = (index) => {
1186
+ this.setState(
1187
+ (prevState) => {
1188
+ const columns = cloneDeep(prevState.columns);
1189
+ columns[index].display = columns[index].display === 'true' ? 'false' : 'true';
1190
+ return {
1191
+ columns: columns,
1192
+ };
1193
+ },
1194
+ () => {
1195
+ this.setTableAction('viewColumnsChange');
1196
+ var cb = this.options.onViewColumnsChange || this.options.onColumnViewChange;
1197
+
1198
+ if (cb) {
1199
+ cb(this.state.columns[index].name, this.state.columns[index].display === 'true' ? 'add' : 'remove');
1200
+ }
1201
+ },
1202
+ );
1203
+ };
1204
+
1205
+ updateColumns = (newColumns) => {
1206
+ this.setState(
1207
+ (prevState) => {
1208
+ return {
1209
+ columns: newColumns,
1210
+ };
1211
+ },
1212
+ () => {
1213
+ this.setTableAction('viewColumnsChange');
1214
+ var cb = this.options.onViewColumnsChange || this.options.onColumnViewChange;
1215
+
1216
+ if (cb) {
1217
+ cb(null, 'update', newColumns);
1218
+ }
1219
+ },
1220
+ );
1221
+ };
1222
+
1223
+ getSortDirectionLabel(sortOrder) {
1224
+ switch (sortOrder.direction) {
1225
+ case 'asc':
1226
+ return 'ascending';
1227
+ case 'desc':
1228
+ return 'descending';
1229
+ case 'none':
1230
+ return 'none';
1231
+ default:
1232
+ return '';
1233
+ }
1234
+ }
1235
+
1236
+ getTableProps() {
1237
+ const { classes } = this.props;
1238
+ const tableProps = this.options.setTableProps() || {};
1239
+
1240
+ tableProps.className = clsx(classes.tableRoot, tableProps.className);
1241
+
1242
+ return tableProps;
1243
+ }
1244
+
1245
+ toggleSortColumn = (index) => {
1246
+ this.setState(
1247
+ (prevState) => {
1248
+ let columns = cloneDeep(prevState.columns);
1249
+ let data = prevState.data;
1250
+ let newOrder = columns[index].sortDescFirst ? 'desc' : 'asc'; // default
1251
+
1252
+ let sequenceOrder = ['asc', 'desc'];
1253
+ if (columns[index].sortDescFirst) {
1254
+ sequenceOrder = ['desc', 'asc'];
1255
+ }
1256
+ if (columns[index].sortThirdClickReset) {
1257
+ sequenceOrder.push('none');
1258
+ }
1259
+
1260
+ if (columns[index].name === this.state.sortOrder.name) {
1261
+ let pos = sequenceOrder.indexOf(this.state.sortOrder.direction);
1262
+ if (pos !== -1) {
1263
+ pos++;
1264
+ if (pos >= sequenceOrder.length) pos = 0;
1265
+ newOrder = sequenceOrder[pos];
1266
+ }
1267
+ }
1268
+
1269
+ const newSortOrder = {
1270
+ name: columns[index].name,
1271
+ direction: newOrder,
1272
+ };
1273
+
1274
+ const orderLabel = this.getSortDirectionLabel(newSortOrder);
1275
+ const announceText = `Table now sorted by ${columns[index].name} : ${orderLabel}`;
1276
+
1277
+ let newState = {
1278
+ columns: columns,
1279
+ announceText: announceText,
1280
+ activeColumn: index,
1281
+ };
1282
+
1283
+ if (this.options.serverSide) {
1284
+ newState = {
1285
+ ...newState,
1286
+ data: prevState.data,
1287
+ displayData: prevState.displayData,
1288
+ selectedRows: prevState.selectedRows,
1289
+ sortOrder: newSortOrder,
1290
+ };
1291
+ } else {
1292
+ const sortedData = this.sortTable(data, index, newOrder, columns[index].sortCompare);
1293
+
1294
+ newState = {
1295
+ ...newState,
1296
+ data: sortedData.data,
1297
+ displayData: this.getDisplayData(
1298
+ columns,
1299
+ sortedData.data,
1300
+ prevState.filterList,
1301
+ prevState.searchText,
1302
+ null,
1303
+ this.props,
1304
+ ),
1305
+ selectedRows: sortedData.selectedRows,
1306
+ sortOrder: newSortOrder,
1307
+ previousSelectedRow: null,
1308
+ };
1309
+ }
1310
+
1311
+ return newState;
1312
+ },
1313
+ () => {
1314
+ this.setTableAction('sort');
1315
+
1316
+ if (this.options.onColumnSortChange) {
1317
+ this.options.onColumnSortChange(this.state.sortOrder.name, this.state.sortOrder.direction);
1318
+ }
1319
+ },
1320
+ );
1321
+ };
1322
+
1323
+ changeRowsPerPage = (rows) => {
1324
+ const rowCount = this.options.count || this.state.displayData.length;
1325
+
1326
+ this.setState(
1327
+ () => ({
1328
+ rowsPerPage: rows,
1329
+ page: getPageValue(rowCount, rows, this.state.page),
1330
+ }),
1331
+ () => {
1332
+ this.setTableAction('changeRowsPerPage');
1333
+
1334
+ if (this.options.onChangeRowsPerPage) {
1335
+ this.options.onChangeRowsPerPage(this.state.rowsPerPage);
1336
+ }
1337
+ },
1338
+ );
1339
+ };
1340
+
1341
+ changePage = (page) => {
1342
+ this.setState(
1343
+ () => ({
1344
+ page: page,
1345
+ }),
1346
+ () => {
1347
+ this.setTableAction('changePage');
1348
+ if (this.options.onChangePage) {
1349
+ this.options.onChangePage(this.state.page);
1350
+ }
1351
+ },
1352
+ );
1353
+ };
1354
+
1355
+ searchClose = () => {
1356
+ this.setState(
1357
+ (prevState) => ({
1358
+ searchText: null,
1359
+ displayData: this.options.serverSide
1360
+ ? prevState.displayData
1361
+ : this.getDisplayData(prevState.columns, prevState.data, prevState.filterList, null, null, this.props),
1362
+ }),
1363
+ () => {
1364
+ this.setTableAction('search');
1365
+ if (this.options.onSearchChange) {
1366
+ this.options.onSearchChange(this.state.searchText);
1367
+ }
1368
+ },
1369
+ );
1370
+ };
1371
+
1372
+ searchTextUpdate = (text) => {
1373
+ this.setState(
1374
+ (prevState) => ({
1375
+ searchText: text && text.length ? text : null,
1376
+ page: 0,
1377
+ displayData: this.options.serverSide
1378
+ ? prevState.displayData
1379
+ : this.getDisplayData(prevState.columns, prevState.data, prevState.filterList, text, null, this.props),
1380
+ }),
1381
+ () => {
1382
+ this.setTableAction('search');
1383
+ if (this.options.onSearchChange) {
1384
+ this.options.onSearchChange(this.state.searchText);
1385
+ }
1386
+ },
1387
+ );
1388
+ };
1389
+
1390
+ resetFilters = () => {
1391
+ this.setState(
1392
+ (prevState) => {
1393
+ const filterList = prevState.columns.map(() => []);
1394
+
1395
+ return {
1396
+ filterList: filterList,
1397
+ displayData: this.options.serverSide
1398
+ ? prevState.displayData
1399
+ : this.getDisplayData(
1400
+ prevState.columns,
1401
+ prevState.data,
1402
+ filterList,
1403
+ prevState.searchText,
1404
+ null,
1405
+ this.props,
1406
+ ),
1407
+ };
1408
+ },
1409
+ () => {
1410
+ this.setTableAction('resetFilters');
1411
+ if (this.options.onFilterChange) {
1412
+ this.options.onFilterChange(null, this.state.filterList, 'reset', null);
1413
+ }
1414
+ },
1415
+ );
1416
+ };
1417
+
1418
+ updateFilterByType = (filterList, index, value, type, customUpdate) => {
1419
+ const filterPos = filterList[index].findIndex((filter) => isEqual(filter, value));
1420
+
1421
+ switch (type) {
1422
+ case 'checkbox':
1423
+ filterPos >= 0 ? filterList[index].splice(filterPos, 1) : filterList[index].push(value);
1424
+ break;
1425
+ case 'chip':
1426
+ filterPos >= 0 ? filterList[index].splice(filterPos, 1) : filterList[index].push(value);
1427
+ break;
1428
+ case 'multiselect':
1429
+ filterList[index] = value === '' ? [] : value;
1430
+ break;
1431
+ case 'dropdown':
1432
+ filterList[index] = value;
1433
+ break;
1434
+ case 'custom':
1435
+ if (customUpdate) {
1436
+ filterList = customUpdate(filterList, filterPos, index);
1437
+ } else {
1438
+ filterList[index] = value;
1439
+ }
1440
+ break;
1441
+ default:
1442
+ filterList[index] = filterPos >= 0 || value === '' ? [] : [value];
1443
+ }
1444
+ };
1445
+
1446
+ filterUpdate = (index, value, column, type, customUpdate, next) => {
1447
+ this.setState(
1448
+ (prevState) => {
1449
+ const filterList = cloneDeep(prevState.filterList);
1450
+ this.updateFilterByType(filterList, index, value, type, customUpdate);
1451
+
1452
+ return {
1453
+ page: 0,
1454
+ filterList: filterList,
1455
+ displayData: this.options.serverSide
1456
+ ? prevState.displayData
1457
+ : this.getDisplayData(
1458
+ prevState.columns,
1459
+ prevState.data,
1460
+ filterList,
1461
+ prevState.searchText,
1462
+ null,
1463
+ this.props,
1464
+ ),
1465
+ previousSelectedRow: null,
1466
+ };
1467
+ },
1468
+ () => {
1469
+ this.setTableAction('filterChange');
1470
+ if (this.options.onFilterChange) {
1471
+ this.options.onFilterChange(column, this.state.filterList, type, index, this.state.displayData);
1472
+ }
1473
+ next && next(this.state.filterList);
1474
+ },
1475
+ );
1476
+ };
1477
+
1478
+ // Collapses or expands all expanded rows
1479
+ toggleAllExpandableRows = () => {
1480
+ let expandedRowsData = [...this.state.expandedRows.data];
1481
+ const { isRowExpandable } = this.options;
1482
+ let affecttedRows = [];
1483
+
1484
+ if (expandedRowsData.length > 0) {
1485
+ // collapse all
1486
+ for (let ii = expandedRowsData.length - 1; ii >= 0; ii--) {
1487
+ let item = expandedRowsData[ii];
1488
+ if (!isRowExpandable || (isRowExpandable && isRowExpandable(item.dataIndex, this.state.expandedRows))) {
1489
+ affecttedRows.push(expandedRowsData.splice(ii, 1));
1490
+ }
1491
+ }
1492
+ } else {
1493
+ // expand all
1494
+ for (let ii = 0; ii < this.state.data.length; ii++) {
1495
+ let item = this.state.data[ii];
1496
+ if (!isRowExpandable || (isRowExpandable && isRowExpandable(item.dataIndex, this.state.expandedRows))) {
1497
+ if (this.state.expandedRows.lookup[item.index] !== true) {
1498
+ let newItem = {
1499
+ index: ii,
1500
+ dataIndex: item.index,
1501
+ };
1502
+ expandedRowsData.push(newItem);
1503
+ affecttedRows.push(newItem);
1504
+ }
1505
+ }
1506
+ }
1507
+ }
1508
+
1509
+ this.setState(
1510
+ {
1511
+ expandedRows: {
1512
+ lookup: buildMap(expandedRowsData),
1513
+ data: expandedRowsData,
1514
+ },
1515
+ },
1516
+ () => {
1517
+ this.setTableAction('expandRow');
1518
+ if (this.options.onRowExpansionChange) {
1519
+ this.options.onRowExpansionChange(
1520
+ affecttedRows,
1521
+ this.state.expandedRows.data,
1522
+ this.state.expandedRows.data.map((item) => item.dataIndex),
1523
+ );
1524
+ }
1525
+ },
1526
+ );
1527
+ };
1528
+
1529
+ areAllRowsExpanded = () => {
1530
+ return this.state.expandedRows.data.length === this.state.data.length;
1531
+ };
1532
+
1533
+ updateColumnOrder = (columnOrder, columnIndex, newPosition) => {
1534
+ this.setState(
1535
+ (prevState) => {
1536
+ return {
1537
+ columnOrder,
1538
+ };
1539
+ },
1540
+ () => {
1541
+ this.setTableAction('columnOrderChange');
1542
+ if (this.options.onColumnOrderChange) {
1543
+ this.options.onColumnOrderChange(this.state.columnOrder, columnIndex, newPosition);
1544
+ }
1545
+ },
1546
+ );
1547
+ };
1548
+
1549
+ selectRowDelete = () => {
1550
+ const { selectedRows, data, filterList } = this.state;
1551
+
1552
+ const selectedMap = buildMap(selectedRows.data);
1553
+ const cleanRows = data.filter(({ index }) => !selectedMap[index]);
1554
+
1555
+ if (this.options.onRowsDelete) {
1556
+ if (
1557
+ this.options.onRowsDelete(
1558
+ selectedRows,
1559
+ cleanRows.map((ii) => ii.data),
1560
+ ) === false
1561
+ )
1562
+ return;
1563
+ }
1564
+
1565
+ this.setTableData(
1566
+ {
1567
+ columns: this.props.columns,
1568
+ data: cleanRows,
1569
+ options: {
1570
+ filterList: filterList,
1571
+ },
1572
+ },
1573
+ TABLE_LOAD.UPDATE,
1574
+ true,
1575
+ () => {
1576
+ this.setTableAction('rowDelete');
1577
+ },
1578
+ );
1579
+ };
1580
+
1581
+ toggleExpandRow = (row) => {
1582
+ const { dataIndex } = row;
1583
+ const { isRowExpandable } = this.options;
1584
+ let { expandedRows } = this.state;
1585
+ const expandedRowsData = [...expandedRows.data];
1586
+ let shouldCollapseExpandedRow = false;
1587
+ let hasRemovedRow = false;
1588
+ let removedRow = [];
1589
+
1590
+ for (var cIndex = 0; cIndex < expandedRowsData.length; cIndex++) {
1591
+ if (expandedRowsData[cIndex].dataIndex === dataIndex) {
1592
+ shouldCollapseExpandedRow = true;
1593
+ break;
1594
+ }
1595
+ }
1596
+
1597
+ if (shouldCollapseExpandedRow) {
1598
+ if ((isRowExpandable && isRowExpandable(dataIndex, expandedRows)) || !isRowExpandable) {
1599
+ removedRow = expandedRowsData.splice(cIndex, 1);
1600
+ hasRemovedRow = true;
1601
+ }
1602
+ } else {
1603
+ if (isRowExpandable && isRowExpandable(dataIndex, expandedRows)) expandedRowsData.push(row);
1604
+ else if (!isRowExpandable) expandedRowsData.push(row);
1605
+ }
1606
+
1607
+ this.setState(
1608
+ {
1609
+ curExpandedRows: hasRemovedRow ? removedRow : [row],
1610
+ expandedRows: {
1611
+ lookup: buildMap(expandedRowsData),
1612
+ data: expandedRowsData,
1613
+ },
1614
+ },
1615
+ () => {
1616
+ this.setTableAction('rowExpansionChange');
1617
+ if (this.options.onRowExpansionChange || this.options.onRowsExpand) {
1618
+ let expandCallback = this.options.onRowExpansionChange || this.options.onRowsExpand;
1619
+ expandCallback(this.state.curExpandedRows, this.state.expandedRows.data);
1620
+ }
1621
+ },
1622
+ );
1623
+ };
1624
+
1625
+ selectRowUpdate = (type, value, shiftAdjacentRows = []) => {
1626
+ // safety check
1627
+ const { selectableRows } = this.options;
1628
+ if (selectableRows === 'none') {
1629
+ return;
1630
+ }
1631
+
1632
+ if (type === 'head') {
1633
+ const { isRowSelectable } = this.options;
1634
+ this.setState(
1635
+ (prevState) => {
1636
+ const { displayData, selectedRows: prevSelectedRows } = prevState;
1637
+ const selectedRowsLen = prevState.selectedRows.data.length;
1638
+ let isDeselect =
1639
+ selectedRowsLen === displayData.length || (selectedRowsLen < displayData.length && selectedRowsLen > 0);
1640
+
1641
+ let selectedRows = displayData.reduce((arr, d, i) => {
1642
+ const selected = isRowSelectable ? isRowSelectable(displayData[i].dataIndex, prevSelectedRows) : true;
1643
+ selected && arr.push({ index: i, dataIndex: displayData[i].dataIndex });
1644
+ return arr;
1645
+ }, []);
1646
+
1647
+ let newRows = [...selectedRows];
1648
+ let selectedMap = buildMap(newRows);
1649
+
1650
+ // if the select toolbar is disabled, the rules are a little different
1651
+ if (this.options.selectToolbarPlacement === STP.NONE) {
1652
+ if (selectedRowsLen > displayData.length) {
1653
+ isDeselect = true;
1654
+ } else {
1655
+ for (let ii = 0; ii < displayData.length; ii++) {
1656
+ if (!selectedMap[displayData[ii].dataIndex]) {
1657
+ isDeselect = true;
1658
+ }
1659
+ }
1660
+ }
1661
+ }
1662
+
1663
+ if (isDeselect) {
1664
+ newRows = prevState.selectedRows.data.filter(({ dataIndex }) => !selectedMap[dataIndex]);
1665
+ selectedMap = buildMap(newRows);
1666
+ }
1667
+
1668
+ return {
1669
+ curSelectedRows: newRows,
1670
+ selectedRows: {
1671
+ data: newRows,
1672
+ lookup: selectedMap,
1673
+ },
1674
+ previousSelectedRow: null,
1675
+ };
1676
+ },
1677
+ () => {
1678
+ this.setTableAction('rowSelectionChange');
1679
+ if (this.options.onRowSelectionChange) {
1680
+ this.options.onRowSelectionChange(
1681
+ this.state.curSelectedRows,
1682
+ this.state.selectedRows.data,
1683
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1684
+ );
1685
+ } else if (this.options.onRowsSelect) {
1686
+ this.options.onRowsSelect(
1687
+ this.state.curSelectedRows,
1688
+ this.state.selectedRows.data,
1689
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1690
+ );
1691
+ }
1692
+ },
1693
+ );
1694
+ } else if (type === 'cell') {
1695
+ this.setState(
1696
+ (prevState) => {
1697
+ const { dataIndex } = value;
1698
+ let selectedRows = [...prevState.selectedRows.data];
1699
+ let rowPos = -1;
1700
+
1701
+ for (let cIndex = 0; cIndex < selectedRows.length; cIndex++) {
1702
+ if (selectedRows[cIndex].dataIndex === dataIndex) {
1703
+ rowPos = cIndex;
1704
+ break;
1705
+ }
1706
+ }
1707
+
1708
+ if (rowPos >= 0) {
1709
+ selectedRows.splice(rowPos, 1);
1710
+
1711
+ // handle rows affected by shift+click
1712
+ if (shiftAdjacentRows.length > 0) {
1713
+ let shiftAdjacentMap = buildMap(shiftAdjacentRows);
1714
+ for (let cIndex = selectedRows.length - 1; cIndex >= 0; cIndex--) {
1715
+ if (shiftAdjacentMap[selectedRows[cIndex].dataIndex]) {
1716
+ selectedRows.splice(cIndex, 1);
1717
+ }
1718
+ }
1719
+ }
1720
+ } else if (selectableRows === 'single') {
1721
+ selectedRows = [value];
1722
+ } else {
1723
+ // multiple
1724
+ selectedRows.push(value);
1725
+
1726
+ // handle rows affected by shift+click
1727
+ if (shiftAdjacentRows.length > 0) {
1728
+ let selectedMap = buildMap(selectedRows);
1729
+ shiftAdjacentRows.forEach((aRow) => {
1730
+ if (!selectedMap[aRow.dataIndex]) {
1731
+ selectedRows.push(aRow);
1732
+ }
1733
+ });
1734
+ }
1735
+ }
1736
+
1737
+ return {
1738
+ selectedRows: {
1739
+ lookup: buildMap(selectedRows),
1740
+ data: selectedRows,
1741
+ },
1742
+ previousSelectedRow: value,
1743
+ };
1744
+ },
1745
+ () => {
1746
+ this.setTableAction('rowSelectionChange');
1747
+ if (this.options.onRowSelectionChange) {
1748
+ this.options.onRowSelectionChange(
1749
+ [value],
1750
+ this.state.selectedRows.data,
1751
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1752
+ );
1753
+ } else if (this.options.onRowsSelect) {
1754
+ this.options.onRowsSelect(
1755
+ [value],
1756
+ this.state.selectedRows.data,
1757
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1758
+ );
1759
+ }
1760
+ },
1761
+ );
1762
+ } else if (type === 'custom') {
1763
+ const { displayData } = this.state;
1764
+
1765
+ const data = value.map((row) => ({ index: row, dataIndex: displayData[row].dataIndex }));
1766
+ const lookup = buildMap(data);
1767
+
1768
+ this.setState(
1769
+ {
1770
+ selectedRows: { data, lookup },
1771
+ previousSelectedRow: null,
1772
+ },
1773
+ () => {
1774
+ this.setTableAction('rowSelectionChange');
1775
+ if (this.options.onRowSelectionChange) {
1776
+ this.options.onRowSelectionChange(
1777
+ this.state.selectedRows.data,
1778
+ this.state.selectedRows.data,
1779
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1780
+ );
1781
+ } else if (this.options.onRowsSelect) {
1782
+ this.options.onRowsSelect(
1783
+ this.state.selectedRows.data,
1784
+ this.state.selectedRows.data,
1785
+ this.state.selectedRows.data.map((item) => item.dataIndex),
1786
+ );
1787
+ }
1788
+ },
1789
+ );
1790
+ }
1791
+ };
1792
+
1793
+ sortTable(data, col, order, columnSortCompare = null) {
1794
+ let hasCustomTableSort = this.options.customSort && !columnSortCompare;
1795
+ let meta = { selectedRows: this.state.selectedRows }; // meta for customSort
1796
+ let dataSrc = hasCustomTableSort
1797
+ ? this.options.customSort(data, col, order || (this.options.sortDescFirst ? 'desc' : 'asc'), meta)
1798
+ : data;
1799
+
1800
+ // reset the order by index
1801
+ let noSortData;
1802
+ if (order === 'none') {
1803
+ noSortData = data.reduce((r, i) => {
1804
+ r[i.index] = i;
1805
+ return r;
1806
+ }, []);
1807
+ }
1808
+
1809
+ let sortedData = dataSrc.map((row, sIndex) => ({
1810
+ data: row.data[col],
1811
+ rowData: row.data,
1812
+ position: sIndex,
1813
+ rowSelected: this.state.selectedRows.lookup[row.index] ? true : false,
1814
+ }));
1815
+
1816
+ if (!hasCustomTableSort) {
1817
+ const sortFn = columnSortCompare || sortCompare;
1818
+ sortedData.sort(sortFn(order));
1819
+ }
1820
+
1821
+ let tableData = [];
1822
+ let selectedRows = [];
1823
+
1824
+ for (let i = 0; i < sortedData.length; i++) {
1825
+ const row = sortedData[i];
1826
+ tableData.push(dataSrc[row.position]);
1827
+ if (row.rowSelected) {
1828
+ selectedRows.push({ index: i, dataIndex: dataSrc[row.position].index });
1829
+ }
1830
+ }
1831
+
1832
+ return {
1833
+ data: order === 'none' ? noSortData : tableData,
1834
+ selectedRows: {
1835
+ lookup: buildMap(selectedRows),
1836
+ data: selectedRows,
1837
+ },
1838
+ };
1839
+ }
1840
+
1841
+ render() {
1842
+ const {
1843
+ classes,
1844
+ className,
1845
+ title,
1846
+ components: {
1847
+ TableBody,
1848
+ TableFilterList,
1849
+ TableFooter,
1850
+ TableHead,
1851
+ TableResize,
1852
+ TableToolbar,
1853
+ TableToolbarSelect,
1854
+ DragDropBackend = HTML5Backend,
1855
+ },
1856
+ } = this.props;
1857
+ const {
1858
+ announceText,
1859
+ activeColumn,
1860
+ data,
1861
+ displayData,
1862
+ columns,
1863
+ page,
1864
+ filterData,
1865
+ filterList,
1866
+ selectedRows,
1867
+ previousSelectedRow,
1868
+ expandedRows,
1869
+ searchText,
1870
+ sortOrder,
1871
+ serverSideFilterList,
1872
+ columnOrder,
1873
+ } = this.state;
1874
+
1875
+ const TableBodyComponent = TableBody || DefaultTableBody;
1876
+ const TableFilterListComponent = TableFilterList || DefaultTableFilterList;
1877
+ const TableFooterComponent = TableFooter || DefaultTableFooter;
1878
+ const TableHeadComponent = TableHead || DefaultTableHead;
1879
+ const TableResizeComponent = TableResize || DefaultTableResize;
1880
+ const TableToolbarComponent = TableToolbar || DefaultTableToolbar;
1881
+ const TableToolbarSelectComponent = TableToolbarSelect || DefaultTableToolbarSelect;
1882
+
1883
+ const rowCount = this.state.count || displayData.length;
1884
+ const rowsPerPage = this.options.pagination ? this.state.rowsPerPage : displayData.length;
1885
+ const showToolbar = hasToolbarItem(this.options, title);
1886
+ const columnNames = columns.map((column) => ({
1887
+ name: column.name,
1888
+ filterType: column.filterType || this.options.filterType,
1889
+ }));
1890
+ const responsiveOption = this.options.responsive;
1891
+ let paperClasses = `${classes.paper} ${className}`;
1892
+ let maxHeight = this.options.tableBodyMaxHeight;
1893
+ let responsiveClass;
1894
+
1895
+ switch (responsiveOption) {
1896
+ // deprecated
1897
+ case 'scroll':
1898
+ responsiveClass = classes.responsiveScroll;
1899
+ maxHeight = '499px';
1900
+ break;
1901
+ // deprecated
1902
+ case 'scrollMaxHeight':
1903
+ responsiveClass = classes.responsiveScrollMaxHeight;
1904
+ maxHeight = '499px';
1905
+ break;
1906
+ // deprecated
1907
+ case 'scrollFullHeight':
1908
+ responsiveClass = classes.responsiveScrollFullHeight;
1909
+ maxHeight = 'none';
1910
+ break;
1911
+ // deprecated
1912
+ case 'scrollFullHeightFullWidth':
1913
+ responsiveClass = classes.responsiveScrollFullHeight;
1914
+ paperClasses = `${classes.paperResponsiveScrollFullHeightFullWidth} ${className}`;
1915
+ break;
1916
+ // deprecated
1917
+ case 'stacked':
1918
+ responsiveClass = classes.responsiveStacked;
1919
+ maxHeight = 'none';
1920
+ break;
1921
+ // deprecated
1922
+ case 'stackedFullWidth':
1923
+ responsiveClass = classes.responsiveStackedFullWidth;
1924
+ paperClasses = `${classes.paperResponsiveScrollFullHeightFullWidth} ${className}`;
1925
+ maxHeight = 'none';
1926
+ break;
1927
+
1928
+ default:
1929
+ responsiveClass = classes.responsiveBase;
1930
+ break;
1931
+ }
1932
+
1933
+ var tableHeightVal = {};
1934
+ if (maxHeight) {
1935
+ tableHeightVal.maxHeight = maxHeight;
1936
+ }
1937
+ if (this.options.tableBodyHeight) {
1938
+ tableHeightVal.height = this.options.tableBodyHeight;
1939
+ }
1940
+
1941
+ const tableProps = this.options.setTableProps ? this.options.setTableProps() || {} : {};
1942
+ const tableClassNames = clsx(classes.tableRoot, tableProps.className);
1943
+ delete tableProps.className; // remove className from props to avoid the className being applied twice
1944
+
1945
+ const dndProps = {};
1946
+ if (typeof window !== 'undefined') {
1947
+ dndProps.context = window;
1948
+ }
1949
+
1950
+ return (
1951
+ <Paper elevation={this.options.elevation} ref={this.tableContent} className={paperClasses}>
1952
+ {(this.options.selectToolbarPlacement === STP.ALWAYS ||
1953
+ (selectedRows.data.length > 0 && this.options.selectToolbarPlacement !== STP.NONE)) && (
1954
+ <TableToolbarSelectComponent
1955
+ options={this.options}
1956
+ selectedRows={selectedRows}
1957
+ onRowsDelete={this.selectRowDelete}
1958
+ displayData={displayData}
1959
+ selectRowUpdate={this.selectRowUpdate}
1960
+ components={this.props.components}
1961
+ />
1962
+ )}
1963
+ {(selectedRows.data.length === 0 ||
1964
+ [STP.ABOVE, STP.NONE].indexOf(this.options.selectToolbarPlacement) !== -1) &&
1965
+ showToolbar && (
1966
+ <TableToolbarComponent
1967
+ columns={columns}
1968
+ columnOrder={columnOrder}
1969
+ displayData={displayData}
1970
+ data={data}
1971
+ filterData={filterData}
1972
+ filterList={filterList}
1973
+ filterUpdate={this.filterUpdate}
1974
+ updateFilterByType={this.updateFilterByType}
1975
+ options={this.options}
1976
+ resetFilters={this.resetFilters}
1977
+ searchText={searchText}
1978
+ searchTextUpdate={this.searchTextUpdate}
1979
+ searchClose={this.searchClose}
1980
+ tableRef={this.getTableContentRef}
1981
+ title={title}
1982
+ toggleViewColumn={this.toggleViewColumn}
1983
+ updateColumns={this.updateColumns}
1984
+ setTableAction={this.setTableAction}
1985
+ components={this.props.components}
1986
+ />
1987
+ )}
1988
+ <TableFilterListComponent
1989
+ options={this.options}
1990
+ serverSideFilterList={this.props.options.serverSideFilterList}
1991
+ filterListRenderers={columns.map((c) => {
1992
+ if (c.customFilterListOptions && c.customFilterListOptions.render) return c.customFilterListOptions.render;
1993
+ // DEPRECATED: This option is being replaced with customFilterListOptions.render
1994
+ if (c.customFilterListRender) return c.customFilterListRender;
1995
+
1996
+ return (f) => f;
1997
+ })}
1998
+ customFilterListUpdate={columns.map((c) => {
1999
+ return c.customFilterListOptions && c.customFilterListOptions.update
2000
+ ? c.customFilterListOptions.update
2001
+ : null;
2002
+ })}
2003
+ filterList={filterList}
2004
+ filterUpdate={this.filterUpdate}
2005
+ columnNames={columnNames}
2006
+ />
2007
+ <div style={{ position: 'relative', ...tableHeightVal }} className={responsiveClass}>
2008
+ {(this.options.resizableColumns === true ||
2009
+ (this.options.resizableColumns && this.options.resizableColumns.enabled)) && (
2010
+ <TableResizeComponent
2011
+ key={rowCount}
2012
+ columnOrder={columnOrder}
2013
+ updateDividers={(fn) => (this.updateDividers = fn)}
2014
+ setResizeable={(fn) => (this.setHeadResizeable = fn)}
2015
+ options={this.props.options}
2016
+ tableId={this.options.tableId}
2017
+ />
2018
+ )}
2019
+ {(() => {
2020
+ const components = (
2021
+ <MuiTable
2022
+ ref={(el) => (this.tableRef = el)}
2023
+ tabIndex={'0'}
2024
+ role={'grid'}
2025
+ className={tableClassNames}
2026
+ {...tableProps}>
2027
+ <caption className={classes.caption}>{title}</caption>
2028
+ <TableHeadComponent
2029
+ columns={columns}
2030
+ activeColumn={activeColumn}
2031
+ data={displayData}
2032
+ count={rowCount}
2033
+ page={page}
2034
+ rowsPerPage={rowsPerPage}
2035
+ selectedRows={selectedRows}
2036
+ selectRowUpdate={this.selectRowUpdate}
2037
+ toggleSort={this.toggleSortColumn}
2038
+ setCellRef={this.setHeadCellRef}
2039
+ expandedRows={expandedRows}
2040
+ areAllRowsExpanded={this.areAllRowsExpanded}
2041
+ toggleAllExpandableRows={this.toggleAllExpandableRows}
2042
+ options={this.options}
2043
+ sortOrder={sortOrder}
2044
+ columnOrder={columnOrder}
2045
+ updateColumnOrder={this.updateColumnOrder}
2046
+ draggableHeadCellRefs={this.draggableHeadCellRefs}
2047
+ tableRef={this.getTableContentRef}
2048
+ tableId={this.options.tableId}
2049
+ timers={this.timers}
2050
+ components={this.props.components}
2051
+ />
2052
+ <TableBodyComponent
2053
+ data={displayData}
2054
+ count={rowCount}
2055
+ columns={columns}
2056
+ page={page}
2057
+ rowsPerPage={rowsPerPage}
2058
+ selectedRows={selectedRows}
2059
+ selectRowUpdate={this.selectRowUpdate}
2060
+ previousSelectedRow={previousSelectedRow}
2061
+ expandedRows={expandedRows}
2062
+ toggleExpandRow={this.toggleExpandRow}
2063
+ options={this.options}
2064
+ columnOrder={columnOrder}
2065
+ filterList={filterList}
2066
+ components={this.props.components}
2067
+ tableId={this.options.tableId}
2068
+ />
2069
+ {this.options.customTableBodyFooterRender
2070
+ ? this.options.customTableBodyFooterRender({
2071
+ data: displayData,
2072
+ count: rowCount,
2073
+ columns,
2074
+ selectedRows,
2075
+ selectableRows: this.options.selectableRows,
2076
+ })
2077
+ : null}
2078
+ </MuiTable>
2079
+ );
2080
+ if (DragDropBackend) {
2081
+ return (
2082
+ <DndProvider backend={DragDropBackend} {...dndProps}>
2083
+ {components}
2084
+ </DndProvider>
2085
+ );
2086
+ }
2087
+
2088
+ return components;
2089
+ })()}
2090
+ </div>
2091
+ <TableFooterComponent
2092
+ options={this.options}
2093
+ page={page}
2094
+ rowCount={rowCount}
2095
+ rowsPerPage={rowsPerPage}
2096
+ changeRowsPerPage={this.changeRowsPerPage}
2097
+ changePage={this.changePage}
2098
+ />
2099
+ <div className={classes.liveAnnounce} aria-live={'polite'}>
2100
+ {announceText}
2101
+ </div>
2102
+ </Paper>
2103
+ );
2104
+ }
2105
+ }
2106
+
2107
+ export default withStyles(MUIDataTable, defaultTableStyles, { name: 'MUIDataTable' });