@eccenca/gui-elements 25.1.0-rc.3 → 25.1.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/CHANGELOG.md +19 -0
- package/dist/cjs/components/Button/Button.js +1 -1
- package/dist/cjs/components/Button/Button.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +7 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +24 -6
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/Button/Button.js +1 -1
- package/dist/esm/components/Button/Button.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +7 -1
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +25 -7
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +7 -1
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +1 -0
- package/package.json +11 -7
- package/src/cmem/markdown/Markdown.stories.tsx +2 -2
- package/src/cmem/markdown/markdown.scss +1 -1
- package/src/components/Badge/Badge.test.tsx +22 -0
- package/src/components/Breadcrumb/breadcrumb.scss +2 -2
- package/src/components/Button/Button.test.tsx +16 -2
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Button/button.scss +2 -0
- package/src/components/Dialog/dialog.scss +2 -2
- package/src/components/Form/form.scss +2 -2
- package/src/components/Icon/canonicalIconNames.tsx +9 -2
- package/src/components/MultiSelect/MultiSelect.tsx +37 -9
- package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +40 -1
- package/src/components/MultiSuggestField/tests/MultiSuggestField.test.tsx +88 -3
- package/src/components/Pagination/pagination.scss +1 -1
- package/src/components/Tabs/tabs.scss +2 -2
- package/src/components/Tag/tag.scss +2 -2
- package/src/components/Toolbar/toolbar.scss +1 -2
- package/src/components/Typography/_reset.scss +1 -0
- package/src/components/Typography/typography.scss +10 -4
- package/src/extensions/react-flow/_react-flow_v12.scss +1 -1
- package/src/extensions/react-flow/handles/_handles.scss +3 -3
- package/src/includes/carbon-components/_requisits.scss +3 -1
|
@@ -36,7 +36,7 @@ This is a paragraph.
|
|
|
36
36
|
* another line
|
|
37
37
|
3. third item
|
|
38
38
|
|
|
39
|
-
This is a paragraph with a [text link](http://example.com/) and a footnote reference [^1].
|
|
39
|
+
This is a paragraph with a [text link](http://example.com/), some \`inline code\`, and a footnote reference [^1].
|
|
40
40
|
|
|
41
41
|
## Headline level 2
|
|
42
42
|
### Headline level 3
|
|
@@ -44,7 +44,7 @@ This is a paragraph with a [text link](http://example.com/) and a footnote refer
|
|
|
44
44
|
##### Headline level 5
|
|
45
45
|
###### Headline level 6
|
|
46
46
|
|
|
47
|
-
This is a code block.
|
|
47
|
+
This is a code block.
|
|
48
48
|
|
|
49
49
|
\`\`\`
|
|
50
50
|
another code block
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
a[href=""]:not(#{$eccgui-selector-text-spot-highlight}) {
|
|
56
56
|
font-size: $eccgui-size-typo-caption;
|
|
57
57
|
line-height: $eccgui-size-typo-caption-lineheight;
|
|
58
|
-
text-decoration: none;
|
|
59
58
|
vertical-align: super;
|
|
59
|
+
text-decoration: none;
|
|
60
60
|
|
|
61
61
|
&::before {
|
|
62
62
|
content: "[";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import "@testing-library/jest-dom";
|
|
5
|
+
|
|
6
|
+
import { Badge } from "../../../index";
|
|
7
|
+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
8
|
+
|
|
9
|
+
describe("Badge", () => {
|
|
10
|
+
it("should shorten a number badge exceeding maxLength to a 9+ notation", () => {
|
|
11
|
+
const { container } = render(<Badge maxLength={2}>{42}</Badge>);
|
|
12
|
+
const badge = container.querySelector(`.${eccgui}-badge__tag`);
|
|
13
|
+
expect(badge).not.toBeNull();
|
|
14
|
+
expect(badge).toHaveTextContent("9+");
|
|
15
|
+
});
|
|
16
|
+
it("should apply maxWidth style to a string badge when maxLength is set", () => {
|
|
17
|
+
const { container } = render(<Badge maxLength={4}>forty two</Badge>);
|
|
18
|
+
const tag = container.querySelector(`.${eccgui}-badge__tag`);
|
|
19
|
+
expect(tag).not.toBeNull();
|
|
20
|
+
expect((tag as HTMLElement).style.maxWidth).toBe("calc((3em + 3ch)/2)");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -19,8 +19,8 @@ $eccgui-color-breadcrumb-link: $eccgui-color-accent !default;
|
|
|
19
19
|
width: $eccgui-size-block-whitespace;
|
|
20
20
|
height: auto;
|
|
21
21
|
margin: 0;
|
|
22
|
-
text-align: center;
|
|
23
22
|
vertical-align: middle;
|
|
23
|
+
text-align: center;
|
|
24
24
|
content: ">";
|
|
25
25
|
background: none;
|
|
26
26
|
}
|
|
@@ -61,8 +61,8 @@ $eccgui-color-breadcrumb-link: $eccgui-color-accent !default;
|
|
|
61
61
|
.#{$eccgui}-breadcrumb__item {
|
|
62
62
|
display: inline-block;
|
|
63
63
|
overflow: hidden;
|
|
64
|
-
font-size: inherit;
|
|
65
64
|
text-overflow: ellipsis;
|
|
65
|
+
font-size: inherit;
|
|
66
66
|
|
|
67
67
|
a {
|
|
68
68
|
@extend .#{$eccgui}-breadcrumb__item;
|
|
@@ -3,6 +3,7 @@ import { render, screen } from "@testing-library/react";
|
|
|
3
3
|
|
|
4
4
|
import "@testing-library/jest-dom";
|
|
5
5
|
|
|
6
|
+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
6
7
|
import Icon from "../Icon/Icon";
|
|
7
8
|
|
|
8
9
|
import Button from "./Button";
|
|
@@ -21,7 +22,7 @@ describe("Button", () => {
|
|
|
21
22
|
</Button>
|
|
22
23
|
);
|
|
23
24
|
expect(screen.getByRole("button").lastChild).toEqual(screen.getByText(/left icon/i));
|
|
24
|
-
expect(container.getElementsByClassName(
|
|
25
|
+
expect(container.getElementsByClassName(`${eccgui}-icon`).length).toBe(1);
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
it("should have icon at the right after the text", () => {
|
|
@@ -31,6 +32,19 @@ describe("Button", () => {
|
|
|
31
32
|
</Button>
|
|
32
33
|
);
|
|
33
34
|
expect(screen.getByRole("button").firstChild).toEqual(screen.getByText(/right icon/i));
|
|
34
|
-
expect(container.getElementsByClassName(
|
|
35
|
+
expect(container.getElementsByClassName(`${eccgui}-icon`).length).toBe(1);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should render badge markup with correct content when used on an icon button", () => {
|
|
39
|
+
const { container } = render(<Button name="item-info" badge={"badge content"} text={"Cation label"} />);
|
|
40
|
+
const badge = container.querySelector(`.${eccgui}-badge`);
|
|
41
|
+
expect(badge).not.toBeNull();
|
|
42
|
+
expect(badge).toHaveTextContent("badge content");
|
|
43
|
+
});
|
|
44
|
+
it("should render badge markup with correct content when batch displays a 0 (zero) number on an icon button", () => {
|
|
45
|
+
const { container } = render(<Button name="item-info" badge={0} text={"Cation label"} />);
|
|
46
|
+
const badge = container.querySelector(`.${eccgui}-badge`);
|
|
47
|
+
expect(badge).not.toBeNull();
|
|
48
|
+
expect(badge).toHaveTextContent("0");
|
|
35
49
|
});
|
|
36
50
|
});
|
|
@@ -113,7 +113,7 @@ export const Button = ({
|
|
|
113
113
|
rightIcon={typeof rightIcon === "string" ? <Icon name={rightIcon} /> : rightIcon}
|
|
114
114
|
>
|
|
115
115
|
{children}
|
|
116
|
-
{badge && (
|
|
116
|
+
{typeof badge !== "undefined" && (
|
|
117
117
|
<Badge
|
|
118
118
|
children={badge}
|
|
119
119
|
{...constructBadgeProperties({
|
|
@@ -166,7 +166,9 @@ $button-intents: (
|
|
|
166
166
|
// special case override: blueprint do not use configured colors here
|
|
167
167
|
@include eccgui-enhance-blueprint-button-intent("primary");
|
|
168
168
|
@include eccgui-enhance-blueprint-button-intent("accent");
|
|
169
|
+
@include eccgui-enhance-blueprint-button-intent("success");
|
|
169
170
|
@include eccgui-enhance-blueprint-button-intent("warning");
|
|
171
|
+
@include eccgui-enhance-blueprint-button-intent("danger");
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
.#{$ns}-button-text {
|
|
@@ -41,7 +41,7 @@ $eccgui-color-modal-backdrop: eccgui-color-rgba(
|
|
|
41
41
|
max-width: calc(100vw - 4rem);
|
|
42
42
|
max-height: calc(100vh - 4rem);
|
|
43
43
|
margin: 2rem;
|
|
44
|
-
pointer-events:
|
|
44
|
+
pointer-events: auto;
|
|
45
45
|
user-select: text;
|
|
46
46
|
|
|
47
47
|
& > * {
|
|
@@ -50,7 +50,7 @@ $eccgui-color-modal-backdrop: eccgui-color-rgba(
|
|
|
50
50
|
max-width: 100%;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
*:has(> svg) {
|
|
54
54
|
pointer-events: all;
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -71,8 +71,8 @@ form {
|
|
|
71
71
|
|
|
72
72
|
.#{$eccgui}-fieldset {
|
|
73
73
|
legend {
|
|
74
|
-
display: block;
|
|
75
74
|
float: left;
|
|
75
|
+
display: block;
|
|
76
76
|
width: 100%;
|
|
77
77
|
color: $eccgui-color-applicationheader-text;
|
|
78
78
|
}
|
|
@@ -133,9 +133,9 @@ form {
|
|
|
133
133
|
.#{$eccgui}-fieldset__fielditems {
|
|
134
134
|
&:not(:first-child) {
|
|
135
135
|
&::before {
|
|
136
|
+
clear: both;
|
|
136
137
|
display: block;
|
|
137
138
|
height: $eccgui-size-block-whitespace;
|
|
138
|
-
clear: both;
|
|
139
139
|
content: " ";
|
|
140
140
|
}
|
|
141
141
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as icons from "@carbon/react/icons";
|
|
2
2
|
import { CarbonIconType as IconType } from "@carbon/react/icons";
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import { transform } from "./transformIcon";
|
|
4
5
|
|
|
5
6
|
const canonicalIcons = {
|
|
6
7
|
"application-activities": icons.Activity,
|
|
@@ -73,6 +74,8 @@ const canonicalIcons = {
|
|
|
73
74
|
"data-time": icons.Time,
|
|
74
75
|
"data-datetime": icons.EventSchedule,
|
|
75
76
|
"data-number": icons.StringInteger,
|
|
77
|
+
"data-sourceschema": icons.PortOutput,
|
|
78
|
+
"data-targetschema": icons.PortInput,
|
|
76
79
|
|
|
77
80
|
"entity-human": icons.User,
|
|
78
81
|
"entity-robot": icons.Bot,
|
|
@@ -138,14 +141,16 @@ const canonicalIcons = {
|
|
|
138
141
|
"navigation-up": icons.ArrowUp,
|
|
139
142
|
|
|
140
143
|
"operation-aggregation": icons.DataCollection,
|
|
144
|
+
"operation-ai-generate": icons.AiGenerate,
|
|
141
145
|
"operation-autolayout": icons.ChartNetwork,
|
|
142
146
|
"operation-clear": icons.Close,
|
|
143
147
|
"operation-commit": icons.Commit,
|
|
144
148
|
"operation-comparison": icons.Compare,
|
|
145
149
|
"operation-erase": icons.Erase,
|
|
150
|
+
"operation-filter": icons.Filter,
|
|
146
151
|
"operation-filteredit": icons.FilterEdit,
|
|
147
152
|
"operation-filterremove": icons.FilterRemove,
|
|
148
|
-
"operation-
|
|
153
|
+
"operation-filterreset": icons.FilterReset,
|
|
149
154
|
"operation-focus": icons.CenterSquare,
|
|
150
155
|
"operation-format-codeblock": icons.CodeBlock,
|
|
151
156
|
"operation-format-text-code": icons.Code,
|
|
@@ -212,6 +217,8 @@ const canonicalIcons = {
|
|
|
212
217
|
"toggler-star-filled": icons.StarFilled,
|
|
213
218
|
"toggler-table": icons.Table,
|
|
214
219
|
"toggler-tree": icons.TreeViewAlt,
|
|
220
|
+
"toggler-pin-empty": icons.Pin,
|
|
221
|
+
"toggler-pin-filled": icons.PinFilled,
|
|
215
222
|
|
|
216
223
|
"form-template": icons.Parameter,
|
|
217
224
|
|
|
@@ -17,11 +17,12 @@ import {
|
|
|
17
17
|
IconButton,
|
|
18
18
|
MenuItem,
|
|
19
19
|
OverflowText,
|
|
20
|
-
Spinner
|
|
20
|
+
Spinner,
|
|
21
21
|
} from "./../../index";
|
|
22
22
|
|
|
23
23
|
export interface MultiSuggestFieldSelectionProps<T> {
|
|
24
24
|
newlySelected?: T;
|
|
25
|
+
newlyRemoved?: T;
|
|
25
26
|
selectedItems: T[];
|
|
26
27
|
createdItems: Partial<T>[];
|
|
27
28
|
}
|
|
@@ -178,6 +179,8 @@ export function MultiSuggestField<T>({
|
|
|
178
179
|
intent,
|
|
179
180
|
...otherMultiSelectProps
|
|
180
181
|
}: MultiSuggestFieldProps<T>) {
|
|
182
|
+
type SelectionChange = { type: "selected"; item: T } | { type: "removed"; item: T } | { type: "none" };
|
|
183
|
+
|
|
181
184
|
// Options created by a user
|
|
182
185
|
const createdItems = useRef<T[]>([]);
|
|
183
186
|
// Options passed ouside (f.e. from the backend)
|
|
@@ -199,6 +202,7 @@ export function MultiSuggestField<T>({
|
|
|
199
202
|
query?: string;
|
|
200
203
|
timeoutId?: number;
|
|
201
204
|
}>({});
|
|
205
|
+
const selectionChange = useRef<SelectionChange>({ type: "none" });
|
|
202
206
|
|
|
203
207
|
/** Update external items when they change
|
|
204
208
|
* e.g for auto-complete when query change
|
|
@@ -209,11 +213,21 @@ export function MultiSuggestField<T>({
|
|
|
209
213
|
}, [items.map((item) => itemId(item)).join("|")]);
|
|
210
214
|
|
|
211
215
|
React.useEffect(() => {
|
|
212
|
-
|
|
213
|
-
newlySelected: selectedItems.slice(-1)[0],
|
|
216
|
+
const selectionParams: MultiSuggestFieldSelectionProps<T> = {
|
|
214
217
|
createdItems: createdItems.current,
|
|
215
218
|
selectedItems,
|
|
216
|
-
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
if (selectionChange.current.type === "selected") {
|
|
222
|
+
selectionParams.newlySelected = selectionChange.current.item;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (selectionChange.current.type === "removed") {
|
|
226
|
+
selectionParams.newlyRemoved = selectionChange.current.item;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
onSelection?.(selectionParams);
|
|
230
|
+
selectionChange.current = { type: "none" };
|
|
217
231
|
}, [
|
|
218
232
|
onSelection,
|
|
219
233
|
selectedItems.map((item) => itemId(item)).join("|"),
|
|
@@ -228,6 +242,7 @@ export function MultiSuggestField<T>({
|
|
|
228
242
|
return;
|
|
229
243
|
}
|
|
230
244
|
|
|
245
|
+
selectionChange.current = { type: "none" };
|
|
231
246
|
setSelectedItems(externalSelectedItems);
|
|
232
247
|
}, [externalSelectedItems?.map((item) => itemId(item)).join("|")]);
|
|
233
248
|
|
|
@@ -268,13 +283,18 @@ export function MultiSuggestField<T>({
|
|
|
268
283
|
* @param matcher
|
|
269
284
|
*/
|
|
270
285
|
const removeItemSelection = (matcher: string) => {
|
|
271
|
-
|
|
272
|
-
|
|
286
|
+
setSelectedItems((items) => {
|
|
287
|
+
const removedItem = items.find((item) => itemId(item) === matcher);
|
|
288
|
+
|
|
289
|
+
selectionChange.current = removedItem ? { type: "removed", item: removedItem } : { type: "none" };
|
|
290
|
+
|
|
291
|
+
return items.filter((item) => itemId(item) !== matcher);
|
|
292
|
+
});
|
|
273
293
|
};
|
|
274
294
|
|
|
275
295
|
const defaultFilterPredicate = (item: T, query: string) => {
|
|
276
|
-
const searchWords = highlighterUtils.extractSearchWords(query, true)
|
|
277
|
-
return highlighterUtils.matchesAllWords(itemLabel(item).toLowerCase(), searchWords)
|
|
296
|
+
const searchWords = highlighterUtils.extractSearchWords(query, true);
|
|
297
|
+
return highlighterUtils.matchesAllWords(itemLabel(item).toLowerCase(), searchWords);
|
|
278
298
|
};
|
|
279
299
|
|
|
280
300
|
/**
|
|
@@ -286,6 +306,7 @@ export function MultiSuggestField<T>({
|
|
|
286
306
|
if (itemHasBeenSelectedAlready(itemId(item))) {
|
|
287
307
|
removeItemSelection(itemId(item));
|
|
288
308
|
} else {
|
|
309
|
+
selectionChange.current = { type: "selected", item };
|
|
289
310
|
setSelectedItems((items) => [...items, item]);
|
|
290
311
|
}
|
|
291
312
|
|
|
@@ -365,6 +386,7 @@ export function MultiSuggestField<T>({
|
|
|
365
386
|
const handleClear = () => {
|
|
366
387
|
requestState.current.query = "";
|
|
367
388
|
|
|
389
|
+
selectionChange.current = { type: "none" };
|
|
368
390
|
setSelectedItems([]);
|
|
369
391
|
setFilteredItems([...externalItems, ...createdItems.current]);
|
|
370
392
|
};
|
|
@@ -375,7 +397,13 @@ export function MultiSuggestField<T>({
|
|
|
375
397
|
* @param index
|
|
376
398
|
*/
|
|
377
399
|
const removeTagFromSelectionViaIndex = (_label: React.ReactNode, index: number) => {
|
|
378
|
-
setSelectedItems(
|
|
400
|
+
setSelectedItems((items) => {
|
|
401
|
+
const removedItem = items[index];
|
|
402
|
+
|
|
403
|
+
selectionChange.current = removedItem ? { type: "removed", item: removedItem } : { type: "none" };
|
|
404
|
+
|
|
405
|
+
return [...items.slice(0, index), ...items.slice(index + 1)];
|
|
406
|
+
});
|
|
379
407
|
};
|
|
380
408
|
|
|
381
409
|
/**
|
|
@@ -5,6 +5,8 @@ import { Meta, StoryFn } from "@storybook/react";
|
|
|
5
5
|
import { fn } from "@storybook/test";
|
|
6
6
|
|
|
7
7
|
import { helpersArgTypes } from "../../../.storybook/helpers";
|
|
8
|
+
import { Notification } from "../Notification/Notification";
|
|
9
|
+
import Spacing from "../Separation/Spacing";
|
|
8
10
|
|
|
9
11
|
import { MultiSuggestField, MultiSuggestFieldSelectionProps, SimpleDialog } from "./../../../index";
|
|
10
12
|
|
|
@@ -61,7 +63,7 @@ Default.args = {
|
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
65
|
* Display always the dropdown after the element was clicked on.
|
|
64
|
-
* Do not wait until the query input was
|
|
66
|
+
* Do not wait until the query input was started.
|
|
65
67
|
*/
|
|
66
68
|
export const dropdownOnFocus = Template.bind({});
|
|
67
69
|
dropdownOnFocus.args = {
|
|
@@ -259,3 +261,40 @@ CustomSearch.args = {
|
|
|
259
261
|
return item.testId.toLowerCase().includes(query) || item.testLabel.toLowerCase().includes(query);
|
|
260
262
|
},
|
|
261
263
|
};
|
|
264
|
+
|
|
265
|
+
const SelectionNotificationComponent = (): React.JSX.Element => {
|
|
266
|
+
const [notification, setNotification] = useState<string | null>(null);
|
|
267
|
+
|
|
268
|
+
const availableItems = useMemo<string[]>(() => ["existing item"], []);
|
|
269
|
+
|
|
270
|
+
const identity = useCallback((item: string): string => item, []);
|
|
271
|
+
|
|
272
|
+
const handleOnSelect = useCallback((params: MultiSuggestFieldSelectionProps<string>) => {
|
|
273
|
+
if (params.newlySelected) {
|
|
274
|
+
setNotification(`Element added: ${params.newlySelected}`);
|
|
275
|
+
} else if (params.newlyRemoved) {
|
|
276
|
+
setNotification(`Element removed: ${params.newlyRemoved}`);
|
|
277
|
+
}
|
|
278
|
+
}, []);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<OverlaysProvider>
|
|
282
|
+
{notification && <Notification intent={"info"}>{notification}</Notification>}
|
|
283
|
+
<Spacing size={"medium"} />
|
|
284
|
+
<MultiSuggestField<string>
|
|
285
|
+
items={availableItems}
|
|
286
|
+
prePopulateWithItems={true}
|
|
287
|
+
onSelection={handleOnSelect}
|
|
288
|
+
itemId={identity}
|
|
289
|
+
itemLabel={identity}
|
|
290
|
+
createNewItemFromQuery={identity}
|
|
291
|
+
/>
|
|
292
|
+
</OverlaysProvider>
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Demonstrates the `newlySelected` and `newlyRemoved` properties of the `onSelection` callback.
|
|
298
|
+
* A notification appears when an element is added or removed from the selection.
|
|
299
|
+
*/
|
|
300
|
+
export const selectionNotification = SelectionNotificationComponent.bind({});
|
|
@@ -261,6 +261,86 @@ describe("MultiSuggestField", () => {
|
|
|
261
261
|
});
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
+
it("should set newlySelected only when an item is added", async () => {
|
|
265
|
+
const onSelection = jest.fn();
|
|
266
|
+
const initiallySelected = predefinedNotControlledValues.args.selectedItems;
|
|
267
|
+
|
|
268
|
+
const { container } = render(
|
|
269
|
+
<MultiSuggestField
|
|
270
|
+
{...dropdownOnFocus.args}
|
|
271
|
+
items={items}
|
|
272
|
+
selectedItems={initiallySelected}
|
|
273
|
+
onSelection={onSelection}
|
|
274
|
+
/>
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
await waitFor(() => {
|
|
278
|
+
expect(onSelection).toHaveBeenCalledWith({
|
|
279
|
+
createdItems: [],
|
|
280
|
+
selectedItems: initiallySelected,
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
onSelection.mockClear();
|
|
285
|
+
|
|
286
|
+
const [inputContainer] = container.getElementsByClassName("eccgui-multiselect");
|
|
287
|
+
const [input] = inputContainer.getElementsByTagName("input");
|
|
288
|
+
|
|
289
|
+
fireEvent.click(input);
|
|
290
|
+
|
|
291
|
+
await waitFor(() => {
|
|
292
|
+
const listbox = screen.getByRole("listbox");
|
|
293
|
+
const menuItems = listbox.getElementsByClassName("eccgui-menu__item");
|
|
294
|
+
|
|
295
|
+
expect(menuItems.length).toBe(dropdownOnFocus.args.items.length);
|
|
296
|
+
|
|
297
|
+
fireEvent.click(menuItems[2]);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
await waitFor(() => {
|
|
301
|
+
expect(onSelection).toHaveBeenLastCalledWith({
|
|
302
|
+
createdItems: [],
|
|
303
|
+
newlySelected: items[2],
|
|
304
|
+
selectedItems: [...initiallySelected, items[2]],
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("should set newlyRemoved only when an item is removed", async () => {
|
|
310
|
+
const onSelection = jest.fn();
|
|
311
|
+
const initiallySelected = predefinedNotControlledValues.args.selectedItems;
|
|
312
|
+
|
|
313
|
+
const { container } = render(
|
|
314
|
+
<MultiSuggestField
|
|
315
|
+
{...predefinedNotControlledValues.args}
|
|
316
|
+
selectedItems={initiallySelected}
|
|
317
|
+
onSelection={onSelection}
|
|
318
|
+
/>
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
await waitFor(() => {
|
|
322
|
+
expect(onSelection).toHaveBeenCalledWith({
|
|
323
|
+
createdItems: [],
|
|
324
|
+
selectedItems: initiallySelected,
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
onSelection.mockClear();
|
|
329
|
+
|
|
330
|
+
const [firstTag] = Array.from(container.querySelectorAll("span[data-tag-index]"));
|
|
331
|
+
const removeTagButton = firstTag.querySelector("button");
|
|
332
|
+
|
|
333
|
+
fireEvent.click(removeTagButton!);
|
|
334
|
+
|
|
335
|
+
await waitFor(() => {
|
|
336
|
+
expect(onSelection).toHaveBeenLastCalledWith({
|
|
337
|
+
createdItems: [],
|
|
338
|
+
newlyRemoved: initiallySelected[0],
|
|
339
|
+
selectedItems: initiallySelected.slice(1),
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
264
344
|
it("should filter items by custom search function", async () => {
|
|
265
345
|
const { container } = render(<MultiSuggestField {...CustomSearch.args} items={items} />);
|
|
266
346
|
|
|
@@ -340,6 +420,13 @@ describe("MultiSuggestField", () => {
|
|
|
340
420
|
expect(getByText(firstSelected)).toBeInTheDocument();
|
|
341
421
|
expect(getByText(secondSelected)).toBeInTheDocument();
|
|
342
422
|
});
|
|
423
|
+
|
|
424
|
+
await waitFor(() => {
|
|
425
|
+
expect(onSelection).toHaveBeenCalledWith({
|
|
426
|
+
createdItems: [],
|
|
427
|
+
selectedItems: predefinedNotControlledValues.args.selectedItems,
|
|
428
|
+
});
|
|
429
|
+
});
|
|
343
430
|
});
|
|
344
431
|
|
|
345
432
|
it("should call onSelection function with the selected items", async () => {
|
|
@@ -485,7 +572,6 @@ describe("MultiSuggestField", () => {
|
|
|
485
572
|
await waitFor(() => {
|
|
486
573
|
const expectedObject = {
|
|
487
574
|
createdItems: [],
|
|
488
|
-
newlySelected: items.at(-1),
|
|
489
575
|
selectedItems: items,
|
|
490
576
|
};
|
|
491
577
|
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
@@ -513,7 +599,6 @@ describe("MultiSuggestField", () => {
|
|
|
513
599
|
await waitFor(() => {
|
|
514
600
|
const expectedObject = {
|
|
515
601
|
createdItems: [],
|
|
516
|
-
newlySelected: items.at(-1),
|
|
517
602
|
selectedItems: items,
|
|
518
603
|
};
|
|
519
604
|
expect(onSelection).toHaveBeenCalledWith(expectedObject);
|
|
@@ -536,7 +621,7 @@ describe("MultiSuggestField", () => {
|
|
|
536
621
|
|
|
537
622
|
const expectedObject = {
|
|
538
623
|
createdItems: [],
|
|
539
|
-
|
|
624
|
+
newlyRemoved: items[i],
|
|
540
625
|
selectedItems: selected,
|
|
541
626
|
};
|
|
542
627
|
|
|
@@ -39,15 +39,15 @@ $tab-indicator-width: 3px !default;
|
|
|
39
39
|
max-width: 15rem;
|
|
40
40
|
margin-bottom: $tab-indicator-width;
|
|
41
41
|
color: inherit;
|
|
42
|
-
border-radius: 0;
|
|
43
42
|
outline: none;
|
|
43
|
+
border-radius: 0;
|
|
44
44
|
|
|
45
45
|
.#{$ns}-button-text {
|
|
46
46
|
overflow-x: hidden;
|
|
47
47
|
text-overflow: ellipsis;
|
|
48
48
|
white-space: nowrap;
|
|
49
49
|
|
|
50
|
-
//min-width: 6em;
|
|
50
|
+
// min-width: 6em;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
&::before,
|
|
@@ -30,8 +30,6 @@ $tag-round-adjustment: 0 !default;
|
|
|
30
30
|
@import "~@blueprintjs/core/src/components/tag/tag";
|
|
31
31
|
|
|
32
32
|
.#{$eccgui}-tag__item {
|
|
33
|
-
--eccgui-tag-border-width: 1px;
|
|
34
|
-
|
|
35
33
|
flex-grow: 0;
|
|
36
34
|
flex-shrink: 0;
|
|
37
35
|
min-width: calc(#{$tag-height} - 2px);
|
|
@@ -141,6 +139,8 @@ $tag-round-adjustment: 0 !default;
|
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
.#{$ns}-tag {
|
|
142
|
+
--eccgui-tag-border-width: 1px;
|
|
143
|
+
|
|
144
144
|
border-style: solid;
|
|
145
145
|
border-width: var(--eccgui-tag-border-width);
|
|
146
146
|
|
|
@@ -13,20 +13,26 @@ html {
|
|
|
13
13
|
|
|
14
14
|
body {
|
|
15
15
|
font-family: $eccgui-font-family-default;
|
|
16
|
-
|
|
17
|
-
text-rendering: optimizelegibility;
|
|
18
|
-
-webkit-font-smoothing: antialiased;
|
|
19
|
-
-moz-osx-font-smoothing: grayscale;
|
|
16
|
+
|
|
20
17
|
// User-facing text may contain Unicode symbols (e.g. "★") that fall outside the primary font stack.
|
|
21
18
|
// Browsers pick different system fallback fonts for such characters, causing glyphs to render at
|
|
22
19
|
// different optical sizes (smaller in Firefox). font-size-adjust normalises the fallback font size
|
|
23
20
|
// by matching the primary font's x-height, reducing the visual size discrepancy across browsers.
|
|
24
21
|
font-size-adjust: from-font;
|
|
22
|
+
font-weight: $eccgui-font-weight-regular;
|
|
23
|
+
text-rendering: optimizelegibility;
|
|
24
|
+
-webkit-font-smoothing: antialiased;
|
|
25
|
+
-moz-osx-font-smoothing: grayscale;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
code {
|
|
28
29
|
font-family: $eccgui-font-family-monospace;
|
|
29
30
|
font-size: 0.9em;
|
|
31
|
+
|
|
32
|
+
.#{$eccgui}-typography__contentblock &,
|
|
33
|
+
&.#{$eccgui}-typography__text {
|
|
34
|
+
background-color: $eccgui-color-workspace-background;
|
|
35
|
+
}
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
strong {
|
|
@@ -62,10 +62,10 @@ div.react-flow__handle {
|
|
|
62
62
|
inset: 0;
|
|
63
63
|
display: none;
|
|
64
64
|
cursor: pointer;
|
|
65
|
-
content: " ";
|
|
66
|
-
border-radius: 100%;
|
|
67
65
|
outline: dotted $eccgui-size-flow-handle-border currentcolor;
|
|
68
66
|
outline-offset: $eccgui-size-flow-handle * 0.75 + $eccgui-size-flow-handle-border * 0.5;
|
|
67
|
+
content: " ";
|
|
68
|
+
border-radius: 100%;
|
|
69
69
|
|
|
70
70
|
.react-flow__node:hover & {
|
|
71
71
|
display: block;
|
|
@@ -207,9 +207,9 @@ div.react-flow__handle-bottom {
|
|
|
207
207
|
.#{$eccgui}-graphviz__node--hidehandles {
|
|
208
208
|
& ~ .react-flow__handle:not(.connectable) {
|
|
209
209
|
z-index: -1;
|
|
210
|
+
visibility: hidden;
|
|
210
211
|
width: 1px;
|
|
211
212
|
height: 1px;
|
|
212
|
-
visibility: hidden;
|
|
213
213
|
border: none;
|
|
214
214
|
|
|
215
215
|
&.react-flow__handle-top {
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
$use-flexbox-grid: $use-flexbox-grid
|
|
9
9
|
);
|
|
10
10
|
@use "~@carbon/react/scss/utilities/_visually-hidden";
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// we replicate the function here because the distinct import is not possible via @carbon/react
|
|
12
13
|
// @import "~@carbon/styles/scss/components/ui-shell/functions";
|
|
13
14
|
@function mini-units($count) {
|
|
14
15
|
@return 0.5rem * $count;
|
|
15
16
|
}
|
|
17
|
+
|
|
16
18
|
@import "~@carbon/react/scss/feature-flags";
|
|
17
19
|
@import "~@carbon/react/scss/colors";
|
|
18
20
|
@import "~@carbon/react/scss/theme";
|