@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.
Files changed (66) 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 +173 -9
  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/helpers/columns.tsx +98 -7
  55. package/src/components/data/DataGrid/hooks/useDataGrid.tsx +58 -17
  56. package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +35 -30
  57. package/src/components/data/DataGrid/index.tsx +21 -14
  58. package/src/components/data/DataGrid/styles.ts +28 -7
  59. package/src/components/data/DataGrid/types.ts +20 -1
  60. package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +38 -3
  61. package/src/components/data/SqlRequestDataGrid/index.tsx +116 -21
  62. package/src/components/ui/ContextMenu/index.tsx +73 -0
  63. package/src/components/ui/ContextMenu/styles.ts +115 -0
  64. package/src/services/advancedRequests.ts +1 -1
  65. package/src/services/sqlRequests.ts +16 -5
  66. 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.7",
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,32 @@ 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
+ count: 'Nombre',
70
+ max: 'Maximum',
71
+ min: 'Minimum',
72
+ sum: 'Somme',
73
+ };
74
+ const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
75
+ average: XBarIcon,
76
+ count: TallyIcon,
77
+ max: ArrowUpBigSmallIcon,
78
+ min: ArrowDownBigSmallIcon,
79
+ sum: SigmaIcon,
80
+ };
81
+
34
82
  export const DataGridFilterMenu = <R,>({
35
83
  columnKey,
36
84
  context,
@@ -39,10 +87,13 @@ export const DataGridFilterMenu = <R,>({
39
87
  const { openModal, modal } = useFilterModal({ columnKey, context });
40
88
  const {
41
89
  filters = {},
90
+ footers = {},
42
91
  rows,
43
92
  columns,
44
93
  setFilters,
45
94
  filterValuesLoader,
95
+ setSorts,
96
+ setFooters,
46
97
  } = useContext(context);
47
98
  const column = columns[columnKey] ?? {};
48
99
  const textFilterInputRef = useRef<HTMLInputElement>(null);
@@ -63,7 +114,13 @@ export const DataGridFilterMenu = <R,>({
63
114
  .map(([, filter]) => filter);
64
115
  const availableRows = applyFilters(rows, otherFilters);
65
116
  const values = availableRows.map((row) => column.filter!.getter(row));
66
- setAvailableValues(() => uniq(values).sort());
117
+ setAvailableValues(() =>
118
+ uniq(values).sort(
119
+ column.filter?.type === 'number'
120
+ ? (a, b) => (a as number) - (b as number)
121
+ : (a, b) => (a as string).localeCompare(b as string)
122
+ )
123
+ );
67
124
  }
68
125
  }, [column.filter, columnKey, filterValuesLoader, filters, rows]);
69
126
 
@@ -169,17 +226,124 @@ export const DataGridFilterMenu = <R,>({
169
226
  toggleValues,
170
227
  ]);
171
228
 
229
+ const onSortAscClicked = useCallback(() => {
230
+ setSorts({ [columnKey]: 'asc' });
231
+ onClose?.();
232
+ }, [columnKey, onClose, setSorts]);
233
+ const onSortDescClicked = useCallback(() => {
234
+ setSorts({ [columnKey]: 'desc' });
235
+ onClose?.();
236
+ }, [columnKey, onClose, setSorts]);
237
+
238
+ const hasFilters = filters[columnKey]?.values.length > 0;
239
+ const [[sortAscText, SortAscIcon], [sortDescText, SortDescIcon]] = [
240
+ sortAsc[column.filter?.type ?? 'text'],
241
+ sortDesc[column.filter?.type ?? 'text'],
242
+ ];
243
+
244
+ const isFooterVisible =
245
+ columnKey in footers && footers[columnKey] !== undefined;
246
+ const showFooter = useCallback(
247
+ (key: string) => {
248
+ setFooters((prevFooters) => ({
249
+ ...prevFooters,
250
+ [columnKey]: key,
251
+ }));
252
+ onClose?.();
253
+ },
254
+ [columnKey, onClose, setFooters]
255
+ );
256
+ const hideFooter = useCallback(() => {
257
+ setFooters((prevFooters) => {
258
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
259
+ const { [columnKey]: _, ...newFooters } = prevFooters;
260
+ return newFooters;
261
+ });
262
+ onClose?.();
263
+ }, [columnKey, onClose, setFooters]);
264
+
172
265
  return (
173
- <styles.Menu onClick={(e) => e.stopPropagation()}>
266
+ <ContextMenu>
174
267
  {modal}
175
- <styles.MenuItem onClick={openModal}>
268
+ {column.sortGetter && (
269
+ <>
270
+ <ContextMenu.Item onClick={onSortAscClicked}>
271
+ <SortAscIcon />
272
+ {sortAscText}
273
+ </ContextMenu.Item>
274
+ <ContextMenu.Item onClick={onSortDescClicked}>
275
+ <SortDescIcon />
276
+ {sortDescText}
277
+ </ContextMenu.Item>
278
+ <ContextMenu.Divider />
279
+ </>
280
+ )}
281
+ {isFooterVisible && typeof column.footer === 'function' && (
282
+ <>
283
+ <ContextMenu.Item onClick={hideFooter}>
284
+ <TableFooterSlashIcon />
285
+ Masquer le total
286
+ </ContextMenu.Item>
287
+ <ContextMenu.Divider />
288
+ </>
289
+ )}
290
+ {!isFooterVisible && typeof column.footer === 'function' && (
291
+ <>
292
+ <ContextMenu.Item onClick={() => showFooter('count')}>
293
+ <TableFooterIcon />
294
+ Afficher le total
295
+ </ContextMenu.Item>
296
+ <ContextMenu.Divider />
297
+ </>
298
+ )}
299
+ {typeof column.footer === 'object' && (
300
+ <>
301
+ <ContextMenu.ParentItem>
302
+ <TableFooterIcon />
303
+ Afficher le total
304
+ <ContextMenu.SubMenu>
305
+ {Object.keys(column.footer).map((key) => {
306
+ const TotalIcon =
307
+ footerFunctionsIcons[
308
+ key as DataGridFooterPredefinedFunction
309
+ ] ?? TableFooterIcon;
310
+ return (
311
+ <ContextMenu.Item key={key} onClick={() => showFooter(key)}>
312
+ <TotalIcon />
313
+ {key in footerFunctionsTexts
314
+ ? footerFunctionsTexts[
315
+ key as DataGridFooterPredefinedFunction
316
+ ]
317
+ : key}
318
+ </ContextMenu.Item>
319
+ );
320
+ })}
321
+ <ContextMenu.Divider />
322
+ <ContextMenu.Item
323
+ onClick={hideFooter}
324
+ disabled={!isFooterVisible}
325
+ >
326
+ <TableFooterSlashIcon />
327
+ Masquer le total
328
+ </ContextMenu.Item>
329
+ </ContextMenu.SubMenu>
330
+ </ContextMenu.ParentItem>
331
+ <ContextMenu.Divider />
332
+ </>
333
+ )}
334
+ <ContextMenu.Item onClick={openModal}>
176
335
  <FilterIcon />
177
336
  Filtrer ...
178
- </styles.MenuItem>
179
- <styles.MenuItem $color="danger" onClick={clearFilter}>
337
+ </ContextMenu.Item>
338
+ <ContextMenu.Item
339
+ $color="danger"
340
+ onClick={clearFilter}
341
+ disabled={!hasFilters}
342
+ >
180
343
  <FilterSlashIcon />
181
344
  Supprimer le filtre
182
- </styles.MenuItem>
345
+ </ContextMenu.Item>
346
+ <ContextMenu.Divider />
183
347
  <styles.InputContainer>
184
348
  <MagnifierIcon />
185
349
  <Input
@@ -195,6 +359,6 @@ export const DataGridFilterMenu = <R,>({
195
359
  <styles.CheckboxesContainer>
196
360
  {checkboxesComponent}
197
361
  </styles.CheckboxesContainer>
198
- </styles.Menu>
362
+ </ContextMenu>
199
363
  );
200
364
  };
@@ -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) => (