es-grid-template 0.0.4 → 0.0.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE +19 -0
  3. package/README.md +1 -6
  4. package/{dist/components/GridTable → es}/CheckboxFilter.d.ts +1 -1
  5. package/es/CheckboxFilter.js +249 -0
  6. package/{dist/components/GridTable → es}/ColumnsChoose.d.ts +3 -2
  7. package/es/ColumnsChoose.js +213 -0
  8. package/{dist/components/GridTable → es}/ContextMenu.d.ts +1 -1
  9. package/es/ContextMenu.js +126 -0
  10. package/{dist/components/GridTable → es}/FilterSearch.d.ts +3 -3
  11. package/es/FilterSearch.js +33 -0
  12. package/es/GridTable.d.ts +7 -0
  13. package/es/GridTable.js +927 -0
  14. package/es/hooks/constant.js +214 -0
  15. package/es/hooks/index.js +5 -0
  16. package/{dist → es}/hooks/useColumns/index.d.ts +1 -1
  17. package/es/hooks/useColumns/index.js +25 -0
  18. package/{dist → es}/hooks/useIsOverflow.d.ts +1 -1
  19. package/es/hooks/useIsOverflow.js +17 -0
  20. package/es/hooks/useOnClickOutside.js +28 -0
  21. package/{dist → es}/hooks/utils.d.ts +7 -3
  22. package/es/hooks/utils.js +192 -0
  23. package/es/index.d.ts +2 -0
  24. package/es/index.js +2 -0
  25. package/es/styles.scss +30 -0
  26. package/es/type.d.ts +88 -0
  27. package/es/type.js +1 -0
  28. package/lib/CheckboxFilter.d.ts +19 -0
  29. package/lib/CheckboxFilter.js +257 -0
  30. package/lib/ColumnsChoose.d.ts +10 -0
  31. package/lib/ColumnsChoose.js +223 -0
  32. package/lib/ContextMenu.d.ts +20 -0
  33. package/lib/ContextMenu.js +135 -0
  34. package/lib/FilterSearch.d.ts +12 -0
  35. package/lib/FilterSearch.js +42 -0
  36. package/lib/GridTable.d.ts +7 -0
  37. package/lib/GridTable.js +936 -0
  38. package/lib/hooks/constant.d.ts +48 -0
  39. package/lib/hooks/constant.js +221 -0
  40. package/lib/hooks/index.d.ts +4 -0
  41. package/lib/hooks/index.js +49 -0
  42. package/lib/hooks/useColumns/index.d.ts +2 -0
  43. package/lib/hooks/useColumns/index.js +31 -0
  44. package/lib/hooks/useIsOverflow.d.ts +1 -0
  45. package/lib/hooks/useIsOverflow.js +26 -0
  46. package/lib/hooks/useOnClickOutside.d.ts +1 -0
  47. package/lib/hooks/useOnClickOutside.js +36 -0
  48. package/lib/hooks/utils.d.ts +18 -0
  49. package/lib/hooks/utils.js +215 -0
  50. package/lib/index.d.ts +2 -0
  51. package/lib/index.js +9 -0
  52. package/lib/styles.scss +30 -0
  53. package/lib/type.d.ts +88 -0
  54. package/lib/type.js +5 -0
  55. package/package.json +75 -94
  56. package/dist/components/GridTable/GridTable.d.ts +0 -6
  57. package/dist/components/GridTable/index.d.ts +0 -1
  58. package/dist/components/index.d.ts +0 -1
  59. package/dist/index.d.ts +0 -2
  60. package/dist/index.js +0 -53
  61. package/dist/type.d.ts +0 -45
  62. /package/{dist → es}/hooks/constant.d.ts +0 -0
  63. /package/{dist → es}/hooks/index.d.ts +0 -0
  64. /package/{dist → es}/hooks/useOnClickOutside.d.ts +0 -0
