@eccenca/gui-elements 23.2.0-rc.0 → 23.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.
Files changed (140) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +24 -20
  3. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  4. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +59 -50
  5. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  6. package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
  7. package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
  8. package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js +9 -6
  9. package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
  10. package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js +33 -0
  11. package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
  12. package/dist/cjs/components/CodeAutocompleteField/index.js +14 -0
  13. package/dist/cjs/components/CodeAutocompleteField/index.js.map +1 -0
  14. package/dist/cjs/components/Depiction/Depiction.js +13 -13
  15. package/dist/cjs/components/Depiction/Depiction.js.map +1 -1
  16. package/dist/cjs/components/Dialog/SimpleDialog.js +5 -5
  17. package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
  18. package/dist/cjs/components/Icon/IconButton.js +9 -3
  19. package/dist/cjs/components/Icon/IconButton.js.map +1 -1
  20. package/dist/cjs/components/Icon/canonicalIconNames.js +2 -0
  21. package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
  22. package/dist/cjs/components/MultiSelect/MultiSelect.js +45 -17
  23. package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
  24. package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js +33 -0
  25. package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
  26. package/dist/cjs/components/OverviewItem/OverviewItem.js +8 -10
  27. package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
  28. package/dist/cjs/components/PropertyValuePair/PropertyName.js +4 -3
  29. package/dist/cjs/components/PropertyValuePair/PropertyName.js.map +1 -1
  30. package/dist/cjs/components/Select/Select.js +18 -3
  31. package/dist/cjs/components/Select/Select.js.map +1 -1
  32. package/dist/cjs/components/SuggestField/SuggestField.js +39 -0
  33. package/dist/cjs/components/SuggestField/SuggestField.js.map +1 -0
  34. package/dist/cjs/components/SuggestField/index.js +19 -0
  35. package/dist/cjs/components/SuggestField/index.js.map +1 -0
  36. package/dist/cjs/components/index.js +3 -0
  37. package/dist/cjs/components/index.js.map +1 -1
  38. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +54 -41
  39. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  40. package/dist/cjs/index.js +1 -0
  41. package/dist/cjs/index.js.map +1 -1
  42. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +23 -18
  43. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  44. package/dist/esm/components/AutocompleteField/AutoCompleteField.js +68 -59
  45. package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  46. package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
  47. package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
  48. package/dist/esm/components/Breadcrumb/BreadcrumbItem.js +9 -6
  49. package/dist/esm/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
  50. package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js +37 -0
  51. package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
  52. package/dist/esm/components/CodeAutocompleteField/index.js +2 -0
  53. package/dist/esm/components/CodeAutocompleteField/index.js.map +1 -0
  54. package/dist/esm/components/Depiction/Depiction.js +12 -12
  55. package/dist/esm/components/Depiction/Depiction.js.map +1 -1
  56. package/dist/esm/components/Dialog/SimpleDialog.js +7 -7
  57. package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
  58. package/dist/esm/components/Icon/IconButton.js +10 -4
  59. package/dist/esm/components/Icon/IconButton.js.map +1 -1
  60. package/dist/esm/components/Icon/canonicalIconNames.js +2 -0
  61. package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
  62. package/dist/esm/components/MultiSelect/MultiSelect.js +52 -22
  63. package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
  64. package/dist/esm/components/MultiSuggestField/MultiSuggestField.js +37 -0
  65. package/dist/esm/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
  66. package/dist/esm/components/OverviewItem/OverviewItem.js +8 -10
  67. package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
  68. package/dist/esm/components/PropertyValuePair/PropertyName.js +4 -3
  69. package/dist/esm/components/PropertyValuePair/PropertyName.js.map +1 -1
  70. package/dist/esm/components/Select/Select.js +19 -4
  71. package/dist/esm/components/Select/Select.js.map +1 -1
  72. package/dist/esm/components/SuggestField/SuggestField.js +43 -0
  73. package/dist/esm/components/SuggestField/SuggestField.js.map +1 -0
  74. package/dist/esm/components/SuggestField/index.js +6 -0
  75. package/dist/esm/components/SuggestField/index.js.map +1 -0
  76. package/dist/esm/components/index.js +3 -0
  77. package/dist/esm/components/index.js.map +1 -1
  78. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +51 -39
  79. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  80. package/dist/esm/index.js +2 -1
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/types/components/AutoSuggestion/AutoSuggestion.d.ts +35 -4
  83. package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +23 -6
  84. package/dist/types/components/AutocompleteField/autoCompleteFieldUtils.d.ts +3 -3
  85. package/dist/types/components/AutocompleteField/index.d.ts +1 -1
  86. package/dist/types/components/AutocompleteField/interfaces.d.ts +1 -1
  87. package/dist/types/components/CodeAutocompleteField/CodeAutocompleteField.d.ts +10 -0
  88. package/dist/types/components/CodeAutocompleteField/index.d.ts +1 -0
  89. package/dist/types/components/Dialog/SimpleDialog.d.ts +2 -2
  90. package/dist/types/components/Icon/IconButton.d.ts +2 -2
  91. package/dist/types/components/Icon/canonicalIconNames.d.ts +1 -1
  92. package/dist/types/components/MultiSelect/MultiSelect.d.ts +20 -2
  93. package/dist/types/components/MultiSuggestField/MultiSuggestField.d.ts +10 -0
  94. package/dist/types/components/PropertyValuePair/PropertyName.d.ts +5 -1
  95. package/dist/types/components/Select/Select.d.ts +28 -9
  96. package/dist/types/components/SuggestField/SuggestField.d.ts +16 -0
  97. package/dist/types/components/SuggestField/index.d.ts +5 -0
  98. package/dist/types/components/index.d.ts +3 -0
  99. package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +7 -7
  100. package/dist/types/index.d.ts +2 -1
  101. package/package.json +1 -1
  102. package/src/components/Application/_header.scss +49 -58
  103. package/src/components/AutoSuggestion/AutoSuggestion.stories.tsx +14 -0
  104. package/src/components/AutoSuggestion/AutoSuggestion.tsx +280 -221
  105. package/src/components/AutocompleteField/AutoCompleteField.stories.tsx +14 -0
  106. package/src/components/AutocompleteField/AutoCompleteField.tsx +157 -121
  107. package/src/components/AutocompleteField/autoCompleteFieldUtils.tsx +10 -16
  108. package/src/components/AutocompleteField/interfaces.ts +5 -6
  109. package/src/components/Breadcrumb/BreadcrumbItem.tsx +19 -18
  110. package/src/components/Breadcrumb/breadcrumb.scss +18 -16
  111. package/src/components/Breadcrumb/stories/BreadcrumbList.stories.tsx +18 -15
  112. package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +89 -0
  113. package/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx +22 -0
  114. package/src/components/CodeAutocompleteField/index.ts +1 -0
  115. package/src/components/ContextOverlay/contextoverlay.scss +10 -2
  116. package/src/components/Depiction/Depiction.tsx +57 -55
  117. package/src/components/Dialog/SimpleDialog.tsx +20 -33
  118. package/src/components/Icon/IconButton.tsx +25 -11
  119. package/src/components/Icon/canonicalIconNames.tsx +4 -0
  120. package/src/components/MultiSelect/MultiSelect.stories.tsx +9 -47
  121. package/src/components/MultiSelect/MultiSelect.tsx +110 -66
  122. package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +58 -0
  123. package/src/components/MultiSuggestField/MultiSuggestField.tsx +22 -0
  124. package/src/components/Notification/notification.scss +20 -17
  125. package/src/components/OverviewItem/OverviewItem.tsx +11 -20
  126. package/src/components/PropertyValuePair/PropertyName.tsx +17 -4
  127. package/src/components/PropertyValuePair/propertyvalue.scss +17 -1
  128. package/src/components/Select/Select.stories.tsx +49 -20
  129. package/src/components/Select/Select.tsx +96 -18
  130. package/src/components/Select/_select.scss +13 -1
  131. package/src/components/SuggestField/SuggestField.stories.tsx +99 -0
  132. package/src/components/SuggestField/SuggestField.tsx +28 -0
  133. package/src/components/SuggestField/index.ts +5 -0
  134. package/src/components/TagInput/taginput.scss +14 -0
  135. package/src/components/index.scss +1 -1
  136. package/src/components/index.ts +3 -0
  137. package/src/extensions/react-flow/nodes/NodeContent.tsx +105 -87
  138. package/src/index.ts +2 -5
  139. package/src/components/AutoSuggestion/stories/AutoSuggestion.stories.tsx +0 -83
  140. package/src/components/AutocompleteField/stories/AutoCompleteField.stories.tsx +0 -86
