@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@addev-be/ui",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "watch": "tsc -b --watch",
@@ -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
- if (column.type === 'date') {
199
- const groups = getDateGroups(filteredAvailableValues);
200
- return (
201
- <FilterValuesScroller
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
- <div
34
- key={index}
35
- className={join(
36
- [
37
- // 'absolute left-0 right-0 flex flex-row cursor-pointer hover:bg-gray-50',
38
- className,
39
- ],
40
- ' '
41
- )}
42
- style={{ ...style, paddingLeft: `${value.level}rem` }}
43
- title={value.title}
44
- onClick={() => onToggle?.([value.value])}
45
- >
46
- <input
47
- type="checkbox"
48
- checked={selectedValues.includes(value.value)}
49
- readOnly
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
- {value.displayValue || '(Vides)'}
56
- </span>
57
- </div>
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: textFilter(key),
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
- ...(groups ?? [])
190
- .map<DataGridFilterCheckbox[]>((group) =>
191
- getCheckboxes(
192
- group.values ?? [],
193
- renderer,
194
- formatter,
195
- group.groups,
196
- level + 1
197
- )
198
- )
199
- .flat(),
200
- ...values.map<DataGridFilterCheckbox>((value) => ({
201
- displayValue: renderer(value),
202
- title: formatter(value),
203
- value: value ?? '',
204
- level,
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',
@@ -123,6 +123,7 @@ export const DataGrid = <R,>({
123
123
  $headerRowHeight={headerRowHeight}
124
124
  $rowHeight={rowHeight}
125
125
  $rowsCount={contextProps.sortedRows.length}
126
+ $withFooter={hasFooter}
126
127
  className={className}
127
128
  >
128
129
  <DataGridHeader context={DataGridContext} />
@@ -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: ${({ $headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT }) =>
186
- `${TOOLBAR_HEIGHT}px ${$headerRowHeight}px auto`};
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
- values?: (string | number | null)[];
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
- value: DataGridFilterValue;
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] ?? '',
@@ -59,7 +59,7 @@ export const SqlRequestDataGrid = <R,>({
59
59
  const columnTypes = useMemo(
60
60
  () =>
61
61
  visibleColumnsKeys.map((key) =>
62
- String(props.columns[key].type ?? 'text')
62
+ String(props.columns[key]?.type ?? 'text')
63
63
  ),
64
64
  [visibleColumnsKeys, props.columns]
65
65
  );
@@ -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
@@ -104,6 +104,10 @@ export const MenuItemContainer = styled.div.attrs({
104
104
  &.opened > ${SubMenu} {
105
105
  display: block;
106
106
  }
107
+ &.opened.left > ${SubMenu} {
108
+ left: auto;
109
+ right: 100%;
110
+ }
107
111
  `;
108
112
  MenuItemContainer.displayName = 'MenuItemContainer';
109
113