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.
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/package.json +115 -0
- package/src/MUIDataTable.js +2107 -0
- package/src/components/ExpandButton.js +39 -0
- package/src/components/JumpToPage.js +96 -0
- package/src/components/Popover.js +89 -0
- package/src/components/TableBody.js +338 -0
- package/src/components/TableBodyCell.js +276 -0
- package/src/components/TableBodyRow.js +98 -0
- package/src/components/TableFilter.js +421 -0
- package/src/components/TableFilterList.js +136 -0
- package/src/components/TableFilterListItem.js +20 -0
- package/src/components/TableFooter.js +74 -0
- package/src/components/TableHead.js +171 -0
- package/src/components/TableHeadCell.js +320 -0
- package/src/components/TableHeadRow.js +29 -0
- package/src/components/TablePagination.js +152 -0
- package/src/components/TableResize.js +288 -0
- package/src/components/TableSearch.js +89 -0
- package/src/components/TableSelectCell.js +163 -0
- package/src/components/TableToolbar.js +630 -0
- package/src/components/TableToolbarSelect.js +91 -0
- package/src/components/TableViewCol.js +101 -0
- package/src/hooks/useColumnDrop.js +186 -0
- package/src/index.js +44 -0
- package/src/localStorage/index.js +2 -0
- package/src/localStorage/load.js +10 -0
- package/src/localStorage/save.js +5 -0
- package/src/plug-ins/DebounceSearchRender.js +118 -0
- package/src/textLabels.js +39 -0
- package/src/utils.js +150 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Paper } from '@mui/material';
|
|
4
|
+
import { IconButton } from '@mui/material';
|
|
5
|
+
import { Typography } from '@mui/material';
|
|
6
|
+
import { Delete as DeleteIcon } from '@mui/icons-material';
|
|
7
|
+
import { withStyles } from 'tss-react/mui';
|
|
8
|
+
import MuiTooltip from '@mui/material/Tooltip';
|
|
9
|
+
|
|
10
|
+
const defaultToolbarSelectStyles = theme => ({
|
|
11
|
+
root: {
|
|
12
|
+
backgroundColor: theme.palette.background.default,
|
|
13
|
+
flex: '1 1 100%',
|
|
14
|
+
display: 'flex',
|
|
15
|
+
position: 'relative',
|
|
16
|
+
zIndex: 120,
|
|
17
|
+
justifyContent: 'space-between',
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
paddingTop: typeof theme.spacing === 'function' ? theme.spacing(1) : theme.spacing.unit,
|
|
20
|
+
paddingBottom: typeof theme.spacing === 'function' ? theme.spacing(1) : theme.spacing.unit,
|
|
21
|
+
'@media print': {
|
|
22
|
+
display: 'none',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
title: {
|
|
26
|
+
paddingLeft: '26px',
|
|
27
|
+
},
|
|
28
|
+
iconButton: {
|
|
29
|
+
marginRight: '24px',
|
|
30
|
+
},
|
|
31
|
+
deleteIcon: {},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
class TableToolbarSelect extends React.Component {
|
|
35
|
+
static propTypes = {
|
|
36
|
+
/** Options used to describe table */
|
|
37
|
+
options: PropTypes.object.isRequired,
|
|
38
|
+
/** Current row selected or not */
|
|
39
|
+
rowSelected: PropTypes.bool,
|
|
40
|
+
/** Callback to trigger selected rows delete */
|
|
41
|
+
onRowsDelete: PropTypes.func,
|
|
42
|
+
/** Extend the style applied to components */
|
|
43
|
+
classes: PropTypes.object,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {number[]} selectedRows Array of rows indexes that are selected, e.g. [0, 2] will select first and third rows in table
|
|
48
|
+
*/
|
|
49
|
+
handleCustomSelectedRows = selectedRows => {
|
|
50
|
+
if (!Array.isArray(selectedRows)) {
|
|
51
|
+
throw new TypeError(`"selectedRows" must be an "array", but it's "${typeof selectedRows}"`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (selectedRows.some(row => typeof row !== 'number')) {
|
|
55
|
+
throw new TypeError(`Array "selectedRows" must contain only numbers`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { options } = this.props;
|
|
59
|
+
if (selectedRows.length > 1 && options.selectableRows === 'single') {
|
|
60
|
+
throw new Error('Can not select more than one row when "selectableRows" is "single"');
|
|
61
|
+
}
|
|
62
|
+
this.props.selectRowUpdate('custom', selectedRows);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
render() {
|
|
66
|
+
const { classes, onRowsDelete, selectedRows, options, displayData, components = {} } = this.props;
|
|
67
|
+
const textLabels = options.textLabels.selectedRows;
|
|
68
|
+
const Tooltip = components.Tooltip || MuiTooltip;
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Paper className={classes.root}>
|
|
72
|
+
<div>
|
|
73
|
+
<Typography variant="subtitle1" className={classes.title}>
|
|
74
|
+
{selectedRows.data.length} {textLabels.text}
|
|
75
|
+
</Typography>
|
|
76
|
+
</div>
|
|
77
|
+
{options.customToolbarSelect ? (
|
|
78
|
+
options.customToolbarSelect(selectedRows, displayData, this.handleCustomSelectedRows)
|
|
79
|
+
) : (
|
|
80
|
+
<Tooltip title={textLabels.delete}>
|
|
81
|
+
<IconButton className={classes.iconButton} onClick={onRowsDelete} aria-label={textLabels.deleteAria}>
|
|
82
|
+
<DeleteIcon className={classes.deleteIcon} />
|
|
83
|
+
</IconButton>
|
|
84
|
+
</Tooltip>
|
|
85
|
+
)}
|
|
86
|
+
</Paper>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default withStyles(TableToolbarSelect, defaultToolbarSelectStyles, { name: 'MUIDataTableToolbarSelect' });
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Checkbox } from '@mui/material';
|
|
4
|
+
import { Typography } from '@mui/material';
|
|
5
|
+
import { FormControl } from '@mui/material';
|
|
6
|
+
import { FormGroup } from '@mui/material';
|
|
7
|
+
import { FormControlLabel } from '@mui/material';
|
|
8
|
+
import { makeStyles } from 'tss-react/mui';
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles({ name: 'MUIDataTableViewCol' })(theme => ({
|
|
11
|
+
root: {
|
|
12
|
+
padding: '16px 24px 16px 24px',
|
|
13
|
+
fontFamily: 'Roboto',
|
|
14
|
+
},
|
|
15
|
+
title: {
|
|
16
|
+
marginLeft: '-7px',
|
|
17
|
+
marginRight: '24px',
|
|
18
|
+
fontSize: '14px',
|
|
19
|
+
color: theme.palette.text.secondary,
|
|
20
|
+
textAlign: 'left',
|
|
21
|
+
fontWeight: 500,
|
|
22
|
+
},
|
|
23
|
+
formGroup: {
|
|
24
|
+
marginTop: '8px',
|
|
25
|
+
},
|
|
26
|
+
formControl: {},
|
|
27
|
+
checkbox: {
|
|
28
|
+
padding: '0px',
|
|
29
|
+
width: '32px',
|
|
30
|
+
height: '32px',
|
|
31
|
+
},
|
|
32
|
+
checkboxRoot: {},
|
|
33
|
+
checked: {},
|
|
34
|
+
label: {
|
|
35
|
+
fontSize: '15px',
|
|
36
|
+
marginLeft: '8px',
|
|
37
|
+
color: theme.palette.text.primary,
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
const TableViewCol = ({ columns, options, components = {}, onColumnUpdate, updateColumns }) => {
|
|
42
|
+
const { classes } = useStyles();
|
|
43
|
+
const textLabels = options.textLabels.viewColumns;
|
|
44
|
+
const CheckboxComponent = components.Checkbox || Checkbox;
|
|
45
|
+
|
|
46
|
+
const handleColChange = index => {
|
|
47
|
+
onColumnUpdate(index);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<FormControl component={'fieldset'} className={classes.root} aria-label={textLabels.titleAria}>
|
|
52
|
+
<Typography variant="caption" className={classes.title}>
|
|
53
|
+
{textLabels.title}
|
|
54
|
+
</Typography>
|
|
55
|
+
<FormGroup className={classes.formGroup}>
|
|
56
|
+
{columns.map((column, index) => {
|
|
57
|
+
return (
|
|
58
|
+
column.display !== 'excluded' &&
|
|
59
|
+
column.viewColumns !== false && (
|
|
60
|
+
<FormControlLabel
|
|
61
|
+
key={index}
|
|
62
|
+
classes={{
|
|
63
|
+
root: classes.formControl,
|
|
64
|
+
label: classes.label,
|
|
65
|
+
}}
|
|
66
|
+
control={
|
|
67
|
+
<CheckboxComponent
|
|
68
|
+
color="primary"
|
|
69
|
+
data-description="table-view-col"
|
|
70
|
+
className={classes.checkbox}
|
|
71
|
+
classes={{
|
|
72
|
+
root: classes.checkboxRoot,
|
|
73
|
+
checked: classes.checked,
|
|
74
|
+
}}
|
|
75
|
+
onChange={() => handleColChange(index)}
|
|
76
|
+
checked={column.display === 'true'}
|
|
77
|
+
value={column.name}
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
80
|
+
label={column.label}
|
|
81
|
+
/>
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
})}
|
|
85
|
+
</FormGroup>
|
|
86
|
+
</FormControl>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
TableViewCol.propTypes = {
|
|
91
|
+
/** Columns used to describe table */
|
|
92
|
+
columns: PropTypes.array.isRequired,
|
|
93
|
+
/** Options used to describe table */
|
|
94
|
+
options: PropTypes.object.isRequired,
|
|
95
|
+
/** Callback to trigger View column update */
|
|
96
|
+
onColumnUpdate: PropTypes.func,
|
|
97
|
+
/** Extend the style applied to components */
|
|
98
|
+
classes: PropTypes.object,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default TableViewCol;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This hook handles the dragging and dropping effects that occur for columns.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useDrop } from 'react-dnd';
|
|
6
|
+
|
|
7
|
+
const getColModel = (headCellRefs, columnOrder, columns) => {
|
|
8
|
+
let colModel = [];
|
|
9
|
+
let leftMostCell = headCellRefs[0] ? headCellRefs[0] : null; // left most cell is the select cell, if it exists
|
|
10
|
+
|
|
11
|
+
if (leftMostCell === null) {
|
|
12
|
+
leftMostCell = { offsetLeft: Infinity };
|
|
13
|
+
let headCells = Object.entries(headCellRefs);
|
|
14
|
+
headCells.forEach(([key, item], idx) => {
|
|
15
|
+
if (item && item.offsetLeft < leftMostCell.offsetLeft) {
|
|
16
|
+
leftMostCell = item;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (leftMostCell.offsetLeft === Infinity) {
|
|
21
|
+
leftMostCell = { offsetParent: 0, offsetWidth: 0, offsetLeft: 0 };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let ii = 0,
|
|
26
|
+
parentOffsetLeft = 0,
|
|
27
|
+
offsetParent = leftMostCell.offsetParent;
|
|
28
|
+
while (offsetParent) {
|
|
29
|
+
parentOffsetLeft = parentOffsetLeft + (offsetParent.offsetLeft || 0) - (offsetParent.scrollLeft || 0);
|
|
30
|
+
offsetParent = offsetParent.offsetParent;
|
|
31
|
+
ii++;
|
|
32
|
+
if (ii > 1000) break;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// if the select cell is present, make sure it is apart of the column model
|
|
36
|
+
if (headCellRefs[0]) {
|
|
37
|
+
colModel[0] = {
|
|
38
|
+
left: parentOffsetLeft + leftMostCell.offsetLeft,
|
|
39
|
+
width: leftMostCell.offsetWidth,
|
|
40
|
+
columnIndex: null,
|
|
41
|
+
ref: leftMostCell,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
columnOrder.forEach((colIdx, idx) => {
|
|
46
|
+
let col = headCellRefs[colIdx + 1];
|
|
47
|
+
let cmIndx = colModel.length - 1;
|
|
48
|
+
if (!(columns[colIdx] && columns[colIdx].display !== 'true')) {
|
|
49
|
+
let prevLeft =
|
|
50
|
+
cmIndx !== -1 ? colModel[cmIndx].left + colModel[cmIndx].width : parentOffsetLeft + leftMostCell.offsetLeft;
|
|
51
|
+
colModel.push({
|
|
52
|
+
left: prevLeft,
|
|
53
|
+
width: col.offsetWidth,
|
|
54
|
+
columnIndex: colIdx,
|
|
55
|
+
ref: col,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return colModel;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const reorderColumns = (prevColumnOrder, columnIndex, newPosition) => {
|
|
64
|
+
let columnOrder = prevColumnOrder.slice();
|
|
65
|
+
let srcIndex = columnOrder.indexOf(columnIndex);
|
|
66
|
+
let targetIndex = columnOrder.indexOf(newPosition);
|
|
67
|
+
|
|
68
|
+
if (srcIndex !== -1 && targetIndex !== -1) {
|
|
69
|
+
let newItem = columnOrder[srcIndex];
|
|
70
|
+
columnOrder = [...columnOrder.slice(0, srcIndex), ...columnOrder.slice(srcIndex + 1)];
|
|
71
|
+
columnOrder = [...columnOrder.slice(0, targetIndex), newItem, ...columnOrder.slice(targetIndex)];
|
|
72
|
+
}
|
|
73
|
+
return columnOrder;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const handleHover = (opts) => {
|
|
77
|
+
const {
|
|
78
|
+
item,
|
|
79
|
+
mon,
|
|
80
|
+
index,
|
|
81
|
+
headCellRefs,
|
|
82
|
+
updateColumnOrder,
|
|
83
|
+
columnOrder,
|
|
84
|
+
transitionTime = 300,
|
|
85
|
+
tableRef,
|
|
86
|
+
tableId,
|
|
87
|
+
timers,
|
|
88
|
+
columns,
|
|
89
|
+
} = opts;
|
|
90
|
+
|
|
91
|
+
let hoverIdx = mon.getItem().colIndex;
|
|
92
|
+
|
|
93
|
+
if (headCellRefs !== mon.getItem().headCellRefs) return;
|
|
94
|
+
|
|
95
|
+
if (hoverIdx !== index) {
|
|
96
|
+
let reorderedCols = reorderColumns(columnOrder, mon.getItem().colIndex, index);
|
|
97
|
+
let newColModel = getColModel(headCellRefs, reorderedCols, columns);
|
|
98
|
+
|
|
99
|
+
let newX = mon.getClientOffset().x;
|
|
100
|
+
let modelIdx = -1;
|
|
101
|
+
for (let ii = 0; ii < newColModel.length; ii++) {
|
|
102
|
+
if (newX > newColModel[ii].left && newX < newColModel[ii].left + newColModel[ii].width) {
|
|
103
|
+
modelIdx = newColModel[ii].columnIndex;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (modelIdx === mon.getItem().colIndex) {
|
|
109
|
+
clearTimeout(timers.columnShift);
|
|
110
|
+
|
|
111
|
+
let curColModel = getColModel(headCellRefs, columnOrder, columns);
|
|
112
|
+
|
|
113
|
+
let transitions = [];
|
|
114
|
+
newColModel.forEach((item) => {
|
|
115
|
+
transitions[item.columnIndex] = item.left;
|
|
116
|
+
});
|
|
117
|
+
curColModel.forEach((item) => {
|
|
118
|
+
transitions[item.columnIndex] = transitions[item.columnIndex] - item.left;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
for (let idx = 1; idx < columnOrder.length; idx++) {
|
|
122
|
+
let colIndex = columnOrder[idx];
|
|
123
|
+
if (columns[colIndex] && columns[colIndex].display !== 'true') {
|
|
124
|
+
// skip
|
|
125
|
+
} else {
|
|
126
|
+
if (headCellRefs[idx]) headCellRefs[idx].style.transition = '280ms';
|
|
127
|
+
if (headCellRefs[idx]) headCellRefs[idx].style.transform = 'translateX(' + transitions[idx - 1] + 'px)';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let allElms = [];
|
|
132
|
+
let dividers = [];
|
|
133
|
+
for (let ii = 0; ii < columnOrder.length; ii++) {
|
|
134
|
+
let elms = tableRef
|
|
135
|
+
? tableRef.querySelectorAll('[data-colindex="' + ii + '"][data-tableid="' + tableId + '"]')
|
|
136
|
+
: [];
|
|
137
|
+
for (let jj = 0; jj < elms.length; jj++) {
|
|
138
|
+
elms[jj].style.transition = transitionTime + 'ms';
|
|
139
|
+
elms[jj].style.transform = 'translateX(' + transitions[ii] + 'px)';
|
|
140
|
+
allElms.push(elms[jj]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let divider = tableRef
|
|
144
|
+
? tableRef.querySelectorAll('[data-divider-index="' + (ii + 1) + '"][data-tableid="' + tableId + '"]')
|
|
145
|
+
: [];
|
|
146
|
+
for (let jj = 0; jj < divider.length; jj++) {
|
|
147
|
+
divider[jj].style.transition = transitionTime + 'ms';
|
|
148
|
+
divider[jj].style.transform = 'translateX(' + transitions[columnOrder[ii]] + 'px)';
|
|
149
|
+
dividers.push(divider[jj]);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let newColIndex = mon.getItem().colIndex;
|
|
154
|
+
timers.columnShift = setTimeout(() => {
|
|
155
|
+
allElms.forEach((item) => {
|
|
156
|
+
item.style.transition = '0s';
|
|
157
|
+
item.style.transform = 'translateX(0)';
|
|
158
|
+
});
|
|
159
|
+
dividers.forEach((item) => {
|
|
160
|
+
item.style.transition = '0s';
|
|
161
|
+
item.style.transform = 'translateX(0)';
|
|
162
|
+
});
|
|
163
|
+
updateColumnOrder(reorderedCols, newColIndex, index);
|
|
164
|
+
}, transitionTime);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const useColumnDrop = (opts) => {
|
|
170
|
+
const [{ isOver, canDrop }, drop] = useDrop({
|
|
171
|
+
accept: 'HEADER',
|
|
172
|
+
drop: (item, mon) => {
|
|
173
|
+
// Handle drop logic here if needed
|
|
174
|
+
},
|
|
175
|
+
hover: (item, mon) => handleHover(Object.assign({}, opts, { item, mon })),
|
|
176
|
+
collect: (mon) => ({
|
|
177
|
+
isOver: !!mon.isOver(),
|
|
178
|
+
canDrop: !!mon.canDrop(),
|
|
179
|
+
}),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
return [drop];
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export { getColModel, reorderColumns, handleHover };
|
|
186
|
+
export default useColumnDrop;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import MUIDataTable from './MUIDataTable';
|
|
2
|
+
import Popover from './components/Popover';
|
|
3
|
+
import TableBodyCell from './components/TableBodyCell';
|
|
4
|
+
import TableBody from './components/TableBody';
|
|
5
|
+
import TableBodyRow from './components/TableBodyRow';
|
|
6
|
+
import TableFilter from './components/TableFilter';
|
|
7
|
+
import TableFilterList from './components/TableFilterList';
|
|
8
|
+
import TableFooter from './components/TableFooter';
|
|
9
|
+
import TableHeadCell from './components/TableHeadCell';
|
|
10
|
+
import TableHead from './components/TableHead';
|
|
11
|
+
import TableHeadRow from './components/TableHeadRow';
|
|
12
|
+
import TablePagination from './components/TablePagination';
|
|
13
|
+
import TableResize from './components/TableResize';
|
|
14
|
+
import TableSearch from './components/TableSearch';
|
|
15
|
+
import TableSelectCell from './components/TableSelectCell';
|
|
16
|
+
import TableToolbar from './components/TableToolbar';
|
|
17
|
+
import TableToolbarSelect from './components/TableToolbarSelect';
|
|
18
|
+
import TableViewCol from './components/TableViewCol';
|
|
19
|
+
import ExpandButton from './components/ExpandButton';
|
|
20
|
+
import { debounceSearchRender, DebounceTableSearch } from './plug-ins/DebounceSearchRender';
|
|
21
|
+
|
|
22
|
+
export default MUIDataTable;
|
|
23
|
+
export {
|
|
24
|
+
Popover,
|
|
25
|
+
TableBodyCell,
|
|
26
|
+
TableBody,
|
|
27
|
+
TableBodyRow,
|
|
28
|
+
TableFilter,
|
|
29
|
+
TableFilterList,
|
|
30
|
+
TableFooter,
|
|
31
|
+
TableHeadCell,
|
|
32
|
+
TableHead,
|
|
33
|
+
TableHeadRow,
|
|
34
|
+
TablePagination,
|
|
35
|
+
TableResize,
|
|
36
|
+
TableSearch,
|
|
37
|
+
TableSelectCell,
|
|
38
|
+
TableToolbar,
|
|
39
|
+
TableToolbarSelect,
|
|
40
|
+
TableViewCol,
|
|
41
|
+
ExpandButton,
|
|
42
|
+
debounceSearchRender,
|
|
43
|
+
DebounceTableSearch,
|
|
44
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
2
|
+
|
|
3
|
+
export const load = storageKey => {
|
|
4
|
+
if (isBrowser) {
|
|
5
|
+
return JSON.parse(window.localStorage.getItem(storageKey));
|
|
6
|
+
} else if (storageKey !== undefined) {
|
|
7
|
+
console.warn('storageKey support only on browser');
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Grow } from '@mui/material';
|
|
3
|
+
import { TextField } from '@mui/material';
|
|
4
|
+
import { Search as SearchIcon } from '@mui/icons-material';
|
|
5
|
+
import { IconButton } from '@mui/material';
|
|
6
|
+
import { Clear as ClearIcon } from '@mui/icons-material';
|
|
7
|
+
import { withStyles } from 'tss-react/mui';
|
|
8
|
+
|
|
9
|
+
function debounce(func, wait, immediate) {
|
|
10
|
+
var timeout;
|
|
11
|
+
return function () {
|
|
12
|
+
var context = this,
|
|
13
|
+
args = arguments;
|
|
14
|
+
var later = function () {
|
|
15
|
+
timeout = null;
|
|
16
|
+
if (!immediate) func.apply(context, args);
|
|
17
|
+
};
|
|
18
|
+
var callNow = immediate && !timeout;
|
|
19
|
+
clearTimeout(timeout);
|
|
20
|
+
timeout = setTimeout(later, wait);
|
|
21
|
+
if (callNow) func.apply(context, args);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const defaultStyles = (theme) => ({
|
|
26
|
+
main: {
|
|
27
|
+
display: 'flex',
|
|
28
|
+
flex: '1 0 auto',
|
|
29
|
+
alignItems: 'center',
|
|
30
|
+
},
|
|
31
|
+
searchIcon: {
|
|
32
|
+
color: theme.palette.text.secondary,
|
|
33
|
+
marginRight: '8px',
|
|
34
|
+
},
|
|
35
|
+
searchText: {
|
|
36
|
+
flex: '0.8 0',
|
|
37
|
+
},
|
|
38
|
+
clearIcon: {
|
|
39
|
+
'&:hover': {
|
|
40
|
+
color: theme.palette.error.main,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
class _DebounceTableSearch extends React.Component {
|
|
46
|
+
handleTextChangeWrapper = (debouncedSearch) => {
|
|
47
|
+
return function (event) {
|
|
48
|
+
debouncedSearch(event.target.value);
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
componentDidMount() {
|
|
53
|
+
document.addEventListener('keydown', this.onKeyDown, false);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
componentWillUnmount() {
|
|
57
|
+
document.removeEventListener('keydown', this.onKeyDown, false);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
onKeyDown = (event) => {
|
|
61
|
+
if (event.keyCode === 27) {
|
|
62
|
+
this.props.onHide();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
render() {
|
|
67
|
+
const { classes, options, onHide, searchText, debounceWait } = this.props;
|
|
68
|
+
|
|
69
|
+
const debouncedSearch = debounce((value) => {
|
|
70
|
+
this.props.onSearch(value);
|
|
71
|
+
}, debounceWait);
|
|
72
|
+
|
|
73
|
+
const clearIconVisibility = options.searchAlwaysOpen ? 'hidden' : 'visible';
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Grow appear in={true} timeout={300}>
|
|
77
|
+
<div className={classes.main}>
|
|
78
|
+
<SearchIcon className={classes.searchIcon} />
|
|
79
|
+
<TextField
|
|
80
|
+
variant={'standard'}
|
|
81
|
+
className={classes.searchText}
|
|
82
|
+
autoFocus={true}
|
|
83
|
+
InputProps={{
|
|
84
|
+
'data-test-id': options.textLabels.toolbar.search,
|
|
85
|
+
'aria-label': options.textLabels.toolbar.search,
|
|
86
|
+
}}
|
|
87
|
+
defaultValue={searchText ?? ''}
|
|
88
|
+
onChange={this.handleTextChangeWrapper(debouncedSearch)}
|
|
89
|
+
fullWidth={true}
|
|
90
|
+
inputRef={(el) => (this.searchField = el)}
|
|
91
|
+
placeholder={options.searchPlaceholder}
|
|
92
|
+
{...(options.searchProps ? options.searchProps : {})}
|
|
93
|
+
/>
|
|
94
|
+
<IconButton className={classes.clearIcon} style={{ visibility: clearIconVisibility }} onClick={onHide}>
|
|
95
|
+
<ClearIcon />
|
|
96
|
+
</IconButton>
|
|
97
|
+
</div>
|
|
98
|
+
</Grow>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var DebounceTableSearch = withStyles(_DebounceTableSearch, defaultStyles, { name: 'MUIDataTableSearch' });
|
|
104
|
+
export { DebounceTableSearch };
|
|
105
|
+
|
|
106
|
+
export function debounceSearchRender(debounceWait = 200) {
|
|
107
|
+
return (searchText, handleSearch, hideSearch, options) => {
|
|
108
|
+
return (
|
|
109
|
+
<DebounceTableSearch
|
|
110
|
+
searchText={searchText}
|
|
111
|
+
onSearch={handleSearch}
|
|
112
|
+
onHide={hideSearch}
|
|
113
|
+
options={options}
|
|
114
|
+
debounceWait={debounceWait}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Default text labels.
|
|
3
|
+
*/
|
|
4
|
+
const getTextLabels = () => ({
|
|
5
|
+
body: {
|
|
6
|
+
noMatch: 'Sorry, no matching records found',
|
|
7
|
+
toolTip: 'Sort',
|
|
8
|
+
},
|
|
9
|
+
pagination: {
|
|
10
|
+
next: 'Next Page',
|
|
11
|
+
previous: 'Previous Page',
|
|
12
|
+
rowsPerPage: 'Rows per page:',
|
|
13
|
+
displayRows: 'of',
|
|
14
|
+
jumpToPage: 'Jump to Page:',
|
|
15
|
+
},
|
|
16
|
+
toolbar: {
|
|
17
|
+
search: 'Search',
|
|
18
|
+
downloadCsv: 'Download CSV',
|
|
19
|
+
print: 'Print',
|
|
20
|
+
viewColumns: 'View Columns',
|
|
21
|
+
filterTable: 'Filter Table',
|
|
22
|
+
},
|
|
23
|
+
filter: {
|
|
24
|
+
all: 'All',
|
|
25
|
+
title: 'FILTERS',
|
|
26
|
+
reset: 'RESET',
|
|
27
|
+
},
|
|
28
|
+
viewColumns: {
|
|
29
|
+
title: 'Show Columns',
|
|
30
|
+
titleAria: 'Show/Hide Table Columns',
|
|
31
|
+
},
|
|
32
|
+
selectedRows: {
|
|
33
|
+
text: 'row(s) selected',
|
|
34
|
+
delete: 'Delete',
|
|
35
|
+
deleteAria: 'Delete Selected Rows',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export default getTextLabels;
|