@arcblock/ux 2.1.6 → 2.1.7
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/lib/Datatable/CustomToolbar.js +330 -0
- package/lib/Datatable/TableSearch.js +100 -0
- package/lib/Datatable/index.js +185 -0
- package/lib/Datatable/utils.js +154 -0
- package/lib/index.js +8 -0
- package/package.json +5 -4
- package/src/Datatable/CustomToolbar.js +371 -0
- package/src/Datatable/TableSearch.js +127 -0
- package/src/Datatable/index.js +145 -0
- package/src/Datatable/utils.js +165 -0
- package/src/index.js +2 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
exports.handleCSVDownload = handleCSVDownload;
|
|
8
|
+
|
|
9
|
+
var _find = _interopRequireDefault(require("lodash/find"));
|
|
10
|
+
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
|
|
13
|
+
function escapeDangerousCSVCharacters(data) {
|
|
14
|
+
if (typeof data === 'string') {
|
|
15
|
+
// Places single quote before the appearance of dangerous characters if they
|
|
16
|
+
// are the first in the data string.
|
|
17
|
+
// eslint-disable-next-line no-useless-escape
|
|
18
|
+
return data.replace(/^\+|^\-|^\=|^\@/g, "'$&");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return data;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function buildCSV(columns, data, options) {
|
|
25
|
+
const replaceDoubleQuoteInString = columnData => typeof columnData === 'string' ? columnData.replace(/"/g, '""') : columnData; // eslint-disable-next-line no-shadow
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const buildHead = columns => {
|
|
29
|
+
return "".concat(columns.reduce((soFar, column) => column.download ? "".concat(soFar, "\"").concat(escapeDangerousCSVCharacters(replaceDoubleQuoteInString(column.label || column.name)), "\"").concat(options.downloadOptions.separator) : soFar, '').slice(0, -1), "\r\n");
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const CSVHead = buildHead(columns); // eslint-disable-next-line no-shadow
|
|
33
|
+
|
|
34
|
+
const buildBody = data => {
|
|
35
|
+
if (!data.length) return '';
|
|
36
|
+
return data.reduce((soFar, row) => "".concat(soFar, "\"").concat(row.data.filter((_, index) => columns[index].download).map(columnData => escapeDangerousCSVCharacters(replaceDoubleQuoteInString(columnData))).join("\"".concat(options.downloadOptions.separator, "\"")), "\"\r\n"), '').trim();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const CSVBody = buildBody(data);
|
|
40
|
+
const csv = options.onDownload ? options.onDownload(buildHead, buildBody, columns, data) : "".concat(CSVHead).concat(CSVBody).trim();
|
|
41
|
+
return csv;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function downloadCSV(csv, filename) {
|
|
45
|
+
const blob = new Blob([csv], {
|
|
46
|
+
type: 'text/csv'
|
|
47
|
+
});
|
|
48
|
+
/* taken from react-csv */
|
|
49
|
+
|
|
50
|
+
if (navigator && navigator.msSaveOrOpenBlob) {
|
|
51
|
+
navigator.msSaveOrOpenBlob(blob, filename);
|
|
52
|
+
} else {
|
|
53
|
+
const dataURI = "data:text/csv;charset=utf-8,".concat(csv);
|
|
54
|
+
const URL = window.URL || window.webkitURL;
|
|
55
|
+
const downloadURI = typeof URL.createObjectURL === 'undefined' ? dataURI : URL.createObjectURL(blob);
|
|
56
|
+
const link = document.createElement('a');
|
|
57
|
+
link.setAttribute('href', downloadURI);
|
|
58
|
+
link.setAttribute('download', filename);
|
|
59
|
+
document.body.appendChild(link);
|
|
60
|
+
link.click();
|
|
61
|
+
document.body.removeChild(link);
|
|
62
|
+
}
|
|
63
|
+
} // eslint-disable-next-line no-shadow
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
function createCSVDownload(columns, data, options, downloadCSV) {
|
|
67
|
+
const csv = buildCSV(columns, data, options);
|
|
68
|
+
|
|
69
|
+
if (options.onDownload && csv === false) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
downloadCSV(csv, options.downloadOptions.filename);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function handleCSVDownload(props) {
|
|
77
|
+
const {
|
|
78
|
+
data,
|
|
79
|
+
displayData,
|
|
80
|
+
columns,
|
|
81
|
+
options,
|
|
82
|
+
columnOrder
|
|
83
|
+
} = props;
|
|
84
|
+
let dataToDownload = [];
|
|
85
|
+
let columnsToDownload = [];
|
|
86
|
+
let columnOrderCopy = Array.isArray(columnOrder) ? columnOrder.slice(0) : [];
|
|
87
|
+
|
|
88
|
+
if (columnOrderCopy.length === 0) {
|
|
89
|
+
columnOrderCopy = columns.map((item, idx) => idx);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
data.forEach(row => {
|
|
93
|
+
const newRow = {
|
|
94
|
+
index: row.index,
|
|
95
|
+
data: []
|
|
96
|
+
};
|
|
97
|
+
columnOrderCopy.forEach(idx => {
|
|
98
|
+
newRow.data.push(row.data[idx]);
|
|
99
|
+
});
|
|
100
|
+
dataToDownload.push(newRow);
|
|
101
|
+
});
|
|
102
|
+
columnOrderCopy.forEach(idx => {
|
|
103
|
+
columnsToDownload.push(columns[idx]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (options.downloadOptions && options.downloadOptions.filterOptions) {
|
|
107
|
+
// check rows first:
|
|
108
|
+
if (options.downloadOptions.filterOptions.useDisplayedRowsOnly) {
|
|
109
|
+
const filteredDataToDownload = displayData.map((row, index) => {
|
|
110
|
+
let i = -1; // Help to preserve sort order in custom render columns
|
|
111
|
+
|
|
112
|
+
row.index = index;
|
|
113
|
+
return {
|
|
114
|
+
data: row.data.map(column => {
|
|
115
|
+
i += 1; // if we have a custom render, which will appear as a react element, we must grab the actual value from data
|
|
116
|
+
// that matches the dataIndex and column
|
|
117
|
+
// TODO: Create a utility function for checking whether or not something is a react object
|
|
118
|
+
|
|
119
|
+
let val = typeof column === 'object' && column !== null && !Array.isArray(column) ? (0, _find.default)(data, d => d.index === row.dataIndex).data[i] : column;
|
|
120
|
+
val = typeof val === 'function' ? (0, _find.default)(data, d => d.index === row.dataIndex).data[i] : val;
|
|
121
|
+
return val;
|
|
122
|
+
})
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
dataToDownload = [];
|
|
126
|
+
filteredDataToDownload.forEach(row => {
|
|
127
|
+
const newRow = {
|
|
128
|
+
index: row.index,
|
|
129
|
+
data: []
|
|
130
|
+
};
|
|
131
|
+
columnOrderCopy.forEach(idx => {
|
|
132
|
+
newRow.data.push(row.data[idx]);
|
|
133
|
+
});
|
|
134
|
+
dataToDownload.push(newRow);
|
|
135
|
+
});
|
|
136
|
+
} // now, check columns:
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if (options.downloadOptions.filterOptions.useDisplayedColumnsOnly) {
|
|
140
|
+
columnsToDownload = columnsToDownload.filter(_ => _.display === 'true');
|
|
141
|
+
dataToDownload = dataToDownload.map(row => {
|
|
142
|
+
row.data = row.data.filter((_, index) => columns[columnOrderCopy[index]].display === 'true');
|
|
143
|
+
return row;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
createCSVDownload(columnsToDownload, dataToDownload, options, downloadCSV);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
var _default = {
|
|
152
|
+
handleCSVDownload
|
|
153
|
+
};
|
|
154
|
+
exports.default = _default;
|
package/lib/index.js
CHANGED
|
@@ -69,6 +69,12 @@ Object.defineProperty(exports, "CountDown", {
|
|
|
69
69
|
return _CountDown.default;
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
|
+
Object.defineProperty(exports, "Datatable", {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
get: function get() {
|
|
75
|
+
return _Datatable.default;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
72
78
|
Object.defineProperty(exports, "Earth", {
|
|
73
79
|
enumerable: true,
|
|
74
80
|
get: function get() {
|
|
@@ -230,6 +236,8 @@ var _Logo = _interopRequireDefault(require("./Logo"));
|
|
|
230
236
|
|
|
231
237
|
var _RelativeTime = _interopRequireDefault(require("./RelativeTime"));
|
|
232
238
|
|
|
239
|
+
var _Datatable = _interopRequireDefault(require("./Datatable"));
|
|
240
|
+
|
|
233
241
|
var _Tabs = _interopRequireDefault(require("./Tabs"));
|
|
234
242
|
|
|
235
243
|
var _Tag = _interopRequireDefault(require("./Tag"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/ux",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.7",
|
|
4
4
|
"description": "Common used react components for arcblock products",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"react": ">=18.1.0",
|
|
53
53
|
"react-ga": "^2.7.0"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "a54ef3a9335aae1bc7404b5f4a8c9c508b6ff81f",
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@arcblock/icons": "^2.1.
|
|
58
|
-
"@arcblock/react-hooks": "^2.1.
|
|
57
|
+
"@arcblock/icons": "^2.1.7",
|
|
58
|
+
"@arcblock/react-hooks": "^2.1.7",
|
|
59
59
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
60
60
|
"@emotion/react": "^11.9.0",
|
|
61
61
|
"@emotion/styled": "^11.8.1",
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"js-cookie": "^2.2.0",
|
|
76
76
|
"lodash": "^4.17.21",
|
|
77
77
|
"mdi-material-ui": "^7.2.0",
|
|
78
|
+
"mui-datatables": "^4.2.2",
|
|
78
79
|
"notistack": "^2.0.5",
|
|
79
80
|
"react-cookie-consent": "^6.4.1",
|
|
80
81
|
"react-helmet": "^6.1.0",
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import React, { useState, useRef, isValidElement } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { TableFilter, TableViewCol } from 'mui-datatables';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
import ReactToPrint, { PrintContextConsumer } from 'react-to-print';
|
|
6
|
+
import IconButton from '@mui/material/IconButton';
|
|
7
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
8
|
+
import DownloadIcon from '@mui/icons-material/CloudDownload';
|
|
9
|
+
import PrintIcon from '@mui/icons-material/Print';
|
|
10
|
+
import ViewColumnIcon from '@mui/icons-material/ViewColumn';
|
|
11
|
+
import FilterIcon from '@mui/icons-material/FilterList';
|
|
12
|
+
import Popover from '@mui/material/Popover';
|
|
13
|
+
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
14
|
+
import Menu from '@mui/material/Menu';
|
|
15
|
+
import MenuItem from '@mui/material/MenuItem';
|
|
16
|
+
import ListItemIcon from '@mui/material/ListItemIcon';
|
|
17
|
+
import ListItemText from '@mui/material/ListItemText';
|
|
18
|
+
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
19
|
+
import { useTheme } from '@mui/material/styles';
|
|
20
|
+
import { handleCSVDownload } from './utils';
|
|
21
|
+
import TableSearch from './TableSearch';
|
|
22
|
+
|
|
23
|
+
function useMobile() {
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
return useMediaQuery(theme.breakpoints.down('sm'));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function CustomToolbar(props) {
|
|
29
|
+
const [menuIconEl, setMenuIconEl] = useState(null);
|
|
30
|
+
const moreBtn = useRef(null);
|
|
31
|
+
const isMobile = useMobile();
|
|
32
|
+
const toolbarId = useRef(Math.random().toString(32).slice(2));
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
data,
|
|
36
|
+
options,
|
|
37
|
+
components,
|
|
38
|
+
columns,
|
|
39
|
+
filterList,
|
|
40
|
+
filterData,
|
|
41
|
+
filterUpdate,
|
|
42
|
+
resetFilters,
|
|
43
|
+
updateFilterByType,
|
|
44
|
+
toggleViewColumn,
|
|
45
|
+
updateColumns,
|
|
46
|
+
title,
|
|
47
|
+
searchText,
|
|
48
|
+
searchTextUpdate,
|
|
49
|
+
searchClose,
|
|
50
|
+
customButtons,
|
|
51
|
+
} = props;
|
|
52
|
+
|
|
53
|
+
const { search, downloadCsv, print, viewColumns, filterTable } = options.textLabels.toolbar;
|
|
54
|
+
|
|
55
|
+
const hideSearch = options.search === false || options.search === 'false';
|
|
56
|
+
const hidePrint = options.print === false || options.print === 'false';
|
|
57
|
+
|
|
58
|
+
const TableFilterComponent = components.TableFilter || TableFilter;
|
|
59
|
+
const TableViewColComponent = components.TableViewCol || TableViewCol;
|
|
60
|
+
|
|
61
|
+
const printArea = func => {
|
|
62
|
+
return (
|
|
63
|
+
<ReactToPrint content={() => props.tableRef()}>
|
|
64
|
+
<PrintContextConsumer>{func}</PrintContextConsumer>
|
|
65
|
+
</ReactToPrint>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const getPopId = key => `toolbar-pop-${toolbarId.current}-${key}`;
|
|
70
|
+
|
|
71
|
+
const defaultButtons = [];
|
|
72
|
+
|
|
73
|
+
if (!(options.download === false || options.download === 'false')) {
|
|
74
|
+
defaultButtons.push({
|
|
75
|
+
Icon: DownloadIcon,
|
|
76
|
+
title: downloadCsv,
|
|
77
|
+
onClick: () => {
|
|
78
|
+
handleCSVDownload(props);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!(options.viewColumns === false || options.viewColumns === 'false')) {
|
|
84
|
+
defaultButtons.push({
|
|
85
|
+
Icon: ViewColumnIcon,
|
|
86
|
+
title: viewColumns,
|
|
87
|
+
popRender() {
|
|
88
|
+
return (
|
|
89
|
+
<TableViewColComponent
|
|
90
|
+
data={data}
|
|
91
|
+
columns={columns}
|
|
92
|
+
options={options}
|
|
93
|
+
onColumnUpdate={toggleViewColumn}
|
|
94
|
+
updateColumns={updateColumns}
|
|
95
|
+
components={components}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!(options.filter === false || options.filter === 'false')) {
|
|
103
|
+
defaultButtons.push({
|
|
104
|
+
Icon: FilterIcon,
|
|
105
|
+
title: filterTable,
|
|
106
|
+
popRender() {
|
|
107
|
+
return (
|
|
108
|
+
<TableFilterComponent
|
|
109
|
+
customFooter={options.customFilterDialogFooter}
|
|
110
|
+
columns={columns}
|
|
111
|
+
options={options}
|
|
112
|
+
filterList={filterList}
|
|
113
|
+
filterData={filterData}
|
|
114
|
+
onFilterUpdate={filterUpdate}
|
|
115
|
+
onFilterReset={resetFilters}
|
|
116
|
+
updateFilterByType={updateFilterByType}
|
|
117
|
+
components={components}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const showMore =
|
|
125
|
+
[!hidePrint, ...defaultButtons, ...customButtons].filter(e => !!e).length > 1 && isMobile;
|
|
126
|
+
|
|
127
|
+
const allPops = [];
|
|
128
|
+
const [allPopsEl, setAllPopsEl] = useState({});
|
|
129
|
+
|
|
130
|
+
const toolbarButtons = [...defaultButtons, ...customButtons].map((e, index) => {
|
|
131
|
+
if (isValidElement(e)) {
|
|
132
|
+
return e;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const popId = getPopId(index);
|
|
136
|
+
|
|
137
|
+
if (e.Icon) {
|
|
138
|
+
const { Icon, popRender } = e;
|
|
139
|
+
if (popRender) {
|
|
140
|
+
allPops.push(
|
|
141
|
+
<Popover
|
|
142
|
+
open={!!allPopsEl[popId]}
|
|
143
|
+
anchorEl={() => allPopsEl[popId]}
|
|
144
|
+
onClose={() => {
|
|
145
|
+
setAllPopsEl({});
|
|
146
|
+
}}
|
|
147
|
+
key={popId}
|
|
148
|
+
anchorOrigin={{
|
|
149
|
+
vertical: 'bottom',
|
|
150
|
+
horizontal: 'right',
|
|
151
|
+
}}>
|
|
152
|
+
<div>{popRender()}</div>
|
|
153
|
+
</Popover>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<Tooltip title={e.title} key={popId}>
|
|
159
|
+
<IconButton
|
|
160
|
+
data-testid={`${e.title}-iconButton`}
|
|
161
|
+
id={`btn-${popId}`}
|
|
162
|
+
aria-label={e.title}
|
|
163
|
+
onClick={() => {
|
|
164
|
+
if (e.onClick) {
|
|
165
|
+
e.onClick();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (popRender) {
|
|
169
|
+
setAllPopsEl({
|
|
170
|
+
[popId]: document.getElementById(`btn-${popId}`),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}}>
|
|
174
|
+
<Icon />
|
|
175
|
+
</IconButton>
|
|
176
|
+
</Tooltip>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return e;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const menuItems = [...defaultButtons, ...customButtons].map((e, index) => {
|
|
184
|
+
const popId = getPopId(index);
|
|
185
|
+
|
|
186
|
+
let content;
|
|
187
|
+
|
|
188
|
+
if (isValidElement(e)) {
|
|
189
|
+
content = e;
|
|
190
|
+
} else if (e.Icon) {
|
|
191
|
+
const { Icon } = e;
|
|
192
|
+
|
|
193
|
+
content = (
|
|
194
|
+
<>
|
|
195
|
+
<ListItemIcon>
|
|
196
|
+
<Icon fontSize="small" />
|
|
197
|
+
</ListItemIcon>
|
|
198
|
+
<ListItemText>{e.title}</ListItemText>
|
|
199
|
+
</>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<MenuItem
|
|
205
|
+
key={popId}
|
|
206
|
+
onClick={() => {
|
|
207
|
+
setMenuIconEl(null);
|
|
208
|
+
if (e.onClick) {
|
|
209
|
+
e.onClick();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (e.popRender) {
|
|
213
|
+
setAllPopsEl({
|
|
214
|
+
[popId]: moreBtn.current,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}}>
|
|
218
|
+
{content}
|
|
219
|
+
</MenuItem>
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<div>
|
|
225
|
+
<Container>
|
|
226
|
+
<div className="custom-toobar-title">
|
|
227
|
+
<div className="custom-toobar-title-inner">
|
|
228
|
+
<span>{title}</span>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div className="custom-toobar-right">
|
|
232
|
+
<div className="custom-toobar-btns">
|
|
233
|
+
{!hideSearch && (
|
|
234
|
+
<TableSearch
|
|
235
|
+
search={search}
|
|
236
|
+
options={options}
|
|
237
|
+
searchText={searchText}
|
|
238
|
+
searchTextUpdate={searchTextUpdate}
|
|
239
|
+
searchClose={searchClose}
|
|
240
|
+
isMobile={isMobile}
|
|
241
|
+
/>
|
|
242
|
+
)}
|
|
243
|
+
{!showMore && (
|
|
244
|
+
<>
|
|
245
|
+
{!hidePrint &&
|
|
246
|
+
printArea(({ handlePrint }) => (
|
|
247
|
+
<span>
|
|
248
|
+
<Tooltip title={print}>
|
|
249
|
+
<IconButton
|
|
250
|
+
data-testid={`${print}-iconButton`}
|
|
251
|
+
aria-label={print}
|
|
252
|
+
disabled={options.print === 'disabled'}
|
|
253
|
+
onClick={handlePrint}>
|
|
254
|
+
<PrintIcon />
|
|
255
|
+
</IconButton>
|
|
256
|
+
</Tooltip>
|
|
257
|
+
</span>
|
|
258
|
+
))}
|
|
259
|
+
|
|
260
|
+
{toolbarButtons}
|
|
261
|
+
</>
|
|
262
|
+
)}
|
|
263
|
+
{showMore && (
|
|
264
|
+
<IconButton
|
|
265
|
+
ref={moreBtn}
|
|
266
|
+
aria-haspopup="true"
|
|
267
|
+
aria-expanded={menuIconEl ? 'true' : undefined}
|
|
268
|
+
onClick={event => setMenuIconEl(event.currentTarget)}>
|
|
269
|
+
<MoreVertIcon />
|
|
270
|
+
</IconButton>
|
|
271
|
+
)}
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
</Container>
|
|
275
|
+
|
|
276
|
+
<Menu
|
|
277
|
+
anchorEl={menuIconEl}
|
|
278
|
+
open={!!menuIconEl}
|
|
279
|
+
onClose={() => setMenuIconEl(null)}
|
|
280
|
+
MenuListProps={{
|
|
281
|
+
'aria-labelledby': 'more-button',
|
|
282
|
+
}}>
|
|
283
|
+
{!hidePrint &&
|
|
284
|
+
printArea(({ handlePrint }) => (
|
|
285
|
+
<MenuItem
|
|
286
|
+
onClick={() => {
|
|
287
|
+
setMenuIconEl(null);
|
|
288
|
+
handlePrint();
|
|
289
|
+
}}>
|
|
290
|
+
<ListItemIcon>
|
|
291
|
+
<PrintIcon fontSize="small" />
|
|
292
|
+
</ListItemIcon>
|
|
293
|
+
<ListItemText>{print}</ListItemText>
|
|
294
|
+
</MenuItem>
|
|
295
|
+
))}
|
|
296
|
+
{menuItems}
|
|
297
|
+
</Menu>
|
|
298
|
+
{allPops.map((e, index) => (
|
|
299
|
+
<div key={getPopId(index)}>{e}</div>
|
|
300
|
+
))}
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
CustomToolbar.propTypes = {
|
|
306
|
+
data: PropTypes.array,
|
|
307
|
+
options: PropTypes.object.isRequired,
|
|
308
|
+
components: PropTypes.object,
|
|
309
|
+
columns: PropTypes.array.isRequired,
|
|
310
|
+
filterList: PropTypes.array,
|
|
311
|
+
filterData: PropTypes.array,
|
|
312
|
+
filterUpdate: PropTypes.func.isRequired,
|
|
313
|
+
resetFilters: PropTypes.func.isRequired,
|
|
314
|
+
updateFilterByType: PropTypes.func.isRequired,
|
|
315
|
+
toggleViewColumn: PropTypes.func.isRequired,
|
|
316
|
+
updateColumns: PropTypes.func.isRequired,
|
|
317
|
+
title: PropTypes.string,
|
|
318
|
+
searchText: PropTypes.any,
|
|
319
|
+
searchTextUpdate: PropTypes.func.isRequired,
|
|
320
|
+
searchClose: PropTypes.func.isRequired,
|
|
321
|
+
tableRef: PropTypes.func.isRequired,
|
|
322
|
+
customButtons: PropTypes.array.isRequired,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
CustomToolbar.defaultProps = {
|
|
326
|
+
data: [],
|
|
327
|
+
components: {},
|
|
328
|
+
filterList: [],
|
|
329
|
+
filterData: [],
|
|
330
|
+
title: '',
|
|
331
|
+
searchText: null,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const Container = styled.div`
|
|
335
|
+
display: flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
height: 56px;
|
|
338
|
+
.custom-toobar {
|
|
339
|
+
&-title {
|
|
340
|
+
position: relative;
|
|
341
|
+
flex: 1;
|
|
342
|
+
font-size: 18px;
|
|
343
|
+
font-weight: 800;
|
|
344
|
+
height: 56px;
|
|
345
|
+
&-inner {
|
|
346
|
+
line-height: 56px;
|
|
347
|
+
width: 100%;
|
|
348
|
+
height: 56px;
|
|
349
|
+
position: absolute;
|
|
350
|
+
left: 0;
|
|
351
|
+
top: 0;
|
|
352
|
+
span {
|
|
353
|
+
display: inline-block;
|
|
354
|
+
max-width: 100%;
|
|
355
|
+
white-space: nowrap;
|
|
356
|
+
text-overflow: ellipsis;
|
|
357
|
+
overflow: hidden;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
&-right {
|
|
362
|
+
display: flex;
|
|
363
|
+
margin-left: auto;
|
|
364
|
+
}
|
|
365
|
+
&-btns {
|
|
366
|
+
display: flex;
|
|
367
|
+
justify-content: center;
|
|
368
|
+
align-items: center;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
`;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import IconButton from '@mui/material/IconButton';
|
|
4
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
5
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
6
|
+
import TextField from '@mui/material/TextField';
|
|
7
|
+
import ClearIcon from '@mui/icons-material/Clear';
|
|
8
|
+
import styled from 'styled-components';
|
|
9
|
+
|
|
10
|
+
export default function TableSearch({
|
|
11
|
+
search,
|
|
12
|
+
options,
|
|
13
|
+
searchText,
|
|
14
|
+
searchTextUpdate,
|
|
15
|
+
searchClose,
|
|
16
|
+
isMobile,
|
|
17
|
+
onSearchOpen,
|
|
18
|
+
}) {
|
|
19
|
+
const [inputMode, setInputMode] = useState(false);
|
|
20
|
+
|
|
21
|
+
const clickSearchIcon = () => {
|
|
22
|
+
setInputMode(true);
|
|
23
|
+
onSearchOpen(true);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const onChange = event => {
|
|
27
|
+
searchTextUpdate(event.currentTarget.value);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const clickClose = () => {
|
|
31
|
+
setInputMode(false);
|
|
32
|
+
searchClose();
|
|
33
|
+
onSearchOpen(false);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Container>
|
|
38
|
+
{inputMode ? (
|
|
39
|
+
<div className="toolbar-search-icon-placeholder-">
|
|
40
|
+
<SearchIcon />
|
|
41
|
+
</div>
|
|
42
|
+
) : (
|
|
43
|
+
<Tooltip title={search} disableFocusListener>
|
|
44
|
+
<IconButton
|
|
45
|
+
aria-label={search}
|
|
46
|
+
data-testid={`${search}-iconButton`}
|
|
47
|
+
disabled={options.search === 'disabled'}
|
|
48
|
+
onClick={clickSearchIcon}>
|
|
49
|
+
<SearchIcon />
|
|
50
|
+
</IconButton>
|
|
51
|
+
</Tooltip>
|
|
52
|
+
)}
|
|
53
|
+
|
|
54
|
+
<div
|
|
55
|
+
className={`toolbar-search-area ${inputMode ? 'toolbar-btn-show' : ''} ${
|
|
56
|
+
isMobile ? 'small-textfield' : ''
|
|
57
|
+
}`}>
|
|
58
|
+
{inputMode && (
|
|
59
|
+
<TextField
|
|
60
|
+
variant="standard"
|
|
61
|
+
spacing={2}
|
|
62
|
+
onChange={onChange}
|
|
63
|
+
value={searchText || ''}
|
|
64
|
+
autoFocus
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
<div className={`toolbar-search-close ${inputMode ? 'toolbar-btn-show' : ''}`}>
|
|
69
|
+
<IconButton onClick={clickClose}>
|
|
70
|
+
<ClearIcon />
|
|
71
|
+
</IconButton>
|
|
72
|
+
</div>
|
|
73
|
+
</Container>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
TableSearch.propTypes = {
|
|
78
|
+
search: PropTypes.string,
|
|
79
|
+
searchText: PropTypes.string,
|
|
80
|
+
onSearchOpen: PropTypes.func,
|
|
81
|
+
options: PropTypes.object.isRequired,
|
|
82
|
+
searchTextUpdate: PropTypes.func.isRequired,
|
|
83
|
+
searchClose: PropTypes.func.isRequired,
|
|
84
|
+
isMobile: PropTypes.bool.isRequired,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
TableSearch.defaultProps = {
|
|
88
|
+
search: '',
|
|
89
|
+
searchText: '',
|
|
90
|
+
onSearchOpen: () => {},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const Container = styled.div`
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
.toolbar-search-area {
|
|
97
|
+
width: 0;
|
|
98
|
+
transition: all ease 0.3s;
|
|
99
|
+
overflow: hidden;
|
|
100
|
+
.MuiFormControl-root {
|
|
101
|
+
width: inherit;
|
|
102
|
+
margin: 0 12px;
|
|
103
|
+
}
|
|
104
|
+
&.toolbar-btn-show {
|
|
105
|
+
width: 260px;
|
|
106
|
+
padding-left: 8px;
|
|
107
|
+
&.small-textfield {
|
|
108
|
+
width: 200px;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
.toolbar-search-close {
|
|
113
|
+
width: 0;
|
|
114
|
+
transition: all ease 0.3s;
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
&.toolbar-btn-show {
|
|
117
|
+
width: 40px;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
.toolbar-search-icon-placeholder {
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
align-items: center;
|
|
124
|
+
width: 40px;
|
|
125
|
+
height: 40px;
|
|
126
|
+
}
|
|
127
|
+
`;
|