@eccenca/gui-elements 23.6.0 → 23.7.0-rc.1

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 (107) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/cmem/markdown/Markdown.js +10 -2
  3. package/dist/cjs/cmem/markdown/Markdown.js.map +1 -1
  4. package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +4 -4
  5. package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
  6. package/dist/cjs/common/index.js +2 -0
  7. package/dist/cjs/common/index.js.map +1 -1
  8. package/dist/cjs/common/utils/getScrollParent.js +24 -0
  9. package/dist/cjs/common/utils/getScrollParent.js.map +1 -0
  10. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +19 -2
  11. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  12. package/dist/cjs/components/MultiSelect/MultiSelect.js +66 -41
  13. package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
  14. package/dist/cjs/components/Sticky/StickyTarget.js +85 -0
  15. package/dist/cjs/components/Sticky/StickyTarget.js.map +1 -0
  16. package/dist/cjs/components/Sticky/index.js +14 -0
  17. package/dist/cjs/components/Sticky/index.js.map +1 -0
  18. package/dist/cjs/components/index.js +1 -0
  19. package/dist/cjs/components/index.js.map +1 -1
  20. package/dist/cjs/extensions/codemirror/CodeMirror.js +1 -1
  21. package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
  22. package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js +7 -7
  23. package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
  24. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js +3 -2
  25. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
  26. package/dist/cjs/extensions/react-flow/handles/HandleContent.js +14 -2
  27. package/dist/cjs/extensions/react-flow/handles/HandleContent.js.map +1 -1
  28. package/dist/cjs/extensions/react-flow/handles/HandleTools.js +1 -1
  29. package/dist/cjs/extensions/react-flow/handles/HandleTools.js.map +1 -1
  30. package/dist/cjs/extensions/react-flow/minimap/MiniMap.js +6 -8
  31. package/dist/cjs/extensions/react-flow/minimap/MiniMap.js.map +1 -1
  32. package/dist/esm/cmem/markdown/Markdown.js +10 -2
  33. package/dist/esm/cmem/markdown/Markdown.js.map +1 -1
  34. package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +5 -5
  35. package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
  36. package/dist/esm/common/index.js +2 -0
  37. package/dist/esm/common/index.js.map +1 -1
  38. package/dist/esm/common/utils/getScrollParent.js +20 -0
  39. package/dist/esm/common/utils/getScrollParent.js.map +1 -0
  40. package/dist/esm/components/AutocompleteField/AutoCompleteField.js +27 -2
  41. package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  42. package/dist/esm/components/MultiSelect/MultiSelect.js +72 -52
  43. package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
  44. package/dist/esm/components/Sticky/StickyTarget.js +89 -0
  45. package/dist/esm/components/Sticky/StickyTarget.js.map +1 -0
  46. package/dist/esm/components/Sticky/index.js +2 -0
  47. package/dist/esm/components/Sticky/index.js.map +1 -0
  48. package/dist/esm/components/index.js +1 -0
  49. package/dist/esm/components/index.js.map +1 -1
  50. package/dist/esm/extensions/codemirror/CodeMirror.js +1 -1
  51. package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
  52. package/dist/esm/extensions/react-flow/edges/EdgeDefault.js +7 -7
  53. package/dist/esm/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
  54. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js +3 -2
  55. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
  56. package/dist/esm/extensions/react-flow/handles/HandleContent.js +13 -2
  57. package/dist/esm/extensions/react-flow/handles/HandleContent.js.map +1 -1
  58. package/dist/esm/extensions/react-flow/handles/HandleTools.js +1 -1
  59. package/dist/esm/extensions/react-flow/handles/HandleTools.js.map +1 -1
  60. package/dist/esm/extensions/react-flow/minimap/MiniMap.js +6 -8
  61. package/dist/esm/extensions/react-flow/minimap/MiniMap.js.map +1 -1
  62. package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +5 -0
  63. package/dist/types/cmem/react-flow/configuration/graph.d.ts +9 -9
  64. package/dist/types/cmem/react-flow/configuration/unspecified.d.ts +2 -2
  65. package/dist/types/common/index.d.ts +2 -0
  66. package/dist/types/common/utils/getScrollParent.d.ts +9 -0
  67. package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +2 -0
  68. package/dist/types/components/MultiSelect/MultiSelect.d.ts +1 -1
  69. package/dist/types/components/Sticky/StickyTarget.d.ts +32 -0
  70. package/dist/types/components/Sticky/index.d.ts +1 -0
  71. package/dist/types/components/index.d.ts +1 -0
  72. package/dist/types/extensions/react-flow/edges/EdgeDefault.d.ts +6 -1
  73. package/dist/types/extensions/react-flow/edges/EdgeLabel.d.ts +1 -1
  74. package/dist/types/extensions/react-flow/edges/edgeTypes.d.ts +10 -10
  75. package/dist/types/extensions/react-flow/handles/HandleContent.d.ts +2 -3
  76. package/dist/types/extensions/react-flow/minimap/MiniMap.d.ts +12 -1
  77. package/package.json +3 -1
  78. package/src/cmem/markdown/Markdown.stories.tsx +8 -1
  79. package/src/cmem/markdown/Markdown.tsx +22 -1
  80. package/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx +10 -4
  81. package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +8 -3
  82. package/src/common/index.ts +3 -0
  83. package/src/common/utils/getScrollParent.ts +20 -0
  84. package/src/components/AutocompleteField/AutoCompleteField.tsx +28 -0
  85. package/src/components/AutocompleteField/autocompletefield.scss +1 -1
  86. package/src/components/MultiSelect/MultiSelect.tsx +72 -47
  87. package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +146 -26
  88. package/src/components/MultiSuggestField/tests/MultiSuggestField.test.tsx +363 -61
  89. package/src/components/Sticky/StickyTarget.tsx +119 -0
  90. package/src/components/Sticky/index.ts +1 -0
  91. package/src/components/Sticky/sticky.scss +69 -0
  92. package/src/components/Sticky/stories/StickyTarget.stories.tsx +63 -0
  93. package/src/components/index.scss +1 -0
  94. package/src/components/index.ts +1 -0
  95. package/src/extensions/codemirror/CodeMirror.tsx +1 -1
  96. package/src/extensions/react-flow/edges/EdgeDefault.tsx +70 -62
  97. package/src/extensions/react-flow/edges/EdgeLabel.tsx +14 -2
  98. package/src/extensions/react-flow/edges/stories/EdgeDefault.stories.tsx +11 -5
  99. package/src/extensions/react-flow/edges/stories/EdgeLabel.stories.tsx +2 -0
  100. package/src/extensions/react-flow/handles/HandleContent.tsx +28 -25
  101. package/src/extensions/react-flow/handles/HandleTools.tsx +1 -0
  102. package/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx +5 -1
  103. package/src/extensions/react-flow/minimap/MiniMap.stories.tsx +62 -0
  104. package/src/extensions/react-flow/minimap/MiniMap.tsx +23 -7
  105. package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +2 -0
  106. package/src/extensions/react-flow/nodes/stories/NodeContentExtension.stories.tsx +2 -0
  107. package/src/extensions/react-flow/nodes/stories/NodeDefault.stories.tsx +0 -1
