@eccenca/gui-elements 23.2.0-rc.0 → 23.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +24 -20
  3. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  4. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +59 -50
  5. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  6. package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
  7. package/dist/cjs/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
  8. package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js +9 -6
  9. package/dist/cjs/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
  10. package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js +33 -0
  11. package/dist/cjs/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
  12. package/dist/cjs/components/CodeAutocompleteField/index.js +14 -0
  13. package/dist/cjs/components/CodeAutocompleteField/index.js.map +1 -0
  14. package/dist/cjs/components/Depiction/Depiction.js +13 -13
  15. package/dist/cjs/components/Depiction/Depiction.js.map +1 -1
  16. package/dist/cjs/components/Dialog/SimpleDialog.js +5 -5
  17. package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
  18. package/dist/cjs/components/Icon/IconButton.js +9 -3
  19. package/dist/cjs/components/Icon/IconButton.js.map +1 -1
  20. package/dist/cjs/components/Icon/canonicalIconNames.js +2 -0
  21. package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
  22. package/dist/cjs/components/MultiSelect/MultiSelect.js +45 -17
  23. package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
  24. package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js +33 -0
  25. package/dist/cjs/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
  26. package/dist/cjs/components/OverviewItem/OverviewItem.js +8 -10
  27. package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
  28. package/dist/cjs/components/PropertyValuePair/PropertyName.js +4 -3
  29. package/dist/cjs/components/PropertyValuePair/PropertyName.js.map +1 -1
  30. package/dist/cjs/components/Select/Select.js +18 -3
  31. package/dist/cjs/components/Select/Select.js.map +1 -1
  32. package/dist/cjs/components/SuggestField/SuggestField.js +39 -0
  33. package/dist/cjs/components/SuggestField/SuggestField.js.map +1 -0
  34. package/dist/cjs/components/SuggestField/index.js +19 -0
  35. package/dist/cjs/components/SuggestField/index.js.map +1 -0
  36. package/dist/cjs/components/index.js +3 -0
  37. package/dist/cjs/components/index.js.map +1 -1
  38. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +54 -41
  39. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  40. package/dist/cjs/index.js +1 -0
  41. package/dist/cjs/index.js.map +1 -1
  42. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +23 -18
  43. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  44. package/dist/esm/components/AutocompleteField/AutoCompleteField.js +68 -59
  45. package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  46. package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js +3 -3
  47. package/dist/esm/components/AutocompleteField/autoCompleteFieldUtils.js.map +1 -1
  48. package/dist/esm/components/Breadcrumb/BreadcrumbItem.js +9 -6
  49. package/dist/esm/components/Breadcrumb/BreadcrumbItem.js.map +1 -1
  50. package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js +37 -0
  51. package/dist/esm/components/CodeAutocompleteField/CodeAutocompleteField.js.map +1 -0
  52. package/dist/esm/components/CodeAutocompleteField/index.js +2 -0
  53. package/dist/esm/components/CodeAutocompleteField/index.js.map +1 -0
  54. package/dist/esm/components/Depiction/Depiction.js +12 -12
  55. package/dist/esm/components/Depiction/Depiction.js.map +1 -1
  56. package/dist/esm/components/Dialog/SimpleDialog.js +7 -7
  57. package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
  58. package/dist/esm/components/Icon/IconButton.js +10 -4
  59. package/dist/esm/components/Icon/IconButton.js.map +1 -1
  60. package/dist/esm/components/Icon/canonicalIconNames.js +2 -0
  61. package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
  62. package/dist/esm/components/MultiSelect/MultiSelect.js +52 -22
  63. package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
  64. package/dist/esm/components/MultiSuggestField/MultiSuggestField.js +37 -0
  65. package/dist/esm/components/MultiSuggestField/MultiSuggestField.js.map +1 -0
  66. package/dist/esm/components/OverviewItem/OverviewItem.js +8 -10
  67. package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
  68. package/dist/esm/components/PropertyValuePair/PropertyName.js +4 -3
  69. package/dist/esm/components/PropertyValuePair/PropertyName.js.map +1 -1
  70. package/dist/esm/components/Select/Select.js +19 -4
  71. package/dist/esm/components/Select/Select.js.map +1 -1
  72. package/dist/esm/components/SuggestField/SuggestField.js +43 -0
  73. package/dist/esm/components/SuggestField/SuggestField.js.map +1 -0
  74. package/dist/esm/components/SuggestField/index.js +6 -0
  75. package/dist/esm/components/SuggestField/index.js.map +1 -0
  76. package/dist/esm/components/index.js +3 -0
  77. package/dist/esm/components/index.js.map +1 -1
  78. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +51 -39
  79. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  80. package/dist/esm/index.js +2 -1
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/types/components/AutoSuggestion/AutoSuggestion.d.ts +35 -4
  83. package/dist/types/components/AutocompleteField/AutoCompleteField.d.ts +23 -6
  84. package/dist/types/components/AutocompleteField/autoCompleteFieldUtils.d.ts +3 -3
  85. package/dist/types/components/AutocompleteField/index.d.ts +1 -1
  86. package/dist/types/components/AutocompleteField/interfaces.d.ts +1 -1
  87. package/dist/types/components/CodeAutocompleteField/CodeAutocompleteField.d.ts +10 -0
  88. package/dist/types/components/CodeAutocompleteField/index.d.ts +1 -0
  89. package/dist/types/components/Dialog/SimpleDialog.d.ts +2 -2
  90. package/dist/types/components/Icon/IconButton.d.ts +2 -2
  91. package/dist/types/components/Icon/canonicalIconNames.d.ts +1 -1
  92. package/dist/types/components/MultiSelect/MultiSelect.d.ts +20 -2
  93. package/dist/types/components/MultiSuggestField/MultiSuggestField.d.ts +10 -0
  94. package/dist/types/components/PropertyValuePair/PropertyName.d.ts +5 -1
  95. package/dist/types/components/Select/Select.d.ts +28 -9
  96. package/dist/types/components/SuggestField/SuggestField.d.ts +16 -0
  97. package/dist/types/components/SuggestField/index.d.ts +5 -0
  98. package/dist/types/components/index.d.ts +3 -0
  99. package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +7 -7
  100. package/dist/types/index.d.ts +2 -1
  101. package/package.json +1 -1
  102. package/src/components/Application/_header.scss +49 -58
  103. package/src/components/AutoSuggestion/AutoSuggestion.stories.tsx +14 -0
  104. package/src/components/AutoSuggestion/AutoSuggestion.tsx +280 -221
  105. package/src/components/AutocompleteField/AutoCompleteField.stories.tsx +14 -0
  106. package/src/components/AutocompleteField/AutoCompleteField.tsx +157 -121
  107. package/src/components/AutocompleteField/autoCompleteFieldUtils.tsx +10 -16
  108. package/src/components/AutocompleteField/interfaces.ts +5 -6
  109. package/src/components/Breadcrumb/BreadcrumbItem.tsx +19 -18
  110. package/src/components/Breadcrumb/breadcrumb.scss +18 -16
  111. package/src/components/Breadcrumb/stories/BreadcrumbList.stories.tsx +18 -15
  112. package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +89 -0
  113. package/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx +22 -0
  114. package/src/components/CodeAutocompleteField/index.ts +1 -0
  115. package/src/components/ContextOverlay/contextoverlay.scss +10 -2
  116. package/src/components/Depiction/Depiction.tsx +57 -55
  117. package/src/components/Dialog/SimpleDialog.tsx +20 -33
  118. package/src/components/Icon/IconButton.tsx +25 -11
  119. package/src/components/Icon/canonicalIconNames.tsx +4 -0
  120. package/src/components/MultiSelect/MultiSelect.stories.tsx +9 -47
  121. package/src/components/MultiSelect/MultiSelect.tsx +110 -66
  122. package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +58 -0
  123. package/src/components/MultiSuggestField/MultiSuggestField.tsx +22 -0
  124. package/src/components/Notification/notification.scss +20 -17
  125. package/src/components/OverviewItem/OverviewItem.tsx +11 -20
  126. package/src/components/PropertyValuePair/PropertyName.tsx +17 -4
  127. package/src/components/PropertyValuePair/propertyvalue.scss +17 -1
  128. package/src/components/Select/Select.stories.tsx +49 -20
  129. package/src/components/Select/Select.tsx +96 -18
  130. package/src/components/Select/_select.scss +13 -1
  131. package/src/components/SuggestField/SuggestField.stories.tsx +99 -0
  132. package/src/components/SuggestField/SuggestField.tsx +28 -0
  133. package/src/components/SuggestField/index.ts +5 -0
  134. package/src/components/TagInput/taginput.scss +14 -0
  135. package/src/components/index.scss +1 -1
  136. package/src/components/index.ts +3 -0
  137. package/src/extensions/react-flow/nodes/NodeContent.tsx +105 -87
  138. package/src/index.ts +2 -5
  139. package/src/components/AutoSuggestion/stories/AutoSuggestion.stories.tsx +0 -83
  140. package/src/components/AutocompleteField/stories/AutoCompleteField.stories.tsx +0 -86