@@ -1,52 +1,14 @@
1
- import React from "react";
2
- import { ComponentStory, ComponentMeta } from "@storybook/react";
3
- import { loremIpsum } from "react-lorem-ipsum";
4
- import { MultiSelect as MultiSelectExample } from "./../../../index";
1
+ import { Meta } from "@storybook/react";
2
+
3
+ import { MultiSelect } from "./../../../index";
4
+ export { Default } from "../MultiSuggestField/MultiSuggestField.stories";
5
5
 
6
6
  export default {
7
7
  title: "Forms/MultiSelect",
8
- component: MultiSelectExample,
9
- argTypes: {
10
- items: {
11
- control: "none",
8
+ component: MultiSelect,
9
+ parameters: {
10
+ controls: {
11
+ exclude: /.*/g,
12
12
  },
13
13
  },
14
- } as ComponentMeta<typeof MultiSelectExample>;
15
-
16
- const Template: ComponentStory<typeof MultiSelectExample> = (args) => <MultiSelectExample {...args} />;
17
-
18
- export const Default = Template.bind({});
19
-
20
- const testLabels = loremIpsum({
21
- p: 1,
22
- avgSentencesPerParagraph: 5,
23
- avgWordsPerSentence: 1,
24
- startWithLoremIpsum: false,
25
- random: false
26
- }).toString().split(".");
27
-
28
- const items = new Array(5).fill(undefined).map((_, id) => {
29
- const testLabel = testLabels[id];
30
- return { testLabel, testId: `${testLabel}-id` };
31
- });
32
-
33
- Default.args = {
34
- items,
35
- canCreateNewItem: true,
36
- prePopulateWithItems: false,
37
- itemId: item => item.testId,
38
- itemLabel: item => item.testLabel,
39
- openOnKeyDown: true,
40
- };
41
-
42
- const TemplateWithOpenDropdown: ComponentStory<typeof MultiSelectExample> = (args) => <MultiSelectExample {...args} />;
43
-
44
- export const openDropdownWhenFocused = TemplateWithOpenDropdown.bind({});
45
-
46
- openDropdownWhenFocused.args = {
47
- items,
48
- canCreateNewItem: true,
49
- prePopulateWithItems: false,
50
- itemId: item => item.testId,
51
- itemLabel: item => item.testLabel,
52
- };
14
+ } as Meta<typeof MultiSelect>;
@@ -1,23 +1,15 @@
1
- import React, {useRef} from "react";
2
- import {
3
- Intent as BlueprintIntent,
4
- HTMLInputProps as BlueprintHTMLInputProps
5
- } from "@blueprintjs/core";
1
+ import React, { useRef } from "react";
2
+ import { HTMLInputProps as BlueprintHTMLInputProps, Intent as BlueprintIntent } from "@blueprintjs/core";
6
3
  import {
7
4
  ItemRendererProps as BlueprintItemRendererProps,
8
5
  MultiSelect2 as BlueprintMultiSelect,
9
- MultiSelect2Props as BlueprintMultiSelectProps
6
+ MultiSelect2Props as BlueprintMultiSelectProps,
10
7
  } from "@blueprintjs/select";
11
- import {
12
- MenuItem,
13
- Highlighter,
14
- Button,
15
- OverflowText,
16
- ContextOverlayProps,
17
- Spinner,
18
- } from "./../../index";
19
8
 
20
- import {removeExtraSpaces} from "../../common/utils/stringUtils";
9
+ import { removeExtraSpaces } from "../../common/utils/stringUtils";
10
+ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
11
+
12
+ import { ContextOverlayProps, Highlighter, IconButton, MenuItem, OverflowText, Spinner } from "./../../index";
21
13
 
22
14
  export interface MultiSelectSelectionProps<T> {
23
15
  newlySelected: T;
@@ -28,7 +20,12 @@ export interface MultiSelectSelectionProps<T> {
28
20
  // @deprecated use `MultiSelectSelectionProps<T>`
29
21
  export type SelectedParamsType<T> = MultiSelectSelectionProps<T>;
30
22
 
31
- export interface MultiSelectProps<T> extends Pick<BlueprintMultiSelectProps<T>, "items" | "placeholder" | "openOnKeyDown"> {
23
+ export interface MultiSelectProps<T>
24
+ extends Pick<BlueprintMultiSelectProps<T>, "items" | "placeholder" | "openOnKeyDown"> {
25
+ /**
26
+ * Additional class name, space separated.
27
+ */
28
+ className?: string;
32
29
  /**
33
30
  * Returns the unique ID of an item. This will be used for equality of items.
34
31
  */
@@ -80,11 +77,11 @@ export interface MultiSelectProps<T> extends Pick<BlueprintMultiSelectProps<T>,
80
77
  /**
81
78
  * Allows to creates new item from a given query. If this is not provided then no new items can be created.
82
79
  */
83
- createNewItemFromQuery?: (query: string) => T
80
+ createNewItemFromQuery?: (query: string) => T;
84
81
  /**
85
82
  * Items that were newly created and not taken from the list will be post-fixed with this string.
86
83
  */
87
- newItemPostfix?: string
84
+ newItemPostfix?: string;
88
85
  /**
89
86
  * The input element is displayed with primary color scheme.
90
87
  */
@@ -106,10 +103,25 @@ export interface MultiSelectProps<T> extends Pick<BlueprintMultiSelectProps<T>,
106
103
  */
107
104
  disabled?: boolean;
108
105
 
109
- /** Delay in ms how long the request for the given query should be delayed. */
110
- requestDelay?: number
106
+ /**
107
+ * Delay in ms how long the request for the given query should be delayed.
108
+ */
109
+ requestDelay?: number;
110
+
111
+ /**
112
+ * Clear query when an option is selected or unselected.
113
+ * The query is empty then and the user need to enter a new query.
114
+ */
115
+ clearQueryOnSelection?: boolean;
111
116
  }
112
117
 
118
+ /**
119
+ * **Element is deprecated for the current type of usage.**
120
+ * Use `MultiSuggestField` as replacement.
121
+ *
122
+ * This component will be re-implemented later as a `Select` allowing multiple selections.
123
+ * @deprecated
124
+ */
113
125
  export function MultiSelect<T>({
114
126
  items,
115
127
  prePopulateWithItems,
@@ -131,6 +143,8 @@ export function MultiSelect<T>({
131
143
  disabled,
132
144
  createNewItemFromQuery,
133
145
  requestDelay = 0,
146
+ clearQueryOnSelection = false,
147
+ className,
134
148
  ...otherProps
135
149
  }: MultiSelectProps<T>) {
136
150
  const [createdItems, setCreatedItems] = React.useState<T[]>([]);
@@ -140,12 +154,12 @@ export function MultiSelect<T>({
140
154
  const [selectedItems, setSelectedItems] = React.useState<T[]>(() => (prePopulateWithItems ? [...items] : []));
141
155
  //currently focused element in popover list
142
156
  const [focusedItem, setFocusedItem] = React.useState<T | null>(null);
143
- const [showSpinner, setShowSpinner] = React.useState(false)
157
+ const [showSpinner, setShowSpinner] = React.useState(false);
144
158
  const inputRef = React.useRef<HTMLInputElement>(null);
145
159
  const requestState = useRef<{
146
- query?: string,
147
- timeoutId?: number
148
- }>({})
160
+ query?: string;
161
+ timeoutId?: number;
162
+ }>({});
149
163
 
150
164
  let intent;
151
165
  switch (true) {
@@ -171,7 +185,6 @@ export function MultiSelect<T>({
171
185
  React.useEffect(() => {
172
186
  setItemsCopy([...items, ...createdItems]);
173
187
  setFilteredItemList([...items, ...createdItems]);
174
- /* eslint-disable react-hooks/exhaustive-deps */
175
188
  }, [items.map((item) => itemId(item)).join("|")]);
176
189
 
177
190
  React.useEffect(() => {
@@ -181,7 +194,6 @@ export function MultiSelect<T>({
181
194
  createdItems: createdSelectedItems,
182
195
  selectedItems,
183
196
  });
184
- /* eslint-disable react-hooks/exhaustive-deps */
185
197
  }, [
186
198
  onSelection,
187
199
  selectedItems.map((item) => itemId(item)).join("|"),
@@ -205,15 +217,12 @@ export function MultiSelect<T>({
205
217
  setSelectedItems((items) => items.filter((item) => itemId(item) !== matcher));
206
218
  };
207
219
 
208
-
209
-
210
220
  /**
211
221
  * selects and deselects an item from selection list
212
222
  * if the item exists it removes it instead
213
223
  * @param item
214
224
  */
215
225
  const onItemSelect = (item: T) => {
216
-
217
226
  if (itemHasBeenSelectedAlready(itemId(item))) {
218
227
  removeItemSelection(itemId(item));
219
228
  } else {
@@ -222,17 +231,24 @@ export function MultiSelect<T>({
222
231
 
223
232
  //remove if already exist
224
233
  if (createdSelectedItems.find((t) => itemLabel(t) === itemLabel(item))) {
225
- setCreatedSelectedItems((prevItems) => prevItems.filter(prevItem => itemLabel(prevItem) !== itemLabel(item)))
226
- }else {
234
+ setCreatedSelectedItems((prevItems) =>
235
+ prevItems.filter((prevItem) => itemLabel(prevItem) !== itemLabel(item))
236
+ );
237
+ } else {
227
238
  const wasNewlyCreated = createdItems.find((t) => itemLabel(t) === itemLabel(item));
228
239
  //only add to createdSelectedItems if it was previously created and not
229
240
  // from the initial items or a possible query response
230
- if(wasNewlyCreated){
231
- setCreatedSelectedItems((prevItems) =>[...prevItems, item])
241
+ if (wasNewlyCreated) {
242
+ setCreatedSelectedItems((prevItems) => [...prevItems, item]);
232
243
  }
233
244
  }
234
245
 
235
- inputRef.current?.select();
246
+ if (clearQueryOnSelection) {
247
+ requestState.current.query = "";
248
+ inputRef.current?.focus();
249
+ } else {
250
+ inputRef.current?.select();
251
+ }
236
252
  };
237
253
 
238
254
  /**
@@ -241,25 +257,25 @@ export function MultiSelect<T>({
241
257
  */
242
258
  const onQueryChange = (query: string) => {
243
259
  if (query.length && query !== requestState.current.query) {
244
- requestState.current.query = query
245
- if(requestState.current.timeoutId) {
246
- clearTimeout(requestState.current.timeoutId)
260
+ requestState.current.query = query;
261
+ if (requestState.current.timeoutId) {
262
+ clearTimeout(requestState.current.timeoutId);
247
263
  }
248
264
  const fn = async () => {
249
- setShowSpinner(true)
250
- setFilteredItemList([])
265
+ setShowSpinner(true);
266
+ setFilteredItemList([]);
251
267
  const resultFromQuery = runOnQueryChange && (await runOnQueryChange(removeExtraSpaces(query)));
252
268
  if (requestState.current.query === query) {
253
269
  // Only use most recent request
254
270
  setFilteredItemList(() =>
255
- [...(resultFromQuery ?? itemsCopy), ...createdItems].filter(item =>
271
+ [...(resultFromQuery ?? itemsCopy), ...createdItems].filter((item) =>
256
272
  itemLabel(item).toLowerCase().includes(query.toLowerCase())
257
273
  )
258
274
  );
259
- setShowSpinner(false)
275
+ setShowSpinner(false);
260
276
  }
261
- }
262
- requestState.current.timeoutId = window.setTimeout(fn, requestDelay && requestDelay > 0 ? requestDelay : 0)
277
+ };
278
+ requestState.current.timeoutId = window.setTimeout(fn, requestDelay && requestDelay > 0 ? requestDelay : 0);
263
279
  }
264
280
  };
265
281
 
@@ -275,9 +291,9 @@ export function MultiSelect<T>({
275
291
  if (!modifiers.matchesPredicate) {
276
292
  return null;
277
293
  }
278
- let label = itemLabel(item)
279
- if(createdItems.find(created => itemId(created) === itemId(item))) {
280
- label += newItemPostfix
294
+ let label = itemLabel(item);
295
+ if (createdItems.find((created) => itemId(created) === itemId(item))) {
296
+ label += newItemPostfix;
281
297
  }
282
298
  return (
283
299
  <MenuItem
@@ -295,6 +311,7 @@ export function MultiSelect<T>({
295
311
  * clear all selected items in the multi-select input
296
312
  */
297
313
  const handleClear = () => {
314
+ requestState.current.query = "";
298
315
  setSelectedItems([]);
299
316
  setFilteredItemList(itemsCopy);
300
317
  };
@@ -306,18 +323,18 @@ export function MultiSelect<T>({
306
323
  */
307
324
  const removeTagFromSelectionViaIndex = (label: React.ReactNode, index: number) => {
308
325
  setSelectedItems([...selectedItems.slice(0, index), ...selectedItems.slice(index + 1)]);
309
- setCreatedSelectedItems(items => items.filter(item => itemLabel(item) !== label));
326
+ setCreatedSelectedItems((items) => items.filter((item) => itemLabel(item) !== label));
310
327
  };
311
328
 
312
329
  /**
313
330
  * Utility function to create a new Item. createNewItemFromQuery is assumed to be defined!
314
331
  */
315
332
  const createNewItem = (query: string): T => {
316
- const newItem = createNewItemFromQuery!!(query);
333
+ const newItem = createNewItemFromQuery!(query);
317
334
  //set new items
318
335
  setCreatedItems((items) => [...items, newItem]);
319
- setCreatedSelectedItems((items) => [...items, newItem])
320
- requestState.current.query = ""
336
+ setCreatedSelectedItems((items) => [...items, newItem]);
337
+ requestState.current.query = "";
321
338
  return newItem;
322
339
  };
323
340
 
@@ -326,7 +343,12 @@ export function MultiSelect<T>({
326
343
  * @param event
327
344
  */
328
345
  const handleOnKeyUp = (event: React.KeyboardEvent<HTMLElement>) => {
329
- if (event.key === "Enter" && !filteredItemList.length && !!requestState.current.query && createNewItemFromQuery) {
346
+ if (
347
+ event.key === "Enter" &&
348
+ !filteredItemList.length &&
349
+ !!requestState.current.query &&
350
+ createNewItemFromQuery
351
+ ) {
330
352
  createNewItem(requestState.current.query);
331
353
  }
332
354
  inputRef.current?.focus();
@@ -374,17 +396,19 @@ export function MultiSelect<T>({
374
396
  // Clear button and spinner are both shown as "right element"
375
397
  const clearButton =
376
398
  selectedItems.length > 0 ? (
377
- <Button icon="operation-clear" data-test-id="clear-all-items" minimal={true} onClick={handleClear} />
399
+ <IconButton
400
+ disabled={disabled}
401
+ name="operation-clear"
402
+ data-test-id="clear-all-items"
403
+ onClick={handleClear}
404
+ />
378
405
  ) : undefined;
379
406
 
380
- const spinnerProps = showSpinner ? {
381
- rightElement: (
382
- <>
383
- <Spinner position={"inline"} size={"tiny"} />
384
- {clearButton ?? null}
385
- </>
386
- )
387
- } : {}
407
+ const spinnerProps = showSpinner
408
+ ? {
409
+ rightElement: <Spinner position={"inline"} size={"tiny"} />,
410
+ }
411
+ : {};
388
412
 
389
413
  return (
390
414
  <BlueprintMultiSelect<T>
@@ -397,7 +421,7 @@ export function MultiSelect<T>({
397
421
  itemsEqual={(a: T, b: T) => itemId(a) === itemId(b)}
398
422
  selectedItems={selectedItems}
399
423
  noResults={<MenuItem disabled={true} text={noResultText} />}
400
- tagRenderer={item => itemLabel(item)}
424
+ tagRenderer={(item) => itemLabel(item)}
401
425
  createNewItemRenderer={newItemRenderer}
402
426
  onActiveItemChange={(activeItem) => setFocusedItem(activeItem)}
403
427
  fill={fullWidth}
@@ -406,31 +430,51 @@ export function MultiSelect<T>({
406
430
  inputProps: {
407
431
  id: "item",
408
432
  autoComplete: "off",
409
- ...inputProps
433
+ ...inputProps,
410
434
  },
435
+ className: `${eccgui}-multiselect` + (className ? ` ${className}` : ""),
436
+ fill: fullWidth,
411
437
  inputRef: inputRef,
412
438
  intent,
413
439
  addOnBlur: true,
414
440
  onKeyDown: handleOnKeyDown,
415
441
  onKeyUp: handleOnKeyUp,
416
442
  onRemove: removeTagFromSelectionViaIndex,
417
- rightElement: disabled ? undefined : clearButton,
443
+ rightElement: (
444
+ <>
445
+ {clearButton ?? null}
446
+ {otherProps.openOnKeyDown !== true && (
447
+ <IconButton disabled={disabled} name={"toggler-caretdown"} />
448
+ )}
449
+ </>
450
+ ),
418
451
  tagProps: { minimal: true },
419
452
  disabled,
420
453
  ...tagInputProps,
421
- ...spinnerProps
454
+ ...spinnerProps,
455
+ }}
456
+ popoverTargetProps={{
457
+ className: `${eccgui}-multiselect__target`,
422
458
  }}
423
-
424
459
  popoverProps={{
425
460
  minimal: true,
426
461
  placement: "bottom-start",
427
- fill: true,
462
+ matchTargetWidth: fullWidth,
428
463
  ...contextOverlayProps,
429
464
  }}
430
465
  />
431
466
  );
432
467
  }
433
468
 
469
+ /** @deprecated */
470
+ /*
471
+ function ofType<U>() {
472
+ return (props: MultiSelectProps<U>) => <MultiSelect<U> {...props} />;
473
+ }
474
+ // */
475
+
476
+ // we still return the BLueprint element here because it was already used like that
477
+ // MultiSelect.ofType = ofType;
434
478
  MultiSelect.ofType = BlueprintMultiSelect.ofType;
435
479
 
436
480
  export default MultiSelect;
@@ -0,0 +1,58 @@
1
+ import { loremIpsum } from "react-lorem-ipsum";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+
4
+ import { MultiSuggestField } from "./../../../index";
5
+
6
+ export default {
7
+ title: "Forms/MultiSuggestField",
8
+ component: MultiSuggestField,
9
+ argTypes: {
10
+ items: {
11
+ control: "none",
12
+ },
13
+ },
14
+ } as Meta<typeof MultiSuggestField>;
15
+
16
+ const Template: StoryFn<typeof MultiSuggestField> = (args) => (
17
+ <div>
18
+ <MultiSuggestField {...args} />
19
+ </div>
20
+ );
21
+
22
+ const testLabels = loremIpsum({
23
+ p: 1,
24
+ avgSentencesPerParagraph: 5,
25
+ avgWordsPerSentence: 1,
26
+ startWithLoremIpsum: false,
27
+ random: false,
28
+ })
29
+ .toString()
30
+ .split(".");
31
+
32
+ const items = new Array(5).fill(undefined).map((_, id) => {
33
+ const testLabel = testLabels[id];
34
+ return { testLabel, testId: `${testLabel}-id` };
35
+ });
36
+
37
+ export const Default = Template.bind({});
38
+ Default.args = {
39
+ items,
40
+ canCreateNewItem: true,
41
+ prePopulateWithItems: false,
42
+ itemId: (item) => item.testId,
43
+ itemLabel: (item) => item.testLabel,
44
+ openOnKeyDown: true,
45
+ };
46
+
47
+ /**
48
+ * Display always the dropdown after the element was clicked on.
49
+ * Do not wait until the query input was startet.
50
+ */
51
+ export const dropdownOnFocus = Template.bind({});
52
+ dropdownOnFocus.args = {
53
+ items,
54
+ canCreateNewItem: true,
55
+ prePopulateWithItems: false,
56
+ itemId: (item) => item.testId,
57
+ itemLabel: (item) => item.testLabel,
58
+ };
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+
3
+ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
4
+ import { MultiSelect, MultiSelectProps } from "../MultiSelect/MultiSelect";
5
+
6
+ export type MultiSuggestFieldProps<T> = MultiSelectProps<T>;
7
+
8
+ /**
9
+ * Element behaves very similar to `SuggestField` but allows multiple selections.
10
+ * Its value does not represent a string but a stack of objects.
11
+ *
12
+ * Example usage: input field for user created tags.
13
+ */
14
+ export function MultiSuggestField<T>({ className, ...otherProps }: MultiSuggestFieldProps<T>) {
15
+ // Currently this works only as an alias element for `MultiSelect`.
16
+ return (
17
+ <MultiSelect<T>
18
+ className={`${eccgui}-multisuggestfield` + (className ? ` ${className}` : "")}
19
+ {...otherProps}
20
+ />
21
+ );
22
+ }
@@ -1,26 +1,25 @@
1
1
  // TODO: add vars and process them
2
2
 
3
3
  @use "sass:math";
4
-
5
4
  @import "~@blueprintjs/core/src/components/toast/toast";
6
5
 
7
6
  .#{$eccgui}-notification {
8
- border-style: solid;
9
- border-width: 1px 1px 1px 0.25rem;
10
- border-color: $eccgui-color-application-text;
11
- color: $eccgui-color-application-text;
12
- background-color: $eccgui-color-application-background;
13
- font-size: 1rem;
14
- line-height: $eccgui-size-typo-base-lineheight;
15
- min-width: math.div(4, 16) * 100vw;
16
7
  width: 100%;
8
+ min-width: math.div(4, 16) * 100vw;
17
9
  max-width: 40rem;
18
10
  margin-top: $eccgui-size-block-whitespace;
11
+ font-size: 1rem;
12
+ line-height: $eccgui-size-typo-base-lineheight;
13
+ color: $eccgui-color-application-text;
14
+ background-color: $eccgui-color-application-background;
15
+ border-color: $eccgui-color-application-text;
16
+ border-style: solid;
17
+ border-width: 1px 1px 1px 0.25rem;
19
18
 
20
19
  & > .#{$eccgui}-icon {
21
- color: inherit;
22
20
  flex-grow: 0;
23
21
  flex-shrink: 0;
22
+ color: inherit;
24
23
  }
25
24
 
26
25
  &.#{$eccgui}-notification--static > .#{$ns}-button-group {
@@ -31,29 +30,33 @@
31
30
 
32
31
  &:not(.#{$eccgui}-notification--toast) {
33
32
  max-width: none;
34
- box-shadow: none;
35
33
  margin-top: 0;
34
+ box-shadow: none;
35
+ }
36
+
37
+ .#{$eccgui}-card__content & {
38
+ min-width: unset;
36
39
  }
37
40
 
38
41
  &.#{$eccgui}-intent--info {
39
- border-color: $eccgui-color-info-text;
40
42
  color: $eccgui-color-info-text;
41
43
  background-color: $eccgui-color-info-background;
44
+ border-color: $eccgui-color-info-text;
42
45
  }
43
46
  &.#{$eccgui}-intent--success {
44
- border-color: $eccgui-color-success-text;
45
47
  color: $eccgui-color-success-text;
46
48
  background-color: $eccgui-color-success-background;
49
+ border-color: $eccgui-color-success-text;
47
50
  }
48
51
  &.#{$eccgui}-intent--warning {
49
- border-color: $eccgui-color-warning-text;
50
52
  color: $eccgui-color-warning-text;
51
53
  background-color: $eccgui-color-warning-background;
54
+ border-color: $eccgui-color-warning-text;
52
55
  }
53
56
  &.#{$eccgui}-intent--danger {
54
- border-color: $eccgui-color-danger-text;
55
57
  color: $eccgui-color-danger-text;
56
58
  background-color: $eccgui-color-danger-background;
59
+ border-color: $eccgui-color-danger-text;
57
60
  }
58
61
  }
59
62
 
@@ -65,15 +68,15 @@
65
68
 
66
69
  .#{$eccgui}-notification__content {
67
70
  display: flex;
68
- justify-content: space-between;
69
71
  align-items: baseline;
72
+ justify-content: space-between;
70
73
  margin: -10px; // TODO: use blueprint var ofr toast padding here
71
74
  }
72
75
 
73
76
  .#{$eccgui}-notification__messagebody {
74
- padding: 10px; // TODO: use blueprint var ofr toast padding here
75
77
  flex-grow: 1;
76
78
  flex-shrink: 1;
79
+ padding: 10px; // TODO: use blueprint var ofr toast padding here
77
80
  }
78
81
 
79
82
  .#{$eccgui}-notification__actions {
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+
2
3
  import { CLASSPREFIX as eccgui } from "../../configuration/constants";
3
4
 
4
5
  export interface OverviewItemProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -18,19 +19,18 @@ export interface OverviewItemProps extends React.HTMLAttributes<HTMLDivElement>
18
19
  */
19
20
  export const OverviewItem = ({
20
21
  children,
21
- className = '',
22
+ className = "",
22
23
  densityHigh = false,
23
24
  hasSpacing = false,
24
25
  ...otherProps
25
26
  }: OverviewItemProps) => {
26
-
27
27
  const item = (
28
28
  <div
29
29
  {...otherProps}
30
30
  className={
31
31
  `${eccgui}-overviewitem__item ` +
32
- (densityHigh ? `${eccgui}-overviewitem__item--highdensity ` : '') +
33
- (hasSpacing ? `${eccgui}-overviewitem__item--hasspacing ` : '') +
32
+ (densityHigh ? `${eccgui}-overviewitem__item--highdensity ` : "") +
33
+ (hasSpacing ? `${eccgui}-overviewitem__item--hasspacing ` : "") +
34
34
  className
35
35
  }
36
36
  >
@@ -38,24 +38,15 @@ export const OverviewItem = ({
38
38
  </div>
39
39
  );
40
40
 
41
- let accessibilityParameters: { [key: string]: any; } = {};
42
- if (
43
- typeof otherProps.onClick !== 'undefined' ||
44
- typeof otherProps.onKeyDown !== 'undefined'
45
- ) {
46
- accessibilityParameters['tabIndex'] = 0;
41
+ const accessibilityParameters: { [key: string]: any } = Object.create(null);
42
+ if (typeof otherProps.onClick !== "undefined" || typeof otherProps.onKeyDown !== "undefined") {
43
+ accessibilityParameters["tabIndex"] = 0;
47
44
  }
48
- if (
49
- typeof otherProps.onClick !== 'undefined' &&
50
- typeof otherProps.onKeyDown !== 'undefined'
51
- ) {
52
- accessibilityParameters['role'] = "button";
45
+ if (typeof otherProps.onClick !== "undefined" && typeof otherProps.onKeyDown !== "undefined") {
46
+ accessibilityParameters["role"] = "button";
53
47
  }
54
48
 
55
- return React.cloneElement(
56
- item,
57
- accessibilityParameters
58
- );
59
- }
49
+ return React.cloneElement(item, accessibilityParameters);
50
+ };
60
51
 
61
52
  export default OverviewItem;