@@ -13,7 +13,7 @@ import { TestableComponent } from "../interfaces";
13
13
  import { ContextOverlayProps, Highlighter, IconButton, MenuItem, OverflowText, Spinner } from "./../../index";
14
14
 
15
15
  export interface MultiSelectSelectionProps<T> {
16
- newlySelected: T;
16
+ newlySelected?: T;
17
17
  selectedItems: T[];
18
18
  createdItems: Partial<T>[];
19
19
  }
@@ -136,7 +136,7 @@ export interface MultiSelectProps<T>
136
136
  */
137
137
  export function MultiSelect<T>({
138
138
  items,
139
- selectedItems: externalSelectedItems = [],
139
+ selectedItems: externalSelectedItems,
140
140
  prePopulateWithItems,
141
141
  itemId,
142
142
  itemLabel,
@@ -163,13 +163,17 @@ export function MultiSelect<T>({
163
163
  wrapperProps,
164
164
  ...otherMultiSelectProps
165
165
  }: MultiSelectProps<T>) {
166
- const [createdItems, setCreatedItems] = React.useState<T[]>([]);
167
- const [createdSelectedItems, setCreatedSelectedItems] = React.useState<T[]>([]);
168
- const [itemsCopy, setItemsCopy] = React.useState<T[]>([...items]);
169
- const [filteredItemList, setFilteredItemList] = React.useState<T[]>([]);
166
+ // Options created by a user
167
+ const createdItems = useRef<T[]>([]);
168
+ // Options passed ouside (f.e. from the backend)
169
+ const [externalItems, setExternalItems] = React.useState<T[]>([...items]);
170
+ // All options (created and passed) that match the query
171
+ const [filteredItems, setFilteredItems] = React.useState<T[]>([]);
172
+ // All options (created and passed) selected by a user, if the component is uncontrolled
170
173
  const [selectedItems, setSelectedItems] = React.useState<T[]>(() =>
171
- prePopulateWithItems ? [...items] : [...externalSelectedItems]
174
+ prePopulateWithItems ? [...items] : externalSelectedItems ? [...externalSelectedItems] : []
172
175
  );
176
+
173
177
  //currently focused element in popover list
174
178
  const [focusedItem, setFocusedItem] = React.useState<T | null>(null);
175
179
  const [showSpinner, setShowSpinner] = React.useState(false);
@@ -197,27 +201,44 @@ export function MultiSelect<T>({
197
201
  break;
198
202
  }
199
203
 
200
- /** update items copy when the items change
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
+ /** Update external items when they change
201
209
  * e.g for auto-complete when query change
202
210
  */
203
211
  React.useEffect(() => {
204
- setItemsCopy([...items, ...createdItems]);
205
- setFilteredItemList([...items, ...createdItems]);
212
+ setExternalItems(items);
213
+ setFilteredItems([...items, ...createdItems.current]);
206
214
  }, [items.map((item) => itemId(item)).join("|")]);
207
215
 
208
216
  React.useEffect(() => {
209
- onSelection &&
217
+ !isControlled &&
218
+ onSelection &&
210
219
  onSelection({
211
220
  newlySelected: selectedItems.slice(-1)[0],
212
- createdItems: createdSelectedItems,
221
+ createdItems: createdItems.current,
213
222
  selectedItems,
214
223
  });
215
224
  }, [
225
+ isControlled,
216
226
  onSelection,
217
227
  selectedItems.map((item) => itemId(item)).join("|"),
218
- createdSelectedItems.map((item) => itemId(item)).join("|"),
228
+ createdItems.current.map((item) => itemId(item)).join("|"),
219
229
  ]);
220
230
 
231
+ /**
232
+ * Update selected items if we get new selected items from outside
233
+ */
234
+ React.useEffect(() => {
235
+ if (!externalSelectedItems) {
236
+ return;
237
+ }
238
+
239
+ setSelectedItems(externalSelectedItems);
240
+ }, [externalSelectedItems]);
241
+
221
242
  /**
222
243
  * using the equality prop specified checks if an item has already been selected
223
244
  * @param matcher
@@ -232,7 +253,16 @@ export function MultiSelect<T>({
232
253
  * @param matcher
233
254
  */
234
255
  const removeItemSelection = (matcher: string) => {
235
- setSelectedItems((items) => items.filter((item) => itemId(item) !== matcher));
256
+ 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
+ }
236
266
  };
237
267
 
238
268
  /**
@@ -243,24 +273,16 @@ export function MultiSelect<T>({
243
273
  const onItemSelect = (item: T) => {
244
274
  if (itemHasBeenSelectedAlready(itemId(item))) {
245
275
  removeItemSelection(itemId(item));
276
+ } else if (isControlled) {
277
+ onSelection({
278
+ newlySelected: item,
279
+ createdItems: createdItems.current,
280
+ selectedItems: [...selectedItems, item],
281
+ });
246
282
  } else {
247
283
  setSelectedItems((items) => [...items, item]);
248
284
  }
249
285
 
250
- //remove if already exist
251
- if (createdSelectedItems.find((t) => itemLabel(t) === itemLabel(item))) {
252
- setCreatedSelectedItems((prevItems) =>
253
- prevItems.filter((prevItem) => itemLabel(prevItem) !== itemLabel(item))
254
- );
255
- } else {
256
- const wasNewlyCreated = createdItems.find((t) => itemLabel(t) === itemLabel(item));
257
- //only add to createdSelectedItems if it was previously created and not
258
- // from the initial items or a possible query response
259
- if (wasNewlyCreated) {
260
- setCreatedSelectedItems((prevItems) => [...prevItems, item]);
261
- }
262
- }
263
-
264
286
  if (clearQueryOnSelection) {
265
287
  requestState.current.query = "";
266
288
  inputRef.current?.focus();
@@ -281,12 +303,13 @@ export function MultiSelect<T>({
281
303
  }
282
304
  const fn = async () => {
283
305
  setShowSpinner(true);
284
- setFilteredItemList([]);
306
+ setFilteredItems([]);
285
307
  const resultFromQuery = runOnQueryChange && (await runOnQueryChange(removeExtraSpaces(query)));
286
308
  if (requestState.current.query === query) {
287
309
  // Only use most recent request
288
- setFilteredItemList(() =>
289
- [...(resultFromQuery ?? itemsCopy), ...createdItems].filter((item) =>
310
+ const outsideOptions = [...(resultFromQuery ?? externalItems)];
311
+ setFilteredItems(
312
+ [...outsideOptions, ...createdItems.current].filter((item) =>
290
313
  itemLabel(item).toLowerCase().includes(query.toLowerCase())
291
314
  )
292
315
  );
@@ -297,7 +320,7 @@ export function MultiSelect<T>({
297
320
  } else if (!query.length) {
298
321
  // if the query is empty we need to show all options and reset current query
299
322
  requestState.current.query = "";
300
- setFilteredItemList(() => [...itemsCopy, ...createdItems]);
323
+ setFilteredItems(() => [...externalItems, ...createdItems.current]);
301
324
  }
302
325
  };
303
326
 
@@ -314,7 +337,7 @@ export function MultiSelect<T>({
314
337
  return null;
315
338
  }
316
339
  let label = itemLabel(item);
317
- if (createdItems.find((created) => itemId(created) === itemId(item))) {
340
+ if (createdItems.current.find((created) => itemId(created) === itemId(item))) {
318
341
  label += newItemPostfix;
319
342
  }
320
343
  return (
@@ -334,8 +357,17 @@ export function MultiSelect<T>({
334
357
  */
335
358
  const handleClear = () => {
336
359
  requestState.current.query = "";
337
- setSelectedItems([]);
338
- setFilteredItemList(itemsCopy);
360
+
361
+ if (isControlled) {
362
+ onSelection({
363
+ selectedItems: [],
364
+ createdItems: createdItems.current,
365
+ });
366
+ } else {
367
+ setSelectedItems([]);
368
+ }
369
+
370
+ setFilteredItems([...externalItems, ...createdItems.current]);
339
371
  };
340
372
 
341
373
  /**
@@ -343,9 +375,8 @@ export function MultiSelect<T>({
343
375
  * @param label
344
376
  * @param index
345
377
  */
346
- const removeTagFromSelectionViaIndex = (label: React.ReactNode, index: number) => {
378
+ const removeTagFromSelectionViaIndex = (_label: React.ReactNode, index: number) => {
347
379
  setSelectedItems([...selectedItems.slice(0, index), ...selectedItems.slice(index + 1)]);
348
- setCreatedSelectedItems((items) => items.filter((item) => itemLabel(item) !== label));
349
380
  };
350
381
 
351
382
  /**
@@ -354,9 +385,8 @@ export function MultiSelect<T>({
354
385
  const createNewItem = (query: string): T => {
355
386
  const newItem = createNewItemFromQuery!(query);
356
387
  //set new items
357
- setCreatedItems((items) => [...items, newItem]);
358
- setCreatedSelectedItems((items) => [...items, newItem]);
359
- setFilteredItemList((items) => [...items, newItem]);
388
+ createdItems.current = [...createdItems.current, newItem];
389
+ setFilteredItems((items) => [...items, newItem]);
360
390
  requestState.current.query = "";
361
391
  return newItem;
362
392
  };
@@ -366,12 +396,7 @@ export function MultiSelect<T>({
366
396
  * @param event
367
397
  */
368
398
  const handleOnKeyUp = (event: React.KeyboardEvent<HTMLElement>) => {
369
- if (
370
- event.key === "Enter" &&
371
- !filteredItemList.length &&
372
- !!requestState.current.query &&
373
- createNewItemFromQuery
374
- ) {
399
+ if (event.key === "Enter" && !filteredItems.length && !!requestState.current.query && createNewItemFromQuery) {
375
400
  createNewItem(requestState.current.query);
376
401
  }
377
402
  inputRef.current?.focus();
@@ -438,7 +463,7 @@ export function MultiSelect<T>({
438
463
  {...otherMultiSelectProps}
439
464
  query={requestState.current.query}
440
465
  onQueryChange={onQueryChange}
441
- items={filteredItemList}
466
+ items={filteredItems}
442
467
  onItemSelect={onItemSelect}
443
468
  itemRenderer={onItemRenderer}
444
469
  itemsEqual={(a: T, b: T) => itemId(a) === itemId(b)}
@@ -2,23 +2,7 @@ import React, { useCallback, useMemo, useState } from "react";
2
2
  import { loremIpsum } from "react-lorem-ipsum";
3
3
  import { Meta, StoryFn } from "@storybook/react";
4
4
 
5
- import { MultiSelectSelectionProps, MultiSuggestField } from "./../../../index";
6
-
7
- export default {
8
- title: "Forms/MultiSuggestField",
9
- component: MultiSuggestField,
10
- argTypes: {
11
- items: {
12
- control: "none",
13
- },
14
- },
15
- } as Meta<typeof MultiSuggestField>;
16
-
17
- const Template: StoryFn<typeof MultiSuggestField> = (args) => (
18
- <div>
19
- <MultiSuggestField {...args} />
20
- </div>
21
- );
5
+ import { MultiSelectSelectionProps, MultiSuggestField, SimpleDialog } from "./../../../index";
22
6
 
23
7
  const testLabels = loremIpsum({
24
8
  p: 1,
@@ -28,13 +12,32 @@ const testLabels = loremIpsum({
28
12
  random: false,
29
13
  })
30
14
  .toString()
31
- .split(".");
15
+ .split(".")
16
+ .map((item) => item.trim());
32
17
 
33
18
  const items = new Array(5).fill(undefined).map((_, id) => {
34
19
  const testLabel = testLabels[id];
35
20
  return { testLabel, testId: `${testLabel}-id` };
36
21
  });
37
22
 
23
+ export default {
24
+ title: "Forms/MultiSuggestField",
25
+ component: MultiSuggestField,
26
+ argTypes: {
27
+ items: {
28
+ control: "none",
29
+ },
30
+ },
31
+ } as Meta<typeof MultiSuggestField>;
32
+
33
+ const Template: StoryFn<typeof MultiSuggestField> = (args) => {
34
+ return (
35
+ <div>
36
+ <MultiSuggestField {...args} />
37
+ </div>
38
+ );
39
+ };
40
+
38
41
  export const Default = Template.bind({});
39
42
  Default.args = {
40
43
  items,
@@ -64,20 +67,56 @@ const selectedItems = items.slice(1, 3);
64
67
  /**
65
68
  * Set the default selected values from the client code.
66
69
  */
67
- export const predefinedValues = Template.bind({});
68
- predefinedValues.args = {
70
+
71
+ export const predefinedNotControlledValues = Template.bind({});
72
+ predefinedNotControlledValues.args = {
69
73
  items,
70
74
  selectedItems,
71
75
  prePopulateWithItems: false,
76
+ onSelection: undefined,
72
77
  itemId: (item) => item.testId,
73
- itemLabel: (item) => <span data-testid={`${item.testLabel.trim()}`}>{item.testLabel}</span>,
78
+ itemLabel: (item) => item.testLabel,
79
+ };
80
+
81
+ const DeferredSelectionTemplate: StoryFn = () => {
82
+ const initialSelected: Array<{ testId: string; testLabel: string }> = [];
83
+ const [loaded, setLoaded] = useState(false);
84
+
85
+ const selected = loaded ? selectedItems : initialSelected;
86
+
87
+ const identity = useCallback((item: string): string => item, []);
88
+
89
+ return (
90
+ <>
91
+ <div>Selected items loaded: {loaded.toString()}</div>
92
+
93
+ <br />
94
+
95
+ <MultiSuggestField<string>
96
+ items={items.map(({ testId }) => testId)}
97
+ selectedItems={selected.map(({ testId }) => testId)}
98
+ itemId={identity}
99
+ itemLabel={(itemId) => items.find(({ testId }) => testId === itemId)?.testLabel ?? itemId}
100
+ createNewItemFromQuery={(query) => query}
101
+ />
102
+
103
+ <br />
104
+
105
+ <button onClick={() => setLoaded((prev) => !prev)}>Toggle selected</button>
106
+ </>
107
+ );
74
108
  };
75
109
 
110
+ /**
111
+ *
112
+ */
113
+ export const deferredSelection = DeferredSelectionTemplate.bind({});
114
+
76
115
  /**
77
116
  * New item creation, add to a existing list
78
117
  */
79
- export const newItemCreation = Template.bind({});
80
- newItemCreation.args = {
118
+ export const uncontrolledNewItemCreation = Template.bind({});
119
+ uncontrolledNewItemCreation.args = {
81
120
  items,
82
121
  createNewItemFromQuery: (query) => ({ testId: `${query}-id`, testLabel: query }),
83
122
  prePopulateWithItems: false,
@@ -88,7 +127,7 @@ newItemCreation.args = {
88
127
  const CreationTemplate: StoryFn = () => {
89
128
  const [selectedValues, setSelectedValues] = useState<string[]>([]);
90
129
 
91
- const empty = useMemo<string[]>(() => [], []);
130
+ const items = useMemo<string[]>(() => ["foo", "bar", "baz"], []);
92
131
 
93
132
  const identity = useCallback((item: string): string => item, []);
94
133
 
@@ -100,7 +139,7 @@ const CreationTemplate: StoryFn = () => {
100
139
 
101
140
  return (
102
141
  <MultiSuggestField<string>
103
- items={empty}
142
+ items={items}
104
143
  selectedItems={selectedValues}
105
144
  onSelection={handleOnSelect}
106
145
  itemId={identity}
@@ -114,4 +153,85 @@ const CreationTemplate: StoryFn = () => {
114
153
  /**
115
154
  * Completely create all items from quieries
116
155
  */
117
- export const buildItemsFromQuery = CreationTemplate.bind({});
156
+ export const conrolledNewItemCreation = CreationTemplate.bind({});
157
+
158
+ const WithResetButtonComponent = (): JSX.Element => {
159
+ const copy: Array<{ testLabel: string; testId: string }> = [items[2]];
160
+
161
+ const [selected, setSelected] = useState(copy);
162
+
163
+ const handleOnSelect = useCallback((params) => {
164
+ const items = params.selectedItems;
165
+ setSelected(items);
166
+ }, []);
167
+
168
+ const handleReset = (): void => {
169
+ setSelected(copy);
170
+ };
171
+
172
+ return (
173
+ <div>
174
+ <button onClick={handleReset}>Reset</button>
175
+ <br />
176
+ <br />
177
+ <MultiSuggestField<{ testLabel: string; testId: string }>
178
+ items={items}
179
+ selectedItems={selected}
180
+ onSelection={handleOnSelect}
181
+ itemId={({ testId }) => testId}
182
+ itemLabel={({ testLabel }) => testLabel}
183
+ createNewItemFromQuery={(query) => ({ testId: `${query}-id`, testLabel: query })}
184
+ />
185
+ </div>
186
+ );
187
+ };
188
+
189
+ const WithResetButton: StoryFn = () => {
190
+ return <WithResetButtonComponent />;
191
+ };
192
+
193
+ /**
194
+ * Reset values
195
+ */
196
+ export const withResetItemAndCreation = WithResetButton.bind({});
197
+
198
+ const WithinModal = (): JSX.Element => {
199
+ const [isOpen, setIsOpen] = useState(false);
200
+
201
+ const copy: Array<{ testLabel: string; testId: string }> = [items[2]];
202
+
203
+ const [selected, setSelected] = useState(copy);
204
+
205
+ const handleOnSelect = useCallback((params) => {
206
+ const items = params.selectedItems;
207
+ setSelected(items);
208
+ }, []);
209
+
210
+ const handleReset = (): void => {
211
+ setSelected(copy);
212
+ };
213
+
214
+ return (
215
+ <>
216
+ <button onClick={() => setIsOpen(true)}>open modal</button>
217
+
218
+ <SimpleDialog isOpen={isOpen} onClose={() => setIsOpen(false)} canOutsideClickClose>
219
+ <div>
220
+ <button onClick={handleReset}>Reset</button>
221
+ <br />
222
+ <br />
223
+ <MultiSuggestField<{ testLabel: string; testId: string }>
224
+ items={items}
225
+ selectedItems={selected}
226
+ onSelection={handleOnSelect}
227
+ itemId={({ testId }) => testId}
228
+ itemLabel={({ testLabel }) => testLabel}
229
+ createNewItemFromQuery={(query) => ({ testId: `${query}-id`, testLabel: query })}
230
+ />
231
+ </div>
232
+ </SimpleDialog>
233
+ </>
234
+ );
235
+ };
236
+
237
+ export const withinModal = WithinModal.bind({});