@@ -1,18 +1,14 @@
1
- import React, {useEffect, useMemo, useState} from "react";
2
- import CodeMirror, {Position} from "codemirror";
3
- import {FieldItem, IconButton, Spinner, Toolbar, ToolbarSection, ContextOverlay} from "./../../";
4
- import {Classes as BlueprintClassNames} from "@blueprintjs/core";
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import { Classes as BlueprintClassNames } from "@blueprintjs/core";
3
+ import CodeMirror, { Position } from "codemirror";
4
+ import { debounce } from "lodash";
5
+
5
6
  import { CLASSPREFIX as eccgui } from "../../configuration/constants";
6
7
 
8
+ import { ContextOverlay, FieldItem, IconButton, Spinner, Toolbar, ToolbarSection } from "./../../";
9
+ import { AutoSuggestionList } from "./AutoSuggestionList";
7
10
  //custom components
8
- import SingleLineCodeEditor, {IRange} from "./SingleLineCodeEditor";
9
- import {AutoSuggestionList} from "./AutoSuggestionList";
10
- import {debounce} from "lodash";
11
-
12
- /*
13
- FIXME: we should find a better name for this component.
14
- `AutoSuggestion` sounds not exact enough and difference to `AutoCompleteField` is not clear enough.
15
- */
11
+ import SingleLineCodeEditor, { IRange } from "./SingleLineCodeEditor";
16
12
 
