@groupeactual/ui-kit 1.0.27-beta.4 → 1.0.27-beta.5

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 (28) hide show
  1. package/dist/cjs/index.js +9 -9
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/Datatable/Datatable.d.ts +16 -0
  4. package/dist/cjs/types/components/Datatable/datatable.helper.d.ts +9 -0
  5. package/dist/cjs/types/components/Datatable/datatable.interface.d.ts +12 -0
  6. package/dist/cjs/types/components/Datatable/index.d.ts +1 -0
  7. package/dist/cjs/types/components/Pagination/Pagination.d.ts +2 -2
  8. package/dist/cjs/types/components/Pagination/pagination.helper.d.ts +1 -0
  9. package/dist/cjs/types/components/index.d.ts +1 -0
  10. package/dist/es/index.d.ts +72 -46
  11. package/dist/es/index.mjs +9 -9
  12. package/dist/es/index.mjs.map +1 -1
  13. package/dist/es/types/components/Datatable/Datatable.d.ts +16 -0
  14. package/dist/es/types/components/Datatable/datatable.helper.d.ts +9 -0
  15. package/dist/es/types/components/Datatable/datatable.interface.d.ts +12 -0
  16. package/dist/es/types/components/Datatable/index.d.ts +1 -0
  17. package/dist/es/types/components/Pagination/Pagination.d.ts +2 -2
  18. package/dist/es/types/components/Pagination/pagination.helper.d.ts +1 -0
  19. package/dist/es/types/components/index.d.ts +1 -0
  20. package/package.json +2 -2
  21. package/src/components/Datatable/Datatable.tsx +174 -0
  22. package/src/components/Datatable/datatable.helper.ts +15 -0
  23. package/src/components/Datatable/datatable.interface.ts +15 -0
  24. package/src/components/Datatable/index.ts +1 -0
  25. package/src/components/Pagination/Pagination.tsx +53 -36
  26. package/src/components/Pagination/pagination.helper.ts +2 -0
  27. package/src/components/Stepper/Step.tsx +2 -1
  28. package/src/components/index.ts +1 -0
@@ -0,0 +1,16 @@
1
+ import { Column, Row } from './datatable.interface';
2
+ interface Props<T extends Row> {
3
+ values: T[];
4
+ columns: Column<T>[];
5
+ withHeader?: boolean;
6
+ withPagination?: boolean;
7
+ defaultRowPerPage?: number;
8
+ totalPerPageTrad?: string;
9
+ totalTrad?: string;
10
+ limitsPerPageArray?: number[];
11
+ }
12
+ declare const Datatable: {
13
+ <T extends Row>({ values, columns, withHeader, withPagination, defaultRowPerPage, totalPerPageTrad, totalTrad, limitsPerPageArray }: Props<T>): import("react/jsx-runtime").JSX.Element;
14
+ displayName: string;
15
+ };
16
+ export default Datatable;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Compares two objects based on a specified property in descending order.
3
+ *
4
+ * @param a - The first object in the comparison.
5
+ * @param b - The second object in the comparison.
6
+ * @param orderBy - The property of the objects to base the comparison on.
7
+ * @returns A number indicating the order of the objects.
8
+ */
9
+ export declare const descendingComparator: <T>(a: T, b: T, orderBy?: string) => 0 | 1 | -1;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ export type Order = 'asc' | 'desc';
3
+ export interface Column<T> {
4
+ name: string;
5
+ render: (record: T) => JSX.Element;
6
+ title?: string;
7
+ width?: string;
8
+ sortable?: boolean;
9
+ }
10
+ export interface Row {
11
+ details?: ReactNode;
12
+ }
@@ -0,0 +1 @@
1
+ export { default } from './Datatable';
@@ -1,15 +1,15 @@
1
1
  interface Props {
2
2
  totalString: string;
3
3
  totalPerPageString: string;
4
- totalPages: number;
5
4
  limitsPerPage: number[];
5
+ totalRows: number;
6
6
  setLimit?: (limit: number) => void;
7
7
  setPage?: (page: number) => void;
8
8
  page?: number;
9
9
  limit?: number;
10
10
  }
11
11
  declare const Pagination: {
12
- ({ totalString, totalPerPageString, totalPages, limitsPerPage, setLimit, setPage, page, limit }: Props): import("react/jsx-runtime").JSX.Element;
12
+ ({ totalString, totalPerPageString, limitsPerPage, setLimit, setPage, page, totalRows, limit }: Props): import("react/jsx-runtime").JSX.Element;
13
13
  displayName: string;
14
14
  };
15
15
  export default Pagination;
