@addev-be/ui 0.2.6 → 0.2.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/assets/icons/arrow-down-1-9.svg +1 -0
- package/assets/icons/arrow-down-big-small.svg +1 -0
- package/assets/icons/arrow-up-9-1.svg +1 -0
- package/assets/icons/arrow-up-big-small.svg +1 -0
- package/assets/icons/chevron-down.svg +1 -0
- package/assets/icons/ellipsis.svg +1 -0
- package/assets/icons/sigma.svg +1 -0
- package/assets/icons/table-footer-slash.svg +5 -0
- package/assets/icons/table-footer.svg +4 -0
- package/assets/icons/table.svg +1 -0
- package/assets/icons/tally.svg +1 -0
- package/assets/icons/x-bar.svg +4 -0
- package/dist/Icons.d.ts +13 -1
- package/dist/Icons.js +25 -1
- package/dist/components/data/AdvancedRequestDataGrid/index.js +3 -3
- package/dist/components/data/DataGrid/DataGridColumnsModal/hooks.js +2 -1
- package/dist/components/data/DataGrid/DataGridFilterMenu/index.js +85 -7
- package/dist/components/data/DataGrid/DataGridFilterMenu/styles.d.ts +3 -9
- package/dist/components/data/DataGrid/DataGridFilterMenu/styles.js +10 -37
- package/dist/components/data/DataGrid/DataGridFooter.d.ts +1 -1
- package/dist/components/data/DataGrid/DataGridFooter.js +35 -12
- package/dist/components/data/DataGrid/DataGridHeader.js +1 -1
- package/dist/components/data/DataGrid/DataGridHeaderCell.js +6 -22
- package/dist/components/data/DataGrid/helpers/columns.d.ts +1 -1
- package/dist/components/data/DataGrid/helpers/columns.js +71 -16
- package/dist/components/data/DataGrid/hooks/useDataGrid.d.ts +1 -1
- package/dist/components/data/DataGrid/hooks/useDataGrid.js +60 -30
- package/dist/components/data/DataGrid/hooks/useDataGridCopy.d.ts +2 -2
- package/dist/components/data/DataGrid/hooks/useDataGridCopy.js +41 -39
- package/dist/components/data/DataGrid/index.d.ts +4 -2
- package/dist/components/data/DataGrid/index.js +22 -12
- package/dist/components/data/DataGrid/styles.d.ts +8 -4
- package/dist/components/data/DataGrid/styles.js +27 -17
- package/dist/components/data/DataGrid/types.d.ts +8 -1
- package/dist/components/data/SqlRequestDataGrid/helpers/columns.d.ts +1 -1
- package/dist/components/data/SqlRequestDataGrid/helpers/columns.js +24 -11
- package/dist/components/data/SqlRequestDataGrid/index.js +105 -33
- package/dist/components/ui/ContextMenu/index.d.ts +11 -0
- package/dist/components/ui/ContextMenu/index.js +58 -0
- package/dist/components/ui/ContextMenu/styles.d.ts +18 -0
- package/dist/components/ui/ContextMenu/styles.js +56 -0
- package/dist/services/advancedRequests.d.ts +1 -1
- package/dist/services/sqlRequests.d.ts +9 -4
- package/dist/services/sqlRequests.js +1 -0
- package/package.json +1 -1
- package/src/Icons.tsx +24 -0
- package/src/components/data/AdvancedRequestDataGrid/index.tsx +3 -5
- package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +2 -1
- package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +173 -9
- package/src/components/data/DataGrid/DataGridFilterMenu/styles.ts +13 -64
- package/src/components/data/DataGrid/DataGridFooter.tsx +20 -22
- package/src/components/data/DataGrid/DataGridHeader.tsx +5 -5
- package/src/components/data/DataGrid/DataGridHeaderCell.tsx +3 -38
- package/src/components/data/DataGrid/helpers/columns.tsx +98 -7
- package/src/components/data/DataGrid/hooks/useDataGrid.tsx +58 -17
- package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +35 -30
- package/src/components/data/DataGrid/index.tsx +21 -14
- package/src/components/data/DataGrid/styles.ts +28 -7
- package/src/components/data/DataGrid/types.ts +20 -1
- package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +38 -3
- package/src/components/data/SqlRequestDataGrid/index.tsx +116 -21
- package/src/components/ui/ContextMenu/index.tsx +73 -0
- package/src/components/ui/ContextMenu/styles.ts +115 -0
- package/src/services/advancedRequests.ts +1 -1
- package/src/services/sqlRequests.ts +16 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,15 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
import * as styles from './styles';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
ArrowDownAZIcon,
|
|
8
|
-
ArrowUpZAIcon,
|
|
9
|
-
ArrowsUpDownIcon,
|
|
10
|
-
FilterFullIcon,
|
|
11
|
-
FilterIcon,
|
|
12
|
-
} from '../../../Icons';
|
|
13
6
|
import { MouseEvent, useCallback, useMemo, useRef, useState } from 'react';
|
|
14
7
|
|
|
8
|
+
import { ChevronDownIcon } from '../../../Icons';
|
|
15
9
|
import { DataGridFilterMenu } from './DataGridFilterMenu';
|
|
16
10
|
import { DataGridHeaderCellProps } from './types';
|
|
17
11
|
import { Dropdown } from '../../layout';
|
|
@@ -29,33 +23,12 @@ export const DataGridHeaderCell = <R,>({
|
|
|
29
23
|
const contextValue = useDataGridContext(context);
|
|
30
24
|
const {
|
|
31
25
|
filters = {},
|
|
32
|
-
sorts = {},
|
|
33
|
-
setSorts,
|
|
34
26
|
setColumnWidth,
|
|
35
27
|
saveSettings,
|
|
36
28
|
headerColor,
|
|
37
29
|
} = contextValue;
|
|
38
30
|
const filterButtonRef = useRef<HTMLButtonElement | null>(null);
|
|
39
31
|
|
|
40
|
-
/** SORTING */
|
|
41
|
-
const SortIcon = sorts[columnKey]
|
|
42
|
-
? sorts[columnKey] === 'desc'
|
|
43
|
-
? ArrowUpZAIcon
|
|
44
|
-
: ArrowDownAZIcon
|
|
45
|
-
: ArrowsUpDownIcon;
|
|
46
|
-
|
|
47
|
-
const onSortButtonClicked = useCallback(
|
|
48
|
-
(columnKey: string) => {
|
|
49
|
-
const sort = sorts[columnKey];
|
|
50
|
-
if (!sort || sort === 'desc') {
|
|
51
|
-
setSorts({ [columnKey]: 'asc' });
|
|
52
|
-
} else {
|
|
53
|
-
setSorts({ [columnKey]: 'desc' });
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
[setSorts, sorts]
|
|
57
|
-
);
|
|
58
|
-
|
|
59
32
|
/** RESIZING */
|
|
60
33
|
|
|
61
34
|
const [isResizing, setIsResizing] = useState(false);
|
|
@@ -97,7 +70,7 @@ export const DataGridHeaderCell = <R,>({
|
|
|
97
70
|
$sourceRect={filterButtonRect}
|
|
98
71
|
onClose={() => setIsFilterDropdownVisible(false)}
|
|
99
72
|
$width={320}
|
|
100
|
-
$height={[
|
|
73
|
+
$height={[250, 400]}
|
|
101
74
|
$autoPositionX
|
|
102
75
|
>
|
|
103
76
|
<DataGridFilterMenu
|
|
@@ -129,20 +102,12 @@ export const DataGridHeaderCell = <R,>({
|
|
|
129
102
|
>
|
|
130
103
|
{filterDropdown}
|
|
131
104
|
<span>{column.name}</span>
|
|
132
|
-
{!!column.sortGetter && (
|
|
133
|
-
<IconButton
|
|
134
|
-
color={headerColor}
|
|
135
|
-
size="small"
|
|
136
|
-
icon={SortIcon}
|
|
137
|
-
onClick={() => onSortButtonClicked?.(columnKey)}
|
|
138
|
-
/>
|
|
139
|
-
)}
|
|
140
105
|
{!!column.filter && (
|
|
141
106
|
<IconButton
|
|
142
107
|
size="small"
|
|
143
108
|
className={hasFilters ? 'danger' : ''}
|
|
144
109
|
ref={filterButtonRef}
|
|
145
|
-
icon={
|
|
110
|
+
icon={ChevronDownIcon}
|
|
146
111
|
color={hasFilters ? 'danger' : headerColor}
|
|
147
112
|
onClick={onFilterButtonClicked}
|
|
148
113
|
/>
|
|
@@ -9,11 +9,15 @@ import {
|
|
|
9
9
|
import { numberFilter, textFilter } from './filters';
|
|
10
10
|
|
|
11
11
|
import moment from 'moment';
|
|
12
|
+
import { repeat } from 'lodash';
|
|
12
13
|
|
|
13
14
|
export const isColumnVisible = <R,>(
|
|
14
15
|
obj: DataGridColumn<R> | DataGridSettings
|
|
15
16
|
): boolean => obj?.order !== -1;
|
|
16
17
|
|
|
18
|
+
const buildExcelFormat = (decimals = 2, suffix = '') =>
|
|
19
|
+
`#0${decimals > 0 ? `.${repeat('0', decimals)}` : ''}${suffix}`;
|
|
20
|
+
|
|
17
21
|
export const textColumn = <R extends Record<string, any>>(
|
|
18
22
|
key: string,
|
|
19
23
|
title: string,
|
|
@@ -24,6 +28,7 @@ export const textColumn = <R extends Record<string, any>>(
|
|
|
24
28
|
render: (row) => row[key] ?? '',
|
|
25
29
|
getter: (row) => row[key] ?? '',
|
|
26
30
|
sortGetter: (row) => row[key] ?? '',
|
|
31
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
27
32
|
filter: textFilter(key),
|
|
28
33
|
...options,
|
|
29
34
|
},
|
|
@@ -46,6 +51,7 @@ export const mailColumn = <R extends Record<string, any>>(
|
|
|
46
51
|
),
|
|
47
52
|
getter: (row) => row[key] ?? '',
|
|
48
53
|
sortGetter: (row) => row[key] ?? '',
|
|
54
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
49
55
|
filter: textFilter(key),
|
|
50
56
|
...options,
|
|
51
57
|
},
|
|
@@ -68,6 +74,7 @@ export const phoneColumn = <R extends Record<string, any>>(
|
|
|
68
74
|
),
|
|
69
75
|
getter: (row) => row[key] ?? '',
|
|
70
76
|
sortGetter: (row) => row[key] ?? '',
|
|
77
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
71
78
|
filter: textFilter(key),
|
|
72
79
|
...options,
|
|
73
80
|
},
|
|
@@ -83,6 +90,7 @@ export const dateColumn = <R extends Record<string, any>>(
|
|
|
83
90
|
render: (row) => moment(row[key]).format('DD/MM/YYYY') ?? '',
|
|
84
91
|
getter: (row) => row[key] ?? '',
|
|
85
92
|
sortGetter: (row) => row[key] ?? '',
|
|
93
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
86
94
|
filter: textFilter(key),
|
|
87
95
|
...options,
|
|
88
96
|
},
|
|
@@ -98,6 +106,7 @@ export const monthColumn = <R extends Record<string, any>>(
|
|
|
98
106
|
render: (row) => (row[key] ? `${row[key]} mois ` : ''),
|
|
99
107
|
getter: (row) => row[key] ?? '',
|
|
100
108
|
sortGetter: (row) => row[key] ?? '',
|
|
109
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
101
110
|
filter: textFilter(key),
|
|
102
111
|
...options,
|
|
103
112
|
},
|
|
@@ -115,11 +124,33 @@ export const numberColumn = <R extends Record<string, any>>(
|
|
|
115
124
|
excelFormatter: () => '#',
|
|
116
125
|
getter: (row) => row[key] ?? '',
|
|
117
126
|
sortGetter: (row) => row[key] ?? '',
|
|
127
|
+
footer: {
|
|
128
|
+
sum: (_, filteredRows) =>
|
|
129
|
+
formatNumber(
|
|
130
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
131
|
+
decimals
|
|
132
|
+
),
|
|
133
|
+
average: (_, filteredRows) =>
|
|
134
|
+
formatNumber(
|
|
135
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
136
|
+
(filteredRows.length || 1),
|
|
137
|
+
decimals
|
|
138
|
+
),
|
|
139
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
140
|
+
max: (_, filteredRows) =>
|
|
141
|
+
formatNumber(
|
|
142
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
143
|
+
decimals
|
|
144
|
+
),
|
|
145
|
+
min: (_, filteredRows) =>
|
|
146
|
+
formatNumber(
|
|
147
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
148
|
+
decimals
|
|
149
|
+
),
|
|
150
|
+
},
|
|
118
151
|
filter: {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
values: [0],
|
|
122
|
-
getter: (value) => value ?? 0,
|
|
152
|
+
...numberFilter(key),
|
|
153
|
+
renderer: (value) => formatNumber(value, decimals) ?? '',
|
|
123
154
|
},
|
|
124
155
|
...options,
|
|
125
156
|
},
|
|
@@ -134,10 +165,37 @@ export const moneyColumn = <R extends Record<string, any>>(
|
|
|
134
165
|
[key]: {
|
|
135
166
|
name: title,
|
|
136
167
|
render: (row) => formatMoney(row[key], decimals) ?? '',
|
|
137
|
-
excelFormatter: () => '
|
|
168
|
+
excelFormatter: () => buildExcelFormat(decimals, ' €'),
|
|
138
169
|
getter: (row) => row[key] ?? '',
|
|
139
170
|
sortGetter: (row) => row[key] ?? '',
|
|
140
|
-
filter:
|
|
171
|
+
filter: {
|
|
172
|
+
...numberFilter(key),
|
|
173
|
+
renderer: (value) => formatMoney(value, decimals) ?? '',
|
|
174
|
+
},
|
|
175
|
+
footer: {
|
|
176
|
+
sum: (_, filteredRows) =>
|
|
177
|
+
formatMoney(
|
|
178
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
179
|
+
decimals
|
|
180
|
+
),
|
|
181
|
+
average: (_, filteredRows) =>
|
|
182
|
+
formatMoney(
|
|
183
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
184
|
+
(filteredRows.length || 1),
|
|
185
|
+
decimals
|
|
186
|
+
),
|
|
187
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
188
|
+
max: (_, filteredRows) =>
|
|
189
|
+
formatMoney(
|
|
190
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
191
|
+
decimals
|
|
192
|
+
),
|
|
193
|
+
min: (_, filteredRows) =>
|
|
194
|
+
formatMoney(
|
|
195
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
196
|
+
decimals
|
|
197
|
+
),
|
|
198
|
+
},
|
|
141
199
|
...options,
|
|
142
200
|
},
|
|
143
201
|
});
|
|
@@ -145,15 +203,40 @@ export const moneyColumn = <R extends Record<string, any>>(
|
|
|
145
203
|
export const percentageColumn = <R extends Record<string, any>>(
|
|
146
204
|
key: string,
|
|
147
205
|
title: string,
|
|
206
|
+
decimals = 2,
|
|
148
207
|
options?: Partial<DataGridColumn<R>>
|
|
149
208
|
): DataGridColumns<R> => ({
|
|
150
209
|
[key]: {
|
|
151
210
|
name: title,
|
|
152
211
|
render: (row) => formatPercentage(row[key]) ?? '',
|
|
153
|
-
excelFormatter: () =>
|
|
212
|
+
excelFormatter: () => buildExcelFormat(decimals),
|
|
154
213
|
getter: (row) => row[key] ?? '',
|
|
155
214
|
sortGetter: (row) => row[key] ?? '',
|
|
156
215
|
filter: numberFilter(key),
|
|
216
|
+
footer: {
|
|
217
|
+
average: (_, filteredRows) =>
|
|
218
|
+
formatNumber(
|
|
219
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
220
|
+
(filteredRows.length || 1),
|
|
221
|
+
decimals
|
|
222
|
+
),
|
|
223
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
224
|
+
max: (_, filteredRows) =>
|
|
225
|
+
formatNumber(
|
|
226
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
227
|
+
decimals
|
|
228
|
+
),
|
|
229
|
+
min: (_, filteredRows) =>
|
|
230
|
+
formatNumber(
|
|
231
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
232
|
+
decimals
|
|
233
|
+
),
|
|
234
|
+
sum: (_, filteredRows) =>
|
|
235
|
+
formatNumber(
|
|
236
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
237
|
+
decimals
|
|
238
|
+
),
|
|
239
|
+
},
|
|
157
240
|
...options,
|
|
158
241
|
},
|
|
159
242
|
});
|
|
@@ -174,6 +257,13 @@ export const checkboxColumn = <R extends Record<string, any>>(
|
|
|
174
257
|
getter: (row) => row[key] ?? '',
|
|
175
258
|
sortGetter: (row) => row[key] ?? '',
|
|
176
259
|
filter: numberFilter(key),
|
|
260
|
+
footer: {
|
|
261
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
262
|
+
checked: (_, filteredRows) =>
|
|
263
|
+
`${filteredRows.filter((row) => !!row[key]).length} cochés`,
|
|
264
|
+
unchecked: (_, filteredRows) =>
|
|
265
|
+
`${filteredRows.filter((row) => !row[key]).length} décochés`,
|
|
266
|
+
},
|
|
177
267
|
...options,
|
|
178
268
|
},
|
|
179
269
|
});
|
|
@@ -191,6 +281,7 @@ export const colorColumn = <R extends Record<string, any>>(
|
|
|
191
281
|
getter: (row) => row[key] ?? '',
|
|
192
282
|
sortGetter: (row) => row[key] ?? '',
|
|
193
283
|
filter: textFilter(key),
|
|
284
|
+
footer: (rows) => `${rows.length} éléments`,
|
|
194
285
|
...options,
|
|
195
286
|
},
|
|
196
287
|
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DataGridContext,
|
|
8
8
|
DataGridContextProps,
|
|
9
9
|
DataGridFilters,
|
|
10
|
+
DataGridFooterFunction,
|
|
10
11
|
DataGridProps,
|
|
11
12
|
DataGridSort,
|
|
12
13
|
} from '../types';
|
|
@@ -26,7 +27,8 @@ import { useDataGridSettings } from './useDataGridSettings';
|
|
|
26
27
|
import { useElementSize } from '../../../../hooks';
|
|
27
28
|
|
|
28
29
|
export const useDataGrid = <R,>(
|
|
29
|
-
props: DataGridProps<R
|
|
30
|
+
props: DataGridProps<R>,
|
|
31
|
+
override?: Partial<DataGridContextProps<R>>
|
|
30
32
|
): [DataGridContextProps<R>, DataGridContext<R>] => {
|
|
31
33
|
const {
|
|
32
34
|
rows,
|
|
@@ -59,7 +61,7 @@ export const useDataGrid = <R,>(
|
|
|
59
61
|
const gridTemplateColumns = useMemo(
|
|
60
62
|
() =>
|
|
61
63
|
[
|
|
62
|
-
...(selectable ? ['var(--space-
|
|
64
|
+
...(selectable ? ['var(--space-10)'] : []),
|
|
63
65
|
...visibleColumns.map(([, col]) => `${col.width ?? 150}px`),
|
|
64
66
|
].join(' '),
|
|
65
67
|
[selectable, visibleColumns]
|
|
@@ -173,9 +175,39 @@ export const useDataGrid = <R,>(
|
|
|
173
175
|
onVisibleRowsChange?.(indexWithTolerance, lengthWithTolerance);
|
|
174
176
|
}, [indexWithTolerance, lengthWithTolerance, onVisibleRowsChange]);
|
|
175
177
|
|
|
178
|
+
/** FOOTERS */
|
|
179
|
+
const [footers, setFooters] = useState<Record<string, string>>(
|
|
180
|
+
props.initialFooters ?? {}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const footerFunctions = useMemo(
|
|
184
|
+
() =>
|
|
185
|
+
Object.entries(footers).reduce((acc, [columnKey, footerKey]) => {
|
|
186
|
+
const column = columns[columnKey];
|
|
187
|
+
if (!column) {
|
|
188
|
+
return acc;
|
|
189
|
+
}
|
|
190
|
+
if (typeof column.footer === 'function') {
|
|
191
|
+
acc[columnKey] = column.footer;
|
|
192
|
+
} else if (
|
|
193
|
+
typeof column.footer === 'object' &&
|
|
194
|
+
typeof column.footer[footerKey] === 'function'
|
|
195
|
+
) {
|
|
196
|
+
acc[columnKey] = column.footer[footerKey];
|
|
197
|
+
}
|
|
198
|
+
return acc;
|
|
199
|
+
}, {} as Record<string, DataGridFooterFunction<R>>),
|
|
200
|
+
[columns, footers]
|
|
201
|
+
);
|
|
202
|
+
|
|
176
203
|
/** COPYING */
|
|
177
204
|
|
|
178
|
-
const { copyTable } = useDataGridCopy(
|
|
205
|
+
const { copyTable } = useDataGridCopy({
|
|
206
|
+
rows,
|
|
207
|
+
visibleColumns,
|
|
208
|
+
footerFunctions,
|
|
209
|
+
loadCopyRows,
|
|
210
|
+
});
|
|
179
211
|
|
|
180
212
|
const contextValue = useMemo<DataGridContextProps<R>>(
|
|
181
213
|
() => ({
|
|
@@ -204,28 +236,35 @@ export const useDataGrid = <R,>(
|
|
|
204
236
|
length,
|
|
205
237
|
rowKeyGetter,
|
|
206
238
|
gridTemplateColumns,
|
|
239
|
+
footers,
|
|
240
|
+
setFooters,
|
|
241
|
+
footerFunctions,
|
|
242
|
+
...override,
|
|
207
243
|
}),
|
|
208
244
|
[
|
|
209
|
-
columns,
|
|
210
|
-
copyTable,
|
|
211
|
-
editingCell,
|
|
212
|
-
filters,
|
|
213
|
-
index,
|
|
214
|
-
length,
|
|
215
|
-
onScroll,
|
|
216
245
|
props,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
246
|
+
columns,
|
|
247
|
+
visibleColumns,
|
|
248
|
+
sortedRows,
|
|
220
249
|
selectedRows,
|
|
250
|
+
selectedKeys,
|
|
251
|
+
sorts,
|
|
252
|
+
filters,
|
|
253
|
+
editingCell,
|
|
254
|
+
copyTable,
|
|
221
255
|
setColumnWidth,
|
|
222
|
-
setSettings,
|
|
223
256
|
settings,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
visibleColumns,
|
|
257
|
+
setSettings,
|
|
258
|
+
saveSettings,
|
|
227
259
|
visibleRows,
|
|
260
|
+
onScroll,
|
|
261
|
+
index,
|
|
262
|
+
length,
|
|
263
|
+
rowKeyGetter,
|
|
228
264
|
gridTemplateColumns,
|
|
265
|
+
footers,
|
|
266
|
+
footerFunctions,
|
|
267
|
+
override,
|
|
229
268
|
]
|
|
230
269
|
);
|
|
231
270
|
|
|
@@ -256,6 +295,8 @@ export const useDataGrid = <R,>(
|
|
|
256
295
|
index: 0,
|
|
257
296
|
length: 0,
|
|
258
297
|
gridTemplateColumns: '',
|
|
298
|
+
footers: {},
|
|
299
|
+
setFooters: () => {},
|
|
259
300
|
}),
|
|
260
301
|
[]
|
|
261
302
|
);
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
|
|
3
|
-
import { DataGridColumn,
|
|
3
|
+
import { DataGridColumn, DataGridContextProps } from '../types';
|
|
4
4
|
|
|
5
5
|
import { useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
export const useDataGridCopy = <R>(
|
|
8
|
-
rows
|
|
9
|
-
|
|
10
|
-
loadCopyRows
|
|
11
|
-
|
|
7
|
+
export const useDataGridCopy = <R>({
|
|
8
|
+
rows,
|
|
9
|
+
visibleColumns = [],
|
|
10
|
+
loadCopyRows,
|
|
11
|
+
footerFunctions,
|
|
12
|
+
}: Pick<
|
|
13
|
+
DataGridContextProps<R>,
|
|
14
|
+
'rows' | 'visibleColumns' | 'loadCopyRows' | 'footerFunctions'
|
|
15
|
+
>) => {
|
|
12
16
|
const generateHeadersHtml = useCallback(() => {
|
|
13
17
|
return `<tr>
|
|
14
|
-
${
|
|
18
|
+
${visibleColumns
|
|
15
19
|
.map(
|
|
16
|
-
(col) =>
|
|
20
|
+
([, col]) =>
|
|
17
21
|
`<th style="
|
|
18
22
|
text-align: left;
|
|
19
23
|
font-weight: bold;
|
|
@@ -24,29 +28,32 @@ export const useDataGridCopy = <R>(
|
|
|
24
28
|
)
|
|
25
29
|
.join('\n')}
|
|
26
30
|
</tr>`;
|
|
27
|
-
}, [
|
|
31
|
+
}, [visibleColumns]);
|
|
28
32
|
|
|
29
33
|
const generateFootersHtml = useCallback(
|
|
30
34
|
(rowsToCopy: R[]) => {
|
|
35
|
+
console.log('generate footers html');
|
|
31
36
|
return `<tr>
|
|
32
|
-
${
|
|
37
|
+
${visibleColumns
|
|
33
38
|
.map(
|
|
34
|
-
(
|
|
39
|
+
([colKey]) =>
|
|
35
40
|
`<td style="
|
|
36
41
|
font-weight: bold;
|
|
37
42
|
white-space: nowrap;
|
|
38
43
|
">
|
|
39
44
|
${
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
footerFunctions?.[colKey]?.(
|
|
46
|
+
rowsToCopy,
|
|
47
|
+
rowsToCopy,
|
|
48
|
+
[]
|
|
49
|
+
) ?? ''
|
|
43
50
|
}
|
|
44
51
|
</td>`
|
|
45
52
|
)
|
|
46
53
|
.join('\n')}
|
|
47
54
|
</tr>`;
|
|
48
55
|
},
|
|
49
|
-
[
|
|
56
|
+
[footerFunctions, visibleColumns]
|
|
50
57
|
);
|
|
51
58
|
|
|
52
59
|
const generateCellText = useCallback((col: DataGridColumn<R>, value: any) => {
|
|
@@ -76,8 +83,8 @@ export const useDataGridCopy = <R>(
|
|
|
76
83
|
.map(
|
|
77
84
|
(row) =>
|
|
78
85
|
`<tr>
|
|
79
|
-
${
|
|
80
|
-
.map((col) => {
|
|
86
|
+
${visibleColumns
|
|
87
|
+
.map(([, col]) => {
|
|
81
88
|
const value: any =
|
|
82
89
|
col.getter && row ? col.getter(row) : '';
|
|
83
90
|
return generateCellHtml(col, value);
|
|
@@ -90,24 +97,22 @@ export const useDataGridCopy = <R>(
|
|
|
90
97
|
</table>
|
|
91
98
|
`;
|
|
92
99
|
},
|
|
93
|
-
[
|
|
100
|
+
[visibleColumns, generateCellHtml, generateFootersHtml, generateHeadersHtml]
|
|
94
101
|
);
|
|
95
102
|
|
|
96
103
|
const generateHeadersText = useCallback(() => {
|
|
97
|
-
return
|
|
98
|
-
|
|
99
|
-
.join('\t');
|
|
100
|
-
}, [columns]);
|
|
104
|
+
return visibleColumns.map(([, col]) => col.name).join('\t');
|
|
105
|
+
}, [visibleColumns]);
|
|
101
106
|
|
|
102
107
|
const generateFootersText = useCallback(
|
|
103
108
|
(rowsToCopy: R[]) => {
|
|
104
|
-
return
|
|
105
|
-
.map(
|
|
106
|
-
|
|
109
|
+
return visibleColumns
|
|
110
|
+
.map(
|
|
111
|
+
([colKey]) => footerFunctions?.[colKey]?.(rowsToCopy, [], []) ?? ''
|
|
107
112
|
)
|
|
108
113
|
.join('\t');
|
|
109
114
|
},
|
|
110
|
-
[
|
|
115
|
+
[footerFunctions, visibleColumns]
|
|
111
116
|
);
|
|
112
117
|
|
|
113
118
|
const generateCopyText = useCallback(
|
|
@@ -115,8 +120,8 @@ export const useDataGridCopy = <R>(
|
|
|
115
120
|
return [
|
|
116
121
|
includeHeaders ? generateHeadersText() : '',
|
|
117
122
|
...(rowsToCopy || []).map((row) =>
|
|
118
|
-
|
|
119
|
-
.map((col) => {
|
|
123
|
+
visibleColumns
|
|
124
|
+
.map(([, col]) => {
|
|
120
125
|
const value: any = col.getter && row ? col.getter(row) : '';
|
|
121
126
|
return col.excelValue
|
|
122
127
|
? col.excelValue(value)
|
|
@@ -131,12 +136,12 @@ export const useDataGridCopy = <R>(
|
|
|
131
136
|
.filter((s) => s != null)
|
|
132
137
|
.join('\n');
|
|
133
138
|
},
|
|
134
|
-
[
|
|
139
|
+
[visibleColumns, generateFootersText, generateHeadersText]
|
|
135
140
|
);
|
|
136
141
|
|
|
137
142
|
const copyTable = useCallback(
|
|
138
143
|
async (includeHeaders = true, includeFooters = true) => {
|
|
139
|
-
const rowsToCopy = loadCopyRows
|
|
144
|
+
const rowsToCopy = await (loadCopyRows ?? (async () => rows))();
|
|
140
145
|
|
|
141
146
|
const copyHtml = generateCopyHtml(
|
|
142
147
|
rowsToCopy,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as styles from './styles';
|
|
2
2
|
|
|
3
|
+
import { DataGridContextProps, DataGridProps } from './types';
|
|
4
|
+
|
|
3
5
|
import { DataGridCell } from './DataGridCell';
|
|
4
6
|
import { DataGridFooter } from './DataGridFooter';
|
|
5
7
|
import { DataGridHeader } from './DataGridHeader';
|
|
6
|
-
import { DataGridProps } from './types';
|
|
7
8
|
import { VirtualScroller } from './VirtualScroller';
|
|
8
9
|
import { useCallback } from 'react';
|
|
9
10
|
import { useDataGrid } from './hooks';
|
|
@@ -11,13 +12,18 @@ import { useDataGrid } from './hooks';
|
|
|
11
12
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
13
|
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
|
|
13
14
|
|
|
14
|
-
export const DataGrid = <R,>(
|
|
15
|
+
export const DataGrid = <R,>({
|
|
16
|
+
contextOverride,
|
|
17
|
+
...props
|
|
18
|
+
}: DataGridProps<R> & {
|
|
19
|
+
contextOverride?: Partial<DataGridContextProps<R>>;
|
|
20
|
+
}) => {
|
|
15
21
|
const {
|
|
16
22
|
className,
|
|
17
23
|
// onRowDoubleClick,
|
|
18
24
|
onVisibleRowsChange,
|
|
19
25
|
} = props;
|
|
20
|
-
const [contextProps, DataGridContext] = useDataGrid(props);
|
|
26
|
+
const [contextProps, DataGridContext] = useDataGrid(props, contextOverride);
|
|
21
27
|
const {
|
|
22
28
|
selectedKeys,
|
|
23
29
|
setSelectedKeys,
|
|
@@ -32,17 +38,15 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
|
|
|
32
38
|
|
|
33
39
|
const hasFooter = Object.values(columns).some((col) => col.footer);
|
|
34
40
|
|
|
35
|
-
const
|
|
36
|
-
(
|
|
37
|
-
|
|
38
|
-
if (selected) {
|
|
39
|
-
if (!selectedKeys.includes(key))
|
|
40
|
-
setSelectedKeys([...selectedKeys, key]);
|
|
41
|
-
} else {
|
|
41
|
+
const toggleSelection = useCallback(
|
|
42
|
+
(key: string) => {
|
|
43
|
+
if (selectedKeys.includes(key)) {
|
|
42
44
|
setSelectedKeys(selectedKeys.filter((p) => p !== key));
|
|
45
|
+
} else {
|
|
46
|
+
setSelectedKeys([...selectedKeys, key]);
|
|
43
47
|
}
|
|
44
48
|
},
|
|
45
|
-
[
|
|
49
|
+
[selectedKeys, setSelectedKeys]
|
|
46
50
|
);
|
|
47
51
|
|
|
48
52
|
const rowTemplate = useCallback(
|
|
@@ -74,12 +78,15 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
|
|
|
74
78
|
return (
|
|
75
79
|
<styles.DataGridRow key={key}>
|
|
76
80
|
{!!props.selectable && (
|
|
77
|
-
<styles.SelectionCell
|
|
81
|
+
<styles.SelectionCell
|
|
82
|
+
key="__select_checkbox__"
|
|
83
|
+
onClick={() => toggleSelection(key)}
|
|
84
|
+
>
|
|
78
85
|
<input
|
|
79
86
|
type="checkbox"
|
|
80
87
|
value={key as string}
|
|
81
88
|
checked={selectedKeys.includes(key)}
|
|
82
|
-
|
|
89
|
+
readOnly
|
|
83
90
|
/>
|
|
84
91
|
</styles.SelectionCell>
|
|
85
92
|
)}
|
|
@@ -103,7 +110,7 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
|
|
|
103
110
|
props,
|
|
104
111
|
rowKeyGetter,
|
|
105
112
|
selectedKeys,
|
|
106
|
-
|
|
113
|
+
toggleSelection,
|
|
107
114
|
visibleColumns,
|
|
108
115
|
]
|
|
109
116
|
);
|
|
@@ -208,21 +208,18 @@ export const DataGridContainer = styled.div<{
|
|
|
208
208
|
`;
|
|
209
209
|
DataGridContainer.displayName = 'DataGridContainer';
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
type DataGridHeaderOrFooterRowProps = {
|
|
212
212
|
$headerRowHeight?: number;
|
|
213
213
|
$headerColor?: ThemeColor;
|
|
214
214
|
$gridTemplateColumns: string;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
},
|
|
219
|
-
}))`
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const dataGridHeaderOrFooterRowCss = css<DataGridHeaderOrFooterRowProps>`
|
|
220
218
|
display: grid;
|
|
221
219
|
grid-template-rows: ${({ $headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT }) =>
|
|
222
220
|
`${$headerRowHeight}px`};
|
|
223
221
|
z-index: 10;
|
|
224
222
|
position: sticky;
|
|
225
|
-
top: ${TOOLBAR_HEIGHT}px;
|
|
226
223
|
align-items: center;
|
|
227
224
|
|
|
228
225
|
${({ $headerColor }) =>
|
|
@@ -236,8 +233,31 @@ export const DataGridHeaderRow = styled.div.attrs<{
|
|
|
236
233
|
color: var(--color-neutral-900);
|
|
237
234
|
`}
|
|
238
235
|
`;
|
|
236
|
+
|
|
237
|
+
export const DataGridHeaderRow = styled.div.attrs<DataGridHeaderOrFooterRowProps>(
|
|
238
|
+
({ $gridTemplateColumns }) => ({
|
|
239
|
+
style: {
|
|
240
|
+
gridTemplateColumns: $gridTemplateColumns,
|
|
241
|
+
},
|
|
242
|
+
})
|
|
243
|
+
)`
|
|
244
|
+
${dataGridHeaderOrFooterRowCss}
|
|
245
|
+
top: ${TOOLBAR_HEIGHT}px;
|
|
246
|
+
`;
|
|
239
247
|
DataGridHeaderRow.displayName = 'DataGridHeaderRow';
|
|
240
248
|
|
|
249
|
+
export const DataGridFooterRow = styled.div.attrs<DataGridHeaderOrFooterRowProps>(
|
|
250
|
+
({ $gridTemplateColumns }) => ({
|
|
251
|
+
style: {
|
|
252
|
+
gridTemplateColumns: $gridTemplateColumns,
|
|
253
|
+
},
|
|
254
|
+
})
|
|
255
|
+
)`
|
|
256
|
+
${dataGridHeaderOrFooterRowCss}
|
|
257
|
+
bottom: 0;
|
|
258
|
+
`;
|
|
259
|
+
DataGridFooterRow.displayName = 'DataGridFooterRow';
|
|
260
|
+
|
|
241
261
|
export const DataGridRow = styled.div`
|
|
242
262
|
display: contents;
|
|
243
263
|
`;
|
|
@@ -262,6 +282,7 @@ const selectionCellStyle = css`
|
|
|
262
282
|
justify-content: center;
|
|
263
283
|
width: var(--space-8);
|
|
264
284
|
padding: 0 var(--space-1);
|
|
285
|
+
cursor: pointer;
|
|
265
286
|
|
|
266
287
|
& > input[type='checkbox'] {
|
|
267
288
|
height: var(--space-4);
|