17
13
  export enum OVERWRITTEN_KEYS {
18
14
  ArrowUp = "ArrowUp",
@@ -20,100 +16,118 @@ export enum OVERWRITTEN_KEYS {
20
16
  Enter = "Enter",
21
17
  Tab = "Tab",
22
18
  }
23
- export type OverwrittenKeyTypes = typeof OVERWRITTEN_KEYS[keyof typeof OVERWRITTEN_KEYS];
19
+ export type OverwrittenKeyTypes = (typeof OVERWRITTEN_KEYS)[keyof typeof OVERWRITTEN_KEYS];
24
20
 
25
21
  /** A single suggestion. */
26
22
  export interface ISuggestionBase {
27
23
  // The actual value
28
- value: string
24
+ value: string;
29
25
  // Optional human-readable label
30
- label?: string
26
+ label?: string;
31
27
  // Optional description of the value.
32
- description?: string
28
+ description?: string;
33
29
  }
34
30
 
35
31
  /** Same as ISuggestionBase, but with the query that was used to fetch this suggestion. */
36
32
  export interface ISuggestionWithReplacementInfo extends ISuggestionBase {
37
33
  // The query this result was filtered by
38
- query: string
34
+ query: string;
39
35
  // The offset of the original string that should be replaced
40
- from: number
36
+ from: number;
41
37
  // The length of the original string that should be replaced
42
- length: number
38
+ length: number;
43
39
  }
44
40
 
45
41
  /** The suggestions for a specific substring of the given input string. */
46
42
  export interface IReplacementResult {
47
43
  // The range of the input string that should be replaced
48
44
  replacementInterval: {
49
- from: number
50
- length: number
51
- }
45
+ from: number;
46
+ length: number;
47
+ };
52
48
  // The extracted query from the local value at the cursor position of the path that was used to retrieve the suggestions.
53
- extractedQuery: string
49
+ extractedQuery: string;
54
50
  // The suggested replacements for the substring that should be replaced.
55
- replacements: ISuggestionBase[]
51
+ replacements: ISuggestionBase[];
56
52
  }
57
53
 
58
54
  export interface IPartialAutoCompleteResult {
59
55
  // Repeats the input string from the corresponding request
60
- inputString: string
56
+ inputString: string;
61
57
  // Repeats the cursor position from the corresponding request
62
- cursorPosition: number
63
- replacementResults: IReplacementResult[]
58
+ cursorPosition: number;
59
+ replacementResults: IReplacementResult[];
64
60
  }
65
61
 
66
62
  /** Validation result */
67
63
  export interface IValidationResult {
68
64
  // If the input value is valid or not
69
- valid: boolean,
65
+ valid: boolean;
70
66
  parseError?: {
71
67
  // Detail error message
72
- message: string
68
+ message: string;
73
69
  // Start of the parse error in the input string
74
- start: number
70
+ start: number;
75
71
  // End of the parse error in the input string
76
- end: number
77
- }
72
+ end: number;
73
+ };
78
74
  }
79
75
 
80
76
  export interface AutoSuggestionProps {
81
- // Optional label to be shown for the input (above). This will create a FieldItem around the input.
82
- label?: string
83
- // The value the component is initialized with, do not use this to control value changes.
84
- initialValue: string
85
- // Callback on value change
86
- onChange: (currentValue: string) => any
87
- // Fetches the suggestions
88
- fetchSuggestions: (inputString: string, cursorPosition: number) => (IPartialAutoCompleteResult | undefined) | Promise<IPartialAutoCompleteResult | undefined>
89
- // Checks if the input is valid
90
- checkInput?: (inputString: string) => IValidationResult | Promise<IValidationResult | undefined>
91
- // Called with the input validation result
92
- onInputChecked?: (validInput: boolean) => any
93
- // Text that should be shown if the input validation failed.
94
- validationErrorText?: string
95
- // Text that should be shown when hovering over the clear icon
96
- clearIconText?: string
97
- // Called when focus status changes
98
- onFocusChange?: (hasFocus: boolean) => any
99
- // Optional ID to attach to the outer element
100
- id?: string
101
- // If the <Tab> key should be used for auto-completing items. Else it will have its default behavior.
102
- useTabForCompletions?: boolean
77
+ /** Additional class name.
78
+ */
79
+ className?: string;
80
+ /** Optional label to be shown for the input (above). This will create a FieldItem around the input.
81
+ */
82
+ label?: string;
83
+ /** The value the component is initialized with, do not use this to control value changes.
84
+ */
85
+ initialValue: string;
86
+ /** Callback on value change
87
+ */
88
+ onChange: (currentValue: string) => any;
89
+ /** Fetches the suggestions
90
+ */
91
+ fetchSuggestions: (
92
+ inputString: string,
93
+ cursorPosition: number
94
+ ) => (IPartialAutoCompleteResult | undefined) | Promise<IPartialAutoCompleteResult | undefined>;
95
+ /** Checks if the input is valid
96
+ */
97
+ checkInput?: (inputString: string) => IValidationResult | Promise<IValidationResult | undefined>;
98
+ /** Called with the input validation result
99
+ */
100
+ onInputChecked?: (validInput: boolean) => any;
101
+ /** Text that should be shown if the input validation failed.
102
+ */
103
+ validationErrorText?: string;
104
+ /** Text that should be shown when hovering over the clear icon
105
+ */
106
+ clearIconText?: string;
107
+ /** Called when focus status changes
108
+ */
109
+ onFocusChange?: (hasFocus: boolean) => any;
110
+ /** Optional ID to attach to the outer element
111
+ */
112
+ id?: string;
113
+ /** If the <Tab> key should be used for auto-completing items. Else it will have its default behavior.
114
+ */
115
+ useTabForCompletions?: boolean;
103
116
  /** An additional element that is put to the left side of the input field */
104
- leftElement?: JSX.Element | null
105
- // An additional element that is put to the right side of the input field
106
- rightElement?: JSX.Element | null
117
+ leftElement?: JSX.Element | null;
118
+ /** An additional element that is put to the right side of the input field
119
+ */
120
+ rightElement?: JSX.Element | null;
107
121
  /** Placeholder tobe shown when no text has been entered, yet. */
108
- placeholder?: string
122
+ placeholder?: string;
109
123
  /** If the horizontal scrollbars should be shown. */
110
- showScrollBar?: boolean
124
+ showScrollBar?: boolean;
111
125
  /** Delay in ms before an auto-completion request should be send after nothing is typed in anymore.
112
126
  * This should prevent the UI to send too many requests to the backend. */
113
- autoCompletionRequestDelay?: number
127
+ autoCompletionRequestDelay?: number;
114
128
  /** Delay in ms before a validation request should be send after nothing is typed in anymore.
115
129
  * This should prevent the UI to send too many requests to the backend. */
116
- validationRequestDelay?: number
130
+ validationRequestDelay?: number;
117
131
  }