@@ -0,0 +1 @@
1
+ export declare const getTotalPages: (totalRows: number, limitPerPage: number) => number;
@@ -23,3 +23,4 @@ export { default as BannerNotification } from './BannerNotification/BannerNotifi
23
23
  export { default as Stepper } from './Stepper/Stepper';
24
24
  export { default as Switch } from './Form/Switch/Switch';
25
25
  export { default as DatePicker } from './Form/DatePicker';
26
+ export { default as Datatable } from './Datatable/Datatable';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groupeactual/ui-kit",
3
- "version": "1.0.27-beta.4",
3
+ "version": "1.0.27-beta.5",
4
4
  "type": "module",
5
5
  "description": "A simple template for a custom React component library",
6
6
  "devDependencies": {
@@ -54,7 +54,7 @@
54
54
  "notistack": "^3.0.1",
55
55
  "react": "^18.2.0",
56
56
  "react-dom": "^18.2.0",
57
- "@groupeactual/design-tokens": "1.0.27-beta.4"
57
+ "@groupeactual/design-tokens": "1.0.27-beta.5"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "react": "^18.2.0",
@@ -0,0 +1,174 @@
1
+ import { useMemo, useState } from 'react';
2
+
3
+ import { faArrowDown, faArrowUp } from '@fortawesome/pro-regular-svg-icons';
4
+ import { DatatableStyle } from '@groupeactual/design-tokens';
5
+ import {
6
+ Box,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableRow,
13
+ TableSortLabel,
14
+ styled,
15
+ useTheme
16
+ } from '@mui/material';
17
+
18
+ import IconProvider from '../IconProvider';
19
+ import Pagination from '../Pagination';
20
+ import Text from '../Text';
21
+ import { descendingComparator } from './datatable.helper';
22
+ import { Column, Order, Row } from './datatable.interface';
23
+
24
+ interface Props<T extends Row> {
25
+ values: T[];
26
+ columns: Column<T>[];
27
+ withHeader?: boolean;
28
+ withPagination?: boolean;
29
+ defaultRowPerPage?: number;
30
+ totalPerPageTrad?: string;
31
+ totalTrad?: string;
32
+ limitsPerPageArray?: number[];
33
+ }
34
+
35
+ const Datatable = <T extends Row>({
36
+ values,
37
+ columns,
38
+ withHeader = true,
39
+ withPagination = false,
40
+ defaultRowPerPage = 5,
41
+ totalPerPageTrad = 'résultats par page',
42
+ totalTrad = 'résultats',
43
+ limitsPerPageArray = [3, 5, 10, 20]
44
+ }: Props<T>) => {
45
+ const theme = useTheme();
46
+ const [order, setOrder] = useState<Order>('asc');
47
+ const [orderBy, setOrderBy] = useState<string>();
48
+
49
+ const isAsc = order === 'asc';
50
+
51
+ const [page, setPage] = useState(1);
52
+ const [rowsPerPage, setRowsPerPage] = useState(defaultRowPerPage);
53
+
54
+ const StyledDatatable = useMemo(
55
+ () => styled(Box)(DatatableStyle(theme)),
56
+ [theme]
57
+ );
58
+
59
+ const visibleRows = useMemo(() => {
60
+ const sortedValues = values.sort(
61
+ order === 'desc'
62
+ ? (a, b) => descendingComparator(a, b, orderBy)
63
+ : (a, b) => -descendingComparator(a, b, orderBy)
64
+ );
65
+
66
+ return withPagination
67
+ ? sortedValues.slice(
68
+ (page - 1) * rowsPerPage,
69
+ (page - 1) * rowsPerPage + rowsPerPage
70
+ )
71
+ : sortedValues;
72
+ }, [page, rowsPerPage, order, orderBy, withPagination]);
73
+
74
+ return (
75
+ <StyledDatatable>
76
+ {values.length > 0 && (
77
+ <TableContainer>
78
+ <Table>
79
+ {withHeader && (
80
+ <TableHead>
81
+ <TableRow>
82
+ {columns.map(({ name, title = '', sortable = false }) => {
83
+ const isOrderBy = orderBy === name;
84
+ return (
85
+ <TableCell
86
+ key={name}
87
+ sortDirection={orderBy === name ? order : false}
88
+ >
89
+ {(sortable && (
90
+ <TableSortLabel
91
+ active={orderBy === name}
92
+ onClick={() => {
93
+ setOrder(isAsc && isOrderBy ? 'desc' : 'asc');
94
+ setOrderBy(name);
95
+ }}
96
+ IconComponent={() => (
97
+ <>
98
+ <IconProvider
99
+ icon={faArrowUp}
100
+ color={
101
+ isAsc && isOrderBy
102
+ ? '#000'
103
+ : theme.palette.greyLightDefaultBorder
104
+ }
105
+ />
106
+ <IconProvider
107
+ icon={faArrowDown}
108
+ color={
109
+ !isAsc && isOrderBy
110
+ ? '#000'
111
+ : theme.palette.greyLightDefaultBorder
112
+ }
113
+ />
114
+ </>
115
+ )}
116
+ >
117
+ <Text>{title}</Text>
118
+ </TableSortLabel>
119
+ )) || <Text>{title}</Text>}
120
+ </TableCell>
121
+ );
122
+ })}
123
+ </TableRow>
124
+ </TableHead>
125
+ )}
126
+ <TableBody>
127
+ {visibleRows.map((record, index) => (
128
+ <>
129
+ <TableRow
130
+ sx={{
131
+ '& > *': {
132
+ borderBottom: record.details ? 'unset' : 'default'
133
+ }
134
+ }}
135
+ key={index}
136
+ >
137
+ {columns.map(({ name, width, render }) => (
138
+ <TableCell key={name} width={width}>
139
+ {render(record)}
140
+ </TableCell>
141
+ ))}
142
+ </TableRow>
143
+ {record.details && (
144
+ <TableRow>
145
+ <TableCell colSpan={columns.length}>
146
+ {record.details}
147
+ </TableCell>
148
+ </TableRow>
149
+ )}
150
+ </>
151
+ ))}
152
+ </TableBody>
153
+ </Table>
154
+ </TableContainer>
155
+ )}
156
+ {withPagination && (
157
+ <Pagination
158
+ page={page}
159
+ limit={rowsPerPage}
160
+ setPage={setPage}
161
+ setLimit={setRowsPerPage}
162
+ limitsPerPage={limitsPerPageArray}
163
+ totalPerPageString={totalPerPageTrad}
164
+ totalRows={values.length}
165
+ totalString={totalTrad}
166
+ />
167
+ )}
168
+ </StyledDatatable>
169
+ );
170
+ };
171
+
172
+ Datatable.displayName = 'Datatable';
173
+
174
+ export default Datatable;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Compares two objects based on a specified property in descending order.
3
+ *
4
+ * @param a - The first object in the comparison.
5
+ * @param b - The second object in the comparison.
6
+ * @param orderBy - The property of the objects to base the comparison on.
7
+ * @returns A number indicating the order of the objects.
8
+ */
9
+ export const descendingComparator = <T>(a: T, b: T, orderBy?: string) => {
10
+ if (!orderBy) {
11
+ return 0;
12
+ }
13
+
14
+ return b[orderBy] < a[orderBy] ? -1 : b[orderBy] > a[orderBy] ? 1 : 0;
15
+ };
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export type Order = 'asc' | 'desc';
4
+
5
+ export interface Column<T> {
6
+ name: string;
7
+ render: (record: T) => JSX.Element;
8
+ title?: string;
9
+ width?: string;
10
+ sortable?: boolean;
11
+ }
12
+
13
+ export interface Row {
14
+ details?: ReactNode;
15
+ }
@@ -0,0 +1 @@
1
+ export { default } from './Datatable';
@@ -1,23 +1,23 @@
1
1
  import React, { useEffect, useMemo, useState } from 'react';
2
+
3
+ import { PaginationStyle } from '@groupeactual/design-tokens';
2
4
  import {
3
5
  Box,
4
6
  Divider,
5
7
  Pagination as MUIPagination,
6
- MenuItem,
7
- Select,
8
8
  styled,
9
9
  useTheme
10
10
  } from '@mui/material';
11
11
 
12
- import { PaginationStyle } from '@groupeactual/design-tokens';
13
-
12
+ import Select from '../Form/Select';
14
13
  import Text from '../Text';
14
+ import { getTotalPages } from './pagination.helper';
15
15
 
16
16
  interface Props {
17
17
  totalString: string;
18
18
  totalPerPageString: string;
19
- totalPages: number;
20
19
  limitsPerPage: number[];
20
+ totalRows: number;
21
21
  setLimit?: (limit: number) => void;
22
22
  setPage?: (page: number) => void;
23
23
  page?: number;
@@ -27,11 +27,11 @@ interface Props {
27
27
  const Pagination = ({
28
28
  totalString,
29
29
  totalPerPageString,
30
- totalPages,
31
30
  limitsPerPage,
32
31
  setLimit,
33
32
  setPage,
34
33
  page = 1,
34
+ totalRows,
35
35
  limit
36
36
  }: Props) => {
37
37
  const theme = useTheme();
@@ -44,6 +44,28 @@ const Pagination = ({
44
44
  const [internalLimit, setInternalLimit] = useState<number>(
45
45
  limit ?? limitsPerPage[0]
46
46
  );
47
+
48
+ const displayablePages = getTotalPages(totalRows, internalLimit);
49
+
50
+ const changePage = (newPage: number) => {
51
+ setInternalPage(newPage);
52
+ setPage?.(newPage);
53
+ };
54
+
55
+ const changeLimit = (newLimit: number) => {
56
+ setInternalLimit(newLimit);
57
+ setLimit?.(newLimit);
58
+ };
59
+
60
+ const handleChangeLimit = (newLimit: number) => {
61
+ const newDisplayablePages = getTotalPages(totalRows, newLimit);
62
+
63
+ if (newDisplayablePages < displayablePages) {
64
+ changePage(newDisplayablePages);
65
+ }
66
+ changeLimit(newLimit);
67
+ };
68
+
47
69
  useEffect(() => {
48
70
  if (page !== internalPage) {
49
71
  setInternalPage(page);
@@ -57,41 +79,39 @@ const Pagination = ({
57
79
  }, [limit]);
58
80
 
59
81
  return (
60
- <>
82
+ <Box
83
+ display="flex"
84
+ flexDirection="row"
85
+ justifyContent="flex-end"
86
+ sx={{
87
+ padding: '12px 8px'
88
+ }}
89
+ >
61
90
  <Box display="flex">
62
91
  <Text color="greyXDark" variant="body1Bold" pt="10px" pr="16px">
63
- {totalString}
92
+ {totalRows} {totalString}
64
93
  </Text>
65
- {totalPages > 1 && (
94
+ {displayablePages > 1 && (
66
95
  <>
67
96
  <Divider
68
97
  orientation="vertical"
69
98
  sx={{ marginRight: '16px', color: 'greyXLight' }}
70
99
  />
71
100
  <Select
72
- sx={{
73
- // @TODO replace by Select from ui-kit when ready
74
- height: '32px',
75
- width: '75px',
76
- fontSize: '14px',
77
- fontWeight: 400
78
- }}
101
+ label=""
79
102
  className="dac-select-label"
80
103
  labelId="select-label"
81
104
  value={internalLimit}
82
- onChange={(event) => {
83
- setInternalLimit(Number(event?.target?.value));
84
- if (setLimit) {
85
- setLimit(Number(event?.target?.value));
105
+ onChange={handleChangeLimit}
106
+ options={limitsPerPage}
107
+ getRenderValue={(value) => value.toString()}
108
+ width={75}
109
+ sx={{
110
+ '&.MuiInputBase-root': {
111
+ height: '32px !important'
86
112
  }
87
113
  }}
88
- >
89
- {limitsPerPage.map((limit, id) => (
90
- <MenuItem key={id} value={limit}>
91
- {limit}
92
- </MenuItem>
93
- ))}
94
- </Select>
114
+ />
95
115
  <Text
96
116
  color="greyXDark"
97
117
  variant="body1Regular"
@@ -108,23 +128,20 @@ const Pagination = ({
108
128
  </>
109
129
  )}
110
130
  </Box>
111
- {totalPages > 1 && (
131
+ {displayablePages > 1 && (
112
132
  <Box display="flex" pr="4px">
113
133
  <StyledPagination
114
134
  variant="outlined"
115
135
  shape="rounded"
116
- count={totalPages}
136
+ count={displayablePages}
117
137
  page={internalPage}
118
- onChange={(event: React.ChangeEvent<unknown>, value: number) => {
119
- setInternalPage(value);
120
- if (setPage) {
121
- setPage(value);
122
- }
123
- }}
138
+ onChange={(_: React.ChangeEvent<unknown>, value: number) =>
139
+ changePage(value)
140
+ }
124
141
  />
125
142
  </Box>
126
143
  )}
127
- </>
144
+ </Box>
128
145
  );
129
146
  };
130
147
 
@@ -0,0 +1,2 @@
1
+ export const getTotalPages = (totalRows: number, limitPerPage: number) =>
2
+ Math.ceil(totalRows / limitPerPage);
@@ -91,7 +91,8 @@ export const StepComponent = ({
91
91
  palette.greyLightDefaultBorder
92
92
  }
93
93
  sx={{
94
- background: palette.greyXLight
94
+ background: palette.white,
95
+ borderRadius: '50%',
95
96
  }}
96
97
  />
97
98
  <Text
@@ -23,3 +23,4 @@ export { default as BannerNotification } from './BannerNotification/BannerNotifi
23
23
  export { default as Stepper } from './Stepper/Stepper';
24
24
  export { default as Switch } from './Form/Switch/Switch';
25
25
  export { default as DatePicker } from './Form/DatePicker';
26
+ export { default as Datatable } from './Datatable/Datatable';