@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.
- package/CHANGELOG.md +22 -0
- package/dist/cjs/cmem/markdown/Markdown.js +10 -2
- package/dist/cjs/cmem/markdown/Markdown.js.map +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +4 -4
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/cjs/common/index.js +2 -0
- package/dist/cjs/common/index.js.map +1 -1
- package/dist/cjs/common/utils/getScrollParent.js +24 -0
- package/dist/cjs/common/utils/getScrollParent.js.map +1 -0
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +19 -2
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +66 -41
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/Sticky/StickyTarget.js +85 -0
- package/dist/cjs/components/Sticky/StickyTarget.js.map +1 -0
- package/dist/cjs/components/Sticky/index.js +14 -0
- package/dist/cjs/components/Sticky/index.js.map +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js +7 -7
- package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
- package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js +3 -2
- package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
- package/dist/cjs/extensions/react-flow/handles/HandleContent.js +14 -2
- package/dist/cjs/extensions/react-flow/handles/HandleContent.js.map +1 -1
- package/dist/cjs/extensions/react-flow/handles/HandleTools.js +1 -1
- package/dist/cjs/extensions/react-flow/handles/HandleTools.js.map +1 -1
- package/dist/cjs/extensions/react-flow/minimap/MiniMap.js +6 -8
- package/dist/cjs/extensions/react-flow/minimap/MiniMap.js.map +1 -1
- package/dist/esm/cmem/markdown/Markdown.js +10 -2
- package/dist/esm/cmem/markdown/Markdown.js.map +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +5 -5
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/esm/common/index.js +2 -0
- package/dist/esm/common/index.js.map +1 -1
- package/dist/esm/common/utils/getScrollParent.js +20 -0
- package/dist/esm/common/utils/getScrollParent.js.map +1 -0
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +27 -2
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +72 -52
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/Sticky/StickyTarget.js +89 -0
- package/dist/esm/components/Sticky/StickyTarget.js.map +1 -0
- package/dist/esm/components/Sticky/index.js +2 -0
- package/dist/esm/components/Sticky/index.js.map +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/esm/extensions/react-flow/edges/EdgeDefault.js +7 -7
- package/dist/esm/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
- package/dist/esm/extensions/react-flow/edges/EdgeLabel.js +3 -2
- package/dist/esm/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
- package/dist/esm/extensions/react-flow/handles/HandleContent.js +13 -2
- package/dist/esm/extensions/react-flow/handles/HandleContent.js.map +1 -1
- package/dist/esm/extensions/react-flow/handles/HandleTools.js +1 -1
- package/dist/esm/extensions/react-flow/handles/HandleTools.js.map +1 -1
- package/dist/esm/extensions/react-flow/minimap/MiniMap.js +6 -8
- package/dist/esm/extensions/react-flow/minimap/MiniMap.js.map +1 -1
- package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +5 -0
- package/dist/types/cmem/react-flow/configuration/graph.d.ts +9 -9
- package/dist/types/cmem/react-flow/configuration/unspecified.d.ts +2 -2
- package/dist/types/common/index.d.ts +2 -0
- package/dist/types/common/utils/getScrollParent.d.ts +9 -0
- package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +2 -0
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +1 -1
- package/dist/types/components/Sticky/StickyTarget.d.ts +32 -0
- package/dist/types/components/Sticky/index.d.ts +1 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/extensions/react-flow/edges/EdgeDefault.d.ts +6 -1
- package/dist/types/extensions/react-flow/edges/EdgeLabel.d.ts +1 -1
- package/dist/types/extensions/react-flow/edges/edgeTypes.d.ts +10 -10
- package/dist/types/extensions/react-flow/handles/HandleContent.d.ts +2 -3
- package/dist/types/extensions/react-flow/minimap/MiniMap.d.ts +12 -1
- package/package.json +3 -1
- package/src/cmem/markdown/Markdown.stories.tsx +8 -1
- package/src/cmem/markdown/Markdown.tsx +22 -1
- package/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx +10 -4
- package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +8 -3
- package/src/common/index.ts +3 -0
- package/src/common/utils/getScrollParent.ts +20 -0
- package/src/components/AutocompleteField/AutoCompleteField.tsx +28 -0
- package/src/components/AutocompleteField/autocompletefield.scss +1 -1
- package/src/components/MultiSelect/MultiSelect.tsx +72 -47
- package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +146 -26
- package/src/components/MultiSuggestField/tests/MultiSuggestField.test.tsx +363 -61
- package/src/components/Sticky/StickyTarget.tsx +119 -0
- package/src/components/Sticky/index.ts +1 -0
- package/src/components/Sticky/sticky.scss +69 -0
- package/src/components/Sticky/stories/StickyTarget.stories.tsx +63 -0
- package/src/components/index.scss +1 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/codemirror/CodeMirror.tsx +1 -1
- package/src/extensions/react-flow/edges/EdgeDefault.tsx +70 -62
- package/src/extensions/react-flow/edges/EdgeLabel.tsx +14 -2
- package/src/extensions/react-flow/edges/stories/EdgeDefault.stories.tsx +11 -5
- package/src/extensions/react-flow/edges/stories/EdgeLabel.stories.tsx +2 -0
- package/src/extensions/react-flow/handles/HandleContent.tsx +28 -25
- package/src/extensions/react-flow/handles/HandleTools.tsx +1 -0
- package/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx +5 -1
- package/src/extensions/react-flow/minimap/MiniMap.stories.tsx +62 -0
- package/src/extensions/react-flow/minimap/MiniMap.tsx +23 -7
- package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +2 -0
- package/src/extensions/react-flow/nodes/stories/NodeContentExtension.stories.tsx +2 -0
- 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
|
|
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
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
const [
|
|
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
|
-
|
|
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
|
-
|
|
205
|
-
|
|
212
|
+
setExternalItems(items);
|
|
213
|
+
setFilteredItems([...items, ...createdItems.current]);
|
|
206
214
|
}, [items.map((item) => itemId(item)).join("|")]);
|
|
207
215
|
|
|
208
216
|
React.useEffect(() => {
|
|
209
|
-
|
|
217
|
+
!isControlled &&
|
|
218
|
+
onSelection &&
|
|
210
219
|
onSelection({
|
|
211
220
|
newlySelected: selectedItems.slice(-1)[0],
|
|
212
|
-
createdItems:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
289
|
-
|
|
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
|
-
|
|
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
|
-
|
|
338
|
-
|
|
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 = (
|
|
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
|
-
|
|
358
|
-
|
|
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={
|
|
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
|
-
|
|
68
|
-
|
|
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) =>
|
|
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
|
|
80
|
-
|
|
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
|
|
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={
|
|
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
|
|
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({});
|