118
132
 
119
133
  // @deprecated
@@ -121,122 +135,127 @@ export type IProps = AutoSuggestionProps;
121
135
 
122
136
  // Meta data regarding a request
123
137
  interface RequestMetaData {
124
- requestId: string | undefined
138
+ requestId: string | undefined;
125
139
  }
126
140
 
127
- type HorizontalShiftCallbackFunction = (shift: number) => any
141
+ type HorizontalShiftCallbackFunction = (shift: number) => any;
128
142
 
129
- /** Input component that allows partial, fine-grained auto-completion, i.e. of sub-strings of the input string.
130
- * This is comparable to a one line code editor. */
143
+ /**
144
+ * **Element is deprecated.**
145
+ * Use `CodeAutocompleteField` as replacement.
146
+ *
147
+ * @deprecated
148
+ */
131
149
  export const AutoSuggestion = ({
132
- label,
133
- initialValue,
134
- onChange,
135
- fetchSuggestions,
136
- checkInput,
137
- validationErrorText = "Invalid value",
138
- clearIconText = "Clear",
139
- onFocusChange,
140
- id,
141
- onInputChecked,
142
- leftElement,
143
- rightElement,
144
- useTabForCompletions = false,
145
- placeholder,
146
- showScrollBar = true,
147
- autoCompletionRequestDelay = 1000,
148
- validationRequestDelay = 200
149
- }: AutoSuggestionProps) => {
150
- const value = React.useRef<string>(initialValue)
150
+ className,
151
+ label,
152
+ initialValue,
153
+ onChange,
154
+ fetchSuggestions,
155
+ checkInput,
156
+ validationErrorText = "Invalid value",
157
+ clearIconText = "Clear",
158
+ onFocusChange,
159
+ id,
160
+ onInputChecked,
161
+ leftElement,
162
+ rightElement,
163
+ useTabForCompletions = false,
164
+ placeholder,
165
+ showScrollBar = true,
166
+ autoCompletionRequestDelay = 1000,
167
+ validationRequestDelay = 200,
168
+ }: AutoSuggestionProps) => {
169
+ const value = React.useRef<string>(initialValue);
151
170
  const cursorPosition = React.useRef(0);
152
- const horizontalShiftSubscriber = React.useRef<HorizontalShiftCallbackFunction | undefined>(undefined)
171
+ const horizontalShiftSubscriber = React.useRef<HorizontalShiftCallbackFunction | undefined>(undefined);
153
172
  const [shouldShowDropdown, setShouldShowDropdown] = React.useState(false);
154
173
  const [suggestions, setSuggestions] = React.useState<ISuggestionWithReplacementInfo[]>([]);
155
174
  const [suggestionsPending, setSuggestionsPending] = React.useState(false);
156
- const suggestionRequestData = React.useRef<RequestMetaData>({requestId: undefined})
157
- const [pathValidationPending, setPathValidationPending] = React.useState(false)
158
- const validationRequestData = React.useRef<RequestMetaData>({requestId: undefined})
175
+ const suggestionRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
176
+ const [pathValidationPending, setPathValidationPending] = React.useState(false);
177
+ const validationRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
159
178
  const [, setErrorMarkers] = React.useState<CodeMirror.TextMarker[]>([]);
160
- const [validationResponse, setValidationResponse] = useState<IValidationResult | undefined>(undefined)
161
- const [suggestionResponse, setSuggestionResponse] = useState<IPartialAutoCompleteResult | undefined>(undefined)
179
+ const [validationResponse, setValidationResponse] = useState<IValidationResult | undefined>(undefined);
180
+ const [suggestionResponse, setSuggestionResponse] = useState<IPartialAutoCompleteResult | undefined>(undefined);
162
181
  // The element that should be used for replacement highlighting
163
- const [highlightedElement, setHighlightedElement] = useState<ISuggestionWithReplacementInfo | undefined>(undefined)
182
+ const [highlightedElement, setHighlightedElement] = useState<ISuggestionWithReplacementInfo | undefined>(undefined);
164
183
  const [editorInstance, setEditorInstance] = React.useState<CodeMirror.Editor>();
165
184
  const isFocused = React.useRef(false);
166
185
  /** Mutable editor state, since this needs to be current in scope of the SingleLineEditorComponent. */
167
186
  const [editorState] = React.useState<{
168
- index: number,
169
- suggestions: ISuggestionWithReplacementInfo[],
170
- editorInstance?: CodeMirror.Editor,
171
- dropdownShown: boolean
172
- }>({index: 0, suggestions: [], dropdownShown: false})
187
+ index: number;
188
+ suggestions: ISuggestionWithReplacementInfo[];
189
+ editorInstance?: CodeMirror.Editor;
190
+ dropdownShown: boolean;
191
+ }>({ index: 0, suggestions: [], dropdownShown: false });
173
192
  /** This is for the AutoSuggestionList component in order to re-render. */