@@ -0,0 +1,927 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import React, { Fragment, useLayoutEffect, useMemo, useRef, useState } from 'react';
3
+ import { Table } from "ui-rc";
4
+ import { Resizable } from 'react-resizable';
5
+ import { createStyles } from 'antd-style';
6
+ import { NumericFormat, numericFormatter } from "react-numeric-component";
7
+ // import {Button, DatePicker, Input, Space} from "antd"
8
+ import { SearchOutlined } from '@ant-design/icons';
9
+ import { Select, Toolbar, DatePicker, Input } from "ui-rc";
10
+ // import {flatColumns} from "../../hooks/useColumns";
11
+ // import {
12
+ // checkDecimalSeparator,
13
+ // checkThousandSeparator,
14
+ // convertDateToDayjs,
15
+ // convertDayjsToDate,
16
+ // getTypeFilter,
17
+ // getDatepickerFormat,
18
+ // isColor,
19
+ // isEmpty,
20
+ // numberOperator,
21
+ // sumDataByField,
22
+ // translateOption
23
+ // } from "../hooks";
24
+
25
+ // import type {ColumnsType, ColumnType, GridTableProps} from "../../type";
26
+ import dayjs from "dayjs";
27
+ import 'dayjs/locale/es';
28
+ import 'dayjs/locale/vi';
29
+ import "./styles.scss";
30
+
31
+ // import en from 'antd/es/date-picker/locale/en_US'
32
+
33
+ // import vi from 'antd/es/date-picker/locale/vi_VN'
34
+
35
+ import moment from "moment";
36
+ import CheckboxFilter from "./CheckboxFilter";
37
+ import ContextMenu from "./ContextMenu";
38
+ import { ColumnsChoose } from "./ColumnsChoose";
39
+ import classNames from "classnames";
40
+ // import type {PickerLocale} from "antd/es/date-picker/generatePicker";
41
+
42
+ import { checkDecimalSeparator, checkThousandSeparator, convertDateToDayjs, convertDayjsToDate, getTypeFilter, getDatepickerFormat, isColor, isEmpty, numberOperator, sumDataByField, translateOption } from "./hooks";
43
+ // import type {PickerLocale} from "ui-rc/dist/date-picker/generatePicker";
44
+
45
+ import { Button } from "antd";
46
+ import { flatColumns } from "./hooks/useColumns";
47
+ const {
48
+ RangePicker
49
+ } = DatePicker;
50
+ const convertFilters = filters => {
51
+ const result = [];
52
+ filters.forEach(({
53
+ key,
54
+ column,
55
+ filteredKeys,
56
+ operator
57
+ }) => {
58
+ if (!filteredKeys || filteredKeys.length === 0) return;
59
+ if (column.typeFilter === "DateRange" && filteredKeys.length === 2) {
60
+ result.push({
61
+ key,
62
+ field: column.dataIndex,
63
+ value: filteredKeys[0],
64
+ predicate: "and",
65
+ operator: "greaterthanorequal"
66
+ }, {
67
+ key,
68
+ field: column.dataIndex,
69
+ value: filteredKeys[1],
70
+ predicate: "and",
71
+ operator: "lessthanorequal"
72
+ });
73
+ } else if (column.typeFilter === 'Checkbox') {
74
+ filteredKeys.forEach(value => {
75
+ result.push({
76
+ key,
77
+ field: column.dataIndex,
78
+ value,
79
+ predicate: "or",
80
+ operator
81
+ });
82
+ });
83
+ } else {
84
+ result.push({
85
+ key,
86
+ field: column.dataIndex,
87
+ value: filteredKeys[0],
88
+ predicate: 'and',
89
+ operator
90
+ });
91
+ }
92
+ });
93
+ return result;
94
+ };
95
+ const ResizableTitle = props => {
96
+ const {
97
+ onResize,
98
+ width,
99
+ ...restProps
100
+ } = props;
101
+ if (!width) {
102
+ return /*#__PURE__*/React.createElement("th", restProps);
103
+ }
104
+ return (
105
+ /*#__PURE__*/
106
+ // @ts-ignore
107
+ React.createElement(Resizable, {
108
+ width: width,
109
+ height: 0,
110
+ handle: /*#__PURE__*/React.createElement("span", {
111
+ className: "react-resizable-handle",
112
+ onClick: e => {
113
+ e.stopPropagation();
114
+ }
115
+ }),
116
+ onResize: onResize,
117
+ draggableOpts: {
118
+ enableUserSelectHack: false
119
+ }
120
+ }, /*#__PURE__*/React.createElement("th", restProps))
121
+ );
122
+ };
123
+ const useStyle = createStyles(({
124
+ css
125
+ }) => {
126
+ // const { antCls } = token
127
+ const antCls = 'ui-rc';
128
+ return {
129
+ customTable: css`
130
+ ${antCls}-table {
131
+ ${antCls}-table-container {
132
+ ${antCls}-table-body,
133
+ ${antCls}-table-content {
134
+ scrollbar-width: thin;
135
+ scrollbar-color: #eaeaea transparent;
136
+ scrollbar-gutter: stable;
137
+ }
138
+ }
139
+ }
140
+ `
141
+ };
142
+ });
143
+ const GridTable = props => {
144
+ const {
145
+ columns: defaultColumns,
146
+ dataSource,
147
+ format,
148
+ virtual = true,
149
+ t,
150
+ lang,
151
+ contextMenuOpen,
152
+ contextMenuItems: propContextMenuItems,
153
+ contextMenuHidden,
154
+ contextMenuClick,
155
+ recordDoubleClick,
156
+ toolbarItems,
157
+ showColumnChoose,
158
+ onFilter,
159
+ selectionSettings,
160
+ rowSelection,
161
+ rowSelected,
162
+ rowKey = 'id',
163
+ ...rest
164
+ } = props;
165
+ const {
166
+ styles
167
+ } = useStyle();
168
+
169
+ // const locale = lang && lang === 'en' ? en : vi
170
+
171
+ // const buddhistLocale: PickerLocale = {
172
+ // ...locale,
173
+ // lang: {
174
+ // ...locale.lang
175
+ //
176
+ // }
177
+ // }
178
+
179
+ // console.log('buddhistLocale', buddhistLocale)
180
+ const clickRef = useRef(null);
181
+ const searchInput = useRef(null);
182
+ const menuRef = useRef(null);
183
+ const viewportWidth = window.innerWidth;
184
+ const viewportHeight = window.innerHeight;
185
+ const defaultSelected = useMemo(() => {
186
+ return selectionSettings?.defaultSelectedRowKeys ?? [];
187
+ }, [selectionSettings?.defaultSelectedRowKeys]);
188
+ const [menuVisible, setMenuVisible] = React.useState(false);
189
+ const [selectedRowData, setSelectedRowData] = React.useState(null);
190
+ const [position, setPosition] = React.useState({
191
+ x: 0,
192
+ y: 0,
193
+ viewportWidth,
194
+ viewportHeight
195
+ });
196
+ // const [filters, setFilters] = React.useState<any[]>([])
197
+
198
+ const [selectedRowKeys, setSelectedRowKeys] = useState(defaultSelected);
199
+ const contextMenuItems = React.useMemo(() => {
200
+ if (typeof contextMenuHidden === "function" && propContextMenuItems && selectedRowData) {
201
+ const hiddenItems = contextMenuHidden({
202
+ rowInfo: {
203
+ rowData: selectedRowData
204
+ }
205
+ });
206
+ return propContextMenuItems.filter(item => !hiddenItems.includes(item?.key));
207
+ }
208
+ if (contextMenuHidden && typeof contextMenuHidden !== 'function' && propContextMenuItems) {
209
+ return propContextMenuItems.filter(item => !contextMenuHidden.includes(item?.key));
210
+ }
211
+ return propContextMenuItems;
212
+ }, [propContextMenuItems, contextMenuHidden, selectedRowData]);
213
+ useLayoutEffect(() => {
214
+ setMenuVisible(false);
215
+ }, []);
216
+ const handleSearch = (selectedKeys, confirm
217
+ // dataIndex: any
218
+ ) => {
219
+ confirm();
220
+ };
221
+ const renderFilter = (column, selectedKeys, setSelectedKeys, confirm, visible, searchValue, setSearchValue) => {
222
+ const type = getTypeFilter(column);
223
+ const dateFormat = getDatepickerFormat(column.type, column) ?? 'DD/MM/YYYY';
224
+ const dateRangeFormat = getDatepickerFormat(column.type, column) ?? 'DD/MM/YYYY';
225
+ switch (type) {
226
+ case 'Number':
227
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
228
+ className: 'mb-1'
229
+ }, /*#__PURE__*/React.createElement(NumericFormat, {
230
+ value: selectedKeys[0]
231
+ // thousandSeparator={checkThousandSeparator(thousandSeparator, decimalSeparator)}
232
+ // decimalSeparator={checkDecimalSeparator(thousandSeparator, decimalSeparator)}
233
+ // allowNegative={col.format && col.format.allowNegative === true}
234
+ ,
235
+ allowNegative: true,
236
+ customInput: Input,
237
+ className: ' rounded-0 input-element form-control',
238
+ onValueChange: values => {
239
+ // onChangeValueFilter(type, values.floatValue)
240
+ setSelectedKeys(values.floatValue || values.floatValue === 0 ? [values.floatValue] : []);
241
+ }
242
+ }))));
243
+ case 'NumberRange':
244
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
245
+ className: 'mb-1 d-flex flex-column gap-1'
246
+ }, /*#__PURE__*/React.createElement("div", {
247
+ style: {
248
+ marginBottom: 8
249
+ }
250
+ }, /*#__PURE__*/React.createElement(NumericFormat, {
251
+ value: selectedKeys[0]
252
+ // thousandSeparator={checkThousandSeparator(thousandSeparator, decimalSeparator)}
253
+ // decimalSeparator={checkDecimalSeparator(thousandSeparator, decimalSeparator)}
254
+ ,
255
+ allowNegative: true,
256
+ customInput: Input,
257
+ className: ' rounded-0 input-element form-control'
258
+ // onValueChange={(values: any) => {
259
+ // onChangeValueFilter(type, values.floatValue, 'min')
260
+ // }}
261
+ ,
262
+ placeholder: 'Min',
263
+ autoFocus: true
264
+ })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(NumericFormat, {
265
+ value: selectedKeys[1]
266
+ // thousandSeparator={checkThousandSeparator(thousandSeparator, decimalSeparator)}
267
+ // decimalSeparator={checkDecimalSeparator(thousandSeparator, decimalSeparator)}
268
+ ,
269
+ allowNegative: true,
270
+ customInput: Input,
271
+ className: ' rounded-0 input-element form-control',
272
+ onValueChange: () => {
273
+ // onChangeValueFilter(type, values.floatValue, 'max')
274
+ },
275
+ placeholder: 'Max'
276
+ })))));
277
+ case 'Date':
278
+ const dateValue = selectedKeys[0] ? convertDateToDayjs(new Date(selectedKeys[0]), dateFormat) : null;
279
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
280
+ className: 'mb-1'
281
+ }, /*#__PURE__*/React.createElement(DatePicker, {
282
+ format: {
283
+ format: dateFormat,
284
+ type: 'mask'
285
+ }
286
+ // locale={buddhistLocale}
287
+ ,
288
+ style: {
289
+ width: '100%',
290
+ height: '100%'
291
+ },
292
+ value: dateValue,
293
+ defaultValue: dateValue,
294
+ placeholder: column.placeholder,
295
+ onChange: (valueDate, dateString) => {
296
+ const newDateValue = dateString ? moment(convertDayjsToDate(dateString, dateFormat)).format() : null;
297
+ setSelectedKeys(newDateValue ? [newDateValue] : []);
298
+ }
299
+ }))));
300
+ case 'DateRange':
301
+ const dateRangeValue = [selectedKeys[0] ? convertDateToDayjs(new Date(selectedKeys[0]), dateRangeFormat) : '', selectedKeys[1] ? convertDateToDayjs(new Date(selectedKeys[1]), dateRangeFormat) : ''];
302
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
303
+ className: 'mb-1'
304
+ }, /*#__PURE__*/React.createElement(RangePicker, {
305
+ format: {
306
+ format: dateRangeFormat,
307
+ type: 'mask'
308
+ }
309
+ // defaultValue={dateRangeValue}
310
+ ,
311
+ value: dateRangeValue,
312
+ placeholder: ['Ngày bắt đầu', 'Ngày kết thúc'],
313
+ popupStyle: {
314
+ zIndex: 9999
315
+ },
316
+ onChange: (value, dateString) => {
317
+ const newDateRangeValue = dateString[0] ? [dateString[0] ? moment(convertDayjsToDate(dateString[0], dateRangeFormat)).format() : '', dateString[1] ? moment(convertDayjsToDate(dateString[1], dateRangeFormat)).format() : ''] : '';
318
+
319
+ // setSelectedKeys(newDateValue ? [newDateValue] : [])
320
+ setSelectedKeys(newDateRangeValue);
321
+ },
322
+ style: {
323
+ width: '100%'
324
+ }
325
+ // popupClassName={'adv-popup-container'}
326
+ // getPopupContainer={() => menuRef.current}
327
+ }))));
328
+ case 'Dropdown':
329
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
330
+ className: 'mb-1'
331
+ }, /*#__PURE__*/React.createElement(Select, {
332
+ options: translateOption(numberOperator, t),
333
+ style: {
334
+ width: '100%',
335
+ marginBottom: 8
336
+ },
337
+ value: selectedKeys[0],
338
+ onChange: val => {
339
+ // setOperatorKey(val)
340
+ setSelectedKeys(val ? [val] : []);
341
+ },
342
+ showSearch: true,
343
+ allowClear: true
344
+ }))));
345
+
346
+ // case 'DropTree':
347
+ // return (
348
+ // <Fragment>
349
+ // <div>
350
+ // {col.filterOption && col.filterOption.showOperator === false ? (
351
+ // ''
352
+ // ) : (
353
+ // <div className={'mb-1'}>
354
+ // <Select
355
+ // options={translateOption(numberOperator, t)}
356
+ // // options={t ? numberOperator.map((it: any) => ({...it, label: t(it.label)})) : numberOperator}
357
+ //
358
+ // classNamePrefix='select'
359
+ // className={`react-select`}
360
+ // value={translateOption(numberOperator, t).find(
361
+ // ope => ope.value === (operator ? operator : getDefaultOperator(col))
362
+ // )}
363
+ // onChange={(val: any) => {
364
+ // setCurrentFilter((prevState: any) => ({ ...prevState, operator: val.value }))
365
+ // }}
366
+ // />
367
+ // </div>
368
+ // )}
369
+ //
370
+ // <div className={'mb-1'}>
371
+ // <Input
372
+ // placeholder={'Nhập giá trị'}
373
+ // value={value}
374
+ // onChange={(val: any) => {
375
+ // onChangeValueFilter(type, val.value)
376
+ // }}
377
+ // />
378
+ // </div>
379
+ //
380
+ // <div className={'d-flex justify-content-end'}>
381
+ // <Button color='flat-primary' className={'me-1 be-button'} onClick={(e: any) => handleOnFilter(e)}>
382
+ // {t ? t('Filter') : 'Filter'}
383
+ // </Button>
384
+ // <Button color='flat-secondary' className={'be-button'} onClick={(e: any) => handleClearFilter(e)}>
385
+ // {t ? t('Delete') : 'Delete'}
386
+ // </Button>
387
+ // </div>
388
+ // </div>
389
+ // </Fragment>
390
+ // )
391
+ //
392
+ case 'Checkbox':
393
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
394
+ className: 'mb-1'
395
+ }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(CheckboxFilter
396
+ // column={column}
397
+ , {
398
+ locale: {
399
+ filterTitle: 'Chọn tất cả',
400
+ filterCheckall: 'Chọn tất cả'
401
+ },
402
+ selectedKeys: selectedKeys,
403
+ onSelect: setSelectedKeys,
404
+ options: [{
405
+ text: 'Joe',
406
+ value: 'Joe'
407
+ }, {
408
+ text: 'Jim',
409
+ value: 'Jim'
410
+ }, {
411
+ text: 'Green',
412
+ value: 'Green'
413
+ }, {
414
+ text: 'Black',
415
+ value: 'Black'
416
+ }, {
417
+ text: 'Category 1',
418
+ value: 'Category 1'
419
+ }, {
420
+ text: 'Yellow',
421
+ value: 'Yellow'
422
+ }, {
423
+ text: 'Pink',
424
+ value: 'Pink'
425
+ }, {
426
+ text: 'Category 2',
427
+ value: 'Category 666'
428
+ }, {
429
+ text: 'Category 2',
430
+ value: 'Category 555'
431
+ }, {
432
+ text: 'Category 2',
433
+ value: 'Category 55'
434
+ }, {
435
+ text: 'Category 2',
436
+ value: 'Category 44'
437
+ }, {
438
+ text: 'Category 2',
439
+ value: 'Category 33'
440
+ }, {
441
+ text: 'Category 2',
442
+ value: 'Category 22'
443
+ }, {
444
+ text: 'Category 2',
445
+ value: 'Category 11'
446
+ }
447
+ // {
448
+ // text: 'Submenu',
449
+ // value: 'Submenu',
450
+ // children: [
451
+ // {
452
+ // text: 'Green',
453
+ // value: 'Green',
454
+ // },
455
+ // {
456
+ // text: 'Black',
457
+ // value: 'Black',
458
+ // },
459
+ // ],
460
+ // },
461
+ ],
462
+ filterMultiple: true,
463
+ open: visible,
464
+ searchValue: searchValue,
465
+ setSearchValue: setSearchValue
466
+ })))));
467
+ case 'Text':
468
+ default:
469
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
470
+ className: 'mb-1'
471
+ }, /*#__PURE__*/React.createElement(Input, {
472
+ ref: searchInput,
473
+ placeholder: `Search ${column.key}`,
474
+ value: selectedKeys[0],
475
+ onChange: e => setSelectedKeys(e.target.value ? [e.target.value] : []),
476
+ onPressEnter: () => handleSearch(selectedKeys, confirm),
477
+ allowClear: true
478
+ }))));
479
+ }
480
+ };
481
+ const getColumnSearchProps = column => ({
482
+ filterDropdown: ({
483
+ setSelectedKeys,
484
+ selectedKeys,
485
+ confirm,
486
+ // clearFilters,
487
+ close,
488
+ setOperatorKey,
489
+ operatorKey,
490
+ visible,
491
+ searchValue,
492
+ setSearchValue
493
+ }) => {
494
+ // const typeFilter = getTypeFilter(columns as RcColumnType)
495
+ return /*#__PURE__*/React.createElement("div", {
496
+ style: {
497
+ padding: 8,
498
+ minWidth: 275
499
+ },
500
+ onKeyDown: e => e.stopPropagation()
501
+ }, (column.showOperator !== false || column.typeFilter !== 'DateRange' && column.typeFilter !== 'NumberRange') && /*#__PURE__*/React.createElement("div", {
502
+ className: 'mb-1'
503
+ }, /*#__PURE__*/React.createElement(Select, {
504
+ options: translateOption(numberOperator, t),
505
+ style: {
506
+ width: '100%',
507
+ marginBottom: 8
508
+ },
509
+ value: operatorKey,
510
+ onChange: val => {
511
+ setOperatorKey(val);
512
+ }
513
+ })), /*#__PURE__*/React.createElement("div", {
514
+ style: {
515
+ marginBottom: 8
516
+ }
517
+ }, renderFilter(column, selectedKeys, setSelectedKeys, confirm, visible, searchValue, setSearchValue)), /*#__PURE__*/React.createElement("div", {
518
+ style: {
519
+ justifyContent: 'end',
520
+ width: '100%'
521
+ }
522
+ }, /*#__PURE__*/React.createElement(Button, {
523
+ type: "primary",
524
+ onClick: () => {
525
+ confirm({
526
+ closeDropdown: false
527
+ });
528
+ handleSearch(selectedKeys, confirm);
529
+ },
530
+ icon: /*#__PURE__*/React.createElement(SearchOutlined, null),
531
+ size: "small",
532
+ style: {
533
+ width: 90
534
+ }
535
+ }, "Filter"), /*#__PURE__*/React.createElement(Button, {
536
+ type: "link",
537
+ size: "small",
538
+ onClick: () => {
539
+ close();
540
+ }
541
+ }, "close")));
542
+ },
543
+ // filterIcon: (filtered: boolean) => (
544
+ // <SearchOutlined style={{ color: filtered ? '#1677ff' : undefined }} />
545
+ // ),
546
+
547
+ onFilter: (value, record) => {
548
+ // @ts-ignore
549
+ return record[column.dataIndex];
550
+ },
551
+ filterDropdownProps: {
552
+ onOpenChange(open) {
553
+ if (open) {
554
+ setTimeout(() => searchInput.current?.select(), 100);
555
+ }
556
+ }
557
+
558
+ // trigger: ['hover']
559
+ }
560
+ });
561
+ const renderContent = column => value => {
562
+ switch (column?.type) {
563
+ case 'number':
564
+ const thousandSeparator = column.format?.thousandSeparator ? column.format?.thousandSeparator : format?.thousandSeparator;
565
+ const decimalSeparator = column.format?.decimalSeparator ? column.format?.decimalSeparator : format?.decimalSeparator;
566
+ const dec = column.format?.decimalScale || column.format?.decimalScale === 0 ? column.format?.decimalScale : format?.decimalScale;
567
+ const content = !isEmpty(value) ? dec || dec === 0 ? parseFloat(Number(value).toFixed(dec)).toString() : value.toString() : '0';
568
+ const numericFormatProps = {
569
+ thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator),
570
+ decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator),
571
+ allowNegative: (column.format?.allowNegative ? column.format?.allowNegative : format?.allowNegative) ?? true,
572
+ prefix: column.format?.prefix ? column.format?.prefix : format?.prefix,
573
+ suffix: column.format?.suffix ? column.format?.suffix : format?.suffix,
574
+ decimalScale: column.format?.decimalScale || column.format?.decimalScale === 0 ? column.format?.decimalScale : format?.decimalScale,
575
+ fixedDecimalScale: (column.format?.fixedDecimalScale ? column.format?.fixedDecimalScale : format?.fixedDecimalScale) ?? false
576
+ };
577
+ return !isEmpty(content) ? numericFormatter(content, numericFormatProps) : '';
578
+ case 'date':
579
+ return value ? dayjs(value).format(column.format?.dateFormat ?? format?.dateFormat ?? 'DD/MM/YYYY') : '';
580
+ case 'time':
581
+ return value ? value : '';
582
+ case 'year':
583
+ const year = value ? moment(value).format('yyyy') : '';
584
+ return /*#__PURE__*/React.createElement(Fragment, null, year);
585
+ case 'datetime':
586
+ return value ? moment(value).format(column.format?.datetimeFormat ?? format?.datetimeFormat ?? 'DD/MM/YYYY HH:mm') : '';
587
+ case 'boolean':
588
+ return value ? 'true' : 'false';
589
+ case 'color':
590
+ return /*#__PURE__*/React.createElement(Fragment, null, isColor(value) ? /*#__PURE__*/React.createElement("div", {
591
+ className: 'w-100 h-100',
592
+ style: {
593
+ backgroundColor: value,
594
+ border: '1px solid #f0f0f0'
595
+ }
596
+ }) : '');
597
+ case 'checkbox':
598
+ return /*#__PURE__*/React.createElement(Input, {
599
+ checked: !!content,
600
+ readOnly: true,
601
+ type: "checkbox"
602
+ });
603
+ case 'file':
604
+ const nameFile = typeof value === 'object' && !Array.isArray(value) ? value.name : Array.isArray(value) ? value.map(it => typeof it === 'object' ? it.name : it).filter(Boolean).join(", ") : '';
605
+ return value ? nameFile : '';
606
+ default:
607
+ if (Array.isArray(value)) {
608
+ return value.join(', ');
609
+ }
610
+ return value;
611
+ }
612
+ };
613
+ const addIsFilter = columns => {
614
+ return columns.map(column => {
615
+ // @ts-ignore
616
+ if (!column?.dataIndex && !column.key) {
617
+ return column;
618
+ }
619
+ // @ts-ignore
620
+ if (column?.children && column.children.length > 0) {
621
+ return {
622
+ ...column,
623
+ // @ts-ignore
624
+ children: addIsFilter(column.children) // Xử lý đệ quy cho cấp con
625
+ };
626
+ }
627
+ // @ts-ignore
628
+ if (column?.dataIndex === 'index' || column.allowFiltering === false) {
629
+ return {
630
+ ...column
631
+ };
632
+ }
633
+ return {
634
+ ...getColumnSearchProps(column),
635
+ render: renderContent(column),
636
+ ...column
637
+ };
638
+ });
639
+ };
640
+ const tmpColumns = useMemo(() => {
641
+ // return addIsFilter(defaultColumns ?? [])
642
+ return addIsFilter(defaultColumns ? [Table.SELECTION_COLUMN, ...defaultColumns] : []);
643
+ }, [defaultColumns]);
644
+ const [columns, setColumns] = useState(tmpColumns ?? []);
645
+ const handleResize = indexPath => (e, {
646
+ size
647
+ }) => {
648
+ const updateColumns = (cols, path) => {
649
+ const [currentIndex, ...restPath] = path;
650
+ return cols.map((col, idx) => {
651
+ if (idx === currentIndex) {
652
+ if (restPath.length === 0) {
653
+ // Cập nhật width của cột cuối cùng trong path
654
+ // return { ...col, width: size.width }
655
+
656
+ // Kiểm tra minWidth trước khi cập nhật width
657
+ if (col.minWidth && size.width < col.minWidth) {
658
+ e.preventDefault();
659
+ return col; // Không cập nhật nếu nhỏ hơn minWidth
660
+ }
661
+
662
+ // Kiểm tra minWidth trước khi cập nhật width
663
+ if (col.maxWidth && size.width > col.maxWidth) {
664
+ e.preventDefault();
665
+ return col; // Không cập nhật nếu nhỏ hơn minWidth
666
+ }
667
+ return {
668
+ ...col,
669
+ width: size.width
670
+ };
671
+ } else if (col.children) {
672
+ // Tiếp tục cập nhật các cấp con
673
+ return {
674
+ ...col,
675
+ children: updateColumns(col.children, restPath)
676
+ };
677
+ }
678
+ }
679
+ // e.preventDefault()
680
+ return col;
681
+ });
682
+ };
683
+ setColumns(prevColumns => updateColumns(prevColumns, indexPath));
684
+ };
685
+ const addResizeHandlers = (cols, parentPath = []) => {
686
+ return cols.map((col, index) => {
687
+ const currentPath = [...parentPath, index];
688
+ if (!col?.dataIndex && !col.key) {
689
+ return col;
690
+ }
691
+ if (col.children) {
692
+ return {
693
+ ...col,
694
+ ellipsis: col.ellipsis !== true,
695
+ children: addResizeHandlers(col.children, currentPath)
696
+ };
697
+ }
698
+ return {
699
+ ...col,
700
+ ellipsis: col.ellipsis !== true,
701
+ onHeaderCell: () => ({
702
+ width: col.width,
703
+ onResize: handleResize(currentPath)
704
+ })
705
+ };
706
+ });
707
+ };
708
+
709
+ // const resizableColumns = createResizableColumns(columns)
710
+
711
+ // const resizableColumns = addResizeHandlers(columns)
712
+ const resizableColumns = useMemo(() => {
713
+ return addResizeHandlers(columns);
714
+ }, [columns]);
715
+
716
+ // const handleReset = (clearFilters: () => void) => {
717
+ // clearFilters()
718
+ // }
719
+
720
+ // const handleChangeOperator = (val: IFilterOperator) => {
721
+ // setOperator(val)
722
+ // }
723
+
724
+ const onContextMenu = data => event => {
725
+ event.preventDefault(); // Ngăn chặn menu mặc định của trình duyệt
726
+
727
+ setSelectedRowData(data);
728
+ contextMenuOpen?.({
729
+ rowInfo: {
730
+ rowData: data
731
+ },
732
+ event
733
+ });
734
+ setMenuVisible(true);
735
+
736
+ // Đợi DOM cập nhật và lấy kích thước menu
737
+ setTimeout(() => {
738
+ const menuElement = menuRef.current; // Lấy menu từ DOM
739
+ const menuWidth = menuElement?.offsetWidth || 200; // Mặc định 200px nếu chưa render
740
+ const menuHeight = menuElement?.offsetHeight; // Mặc định 450px nếu chưa render
741
+
742
+ // Điều chỉnh vị trí menu
743
+ let x = event.clientX;
744
+ let y = event.clientY;
745
+ if (x + menuWidth > viewportWidth) {
746
+ x = x - menuWidth - 10; // Cách cạnh phải 10px
747
+ }
748
+ if (y + menuHeight > viewportHeight) {
749
+ if (y < menuHeight) {
750
+ y = 10;
751
+ } else {
752
+ y = y - 10 - menuHeight; // Cách cạnh dưới 10px
753
+ }
754
+ }
755
+ setPosition(prevState => ({
756
+ ...prevState,
757
+ x,
758
+ y
759
+ }));
760
+ }, 100);
761
+ if (!menuVisible) {
762
+ document.addEventListener(`click`, function onClickOutside(e) {
763
+ const element = e.target;
764
+ const menuContainer = document.querySelector(".popup-context-menu");
765
+ const isInsideContainer = element.closest(".popup-context-menu") && menuContainer;
766
+ if (isInsideContainer) {
767
+ return;
768
+ }
769
+ setMenuVisible(false);
770
+ document.removeEventListener(`click`, onClickOutside);
771
+ });
772
+ }
773
+ };
774
+ const handleRowClick = () => {
775
+ if (clickRef.current) return;
776
+
777
+ // @ts-ignore
778
+ clickRef.current = setTimeout(() => {
779
+ // console.log("Single Click:", record);
780
+ clickRef.current = null;
781
+ }, 250);
782
+ };
783
+ const handleRowDoubleClick = (record, index) => e => {
784
+ if (clickRef.current) {
785
+ clearTimeout(clickRef.current);
786
+ clickRef.current = null;
787
+ }
788
+ recordDoubleClick?.({
789
+ e,
790
+ rowIndex: index,
791
+ rowData: record
792
+ });
793
+ };
794
+ const onSelectChange = (keys, selectedRows, info, selectedRow) => {
795
+ if (info.type === 'all') {
796
+ // setSelectedRowKeys(keys)
797
+ rowSelected?.({
798
+ selected: selectedRows,
799
+ type: 'rowSelected',
800
+ rowData: {}
801
+ });
802
+ } else {
803
+ if (selectionSettings?.type === 'multiple') {
804
+ // setSelectedRowKeys(keys)
805
+ rowSelected?.({
806
+ selected: selectedRows,
807
+ type: 'rowSelected',
808
+ rowData: selectedRow
809
+ });
810
+ } else {
811
+ // @ts-ignore
812
+ setSelectedRowKeys([selectedRow[rowKey]]);
813
+ rowSelected?.({
814
+ selected: [selectedRow],
815
+ type: 'rowSelected',
816
+ rowData: selectedRow
817
+ });
818
+ }
819
+ }
820
+ };
821
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(ContextMenu, {
822
+ open: menuVisible,
823
+ pos: position,
824
+ setOpen: setMenuVisible,
825
+ menuRef: menuRef,
826
+ contextMenuItems: contextMenuItems,
827
+ contextMenuClick: contextMenuClick,
828
+ rowData: selectedRowData
829
+ }), /*#__PURE__*/React.createElement(Table, _extends({}, rest, {
830
+ dataSource: dataSource
831
+ // className={styles.customTable}
832
+ ,
833
+ className: classNames('', {
834
+ 'table-none-column-select': selectionSettings?.mode === undefined && selectionSettings?.type !== 'multiple'
835
+ }, styles.customTable),
836
+ bordered: true,
837
+ virtual: virtual,
838
+ columns: resizableColumns,
839
+ rowKey: rowKey,
840
+ rowHoverable: true,
841
+ components: {
842
+ header: {
843
+ cell: ResizableTitle
844
+ }
845
+ },
846
+ onRow: (data, index) => {
847
+ return {
848
+ onDoubleClick: handleRowDoubleClick(data, index),
849
+ // onClick: handleRowClick(data),
850
+ onClick: handleRowClick,
851
+ onContextMenu: onContextMenu(data)
852
+ };
853
+ },
854
+ rowSelection: {
855
+ type: selectionSettings?.mode === 'checkbox' || selectionSettings?.type === 'multiple' ? 'checkbox' : "radio",
856
+ // columnWidth: selectionSettings?.mode === 'checkbox' || selectionSettings?.mode === 'radio' || selectionSettings?.type === 'multiple' ? 50 : 0.000001,
857
+ columnWidth: !selectionSettings?.mode ? 0.0000001 : selectionSettings?.columnWidth ?? 50,
858
+ onChange: onSelectChange,
859
+ // onSelect: (record, selected, selectedRows, nativeEvent)=> {
860
+ // // console.log(record, selected, selectedRows, nativeEvent)
861
+ // },
862
+
863
+ selectedRowKeys: selectionSettings?.mode === 'checkbox' && selectionSettings?.type === 'single' ? selectedRowKeys : undefined,
864
+ defaultSelectedRowKeys: selectionSettings?.defaultSelectedRowKeys,
865
+ preserveSelectedRowKeys: true,
866
+ ...rowSelection,
867
+ // hideSelectAll: !selectionSettings?.type || selectionSettings?.type === 'single' || selectionSettings?.mode === 'radio' ? true : rowSelection?.hideSelectAll ?? selectionSettings?.type !== 'multiple',
868
+ hideSelectAll: !selectionSettings?.type || selectionSettings?.type === 'single' || selectionSettings?.mode === 'radio' ? true : selectionSettings?.hideSelectAll ?? selectionSettings?.type !== 'multiple'
869
+ },
870
+ onScroll: () => {
871
+ setMenuVisible(false);
872
+ },
873
+ title: () => {
874
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, "Header"), toolbarItems && /*#__PURE__*/React.createElement("div", {
875
+ style: {
876
+ display: 'flex',
877
+ justifyContent: 'space-between'
878
+ }
879
+ }, /*#__PURE__*/React.createElement(Toolbar, {
880
+ style: {
881
+ width: '100%'
882
+ },
883
+ items: toolbarItems,
884
+ mode: 'responsive'
885
+ // mode={'scroll'}
886
+ ,
887
+ onClick: val => {
888
+ console.log(val);
889
+ }
890
+ }), showColumnChoose && /*#__PURE__*/React.createElement(ColumnsChoose, {
891
+ columns: columns,
892
+ setColumns: setColumns
893
+ }), /*#__PURE__*/React.createElement("div", null)));
894
+ },
895
+ summary: () => /*#__PURE__*/React.createElement(Table.Summary, {
896
+ fixed: true
897
+ }, /*#__PURE__*/React.createElement(Table.Summary.Row, null, flatColumns(tmpColumns).filter(col => col.hidden !== true).map((col, index) => {
898
+ const thousandSeparator = col.format?.thousandSeparator ? col.format?.thousandSeparator : format?.thousandSeparator;
899
+ const decimalSeparator = col.format?.decimalSeparator ? col.format?.decimalSeparator : format?.decimalSeparator;
900
+ const dec = col.format?.decimalScale || col.format?.decimalScale === 0 ? col.format?.decimalScale : format?.decimalScale;
901
+ const sumValue = col.type === 'number' ? sumDataByField(dataSource, col?.key) : 0;
902
+ const value = !isEmpty(sumValue) ? dec || dec === 0 ? parseFloat(Number(sumValue).toFixed(dec)).toString() : sumValue.toString() : '0';
903
+ const cellValue = col.type === 'number' && col.isSummary !== false ? value : '';
904
+ const numericFormatProps = {
905
+ thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator),
906
+ decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator),
907
+ allowNegative: (col.format?.allowNegative ? col.format?.allowNegative : format?.allowNegative) ?? false,
908
+ prefix: col.format?.prefix ? col.format?.prefix : format?.prefix,
909
+ suffix: col.format?.suffix ? col.format?.suffix : format?.suffix,
910
+ decimalScale: dec,
911
+ fixedDecimalScale: (col.format?.fixedDecimalScale ? col.format?.fixedDecimalScale : format?.fixedDecimalScale) ?? false
912
+ };
913
+ return (
914
+ /*#__PURE__*/
915
+ // <Table.Summary.Cell index={index}>{col.summaryTemplate ? col.summaryTemplate(cellValue, (col.key || col.dataIndex) as string) : numericFormatter(cellValue, numericFormatProps)}</Table.Summary.Cell>
916
+ React.createElement(Table.Summary.Cell, {
917
+ key: index,
918
+ index: index
919
+ }, col.summaryTemplate ? col.summaryTemplate(cellValue, col.key) : numericFormatter(cellValue, numericFormatProps))
920
+ );
921
+ }))),
922
+ onFilter: val => {
923
+ onFilter?.(convertFilters(val));
924
+ }
925
+ })));
926
+ };
927
+ export default GridTable;