@addev-be/ui 0.2.6 → 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.
Files changed (68) hide show
  1. package/assets/icons/arrow-down-1-9.svg +1 -0
  2. package/assets/icons/arrow-down-big-small.svg +1 -0
  3. package/assets/icons/arrow-up-9-1.svg +1 -0
  4. package/assets/icons/arrow-up-big-small.svg +1 -0
  5. package/assets/icons/chevron-down.svg +1 -0
  6. package/assets/icons/ellipsis.svg +1 -0
  7. package/assets/icons/sigma.svg +1 -0
  8. package/assets/icons/table-footer-slash.svg +5 -0
  9. package/assets/icons/table-footer.svg +4 -0
  10. package/assets/icons/table.svg +1 -0
  11. package/assets/icons/tally.svg +1 -0
  12. package/assets/icons/x-bar.svg +4 -0
  13. package/dist/Icons.d.ts +13 -1
  14. package/dist/Icons.js +25 -1
  15. package/dist/components/data/AdvancedRequestDataGrid/index.js +3 -3
  16. package/dist/components/data/DataGrid/DataGridColumnsModal/hooks.js +2 -1
  17. package/dist/components/data/DataGrid/DataGridFilterMenu/index.js +85 -7
  18. package/dist/components/data/DataGrid/DataGridFilterMenu/styles.d.ts +3 -9
  19. package/dist/components/data/DataGrid/DataGridFilterMenu/styles.js +10 -37
  20. package/dist/components/data/DataGrid/DataGridFooter.d.ts +1 -1
  21. package/dist/components/data/DataGrid/DataGridFooter.js +35 -12
  22. package/dist/components/data/DataGrid/DataGridHeader.js +1 -1
  23. package/dist/components/data/DataGrid/DataGridHeaderCell.js +6 -22
  24. package/dist/components/data/DataGrid/helpers/columns.d.ts +1 -1
  25. package/dist/components/data/DataGrid/helpers/columns.js +71 -16
  26. package/dist/components/data/DataGrid/hooks/useDataGrid.d.ts +1 -1
  27. package/dist/components/data/DataGrid/hooks/useDataGrid.js +60 -30
  28. package/dist/components/data/DataGrid/hooks/useDataGridCopy.d.ts +2 -2
  29. package/dist/components/data/DataGrid/hooks/useDataGridCopy.js +41 -39
  30. package/dist/components/data/DataGrid/index.d.ts +4 -2
  31. package/dist/components/data/DataGrid/index.js +22 -12
  32. package/dist/components/data/DataGrid/styles.d.ts +8 -4
  33. package/dist/components/data/DataGrid/styles.js +27 -17
  34. package/dist/components/data/DataGrid/types.d.ts +8 -1
  35. package/dist/components/data/SqlRequestDataGrid/helpers/columns.d.ts +1 -1
  36. package/dist/components/data/SqlRequestDataGrid/helpers/columns.js +24 -11
  37. package/dist/components/data/SqlRequestDataGrid/index.js +105 -33
  38. package/dist/components/ui/ContextMenu/index.d.ts +11 -0
  39. package/dist/components/ui/ContextMenu/index.js +58 -0
  40. package/dist/components/ui/ContextMenu/styles.d.ts +18 -0
  41. package/dist/components/ui/ContextMenu/styles.js +56 -0
  42. package/dist/services/advancedRequests.d.ts +1 -1
  43. package/dist/services/sqlRequests.d.ts +9 -4
  44. package/dist/services/sqlRequests.js +1 -0
  45. package/package.json +1 -1
  46. package/src/Icons.tsx +24 -0
  47. package/src/components/data/AdvancedRequestDataGrid/index.tsx +3 -5
  48. package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +2 -1
  49. package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +180 -22
  50. package/src/components/data/DataGrid/DataGridFilterMenu/styles.ts +13 -64
  51. package/src/components/data/DataGrid/DataGridFooter.tsx +20 -22
  52. package/src/components/data/DataGrid/DataGridHeader.tsx +5 -5
  53. package/src/components/data/DataGrid/DataGridHeaderCell.tsx +3 -38
  54. package/src/components/data/DataGrid/FilterValuesScroller.tsx +33 -27
  55. package/src/components/data/DataGrid/helpers/columns.tsx +103 -8
  56. package/src/components/data/DataGrid/helpers/filters.ts +29 -19
  57. package/src/components/data/DataGrid/hooks/useDataGrid.tsx +58 -17
  58. package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +35 -30
  59. package/src/components/data/DataGrid/index.tsx +22 -14
  60. package/src/components/data/DataGrid/styles.ts +50 -9
  61. package/src/components/data/DataGrid/types.ts +24 -3
  62. package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +39 -3
  63. package/src/components/data/SqlRequestDataGrid/index.tsx +116 -21
  64. package/src/components/ui/ContextMenu/index.tsx +79 -0
  65. package/src/components/ui/ContextMenu/styles.ts +119 -0
  66. package/src/services/advancedRequests.ts +1 -1
  67. package/src/services/sqlRequests.ts +16 -5
  68. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