174
- const [focusedIndex, setFocusedIndex] = React.useState(0)
175
- const selectedTextRanges = React.useRef<IRange[]>([])
193
+ const [focusedIndex, setFocusedIndex] = React.useState(0);
194
+ const selectedTextRanges = React.useRef<IRange[]>([]);
176
195
 
177
196
  const pathIsValid = validationResponse?.valid ?? true;
178
197
 
179
198
  const setCurrentIndex = (newIndex: number) => {
180
- editorState.index = newIndex
181
- setFocusedIndex(newIndex)
182
- }
183
- const currentIndex = () => editorState.index
199
+ editorState.index = newIndex;
200
+ setFocusedIndex(newIndex);
201
+ };
202
+ const currentIndex = () => editorState.index;
184
203
 
185
204
  React.useEffect(() => {
186
- editorState.editorInstance = editorInstance
187
- }, [editorInstance, editorState])
205
+ editorState.editorInstance = editorInstance;
206
+ }, [editorInstance, editorState]);
188
207
 
189
208
  React.useEffect(() => {
190
- if(initialValue != null) {
191
- editorInstance?.setValue(initialValue)
209
+ if (initialValue != null) {
210
+ editorInstance?.setValue(initialValue);
192
211
  }
193
- }, [initialValue, editorInstance])
212
+ }, [initialValue, editorInstance]);
194
213
 
195
214
  React.useEffect(() => {
196
- editorState.dropdownShown = shouldShowDropdown
197
- }, [shouldShowDropdown, editorState])
215
+ editorState.dropdownShown = shouldShowDropdown;
216
+ }, [shouldShowDropdown, editorState]);
198
217
 
199
218
  // Handle replacement highlighting
200
219
  useEffect(() => {
201
220
  if (highlightedElement && editorInstance) {
202
221
  const { from, length } = highlightedElement;
203
- if(length > 0 && selectedTextRanges.current.length === 0) {
222
+ if (length > 0 && selectedTextRanges.current.length === 0) {
204
223
  const to = from + length;
205
224
  const marker = editorInstance.markText(
206
- {line: 0, ch: from},
207
- {line: 0, ch: to},
208
- {className: `${eccgui}-autosuggestion__text--highlighted`}
225
+ { line: 0, ch: from },
226
+ { line: 0, ch: to },
227
+ { className: `${eccgui}-autosuggestion__text--highlighted` }
209
228
  );
210
- return () => marker.clear()
229
+ return () => marker.clear();
211
230
  }
212
231
  }
213
232
  return;
214
- }, [highlightedElement, selectedTextRanges, editorInstance])
233
+ }, [highlightedElement, selectedTextRanges, editorInstance]);
215
234
 
216
235
  //handle linting
217
236
  React.useEffect(() => {
218
237
  const parseError = validationResponse?.parseError;
219
238
  if (parseError && editorInstance) {
220
239
  const { message, start, end } = parseError;
221
- editorInstance.getDoc().getEditor()
240
+ editorInstance.getDoc().getEditor();
222
241
  const marker = editorInstance.markText(
223
242
  { line: 0, ch: start },
224
243
  { line: 0, ch: end },
225
244
  { className: `${eccgui}-autosuggestion__text--highlighted-error`, title: message }
226
245
  );
227
246
  setErrorMarkers((previousMarkers) => {
228
- previousMarkers.forEach(marker => marker.clear())
229
- return [marker]
247
+ previousMarkers.forEach((marker) => marker.clear());
248
+ return [marker];
230
249
  });
231
250
  } else {
232
251
  // Valid, clear all error markers
233
252
  setErrorMarkers((previous) => {
234
- previous.forEach(marker => marker.clear())
235
- return []
236
- })
253
+ previous.forEach((marker) => marker.clear());
254
+ return [];
255
+ });
237
256
  }
238
- const isValid = validationResponse?.valid === undefined || validationResponse.valid
239
- onInputChecked && onInputChecked(isValid)
257
+ const isValid = validationResponse?.valid === undefined || validationResponse.valid;
258
+ onInputChecked && onInputChecked(isValid);
240
259
  }, [validationResponse?.valid, validationResponse?.parseError, editorInstance, onInputChecked]);
