@addev-be/ui 0.2.7 → 0.2.8
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/package.json +1 -1
- package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +7 -13
- package/src/components/data/DataGrid/FilterValuesScroller.tsx +33 -27
- package/src/components/data/DataGrid/helpers/columns.tsx +5 -1
- package/src/components/data/DataGrid/helpers/filters.ts +29 -19
- package/src/components/data/DataGrid/index.tsx +1 -0
- package/src/components/data/DataGrid/styles.ts +22 -2
- package/src/components/data/DataGrid/types.ts +4 -2
- package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +1 -0
- package/src/components/data/SqlRequestDataGrid/index.tsx +1 -1
- package/src/components/ui/ContextMenu/index.tsx +7 -1
- package/src/components/ui/ContextMenu/styles.ts +4 -0
package/package.json
CHANGED
|
@@ -66,6 +66,7 @@ const sortDesc: Record<DataGridFilterType, [string, IconFC]> = {
|
|
|
66
66
|
|
|
67
67
|
const footerFunctionsTexts: Record<DataGridFooterPredefinedFunction, string> = {
|
|
68
68
|
average: 'Moyenne',
|
|
69
|
+
avg: 'Moyenne',
|
|
69
70
|
count: 'Nombre',
|
|
70
71
|
max: 'Maximum',
|
|
71
72
|
min: 'Minimum',
|
|
@@ -73,6 +74,7 @@ const footerFunctionsTexts: Record<DataGridFooterPredefinedFunction, string> = {
|
|
|
73
74
|
};
|
|
74
75
|
const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
|
|
75
76
|
average: XBarIcon,
|
|
77
|
+
avg: XBarIcon,
|
|
76
78
|
count: TallyIcon,
|
|
77
79
|
max: ArrowUpBigSmallIcon,
|
|
78
80
|
min: ArrowDownBigSmallIcon,
|
|
@@ -195,19 +197,10 @@ export const DataGridFilterMenu = <R,>({
|
|
|
195
197
|
}, []);
|
|
196
198
|
|
|
197
199
|
const checkboxesComponent = useMemo(() => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
values={filteredAvailableValues}
|
|
203
|
-
selectedValues={selectedValues}
|
|
204
|
-
onToggle={toggleValues}
|
|
205
|
-
formatter={formatter}
|
|
206
|
-
renderer={renderer}
|
|
207
|
-
groups={groups}
|
|
208
|
-
/>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
200
|
+
const groups =
|
|
201
|
+
column.type === 'date'
|
|
202
|
+
? getDateGroups(filteredAvailableValues)
|
|
203
|
+
: undefined;
|
|
211
204
|
return (
|
|
212
205
|
<FilterValuesScroller
|
|
213
206
|
values={filteredAvailableValues}
|
|
@@ -215,6 +208,7 @@ export const DataGridFilterMenu = <R,>({
|
|
|
215
208
|
onToggle={toggleValues}
|
|
216
209
|
formatter={formatter}
|
|
217
210
|
renderer={renderer}
|
|
211
|
+
groups={groups}
|
|
218
212
|
/>
|
|
219
213
|
);
|
|
220
214
|
}, [
|
|
@@ -29,33 +29,39 @@ const CheckboxTemplate = ({
|
|
|
29
29
|
className?: string;
|
|
30
30
|
style?: React.CSSProperties;
|
|
31
31
|
onToggle?: (values: DataGridFilterValue[]) => void;
|
|
32
|
-
}) =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// className="inline-block mr-2"
|
|
51
|
-
/>
|
|
52
|
-
<span
|
|
53
|
-
// className="mr-2 truncate"
|
|
32
|
+
}) => {
|
|
33
|
+
const checked = useMemo(
|
|
34
|
+
() => value.values.every((v) => selectedValues.includes(v)),
|
|
35
|
+
[selectedValues, value.values]
|
|
36
|
+
);
|
|
37
|
+
return (
|
|
38
|
+
<styles.FilterValueContainer
|
|
39
|
+
key={index}
|
|
40
|
+
className={join(
|
|
41
|
+
[
|
|
42
|
+
// 'absolute left-0 right-0 flex flex-row cursor-pointer hover:bg-gray-50',
|
|
43
|
+
className,
|
|
44
|
+
],
|
|
45
|
+
' '
|
|
46
|
+
)}
|
|
47
|
+
style={{ ...style, paddingLeft: `${value.level}rem` }}
|
|
48
|
+
title={value.title}
|
|
49
|
+
onClick={() => onToggle?.(value.values)}
|
|
54
50
|
>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
<input
|
|
52
|
+
type="checkbox"
|
|
53
|
+
checked={checked}
|
|
54
|
+
readOnly
|
|
55
|
+
// className="inline-block mr-2"
|
|
56
|
+
/>
|
|
57
|
+
<span
|
|
58
|
+
// className="mr-2 truncate"
|
|
59
|
+
>
|
|
60
|
+
{value.displayValue || '(Vides)'}
|
|
61
|
+
</span>
|
|
62
|
+
</styles.FilterValueContainer>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
59
65
|
|
|
60
66
|
type FilterValuesScrollerProps = {
|
|
61
67
|
values: DataGridFilterValue[];
|
|
@@ -96,7 +102,7 @@ export const FilterValuesScroller = ({
|
|
|
96
102
|
);
|
|
97
103
|
|
|
98
104
|
const checkboxes = useMemo(
|
|
99
|
-
() => getCheckboxes(values, renderer, formatter, groups),
|
|
105
|
+
() => getCheckboxes(values, '', renderer, formatter, groups),
|
|
100
106
|
[values, groups, renderer, formatter]
|
|
101
107
|
);
|
|
102
108
|
const visibleCheckboxes = checkboxes.slice(
|
|
@@ -87,11 +87,15 @@ export const dateColumn = <R extends Record<string, any>>(
|
|
|
87
87
|
): DataGridColumns<R> => ({
|
|
88
88
|
[key]: {
|
|
89
89
|
name: title,
|
|
90
|
+
type: 'date',
|
|
90
91
|
render: (row) => moment(row[key]).format('DD/MM/YYYY') ?? '',
|
|
91
92
|
getter: (row) => row[key] ?? '',
|
|
92
93
|
sortGetter: (row) => row[key] ?? '',
|
|
93
94
|
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
94
|
-
filter:
|
|
95
|
+
filter: {
|
|
96
|
+
...textFilter(key),
|
|
97
|
+
renderer: (value) => moment(value).format('DD/MM/YYYY') ?? '',
|
|
98
|
+
},
|
|
95
99
|
...options,
|
|
96
100
|
},
|
|
97
101
|
});
|
|
@@ -168,8 +168,10 @@ export const getDateGroups = (dates: any[]): DataGridFilterGroup[] => {
|
|
|
168
168
|
const grouperDates = groupDatesByYearAndMonth(dates);
|
|
169
169
|
return Object.entries(grouperDates).map(([year, months]) => ({
|
|
170
170
|
name: year,
|
|
171
|
+
displayValue: year,
|
|
171
172
|
values: Object.values(months).flat(),
|
|
172
173
|
groups: Object.entries(months).map(([month, dates]) => ({
|
|
174
|
+
displayValue: month,
|
|
173
175
|
name: month,
|
|
174
176
|
values: dates,
|
|
175
177
|
})),
|
|
@@ -181,29 +183,37 @@ export const defaultRendererAndFormatter = (value: any) =>
|
|
|
181
183
|
|
|
182
184
|
export const getCheckboxes = (
|
|
183
185
|
values: DataGridFilterValue[],
|
|
186
|
+
displayValue: DataGridFilterValue,
|
|
184
187
|
renderer: DataGridFilterRenderer,
|
|
185
188
|
formatter: DataGridFilterFormatter,
|
|
186
189
|
groups?: DataGridFilterGroup[],
|
|
187
190
|
level = 0
|
|
188
|
-
): DataGridFilterCheckbox[] =>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
]
|
|
191
|
+
): DataGridFilterCheckbox[] =>
|
|
192
|
+
groups
|
|
193
|
+
? groups
|
|
194
|
+
.map<DataGridFilterCheckbox[]>((group) => [
|
|
195
|
+
{
|
|
196
|
+
displayValue: group.displayValue,
|
|
197
|
+
title: formatter(group.displayValue),
|
|
198
|
+
values: group.values ?? [],
|
|
199
|
+
level,
|
|
200
|
+
},
|
|
201
|
+
...getCheckboxes(
|
|
202
|
+
group.values ?? [],
|
|
203
|
+
group.displayValue,
|
|
204
|
+
renderer,
|
|
205
|
+
formatter,
|
|
206
|
+
group.groups,
|
|
207
|
+
level + 1
|
|
208
|
+
),
|
|
209
|
+
])
|
|
210
|
+
.flat()
|
|
211
|
+
: values.map<DataGridFilterCheckbox>((value) => ({
|
|
212
|
+
displayValue: renderer(value),
|
|
213
|
+
title: formatter(value),
|
|
214
|
+
values: [value ?? ''],
|
|
215
|
+
level,
|
|
216
|
+
}));
|
|
207
217
|
|
|
208
218
|
export const textFilter = (key: string): DataGridFilter<'text'> => ({
|
|
209
219
|
type: 'text',
|
|
@@ -5,6 +5,7 @@ import { ThemeColor } from '../../../providers/ThemeProvider/types';
|
|
|
5
5
|
export const VIRTUAL_SCROLL_TOLERANCE = 20;
|
|
6
6
|
export const TOOLBAR_HEIGHT = 40;
|
|
7
7
|
export const DEFAULT_HEADER_ROW_HEIGHT = 40;
|
|
8
|
+
export const DEFAULT_FOOTER_ROW_HEIGHT = 40;
|
|
8
9
|
export const DEFAULT_ROW_HEIGHT = 32;
|
|
9
10
|
export const DEFAULT_FILTER_ROW_HEIGHT = 24;
|
|
10
11
|
|
|
@@ -175,6 +176,7 @@ export const DataGridContainer = styled.div<{
|
|
|
175
176
|
$rowHeight?: number;
|
|
176
177
|
$rowsCount: number;
|
|
177
178
|
$showToolsHeader?: boolean;
|
|
179
|
+
$withFooter?: boolean;
|
|
178
180
|
}>`
|
|
179
181
|
display: grid;
|
|
180
182
|
width: 100%;
|
|
@@ -182,8 +184,13 @@ export const DataGridContainer = styled.div<{
|
|
|
182
184
|
background-color: var(--color-neutral-50);
|
|
183
185
|
font-size: var(--text-base);
|
|
184
186
|
overflow: scroll;
|
|
185
|
-
grid-template-rows: ${({
|
|
186
|
-
|
|
187
|
+
grid-template-rows: ${({
|
|
188
|
+
$headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT,
|
|
189
|
+
$withFooter = false,
|
|
190
|
+
}) =>
|
|
191
|
+
`${TOOLBAR_HEIGHT}px ${$headerRowHeight}px auto ${
|
|
192
|
+
$withFooter ? DEFAULT_FOOTER_ROW_HEIGHT + 'px' : ''
|
|
193
|
+
}`};
|
|
187
194
|
|
|
188
195
|
${DataGridToolsRow} {
|
|
189
196
|
height: ${TOOLBAR_HEIGHT}px;
|
|
@@ -345,3 +352,16 @@ export const FilterValuesScrollerContainer = styled.div.attrs({
|
|
|
345
352
|
}
|
|
346
353
|
}
|
|
347
354
|
`;
|
|
355
|
+
|
|
356
|
+
export const FilterValueContainer = styled.div.attrs({
|
|
357
|
+
className: 'FilterValueContainer',
|
|
358
|
+
})`
|
|
359
|
+
position: absolute;
|
|
360
|
+
display: flex;
|
|
361
|
+
flex-direction: row;
|
|
362
|
+
align-items: center;
|
|
363
|
+
cursor: pointer;
|
|
364
|
+
&:hover {
|
|
365
|
+
background-color: var(--color-neutral-50);
|
|
366
|
+
}
|
|
367
|
+
`;
|
|
@@ -23,6 +23,7 @@ export type DataGridCellFC = FC<{
|
|
|
23
23
|
|
|
24
24
|
export type DataGridFooterPredefinedFunction =
|
|
25
25
|
| 'average'
|
|
26
|
+
| 'avg'
|
|
26
27
|
| 'count'
|
|
27
28
|
| 'max'
|
|
28
29
|
| 'min'
|
|
@@ -246,7 +247,8 @@ export type DataGridFilter<T extends string = DataGridFilterType> =
|
|
|
246
247
|
|
|
247
248
|
export type DataGridFilterGroup = {
|
|
248
249
|
name: string;
|
|
249
|
-
|
|
250
|
+
displayValue: DataGridFilterValue;
|
|
251
|
+
values?: DataGridFilterValue[];
|
|
250
252
|
groups?: DataGridFilterGroup[];
|
|
251
253
|
};
|
|
252
254
|
|
|
@@ -255,6 +257,6 @@ export type DataGridFilterValue = string | number | null;
|
|
|
255
257
|
export type DataGridFilterCheckbox = {
|
|
256
258
|
displayValue: ReactNode;
|
|
257
259
|
title: string;
|
|
258
|
-
|
|
260
|
+
values: DataGridFilterValue[];
|
|
259
261
|
level: number;
|
|
260
262
|
};
|
|
@@ -99,6 +99,7 @@ export const sqlDateColumn = <R extends Record<string, any>>(
|
|
|
99
99
|
): SqlRequestDataGridColumns<R> => ({
|
|
100
100
|
[key]: {
|
|
101
101
|
name: title,
|
|
102
|
+
type: 'date',
|
|
102
103
|
render: (row) => formatDate(row[key]),
|
|
103
104
|
getter: (row) => row[key] ?? '',
|
|
104
105
|
sortGetter: (row) => row[key] ?? '',
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
HTMLAttributes,
|
|
5
5
|
PropsWithChildren,
|
|
6
6
|
useCallback,
|
|
7
|
+
useRef,
|
|
7
8
|
useState,
|
|
8
9
|
} from 'react';
|
|
9
10
|
|
|
@@ -27,7 +28,9 @@ export const ParentMenuItem: FC<HTMLAttributes<HTMLDivElement>> = ({
|
|
|
27
28
|
...props
|
|
28
29
|
}) => {
|
|
29
30
|
const [isOpened, setIsOpened] = useState(false);
|
|
31
|
+
const [isSubMenuLeft, setIsSubMenuLeft] = useState(false);
|
|
30
32
|
const [currentTimeout, setCurrentTimeout] = useState<number | null>(null);
|
|
33
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
31
34
|
|
|
32
35
|
const stopTimeout = useCallback(() => {
|
|
33
36
|
if (currentTimeout) {
|
|
@@ -42,6 +45,8 @@ export const ParentMenuItem: FC<HTMLAttributes<HTMLDivElement>> = ({
|
|
|
42
45
|
setCurrentTimeout(
|
|
43
46
|
window.setTimeout(
|
|
44
47
|
() => {
|
|
48
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
49
|
+
setIsSubMenuLeft(!!rect && rect.right + 280 > window.innerWidth);
|
|
45
50
|
setIsOpened(open);
|
|
46
51
|
},
|
|
47
52
|
open ? 100 : 300
|
|
@@ -56,8 +61,9 @@ export const ParentMenuItem: FC<HTMLAttributes<HTMLDivElement>> = ({
|
|
|
56
61
|
|
|
57
62
|
return (
|
|
58
63
|
<MenuItemContainer
|
|
64
|
+
ref={containerRef}
|
|
59
65
|
{...props}
|
|
60
|
-
className={isOpened ? 'opened' : ''}
|
|
66
|
+
className={`${isOpened ? 'opened' : ''} ${isSubMenuLeft ? 'left' : ''}`}
|
|
61
67
|
onMouseEnter={open}
|
|
62
68
|
onMouseLeave={close}
|
|
63
69
|
$withArrow
|