@onewelcome/react-lib-components 8.1.2 → 8.2.0
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/dist/cjs/DataGrid/DataGrid.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGrid.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridBody.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridBody.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridCell/DataGridCell.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridCell/DataGridCell.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridCell/DataGridCell.module.scss.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridRow/DataGridRow.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridRow/DataGridRow.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridRow/DataGridRow.module.scss.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridBody/DataGridRow/useNestedRow.cjs.js +2 -0
- package/dist/cjs/DataGrid/DataGridBody/DataGridRow/useNestedRow.cjs.js.map +1 -0
- package/dist/cjs/DataGrid/DataGridFilters/DataGridFilterPopover.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridFilters/DataGridFilterPopover.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridFilters/DataGridFilters.interfaces.cjs.js.map +1 -1
- package/dist/cjs/DataGrid/DataGridFilters/DataGridToolbar.module.scss.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridHeader/DataGridHeader.cjs.js +1 -1
- package/dist/cjs/DataGrid/DataGridHeader/DataGridHeader.cjs.js.map +1 -1
- package/dist/cjs/Form/Wrapper/InputWrapper/InputWrapper.module.scss.cjs.js +1 -1
- package/dist/cjs/Notifications/Alert/AlertContainer/AlertContainer.module.scss.cjs.js +1 -1
- package/dist/cjs/Notifications/Alert/AlertItem/AlertItem.module.scss.cjs.js +1 -1
- package/dist/cjs/src/components/DataGrid/DataGrid.d.ts +3 -0
- package/dist/cjs/src/components/DataGrid/DataGridBody/DataGridBody.d.ts +3 -0
- package/dist/cjs/src/components/DataGrid/DataGridBody/DataGridCell/DataGridCell.d.ts +1 -0
- package/dist/cjs/src/components/DataGrid/DataGridBody/DataGridRow/DataGridRow.d.ts +19 -3
- package/dist/cjs/src/components/DataGrid/DataGridBody/DataGridRow/DataGridWithNestedRows.test.d.ts +1 -0
- package/dist/cjs/src/components/DataGrid/DataGridBody/DataGridRow/useNestedRow.d.ts +855 -0
- package/dist/cjs/src/components/DataGrid/DataGridFilters/DataGridFilters.interfaces.d.ts +1 -0
- package/dist/cjs/src/components/DataGrid/DataGridHeader/DataGridHeader.d.ts +1 -0
- package/dist/esm/DataGrid/DataGrid.esm.js +3 -3
- package/dist/esm/DataGrid/DataGrid.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridBody/DataGridBody.esm.js +9 -2
- package/dist/esm/DataGrid/DataGridBody/DataGridBody.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridBody/DataGridCell/DataGridCell.esm.js +7 -4
- package/dist/esm/DataGrid/DataGridBody/DataGridCell/DataGridCell.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridBody/DataGridCell/DataGridCell.module.scss.esm.js +2 -2
- package/dist/esm/DataGrid/DataGridBody/DataGridRow/DataGridRow.esm.js +41 -11
- package/dist/esm/DataGrid/DataGridBody/DataGridRow/DataGridRow.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridBody/DataGridRow/DataGridRow.module.scss.esm.js +2 -2
- package/dist/esm/DataGrid/DataGridBody/DataGridRow/useNestedRow.esm.js +92 -0
- package/dist/esm/DataGrid/DataGridBody/DataGridRow/useNestedRow.esm.js.map +1 -0
- package/dist/esm/DataGrid/DataGridFilters/DataGridFilterPopover.esm.js +13 -9
- package/dist/esm/DataGrid/DataGridFilters/DataGridFilterPopover.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridFilters/DataGridFilters.interfaces.esm.js.map +1 -1
- package/dist/esm/DataGrid/DataGridFilters/DataGridToolbar.module.scss.esm.js +1 -1
- package/dist/esm/DataGrid/DataGridHeader/DataGridHeader.esm.js +1 -1
- package/dist/esm/DataGrid/DataGridHeader/DataGridHeader.esm.js.map +1 -1
- package/dist/esm/Form/Wrapper/InputWrapper/InputWrapper.module.scss.esm.js +2 -2
- package/dist/esm/Notifications/Alert/AlertContainer/AlertContainer.module.scss.esm.js +1 -1
- package/dist/esm/Notifications/Alert/AlertItem/AlertItem.module.scss.esm.js +1 -1
- package/dist/esm/src/components/DataGrid/DataGrid.d.ts +3 -0
- package/dist/esm/src/components/DataGrid/DataGridBody/DataGridBody.d.ts +3 -0
- package/dist/esm/src/components/DataGrid/DataGridBody/DataGridCell/DataGridCell.d.ts +1 -0
- package/dist/esm/src/components/DataGrid/DataGridBody/DataGridRow/DataGridRow.d.ts +19 -3
- package/dist/esm/src/components/DataGrid/DataGridBody/DataGridRow/DataGridWithNestedRows.test.d.ts +1 -0
- package/dist/esm/src/components/DataGrid/DataGridBody/DataGridRow/useNestedRow.d.ts +855 -0
- package/dist/esm/src/components/DataGrid/DataGridFilters/DataGridFilters.interfaces.d.ts +1 -0
- package/dist/esm/src/components/DataGrid/DataGridHeader/DataGridHeader.d.ts +1 -0
- package/package.json +6 -5
- package/src/components/DataGrid/DataGrid.tsx +6 -0
- package/src/components/DataGrid/DataGridBody/DataGridBody.tsx +12 -1
- package/src/components/DataGrid/DataGridBody/DataGridCell/DataGridCell.module.scss +6 -0
- package/src/components/DataGrid/DataGridBody/DataGridCell/DataGridCell.tsx +30 -5
- package/src/components/DataGrid/DataGridBody/DataGridRow/DataGridRow.module.scss +98 -5
- package/src/components/DataGrid/DataGridBody/DataGridRow/DataGridRow.tsx +83 -16
- package/src/components/DataGrid/DataGridBody/DataGridRow/useNestedRow.tsx +143 -0
- package/src/components/DataGrid/DataGridFilters/DataGridFilterPopover.tsx +15 -10
- package/src/components/DataGrid/DataGridFilters/DataGridFilters.interfaces.ts +1 -0
- package/src/components/DataGrid/DataGridFilters/DataGridToolbar.module.scss +2 -0
- package/src/components/DataGrid/DataGridHeader/DataGridHeader.tsx +2 -0
- package/src/components/Form/Wrapper/InputWrapper/InputWrapper.module.scss +2 -0
- package/src/components/Notifications/Alert/AlertContainer/AlertContainer.module.scss +2 -1
- package/src/components/Notifications/Alert/AlertItem/AlertItem.module.scss +3 -1
- package/src/components/Notifications/Alert/alertVariables.scss +17 -0
- package/src/mixins.module.scss +12 -0
|
@@ -5,6 +5,7 @@ export interface Props extends ComponentPropsWithRef<"thead"> {
|
|
|
5
5
|
initialSort?: Sort;
|
|
6
6
|
onSort?: OnSortFunction;
|
|
7
7
|
enableExpandableRow?: boolean;
|
|
8
|
+
enableNestedRows?: boolean;
|
|
8
9
|
disableContextMenuColumn?: boolean;
|
|
9
10
|
enableMultiSorting?: boolean;
|
|
10
11
|
spacing?: React.CSSProperties;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"homepage": "http://onewelcome.github.io/react-lib-components",
|
|
3
3
|
"name": "@onewelcome/react-lib-components",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.2.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "OneWelcome B.V.",
|
|
7
7
|
"main": "dist/cjs/src/index.cjs.js",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"analyze": "size-limit --why",
|
|
34
|
-
"build": "
|
|
34
|
+
"build": "rimraf dist && rollup -c --bundleConfigAsCjs",
|
|
35
35
|
"build-storybook": "storybook build",
|
|
36
36
|
"chromatic": "chromatic --exit-zero-on-changes",
|
|
37
37
|
"dev": "npm-run-all -p start test:watch storybook",
|
|
38
|
-
"lint": "eslint
|
|
39
|
-
"prepare": "husky
|
|
38
|
+
"lint": "eslint \"**/*.{ts,tsx}\"",
|
|
39
|
+
"prepare": "husky && rollup -c --bundleConfigAsCjs",
|
|
40
40
|
"size": "size-limit",
|
|
41
41
|
"start": "rollup -c -w --bundleConfigAsCjs",
|
|
42
42
|
"test": "jest",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"eslint-plugin-react": "^7.34.3",
|
|
103
103
|
"eslint-plugin-react-hooks": "^4.6.2",
|
|
104
104
|
"eslint-plugin-storybook": "^0.8.0",
|
|
105
|
-
"husky": "^9.
|
|
105
|
+
"husky": "^9.1.6",
|
|
106
106
|
"identity-obj-proxy": "^3.0.0",
|
|
107
107
|
"jest": "^29.7.0",
|
|
108
108
|
"jest-environment-jsdom": "^29.7.0",
|
|
@@ -120,6 +120,7 @@
|
|
|
120
120
|
"react-is": "^18.3.1",
|
|
121
121
|
"react-router-dom": "^6.24.1",
|
|
122
122
|
"remark-gfm": "^4.0.0",
|
|
123
|
+
"rimraf": "^6.0.1",
|
|
123
124
|
"rollup": "^4.18.0",
|
|
124
125
|
"rollup-plugin-postcss": "^4.0.2",
|
|
125
126
|
"sass": "^1.77.6",
|
|
@@ -52,6 +52,9 @@ export interface Props<T> extends Omit<ComponentPropsWithRef<"div">, "children">
|
|
|
52
52
|
searchBtnProps?: ButtonProps;
|
|
53
53
|
searchIconBtnProps?: ButtonProps;
|
|
54
54
|
};
|
|
55
|
+
nestedRowConfig?: {
|
|
56
|
+
nestedItemsKey?: keyof T;
|
|
57
|
+
};
|
|
55
58
|
emptyLabel?: string;
|
|
56
59
|
paginationProps?: PaginationProps;
|
|
57
60
|
disableContextMenuColumn?: boolean;
|
|
@@ -75,6 +78,7 @@ const DataGridInner = <T extends {}>(
|
|
|
75
78
|
headers,
|
|
76
79
|
actions = {},
|
|
77
80
|
paginationProps,
|
|
81
|
+
nestedRowConfig,
|
|
78
82
|
disableContextMenuColumn,
|
|
79
83
|
enableExpandableRow,
|
|
80
84
|
filters,
|
|
@@ -177,6 +181,7 @@ const DataGridInner = <T extends {}>(
|
|
|
177
181
|
onSort={onSort}
|
|
178
182
|
disableContextMenuColumn={disableContextMenuColumn}
|
|
179
183
|
enableExpandableRow={enableExpandableRow}
|
|
184
|
+
enableNestedRows={!!nestedRowConfig}
|
|
180
185
|
enableMultiSorting={enableMultiSorting}
|
|
181
186
|
spacing={styleWithSpacing}
|
|
182
187
|
/>
|
|
@@ -185,6 +190,7 @@ const DataGridInner = <T extends {}>(
|
|
|
185
190
|
headers={internalHeaders}
|
|
186
191
|
isLoading={isLoading}
|
|
187
192
|
disableContextMenuColumn={disableContextMenuColumn}
|
|
193
|
+
nestedRowConfig={nestedRowConfig}
|
|
188
194
|
emptyLabel={emptyLabel}
|
|
189
195
|
spacing={styleWithSpacing}
|
|
190
196
|
searchValue={search?.initialSearchValue}
|
|
@@ -24,6 +24,9 @@ import { Typography } from "../../Typography/Typography";
|
|
|
24
24
|
export interface Props<T> extends Omit<ComponentPropsWithRef<"tbody">, "children"> {
|
|
25
25
|
children: ({ item, index }: { item: T; index: number }) => ReactElement;
|
|
26
26
|
data?: T[];
|
|
27
|
+
nestedRowConfig?: {
|
|
28
|
+
nestedItemsKey?: keyof T;
|
|
29
|
+
};
|
|
27
30
|
headers: HeaderCell[];
|
|
28
31
|
isLoading?: boolean;
|
|
29
32
|
disableContextMenuColumn?: boolean;
|
|
@@ -39,6 +42,7 @@ const DataGridBodyInner = <T extends {}>(
|
|
|
39
42
|
children,
|
|
40
43
|
data,
|
|
41
44
|
headers,
|
|
45
|
+
nestedRowConfig,
|
|
42
46
|
isLoading,
|
|
43
47
|
disableContextMenuColumn,
|
|
44
48
|
emptyLabel,
|
|
@@ -82,7 +86,14 @@ const DataGridBodyInner = <T extends {}>(
|
|
|
82
86
|
searchValue: searchValue,
|
|
83
87
|
headers,
|
|
84
88
|
spacing,
|
|
85
|
-
|
|
89
|
+
item,
|
|
90
|
+
disableContextMenuColumn,
|
|
91
|
+
nestedRowProps: {
|
|
92
|
+
rowTemplate: children,
|
|
93
|
+
enableNestedRow: !!nestedRowConfig,
|
|
94
|
+
nestedItemsKey: nestedRowConfig?.nestedItemsKey,
|
|
95
|
+
isLastChild: index + 1 === data.length
|
|
96
|
+
}
|
|
86
97
|
});
|
|
87
98
|
});
|
|
88
99
|
};
|
|
@@ -25,6 +25,7 @@ import classes from "./DataGridCell.module.scss";
|
|
|
25
25
|
|
|
26
26
|
export interface Props extends ComponentPropsWithRef<"td"> {
|
|
27
27
|
children?: ReactElement | string | number;
|
|
28
|
+
prefixElement?: ReactElement;
|
|
28
29
|
isLoading?: boolean;
|
|
29
30
|
spacing?: React.CSSProperties;
|
|
30
31
|
searchValue?: string;
|
|
@@ -39,6 +40,7 @@ const DataGridCellComponent: ForwardRefRenderFunction<HTMLTableCellElement, Prop
|
|
|
39
40
|
className,
|
|
40
41
|
isLoading,
|
|
41
42
|
spacing,
|
|
43
|
+
prefixElement,
|
|
42
44
|
searchValue,
|
|
43
45
|
cellIndex,
|
|
44
46
|
columnLength,
|
|
@@ -91,11 +93,34 @@ const DataGridCellComponent: ForwardRefRenderFunction<HTMLTableCellElement, Prop
|
|
|
91
93
|
style={{ ...rest.style, ...cellStyle }}
|
|
92
94
|
className={`${classes["cell"]} ${className ?? ""}`}
|
|
93
95
|
>
|
|
94
|
-
{
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
96
|
+
{prefixElement ? (
|
|
97
|
+
<div className={classes["content-wrapper"]}>
|
|
98
|
+
{prefixElement}
|
|
99
|
+
{isLoading && (
|
|
100
|
+
<div className={classes["loading"]} aria-busy="true" aria-live="polite"></div>
|
|
101
|
+
)}
|
|
102
|
+
{!isLoading && (
|
|
103
|
+
<Typography
|
|
104
|
+
className={classes["text"]}
|
|
105
|
+
variant="body"
|
|
106
|
+
tag="span"
|
|
107
|
+
spacing={{ marginBottom: 0 }}
|
|
108
|
+
>
|
|
109
|
+
{renderContent()}
|
|
110
|
+
</Typography>
|
|
111
|
+
)}
|
|
112
|
+
</div>
|
|
113
|
+
) : (
|
|
114
|
+
<>
|
|
115
|
+
{isLoading && (
|
|
116
|
+
<div className={classes["loading"]} aria-busy="true" aria-live="polite"></div>
|
|
117
|
+
)}
|
|
118
|
+
{!isLoading && (
|
|
119
|
+
<Typography className={classes["text"]} variant="body" tag="span">
|
|
120
|
+
{renderContent()}
|
|
121
|
+
</Typography>
|
|
122
|
+
)}
|
|
123
|
+
</>
|
|
99
124
|
)}
|
|
100
125
|
</td>
|
|
101
126
|
);
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
$nesting-limit: 6;
|
|
16
17
|
|
|
17
18
|
.row {
|
|
18
19
|
position: relative;
|
|
@@ -22,24 +23,45 @@
|
|
|
22
23
|
background-color: var(--data-grid-row-hover-background-color);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
@mixin borderAfter {
|
|
26
|
+
@mixin borderAfter($i, $no-offset: false) {
|
|
26
27
|
content: "";
|
|
27
28
|
position: absolute;
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
@if $no-offset {
|
|
31
|
+
width: 100%;
|
|
32
|
+
left: 0;
|
|
33
|
+
} @else if $i > 0 {
|
|
34
|
+
width: calc(100% - calc(3.0625rem + $i * 4.125rem));
|
|
35
|
+
left: calc(3.0625rem + $i * 4.125rem);
|
|
36
|
+
} @else {
|
|
37
|
+
width: calc(100% - 3.0625rem);
|
|
38
|
+
left: 3.0625rem;
|
|
39
|
+
}
|
|
30
40
|
bottom: 0;
|
|
31
41
|
border-bottom: 1px solid var(--light-grey-border);
|
|
32
42
|
}
|
|
33
43
|
|
|
44
|
+
@mixin border-x {
|
|
45
|
+
@for $i from 0 through $nesting-limit {
|
|
46
|
+
&.border-#{$i} {
|
|
47
|
+
&:not(:last-child)::after {
|
|
48
|
+
@include borderAfter($i);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@include border-x();
|
|
55
|
+
|
|
34
56
|
&.border {
|
|
35
57
|
&:not(:last-child)::after {
|
|
36
|
-
@include borderAfter();
|
|
58
|
+
@include borderAfter(0, true);
|
|
37
59
|
}
|
|
38
60
|
}
|
|
39
61
|
|
|
40
62
|
&.border-drawer {
|
|
41
63
|
&:not(:last-child):not(:nth-last-child(2))::after {
|
|
42
|
-
@include borderAfter();
|
|
64
|
+
@include borderAfter(0, true);
|
|
43
65
|
}
|
|
44
66
|
}
|
|
45
67
|
}
|
|
@@ -47,3 +69,74 @@
|
|
|
47
69
|
.expand-button-cell {
|
|
48
70
|
padding: 0;
|
|
49
71
|
}
|
|
72
|
+
|
|
73
|
+
@mixin offset-left {
|
|
74
|
+
@for $i from 0 through $nesting-limit {
|
|
75
|
+
&.offset-left-#{$i} {
|
|
76
|
+
left: $i * 4.125rem;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.connector {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
left: 0;
|
|
85
|
+
width: 2.875rem;
|
|
86
|
+
height: 3.25rem;
|
|
87
|
+
|
|
88
|
+
@include offset-left();
|
|
89
|
+
|
|
90
|
+
&.vertical {
|
|
91
|
+
&::before {
|
|
92
|
+
position: absolute;
|
|
93
|
+
content: "";
|
|
94
|
+
left: 50%;
|
|
95
|
+
height: 100%;
|
|
96
|
+
width: 0.0625rem;
|
|
97
|
+
background-color: var(--color-blue-grey200);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&.t-shape {
|
|
102
|
+
&::before {
|
|
103
|
+
position: absolute;
|
|
104
|
+
content: "";
|
|
105
|
+
left: 50%;
|
|
106
|
+
height: 3.25rem;
|
|
107
|
+
width: 0.0625rem;
|
|
108
|
+
background-color: var(--color-blue-grey200);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&::after {
|
|
112
|
+
position: absolute;
|
|
113
|
+
content: "";
|
|
114
|
+
top: 50%;
|
|
115
|
+
left: 50%;
|
|
116
|
+
height: 0.0625rem;
|
|
117
|
+
width: 100%;
|
|
118
|
+
background-color: var(--color-blue-grey200);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.line {
|
|
123
|
+
&::before {
|
|
124
|
+
position: absolute;
|
|
125
|
+
content: "";
|
|
126
|
+
left: 50%;
|
|
127
|
+
height: 50%;
|
|
128
|
+
width: 1px;
|
|
129
|
+
background-color: var(--color-blue-grey200);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&::after {
|
|
133
|
+
position: absolute;
|
|
134
|
+
content: "";
|
|
135
|
+
top: 50%;
|
|
136
|
+
left: 50%;
|
|
137
|
+
height: 1px;
|
|
138
|
+
width: 100%;
|
|
139
|
+
background-color: var(--color-blue-grey200);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import React, { ComponentPropsWithRef, useState, Fragment,
|
|
17
|
+
import React, { ComponentPropsWithRef, useState, Fragment, Ref, ReactElement } from "react";
|
|
18
18
|
import { HeaderCell } from "../../datagrid.interfaces";
|
|
19
19
|
import classes from "./DataGridRow.module.scss";
|
|
20
20
|
import { IconButton } from "../../../Button/IconButton";
|
|
@@ -22,13 +22,22 @@ import { Icon, Icons } from "../../../Icon/Icon";
|
|
|
22
22
|
import { DataGridCell } from "../DataGridCell/DataGridCell";
|
|
23
23
|
import { DataGridDrawer } from "../DataGridDrawer/DataGridDrawer";
|
|
24
24
|
import { generateID } from "../../../../util/helper";
|
|
25
|
+
import { useNestedRow } from "./useNestedRow";
|
|
25
26
|
|
|
26
|
-
export interface Props extends ComponentPropsWithRef<"tr"> {
|
|
27
|
+
export interface Props<T> extends ComponentPropsWithRef<"tr"> {
|
|
28
|
+
item?: T;
|
|
27
29
|
headers?: HeaderCell[];
|
|
28
30
|
isLoading?: boolean;
|
|
29
31
|
spacing?: React.CSSProperties;
|
|
30
32
|
searchValue?: string;
|
|
31
33
|
disableContextMenuColumn?: boolean;
|
|
34
|
+
nestedRowProps?: {
|
|
35
|
+
rowTemplate?: ({ item, index }: { item: T; index: number }) => ReactElement;
|
|
36
|
+
indentationLevel?: number;
|
|
37
|
+
indentationLevels?: { level: number; isLastChild: boolean }[];
|
|
38
|
+
enableNestedRow?: boolean;
|
|
39
|
+
nestedItemsKey?: keyof T;
|
|
40
|
+
};
|
|
32
41
|
expandableRowProps?: {
|
|
33
42
|
enableExpandableRow: boolean;
|
|
34
43
|
expandableRowContent: React.ReactNode;
|
|
@@ -38,8 +47,9 @@ export interface Props extends ComponentPropsWithRef<"tr"> {
|
|
|
38
47
|
};
|
|
39
48
|
}
|
|
40
49
|
|
|
41
|
-
const DataGridRowComponent
|
|
50
|
+
const DataGridRowComponent = <T,>(
|
|
42
51
|
{
|
|
52
|
+
item,
|
|
43
53
|
children,
|
|
44
54
|
className,
|
|
45
55
|
headers,
|
|
@@ -48,9 +58,10 @@ const DataGridRowComponent: ForwardRefRenderFunction<HTMLTableRowElement, Props>
|
|
|
48
58
|
spacing,
|
|
49
59
|
expandableRowProps,
|
|
50
60
|
disableContextMenuColumn,
|
|
61
|
+
nestedRowProps,
|
|
51
62
|
...rest
|
|
52
|
-
}
|
|
53
|
-
ref
|
|
63
|
+
}: Props<T>,
|
|
64
|
+
ref: Ref<HTMLTableRowElement>
|
|
54
65
|
) => {
|
|
55
66
|
const {
|
|
56
67
|
enableExpandableRow = false,
|
|
@@ -59,15 +70,73 @@ const DataGridRowComponent: ForwardRefRenderFunction<HTMLTableRowElement, Props>
|
|
|
59
70
|
drawerId = `ID-${generateID()}`,
|
|
60
71
|
expandableRowContent
|
|
61
72
|
} = expandableRowProps || {};
|
|
73
|
+
const {
|
|
74
|
+
indentationLevels,
|
|
75
|
+
indentationLevel = 0,
|
|
76
|
+
nestedItemsKey,
|
|
77
|
+
enableNestedRow,
|
|
78
|
+
rowTemplate
|
|
79
|
+
} = nestedRowProps || {};
|
|
62
80
|
const [isRowExpanded, setIsRowExpanded] = useState(false);
|
|
81
|
+
const { renderNestedRowConnectors, renderNestedRow, getNestedChildSpacing, hasNestedChildren } =
|
|
82
|
+
useNestedRow({
|
|
83
|
+
indentationLevels,
|
|
84
|
+
indentationLevel,
|
|
85
|
+
item,
|
|
86
|
+
nestedItemsKey,
|
|
87
|
+
rowTemplate,
|
|
88
|
+
isRowExpanded,
|
|
89
|
+
enableNestedRow,
|
|
90
|
+
rowProps: {
|
|
91
|
+
searchValue,
|
|
92
|
+
headers,
|
|
93
|
+
spacing,
|
|
94
|
+
disableContextMenuColumn
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const classNames = [classes["row"]];
|
|
99
|
+
const rowBorderClass = enableNestedRow
|
|
100
|
+
? classes[`border-${indentationLevel}`]
|
|
101
|
+
: classes[`border`];
|
|
102
|
+
|
|
103
|
+
className && classNames.push(className);
|
|
104
|
+
enableExpandableRow
|
|
105
|
+
? !isRowExpanded && classNames.push(classes["border-drawer"])
|
|
106
|
+
: classNames.push(rowBorderClass);
|
|
107
|
+
isLoading && classNames.push(classes["loading"]);
|
|
108
|
+
|
|
109
|
+
const getPrefixButton = (hasNestedChildren: boolean) =>
|
|
110
|
+
hasNestedChildren ? (
|
|
111
|
+
<IconButton
|
|
112
|
+
id={expandButtonId}
|
|
113
|
+
title={expandButtonTitle}
|
|
114
|
+
aria-expanded={isRowExpanded}
|
|
115
|
+
onClick={() => setIsRowExpanded(!isRowExpanded)}
|
|
116
|
+
>
|
|
117
|
+
<Icon size="0.75rem" icon={isRowExpanded ? Icons.ChevronUp : Icons.ChevronDown} />
|
|
118
|
+
</IconButton>
|
|
119
|
+
) : null;
|
|
120
|
+
|
|
63
121
|
const visibleCells = React.Children.map(children as React.ReactElement[], (child, index) => {
|
|
122
|
+
const childSpacing = enableNestedRow ? getNestedChildSpacing(spacing, index) : spacing;
|
|
123
|
+
|
|
124
|
+
const prefixElement =
|
|
125
|
+
enableNestedRow && index === 0 ? (
|
|
126
|
+
<>
|
|
127
|
+
{getPrefixButton(!!hasNestedChildren)}
|
|
128
|
+
{renderNestedRowConnectors()}
|
|
129
|
+
</>
|
|
130
|
+
) : null;
|
|
131
|
+
|
|
64
132
|
if (child) {
|
|
65
133
|
const cellWithSpacing = React.cloneElement(child, {
|
|
66
134
|
searchValue,
|
|
67
|
-
spacing:
|
|
135
|
+
spacing: childSpacing,
|
|
68
136
|
cellIndex: index,
|
|
69
137
|
columnLength: headers?.length,
|
|
70
|
-
disableContextMenuColumn
|
|
138
|
+
disableContextMenuColumn,
|
|
139
|
+
prefixElement
|
|
71
140
|
});
|
|
72
141
|
|
|
73
142
|
const visible = headers && headers.length > index ? !headers[index].hidden : true;
|
|
@@ -76,13 +145,6 @@ const DataGridRowComponent: ForwardRefRenderFunction<HTMLTableRowElement, Props>
|
|
|
76
145
|
return null;
|
|
77
146
|
});
|
|
78
147
|
|
|
79
|
-
const classNames = [classes["row"]];
|
|
80
|
-
className && classNames.push(className);
|
|
81
|
-
enableExpandableRow
|
|
82
|
-
? !isRowExpanded && classNames.push(classes["border-drawer"])
|
|
83
|
-
: classNames.push(classes["border"]);
|
|
84
|
-
isLoading && classNames.push(classes["loading"]);
|
|
85
|
-
|
|
86
148
|
return (
|
|
87
149
|
<Fragment>
|
|
88
150
|
<tr {...rest} ref={ref} className={classNames.join(" ")}>
|
|
@@ -90,7 +152,9 @@ const DataGridRowComponent: ForwardRefRenderFunction<HTMLTableRowElement, Props>
|
|
|
90
152
|
<DataGridCell
|
|
91
153
|
className={classes["expand-button-cell"]}
|
|
92
154
|
onClick={() => setIsRowExpanded(!isRowExpanded)}
|
|
93
|
-
style={{
|
|
155
|
+
style={{
|
|
156
|
+
width: "1px"
|
|
157
|
+
}}
|
|
94
158
|
>
|
|
95
159
|
<IconButton
|
|
96
160
|
id={expandButtonId}
|
|
@@ -118,8 +182,11 @@ const DataGridRowComponent: ForwardRefRenderFunction<HTMLTableRowElement, Props>
|
|
|
118
182
|
</td>
|
|
119
183
|
</tr>
|
|
120
184
|
)}
|
|
185
|
+
{enableNestedRow && renderNestedRow()}
|
|
121
186
|
</Fragment>
|
|
122
187
|
);
|
|
123
188
|
};
|
|
124
189
|
|
|
125
|
-
export const DataGridRow = React.forwardRef(DataGridRowComponent)
|
|
190
|
+
export const DataGridRow = React.forwardRef(DataGridRowComponent) as <T extends {}>(
|
|
191
|
+
p: Props<T> & { ref?: Ref<HTMLTableRowElement> }
|
|
192
|
+
) => ReactElement;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import React, { ReactElement } from "react";
|
|
18
|
+
import classes from "./DataGridRow.module.scss";
|
|
19
|
+
import { HeaderCell } from "../../datagrid.interfaces";
|
|
20
|
+
|
|
21
|
+
export interface UseNestedRowProps<T> {
|
|
22
|
+
indentationLevels?: { level: number; isLastChild: boolean }[];
|
|
23
|
+
item?: T;
|
|
24
|
+
nestedItemsKey?: keyof T;
|
|
25
|
+
rowTemplate?: ({ item, index }: { item: T; index: number }) => ReactElement;
|
|
26
|
+
isRowExpanded?: boolean;
|
|
27
|
+
indentationLevel: number;
|
|
28
|
+
enableNestedRow?: boolean;
|
|
29
|
+
rowProps: {
|
|
30
|
+
searchValue?: string;
|
|
31
|
+
headers?: HeaderCell[];
|
|
32
|
+
spacing?: React.CSSProperties;
|
|
33
|
+
disableContextMenuColumn?: boolean;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const useNestedRow = <T,>({
|
|
38
|
+
indentationLevels,
|
|
39
|
+
item,
|
|
40
|
+
nestedItemsKey,
|
|
41
|
+
rowTemplate,
|
|
42
|
+
isRowExpanded,
|
|
43
|
+
indentationLevel,
|
|
44
|
+
enableNestedRow,
|
|
45
|
+
rowProps: { searchValue, headers, spacing, disableContextMenuColumn }
|
|
46
|
+
}: UseNestedRowProps<T>) => {
|
|
47
|
+
const hasNestedChildren = item && nestedItemsKey && item[nestedItemsKey];
|
|
48
|
+
|
|
49
|
+
const getNestedChildSpacing = (spacing: React.CSSProperties | undefined, index: number) => {
|
|
50
|
+
const expandButtonWidth = 46;
|
|
51
|
+
const nestedChildOffset = !hasNestedChildren ? expandButtonWidth : 0;
|
|
52
|
+
|
|
53
|
+
const connectorWidth = 68;
|
|
54
|
+
const nestedChildIndentation = `${nestedChildOffset + indentationLevel * connectorWidth}`;
|
|
55
|
+
|
|
56
|
+
const gap = 4;
|
|
57
|
+
const notIndentedWithNoChildrenOffset =
|
|
58
|
+
indentationLevel === 0 && !hasNestedChildren ? expandButtonWidth + gap : gap;
|
|
59
|
+
const childIndentation = `${indentationLevel ? nestedChildIndentation : notIndentedWithNoChildrenOffset}px`;
|
|
60
|
+
|
|
61
|
+
if (spacing) {
|
|
62
|
+
return {
|
|
63
|
+
...spacing,
|
|
64
|
+
paddingLeft: index === 0 ? childIndentation : spacing.paddingLeft
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
paddingLeft: index === 0 ? childIndentation : ""
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const renderNestedRowConnectors = () => {
|
|
73
|
+
if (indentationLevels) {
|
|
74
|
+
return indentationLevels.map(({ level, isLastChild }) =>
|
|
75
|
+
renderNestedRowConnector(level, isLastChild, indentationLevels.length)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const renderNestedRowConnector = (level: number, isLastChild: boolean, levelsLength: number) => {
|
|
83
|
+
const offsetLeftClass = classes[`offset-left-${level - 1}`];
|
|
84
|
+
|
|
85
|
+
if (level === levelsLength) {
|
|
86
|
+
const variant = isLastChild ? "line" : "t-shape";
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div
|
|
90
|
+
key={level}
|
|
91
|
+
data-testid="dataGridRowConnector"
|
|
92
|
+
className={`${classes["connector"]} ${classes[variant]} ${offsetLeftClass}`}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
} else if (!isLastChild) {
|
|
96
|
+
return (
|
|
97
|
+
<div
|
|
98
|
+
key={level}
|
|
99
|
+
data-testid="dataGridRowConnector"
|
|
100
|
+
className={`${classes["connector"]} ${classes["vertical"]} ${offsetLeftClass}`}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const renderNestedRow = () => {
|
|
108
|
+
if (rowTemplate && item && nestedItemsKey && item[nestedItemsKey] && isRowExpanded) {
|
|
109
|
+
const nestedItemsArray: T[] = item[nestedItemsKey] as T[];
|
|
110
|
+
const getIndentationLevel = (index: number) => ({
|
|
111
|
+
level: indentationLevel + 1,
|
|
112
|
+
isLastChild: index + 1 === nestedItemsArray.length
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return nestedItemsArray.map((item, index) => {
|
|
116
|
+
return React.cloneElement(rowTemplate({ item, index }), {
|
|
117
|
+
searchValue,
|
|
118
|
+
headers,
|
|
119
|
+
spacing,
|
|
120
|
+
disableContextMenuColumn,
|
|
121
|
+
item,
|
|
122
|
+
nestedRowProps: {
|
|
123
|
+
rowTemplate,
|
|
124
|
+
enableNestedRow,
|
|
125
|
+
nestedItemsKey,
|
|
126
|
+
indentationLevel: indentationLevel + 1,
|
|
127
|
+
indentationLevels:
|
|
128
|
+
indentationLevels && nestedItemsArray
|
|
129
|
+
? [...indentationLevels, getIndentationLevel(index)]
|
|
130
|
+
: [getIndentationLevel(index)]
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
renderNestedRow,
|
|
139
|
+
renderNestedRowConnectors,
|
|
140
|
+
getNestedChildSpacing,
|
|
141
|
+
hasNestedChildren
|
|
142
|
+
};
|
|
143
|
+
};
|
|
@@ -87,6 +87,9 @@ export const DataGridFilterPopover = ({
|
|
|
87
87
|
}
|
|
88
88
|
}, [isOpen]);
|
|
89
89
|
|
|
90
|
+
const columnMetadata = columnsMetadata.find(({ name }) => name === column);
|
|
91
|
+
const disableAddNew = columnMetadata?.disableAddNew;
|
|
92
|
+
|
|
90
93
|
return (
|
|
91
94
|
<Popover
|
|
92
95
|
tabIndex={-1}
|
|
@@ -153,16 +156,18 @@ export const DataGridFilterPopover = ({
|
|
|
153
156
|
)
|
|
154
157
|
}
|
|
155
158
|
selectProps={{
|
|
156
|
-
addNew:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
addNew: disableAddNew
|
|
160
|
+
? undefined
|
|
161
|
+
: {
|
|
162
|
+
label: addNewValueLabel,
|
|
163
|
+
onAddNew: value => {
|
|
164
|
+
if (value) {
|
|
165
|
+
setValues(prev => [...prev, value]);
|
|
166
|
+
setPickedValues(prev => [...prev, value]);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
btnProps: { title: addNewValueButtonTitle, type: "button" }
|
|
170
|
+
},
|
|
166
171
|
search: {
|
|
167
172
|
enabled: true,
|
|
168
173
|
renderThreshold: 0
|