241
260
 
242
261
  /** generate suggestions and also populate the replacement indexes dict */
@@ -251,17 +270,22 @@ export const AutoSuggestion = ({
251
270
  if (suggestionResponse?.replacementResults?.length) {
252
271
  suggestionResponse.replacementResults.forEach(
253
272
  ({ replacements, replacementInterval: { from, length }, extractedQuery }) => {
254
- const replacementsWithMetaData = replacements.map(r => ({...r, query: extractedQuery, from, length}))
273
+ const replacementsWithMetaData = replacements.map((r) => ({
274
+ ...r,
275
+ query: extractedQuery,
276
+ from,
277
+ length,
278
+ }));
255
279
  newSuggestions = [...newSuggestions, ...replacementsWithMetaData];
256
280
  }
257
281
  );
258
- editorState.suggestions = newSuggestions
282
+ editorState.suggestions = newSuggestions;
259
283
  setSuggestions(newSuggestions);
260
284
  } else {
261
- editorState.suggestions = []
262
- setSuggestions([])
285
+ editorState.suggestions = [];
286
+ setSuggestions([]);
263
287
  }
264
- editorState.index = 0
288
+ editorState.index = 0;
265
289
  }, [suggestionResponse, editorState]);
266
290
 
267
291
  const inputactionsDisplayed = React.useCallback((node) => {
@@ -273,58 +297,76 @@ export const AutoSuggestion = ({
273
297
  }
274
298
  }, []);
275
299
 
276
- const asyncCheckInput = useMemo(() => async (inputString: string) => {
277
- if(!checkInput || inputString !== value.current || validationRequestData.current.requestId === inputString) {
278
- return
279
- }
280
- validationRequestData.current.requestId = inputString
281
- setPathValidationPending(true)
282
- try {
283
- const result: IValidationResult | undefined = await checkInput(inputString)
284
- setValidationResponse(result)
285
- } catch(e) {
286
- setValidationResponse(undefined)
287
- // TODO: Error handling
288
- } finally {
289
- setPathValidationPending(false)
290
- }
291
- }, [checkInput])
300
+ const asyncCheckInput = useMemo(
301
+ () => async (inputString: string) => {
302
+ if (
303
+ !checkInput ||
304
+ inputString !== value.current ||
305
+ validationRequestData.current.requestId === inputString
306
+ ) {
307
+ return;
308
+ }
309
+ validationRequestData.current.requestId = inputString;
310
+ setPathValidationPending(true);
311
+ try {
312
+ const result: IValidationResult | undefined = await checkInput(inputString);
313
+ setValidationResponse(result);
314
+ } catch (e) {
315
+ setValidationResponse(undefined);
316
+ // TODO: Error handling
317
+ } finally {
318
+ setPathValidationPending(false);
319
+ }
320
+ },
321
+ [checkInput]
322
+ );
292
323
 
293
324
  const checkValuePathValidity = useMemo(
294
325
  () => debounce((inputString: string) => asyncCheckInput(inputString), validationRequestDelay),
295
326
  [asyncCheckInput, validationRequestDelay]
296
- )
327
+ );
297
328
 
