@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.
- package/CHANGELOG.md +32 -3
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +24 -20
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +59 -50
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
- package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
- package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js +9 -6
- package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
- package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js +33 -0
- package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
- package/dist/cjs/components/CodeAutocompleteField/index.js +14 -0
- package/dist/cjs/components/CodeAutocompleteField/index.js.map +1 -0
- package/dist/cjs/components/Depiction/Depiction.js +13 -13
- package/dist/cjs/components/Depiction/Depiction.js.map +1 -1
- package/dist/cjs/components/Dialog/SimpleDialog.js +5 -5
- package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/cjs/components/Icon/IconButton.js +9 -3
- package/dist/cjs/components/Icon/IconButton.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +2 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +45 -17
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js +33 -0
- package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
- package/dist/cjs/components/OverviewItem/OverviewItem.js +8 -10
- package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/cjs/components/PropertyValuePair/PropertyName.js +4 -3
- package/dist/cjs/components/PropertyValuePair/PropertyName.js.map +1 -1
- package/dist/cjs/components/Select/Select.js +18 -3
- package/dist/cjs/components/Select/Select.js.map +1 -1
- package/dist/cjs/components/SuggestField/SuggestField.js +39 -0
- package/dist/cjs/components/SuggestField/SuggestField.js.map +1 -0
- package/dist/cjs/components/SuggestField/index.js +19 -0
- package/dist/cjs/components/SuggestField/index.js.map +1 -0
- package/dist/cjs/components/index.js +3 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +54 -41
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +23 -18
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +68 -59
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
- package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
- package/dist/esm/components/Breadcrumb/BreadcrumbItem.js +9 -6
- package/dist/esm/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
- package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js +37 -0
- package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
- package/dist/esm/components/CodeAutocompleteField/index.js +2 -0
- package/dist/esm/components/CodeAutocompleteField/index.js.map +1 -0
- package/dist/esm/components/Depiction/Depiction.js +12 -12
- package/dist/esm/components/Depiction/Depiction.js.map +1 -1
- package/dist/esm/components/Dialog/SimpleDialog.js +7 -7
- package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/esm/components/Icon/IconButton.js +10 -4
- package/dist/esm/components/Icon/IconButton.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +2 -0
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +52 -22
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/MultiSuggestField/MultiSuggestField.js +37 -0
- package/dist/esm/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
- package/dist/esm/components/OverviewItem/OverviewItem.js +8 -10
- package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/esm/components/PropertyValuePair/PropertyName.js +4 -3
- package/dist/esm/components/PropertyValuePair/PropertyName.js.map +1 -1
- package/dist/esm/components/Select/Select.js +19 -4
- package/dist/esm/components/Select/Select.js.map +1 -1
- package/dist/esm/components/SuggestField/SuggestField.js +43 -0
- package/dist/esm/components/SuggestField/SuggestField.js.map +1 -0
- package/dist/esm/components/SuggestField/index.js +6 -0
- package/dist/esm/components/SuggestField/index.js.map +1 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js +51 -39
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/types/components/AutoSuggestion/AutoSuggestion.d.ts +35 -4
- package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +23 -6
- package/dist/types/components/AutocompleteField/autoCompleteFieldUtils.d.ts +3 -3
- package/dist/types/components/AutocompleteField/index.d.ts +1 -1
- package/dist/types/components/AutocompleteField/interfaces.d.ts +1 -1
- package/dist/types/components/CodeAutocompleteField/CodeAutocompleteField.d.ts +10 -0
- package/dist/types/components/CodeAutocompleteField/index.d.ts +1 -0
- package/dist/types/components/Dialog/SimpleDialog.d.ts +2 -2
- package/dist/types/components/Icon/IconButton.d.ts +2 -2
- package/dist/types/components/Icon/canonicalIconNames.d.ts +1 -1
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +20 -2
- package/dist/types/components/MultiSuggestField/MultiSuggestField.d.ts +10 -0
- package/dist/types/components/PropertyValuePair/PropertyName.d.ts +5 -1
- package/dist/types/components/Select/Select.d.ts +28 -9
- package/dist/types/components/SuggestField/SuggestField.d.ts +16 -0
- package/dist/types/components/SuggestField/index.d.ts +5 -0
- package/dist/types/components/index.d.ts +3 -0
- package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +7 -7
- package/dist/types/index.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/Application/_header.scss +49 -58
- package/src/components/AutoSuggestion/AutoSuggestion.stories.tsx +14 -0
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +280 -221
- package/src/components/AutocompleteField/AutoCompleteField.stories.tsx +14 -0
- package/src/components/AutocompleteField/AutoCompleteField.tsx +157 -121
- package/src/components/AutocompleteField/autoCompleteFieldUtils.tsx +10 -16
- package/src/components/AutocompleteField/interfaces.ts +5 -6
- package/src/components/Breadcrumb/BreadcrumbItem.tsx +19 -18
- package/src/components/Breadcrumb/breadcrumb.scss +18 -16
- package/src/components/Breadcrumb/stories/BreadcrumbList.stories.tsx +18 -15
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +89 -0
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx +22 -0
- package/src/components/CodeAutocompleteField/index.ts +1 -0
- package/src/components/ContextOverlay/contextoverlay.scss +10 -2
- package/src/components/Depiction/Depiction.tsx +57 -55
- package/src/components/Dialog/SimpleDialog.tsx +20 -33
- package/src/components/Icon/IconButton.tsx +25 -11
- package/src/components/Icon/canonicalIconNames.tsx +4 -0
- package/src/components/MultiSelect/MultiSelect.stories.tsx +9 -47
- package/src/components/MultiSelect/MultiSelect.tsx +110 -66
- package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +58 -0
- package/src/components/MultiSuggestField/MultiSuggestField.tsx +22 -0
- package/src/components/Notification/notification.scss +20 -17
- package/src/components/OverviewItem/OverviewItem.tsx +11 -20
- package/src/components/PropertyValuePair/PropertyName.tsx +17 -4
- package/src/components/PropertyValuePair/propertyvalue.scss +17 -1
- package/src/components/Select/Select.stories.tsx +49 -20
- package/src/components/Select/Select.tsx +96 -18
- package/src/components/Select/_select.scss +13 -1
- package/src/components/SuggestField/SuggestField.stories.tsx +99 -0
- package/src/components/SuggestField/SuggestField.tsx +28 -0
- package/src/components/SuggestField/index.ts +5 -0
- package/src/components/TagInput/taginput.scss +14 -0
- package/src/components/index.scss +1 -1
- package/src/components/index.ts +3 -0
- package/src/extensions/react-flow/nodes/NodeContent.tsx +105 -87
- package/src/index.ts +2 -5
- package/src/components/AutoSuggestion/stories/AutoSuggestion.stories.tsx +0 -83
- package/src/components/AutocompleteField/stories/AutoCompleteField.stories.tsx +0 -86
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Meta } from "@storybook/react";
|
|
2
|
+
|
|
3
|
+
import { AutoCompleteField } from "./../../../index";
|
|
4
|
+
export { Default } from "../SuggestField/SuggestField.stories";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Forms/AutoCompleteField",
|
|
8
|
+
component: AutoCompleteField,
|
|
9
|
+
parameters: {
|
|
10
|
+
controls: {
|
|
11
|
+
exclude: /.*/g,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
} as Meta<typeof AutoCompleteField>;
|
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
import React, {useEffect,
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
2
|
import {
|
|
3
3
|
HTMLInputProps as BlueprintHTMLInputProps,
|
|
4
4
|
InputGroupProps2 as BlueprintInputGroupProps,
|
|
5
5
|
} from "@blueprintjs/core";
|
|
6
|
+
import { Suggest2 as BlueprintSuggest } from "@blueprintjs/select";
|
|
7
|
+
|
|
8
|
+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
6
9
|
import {
|
|
7
|
-
|
|
8
|
-
} from "@blueprintjs/select";
|
|
9
|
-
import {
|
|
10
|
+
ContextOverlayProps,
|
|
10
11
|
Highlighter,
|
|
11
12
|
IconButton,
|
|
12
13
|
Menu,
|
|
13
|
-
Notification,
|
|
14
14
|
MenuItem,
|
|
15
|
+
Notification,
|
|
15
16
|
OverflowText,
|
|
16
17
|
Spinner,
|
|
17
|
-
ContextOverlayProps,
|
|
18
18
|
} from "../../index";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
IRenderModifiers as IRenderModifiersOrig
|
|
22
|
-
} from "./interfaces";
|
|
23
|
-
import {CLASSPREFIX as eccgui} from "../../configuration/constants";
|
|
19
|
+
|
|
20
|
+
import { IElementWidth as IElementWidthOrig, IRenderModifiers as IRenderModifiersOrig } from "./interfaces";
|
|
24
21
|
|
|
25
22
|
// @deprecated import from `src/components/AutocompleteField/interfaces`
|
|
26
23
|
export type IElementWidth = IElementWidthOrig;
|
|
27
24
|
// @deprecated import from `src/components/AutocompleteField/interfaces`
|
|
28
25
|
export type IRenderModifiers = IRenderModifiersOrig;
|
|
29
26
|
|
|
30
|
-
type SearchFunction<T
|
|
31
|
-
type AsyncSearchFunction<T
|
|
27
|
+
type SearchFunction<T> = (value: string) => T[];
|
|
28
|
+
type AsyncSearchFunction<T> = (value: string) => Promise<T[]>;
|
|
32
29
|
|
|
33
30
|
/**
|
|
34
31
|
* Parameters for the auto-complete field parameterized by T and U.
|
|
35
32
|
* @param T is the input data structure/type of the items that can be selected.
|
|
36
33
|
* @param UPDATE_VALUE The value type that will be pushed into the onChange callback.
|
|
37
34
|
*/
|
|
38
|
-
export interface AutoCompleteFieldProps<T
|
|
35
|
+
export interface AutoCompleteFieldProps<T, UPDATE_VALUE> {
|
|
36
|
+
/**
|
|
37
|
+
* Additional class names.
|
|
38
|
+
*/
|
|
39
|
+
className?: string;
|
|
39
40
|
/**
|
|
40
41
|
* Fired when text is typed into the input field. Returns a list of items of type T.
|
|
41
42
|
*/
|
|
@@ -76,10 +77,10 @@ export interface AutoCompleteFieldProps<T extends any, UPDATE_VALUE extends any>
|
|
|
76
77
|
itemValueSelector(item: T): UPDATE_VALUE;
|
|
77
78
|
|
|
78
79
|
/** The string representation of the actual value, i.e. without meta data etc. This will be used to compare if values are equal. */
|
|
79
|
-
itemValueString(item: T): string
|
|
80
|
+
itemValueString(item: T): string;
|
|
80
81
|
|
|
81
82
|
/** The text that should be displayed when no search result has been found and no custom entry can be created. */
|
|
82
|
-
noResultText: string
|
|
83
|
+
noResultText: string;
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
86
|
* Props to spread to the underlying input field. This is BlueprintJs specific. To control this input, use
|
|
@@ -91,7 +92,7 @@ export interface AutoCompleteFieldProps<T extends any, UPDATE_VALUE extends any>
|
|
|
91
92
|
/**
|
|
92
93
|
* Optional props of the internally used `<ContextOverlay/>` element..
|
|
93
94
|
*/
|
|
94
|
-
contextOverlayProps?: Partial<Omit<ContextOverlayProps, "content" | "children"
|
|
95
|
+
contextOverlayProps?: Partial<Omit<ContextOverlayProps, "content" | "children">>;
|
|
95
96
|
|
|
96
97
|
/** Defines if a value can be reset, i.e. a reset icon is shown and the value is set to a specific value.
|
|
97
98
|
* When undefined, a value cannot be reset.
|
|
@@ -105,7 +106,7 @@ export interface AutoCompleteFieldProps<T extends any, UPDATE_VALUE extends any>
|
|
|
105
106
|
resetValue: UPDATE_VALUE;
|
|
106
107
|
|
|
107
108
|
/** The reset button text that is shown on hovering over the reset icon. */
|
|
108
|
-
resetButtonText: string
|
|
109
|
+
resetButtonText: string;
|
|
109
110
|
};
|
|
110
111
|
|
|
111
112
|
/** If enabled the auto completion component will auto focus. */
|
|
@@ -126,7 +127,7 @@ export interface AutoCompleteFieldProps<T extends any, UPDATE_VALUE extends any>
|
|
|
126
127
|
/** If the new item option will always be shown as the first entry in the suggestion list, else it will be the last entry.
|
|
127
128
|
* @default false
|
|
128
129
|
*/
|
|
129
|
-
showNewItemOptionFirst?: boolean
|
|
130
|
+
showNewItemOptionFirst?: boolean;
|
|
130
131
|
};
|
|
131
132
|
|
|
132
133
|
/** Dropdown is only rendered when the query has a value (input field is not empty). */
|
|
@@ -140,38 +141,47 @@ export interface AutoCompleteFieldProps<T extends any, UPDATE_VALUE extends any>
|
|
|
140
141
|
*
|
|
141
142
|
* @param selectedValue The currently selected value.
|
|
142
143
|
*/
|
|
143
|
-
resetQueryToValue?(selectedValue: T): string
|
|
144
|
+
resetQueryToValue?(selectedValue: T): string;
|
|
144
145
|
|
|
145
146
|
/** If an error occurs during the auto-completion request, the error details will be prefixed with this string. */
|
|
146
|
-
requestErrorPrefix?: string
|
|
147
|
+
requestErrorPrefix?: string;
|
|
147
148
|
|
|
148
149
|
/** Creates a backdrop when the popover is shown that captures outside clicks in order to close the popover.
|
|
149
150
|
* This is needed if other components on the same page are swallowing events, e.g. the react-flow canvas.
|
|
150
151
|
* hasBackDrop should then be set to true in these cases otherwise the popover won't close when clicking those other components.
|
|
151
152
|
**/
|
|
152
|
-
hasBackDrop?: boolean
|
|
153
|
+
hasBackDrop?: boolean;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Use the full available width of the parent container.
|
|
157
|
+
*/
|
|
158
|
+
fill?: boolean;
|
|
153
159
|
}
|
|
154
160
|
|
|
155
|
-
export type IAutoCompleteFieldProps<T
|
|
161
|
+
export type IAutoCompleteFieldProps<T, UPDATE_VALUE> = AutoCompleteFieldProps<T, UPDATE_VALUE>;
|
|
156
162
|
|
|
157
163
|
AutoCompleteField.defaultProps = {
|
|
158
164
|
autoFocus: false,
|
|
159
165
|
disabled: false,
|
|
166
|
+
onlyDropdownWithQuery: false, // FIXME: this should be `true` by default, otherwise similarity to `<Select />` is very close
|
|
167
|
+
fill: true,
|
|
168
|
+
requestErrorPrefix: "",
|
|
169
|
+
hasBackDrop: false,
|
|
160
170
|
};
|
|
161
171
|
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props: AutoCompleteFieldProps<T, UPDATE_VALUE>) {
|
|
172
|
+
/**
|
|
173
|
+
* **Element is deprecated.**
|
|
174
|
+
* Use `SuggestField` as replacement.
|
|
175
|
+
*
|
|
176
|
+
* @deprecated
|
|
177
|
+
*/
|
|
178
|
+
export function AutoCompleteField<T, UPDATE_VALUE>(props: AutoCompleteFieldProps<T, UPDATE_VALUE>) {
|
|
170
179
|
const {
|
|
180
|
+
className,
|
|
171
181
|
reset,
|
|
172
182
|
noResultText,
|
|
173
183
|
disabled,
|
|
174
|
-
onlyDropdownWithQuery
|
|
184
|
+
onlyDropdownWithQuery,
|
|
175
185
|
itemValueSelector,
|
|
176
186
|
itemRenderer,
|
|
177
187
|
onSearch,
|
|
@@ -182,8 +192,9 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
182
192
|
itemValueRenderer,
|
|
183
193
|
resetQueryToValue,
|
|
184
194
|
itemValueString,
|
|
185
|
-
requestErrorPrefix
|
|
186
|
-
hasBackDrop
|
|
195
|
+
requestErrorPrefix,
|
|
196
|
+
hasBackDrop,
|
|
197
|
+
fill,
|
|
187
198
|
...otherProps
|
|
188
199
|
} = props;
|
|
189
200
|
const [selectedItem, setSelectedItem] = useState<T | undefined>(initialValue);
|
|
@@ -194,29 +205,26 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
194
205
|
// If the input field has focus
|
|
195
206
|
const [inputHasFocus, setInputHasFocus] = useState<boolean>(false);
|
|
196
207
|
const [highlightingEnabled, setHighlightingEnabled] = useState<boolean>(true);
|
|
197
|
-
const [requestError, setRequestError] = useState<string | undefined>(undefined)
|
|
208
|
+
const [requestError, setRequestError] = useState<string | undefined>(undefined);
|
|
198
209
|
|
|
199
210
|
// The suggestions that match the user's input
|
|
200
211
|
const [filtered, setFiltered] = useState<T[]>([]);
|
|
201
212
|
|
|
202
|
-
const
|
|
203
|
-
const readOnly = !!otherProps.inputProps?.readOnly
|
|
213
|
+
const readOnly = !!otherProps.inputProps?.readOnly;
|
|
204
214
|
|
|
205
215
|
// Sets the query to the item value if it has a valid string value
|
|
206
216
|
const setQueryToSelectedValue = (item?: T) => {
|
|
207
217
|
if (item) {
|
|
208
218
|
// If new values can be created, always reset the query value to the actual value of the selected item.
|
|
209
219
|
// This e.g. prevents that the "create new" option will be shown, since an item with the same value already exists.
|
|
210
|
-
const defaultResetValue: string = createNewItem
|
|
211
|
-
itemValueString(item) as string
|
|
212
|
-
|
|
213
|
-
const resetVal = resetQueryToValue ? resetQueryToValue(item) : defaultResetValue
|
|
214
|
-
setQuery(resetVal)
|
|
220
|
+
const defaultResetValue: string = createNewItem
|
|
221
|
+
? (itemValueString(item) as string)
|
|
222
|
+
: itemValueRenderer(item);
|
|
223
|
+
const resetVal = resetQueryToValue ? resetQueryToValue(item) : defaultResetValue;
|
|
224
|
+
setQuery(resetVal);
|
|
215
225
|
}
|
|
216
226
|
};
|
|
217
227
|
|
|
218
|
-
const fieldRef = useRef(null)
|
|
219
|
-
|
|
220
228
|
// The key for the option elements
|
|
221
229
|
const itemKey = (item: T): string => {
|
|
222
230
|
return itemValueString(item);
|
|
@@ -224,10 +232,7 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
224
232
|
|
|
225
233
|
useEffect(() => {
|
|
226
234
|
setQueryToSelectedValue(selectedItem);
|
|
227
|
-
},
|
|
228
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
229
|
-
[selectedItem]
|
|
230
|
-
);
|
|
235
|
+
}, [selectedItem]);
|
|
231
236
|
|
|
232
237
|
useEffect(() => {
|
|
233
238
|
if (!disabled && !readOnly && inputHasFocus) {
|
|
@@ -241,12 +246,7 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
241
246
|
};
|
|
242
247
|
}
|
|
243
248
|
return;
|
|
244
|
-
},
|
|
245
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
246
|
-
[inputHasFocus, query]
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
const fieldWidthLimits = elementWidth(fieldRef);
|
|
249
|
+
}, [inputHasFocus, query]);
|
|
250
250
|
|
|
251
251
|
// We need to fire some actions when the auto-complete widget gets or loses focus
|
|
252
252
|
const handleOnFocusIn = () => {
|
|
@@ -263,7 +263,7 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
263
263
|
setQueryToSelectedValue(selectedItem);
|
|
264
264
|
// Reset option list when the popover closes, so next use there is not displayed a stale list
|
|
265
265
|
setFiltered([]);
|
|
266
|
-
}
|
|
266
|
+
};
|
|
267
267
|
|
|
268
268
|
// Triggered when an item from the selection list gets selected
|
|
269
269
|
const onSelectionChange = (value: any, e: any) => {
|
|
@@ -289,11 +289,14 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
289
289
|
// Fetches the results for the given query
|
|
290
290
|
const fetchQueryResults = async (input: string) => {
|
|
291
291
|
setListLoading(true);
|
|
292
|
-
setRequestError(undefined)
|
|
292
|
+
setRequestError(undefined);
|
|
293
293
|
try {
|
|
294
294
|
let result = await onSearch(input);
|
|
295
|
-
const onlySelectItemReturned =
|
|
296
|
-
|
|
295
|
+
const onlySelectItemReturned =
|
|
296
|
+
result.length <= 1 &&
|
|
297
|
+
selectedItem &&
|
|
298
|
+
input.length > 0 &&
|
|
299
|
+
(itemValueRenderer(selectedItem) === input || itemValueString(selectedItem) === input);
|
|
297
300
|
let enableHighlighting = true;
|
|
298
301
|
if (onlySelectItemReturned) {
|
|
299
302
|
// If the auto-completion only returns no suggestion or the selected item itself, query with empty string.
|
|
@@ -302,7 +305,7 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
302
305
|
enableHighlighting = false;
|
|
303
306
|
// Put selected item at the top if it is not in the result list
|
|
304
307
|
if (!!selectedItem && itemIndexOf(emptyStringResults, selectedItem) > -1) {
|
|
305
|
-
emptyStringResults.splice(itemIndexOf(emptyStringResults, selectedItem), 1)
|
|
308
|
+
emptyStringResults.splice(itemIndexOf(emptyStringResults, selectedItem), 1);
|
|
306
309
|
result = [selectedItem, ...emptyStringResults];
|
|
307
310
|
} else {
|
|
308
311
|
result = emptyStringResults;
|
|
@@ -311,24 +314,26 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
311
314
|
setHighlightingEnabled(enableHighlighting);
|
|
312
315
|
setFiltered(result);
|
|
313
316
|
} catch (e: any) {
|
|
314
|
-
const details = e?.message ?? ""
|
|
315
|
-
setRequestError(requestErrorPrefix + details)
|
|
317
|
+
const details = e?.message ?? "";
|
|
318
|
+
setRequestError(requestErrorPrefix + details);
|
|
316
319
|
} finally {
|
|
317
320
|
setListLoading(false);
|
|
318
321
|
}
|
|
319
322
|
};
|
|
320
323
|
|
|
321
324
|
// Renders the item in the selection list
|
|
322
|
-
const optionRenderer = (
|
|
325
|
+
const optionRenderer = (
|
|
326
|
+
item: any,
|
|
327
|
+
{ handleClick, modifiers, query }: { handleClick: any; modifiers: any; query: any }
|
|
328
|
+
) => {
|
|
323
329
|
if (!modifiers.matchesPredicate) {
|
|
324
330
|
return null;
|
|
325
331
|
}
|
|
326
332
|
const relevantModifiers: IRenderModifiers = {
|
|
327
333
|
active: modifiers.active,
|
|
328
334
|
disabled: modifiers.disabled,
|
|
329
|
-
styleWidth: fieldWidthLimits,
|
|
330
335
|
highlightingEnabled: highlightingEnabled,
|
|
331
|
-
}
|
|
336
|
+
};
|
|
332
337
|
const renderedItem = itemRenderer(item, query, relevantModifiers, handleClick);
|
|
333
338
|
if (typeof renderedItem === "string") {
|
|
334
339
|
return (
|
|
@@ -338,8 +343,12 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
338
343
|
key={itemKey(item)}
|
|
339
344
|
onClick={handleClick}
|
|
340
345
|
text={
|
|
341
|
-
<OverflowText
|
|
342
|
-
{!highlightingEnabled ?
|
|
346
|
+
<OverflowText>
|
|
347
|
+
{!highlightingEnabled ? (
|
|
348
|
+
renderedItem
|
|
349
|
+
) : (
|
|
350
|
+
<Highlighter label={renderedItem} searchValue={query} />
|
|
351
|
+
)}
|
|
343
352
|
</OverflowText>
|
|
344
353
|
}
|
|
345
354
|
/>
|
|
@@ -355,12 +364,11 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
355
364
|
setQuery("");
|
|
356
365
|
};
|
|
357
366
|
const requestErrorRenderer = () => {
|
|
358
|
-
return <Notification danger={true} message={requestError}
|
|
359
|
-
}
|
|
367
|
+
return <Notification danger={true} message={requestError} />;
|
|
368
|
+
};
|
|
360
369
|
// Optional clear button to reset the selected value
|
|
361
|
-
const clearButton =
|
|
362
|
-
selectedItem != null &&
|
|
363
|
-
reset.resettableValue(selectedItem) ? (
|
|
370
|
+
const clearButton =
|
|
371
|
+
!readOnly && !disabled && reset && selectedItem != null && reset.resettableValue(selectedItem) ? (
|
|
364
372
|
<IconButton
|
|
365
373
|
data-test-id={
|
|
366
374
|
(otherProps.inputProps?.id ? `${otherProps.inputProps.id}-` : "") + "auto-complete-clear-btn"
|
|
@@ -372,72 +380,100 @@ export function AutoCompleteField<T extends any, UPDATE_VALUE extends any>(props
|
|
|
372
380
|
) : undefined;
|
|
373
381
|
// Additional properties for the input element of the auto-completion widget
|
|
374
382
|
const updatedInputProps: BlueprintInputGroupProps & BlueprintHTMLInputProps = {
|
|
375
|
-
rightElement:
|
|
383
|
+
rightElement:
|
|
384
|
+
clearButton || onlyDropdownWithQuery === false ? (
|
|
385
|
+
<>
|
|
386
|
+
{clearButton}
|
|
387
|
+
{onlyDropdownWithQuery === false && (
|
|
388
|
+
<IconButton
|
|
389
|
+
name={"toggler-caretdown"}
|
|
390
|
+
onClick={(e) => {
|
|
391
|
+
const target = e.currentTarget
|
|
392
|
+
.closest(`.${eccgui}-autocompletefield__input`)
|
|
393
|
+
?.querySelector("input");
|
|
394
|
+
(target as HTMLElement).focus();
|
|
395
|
+
e.stopPropagation();
|
|
396
|
+
}}
|
|
397
|
+
/>
|
|
398
|
+
)}
|
|
399
|
+
</>
|
|
400
|
+
) : undefined,
|
|
376
401
|
autoFocus: autoFocus,
|
|
377
402
|
onBlur: handleOnFocusOut,
|
|
378
403
|
onFocus: handleOnFocusIn,
|
|
379
404
|
...otherProps.inputProps,
|
|
380
|
-
title:
|
|
405
|
+
title:
|
|
406
|
+
selectedItem !== undefined && (readOnly || disabled)
|
|
407
|
+
? itemValueString(selectedItem)
|
|
408
|
+
: otherProps.inputProps?.title,
|
|
381
409
|
};
|
|
382
|
-
const preventOverlayOnReadonly = readOnly ? { isOpen: false } : {}
|
|
410
|
+
const preventOverlayOnReadonly = readOnly ? { isOpen: false } : {};
|
|
383
411
|
const updatedContextOverlayProps: Partial<Omit<ContextOverlayProps, "content" | "children">> = {
|
|
384
412
|
minimal: true,
|
|
385
|
-
|
|
413
|
+
matchTargetWidth: fill,
|
|
386
414
|
popoverClassName: `${eccgui}-autocompletefield__options`,
|
|
387
|
-
rootBoundary: "viewport",
|
|
388
415
|
onClosed: onPopoverClose,
|
|
389
416
|
...otherProps.contextOverlayProps,
|
|
390
417
|
...preventOverlayOnReadonly,
|
|
391
418
|
// Needed to capture clicks outside of the popover, e.g. in order to close it.
|
|
392
|
-
hasBackdrop: hasBackDrop
|
|
393
|
-
}
|
|
394
|
-
if(selectedItem !== undefined) {
|
|
419
|
+
hasBackdrop: hasBackDrop,
|
|
420
|
+
};
|
|
421
|
+
if (selectedItem !== undefined) {
|
|
395
422
|
// Makes sure that even when an empty string is selected, the placeholder won't be shown.
|
|
396
|
-
updatedInputProps.placeholder = ""
|
|
423
|
+
updatedInputProps.placeholder = "";
|
|
397
424
|
}
|
|
398
425
|
// For some reason Typescript is not able to infer the union type from the ternary expression
|
|
399
|
-
const createNewItemPosition: "first" | "last" = createNewItem?.showNewItemOptionFirst ? "first" : "last"
|
|
400
|
-
const createNewItemProps = createNewItem
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
426
|
+
const createNewItemPosition: "first" | "last" = createNewItem?.showNewItemOptionFirst ? "first" : "last";
|
|
427
|
+
const createNewItemProps = createNewItem
|
|
428
|
+
? {
|
|
429
|
+
createNewItemFromQuery: createNewItem.itemFromQuery,
|
|
430
|
+
createNewItemRenderer: (
|
|
431
|
+
query: string,
|
|
432
|
+
active: boolean,
|
|
433
|
+
handleClick: React.MouseEventHandler<HTMLElement>
|
|
434
|
+
) => {
|
|
435
|
+
if (selectedItem && query === itemValueString(selectedItem)) {
|
|
436
|
+
// Never show create new item option if the same item is already selected
|
|
437
|
+
return undefined;
|
|
438
|
+
} else {
|
|
439
|
+
return createNewItem!.itemRenderer(query, { active, highlightingEnabled: false }, handleClick);
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
createNewItemPosition,
|
|
443
|
+
}
|
|
444
|
+
: {};
|
|
412
445
|
return (
|
|
413
|
-
<
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
446
|
+
<BlueprintSuggest<T>
|
|
447
|
+
className={`${eccgui}-autocompletefield__input` + (className ? ` ${className}` : "")}
|
|
448
|
+
disabled={disabled}
|
|
449
|
+
// Need to display error messages in list
|
|
450
|
+
items={requestError ? [requestError as unknown as T] : filtered}
|
|
451
|
+
initialContent={onlyDropdownWithQuery ? null : undefined}
|
|
452
|
+
inputValueRenderer={selectedItem !== undefined ? itemValueRenderer : () => ""}
|
|
453
|
+
itemRenderer={requestError ? requestErrorRenderer : optionRenderer}
|
|
454
|
+
itemsEqual={areEqualItems}
|
|
455
|
+
noResults={<MenuItem disabled={true} text={noResultText} />}
|
|
456
|
+
onItemSelect={onSelectionChange}
|
|
457
|
+
onQueryChange={(q) => setQuery(q)}
|
|
458
|
+
closeOnSelect={true}
|
|
459
|
+
query={query}
|
|
460
|
+
// This leads to odd compile errors without "as any"
|
|
461
|
+
popoverProps={updatedContextOverlayProps as any}
|
|
462
|
+
selectedItem={selectedItem}
|
|
463
|
+
fill={fill}
|
|
464
|
+
{...createNewItemProps}
|
|
465
|
+
// This leads to odd compile errors without "as any"
|
|
466
|
+
inputProps={updatedInputProps as any}
|
|
467
|
+
itemListRenderer={
|
|
468
|
+
listLoading
|
|
469
|
+
? () => (
|
|
470
|
+
<Menu>
|
|
471
|
+
<MenuItem disabled={true} text={<Spinner position={"inline"} />} />
|
|
472
|
+
</Menu>
|
|
473
|
+
)
|
|
474
|
+
: undefined
|
|
475
|
+
}
|
|
476
|
+
/>
|
|
441
477
|
);
|
|
442
478
|
}
|
|
443
479
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
|
|
3
|
+
import { ValidIconName } from "../Icon/canonicalIconNames";
|
|
4
4
|
import MenuItem from "../Menu/MenuItem";
|
|
5
|
+
import OverflowText from "../Typography/OverflowText";
|
|
6
|
+
|
|
5
7
|
import { TestIconProps } from "./../Icon/TestIcon";
|
|
6
|
-
import {
|
|
8
|
+
import { IRenderModifiers } from "./interfaces";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Returns a function to be used in an AutoComplete widget for rendering custom elements based on the query string.
|
|
@@ -12,27 +14,19 @@ import { ValidIconName } from "../Icon/canonicalIconNames";
|
|
|
12
14
|
* @param iconName Optional icon to show left to the text.
|
|
13
15
|
*/
|
|
14
16
|
export const createNewItemRendererFactory = (
|
|
15
|
-
itemTextRenderer: (query: string
|
|
17
|
+
itemTextRenderer: (query: string) => string | JSX.Element,
|
|
16
18
|
iconName?: ValidIconName | React.ReactElement<TestIconProps>
|
|
17
19
|
) => {
|
|
18
20
|
// Return custom render function
|
|
19
21
|
return (query: string, modifiers: IRenderModifiers, handleClick: React.MouseEventHandler<HTMLElement>) => {
|
|
20
|
-
let textElement = itemTextRenderer(query
|
|
22
|
+
let textElement = itemTextRenderer(query);
|
|
21
23
|
if (typeof textElement === "string") {
|
|
22
24
|
textElement = (
|
|
23
|
-
<OverflowText
|
|
24
|
-
|
|
25
|
-
</OverflowText>
|
|
26
|
-
)
|
|
25
|
+
<OverflowText>{textElement.trim() !== "" ? textElement : `Create option '${query}'`}</OverflowText>
|
|
26
|
+
);
|
|
27
27
|
}
|
|
28
28
|
return (
|
|
29
|
-
<MenuItem
|
|
30
|
-
icon={iconName}
|
|
31
|
-
active={modifiers.active}
|
|
32
|
-
key={query}
|
|
33
|
-
onClick={handleClick}
|
|
34
|
-
text={textElement}
|
|
35
|
-
/>
|
|
29
|
+
<MenuItem icon={iconName} active={modifiers.active} key={query} onClick={handleClick} text={textElement} />
|
|
36
30
|
);
|
|
37
31
|
};
|
|
38
32
|
};
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
export interface IRenderModifiers {
|
|
2
|
-
active: boolean
|
|
3
|
-
disabled?: boolean
|
|
2
|
+
active: boolean;
|
|
3
|
+
disabled?: boolean;
|
|
4
4
|
// The width styles that should be given to the rendered option items
|
|
5
|
-
styleWidth
|
|
6
|
-
highlightingEnabled: boolean
|
|
5
|
+
styleWidth?: IElementWidth;
|
|
6
|
+
highlightingEnabled: boolean;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/** Style object to be used in menu option items. */
|
|
10
10
|
export interface IElementWidth {
|
|
11
11
|
minWidth: string;
|
|
12
|
-
|
|
13
|
-
maxWidth: string
|
|
12
|
+
maxWidth: string;
|
|
14
13
|
}
|
|
@@ -4,17 +4,15 @@ import {
|
|
|
4
4
|
Breadcrumb as BlueprintBreadcrumbItem,
|
|
5
5
|
BreadcrumbProps as BlueprintBreadcrumbItemProps,
|
|
6
6
|
} from "@blueprintjs/core";
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import { openInNewTab } from "../../common/utils/openInNewTab";
|
|
9
|
+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
9
10
|
|
|
10
11
|
// FIXME: enforce href and remove onClick later
|
|
11
12
|
export type BreadcrumbItemProps = Omit<
|
|
12
13
|
BlueprintBreadcrumbItemProps,
|
|
13
14
|
// we remove some properties that are currently not necessary, required usage should be discussed
|
|
14
|
-
"icon" |
|
|
15
|
-
"iconTitle" |
|
|
16
|
-
"intent" |
|
|
17
|
-
"target"
|
|
15
|
+
"icon" | "iconTitle" | "intent" | "target"
|
|
18
16
|
>;
|
|
19
17
|
|
|
20
18
|
/**
|
|
@@ -28,7 +26,6 @@ export const BreadcrumbItem = ({
|
|
|
28
26
|
//itemDivider='',
|
|
29
27
|
...otherBlueprintBreadcrumbProps
|
|
30
28
|
}: BreadcrumbItemProps) => {
|
|
31
|
-
|
|
32
29
|
/*
|
|
33
30
|
FIXME: adding `data-divider` does not work this way because BlueprintJS
|
|
34
31
|
breadcrumb component does not support (and forward) it on HTML element
|
|
@@ -37,19 +34,23 @@ export const BreadcrumbItem = ({
|
|
|
37
34
|
with slash char.
|
|
38
35
|
*/
|
|
39
36
|
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const actionIsSet = !!onClick || !!href;
|
|
38
|
+
const allowActions =
|
|
39
|
+
!otherBlueprintBreadcrumbProps.current && !otherBlueprintBreadcrumbProps.disabled && actionIsSet;
|
|
40
|
+
const actions = allowActions
|
|
41
|
+
? {
|
|
42
|
+
href,
|
|
43
|
+
onClick: (e: React.MouseEvent<HTMLAnchorElement>) => openInNewTab(e, onClick, href),
|
|
44
|
+
}
|
|
45
|
+
: {};
|
|
45
46
|
return (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
<BlueprintBreadcrumbItem
|
|
48
|
+
{...otherBlueprintBreadcrumbProps}
|
|
49
|
+
{...actions}
|
|
50
|
+
className={`${eccgui}-breadcrumb__item ` + className}
|
|
51
|
+
/* data-divider={itemDivider ? itemDivider : ''} */
|
|
52
|
+
/>
|
|
52
53
|
);
|
|
53
|
-
}
|
|
54
|
+
};
|
|
54
55
|
|
|
55
56
|
export default BreadcrumbItem;
|