@eccenca/gui-elements 22.0.1 → 22.1.0-rc.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 +20 -4
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +18 -14
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/cmem/ActivityControl/SilkActivityControl.js +58 -30
- package/dist/cjs/cmem/ActivityControl/SilkActivityControl.js.map +1 -1
- package/dist/cjs/cmem/ActivityControl/index.js +11 -0
- package/dist/cjs/cmem/ActivityControl/index.js.map +1 -0
- package/dist/cjs/cmem/ContentBlobToggler/index.js +8 -0
- package/dist/cjs/cmem/ContentBlobToggler/index.js.map +1 -0
- package/dist/cjs/cmem/index.js +14 -13
- package/dist/cjs/cmem/index.js.map +1 -1
- package/dist/cjs/cmem/react-flow/ReactFlow/ReactFlow.js +57 -0
- package/dist/cjs/cmem/react-flow/ReactFlow/ReactFlow.js.map +1 -0
- package/dist/cjs/cmem/react-flow/configuration/_colors-graph.module.scss +35 -0
- package/dist/cjs/cmem/react-flow/configuration/_colors-linking.module.scss +29 -0
- package/dist/cjs/cmem/react-flow/configuration/_colors-workflow.module.scss +22 -0
- package/dist/cjs/cmem/react-flow/configuration/graph.js +31 -0
- package/dist/cjs/cmem/react-flow/configuration/graph.js.map +1 -0
- package/dist/cjs/cmem/react-flow/configuration/linking.js +29 -0
- package/dist/cjs/cmem/react-flow/configuration/linking.js.map +1 -0
- package/dist/cjs/cmem/react-flow/configuration/unspecified.js +15 -0
- package/dist/cjs/cmem/react-flow/configuration/unspecified.js.map +1 -0
- package/dist/cjs/cmem/react-flow/configuration/workflow.js +27 -0
- package/dist/cjs/cmem/react-flow/configuration/workflow.js.map +1 -0
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +285 -0
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -0
- package/dist/cjs/components/AutoSuggestion/AutoSuggestionList.js +81 -0
- package/dist/cjs/components/AutoSuggestion/AutoSuggestionList.js.map +1 -0
- package/dist/cjs/components/AutoSuggestion/SingleLineCodeEditor.js +46 -0
- package/dist/cjs/components/AutoSuggestion/SingleLineCodeEditor.js.map +1 -0
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +8 -12
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/Button/Button.js.map +1 -1
- package/dist/cjs/components/ContextOverlay/ContextMenu.js +1 -1
- package/dist/cjs/components/ContextOverlay/ContextMenu.js.map +1 -1
- package/dist/cjs/components/Dialog/Modal.js +2 -2
- package/dist/cjs/components/Dialog/Modal.js.map +1 -1
- package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/cjs/components/Icon/Icon.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +30 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +219 -0
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -0
- package/dist/cjs/components/Tabs/Tab.js +95 -0
- package/dist/cjs/components/Tabs/Tab.js.map +1 -0
- package/dist/cjs/components/Tabs/TabTitle.js +20 -0
- package/dist/cjs/components/Tabs/TabTitle.js.map +1 -0
- package/dist/cjs/components/Tabs/Tabs.js +29 -19
- package/dist/cjs/components/Tabs/Tabs.js.map +1 -1
- package/dist/cjs/components/Tag/Tag.js +7 -1
- package/dist/cjs/components/Tag/Tag.js.map +1 -1
- package/dist/cjs/extensions/react-flow/edges/utils.js +96 -4
- package/dist/cjs/extensions/react-flow/edges/utils.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +5 -4
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/NodeContentExtension.js +2 -2
- package/dist/cjs/extensions/react-flow/nodes/NodeContentExtension.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/NodeTools.js.map +1 -1
- package/dist/cjs/index.js +17 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/legacy-replacements/Button/AffirmativeButton.js +25 -0
- package/dist/cjs/legacy-replacements/Button/AffirmativeButton.js.map +1 -0
- package/dist/cjs/legacy-replacements/Button/Button.js +61 -0
- package/dist/cjs/legacy-replacements/Button/Button.js.map +1 -0
- package/dist/cjs/legacy-replacements/Button/DismissiveButton.js +25 -0
- package/dist/cjs/legacy-replacements/Button/DismissiveButton.js.map +1 -0
- package/dist/cjs/legacy-replacements/Button/DisruptiveButton.js +25 -0
- package/dist/cjs/legacy-replacements/Button/DisruptiveButton.js.map +1 -0
- package/dist/cjs/legacy-replacements/Checkbox/Checkbox.js +55 -0
- package/dist/cjs/legacy-replacements/Checkbox/Checkbox.js.map +1 -0
- package/dist/cjs/legacy-replacements/Radio/RadioButton.js +48 -0
- package/dist/cjs/legacy-replacements/Radio/RadioButton.js.map +1 -0
- package/dist/cjs/legacy-replacements/Tabs/Tabs.js +36 -0
- package/dist/cjs/legacy-replacements/Tabs/Tabs.js.map +1 -0
- package/dist/cjs/legacy-replacements/TextField/TextField.js +75 -0
- package/dist/cjs/legacy-replacements/TextField/TextField.js.map +1 -0
- package/dist/cjs/legacy-replacements/index.js +22 -0
- package/dist/cjs/legacy-replacements/index.js.map +1 -0
- package/dist/es5/cmem/ActivityControl/ActivityControlWidget.js +19 -15
- package/dist/es5/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/es5/cmem/ActivityControl/SilkActivityControl.js +56 -30
- package/dist/es5/cmem/ActivityControl/SilkActivityControl.js.map +1 -1
- package/dist/es5/cmem/ActivityControl/index.js +4 -0
- package/dist/es5/cmem/ActivityControl/index.js.map +1 -0
- package/dist/es5/cmem/ContentBlobToggler/index.js +3 -0
- package/dist/es5/cmem/ContentBlobToggler/index.js.map +1 -0
- package/dist/es5/cmem/index.js +6 -8
- package/dist/es5/cmem/index.js.map +1 -1
- package/dist/es5/cmem/react-flow/ReactFlow/ReactFlow.js +43 -0
- package/dist/es5/cmem/react-flow/ReactFlow/ReactFlow.js.map +1 -0
- package/dist/es5/cmem/react-flow/configuration/_colors-graph.module.scss +35 -0
- package/dist/es5/cmem/react-flow/configuration/_colors-linking.module.scss +29 -0
- package/dist/es5/cmem/react-flow/configuration/_colors-workflow.module.scss +22 -0
- package/dist/es5/cmem/react-flow/configuration/graph.js +23 -0
- package/dist/es5/cmem/react-flow/configuration/graph.js.map +1 -0
- package/dist/es5/cmem/react-flow/configuration/linking.js +21 -0
- package/dist/es5/cmem/react-flow/configuration/linking.js.map +1 -0
- package/dist/es5/cmem/react-flow/configuration/unspecified.js +12 -0
- package/dist/es5/cmem/react-flow/configuration/unspecified.js.map +1 -0
- package/dist/es5/cmem/react-flow/configuration/workflow.js +19 -0
- package/dist/es5/cmem/react-flow/configuration/workflow.js.map +1 -0
- package/dist/es5/components/AutoSuggestion/AutoSuggestion.js +347 -0
- package/dist/es5/components/AutoSuggestion/AutoSuggestion.js.map +1 -0
- package/dist/es5/components/AutoSuggestion/AutoSuggestionList.js +93 -0
- package/dist/es5/components/AutoSuggestion/AutoSuggestionList.js.map +1 -0
- package/dist/es5/components/AutoSuggestion/SingleLineCodeEditor.js +42 -0
- package/dist/es5/components/AutoSuggestion/SingleLineCodeEditor.js.map +1 -0
- package/dist/es5/components/AutocompleteField/AutoCompleteField.js +8 -12
- package/dist/es5/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/es5/components/Button/Button.js.map +1 -1
- package/dist/es5/components/ContextOverlay/ContextMenu.js +1 -1
- package/dist/es5/components/ContextOverlay/ContextMenu.js.map +1 -1
- package/dist/es5/components/Dialog/Modal.js +2 -2
- package/dist/es5/components/Dialog/Modal.js.map +1 -1
- package/dist/es5/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/es5/components/Icon/Icon.js.map +1 -1
- package/dist/es5/components/Icon/canonicalIconNames.js +30 -0
- package/dist/es5/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/es5/components/MultiSelect/MultiSelect.js +301 -0
- package/dist/es5/components/MultiSelect/MultiSelect.js.map +1 -0
- package/dist/es5/components/Tabs/Tab.js +98 -0
- package/dist/es5/components/Tabs/Tab.js.map +1 -0
- package/dist/es5/components/Tabs/TabTitle.js +16 -0
- package/dist/es5/components/Tabs/TabTitle.js.map +1 -0
- package/dist/es5/components/Tabs/Tabs.js +11 -21
- package/dist/es5/components/Tabs/Tabs.js.map +1 -1
- package/dist/es5/components/Tag/Tag.js +7 -1
- package/dist/es5/components/Tag/Tag.js.map +1 -1
- package/dist/es5/extensions/react-flow/edges/utils.js +99 -5
- package/dist/es5/extensions/react-flow/edges/utils.js.map +1 -1
- package/dist/es5/extensions/react-flow/nodes/NodeContent.js +21 -4
- package/dist/es5/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/es5/extensions/react-flow/nodes/NodeContentExtension.js +2 -2
- package/dist/es5/extensions/react-flow/nodes/NodeContentExtension.js.map +1 -1
- package/dist/es5/extensions/react-flow/nodes/NodeTools.js.map +1 -1
- package/dist/es5/index.js +9 -2
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/legacy-replacements/Button/AffirmativeButton.js +29 -0
- package/dist/es5/legacy-replacements/Button/AffirmativeButton.js.map +1 -0
- package/dist/es5/legacy-replacements/Button/Button.js +65 -0
- package/dist/es5/legacy-replacements/Button/Button.js.map +1 -0
- package/dist/es5/legacy-replacements/Button/DismissiveButton.js +29 -0
- package/dist/es5/legacy-replacements/Button/DismissiveButton.js.map +1 -0
- package/dist/es5/legacy-replacements/Button/DisruptiveButton.js +29 -0
- package/dist/es5/legacy-replacements/Button/DisruptiveButton.js.map +1 -0
- package/dist/es5/legacy-replacements/Checkbox/Checkbox.js +59 -0
- package/dist/es5/legacy-replacements/Checkbox/Checkbox.js.map +1 -0
- package/dist/es5/legacy-replacements/Radio/RadioButton.js +52 -0
- package/dist/es5/legacy-replacements/Radio/RadioButton.js.map +1 -0
- package/dist/es5/legacy-replacements/Tabs/Tabs.js +40 -0
- package/dist/es5/legacy-replacements/Tabs/Tabs.js.map +1 -0
- package/dist/es5/legacy-replacements/TextField/TextField.js +81 -0
- package/dist/es5/legacy-replacements/TextField/TextField.js.map +1 -0
- package/dist/es5/legacy-replacements/index.js +10 -0
- package/dist/es5/legacy-replacements/index.js.map +1 -0
- package/dist/types/cmem/ActivityControl/ActivityControlTypes.d.ts +2 -1
- package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +39 -2
- package/dist/types/cmem/ActivityControl/SilkActivityControl.d.ts +16 -3
- package/dist/types/cmem/ActivityControl/index.d.ts +3 -0
- package/dist/types/cmem/ContentBlobToggler/index.d.ts +2 -0
- package/dist/types/cmem/index.d.ts +8 -8
- package/dist/types/cmem/react-flow/ReactFlow/ReactFlow.d.ts +14 -0
- package/dist/types/cmem/react-flow/configuration/graph.d.ts +21 -0
- package/dist/types/cmem/react-flow/configuration/linking.d.ts +19 -0
- package/dist/types/cmem/react-flow/configuration/unspecified.d.ts +9 -0
- package/dist/types/cmem/react-flow/configuration/workflow.d.ts +17 -0
- package/dist/types/components/AutoSuggestion/AutoSuggestion.d.ts +67 -0
- package/dist/types/components/AutoSuggestion/AutoSuggestionList.d.ts +13 -0
- package/dist/types/components/AutoSuggestion/SingleLineCodeEditor.d.ts +25 -0
- package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +8 -7
- package/dist/types/components/Button/Button.d.ts +3 -2
- package/dist/types/components/ContextOverlay/ContextMenu.d.ts +6 -1
- package/dist/types/components/Dialog/Modal.d.ts +4 -3
- package/dist/types/components/Dialog/SimpleDialog.d.ts +2 -0
- package/dist/types/components/Icon/Icon.d.ts +2 -2
- package/dist/types/components/Icon/IconButton.d.ts +1 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +1 -1
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +79 -0
- package/dist/types/components/Tabs/Tab.d.ts +549 -0
- package/dist/types/components/Tabs/TabTitle.d.ts +38 -0
- package/dist/types/components/Tabs/Tabs.d.ts +14 -20
- package/dist/types/components/Tag/Tag.d.ts +1 -1
- package/dist/types/extensions/react-flow/edges/utils.d.ts +1 -1
- package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +8 -8
- package/dist/types/extensions/react-flow/nodes/NodeDefault.d.ts +2 -2
- package/dist/types/extensions/react-flow/nodes/NodeTools.d.ts +2 -1
- package/dist/types/extensions/react-flow/nodes/nodeTypes.d.ts +10 -10
- package/dist/types/index.d.ts +9 -2
- package/dist/types/legacy-replacements/Button/AffirmativeButton.d.ts +2 -0
- package/dist/types/legacy-replacements/Button/Button.d.ts +5 -0
- package/dist/types/legacy-replacements/Button/DismissiveButton.d.ts +2 -0
- package/dist/types/legacy-replacements/Button/DisruptiveButton.d.ts +2 -0
- package/dist/types/legacy-replacements/Checkbox/Checkbox.d.ts +2 -0
- package/dist/types/legacy-replacements/Radio/RadioButton.d.ts +2 -0
- package/dist/types/legacy-replacements/Tabs/Tabs.d.ts +22 -0
- package/dist/types/legacy-replacements/TextField/TextField.d.ts +2 -0
- package/dist/types/legacy-replacements/index.d.ts +10 -0
- package/package.json +16 -7
- package/src/cmem/ActivityControl/ActivityControlTypes.ts +3 -1
- package/src/cmem/ActivityControl/ActivityControlWidget.stories.tsx +98 -0
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +131 -89
- package/src/cmem/ActivityControl/SilkActivityControl.tsx +178 -120
- package/src/cmem/ActivityControl/index.ts +3 -0
- package/src/cmem/ContentBlobToggler/index.ts +2 -0
- package/src/cmem/_index.scss +6 -0
- package/src/cmem/index.ts +10 -23
- package/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx +222 -0
- package/src/cmem/react-flow/ReactFlow/ReactFlow.tsx +40 -0
- package/src/cmem/react-flow/_edges.scss +23 -0
- package/src/cmem/react-flow/_handles.scss +34 -0
- package/src/cmem/react-flow/_index.scss +5 -0
- package/src/cmem/react-flow/_minimap.scss +33 -0
- package/src/cmem/react-flow/_nodes.scss +60 -0
- package/src/cmem/react-flow/configuration/_colors-graph.module.scss +35 -0
- package/src/cmem/react-flow/configuration/_colors-linking.module.scss +29 -0
- package/src/cmem/react-flow/configuration/_colors-workflow.module.scss +22 -0
- package/src/cmem/react-flow/configuration/_colors.scss +3 -0
- package/src/cmem/react-flow/configuration/graph.ts +29 -0
- package/src/cmem/react-flow/configuration/linking.ts +28 -0
- package/src/cmem/react-flow/configuration/unspecified.ts +13 -0
- package/src/cmem/react-flow/configuration/workflow.ts +25 -0
- package/src/components/AutoSuggestion/AutoSuggestion.scss +100 -0
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +447 -0
- package/src/components/AutoSuggestion/AutoSuggestionList.tsx +170 -0
- package/src/components/AutoSuggestion/SingleLineCodeEditor.tsx +97 -0
- package/src/components/AutoSuggestion/tests/AutoSuggestion.test.tsx +37 -0
- package/src/components/AutoSuggestion/tests/AutoSuggestionList.test.tsx +124 -0
- package/src/components/AutoSuggestion/tests/SingleLineCodeEditor.test.tsx +55 -0
- package/src/components/AutocompleteField/AutoCompleteField.tsx +19 -19
- package/src/components/AutocompleteField/autoCompleteFieldUtils.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -2
- package/src/components/ContextOverlay/ContextMenu.tsx +8 -2
- package/src/components/Dialog/Modal.tsx +9 -2
- package/src/components/Dialog/SimpleDialog.tsx +2 -0
- package/src/components/Icon/Icon.tsx +4 -4
- package/src/components/Icon/IconButton.tsx +1 -1
- package/src/components/Icon/canonicalIconNames.tsx +39 -2
- package/src/components/MultiSelect/MultiSelect.stories.tsx +63 -0
- package/src/components/MultiSelect/MultiSelect.tsx +370 -0
- package/src/components/Tabs/Tab.tsx +112 -0
- package/src/components/Tabs/TabTitle.tsx +71 -0
- package/src/components/Tabs/Tabs.tsx +26 -90
- package/src/components/Tabs/stories/Tab.stories.tsx +65 -0
- package/src/components/Tabs/stories/TabTitle.stories.tsx +35 -0
- package/src/components/Tabs/stories/Tabs.stories.tsx +98 -0
- package/src/components/Tabs/tabs.scss +11 -4
- package/src/components/Tag/Tag.tsx +10 -3
- package/src/components/Tag/tag.scss +1 -1
- package/src/components/TextField/TextField.tsx +1 -1
- package/src/configuration/_variables.scss +3 -3
- package/src/extensions/react-flow/_config.scss +2 -2
- package/src/extensions/react-flow/edges/_edges.scss +3 -28
- package/src/extensions/react-flow/edges/utils.ts +139 -4
- package/src/extensions/react-flow/handles/_handles.scss +4 -58
- package/src/extensions/react-flow/minimap/_minimap.scss +0 -45
- package/src/extensions/react-flow/nodes/NodeContent.tsx +134 -133
- package/src/extensions/react-flow/nodes/NodeContentExtension.tsx +11 -10
- package/src/extensions/react-flow/nodes/NodeDefault.tsx +2 -2
- package/src/extensions/react-flow/nodes/NodeTools.tsx +2 -1
- package/src/extensions/react-flow/nodes/_nodes.scss +31 -185
- package/src/extensions/react-flow/nodes/{NodeContent.stories.tsx → stories/NodeContent.stories.tsx} +4 -4
- package/src/extensions/react-flow/nodes/{NodeContentExtension.stories.tsx → stories/NodeContentExtension.stories.tsx} +4 -4
- package/src/extensions/react-flow/nodes/{NodeDefault.stories.tsx → stories/NodeDefault.stories.tsx} +5 -4
- package/src/index.scss +1 -0
- package/src/index.ts +16 -1
- package/src/legacy-replacements/Tabs/Tabs.stories.tsx +46 -0
- package/src/legacy-replacements/Tabs/Tabs.tsx +84 -0
- package/src/legacy-replacements/index.ts +11 -0
- package/src/test/setupTests.js +19 -0
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Classes as BlueprintClassNames,
|
|
9
|
+
OverlayProps, Overlay as BlueprintOverlay,
|
|
10
|
+
IOverlayState,
|
|
11
|
+
} from "@blueprintjs/core";
|
|
8
12
|
import {Card} from "./../Card";
|
|
9
13
|
import {CLASSPREFIX as eccgui} from "../../configuration/constants";
|
|
10
|
-
import { IOverlayState } from '@blueprintjs/core';
|
|
11
14
|
|
|
12
15
|
export interface ModalProps extends OverlayProps, IOverlayState {
|
|
13
16
|
children: React.ReactNode | React.ReactNode[];
|
|
@@ -23,6 +26,8 @@ export interface ModalProps extends OverlayProps, IOverlayState {
|
|
|
23
26
|
* Prevents that a backdrop area is displayed behind the modal elements.
|
|
24
27
|
*/
|
|
25
28
|
preventBackdrop?: boolean;
|
|
29
|
+
/** Optional props for the wrapper div element inside the modal overlay. */
|
|
30
|
+
wrapperDivProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
/**
|
|
@@ -38,6 +43,7 @@ function Modal({
|
|
|
38
43
|
canOutsideClickClose=false,
|
|
39
44
|
canEscapeKeyClose=false,
|
|
40
45
|
preventBackdrop=false,
|
|
46
|
+
wrapperDivProps,
|
|
41
47
|
...otherProps
|
|
42
48
|
}: ModalProps) {
|
|
43
49
|
|
|
@@ -65,6 +71,7 @@ function Modal({
|
|
|
65
71
|
hasBackdrop={!preventBackdrop}
|
|
66
72
|
>
|
|
67
73
|
<div
|
|
74
|
+
{...wrapperDivProps}
|
|
68
75
|
className={BlueprintClassNames.DIALOG_CONTAINER}
|
|
69
76
|
// this is a workaround because data attribute on SimpleDialog is not correctly routed to the overlay by blueprint js
|
|
70
77
|
data-test-id={(otherProps as any)["data-test-id"] ?? "simpleDialogWidget"}
|
|
@@ -47,6 +47,8 @@ export interface SimpleDialogProps extends ModalProps, TestableComponent {
|
|
|
47
47
|
* Define purpose of the dialog, e.g. if it is a warning.
|
|
48
48
|
*/
|
|
49
49
|
intent?: IntentTypes;
|
|
50
|
+
/** Optional props for the wrapper div element inside the modal. */
|
|
51
|
+
wrapperDivProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
/**
|
|
@@ -5,7 +5,7 @@ import { IntentTypes } from "../../common/Intent";
|
|
|
5
5
|
import Tooltip, { TooltipProps } from "./../Tooltip/Tooltip";
|
|
6
6
|
import canonicalIcons, {IconSized, ValidIconName} from "./canonicalIconNames"
|
|
7
7
|
|
|
8
|
-
interface IconProps extends Omit<CarbonIconProps, "icon" | "description" | "name"> {
|
|
8
|
+
export interface IconProps extends Omit<CarbonIconProps, "icon" | "description" | "name"> {
|
|
9
9
|
// The CSS class name.
|
|
10
10
|
className?: string,
|
|
11
11
|
// Canonical icon name
|
|
@@ -38,16 +38,16 @@ const findExistingIcon = (iconName: ValidIconName | string[],
|
|
|
38
38
|
|
|
39
39
|
/** Returns the first icon name that exists or the fallback icon name. */
|
|
40
40
|
export const findExistingIconName = (iconNames: string[],
|
|
41
|
-
fallbackIconName:
|
|
41
|
+
fallbackIconName: ValidIconName = "Undefined"): ValidIconName => {
|
|
42
42
|
let foundIconName: string = fallbackIconName;
|
|
43
43
|
const iconNameStack = [...iconNames]
|
|
44
44
|
while (foundIconName === fallbackIconName && iconNameStack.length > 0) {
|
|
45
45
|
let iconNameToTest = iconNameStack.shift();
|
|
46
|
-
if (iconNameToTest && canonicalIcons[iconNameToTest] != null) {
|
|
46
|
+
if (iconNameToTest && (canonicalIcons as any)[iconNameToTest] != null) {
|
|
47
47
|
foundIconName = iconNameToTest
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
return foundIconName
|
|
50
|
+
return foundIconName as ValidIconName
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function Icon({
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as icons from "@carbon/icons-react"
|
|
2
2
|
|
|
3
3
|
/** Valid icon names. */
|
|
4
|
-
export type ValidIconName =
|
|
5
|
-
| "application-dataintegration"
|
|
4
|
+
export type ValidIconName = "application-dataintegration"
|
|
6
5
|
| "application-homepage"
|
|
7
6
|
| "application-useraccount"
|
|
8
7
|
| "application-warning"
|
|
@@ -65,6 +64,11 @@ export type ValidIconName = string // allow also dynamic string parameter (in in
|
|
|
65
64
|
| "operation-logout"
|
|
66
65
|
| "operation-filter"
|
|
67
66
|
| "operation-filteredit"
|
|
67
|
+
| "operation-comparison"
|
|
68
|
+
| "operation-transform"
|
|
69
|
+
| "operation-aggregation"
|
|
70
|
+
| "data-sourcepath"
|
|
71
|
+
| "data-targetpath"
|
|
68
72
|
| "list-sort"
|
|
69
73
|
| "list-sortasc"
|
|
70
74
|
| "list-sortdesc"
|
|
@@ -106,6 +110,7 @@ export type ValidIconName = string // allow also dynamic string parameter (in in
|
|
|
106
110
|
| "linked-item"
|
|
107
111
|
| "operation-auto-graph-layout"
|
|
108
112
|
| "unlinked-item"
|
|
113
|
+
| "write-protected"
|
|
109
114
|
| "undefined"
|
|
110
115
|
| "Undefined";
|
|
111
116
|
|
|
@@ -433,6 +438,32 @@ const canonicalIconNames: Record<ValidIconName, IconSized> = {
|
|
|
433
438
|
normal: icons.FilterEdit20,
|
|
434
439
|
large: icons.FilterEdit32
|
|
435
440
|
},
|
|
441
|
+
"operation-transform": {
|
|
442
|
+
small: icons.Calculation16,
|
|
443
|
+
normal: icons.Calculation20,
|
|
444
|
+
large: icons.Calculation32
|
|
445
|
+
},
|
|
446
|
+
"operation-comparison": {
|
|
447
|
+
small: icons.Compare16,
|
|
448
|
+
normal: icons.Compare20,
|
|
449
|
+
large: icons.Compare32
|
|
450
|
+
},
|
|
451
|
+
"operation-aggregation": {
|
|
452
|
+
small: icons.DataCollection16,
|
|
453
|
+
normal: icons.DataCollection20,
|
|
454
|
+
large: icons.DataCollection32
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
"data-sourcepath": {
|
|
458
|
+
small: icons.Data_216,
|
|
459
|
+
normal: icons.Data_220,
|
|
460
|
+
large: icons.Data_232
|
|
461
|
+
},
|
|
462
|
+
"data-targetpath": {
|
|
463
|
+
small: icons.Data_116,
|
|
464
|
+
normal: icons.Data_120,
|
|
465
|
+
large: icons.Data_132
|
|
466
|
+
},
|
|
436
467
|
|
|
437
468
|
"list-sort": {
|
|
438
469
|
small: icons.ArrowsVertical16,
|
|
@@ -646,6 +677,12 @@ const canonicalIconNames: Record<ValidIconName, IconSized> = {
|
|
|
646
677
|
large: icons.ChartNetwork32
|
|
647
678
|
},
|
|
648
679
|
|
|
680
|
+
"write-protected": {
|
|
681
|
+
small: icons.DocumentProtected16,
|
|
682
|
+
normal: icons.DocumentProtected20,
|
|
683
|
+
large: icons.DocumentProtected32
|
|
684
|
+
},
|
|
685
|
+
|
|
649
686
|
"undefined": {
|
|
650
687
|
small: icons.Undefined16,
|
|
651
688
|
normal: icons.Undefined20,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ComponentStory, ComponentMeta } from "@storybook/react";
|
|
3
|
+
import { name } from "react-lorem-ipsum";
|
|
4
|
+
|
|
5
|
+
import MultiSelectExample from "./MultiSelect";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "Components/MultiSelect",
|
|
9
|
+
component: MultiSelectExample,
|
|
10
|
+
argTypes: {
|
|
11
|
+
placeholder: {
|
|
12
|
+
description: "Input placeholder text",
|
|
13
|
+
control: "text",
|
|
14
|
+
table: {
|
|
15
|
+
type: { summary: "string" },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
openOnKeyDown: {
|
|
19
|
+
description:
|
|
20
|
+
"If true, the component waits until a keydown event in the TagInput before opening its popover. If false, the popover opens immediately after a mouse click focuses the component's TagInput ",
|
|
21
|
+
control: "boolean",
|
|
22
|
+
defaultValue: false,
|
|
23
|
+
table: {
|
|
24
|
+
type: { summary: "boolean" },
|
|
25
|
+
defaultValue: { summary: false },
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
items: {
|
|
29
|
+
description: "Array of items in the list",
|
|
30
|
+
control: "none",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
} as ComponentMeta<typeof MultiSelectExample>;
|
|
34
|
+
|
|
35
|
+
const Template: ComponentStory<typeof MultiSelectExample> = (args) => <MultiSelectExample {...args} />;
|
|
36
|
+
|
|
37
|
+
export const Default = Template.bind({});
|
|
38
|
+
|
|
39
|
+
const items = new Array(5).fill(undefined).map((_) => {
|
|
40
|
+
const testLabel = name();
|
|
41
|
+
return { testLabel, testId: `${testLabel}-id` };
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Default.args = {
|
|
45
|
+
items,
|
|
46
|
+
canCreateNewItem: true,
|
|
47
|
+
prePopulateWithItems: false,
|
|
48
|
+
equalityProp: "testId",
|
|
49
|
+
labelProp: "testLabel",
|
|
50
|
+
openOnKeyDown: true,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const TemplateWithOpenDropdown: ComponentStory<typeof MultiSelectExample> = (args) => <MultiSelectExample {...args} />;
|
|
54
|
+
|
|
55
|
+
export const openDropdownWhenFocused = TemplateWithOpenDropdown.bind({});
|
|
56
|
+
|
|
57
|
+
openDropdownWhenFocused.args = {
|
|
58
|
+
items,
|
|
59
|
+
canCreateNewItem: true,
|
|
60
|
+
prePopulateWithItems: false,
|
|
61
|
+
equalityProp: "testId",
|
|
62
|
+
labelProp: "testLabel",
|
|
63
|
+
};
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Intent as BlueprintIntent } from "@blueprintjs/core";
|
|
3
|
+
import { MultiSelect as BlueprintMultiSelect, MultiSelectProps, IItemRendererProps } from "@blueprintjs/select";
|
|
4
|
+
import MenuItem from "../Menu/MenuItem";
|
|
5
|
+
import Highlighter from "../Typography/Highlighter";
|
|
6
|
+
import Button from "../Button/Button";
|
|
7
|
+
import OverflowText from "../Typography/OverflowText";
|
|
8
|
+
|
|
9
|
+
interface SelectedParamsType<T> {
|
|
10
|
+
newlySelected: T;
|
|
11
|
+
selectedItems: T[];
|
|
12
|
+
createdItems: Partial<T>[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IProps<T> extends Pick<MultiSelectProps<T>, "items" | "placeholder" | "openOnKeyDown"> {
|
|
16
|
+
/**
|
|
17
|
+
* field in an item, that differentiates on item from the other.
|
|
18
|
+
*/
|
|
19
|
+
equalityProp: string;
|
|
20
|
+
/**
|
|
21
|
+
* field in the item object that would be used to describe the item.
|
|
22
|
+
* this would be used in the item selection list as well as the multi-select input
|
|
23
|
+
*/
|
|
24
|
+
labelProp: string;
|
|
25
|
+
/**
|
|
26
|
+
* if new items that are not in the original item list can be created and appended
|
|
27
|
+
*/
|
|
28
|
+
canCreateNewItem?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* When set to true will set the multi-select value with all the items provided
|
|
31
|
+
*/
|
|
32
|
+
prePopulateWithItems?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* function handler that would be called anytime an item is selected/deselected or an item is created/removed
|
|
35
|
+
*/
|
|
36
|
+
onSelection?: (params: SelectedParamsType<T>) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Props to spread to `Popover`. Note that `content` cannot be changed.
|
|
39
|
+
*/
|
|
40
|
+
popoverProps?: MultiSelectProps<T>["popoverProps"];
|
|
41
|
+
/**
|
|
42
|
+
* Props to spread to `TagInput`. Use `query` and `onQueryChange` to control the input.
|
|
43
|
+
*/
|
|
44
|
+
tagInputProps?: MultiSelectProps<T>["tagInputProps"];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* prop to listen for query changes, when text is entered in the multi-select input
|
|
48
|
+
*/
|
|
49
|
+
runOnQueryChange?: (query: string) => Promise<T[] | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the component should take up the full width of its container.
|
|
52
|
+
* This overrides `popoverProps.fill` and `tagInputProps.fill`.
|
|
53
|
+
*/
|
|
54
|
+
fullWidth?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* text content to render when filtering items returns zero results.
|
|
57
|
+
* If omitted, "No results." will be rendered in this case.
|
|
58
|
+
*/
|
|
59
|
+
noResultText?: string;
|
|
60
|
+
/**
|
|
61
|
+
* text content to render when a new item non-existing in filtered items is about to be created .
|
|
62
|
+
* If omitted, "No results." will be rendered in this case.
|
|
63
|
+
*/
|
|
64
|
+
newItemCreationText?: string;
|
|
65
|
+
/**
|
|
66
|
+
* The input element is displayed with primary color scheme.
|
|
67
|
+
*/
|
|
68
|
+
hasStatePrimary?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The input element is displayed with success (some type of green) color scheme.
|
|
71
|
+
*/
|
|
72
|
+
hasStateSuccess?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The input element is displayed with success (some type of orange) color scheme.
|
|
75
|
+
*/
|
|
76
|
+
hasStateWarning?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* The input element is displayed with success (some type of red) color scheme.
|
|
79
|
+
*/
|
|
80
|
+
hasStateDanger?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Disables the input element
|
|
83
|
+
*/
|
|
84
|
+
disabled?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function MultiSelect<T>({
|
|
88
|
+
items,
|
|
89
|
+
prePopulateWithItems,
|
|
90
|
+
equalityProp,
|
|
91
|
+
labelProp,
|
|
92
|
+
onSelection,
|
|
93
|
+
canCreateNewItem,
|
|
94
|
+
popoverProps,
|
|
95
|
+
tagInputProps,
|
|
96
|
+
runOnQueryChange,
|
|
97
|
+
fullWidth = true,
|
|
98
|
+
noResultText = "No results.",
|
|
99
|
+
newItemCreationText = "Add new tag",
|
|
100
|
+
hasStatePrimary,
|
|
101
|
+
hasStateDanger,
|
|
102
|
+
hasStateSuccess,
|
|
103
|
+
hasStateWarning,
|
|
104
|
+
disabled,
|
|
105
|
+
...otherProps
|
|
106
|
+
}: IProps<T>) {
|
|
107
|
+
const [createdItems, setCreatedItems] = React.useState<T[]>([]);
|
|
108
|
+
const [itemsCopy, setItemsCopy] = React.useState<T[]>([...items]);
|
|
109
|
+
const [filteredItemList, setFilteredItemList] = React.useState<T[]>([]);
|
|
110
|
+
const [selectedItems, setSelectedItems] = React.useState<T[]>(() => (prePopulateWithItems ? [...items] : []));
|
|
111
|
+
const [query, setQuery] = React.useState<string | undefined>(undefined);
|
|
112
|
+
//currently focused element in popover list
|
|
113
|
+
const [focusedItem, setFocusedItem] = React.useState<T | null>(null);
|
|
114
|
+
const tagInputRef = React.useRef<any>();
|
|
115
|
+
|
|
116
|
+
let intent;
|
|
117
|
+
switch (true) {
|
|
118
|
+
case hasStatePrimary:
|
|
119
|
+
intent = BlueprintIntent.PRIMARY;
|
|
120
|
+
break;
|
|
121
|
+
case hasStateSuccess:
|
|
122
|
+
intent = BlueprintIntent.SUCCESS;
|
|
123
|
+
break;
|
|
124
|
+
case hasStateWarning:
|
|
125
|
+
intent = BlueprintIntent.WARNING;
|
|
126
|
+
break;
|
|
127
|
+
case hasStateDanger:
|
|
128
|
+
intent = BlueprintIntent.DANGER;
|
|
129
|
+
break;
|
|
130
|
+
default:
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** update items copy when the items change
|
|
135
|
+
* e.g for auto-complete when query change
|
|
136
|
+
*/
|
|
137
|
+
React.useEffect(() => {
|
|
138
|
+
setItemsCopy([...items, ...createdItems]);
|
|
139
|
+
setFilteredItemList([...items, ...createdItems]);
|
|
140
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
141
|
+
}, [items.map((item) => item[equalityProp as keyof T]).join("|")]);
|
|
142
|
+
|
|
143
|
+
React.useEffect(() => {
|
|
144
|
+
onSelection &&
|
|
145
|
+
onSelection({
|
|
146
|
+
newlySelected: selectedItems.slice(-1)[0],
|
|
147
|
+
createdItems,
|
|
148
|
+
selectedItems,
|
|
149
|
+
});
|
|
150
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
151
|
+
}, [
|
|
152
|
+
onSelection,
|
|
153
|
+
selectedItems.map((item) => item[equalityProp as keyof T]).join("|"),
|
|
154
|
+
createdItems.map((item) => item[equalityProp as keyof T]).join("|"),
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* using the equality prop specified checks if an item has already been selected
|
|
159
|
+
* @param matcher
|
|
160
|
+
* @returns
|
|
161
|
+
*/
|
|
162
|
+
const itemHasBeenSelectedAlready = (matcher: string) => {
|
|
163
|
+
return !!selectedItems.find((item) => String(item[equalityProp as keyof typeof item]).toString() === matcher);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* removes already selected item from the selectedItems
|
|
168
|
+
* @param matcher
|
|
169
|
+
*/
|
|
170
|
+
const removeItemSelection = (matcher: string) => {
|
|
171
|
+
setSelectedItems((items) => items.filter((t) => String(t[equalityProp as keyof typeof t]).toString() !== matcher));
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* selects and deselects an item from selection list
|
|
176
|
+
* if the item exists it removes it instead
|
|
177
|
+
* @param item
|
|
178
|
+
*/
|
|
179
|
+
const onItemSelect = (item: T) => {
|
|
180
|
+
if (itemHasBeenSelectedAlready(String(item[equalityProp as keyof T]).toString())) {
|
|
181
|
+
removeItemSelection(String(item[equalityProp as keyof T]).toString());
|
|
182
|
+
} else {
|
|
183
|
+
setSelectedItems((items) => [...items, item]);
|
|
184
|
+
}
|
|
185
|
+
setQuery("");
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* search through item list using "label prop" and update the items popover
|
|
190
|
+
* @param query
|
|
191
|
+
*/
|
|
192
|
+
const onQueryChange = async (query: string) => {
|
|
193
|
+
if (query.length) {
|
|
194
|
+
setQuery(query);
|
|
195
|
+
const resultFromQuery = runOnQueryChange && (await runOnQueryChange(removeExtraSpaces(query)));
|
|
196
|
+
setFilteredItemList(() =>
|
|
197
|
+
[...(resultFromQuery ?? itemsCopy), ...createdItems].filter((t) =>
|
|
198
|
+
String(t[labelProp as keyof typeof t]).toLowerCase().includes(query.toLowerCase())
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Renders the entries of the (search) options list
|
|
205
|
+
const optionRenderer = (label: string) => {
|
|
206
|
+
return <Highlighter label={label} searchValue={query} />;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* defines how an item in the item list is displayed
|
|
211
|
+
* @param tag
|
|
212
|
+
* @param param
|
|
213
|
+
* @returns
|
|
214
|
+
*/
|
|
215
|
+
const onItemRenderer = (item: T, { handleClick, modifiers }: IItemRendererProps) => {
|
|
216
|
+
if (!modifiers.matchesPredicate) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const label = createdItems.find((createdItem) => createdItem[labelProp as keyof T] === item[labelProp as keyof T])
|
|
220
|
+
? `${item[labelProp as keyof T]} (new tag)`
|
|
221
|
+
: item[labelProp as keyof T];
|
|
222
|
+
return (
|
|
223
|
+
<MenuItem
|
|
224
|
+
active={modifiers.active}
|
|
225
|
+
key={String(item[equalityProp as keyof T]).toString()}
|
|
226
|
+
icon={itemHasBeenSelectedAlready(String(item[equalityProp as keyof T]).toString()) ? "state-checked" : "state-unchecked"}
|
|
227
|
+
onClick={handleClick}
|
|
228
|
+
text={optionRenderer(String(label).toString())}
|
|
229
|
+
shouldDismissPopover={false}
|
|
230
|
+
/>
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* clear all selected items in the multi-select input
|
|
236
|
+
*/
|
|
237
|
+
const handleClear = () => {
|
|
238
|
+
setSelectedItems([]);
|
|
239
|
+
setFilteredItemList(itemsCopy);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* remove a specific item from the multi-select input
|
|
244
|
+
* @param label
|
|
245
|
+
* @param index
|
|
246
|
+
*/
|
|
247
|
+
const removeTagFromSelectionViaIndex = (label: string, index: number) => {
|
|
248
|
+
setSelectedItems([...selectedItems.slice(0, index), ...selectedItems.slice(index + 1)]);
|
|
249
|
+
setCreatedItems((items) => items.filter((t) => String(t[labelProp as keyof typeof t]).toString() !== label));
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const removeExtraSpaces = (text: string) => text.replace(/\s+/g, " ").trim();
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* utility function to create a new Item
|
|
256
|
+
* @param event
|
|
257
|
+
* @param label
|
|
258
|
+
*/
|
|
259
|
+
const createNewItem = (event: React.KeyboardEvent<HTMLElement> | React.MouseEvent<HTMLElement>, label: string): T => {
|
|
260
|
+
const newItem = { [labelProp]: removeExtraSpaces(label), [equalityProp]: removeExtraSpaces(label) } as any;
|
|
261
|
+
//set new items
|
|
262
|
+
setCreatedItems((items) => [...items, newItem]);
|
|
263
|
+
setQuery("");
|
|
264
|
+
itemsCopy.push(newItem);
|
|
265
|
+
return newItem;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* added functionality to create new item when there are no matching items on enter keypress
|
|
270
|
+
* @param event
|
|
271
|
+
*/
|
|
272
|
+
const handleOnKeyUp = (event: React.KeyboardEvent<HTMLElement>) => {
|
|
273
|
+
if (event.key === "Enter" && !filteredItemList.length && !!query) {
|
|
274
|
+
createNewItem(event, query);
|
|
275
|
+
}
|
|
276
|
+
tagInputRef.current?.focus();
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* added functionality to either create new item
|
|
281
|
+
* when there are no matching items or select an item on tab keypress
|
|
282
|
+
* @param event
|
|
283
|
+
*/
|
|
284
|
+
const handleOnKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
|
285
|
+
if (event.key === "Tab" && !!query) {
|
|
286
|
+
event.preventDefault();
|
|
287
|
+
focusedItem ? onItemSelect(focusedItem) : onItemSelect(createNewItem(event, query));
|
|
288
|
+
setTimeout(() => tagInputRef.current?.focus());
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* create new item handler, displays the new item selector and creates a new item when selected
|
|
294
|
+
* @param label '
|
|
295
|
+
* @param active
|
|
296
|
+
* @param handleClick
|
|
297
|
+
* @returns
|
|
298
|
+
*/
|
|
299
|
+
const newItemRenderer = (label: string, active: boolean, handleClick: React.MouseEventHandler<HTMLElement>) => {
|
|
300
|
+
if (!canCreateNewItem) return undefined;
|
|
301
|
+
const clickHandler = (e: React.MouseEvent<HTMLElement>) => {
|
|
302
|
+
createNewItem(e, label);
|
|
303
|
+
handleClick(e);
|
|
304
|
+
};
|
|
305
|
+
return (
|
|
306
|
+
<MenuItem
|
|
307
|
+
id={"new-tag"}
|
|
308
|
+
icon="item-add-artefact"
|
|
309
|
+
active={active}
|
|
310
|
+
key={label}
|
|
311
|
+
onClick={clickHandler}
|
|
312
|
+
text={<OverflowText>{`${newItemCreationText} '${label}'`}</OverflowText>}
|
|
313
|
+
/>
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const clearButton =
|
|
318
|
+
selectedItems.length > 0 ? (
|
|
319
|
+
<Button icon="operation-clear" data-test-id="clear-all-items" minimal={true} onClick={handleClear} />
|
|
320
|
+
) : undefined;
|
|
321
|
+
|
|
322
|
+
return (
|
|
323
|
+
<BlueprintMultiSelect
|
|
324
|
+
{...otherProps}
|
|
325
|
+
query={query}
|
|
326
|
+
onQueryChange={onQueryChange}
|
|
327
|
+
items={filteredItemList}
|
|
328
|
+
onItemSelect={onItemSelect}
|
|
329
|
+
itemRenderer={onItemRenderer}
|
|
330
|
+
itemsEqual={(a: T, b: T) => a[labelProp as keyof T] === b[labelProp as keyof T]}
|
|
331
|
+
selectedItems={selectedItems}
|
|
332
|
+
noResults={<MenuItem disabled={true} text={noResultText} />}
|
|
333
|
+
tagRenderer={(tag) => tag[labelProp as keyof typeof tag]}
|
|
334
|
+
createNewItemRenderer={newItemRenderer}
|
|
335
|
+
onActiveItemChange={(activeItem) => setFocusedItem(activeItem)}
|
|
336
|
+
fill={fullWidth}
|
|
337
|
+
createNewItemFromQuery={(query) =>
|
|
338
|
+
({
|
|
339
|
+
[labelProp]: removeExtraSpaces(query),
|
|
340
|
+
[equalityProp]: removeExtraSpaces(query),
|
|
341
|
+
} as any)
|
|
342
|
+
}
|
|
343
|
+
tagInputProps={{
|
|
344
|
+
inputProps: {
|
|
345
|
+
id: "item",
|
|
346
|
+
autoComplete: "off",
|
|
347
|
+
},
|
|
348
|
+
inputRef: tagInputRef,
|
|
349
|
+
intent,
|
|
350
|
+
addOnBlur: true,
|
|
351
|
+
onKeyDown: handleOnKeyDown,
|
|
352
|
+
onKeyUp: handleOnKeyUp,
|
|
353
|
+
onRemove: removeTagFromSelectionViaIndex,
|
|
354
|
+
rightElement: disabled ? undefined : clearButton,
|
|
355
|
+
tagProps: { minimal: true },
|
|
356
|
+
disabled,
|
|
357
|
+
...tagInputProps,
|
|
358
|
+
}}
|
|
359
|
+
popoverProps={{
|
|
360
|
+
minimal: true,
|
|
361
|
+
position: "bottom-left",
|
|
362
|
+
hasBackdrop: true,
|
|
363
|
+
...popoverProps,
|
|
364
|
+
defaultIsOpen: true,
|
|
365
|
+
}}
|
|
366
|
+
/>
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default MultiSelect;
|