@eccenca/gui-elements 23.7.0-rc.2 → 23.7.0-rc.4
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/CHANGELOG.md +9 -1
- package/dist/cjs/components/Depiction/Depiction.js +4 -2
- package/dist/cjs/components/Depiction/Depiction.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +5 -33
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/Sticky/StickyTarget.js +46 -5
- package/dist/cjs/components/Sticky/StickyTarget.js.map +1 -1
- package/dist/esm/components/Depiction/Depiction.js +4 -2
- package/dist/esm/components/Depiction/Depiction.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +5 -33
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/Sticky/StickyTarget.js +46 -5
- package/dist/esm/components/Sticky/StickyTarget.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlTypes.d.ts +1 -0
- package/dist/types/components/Depiction/Depiction.d.ts +7 -1
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +14 -9
- package/dist/types/components/Sticky/StickyTarget.d.ts +14 -3
- package/package.json +1 -1
- package/src/cmem/ActivityControl/ActivityControlTypes.ts +2 -0
- package/src/components/Depiction/Depiction.tsx +10 -1
- package/src/components/Depiction/depiction.scss +25 -0
- package/src/components/MultiSelect/MultiSelect.tsx +25 -43
- package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +1 -2
- package/src/components/MultiSuggestField/tests/MultiSuggestField.test.tsx +90 -6
- package/src/components/Select/Select.stories.tsx +11 -2
- package/src/components/Sticky/StickyTarget.tsx +63 -7
- package/src/components/Sticky/sticky.scss +71 -12
- package/src/components/TextField/textfield.scss +3 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StickyTarget.js","sourceRoot":"","sources":["../../../../src/components/Sticky/StickyTarget.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,WAAW,IAAI,MAAM,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"StickyTarget.js","sourceRoot":"","sources":["../../../../src/components/Sticky/StickyTarget.tsx"],"names":[],"mappings":"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"}
|
|
@@ -48,6 +48,12 @@ export interface DepictionProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
48
48
|
* The amount of padding is defined relative to the depiction size, so a small padding on a small depiction is displayed smaller than a small padding on a large depiction.
|
|
49
49
|
*/
|
|
50
50
|
padding?: "none" | "tiny" | "small" | "medium" | "large";
|
|
51
|
+
/**
|
|
52
|
+
* Reduce opacity to let it appear as inactive.
|
|
53
|
+
* Even if it is no form control element it could be used inside one.
|
|
54
|
+
* Use this property if the `disabled` state there is not adapted automatically to the depiction.
|
|
55
|
+
*/
|
|
56
|
+
disabled?: boolean;
|
|
51
57
|
/**
|
|
52
58
|
* Description of the depiction.
|
|
53
59
|
*/
|
|
@@ -68,4 +74,4 @@ export interface DepictionProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
68
74
|
/**
|
|
69
75
|
* Display a graphical representation and attache a caption or a badge to it.
|
|
70
76
|
*/
|
|
71
|
-
export declare function Depiction({ className, image, forceInlineSvg, size, resizing, ratio, caption, captionPosition, backgroundColor, border, rounded, padding, badge, tooltipProps, ...otherFigureProps }: DepictionProps): React.JSX.Element;
|
|
77
|
+
export declare function Depiction({ className, image, forceInlineSvg, size, resizing, ratio, caption, captionPosition, backgroundColor, border, rounded, padding, disabled, badge, tooltipProps, ...otherFigureProps }: DepictionProps): React.JSX.Element;
|
|
@@ -9,11 +9,7 @@ export interface MultiSelectSelectionProps<T> {
|
|
|
9
9
|
createdItems: Partial<T>[];
|
|
10
10
|
}
|
|
11
11
|
export declare type SelectedParamsType<T> = MultiSelectSelectionProps<T>;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Predefined selected values
|
|
15
|
-
*/
|
|
16
|
-
selectedItems?: T[];
|
|
12
|
+
interface MultiSelectCommonProps<T> extends TestableComponent, Pick<BlueprintMultiSelectProps<T>, "items" | "placeholder" | "openOnKeyDown"> {
|
|
17
13
|
/**
|
|
18
14
|
* Additional class name, space separated.
|
|
19
15
|
*/
|
|
@@ -27,10 +23,6 @@ export interface MultiSelectProps<T> extends TestableComponent, Pick<BlueprintMu
|
|
|
27
23
|
* this would be used in the item selection list as well as the multi-select input
|
|
28
24
|
*/
|
|
29
25
|
itemLabel: (item: T) => string;
|
|
30
|
-
/**
|
|
31
|
-
* When set to true will set the multi-select value with all the items provided
|
|
32
|
-
*/
|
|
33
|
-
prePopulateWithItems?: boolean;
|
|
34
26
|
/**
|
|
35
27
|
* function handler that would be called anytime an item is selected/deselected or an item is created/removed
|
|
36
28
|
*/
|
|
@@ -107,6 +99,19 @@ export interface MultiSelectProps<T> extends TestableComponent, Pick<BlueprintMu
|
|
|
107
99
|
*/
|
|
108
100
|
wrapperProps?: React.HTMLAttributes<HTMLDivElement>;
|
|
109
101
|
}
|
|
102
|
+
export declare type MultiSelectProps<T> = MultiSelectCommonProps<T> & ({
|
|
103
|
+
/**
|
|
104
|
+
* Predefined selected values
|
|
105
|
+
*/
|
|
106
|
+
selectedItems?: T[];
|
|
107
|
+
prePopulateWithItems?: never;
|
|
108
|
+
} | {
|
|
109
|
+
selectedItems?: never;
|
|
110
|
+
/**
|
|
111
|
+
* When set to true will set the multi-select value with all the items provided
|
|
112
|
+
*/
|
|
113
|
+
prePopulateWithItems?: boolean;
|
|
114
|
+
});
|
|
110
115
|
/**
|
|
111
116
|
* **Element is deprecated for the current type of usage.**
|
|
112
117
|
* Use `MultiSuggestField` as replacement.
|
|
@@ -9,15 +9,26 @@ export interface StickyTargetProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
9
9
|
* The application header is not taken into offset calculation
|
|
10
10
|
*/
|
|
11
11
|
local?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Set additional distance to original sticky position.
|
|
14
|
+
*/
|
|
15
|
+
offset?: `${number}${string}`;
|
|
12
16
|
/**
|
|
13
17
|
* Set the background color used for the sticky area.
|
|
14
18
|
* As it can overlay other content readability could be harmed if the overlayed content is shining through.
|
|
15
19
|
*/
|
|
16
20
|
background?: "card" | "application" | "transparent";
|
|
17
21
|
/**
|
|
18
|
-
*
|
|
22
|
+
* In some situations there could be a gap between sticky target area and the border of the related scroll area.
|
|
23
|
+
* The main gap is the gap towards the direction of the sticky behaviour, specified by `to`.
|
|
24
|
+
* You can fill this gap with a gradient or full background color.
|
|
19
25
|
*/
|
|
20
|
-
|
|
26
|
+
fillMainGap?: "full" | "gradient";
|
|
27
|
+
/**
|
|
28
|
+
* The secondary gap is the gap against the direction of the sticky behaviour.
|
|
29
|
+
* So in case of `to="top"` this is rendered on the bottom of the sticky area.
|
|
30
|
+
*/
|
|
31
|
+
fillSecondaryGap?: "full" | "gradient";
|
|
21
32
|
/**
|
|
22
33
|
* Callback that returns an DOM element.
|
|
23
34
|
* The position of `StickyTarget` is then calculated relative to that element.
|
|
@@ -28,5 +39,5 @@ export interface StickyTargetProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
28
39
|
* Element wraps the content that need to be displayed sticky.
|
|
29
40
|
* The content then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor).
|
|
30
41
|
*/
|
|
31
|
-
export declare const StickyTarget: ({ className, to, local, background,
|
|
42
|
+
export declare const StickyTarget: ({ className, to, local, offset, background, fillMainGap, fillSecondaryGap, style, getConnectedElement, ...otherDivProps }: StickyTargetProps) => React.JSX.Element;
|
|
32
43
|
export default StickyTarget;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eccenca/gui-elements",
|
|
3
3
|
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
|
|
4
|
-
"version": "23.7.0-rc.
|
|
4
|
+
"version": "23.7.0-rc.4",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/eccenca/gui-elements",
|
|
7
7
|
"bugs": "https://github.com/eccenca/gui-elements/issues",
|
|
@@ -16,6 +16,8 @@ export interface IActivityStatus {
|
|
|
16
16
|
statusName: "Waiting" | "Finished" | "Idle" | "Running" | "Canceling";
|
|
17
17
|
// A number between 0 and 100
|
|
18
18
|
progress: number;
|
|
19
|
+
// timestamp for last update
|
|
20
|
+
lastUpdateTime: number;
|
|
19
21
|
// More information corresponding to the status
|
|
20
22
|
message: string;
|
|
21
23
|
// If the activity has been cancelled
|
|
@@ -56,6 +56,12 @@ export interface DepictionProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
56
56
|
* The amount of padding is defined relative to the depiction size, so a small padding on a small depiction is displayed smaller than a small padding on a large depiction.
|
|
57
57
|
*/
|
|
58
58
|
padding?: "none" | "tiny" | "small" | "medium" | "large";
|
|
59
|
+
/**
|
|
60
|
+
* Reduce opacity to let it appear as inactive.
|
|
61
|
+
* Even if it is no form control element it could be used inside one.
|
|
62
|
+
* Use this property if the `disabled` state there is not adapted automatically to the depiction.
|
|
63
|
+
*/
|
|
64
|
+
disabled?: boolean;
|
|
59
65
|
/**
|
|
60
66
|
* Description of the depiction.
|
|
61
67
|
*/
|
|
@@ -90,6 +96,7 @@ export function Depiction({
|
|
|
90
96
|
border,
|
|
91
97
|
rounded,
|
|
92
98
|
padding = "none",
|
|
99
|
+
disabled,
|
|
93
100
|
badge,
|
|
94
101
|
tooltipProps,
|
|
95
102
|
...otherFigureProps
|
|
@@ -105,6 +112,7 @@ export function Depiction({
|
|
|
105
112
|
[`--${eccgui}-depiction-color`]: decideContrastColorValue({ testColor: color }),
|
|
106
113
|
};
|
|
107
114
|
} catch (ex) {
|
|
115
|
+
// eslint-disable-next-line no-console
|
|
108
116
|
console.warn("Received invalid background color for depiction: " + backgroundColor);
|
|
109
117
|
}
|
|
110
118
|
}
|
|
@@ -171,7 +179,8 @@ export function Depiction({
|
|
|
171
179
|
(backgroundColor ? ` ${eccgui}-depiction__image--color-config` : "") +
|
|
172
180
|
(border ? ` ${eccgui}-depiction__image--hasborder` : "") +
|
|
173
181
|
(rounded ? ` ${eccgui}-depiction__image--roundedborder` : "") +
|
|
174
|
-
(padding && padding !== "none" ? ` ${eccgui}-depiction__image--padding-${padding}` : "")
|
|
182
|
+
(padding && padding !== "none" ? ` ${eccgui}-depiction__image--padding-${padding}` : "") +
|
|
183
|
+
(disabled ? ` ${eccgui}-depiction__image--disabled` : "")
|
|
175
184
|
}
|
|
176
185
|
style={styleDepictionColors as React.CSSProperties}
|
|
177
186
|
>
|
|
@@ -21,6 +21,20 @@ $eccgui-size-depiction-border-radius: $pt-border-radius !default;
|
|
|
21
21
|
& + .#{$eccgui}-overviewitem__description {
|
|
22
22
|
margin-left: mini-units(1);
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
.#{$ns}-button & {
|
|
26
|
+
.#{$eccgui}-icon:first-child:last-child {
|
|
27
|
+
margin-right: 0;
|
|
28
|
+
margin-left: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.#{$ns}-button &:first-child {
|
|
33
|
+
margin-left: -($pt-button-height - $pt-icon-size-standard) * 0.5;
|
|
34
|
+
}
|
|
35
|
+
.#{$ns}-button &:last-child {
|
|
36
|
+
margin-right: -($pt-button-height - $pt-icon-size-standard) * 0.5;
|
|
37
|
+
}
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
.#{$eccgui}-depiction__image {
|
|
@@ -35,6 +49,13 @@ $eccgui-size-depiction-border-radius: $pt-border-radius !default;
|
|
|
35
49
|
height: 100%;
|
|
36
50
|
}
|
|
37
51
|
|
|
52
|
+
*:disabled & {
|
|
53
|
+
img,
|
|
54
|
+
svg:not(.#{$eccgui}-icon) {
|
|
55
|
+
opacity: $eccgui-opacity-disabled;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
38
59
|
.#{$eccgui}-icon {
|
|
39
60
|
vertical-align: initial;
|
|
40
61
|
}
|
|
@@ -53,6 +74,10 @@ $eccgui-size-depiction-border-radius: $pt-border-radius !default;
|
|
|
53
74
|
}
|
|
54
75
|
}
|
|
55
76
|
|
|
77
|
+
.#{$eccgui}-depiction__image--disabled {
|
|
78
|
+
opacity: $eccgui-opacity-disabled;
|
|
79
|
+
}
|
|
80
|
+
|
|
56
81
|
.#{$eccgui}-depiction__image--ratio-source {
|
|
57
82
|
aspect-ratio: auto;
|
|
58
83
|
|
|
@@ -21,14 +21,9 @@ export interface MultiSelectSelectionProps<T> {
|
|
|
21
21
|
// @deprecated use `MultiSelectSelectionProps<T>`
|
|
22
22
|
export type SelectedParamsType<T> = MultiSelectSelectionProps<T>;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
interface MultiSelectCommonProps<T>
|
|
25
25
|
extends TestableComponent,
|
|
26
26
|
Pick<BlueprintMultiSelectProps<T>, "items" | "placeholder" | "openOnKeyDown"> {
|
|
27
|
-
/**
|
|
28
|
-
* Predefined selected values
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
selectedItems?: T[];
|
|
32
27
|
/**
|
|
33
28
|
* Additional class name, space separated.
|
|
34
29
|
*/
|
|
@@ -42,10 +37,7 @@ export interface MultiSelectProps<T>
|
|
|
42
37
|
* this would be used in the item selection list as well as the multi-select input
|
|
43
38
|
*/
|
|
44
39
|
itemLabel: (item: T) => string;
|
|
45
|
-
|
|
46
|
-
* When set to true will set the multi-select value with all the items provided
|
|
47
|
-
*/
|
|
48
|
-
prePopulateWithItems?: boolean;
|
|
40
|
+
|
|
49
41
|
/**
|
|
50
42
|
* function handler that would be called anytime an item is selected/deselected or an item is created/removed
|
|
51
43
|
*/
|
|
@@ -127,6 +119,24 @@ export interface MultiSelectProps<T>
|
|
|
127
119
|
wrapperProps?: React.HTMLAttributes<HTMLDivElement>;
|
|
128
120
|
}
|
|
129
121
|
|
|
122
|
+
export type MultiSelectProps<T> = MultiSelectCommonProps<T> &
|
|
123
|
+
(
|
|
124
|
+
| {
|
|
125
|
+
/**
|
|
126
|
+
* Predefined selected values
|
|
127
|
+
*/
|
|
128
|
+
selectedItems?: T[];
|
|
129
|
+
prePopulateWithItems?: never;
|
|
130
|
+
}
|
|
131
|
+
| {
|
|
132
|
+
selectedItems?: never;
|
|
133
|
+
/**
|
|
134
|
+
* When set to true will set the multi-select value with all the items provided
|
|
135
|
+
*/
|
|
136
|
+
prePopulateWithItems?: boolean;
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
130
140
|
/**
|
|
131
141
|
* **Element is deprecated for the current type of usage.**
|
|
132
142
|
* Use `MultiSuggestField` as replacement.
|
|
@@ -169,7 +179,7 @@ export function MultiSelect<T>({
|
|
|
169
179
|
const [externalItems, setExternalItems] = React.useState<T[]>([...items]);
|
|
170
180
|
// All options (created and passed) that match the query
|
|
171
181
|
const [filteredItems, setFilteredItems] = React.useState<T[]>([]);
|
|
172
|
-
// All options (created and passed) selected by a user
|
|
182
|
+
// All options (created and passed) selected by a user
|
|
173
183
|
const [selectedItems, setSelectedItems] = React.useState<T[]>(() =>
|
|
174
184
|
prePopulateWithItems ? [...items] : externalSelectedItems ? [...externalSelectedItems] : []
|
|
175
185
|
);
|
|
@@ -201,10 +211,6 @@ export function MultiSelect<T>({
|
|
|
201
211
|
break;
|
|
202
212
|
}
|
|
203
213
|
|
|
204
|
-
// If the component is contolled from outside, we don't need to store selected state within the component
|
|
205
|
-
// when user selects or removes selection - options will be set in a parent component
|
|
206
|
-
const isControlled = !!(externalSelectedItems && onSelection);
|
|
207
|
-
|
|
208
214
|
/** Update external items when they change
|
|
209
215
|
* e.g for auto-complete when query change
|
|
210
216
|
*/
|
|
@@ -214,15 +220,13 @@ export function MultiSelect<T>({
|
|
|
214
220
|
}, [items.map((item) => itemId(item)).join("|")]);
|
|
215
221
|
|
|
216
222
|
React.useEffect(() => {
|
|
217
|
-
|
|
218
|
-
onSelection &&
|
|
223
|
+
onSelection &&
|
|
219
224
|
onSelection({
|
|
220
225
|
newlySelected: selectedItems.slice(-1)[0],
|
|
221
226
|
createdItems: createdItems.current,
|
|
222
227
|
selectedItems,
|
|
223
228
|
});
|
|
224
229
|
}, [
|
|
225
|
-
isControlled,
|
|
226
230
|
onSelection,
|
|
227
231
|
selectedItems.map((item) => itemId(item)).join("|"),
|
|
228
232
|
createdItems.current.map((item) => itemId(item)).join("|"),
|
|
@@ -237,7 +241,7 @@ export function MultiSelect<T>({
|
|
|
237
241
|
}
|
|
238
242
|
|
|
239
243
|
setSelectedItems(externalSelectedItems);
|
|
240
|
-
}, [externalSelectedItems]);
|
|
244
|
+
}, [externalSelectedItems?.map((item) => itemId(item)).join("|")]);
|
|
241
245
|
|
|
242
246
|
/**
|
|
243
247
|
* using the equality prop specified checks if an item has already been selected
|
|
@@ -254,15 +258,7 @@ export function MultiSelect<T>({
|
|
|
254
258
|
*/
|
|
255
259
|
const removeItemSelection = (matcher: string) => {
|
|
256
260
|
const filteredItems = selectedItems.filter((item) => itemId(item) !== matcher);
|
|
257
|
-
|
|
258
|
-
if (isControlled) {
|
|
259
|
-
onSelection({
|
|
260
|
-
createdItems: createdItems.current,
|
|
261
|
-
selectedItems: filteredItems,
|
|
262
|
-
});
|
|
263
|
-
} else {
|
|
264
|
-
setSelectedItems(filteredItems);
|
|
265
|
-
}
|
|
261
|
+
setSelectedItems(filteredItems);
|
|
266
262
|
};
|
|
267
263
|
|
|
268
264
|
/**
|
|
@@ -273,12 +269,6 @@ export function MultiSelect<T>({
|
|
|
273
269
|
const onItemSelect = (item: T) => {
|
|
274
270
|
if (itemHasBeenSelectedAlready(itemId(item))) {
|
|
275
271
|
removeItemSelection(itemId(item));
|
|
276
|
-
} else if (isControlled) {
|
|
277
|
-
onSelection({
|
|
278
|
-
newlySelected: item,
|
|
279
|
-
createdItems: createdItems.current,
|
|
280
|
-
selectedItems: [...selectedItems, item],
|
|
281
|
-
});
|
|
282
272
|
} else {
|
|
283
273
|
setSelectedItems((items) => [...items, item]);
|
|
284
274
|
}
|
|
@@ -358,15 +348,7 @@ export function MultiSelect<T>({
|
|
|
358
348
|
const handleClear = () => {
|
|
359
349
|
requestState.current.query = "";
|
|
360
350
|
|
|
361
|
-
|
|
362
|
-
onSelection({
|
|
363
|
-
selectedItems: [],
|
|
364
|
-
createdItems: createdItems.current,
|
|
365
|
-
});
|
|
366
|
-
} else {
|
|
367
|
-
setSelectedItems([]);
|
|
368
|
-
}
|
|
369
|
-
|
|
351
|
+
setSelectedItems([]);
|
|
370
352
|
setFilteredItems([...externalItems, ...createdItems.current]);
|
|
371
353
|
};
|
|
372
354
|
|
|
@@ -125,7 +125,7 @@ uncontrolledNewItemCreation.args = {
|
|
|
125
125
|
};
|
|
126
126
|
|
|
127
127
|
const CreationTemplate: StoryFn = () => {
|
|
128
|
-
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
|
128
|
+
const [selectedValues, setSelectedValues] = useState<string[]>(["foo"]);
|
|
129
129
|
|
|
130
130
|
const items = useMemo<string[]>(() => ["foo", "bar", "baz"], []);
|
|
131
131
|
|
|
@@ -145,7 +145,6 @@ const CreationTemplate: StoryFn = () => {
|
|
|
145
145
|
itemId={identity}
|
|
146
146
|
itemLabel={identity}
|
|
147
147
|
createNewItemFromQuery={identity}
|
|
148
|
-
prePopulateWithItems
|
|
149
148
|
/>
|
|
150
149
|
);
|
|
151
150
|
};
|
|
@@ -47,7 +47,7 @@ export const TestComponent = (): JSX.Element => {
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
describe("MultiSuggestField", () => {
|
|
50
|
-
describe("uncontrolled", () => {
|
|
50
|
+
describe("uncontrolled (when only selectedItems or onSelect is provided)", () => {
|
|
51
51
|
it("should render default input", () => {
|
|
52
52
|
const { container } = render(<MultiSuggestField {...Default.args} />);
|
|
53
53
|
const [input] = container.getElementsByClassName("eccgui-multiselect");
|
|
@@ -262,7 +262,7 @@ describe("MultiSuggestField", () => {
|
|
|
262
262
|
});
|
|
263
263
|
});
|
|
264
264
|
|
|
265
|
-
describe("controlled", () => {
|
|
265
|
+
describe("controlled (when both selectedItems and onSelect are provided)", () => {
|
|
266
266
|
it("should render default selected items", async () => {
|
|
267
267
|
const onSelection = jest.fn();
|
|
268
268
|
|
|
@@ -287,7 +287,12 @@ describe("MultiSuggestField", () => {
|
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
const { container } = render(
|
|
290
|
-
<MultiSuggestField
|
|
290
|
+
<MultiSuggestField
|
|
291
|
+
{...dropdownOnFocus.args}
|
|
292
|
+
items={items}
|
|
293
|
+
selectedItems={[]}
|
|
294
|
+
onSelection={onSelection}
|
|
295
|
+
/>
|
|
291
296
|
);
|
|
292
297
|
|
|
293
298
|
const [inputContainer] = container.getElementsByClassName("eccgui-multiselect");
|
|
@@ -355,7 +360,6 @@ describe("MultiSuggestField", () => {
|
|
|
355
360
|
newlySelected: items[0],
|
|
356
361
|
selectedItems: [items[0]],
|
|
357
362
|
};
|
|
358
|
-
expect(onSelection).toHaveBeenCalledTimes(1);
|
|
359
363
|
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
360
364
|
});
|
|
361
365
|
|
|
@@ -381,7 +385,6 @@ describe("MultiSuggestField", () => {
|
|
|
381
385
|
selectedItems: [...selectedItems, items[0]],
|
|
382
386
|
};
|
|
383
387
|
|
|
384
|
-
expect(onSelection).toHaveBeenCalledTimes(2);
|
|
385
388
|
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
386
389
|
});
|
|
387
390
|
|
|
@@ -399,9 +402,90 @@ describe("MultiSuggestField", () => {
|
|
|
399
402
|
selectedItems: [],
|
|
400
403
|
};
|
|
401
404
|
|
|
402
|
-
expect(onSelection).toHaveBeenCalledTimes(3);
|
|
403
405
|
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
404
406
|
});
|
|
405
407
|
});
|
|
408
|
+
|
|
409
|
+
it("should set prePopulateWithItems as selected values and override passed values", async () => {
|
|
410
|
+
const onSelection = jest.fn((values) => {
|
|
411
|
+
// eslint-disable-next-line no-console
|
|
412
|
+
console.log("Mocked onSelection function values: ", values);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
const items = dropdownOnFocus.args.items;
|
|
416
|
+
|
|
417
|
+
const args = { ...dropdownOnFocus.args, onSelection: onSelection };
|
|
418
|
+
|
|
419
|
+
const { container } = render(
|
|
420
|
+
<MultiSuggestField {...args} data-test-id="multi-suggest-field" prePopulateWithItems />
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
await waitFor(() => {
|
|
424
|
+
const expectedObject = {
|
|
425
|
+
createdItems: [],
|
|
426
|
+
newlySelected: items.at(-1),
|
|
427
|
+
selectedItems: items,
|
|
428
|
+
};
|
|
429
|
+
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
const tags = container.querySelectorAll("span[data-tag-index]");
|
|
433
|
+
|
|
434
|
+
expect(tags.length).toBe(items.length);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it("should correctly deselect all tags from input", async () => {
|
|
438
|
+
const onSelection = jest.fn((values) => {
|
|
439
|
+
// eslint-disable-next-line no-console
|
|
440
|
+
console.log("Mocked onSelection function values 111: ", values);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const items = predefinedNotControlledValues.args.items;
|
|
444
|
+
|
|
445
|
+
const args = { ...predefinedNotControlledValues.args, selectedItems: undefined, onSelection: onSelection };
|
|
446
|
+
|
|
447
|
+
const { container } = render(
|
|
448
|
+
<MultiSuggestField {...args} data-test-id="multi-suggest-field" prePopulateWithItems />
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
await waitFor(() => {
|
|
452
|
+
const expectedObject = {
|
|
453
|
+
createdItems: [],
|
|
454
|
+
newlySelected: items.at(-1),
|
|
455
|
+
selectedItems: items,
|
|
456
|
+
};
|
|
457
|
+
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
let tags = container.querySelectorAll("span[data-tag-index]");
|
|
461
|
+
expect(tags.length).toBe(items.length);
|
|
462
|
+
|
|
463
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
464
|
+
const tag = tags[0];
|
|
465
|
+
expect(tag.querySelector("span")).toHaveTextContent(items[i].testLabel);
|
|
466
|
+
|
|
467
|
+
const removeTagButton = tag.querySelector("button");
|
|
468
|
+
expect(removeTagButton).toBeTruthy();
|
|
469
|
+
|
|
470
|
+
fireEvent.click(removeTagButton!);
|
|
471
|
+
|
|
472
|
+
await waitFor(() => {
|
|
473
|
+
const selected = items.slice(i + 1);
|
|
474
|
+
|
|
475
|
+
const expectedObject = {
|
|
476
|
+
createdItems: [],
|
|
477
|
+
newlySelected: selected.at(-1),
|
|
478
|
+
selectedItems: selected,
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
tags = container.querySelectorAll("span[data-tag-index]");
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const tagsAfterRemove = container.querySelectorAll("span[data-tag-index]");
|
|
488
|
+
expect(tagsAfterRemove.length).toBe(0);
|
|
489
|
+
});
|
|
406
490
|
});
|
|
407
491
|
});
|
|
@@ -3,7 +3,8 @@ import { loremIpsum } from "react-lorem-ipsum";
|
|
|
3
3
|
import { Meta, StoryFn } from "@storybook/react";
|
|
4
4
|
|
|
5
5
|
import { helpersArgTypes } from "../../../.storybook/helpers";
|
|
6
|
-
import { Button, MenuItem, Select } from "../../index";
|
|
6
|
+
import { Button, Depiction, MenuItem, Select } from "../../index";
|
|
7
|
+
import { FullExample as DepictionExample } from "../Depiction/stories/Depiction.stories";
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
title: "Forms/Select",
|
|
@@ -32,7 +33,15 @@ Default.args = {
|
|
|
32
33
|
return <MenuItem text={item.label} title={item.label} />;
|
|
33
34
|
},
|
|
34
35
|
fill: true,
|
|
35
|
-
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Using a `Depiction` element instead of a simple `icon` name
|
|
40
|
+
*/
|
|
41
|
+
export const UsingDepictionAsIcon = Template.bind({});
|
|
42
|
+
UsingDepictionAsIcon.args = {
|
|
43
|
+
...Default.args,
|
|
44
|
+
icon: <Depiction {...DepictionExample.args} size="tiny" resizing="cover" ratio="1:1" />,
|
|
36
45
|
};
|
|
37
46
|
|
|
38
47
|
/**
|