3
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
4
+ return cooked;
5
+ };
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || function (mod) {
23
+ if (mod && mod.__esModule) return mod;
24
+ var result = {};
25
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
26
+ __setModuleDefault(result, mod);
27
+ return result;
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.Divider = exports.MenuItemContainer = exports.SubMenu = exports.MenuContainer = void 0;
31
+ var styled_components_1 = __importStar(require("styled-components"));
32
+ var menuContainerCss = (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n position: absolute;\n color: var(--color-neutral-900);\n border-radius: var(--rounded-md);\n padding: var(--space-1) 0;\n box-shadow: var(--shadow-lg);\n background-color: var(--color-neutral-100);\n min-width: 20em;\n outline: 1px solid var(--color-neutral-200);\n display: flex;\n flex-direction: column;\n"], ["\n position: absolute;\n color: var(--color-neutral-900);\n border-radius: var(--rounded-md);\n padding: var(--space-1) 0;\n box-shadow: var(--shadow-lg);\n background-color: var(--color-neutral-100);\n min-width: 20em;\n outline: 1px solid var(--color-neutral-200);\n display: flex;\n flex-direction: column;\n"])));
33
+ exports.MenuContainer = styled_components_1.default.div.attrs({
34
+ className: 'MenuContainer',
35
+ })(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n ", "\n inset: 0;\n"], ["\n ", "\n inset: 0;\n"])), menuContainerCss);
36
+ exports.MenuContainer.displayName = 'MenuContainer';
37
+ exports.SubMenu = styled_components_1.default.div.attrs({
38
+ className: 'SubMenu',
39
+ })(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n ", "\n top: 0;\n left: 100%;\n margin-top: -var(--space-1);\n"], ["\n ", "\n top: 0;\n left: 100%;\n margin-top: -var(--space-1);\n"])), menuContainerCss);
40
+ exports.SubMenu.displayName = 'SubMenu';
41
+ exports.MenuItemContainer = styled_components_1.default.div.attrs({
42
+ className: 'MenuItemContainer',
43
+ })(templateObject_8 || (templateObject_8 = __makeTemplateObject(["\n position: relative;\n display: flex;\n align-items: center;\n font-family: var(--font-sans);\n font-weight: normal;\n text-align: left;\n padding: var(--space-1) var(--space-2);\n font-size: var(--text-base);\n line-height: var(--leading-6);\n border: none;\n cursor: pointer;\n\n ", "\n\n ", "\n\n svg {\n fill: currentColor;\n width: var(--space-4);\n height: var(--space-4);\n margin-right: var(--space-2);\n }\n\n & > ", " {\n display: none;\n margin-top: calc(0px - var(--space-1));\n }\n &.opened > ", " {\n display: block;\n }\n"], ["\n position: relative;\n display: flex;\n align-items: center;\n font-family: var(--font-sans);\n font-weight: normal;\n text-align: left;\n padding: var(--space-1) var(--space-2);\n font-size: var(--text-base);\n line-height: var(--leading-6);\n border: none;\n cursor: pointer;\n\n ", "\n\n ", "\n\n svg {\n fill: currentColor;\n width: var(--space-4);\n height: var(--space-4);\n margin-right: var(--space-2);\n }\n\n & > ", " {\n display: none;\n margin-top: calc(0px - var(--space-1));\n }\n &.opened > ", " {\n display: block;\n }\n"])), function (_a) {
44
+ var $withArrow = _a.$withArrow;
45
+ return $withArrow && (0, styled_components_1.css)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n &::after {\n content: '';\n position: absolute;\n right: var(--space-2);\n top: 50%;\n transform: translateY(-50%);\n border: 4px solid transparent;\n border-left-color: var(--color-neutral-600);\n }\n "], ["\n &::after {\n content: '';\n position: absolute;\n right: var(--space-2);\n top: 50%;\n transform: translateY(-50%);\n border: 4px solid transparent;\n border-left-color: var(--color-neutral-600);\n }\n "])));
46
+ }, function (_a) {
47
+ var $color = _a.$color, disabled = _a.disabled;
48
+ return disabled
49
+ ? (0, styled_components_1.css)(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n color: var(--color-neutral-300);\n background-color: var(--color-neutral-100);\n cursor: default;\n "], ["\n color: var(--color-neutral-300);\n background-color: var(--color-neutral-100);\n cursor: default;\n "]))) : $color
50
+ ? (0, styled_components_1.css)(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n color: var(--color-", "-600);\n background-color: var(--color-neutral-100);\n &:hover {\n background-color: var(--color-", "-200);\n }\n "], ["\n color: var(--color-", "-600);\n background-color: var(--color-neutral-100);\n &:hover {\n background-color: var(--color-", "-200);\n }\n "])), $color, $color) : (0, styled_components_1.css)(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n color: var(--color-neutral-900);\n background-color: var(--color-neutral-100);\n &:hover {\n background-color: var(--color-neutral-200);\n }\n "], ["\n color: var(--color-neutral-900);\n background-color: var(--color-neutral-100);\n &:hover {\n background-color: var(--color-neutral-200);\n }\n "])));
51
+ }, exports.SubMenu, exports.SubMenu);
52
+ exports.MenuItemContainer.displayName = 'MenuItemContainer';
53
+ exports.Divider = styled_components_1.default.div.attrs({
54
+ className: 'Divider',
55
+ })(templateObject_9 || (templateObject_9 = __makeTemplateObject(["\n border-top: 1px solid var(--color-neutral-200);\n margin: var(--space-1) 0;\n"], ["\n border-top: 1px solid var(--color-neutral-200);\n margin: var(--space-1) 0;\n"])));
56
+ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9;
@@ -31,7 +31,7 @@ export type AdvancedRequestRow<R> = {
31
31
  };
32
32
  export type AdvancedResponseDTO<T = any> = {
33
33
  data: AdvancedRequestRow<T>[];
34
- total?: number;
34
+ count?: number;
35
35
  };
36
36
  export type AdvancedRequestFieldDTO = string | {
37
37
  name: string;
@@ -14,27 +14,32 @@ export type ConditionDTO = {
14
14
  };
15
15
  export type OrderByDTO = {
16
16
  field: string;
17
+ type: string;
17
18
  direction?: 'ASC' | 'DESC';
18
19
  };
20
+ export type SqlRequestFooterFunction = 'sum' | 'avg' | 'count' | 'max' | 'min';
19
21
  export type SqlRequestDTO = {
20
22
  columns?: string[];
21
23
  returnColumns?: string[];
24
+ columnTypes?: string[];
25
+ totalColumns?: Record<string, SqlRequestFooterFunction>;
22
26
  conditions?: ConditionDTO[];
23
27
  orderBy?: OrderByDTO[];
24
28
  start?: number;
25
29
  length?: number;
26
- getTotal?: boolean;
30
+ getCount?: boolean;
27
31
  unique?: boolean;
28
32
  };
29
33
  export type SqlRequestRow<R> = {
30
- [K in keyof R]: R[K] extends string | number | null ? R[K] : string | number | null;
34
+ [K in keyof R]: R[K] extends string | number | null | undefined ? R[K] : string | number | null | undefined;
31
35
  };
32
36
  export type SqlResponseDTO<T = any> = {
33
37
  data: SqlRequestRow<T>[];
34
- total?: number;
38
+ count?: number;
39
+ totals?: Record<string, string | number | null | undefined>;
35
40
  };
36
41
  type SqlRequestHandler<T> = (request: SqlRequestDTO) => Promise<SqlResponseDTO<T>>;
37
42
  export declare const useSqlRequestHandler: <T = any>(name: string) => [SqlRequestHandler<T>, SqlRequestHandler<{
38
43
  Id: string;
39
- }>];
44
+ }>, SqlRequestHandler<Partial<T>>];
40
45
  export {};
@@ -6,5 +6,6 @@ var hooks_1 = require("./hooks");
6
6
  var useSqlRequestHandler = function (name) { return [
7
7
  (0, hooks_1.useWebSocketRequestHandler)(name),
8
8
  (0, hooks_1.useWebSocketRequestHandler)(name),
9
+ (0, hooks_1.useWebSocketRequestHandler)(name),
9
10
  ]; };
10
11
  exports.useSqlRequestHandler = useSqlRequestHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@addev-be/ui",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "watch": "tsc -b --watch",
package/src/Icons.tsx CHANGED
@@ -1,12 +1,18 @@
1
1
  import { FC, SVGProps, useEffect, useState } from 'react';
2
2
 
3
+ import ArrowDown19Icon from '../assets/icons/arrow-down-1-9.svg?react';
3
4
  import ArrowDownAZIcon from '../assets/icons/arrow-down-a-z.svg?react';
5
+ import ArrowDownBigSmallIcon from '../assets/icons/arrow-down-big-small.svg?react';
6
+ import ArrowUp91Icon from '../assets/icons/arrow-up-9-1.svg?react';
7
+ import ArrowUpBigSmallIcon from '../assets/icons/arrow-up-big-small.svg?react';
4
8
  import ArrowUpZAIcon from '../assets/icons/arrow-up-z-a.svg?react';
5
9
  import ArrowsRotateIcon from '../assets/icons/arrows-rotate.svg?react';
6
10
  import ArrowsUpDownIcon from '../assets/icons/arrows-up-down.svg?react';
7
11
  import CheckIcon from '../assets/icons/check.svg?react';
12
+ import ChevronDownIcon from '../assets/icons/chevron-down.svg?react';
8
13
  import CopyIcon from '../assets/icons/copy.svg?react';
9
14
  import DownIcon from '../assets/icons/down.svg?react';
15
+ import EllipsisIcon from '../assets/icons/ellipsis.svg?react';
10
16
  import FilterFullIcon from '../assets/icons/filter-full.svg?react';
11
17
  import FilterIcon from '../assets/icons/filter.svg?react';
12
18
  import FilterSlashIcon from '../assets/icons/filter-slash.svg?react';
@@ -17,10 +23,16 @@ import MagnifierIcon from '../assets/icons/magnifier.svg?react';
17
23
  import PhoneIcon from '../assets/icons/phone.svg?react';
18
24
  import PlusIcon from '../assets/icons/plus.svg?react';
19
25
  import RightIcon from '../assets/icons/right.svg?react';
26
+ import SigmaIcon from '../assets/icons/sigma.svg?react';
20
27
  import SpinnerIcon from '../assets/icons/spinner-third.svg?react';
21
28
  import TableColumnsIcon from '../assets/icons/table-columns.svg?react';
29
+ import TableFooterIcon from '../assets/icons/table-footer.svg?react';
30
+ import TableFooterSlashIcon from '../assets/icons/table-footer-slash.svg?react';
31
+ import TableIcon from '../assets/icons/table.svg?react';
32
+ import TallyIcon from '../assets/icons/tally.svg?react';
22
33
  import UpIcon from '../assets/icons/up.svg?react';
23
34
  import UserTieIcon from '../assets/icons/user-tie.svg?react';
35
+ import XBarIcon from '../assets/icons/x-bar.svg?react';
24
36
 
25
37
  type IconFCProps = SVGProps<SVGSVGElement>;
26
38
  export type IconFC = FC<IconFCProps>;
@@ -57,12 +69,18 @@ export const LoadingIcon: FC<IconFCProps> = ({ className, ...props }) => (
57
69
 
58
70
  export {
59
71
  ArrowDownAZIcon,
72
+ ArrowDown19Icon,
73
+ ArrowDownBigSmallIcon,
60
74
  ArrowUpZAIcon,
75
+ ArrowUpBigSmallIcon,
76
+ ArrowUp91Icon,
61
77
  ArrowsRotateIcon,
62
78
  ArrowsUpDownIcon,
63
79
  CheckIcon,
80
+ ChevronDownIcon,
64
81
  CopyIcon,
65
82
  DownIcon,
83
+ EllipsisIcon,
66
84
  FilterFullIcon,
67
85
  FilterIcon,
68
86
  FilterSlashIcon,
@@ -73,8 +91,14 @@ export {
73
91
  PhoneIcon,
74
92
  PlusIcon,
75
93
  RightIcon,
94
+ SigmaIcon,
76
95
  SpinnerIcon,
77
96
  TableColumnsIcon,
97
+ TableFooterIcon,
98
+ TableFooterSlashIcon,
99
+ TableIcon,
100
+ TallyIcon,
78
101
  UpIcon,
79
102
  UserTieIcon,
103
+ XBarIcon,
80
104
  };
@@ -95,8 +95,8 @@ export const AdvancedRequestDataGrid = <R,>({
95
95
  })
96
96
  ).then((response) => {
97
97
  if (getTotal) {
98
- currentRows.current = Array(response.total).fill(null);
99
- if (getTotal) setTotal(response.total ?? 0);
98
+ currentRows.current = Array(response.count).fill(null);
99
+ if (getTotal) setTotal(response.count ?? 0);
100
100
  }
101
101
  const parsedRows = parseJsonObjectFields(
102
102
  response.data,
@@ -121,9 +121,7 @@ export const AdvancedRequestDataGrid = <R,>({
121
121
  ],
122
122
  conditions: [
123
123
  ...(props.conditions ?? []),
124
- ...Object.values(
125
- _.pickBy(conditions, (condition, key) => key !== columnKey)
126
- ),
124
+ ...Object.values(_.pickBy(conditions, (_, key) => key !== columnKey)),
127
125
  ].filter((condition) => condition.field !== columnKey),
128
126
  orderBy: [
129
127
  {
@@ -12,8 +12,9 @@ export const useDataGridColumnsModal = <R,>(context: DataGridContext<R>) => {
12
12
  const [currentColumns, setCurrentColumns] = useState(columns);
13
13
 
14
14
  const openModal = useCallback(() => {
15
+ setCurrentColumns(columns);
15
16
  setIsVisible(true);
16
- }, []);
17
+ }, [columns]);
17
18
  const closeModal = useCallback(() => {
18
19
  setIsVisible(false);
19
20
  }, []);
@@ -3,8 +3,29 @@
3
3
 
4
4
  import * as styles from './styles';
5
5
 
6
- import { DataGridContext, DataGridFilterValue } from '../types';
7
- import { FilterIcon, FilterSlashIcon, MagnifierIcon } from '../../../../Icons';
6
+ import {
7
+ ArrowDown19Icon,
8
+ ArrowDownAZIcon,
9
+ ArrowDownBigSmallIcon,
10
+ ArrowUp91Icon,
11
+ ArrowUpBigSmallIcon,
12
+ ArrowUpZAIcon,
13
+ FilterIcon,
14
+ FilterSlashIcon,
15
+ IconFC,
16
+ MagnifierIcon,
17
+ SigmaIcon,
18
+ TableFooterIcon,
19
+ TableFooterSlashIcon,
20
+ TallyIcon,
21
+ XBarIcon,
22
+ } from '../../../../Icons';
23
+ import {
24
+ DataGridContext,
25
+ DataGridFilterType,
26
+ DataGridFilterValue,
27
+ DataGridFooterPredefinedFunction,
28
+ } from '../types';
8
29
  import {
9
30
  applyFilters,
10
31
  defaultRendererAndFormatter,
@@ -20,6 +41,7 @@ import {
20
41
  useState,
21
42
  } from 'react';
22
43
 
44
+ import { ContextMenu } from '../../../ui/ContextMenu';
23
45
  import { FilterValuesScroller } from '../FilterValuesScroller';
24
46
  import { Input } from '../../../forms';
25
47
  import { useFilterModal } from './hooks';
@@ -31,6 +53,34 @@ type FilterValuesProps<R> = {
31
53
  onClose?: () => void;
32
54
  };
33
55
 
56
+ const sortAsc: Record<DataGridFilterType, [string, IconFC]> = {
57
+ number: ['Trier du plus petit au plus grand', ArrowDown19Icon],
58
+ text: ['Trier de A à Z', ArrowDownAZIcon],
59
+ // date: 'Trier du plus ancien au plus récent',
60
+ };
61
+ const sortDesc: Record<DataGridFilterType, [string, IconFC]> = {
62
+ number: ['Trier du plus grand au plus petit', ArrowUp91Icon],
63
+ text: ['Trier de Z à A', ArrowUpZAIcon],
64
+ // date: 'Trier du plus récent au plus ancien',
65
+ };
66
+
67
+ const footerFunctionsTexts: Record<DataGridFooterPredefinedFunction, string> = {
68
+ average: 'Moyenne',
69
+ avg: 'Moyenne',
70
+ count: 'Nombre',
71
+ max: 'Maximum',
72
+ min: 'Minimum',
73
+ sum: 'Somme',
74
+ };
75
+ const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
76
+ average: XBarIcon,
77
+ avg: XBarIcon,
78
+ count: TallyIcon,
79
+ max: ArrowUpBigSmallIcon,
80
+ min: ArrowDownBigSmallIcon,
81
+ sum: SigmaIcon,
82
+ };
83
+
34
84
  export const DataGridFilterMenu = <R,>({
35
85
  columnKey,
36
86
  context,
@@ -39,10 +89,13 @@ export const DataGridFilterMenu = <R,>({
39
89
  const { openModal, modal } = useFilterModal({ columnKey, context });
40
90
  const {
41
91
  filters = {},
92
+ footers = {},
42
93
  rows,
43
94
  columns,
44
95
  setFilters,
45
96
  filterValuesLoader,
97
+ setSorts,
98
+ setFooters,
46
99
  } = useContext(context);
47
100
  const column = columns[columnKey] ?? {};
48
101
  const textFilterInputRef = useRef<HTMLInputElement>(null);
@@ -63,7 +116,13 @@ export const DataGridFilterMenu = <R,>({
63
116
  .map(([, filter]) => filter);
64
117
  const availableRows = applyFilters(rows, otherFilters);
65
118
  const values = availableRows.map((row) => column.filter!.getter(row));
66
- setAvailableValues(() => uniq(values).sort());
119
+ setAvailableValues(() =>
120
+ uniq(values).sort(
121
+ column.filter?.type === 'number'
122
+ ? (a, b) => (a as number) - (b as number)
123
+ : (a, b) => (a as string).localeCompare(b as string)
124
+ )
125
+ );
67
126
  }
68
127
  }, [column.filter, columnKey, filterValuesLoader, filters, rows]);
69
128
 
@@ -138,19 +197,10 @@ export const DataGridFilterMenu = <R,>({
138
197
  }, []);
139
198
 
140
199
  const checkboxesComponent = useMemo(() => {
141
- if (column.type === 'date') {
142
- const groups = getDateGroups(filteredAvailableValues);
143
- return (
144
- <FilterValuesScroller
145
- values={filteredAvailableValues}
146
- selectedValues={selectedValues}
147
- onToggle={toggleValues}
148
- formatter={formatter}
149
- renderer={renderer}
150
- groups={groups}
151
- />
152
- );
153
- }
200
+ const groups =
201
+ column.type === 'date'
202
+ ? getDateGroups(filteredAvailableValues)
203
+ : undefined;
154
204
  return (
155
205
  <FilterValuesScroller
156
206
  values={filteredAvailableValues}
@@ -158,6 +208,7 @@ export const DataGridFilterMenu = <R,>({
158
208
  onToggle={toggleValues}
159
209
  formatter={formatter}
160
210
  renderer={renderer}
211
+ groups={groups}
161
212
  />
162
213
  );
163
214
  }, [
@@ -169,17 +220,124 @@ export const DataGridFilterMenu = <R,>({
169
220
  toggleValues,
170
221
  ]);
171
222
 
223
+ const onSortAscClicked = useCallback(() => {
224
+ setSorts({ [columnKey]: 'asc' });
225
+ onClose?.();
226
+ }, [columnKey, onClose, setSorts]);
227
+ const onSortDescClicked = useCallback(() => {
228
+ setSorts({ [columnKey]: 'desc' });
229
+ onClose?.();
230
+ }, [columnKey, onClose, setSorts]);
231
+
232
+ const hasFilters = filters[columnKey]?.values.length > 0;
233
+ const [[sortAscText, SortAscIcon], [sortDescText, SortDescIcon]] = [
234
+ sortAsc[column.filter?.type ?? 'text'],
235
+ sortDesc[column.filter?.type ?? 'text'],
236
+ ];
237
+
238
+ const isFooterVisible =
239
+ columnKey in footers && footers[columnKey] !== undefined;
240
+ const showFooter = useCallback(
241
+ (key: string) => {
242
+ setFooters((prevFooters) => ({
243
+ ...prevFooters,
244
+ [columnKey]: key,
245
+ }));
246
+ onClose?.();
247
+ },
248
+ [columnKey, onClose, setFooters]
249
+ );
250
+ const hideFooter = useCallback(() => {
251
+ setFooters((prevFooters) => {
252
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
253
+ const { [columnKey]: _, ...newFooters } = prevFooters;
254
+ return newFooters;
255
+ });
256
+ onClose?.();
257
+ }, [columnKey, onClose, setFooters]);
258
+
172
259
  return (
173
- <styles.Menu onClick={(e) => e.stopPropagation()}>
260
+ <ContextMenu>
174
261
  {modal}
175
- <styles.MenuItem onClick={openModal}>
262
+ {column.sortGetter && (
263
+ <>
264
+ <ContextMenu.Item onClick={onSortAscClicked}>
265
+ <SortAscIcon />
266
+ {sortAscText}
267
+ </ContextMenu.Item>
268
+ <ContextMenu.Item onClick={onSortDescClicked}>
269
+ <SortDescIcon />
270
+ {sortDescText}
271
+ </ContextMenu.Item>
272
+ <ContextMenu.Divider />
273
+ </>
274
+ )}
275
+ {isFooterVisible && typeof column.footer === 'function' && (
276
+ <>
277
+ <ContextMenu.Item onClick={hideFooter}>
278
+ <TableFooterSlashIcon />
279
+ Masquer le total
280
+ </ContextMenu.Item>
281
+ <ContextMenu.Divider />
282
+ </>
283
+ )}
284
+ {!isFooterVisible && typeof column.footer === 'function' && (
285
+ <>
286
+ <ContextMenu.Item onClick={() => showFooter('count')}>
287
+ <TableFooterIcon />
288
+ Afficher le total
289
+ </ContextMenu.Item>
290
+ <ContextMenu.Divider />
291
+ </>
292
+ )}
293
+ {typeof column.footer === 'object' && (
294
+ <>
295
+ <ContextMenu.ParentItem>
296
+ <TableFooterIcon />
297
+ Afficher le total
298
+ <ContextMenu.SubMenu>
299
+ {Object.keys(column.footer).map((key) => {
300
+ const TotalIcon =
301
+ footerFunctionsIcons[
302
+ key as DataGridFooterPredefinedFunction
303
+ ] ?? TableFooterIcon;
304
+ return (
305
+ <ContextMenu.Item key={key} onClick={() => showFooter(key)}>
306
+ <TotalIcon />
307
+ {key in footerFunctionsTexts
308
+ ? footerFunctionsTexts[
309
+ key as DataGridFooterPredefinedFunction
310
+ ]
311
+ : key}
312
+ </ContextMenu.Item>
313
+ );
314
+ })}
315
+ <ContextMenu.Divider />
316
+ <ContextMenu.Item
317
+ onClick={hideFooter}
318
+ disabled={!isFooterVisible}
319
+ >
320
+ <TableFooterSlashIcon />
321
+ Masquer le total
322
+ </ContextMenu.Item>
323
+ </ContextMenu.SubMenu>
324
+ </ContextMenu.ParentItem>
325
+ <ContextMenu.Divider />
326
+ </>
327
+ )}
328
+ <ContextMenu.Item onClick={openModal}>
176
329
  <FilterIcon />
177
330
  Filtrer ...
178
- </styles.MenuItem>
179
- <styles.MenuItem $color="danger" onClick={clearFilter}>
331
+ </ContextMenu.Item>
332
+ <ContextMenu.Item
333
+ $color="danger"
334
+ onClick={clearFilter}
335
+ disabled={!hasFilters}
336
+ >
180
337
  <FilterSlashIcon />
181
338
  Supprimer le filtre
182
- </styles.MenuItem>
339
+ </ContextMenu.Item>
340
+ <ContextMenu.Divider />
183
341
  <styles.InputContainer>
184
342
  <MagnifierIcon />
185
343
  <Input
@@ -195,6 +353,6 @@ export const DataGridFilterMenu = <R,>({
195
353
  <styles.CheckboxesContainer>
196
354
  {checkboxesComponent}
197
355
  </styles.CheckboxesContainer>
198
- </styles.Menu>
356
+ </ContextMenu>
199
357
  );
200
358
  };
@@ -1,70 +1,11 @@
1
- import styled, { css } from 'styled-components';
2
-
3
- import { ThemeColor } from '../../../../providers/ThemeProvider/types';
4
-
5
- export const Menu = styled.div.attrs({
6
- className: 'Menu',
7
- })`
8
- position: absolute;
9
- inset: 0;
10
- color: var(--color-neutral-900);
11
- border-radius: var(--rounded-md);
12
- padding: var(--space-1) 0;
13
- box-shadow: var(--shadow-lg);
14
- background-color: var(--color-neutral-100);
15
- min-width: 20em;
16
- outline: 1px solid var(--color-neutral-200);
17
- display: flex;
18
- flex-direction: column;
19
- `;
20
-
21
- export const MenuItem = styled.button.attrs({
22
- className: 'MenuItem',
23
- })<{ $color?: ThemeColor }>`
24
- display: flex;
25
- align-items: center;
26
- width: 100%;
27
- font-family: var(--font-sans);
28
- font-weight: normal;
29
- text-align: left;
30
- padding: var(--space-1) var(--space-2);
31
- font-size: var(--text-base);
32
- line-height: var(--leading-6);
33
- border: none;
34
- cursor: pointer;
35
-
36
- ${({ $color }) =>
37
- $color
38
- ? css`
39
- color: var(--color-${$color}-600);
40
- background-color: var(--color-neutral-100);
41
- &:hover {
42
- background-color: var(--color-${$color}-200);
43
- }
44
- `
45
- : css`
46
- color: var(--color-neutral-900);
47
- background-color: var(--color-neutral-100);
48
- &:hover {
49
- background-color: var(--color-neutral-200);
50
- }
51
- `}
52
-
53
- svg {
54
- fill: currentColor;
55
- width: var(--space-4);
56
- height: var(--space-4);
57
- margin-right: var(--space-2);
58
- }
59
- `;
1
+ import styled from 'styled-components';
60
2
 
61
3
  export const InputContainer = styled.div.attrs({
62
4
  className: 'InputContainer',
63
5
  })`
64
6
  position: relative;
65
7
  border-radius: var(--rounded-md);
66
- padding: 0 var(--space-2);
67
- margin-top: var(--space-1);
8
+ padding: 0 var(--space-1);
68
9
 
69
10
  svg {
70
11
  position: absolute;
@@ -89,12 +30,20 @@ export const CheckboxesContainer = styled.div.attrs({
89
30
  font-weight: normal;
90
31
  user-select: none;
91
32
  padding: var(--space-2);
92
- margin: var(--space-2);
93
- border: 1px solid var(--color-neutral-200);
33
+ margin: var(--space-1);
34
+ margin-bottom: 0;
35
+ border: 1px solid var(--color-neutral-300);
94
36
  border-radius: var(--rounded-md);
95
37
  box-shadow: var(--shadow-inner);
96
- background-color: var(--color-neutral-50);
38
+ background-color: var(--color-neutral-0);
97
39
  height: 20em;
98
40
  overflow-y: hidden;
99
41
  white-space: nowrap;
100
42
  `;
43
+
44
+ export const Separator = styled.div.attrs({
45
+ className: 'Separator',
46
+ })`
47
+ border-top: 1px solid var(--color-neutral-200);
48
+ margin: var(--space-1) 0;
49
+ `;
@@ -1,12 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
3
3
 
4
+ import * as styles from './styles';
5
+
4
6
  import { DataGridContext } from './types';
5
- import { getScrollBarSize } from '../../../helpers/getScrollbarSize';
6
7
  import { useDataGridContext } from './hooks';
7
8
 
8
- const SCROLL_BAR_SIZE = getScrollBarSize();
9
-
10
9
  export const DataGridFooter = <R,>({
11
10
  context,
12
11
  }: {
@@ -17,28 +16,27 @@ export const DataGridFooter = <R,>({
17
16
  rows,
18
17
  selectedRows,
19
18
  sortedRows,
20
- rowHeight = 48,
21
19
  selectable,
20
+ footers = {},
21
+ gridTemplateColumns,
22
+ footerFunctions,
22
23
  } = useDataGridContext(context);
23
24
 
25
+ if (!Object.keys(footers).length) {
26
+ return null;
27
+ }
28
+
24
29
  return (
25
- <tfoot
26
- style={{
27
- paddingRight: `${SCROLL_BAR_SIZE[0]}px`,
28
- }}
29
- >
30
- <tr
31
- style={{
32
- height: `${rowHeight}px`,
33
- }}
34
- >
35
- {!!selectable && <div key="__select_checkbox__"></div>}
36
- {visibleColumns.map(([key, col]) => (
37
- <div key={key} style={{ width: (col.width ?? 150) + 'px' }}>
38
- {col.footer?.(rows, sortedRows, selectedRows)}
39
- </div>
40
- ))}
41
- </tr>
42
- </tfoot>
30
+ <styles.DataGridFooterRow $gridTemplateColumns={gridTemplateColumns}>
31
+ {!!selectable && <styles.HeaderSelectionCell />}
32
+ {visibleColumns.map(([key, col]) => (
33
+ <styles.DataGridHeaderCellContainer
34
+ key={key}
35
+ style={{ width: (col.width ?? 150) + 'px' }}
36
+ >
37
+ {footerFunctions?.[key]?.(rows, sortedRows, selectedRows)}
38
+ </styles.DataGridHeaderCellContainer>
39
+ ))}
40
+ </styles.DataGridFooterRow>
43
41
  );
44
42
  };
@@ -102,11 +102,11 @@ export const DataGridHeader = <R,>({
102
102
  $headerColor={headerColor}
103
103
  >
104
104
  {!!selectable && (
105
- <styles.HeaderSelectionCell $headerColor={headerColor}>
106
- <IndeterminateCheckbox
107
- checked={checkboxStatus}
108
- onChange={() => toggleAll(!(checkboxStatus ?? true))}
109
- />
105
+ <styles.HeaderSelectionCell
106
+ $headerColor={headerColor}
107
+ onClick={() => toggleAll(!(checkboxStatus ?? true))}
108
+ >
109
+ <IndeterminateCheckbox checked={checkboxStatus} readOnly />
110
110
  </styles.HeaderSelectionCell>
111
111
  )}
112
112
  {visibleColumns.map(([key, col], index) => (