298
- const asyncHandleEditorInputChange = useMemo(() => async (inputString: string, cursorPosition: number) => {
299
- const requestId = `${inputString} ${cursorPosition}`
300
- if(requestId === suggestionRequestData.current.requestId) {
301
- return
302
- }
303
- suggestionRequestData.current.requestId = requestId
304
- setSuggestionsPending(true)
305
- try {
306
- const result: IPartialAutoCompleteResult | undefined = await fetchSuggestions(inputString, cursorPosition)
307
- if(value.current === inputString) {
308
- setSuggestionResponse(result)
329
+ const asyncHandleEditorInputChange = useMemo(
330
+ () => async (inputString: string, cursorPosition: number) => {
331
+ const requestId = `${inputString} ${cursorPosition}`;
332
+ if (requestId === suggestionRequestData.current.requestId) {
333
+ return;
309
334
  }
310
- } catch(e) {
311
- setSuggestionResponse(undefined)
312
- // TODO: Error handling
313
- } finally {
314
- setSuggestionsPending(false)
315
- }
316
- }, [fetchSuggestions])
335
+ suggestionRequestData.current.requestId = requestId;
336
+ setSuggestionsPending(true);
337
+ try {
338
+ const result: IPartialAutoCompleteResult | undefined = await fetchSuggestions(
339
+ inputString,
340
+ cursorPosition
341
+ );
342
+ if (value.current === inputString) {
343
+ setSuggestionResponse(result);
344
+ }
345
+ } catch (e) {
346
+ setSuggestionResponse(undefined);
347
+ // TODO: Error handling
348
+ } finally {
349
+ setSuggestionsPending(false);
350
+ }
351
+ },
352
+ [fetchSuggestions]
353
+ );
317
354
 
318
- const handleEditorInputChange = useMemo(() =>
319
- debounce((inputString: string, cursorPosition: number) => asyncHandleEditorInputChange(inputString, cursorPosition), autoCompletionRequestDelay),
355
+ const handleEditorInputChange = useMemo(
356
+ () =>
357
+ debounce(
358
+ (inputString: string, cursorPosition: number) =>
359
+ asyncHandleEditorInputChange(inputString, cursorPosition),
360
+ autoCompletionRequestDelay
361
+ ),
320
362
  [asyncHandleEditorInputChange, autoCompletionRequestDelay]
321
- )
363
+ );
322
364
 
323
365
  const handleChange = (val: string) => {
324
- value.current = val
325
- checkValuePathValidity.cancel()
326
- checkValuePathValidity(value.current)
327
- onChange(val)
366
+ value.current = val;
367
+ checkValuePathValidity.cancel();
368
+ checkValuePathValidity(value.current);
369
+ onChange(val);
328
370
  };
329
371
 
330
372
  const handleCursorChange = (pos: Position, coords: any, scrollinfo: any) => {
@@ -332,12 +374,11 @@ export const AutoSuggestion = ({
332
374
  // cursor change is fired after onChange, so we put the auto-complete logic here
333
375
  if (isFocused.current) {
334
376
  setShouldShowDropdown(true);
335
- handleEditorInputChange.cancel()
336
- handleEditorInputChange(value.current, cursorPosition.current)
377
+ handleEditorInputChange.cancel();
378
+ handleEditorInputChange(value.current, cursorPosition.current);
337
379
  }
338
- horizontalShiftSubscriber.current && horizontalShiftSubscriber.current(
339
- Math.min(coords.left, Math.max(coords.left - scrollinfo.left, 0))
340
- )
380
+ horizontalShiftSubscriber.current &&
381
+ horizontalShiftSubscriber.current(Math.min(coords.left, Math.max(coords.left - scrollinfo.left, 0)));
341
382
  };
342
383
 
343
384
  const handleInputEditorKeyPress = (event: KeyboardEvent) => {
@@ -349,53 +390,57 @@ export const AutoSuggestion = ({
349
390
  };
350
391
 
351
392
  const closeDropDown = () => {
352
- setHighlightedElement(undefined)
353
- setShouldShowDropdown(false)
354
- }
393
+ setHighlightedElement(undefined);
394
+ setShouldShowDropdown(false);
395
+ };
355
396
 
356
397
  const handleDropdownChange = (selectedSuggestion: ISuggestionWithReplacementInfo) => {
357
398
  if (selectedSuggestion && editorState.editorInstance) {
358
399
  const { from, length, value } = selectedSuggestion;
359
400
  const to = from + length;
360
- editorState.editorInstance.replaceRange(selectedSuggestion.value, {line: 0, ch: from}, {line: 0, ch: to})
361
- closeDropDown()
401
+ editorState.editorInstance.replaceRange(
402
+ selectedSuggestion.value,
403
+ { line: 0, ch: from },
404
+ { line: 0, ch: to }
405
+ );
406
+ closeDropDown();
362
407
  editorState.editorInstance.setCursor({ line: 0, ch: from + value.length });
363
408
  editorState.editorInstance.focus();
364
409
  }
365
410
  };
366
411
 
367
412
  const handleInputEditorClear = () => {
368
- editorInstance?.setValue("")
369
- cursorPosition.current = 0
370
- handleChange("")
413
+ editorInstance?.setValue("");
414
+ cursorPosition.current = 0;
415
+ handleChange("");
371
416
  editorInstance?.focus();
372
417
  };
373
418
 
374
419
  const handleInputFocus = (focusState: boolean) => {
375
- onFocusChange && onFocusChange(focusState)
376
- focusState ? setShouldShowDropdown(true) : closeDropDown()
377
- if(!isFocused.current && focusState) {
420
+ onFocusChange && onFocusChange(focusState);
421
+ focusState ? setShouldShowDropdown(true) : closeDropDown();
422
+ if (!isFocused.current && focusState) {
378
423
  // Just got focus
379
424
  // Clear suggestions and repeat suggestion request, something else might have changed while this component was not focused
380
- setSuggestions([])
381
- suggestionRequestData.current.requestId = undefined
382
- isFocused.current = focusState
383
- handleEditorInputChange.cancel()
384
- handleEditorInputChange(value.current, cursorPosition.current)
425
+ setSuggestions([]);
426
+ suggestionRequestData.current.requestId = undefined;
427
+ isFocused.current = focusState;
428
+ handleEditorInputChange.cancel();
429
+ handleEditorInputChange(value.current, cursorPosition.current);
385
430
  } else {
386
- isFocused.current = focusState
431
+ isFocused.current = focusState;
387
432
  }
388
433
  };
389
434
 
390
435
  //keyboard handlers
391
436
  const handleArrowDown = () => {
392
437
  const lastSuggestionIndex = editorState.suggestions.length - 1;
393
- setCurrentIndex(currentIndex() === lastSuggestionIndex ? 0 : currentIndex() + 1)
438
+ setCurrentIndex(currentIndex() === lastSuggestionIndex ? 0 : currentIndex() + 1);
394
439
  };
395
440
 
396
441
  const handleArrowUp = () => {
397
442
  const lastSuggestionIndex = editorState.suggestions.length - 1;
398
- setCurrentIndex(currentIndex() === 0 ? lastSuggestionIndex : currentIndex() - 1)
443
+ setCurrentIndex(currentIndex() === 0 ? lastSuggestionIndex : currentIndex() - 1);
399
444
  };
400
445
 
401
446
  const handleEnterPressed = () => {
@@ -424,27 +469,37 @@ export const AutoSuggestion = ({
424
469
  handleTabPressed();
425
470
  break;
426
471
  default:
427
- //do nothing
472
+ //do nothing
428
473
  }
429
474
  }
430
475
  };
431
476
 
432
477
  const handleItemHighlighting = React.useCallback((item: ISuggestionWithReplacementInfo | undefined) => {
433
- setHighlightedElement(item)
434
- }, [])
478
+ setHighlightedElement(item);
479
+ }, []);
435
480
 
436
- const onSelection = React.useMemo(() => (ranges: IRange[]) => {
437
- selectedTextRanges.current = ranges
438
- }, [])
481
+ const onSelection = React.useMemo(
482
+ () => (ranges: IRange[]) => {
483
+ selectedTextRanges.current = ranges;
484
+ },
485
+ []
486
+ );
439
487
 
440
- const subscribeToHorizontalShift = React.useMemo(() => (callback: HorizontalShiftCallbackFunction) => {
441
- horizontalShiftSubscriber.current = callback
442
- }, [])
488
+ const subscribeToHorizontalShift = React.useMemo(
489
+ () => (callback: HorizontalShiftCallbackFunction) => {
490
+ horizontalShiftSubscriber.current = callback;
491
+ },
492
+ []
493
+ );
443
494
 
444
495
  const hasError = !!value.current && !pathIsValid && !pathValidationPending;
445
496
  const autoSuggestionInput = (
446
- <div id={id} className={`${eccgui}-autosuggestion`}>
447
- <div className={`${eccgui}-autosuggestion__inputfield ${BlueprintClassNames.INPUT_GROUP} ${BlueprintClassNames.FILL} ${hasError ? BlueprintClassNames.INTENT_DANGER : ""}`}>
497
+ <div id={id} className={`${eccgui}-autosuggestion` + (className ? ` ${className}` : "")}>
498
+ <div
499
+ className={`${eccgui}-autosuggestion__inputfield ${BlueprintClassNames.INPUT_GROUP} ${
500
+ BlueprintClassNames.FILL
501
+ } ${hasError ? BlueprintClassNames.INTENT_DANGER : ""}`}
502
+ >
448
503
  <ContextOverlay
449
504
  minimal
450
505
  fill
@@ -452,9 +507,9 @@ export const AutoSuggestion = ({
452
507
  placement="bottom-start"
453
508
  openOnTargetFocus={false}
454
509
  autoFocus={false}
455
- content={(
510
+ content={
456
511
  <AutoSuggestionList
457
- id={id+"__dropdown"}
512
+ id={id + "__dropdown"}
458
513
  registerForHorizontalShift={subscribeToHorizontalShift}
459
514
  loading={suggestionsPending}
460
515
  options={suggestions}
@@ -463,7 +518,7 @@ export const AutoSuggestion = ({
463
518
  currentlyFocusedIndex={focusedIndex}
464
519
  itemToHighlight={handleItemHighlighting}
465
520
  />
466
- )}
521
+ }
467
522
  >
468
523
  <SingleLineCodeEditor
469
524
  mode="null"
@@ -493,17 +548,18 @@ export const AutoSuggestion = ({
493
548
  </div>
494
549
  );
495
550
 
496
- const withRightElement = rightElement || leftElement ? (
497
- <Toolbar noWrap>
498
- {leftElement && <ToolbarSection>{leftElement}</ToolbarSection>}
499
- <ToolbarSection canGrow canShrink>
500
- <div style={{minWidth: "100%", maxWidth: "100%"}}>
501
- {autoSuggestionInput}
502
- </div>
503
- </ToolbarSection>
504
- {rightElement && <ToolbarSection>{rightElement}</ToolbarSection>}
505
- </Toolbar>
506
- ) : autoSuggestionInput
551
+ const withRightElement =
552
+ rightElement || leftElement ? (
553
+ <Toolbar noWrap>
554
+ {leftElement && <ToolbarSection>{leftElement}</ToolbarSection>}
555
+ <ToolbarSection canGrow canShrink>
556
+ <div style={{ minWidth: "100%", maxWidth: "100%" }}>{autoSuggestionInput}</div>
557
+ </ToolbarSection>
558
+ {rightElement && <ToolbarSection>{rightElement}</ToolbarSection>}
559
+ </Toolbar>
560
+ ) : (
561
+ autoSuggestionInput
562
+ );
507
563
 
508
564
  return label ? (
509
565
  <FieldItem
@@ -515,14 +571,17 @@ export const AutoSuggestion = ({
515
571
  {(pathValidationPending || suggestionsPending) && (
516
572
  <Spinner size="tiny" position="inline" description="Validating value path" />
517
573
  )}
518
- </>)
574
+ </>
575
+ ),
519
576
  }}
520
577
  hasStateDanger={hasError}
521
578
  messageText={hasError ? validationErrorText : undefined}
522
579
  >
523
580
  {withRightElement}
524
581
  </FieldItem>
525
- ) : withRightElement
582
+ ) : (
583
+ withRightElement
584
+ );
526
585
  };
527
586
 
528
587
  export default AutoSuggestion;