@onehat/ui 0.3.57 → 0.3.59
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/package.json +1 -1
- package/src/Components/Form/Field/Combo/Combo.js +328 -184
- package/src/Components/Form/Field/Tag/Tag.js +99 -64
- package/src/Components/Form/Field/Tag/ValueBox.js +45 -0
- package/src/Components/Form/FieldSet.js +5 -4
- package/src/Components/Form/Form.js +87 -28
- package/src/Components/Hoc/withAlert.js +6 -2
- package/src/Components/Hoc/withEditor.js +32 -4
- package/src/Components/Hoc/withFilters.js +3 -1
- package/src/Components/Hoc/withSelection.js +14 -14
- package/src/Components/Hoc/withValue.js +9 -1
- package/src/Components/Icons/Images.js +14 -0
- package/src/Components/Toolbar/Pagination.js +12 -0
- package/src/Components/Viewer/Viewer.js +1 -0
- package/src/Components/index.js +0 -2
- package/src/Functions/delay.js +3 -0
- package/src/Functions/isVideo.js +18 -0
- package/src/Components/Viewer/TagViewer.js +0 -30
|
@@ -12,37 +12,38 @@ import {
|
|
|
12
12
|
} from '../../../../Constants/UiModes.js';
|
|
13
13
|
import UiGlobals from '../../../../UiGlobals.js';
|
|
14
14
|
import Input from '../Input.js';
|
|
15
|
+
import withAlert from '../../../Hoc/withAlert.js';
|
|
15
16
|
import withComponent from '../../../Hoc/withComponent.js';
|
|
16
17
|
import withData from '../../../Hoc/withData.js';
|
|
17
|
-
import withSelection from '../../../Hoc/withSelection.js';
|
|
18
18
|
import withValue from '../../../Hoc/withValue.js';
|
|
19
19
|
import emptyFn from '../../../../Functions/emptyFn.js';
|
|
20
20
|
import { Grid, WindowedGridEditor } from '../../../Grid/Grid.js';
|
|
21
21
|
import IconButton from '../../../Buttons/IconButton.js';
|
|
22
22
|
import CaretDown from '../../../Icons/CaretDown.js';
|
|
23
|
+
import Xmark from '../../../Icons/Xmark.js';
|
|
23
24
|
import _ from 'lodash';
|
|
24
25
|
|
|
25
|
-
// Combo requires the use of HOC withSelection() whenever it's used.
|
|
26
|
-
// The default export is *with* the HOC. A separate *raw* component is
|
|
27
|
-
// exported which can be combined with many HOCs for various functionality.
|
|
28
|
-
|
|
29
26
|
export function ComboComponent(props) {
|
|
30
27
|
const {
|
|
31
28
|
additionalButtons,
|
|
32
29
|
autoFocus = false,
|
|
33
|
-
forceSelection = true,
|
|
34
30
|
tooltipRef = null,
|
|
35
31
|
tooltip = null,
|
|
36
32
|
menuMinWidth = 150,
|
|
37
33
|
disableDirectEntry = false,
|
|
38
34
|
hideMenuOnSelection = true,
|
|
35
|
+
showXButton = false,
|
|
39
36
|
_input = {},
|
|
40
37
|
isEditor = false,
|
|
41
38
|
isDisabled = false,
|
|
39
|
+
tooltipPlacement = 'bottom',
|
|
40
|
+
onRowPress,
|
|
42
41
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
// withComponent
|
|
43
|
+
self,
|
|
44
|
+
|
|
45
|
+
// withAlert
|
|
46
|
+
confirm,
|
|
46
47
|
|
|
47
48
|
// withData
|
|
48
49
|
Repository,
|
|
@@ -50,32 +51,28 @@ export function ComboComponent(props) {
|
|
|
50
51
|
idIx,
|
|
51
52
|
displayIx,
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
setSelection,
|
|
57
|
-
selectionMode,
|
|
58
|
-
selectNext,
|
|
59
|
-
selectPrev,
|
|
60
|
-
getDisplayValuesFromSelection,
|
|
61
|
-
|
|
62
|
-
tooltipPlacement = 'bottom',
|
|
54
|
+
// withValue
|
|
55
|
+
value,
|
|
56
|
+
setValue,
|
|
63
57
|
} = props,
|
|
64
58
|
styles = UiGlobals.styles,
|
|
65
59
|
inputRef = useRef(),
|
|
66
60
|
triggerRef = useRef(),
|
|
67
61
|
menuRef = useRef(),
|
|
68
|
-
|
|
62
|
+
displayValueRef = useRef(null),
|
|
69
63
|
savedSearch = useRef(null),
|
|
70
64
|
typingTimeout = useRef(),
|
|
71
65
|
[isMenuShown, setIsMenuShown] = useState(false),
|
|
72
66
|
[isRendered, setIsRendered] = useState(false),
|
|
73
|
-
[
|
|
67
|
+
[isReady, setIsReady] = useState(false),
|
|
68
|
+
[isSearchMode, setIsSearchMode] = useState(false),
|
|
69
|
+
[gridSelection, setGridSelection] = useState(null),
|
|
70
|
+
[textInputValue, setTextInputValue] = useState(''),
|
|
71
|
+
[newEntityDisplayValue, setNewEntityDisplayValue] = useState(null),
|
|
74
72
|
[width, setWidth] = useState(0),
|
|
75
|
-
[height, setHeight] = useState(null),
|
|
76
73
|
[top, setTop] = useState(0),
|
|
77
74
|
[left, setLeft] = useState(0),
|
|
78
|
-
showMenu = () => {
|
|
75
|
+
showMenu = async () => {
|
|
79
76
|
if (isMenuShown) {
|
|
80
77
|
return;
|
|
81
78
|
}
|
|
@@ -107,7 +104,7 @@ export function ComboComponent(props) {
|
|
|
107
104
|
}
|
|
108
105
|
}
|
|
109
106
|
if (Repository && !Repository.isLoaded) {
|
|
110
|
-
Repository.
|
|
107
|
+
await Repository.load();
|
|
111
108
|
}
|
|
112
109
|
setIsMenuShown(true);
|
|
113
110
|
},
|
|
@@ -117,11 +114,8 @@ export function ComboComponent(props) {
|
|
|
117
114
|
}
|
|
118
115
|
setIsMenuShown(false);
|
|
119
116
|
},
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
setIsManuallyEnteringText = (bool) => {
|
|
124
|
-
isManuallyEnteringText.current = bool;
|
|
117
|
+
toggleMenu = () => {
|
|
118
|
+
setIsMenuShown(!isMenuShown);
|
|
125
119
|
},
|
|
126
120
|
getSavedSearch = () => {
|
|
127
121
|
return savedSearch.current;
|
|
@@ -129,8 +123,8 @@ export function ComboComponent(props) {
|
|
|
129
123
|
setSavedSearch = (val) => {
|
|
130
124
|
savedSearch.current = val;
|
|
131
125
|
},
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
resetInputTextValue = () => {
|
|
127
|
+
setTextInputValue(getDisplayValue());
|
|
134
128
|
},
|
|
135
129
|
onInputKeyPress = (e, inputValue) => {
|
|
136
130
|
if (disableDirectEntry) {
|
|
@@ -138,6 +132,8 @@ export function ComboComponent(props) {
|
|
|
138
132
|
}
|
|
139
133
|
switch(e.key) {
|
|
140
134
|
case 'Escape':
|
|
135
|
+
setIsSearchMode(false);
|
|
136
|
+
resetInputTextValue();
|
|
141
137
|
hideMenu();
|
|
142
138
|
break;
|
|
143
139
|
case 'Enter':
|
|
@@ -145,24 +141,42 @@ export function ComboComponent(props) {
|
|
|
145
141
|
if (_.isEmpty(inputValue) && !_.isNull(value)) {
|
|
146
142
|
// User pressed Enter on an empty text field, but value is set to something
|
|
147
143
|
// This means the user cleared the input and pressed enter, meaning he wants to clear the value
|
|
148
|
-
|
|
149
|
-
// clear the value
|
|
150
144
|
setValue(null);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
hideMenu();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (_.isEmpty(gridSelection)) {
|
|
150
|
+
confirm('You have nothing selected in the dropdown menu. Clear value?', doIt, true);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
doIt();
|
|
155
|
+
|
|
156
|
+
function doIt() {
|
|
157
|
+
setValue(gridSelection?.id);
|
|
158
|
+
hideMenu();
|
|
156
159
|
}
|
|
157
160
|
break;
|
|
158
|
-
case 'ArrowDown':
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
// case 'ArrowDown':
|
|
162
|
+
// e.preventDefault();
|
|
163
|
+
// showMenu();
|
|
164
|
+
// selectNext();
|
|
165
|
+
// setTimeout(() => {
|
|
166
|
+
// if (!self.children?.dropdownGrid?.selectPrev) {
|
|
167
|
+
// debugger;
|
|
168
|
+
// }
|
|
169
|
+
// self.children.dropdownGrid.selectNext();
|
|
170
|
+
// }, 10);
|
|
171
|
+
// break;
|
|
172
|
+
// case 'ArrowUp':
|
|
173
|
+
// e.preventDefault();
|
|
174
|
+
// showMenu();
|
|
175
|
+
// selectPrev();
|
|
176
|
+
// setTimeout(() => {
|
|
177
|
+
// self.children.dropdownGrid.selectPrev();
|
|
178
|
+
// }, 10);
|
|
179
|
+
// break;
|
|
166
180
|
default:
|
|
167
181
|
}
|
|
168
182
|
},
|
|
@@ -170,140 +184,142 @@ export function ComboComponent(props) {
|
|
|
170
184
|
if (disableDirectEntry) {
|
|
171
185
|
return;
|
|
172
186
|
}
|
|
173
|
-
setTextValue(value);
|
|
174
187
|
|
|
175
|
-
|
|
188
|
+
if (_.isEmpty(value)) {
|
|
189
|
+
// text input is cleared
|
|
190
|
+
hideMenu();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
setTextInputValue(value);
|
|
195
|
+
showMenu();
|
|
196
|
+
|
|
176
197
|
clearTimeout(typingTimeout.current);
|
|
177
198
|
typingTimeout.current = setTimeout(() => {
|
|
178
199
|
searchForMatches(value);
|
|
179
200
|
}, 300);
|
|
180
201
|
},
|
|
202
|
+
onInputFocus = (e) => {
|
|
203
|
+
inputRef.current.select();
|
|
204
|
+
},
|
|
181
205
|
onInputBlur = (e) => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} = e;
|
|
185
|
-
|
|
186
|
-
setIsManuallyEnteringText(false);
|
|
187
|
-
|
|
188
|
-
// If user focused on the trigger and text is blank, clear the selection and close the menu
|
|
189
|
-
if ((triggerRef.current === relatedTarget || triggerRef.current.contains(relatedTarget)) && (_.isEmpty(textValue) || _.isNil(textValue))) {
|
|
190
|
-
if (!disableWithSelection) {
|
|
191
|
-
setSelection([]); // delete current selection
|
|
192
|
-
}
|
|
193
|
-
hideMenu();
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// If user focused on the menu or trigger, ignore this blur
|
|
198
|
-
if (triggerRef.current === relatedTarget ||
|
|
199
|
-
triggerRef.current.contains(relatedTarget) ||
|
|
200
|
-
menuRef.current=== relatedTarget ||
|
|
201
|
-
menuRef.current?.contains(relatedTarget)) {
|
|
206
|
+
if (isEventStillInComponent(e)) {
|
|
207
|
+
// ignore the blur
|
|
202
208
|
return;
|
|
203
209
|
}
|
|
204
210
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
triggerRef.current !== relatedTarget &&
|
|
209
|
-
(!menuRef.current || !menuRef.current.contains(relatedTarget))
|
|
210
|
-
)
|
|
211
|
-
) {
|
|
212
|
-
hideMenu();
|
|
213
|
-
}
|
|
214
|
-
if (_.isEmpty(textValue) || _.isNil(textValue)) {
|
|
215
|
-
|
|
216
|
-
if (!disableWithSelection) {
|
|
217
|
-
setSelection([]); // delete current selection
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
} else if (getIsManuallyEnteringText()) {
|
|
221
|
-
if (forceSelection) {
|
|
222
|
-
if (!disableWithSelection) {
|
|
223
|
-
setSelection([]); // delete current selection
|
|
224
|
-
} else {
|
|
225
|
-
setValue(textValue);
|
|
226
|
-
}
|
|
227
|
-
hideMenu();
|
|
228
|
-
} else {
|
|
229
|
-
setValue(textValue);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (!disableWithSelection) {
|
|
234
|
-
if (_.isEmpty(selection)) {
|
|
235
|
-
setTextValue('');
|
|
236
|
-
}
|
|
237
|
-
}
|
|
211
|
+
setIsSearchMode(false);
|
|
212
|
+
resetInputTextValue();
|
|
213
|
+
hideMenu();
|
|
238
214
|
},
|
|
239
|
-
|
|
215
|
+
onTriggerPress = (e) => {
|
|
240
216
|
if (!isRendered) {
|
|
241
217
|
return;
|
|
242
218
|
}
|
|
219
|
+
clearGridFilters();
|
|
243
220
|
showMenu();
|
|
244
221
|
},
|
|
245
|
-
|
|
246
|
-
if (!
|
|
222
|
+
onTriggerBlur = (e) => {
|
|
223
|
+
if (!isMenuShown) {
|
|
247
224
|
return;
|
|
248
225
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
226
|
+
|
|
227
|
+
if (isEventStillInComponent(e)) {
|
|
228
|
+
// ignore the blur
|
|
229
|
+
return;
|
|
253
230
|
}
|
|
254
|
-
|
|
231
|
+
|
|
232
|
+
setIsSearchMode(false);
|
|
233
|
+
resetInputTextValue();
|
|
234
|
+
hideMenu();
|
|
255
235
|
},
|
|
256
|
-
|
|
236
|
+
onClearBtn = () => {
|
|
237
|
+
setTextInputValue('');
|
|
238
|
+
setValue(null);
|
|
239
|
+
}
|
|
240
|
+
isEventStillInComponent = (e) => {
|
|
257
241
|
const {
|
|
258
242
|
relatedTarget
|
|
259
243
|
} = e;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
244
|
+
return !relatedTarget ||
|
|
245
|
+
!menuRef.current ||
|
|
246
|
+
!triggerRef.current ||
|
|
247
|
+
triggerRef.current === relatedTarget ||
|
|
248
|
+
triggerRef.current.contains(relatedTarget) ||
|
|
249
|
+
menuRef.current === relatedTarget ||
|
|
250
|
+
menuRef.current?.contains(relatedTarget);
|
|
251
|
+
},
|
|
252
|
+
clearGridFilters = async () => {
|
|
253
|
+
if (Repository) {
|
|
254
|
+
if (Repository.isLoading) {
|
|
255
|
+
await Repository.waitUntilDoneLoading();
|
|
264
256
|
}
|
|
265
|
-
|
|
257
|
+
|
|
258
|
+
// clear filter
|
|
259
|
+
if (Repository.isRemote) {
|
|
260
|
+
let searchField = 'q';
|
|
261
|
+
const searchValue = null;
|
|
266
262
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
263
|
+
// Check to see if displayField is a real field
|
|
264
|
+
const
|
|
265
|
+
schema = Repository.getSchema(),
|
|
266
|
+
displayFieldName = schema.model.displayProperty,
|
|
267
|
+
displayFieldDef = schema.getPropertyDefinition(displayFieldName);
|
|
268
|
+
if (!displayFieldDef.isVirtual) {
|
|
269
|
+
searchField = displayFieldName + ' LIKE';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
Repository.clear();
|
|
273
|
+
await Repository.filter(searchField, searchValue);
|
|
274
|
+
if (!this.isAutoLoad) {
|
|
275
|
+
await Repository.reload();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
} else {
|
|
279
|
+
throw Error('Not yet implemented');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
setSavedSearch(null);
|
|
283
|
+
|
|
284
|
+
} else {
|
|
285
|
+
// throw Error('Not yet implemented');
|
|
273
286
|
}
|
|
274
287
|
},
|
|
275
288
|
searchForMatches = async (value) => {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return;
|
|
289
|
+
if (!isMenuShown) {
|
|
290
|
+
showMenu();
|
|
279
291
|
}
|
|
280
292
|
|
|
293
|
+
setIsSearchMode(true);
|
|
294
|
+
|
|
281
295
|
let found;
|
|
282
296
|
if (Repository) {
|
|
297
|
+
if (Repository.isLoading) {
|
|
298
|
+
await Repository.waitUntilDoneLoading();
|
|
299
|
+
}
|
|
283
300
|
|
|
284
301
|
// Set filter
|
|
285
302
|
let filter = {};
|
|
286
303
|
if (Repository.isRemote) {
|
|
287
304
|
let searchField = 'q';
|
|
305
|
+
const searchValue = _.isEmpty(value) ? null : value + '%';
|
|
288
306
|
|
|
289
307
|
// Check to see if displayField is a real field
|
|
290
308
|
const
|
|
291
309
|
schema = Repository.getSchema(),
|
|
292
|
-
displayFieldName = schema.model.displayProperty
|
|
310
|
+
displayFieldName = schema.model.displayProperty,
|
|
293
311
|
displayFieldDef = schema.getPropertyDefinition(displayFieldName);
|
|
294
312
|
if (!displayFieldDef.isVirtual) {
|
|
295
313
|
searchField = displayFieldName + ' LIKE';
|
|
296
314
|
}
|
|
297
315
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
await Repository.filter(searchField, value);
|
|
316
|
+
await Repository.filter(searchField, searchValue);
|
|
301
317
|
if (!this.isAutoLoad) {
|
|
302
318
|
await Repository.reload();
|
|
303
319
|
}
|
|
304
320
|
|
|
305
321
|
} else {
|
|
306
|
-
throw Error('Not
|
|
322
|
+
throw Error('Not yet implemented');
|
|
307
323
|
|
|
308
324
|
// Fuzzy search with getBy filter function
|
|
309
325
|
filter = (entity) => {
|
|
@@ -316,18 +332,12 @@ export function ComboComponent(props) {
|
|
|
316
332
|
}
|
|
317
333
|
|
|
318
334
|
setSavedSearch(value);
|
|
319
|
-
|
|
320
|
-
const numResults = Repository.entities.length;
|
|
321
|
-
if (!numResults) {
|
|
322
|
-
setSelection([]);
|
|
323
|
-
} else if (numResults === 1) {
|
|
324
|
-
const selection = Repository.entities[0];
|
|
325
|
-
setSelection([selection]);
|
|
326
|
-
setSavedSearch(null);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
335
|
+
setNewEntityDisplayValue(value); // capture the search query so we can tell Grid what to use for a new entity's displayValue
|
|
329
336
|
|
|
330
337
|
} else {
|
|
338
|
+
|
|
339
|
+
throw Error('Not yet implemented'); // NOTE: When implementing this, also implement clearGridFilters
|
|
340
|
+
|
|
331
341
|
// Search through data
|
|
332
342
|
found = _.find(data, (item) => {
|
|
333
343
|
if (_.isString(item[displayIx]) && _.isString(value)) {
|
|
@@ -335,23 +345,64 @@ export function ComboComponent(props) {
|
|
|
335
345
|
}
|
|
336
346
|
return item[displayIx] === value;
|
|
337
347
|
});
|
|
338
|
-
if (found) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
newTextValue = getDisplayValuesFromSelection(newSelection);
|
|
348
|
+
// if (found) {
|
|
349
|
+
// const
|
|
350
|
+
// newSelection = [found];
|
|
342
351
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
352
|
+
// setTextInputValue(newTextValue);
|
|
353
|
+
// }
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
getDisplayValue = () => {
|
|
357
|
+
return displayValueRef.current;
|
|
358
|
+
},
|
|
359
|
+
setDisplayValue = async (value) => {
|
|
360
|
+
let displayValue = '';
|
|
361
|
+
if (_.isNil(value)) {
|
|
362
|
+
// do nothing
|
|
363
|
+
} else if (_.isArray(value)) {
|
|
364
|
+
displayValue = [];
|
|
365
|
+
if (Repository) {
|
|
366
|
+
if (!Repository.isLoaded) {
|
|
367
|
+
throw Error('Not yet implemented'); // Would a Combo ever have multiple remote selections? Shouldn't that be a Tag field??
|
|
346
368
|
}
|
|
369
|
+
if (Repository.isLoading) {
|
|
370
|
+
await Repository.waitUntilDoneLoading();
|
|
371
|
+
}
|
|
372
|
+
displayValue = _.each(value, (id) => {
|
|
373
|
+
const entity = Repository.getById(id);
|
|
374
|
+
if (entity) {
|
|
375
|
+
displayValue.push(entity.displayValue)
|
|
376
|
+
}
|
|
377
|
+
});
|
|
347
378
|
} else {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
379
|
+
displayValue = _.each(value, (id) => {
|
|
380
|
+
const item = _.find(data, (datum) => datum[idIx] === id);
|
|
381
|
+
if (item) {
|
|
382
|
+
displayValue.push(item[displayIx]);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
displayValue = displayValue.join(', ');
|
|
387
|
+
} else {
|
|
388
|
+
if (Repository) {
|
|
389
|
+
let entity;
|
|
390
|
+
if (!Repository.isLoaded) {
|
|
391
|
+
entity = await Repository.getSingleEntityFromServer(value);
|
|
392
|
+
} else {
|
|
393
|
+
if (Repository.isLoading) {
|
|
394
|
+
await Repository.waitUntilDoneLoading();
|
|
351
395
|
}
|
|
396
|
+
entity = Repository.getById(value);
|
|
352
397
|
}
|
|
398
|
+
displayValue = entity?.displayValue || '';
|
|
399
|
+
} else {
|
|
400
|
+
const item = _.find(data, (datum) => datum[idIx] === value);
|
|
401
|
+
displayValue = (item && item[displayIx]) || '';
|
|
353
402
|
}
|
|
354
403
|
}
|
|
404
|
+
|
|
405
|
+
displayValueRef.current = displayValue;
|
|
355
406
|
};
|
|
356
407
|
|
|
357
408
|
useEffect(() => {
|
|
@@ -365,30 +416,62 @@ export function ComboComponent(props) {
|
|
|
365
416
|
|
|
366
417
|
}, [isRendered]);
|
|
367
418
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
(async () => {
|
|
421
|
+
setIsSearchMode(false);
|
|
422
|
+
await setDisplayValue(value);
|
|
423
|
+
resetInputTextValue();
|
|
424
|
+
if (!isReady) {
|
|
425
|
+
setIsReady(true);
|
|
372
426
|
}
|
|
427
|
+
})();
|
|
428
|
+
}, [value]);
|
|
373
429
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (!_.isEqual(localTextValue, textValue)) {
|
|
377
|
-
setTextValue(localTextValue);
|
|
378
|
-
}
|
|
379
|
-
setIsManuallyEnteringText(false);
|
|
380
|
-
}, [selection]);
|
|
430
|
+
if (!isReady) {
|
|
431
|
+
return null;
|
|
381
432
|
}
|
|
382
433
|
|
|
434
|
+
if (self) {
|
|
435
|
+
self.clear = onClearBtn;
|
|
436
|
+
}
|
|
383
437
|
|
|
384
438
|
const refProps = {};
|
|
385
439
|
if (tooltipRef) {
|
|
386
440
|
refProps.ref = tooltipRef;
|
|
387
441
|
}
|
|
388
442
|
|
|
443
|
+
const gridProps = _.pick(props, [
|
|
444
|
+
'Editor',
|
|
445
|
+
'model',
|
|
446
|
+
'Repository',
|
|
447
|
+
'data',
|
|
448
|
+
'idIx',
|
|
449
|
+
'displayIx',
|
|
450
|
+
'value',
|
|
451
|
+
'disableView',
|
|
452
|
+
'disableCopy',
|
|
453
|
+
'disableDuplicate',
|
|
454
|
+
'disablePrint',
|
|
455
|
+
]);
|
|
456
|
+
|
|
389
457
|
const WhichGrid = isEditor ? WindowedGridEditor : Grid;
|
|
390
458
|
|
|
391
459
|
let comboComponent = <Row {...refProps} justifyContent="center" alignItems="center" h={styles.FORM_COMBO_HEIGHT} flex={1} onLayout={() => setIsRendered(true)}>
|
|
460
|
+
{showXButton && !_.isNil(value) &&
|
|
461
|
+
<IconButton
|
|
462
|
+
_icon={{
|
|
463
|
+
as: Xmark,
|
|
464
|
+
color: 'trueGray.600',
|
|
465
|
+
size: 'sm',
|
|
466
|
+
}}
|
|
467
|
+
isDisabled={isDisabled}
|
|
468
|
+
onPress={onClearBtn}
|
|
469
|
+
h="100%"
|
|
470
|
+
bg={styles.FORM_COMBO_TRIGGER_BG}
|
|
471
|
+
_hover={{
|
|
472
|
+
bg: styles.FORM_COMBO_TRIGGER_HOVER_BG,
|
|
473
|
+
}}
|
|
474
|
+
/>}
|
|
392
475
|
{disableDirectEntry ?
|
|
393
476
|
<Pressable
|
|
394
477
|
onPress={toggleMenu}
|
|
@@ -424,17 +507,17 @@ export function ComboComponent(props) {
|
|
|
424
507
|
_focus={{
|
|
425
508
|
bg: styles.FORM_COMBO_INPUT_FOCUS_BG,
|
|
426
509
|
}}
|
|
427
|
-
>{
|
|
510
|
+
>{textInputValue}</Text>
|
|
428
511
|
</Pressable> :
|
|
429
512
|
<Input
|
|
430
513
|
ref={inputRef}
|
|
431
|
-
value={
|
|
514
|
+
value={textInputValue}
|
|
432
515
|
autoSubmit={true}
|
|
433
516
|
isDisabled={isDisabled}
|
|
434
517
|
onChangeValue={onInputChangeText}
|
|
435
518
|
onKeyPress={onInputKeyPress}
|
|
519
|
+
onFocus={onInputFocus}
|
|
436
520
|
onBlur={onInputBlur}
|
|
437
|
-
onClick={onInputClick}
|
|
438
521
|
onLayout={(e) => {
|
|
439
522
|
// On web, this is not needed, but on RN it might be, so leave it in for now
|
|
440
523
|
const {
|
|
@@ -447,15 +530,6 @@ export function ComboComponent(props) {
|
|
|
447
530
|
setTop(top + height);
|
|
448
531
|
setLeft(left);
|
|
449
532
|
}}
|
|
450
|
-
// onFocus={(e) => {
|
|
451
|
-
// if (isBlocked.current) {
|
|
452
|
-
// return;
|
|
453
|
-
// }
|
|
454
|
-
// if (!isRendered) {
|
|
455
|
-
// return;
|
|
456
|
-
// }
|
|
457
|
-
// showMenu();
|
|
458
|
-
// }}
|
|
459
533
|
flex={1}
|
|
460
534
|
h="100%"
|
|
461
535
|
m={0}
|
|
@@ -535,20 +609,90 @@ export function ComboComponent(props) {
|
|
|
535
609
|
};
|
|
536
610
|
}}
|
|
537
611
|
autoAdjustPageSizeToHeight={false}
|
|
538
|
-
{...
|
|
612
|
+
{...gridProps}
|
|
613
|
+
reference="dropdownGrid"
|
|
614
|
+
parent={self}
|
|
539
615
|
h={styles.FORM_COMBO_MENU_HEIGHT + 'px'}
|
|
616
|
+
newEntityDisplayValue={newEntityDisplayValue}
|
|
540
617
|
disablePresetButtons={!isEditor}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
618
|
+
onChangeSelection={(selection) => {
|
|
619
|
+
|
|
620
|
+
if (Repository && selection[0]?.isPhantom) {
|
|
621
|
+
// do nothing
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
setGridSelection(selection);
|
|
626
|
+
|
|
627
|
+
if (Repository) {
|
|
628
|
+
|
|
629
|
+
// When we first open the menu, we try to match the selection to the value, ignore this
|
|
630
|
+
if (selection[0]?.displayValue === getDisplayValue()) {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// when user selected the record matching the current value, kill search mode
|
|
635
|
+
if (selection[0]?.id === value) {
|
|
636
|
+
setIsSearchMode(false);
|
|
637
|
+
resetInputTextValue();
|
|
638
|
+
if (hideMenuOnSelection) {
|
|
639
|
+
hideMenu();
|
|
640
|
+
}
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
setValue(selection[0] ? selection[0].id : null);
|
|
645
|
+
|
|
646
|
+
} else {
|
|
647
|
+
|
|
648
|
+
// When we first open the menu, we try to match the selection to the value, ignore this
|
|
649
|
+
if (selection[0] && selection[0][displayIx] === getDisplayValue()) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// when user selected the record matching the current value, kill search mode
|
|
654
|
+
if (selection[0] && selection[0][idIx] === value) {
|
|
655
|
+
setIsSearchMode(false);
|
|
656
|
+
resetInputTextValue();
|
|
657
|
+
if (hideMenuOnSelection) {
|
|
658
|
+
hideMenu();
|
|
659
|
+
}
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
setValue(selection[0] ? selection[0][idIx] : null);
|
|
664
|
+
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (_.isEmpty(selection)) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if (hideMenuOnSelection && !isEditor) {
|
|
546
672
|
hideMenu();
|
|
547
673
|
}
|
|
674
|
+
|
|
548
675
|
}}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
676
|
+
onSave={(selection) => {
|
|
677
|
+
const entity = selection[0];
|
|
678
|
+
if (entity?.id !== value) {
|
|
679
|
+
// Either a phantom record was just solidified into a real record, or a new (non-phantom) record was added.
|
|
680
|
+
// Select it and set the value of the combo.
|
|
681
|
+
setGridSelection([entity]);
|
|
682
|
+
const id = entity.id;
|
|
683
|
+
setValue(id);
|
|
684
|
+
}
|
|
685
|
+
}}
|
|
686
|
+
onRowPress={(item, e) => {
|
|
687
|
+
if (onRowPress) {
|
|
688
|
+
onRowPress(item, e);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const id = Repository ? item.id : item[idIx];
|
|
692
|
+
if (id === value) {
|
|
693
|
+
hideMenu();
|
|
694
|
+
onInputFocus();
|
|
695
|
+
}
|
|
552
696
|
}}
|
|
553
697
|
/>
|
|
554
698
|
</Popover.Body>
|
|
@@ -565,9 +709,9 @@ export function ComboComponent(props) {
|
|
|
565
709
|
}
|
|
566
710
|
|
|
567
711
|
export const Combo = withComponent(
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
712
|
+
withAlert(
|
|
713
|
+
withData(
|
|
714
|
+
withValue(
|
|
571
715
|
ComboComponent
|
|
572
716
|
)
|
|
573
717
|
)
|