@equinor/eds-core-react 2.2.1-beta.0 → 2.3.0-beta.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 (41) hide show
  1. package/dist/eds-core-react.cjs +754 -499
  2. package/dist/esm/components/Autocomplete/AddNewOption.js +31 -14
  3. package/dist/esm/components/Autocomplete/Autocomplete.js +54 -874
  4. package/dist/esm/components/Autocomplete/AutocompleteContext.js +12 -0
  5. package/dist/esm/components/Autocomplete/EmptyOption.js +21 -0
  6. package/dist/esm/components/Autocomplete/MultipleInput.js +85 -0
  7. package/dist/esm/components/Autocomplete/Option.js +42 -23
  8. package/dist/esm/components/Autocomplete/OptionList.js +124 -0
  9. package/dist/esm/components/Autocomplete/RightAdornments.js +48 -0
  10. package/dist/esm/components/Autocomplete/SelectAllOption.js +63 -0
  11. package/dist/esm/components/Autocomplete/SingleInput.js +28 -0
  12. package/dist/esm/components/Autocomplete/useAutocomplete.js +605 -0
  13. package/dist/esm/components/Autocomplete/utils.js +93 -0
  14. package/dist/esm/components/Datepicker/fields/FieldWrapper.js +10 -0
  15. package/dist/esm/components/Dialog/Dialog.js +6 -4
  16. package/dist/esm/components/next/Icon/Icon.js +57 -0
  17. package/dist/esm/components/next/Icon/icon.css.js +6 -0
  18. package/dist/esm/index.js +1 -1
  19. package/dist/esm/index.next.js +1 -0
  20. package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js +26 -0
  21. package/dist/index.next.cjs +82 -0
  22. package/dist/types/components/Autocomplete/AddNewOption.d.ts +4 -12
  23. package/dist/types/components/Autocomplete/Autocomplete.d.ts +22 -7
  24. package/dist/types/components/Autocomplete/AutocompleteContext.d.ts +228 -0
  25. package/dist/types/components/Autocomplete/EmptyOption.d.ts +1 -0
  26. package/dist/types/components/Autocomplete/MultipleInput.d.ts +1 -0
  27. package/dist/types/components/Autocomplete/Option.d.ts +7 -15
  28. package/dist/types/components/Autocomplete/OptionList.d.ts +2 -0
  29. package/dist/types/components/Autocomplete/RightAdornments.d.ts +1 -0
  30. package/dist/types/components/Autocomplete/SelectAllOption.d.ts +6 -0
  31. package/dist/types/components/Autocomplete/SingleInput.d.ts +1 -0
  32. package/dist/types/components/Autocomplete/useAutocomplete.d.ts +122 -0
  33. package/dist/types/components/Autocomplete/utils.d.ts +13 -0
  34. package/dist/types/components/Datepicker/DateRangePicker.d.ts +1 -1
  35. package/dist/types/components/SideBar/SideBarButton/index.d.ts +1 -1
  36. package/dist/types/components/next/Icon/Icon.d.ts +29 -0
  37. package/dist/types/components/next/Icon/Icon.types.d.ts +19 -0
  38. package/dist/types/components/next/Icon/index.d.ts +2 -0
  39. package/dist/types/components/next/Placeholder/Placeholder.figma.d.ts +16 -0
  40. package/dist/types/components/next/index.d.ts +2 -0
  41. package/package.json +3 -2
@@ -0,0 +1,605 @@
1
+ import { useToken, useIsomorphicLayoutEffect } from '@equinor/eds-utils';
2
+ import { useVirtualizer } from '@tanstack/react-virtual';
3
+ import { useMultipleSelection, useCombobox } from 'downshift';
4
+ import { useState, useMemo, useCallback, useRef, useImperativeHandle, useEffect } from 'react';
5
+ import { AddSymbol, AllSymbol, defaultOptionDisabled } from './Autocomplete.js';
6
+ import { multiSelect, selectTokens } from './Autocomplete.tokens.js';
7
+ import { findPrevIndex, findNextIndex, mergeEventsFromRight } from './utils.js';
8
+ import { useEds } from '../EdsProvider/eds.context.js';
9
+
10
+ const useAutocomplete = ({
11
+ options = [],
12
+ totalOptions,
13
+ label,
14
+ meta,
15
+ className,
16
+ style,
17
+ disabled = false,
18
+ readOnly = false,
19
+ loading = false,
20
+ hideClearButton = false,
21
+ onOptionsChange,
22
+ onAddNewOption,
23
+ onInputChange,
24
+ selectedOptions: _selectedOptions,
25
+ selectionDisplay = 'summary',
26
+ multiple,
27
+ itemToKey: _itemToKey,
28
+ itemCompare: _itemCompare,
29
+ allowSelectAll,
30
+ initialSelectedOptions: _initialSelectedOptions = [],
31
+ optionDisabled = defaultOptionDisabled,
32
+ optionsFilter,
33
+ autoWidth,
34
+ placeholder,
35
+ optionLabel,
36
+ clearSearchOnChange = true,
37
+ multiline = false,
38
+ dropdownHeight = 300,
39
+ optionComponent,
40
+ helperText,
41
+ helperIcon,
42
+ noOptionsText = 'No options',
43
+ variant,
44
+ onClear,
45
+ ref,
46
+ ...other
47
+ }) => {
48
+ const [lastScrollOffset, setLastScrollOffset] = useState(0);
49
+ const [controlledHighlightedIndex, setControlledHighlightedIndex] = useState(0);
50
+ const itemCompare = useMemo(() => {
51
+ if (_itemCompare && _itemToKey) {
52
+ console.error('Error: Specifying both itemCompare and itemToKey. itemCompare is deprecated, while itemToKey should be used instead of it. Please only use one.');
53
+ return _itemCompare;
54
+ }
55
+ if (_itemToKey) {
56
+ return (o1, o2) => _itemToKey(o1) === _itemToKey(o2);
57
+ }
58
+ return _itemCompare;
59
+ }, [_itemCompare, _itemToKey]);
60
+ const itemToKey = useCallback(item => {
61
+ return _itemToKey ? _itemToKey(item) : item;
62
+ }, [_itemToKey]);
63
+
64
+ // MARK: initializing data/setup
65
+ const selectedOptions = _selectedOptions ? itemCompare ? options.filter(item => _selectedOptions.some(compare => itemCompare(item, compare))) : _selectedOptions : undefined;
66
+ const initialSelectedOptions = _initialSelectedOptions ? itemCompare ? options.filter(item => _initialSelectedOptions.some(compare => itemCompare(item, compare))) : _initialSelectedOptions : undefined;
67
+ const isControlled = Boolean(selectedOptions);
68
+ const [inputOptions, setInputOptions] = useState(options);
69
+ const [_availableItems, setAvailableItems] = useState(inputOptions);
70
+ const [typedInputValue, setTypedInputValue] = useState('');
71
+ const inputRef = useRef(null);
72
+ useImperativeHandle(ref, () => inputRef.current);
73
+ const showSelectAll = useMemo(() => {
74
+ if (!multiple && allowSelectAll) {
75
+ throw new Error(`allowSelectAll can only be used with multiple`);
76
+ }
77
+ return allowSelectAll && !typedInputValue;
78
+ }, [allowSelectAll, multiple, typedInputValue]);
79
+ const availableItems = useMemo(() => {
80
+ if (showSelectAll && onAddNewOption) return [AddSymbol, AllSymbol, ..._availableItems];
81
+ if (showSelectAll) return [AllSymbol, ..._availableItems];
82
+ if (onAddNewOption) return [AddSymbol, ..._availableItems];
83
+ return _availableItems;
84
+ }, [_availableItems, showSelectAll, onAddNewOption]);
85
+ const getSelectedIndex = useCallback(selectedItem => availableItems.findIndex(item => itemCompare ? itemCompare(item, selectedItem) : item === selectedItem), [availableItems, itemCompare]);
86
+
87
+ //issue 2304, update dataset when options are added dynamically
88
+ useEffect(() => {
89
+ const availableHash = JSON.stringify(inputOptions);
90
+ const optionsHash = JSON.stringify(options);
91
+ if (availableHash !== optionsHash) {
92
+ setInputOptions(options);
93
+ }
94
+ }, [options, inputOptions]);
95
+ useEffect(() => {
96
+ setAvailableItems(inputOptions);
97
+ }, [inputOptions]);
98
+ const {
99
+ density
100
+ } = useEds();
101
+ const token = useToken({
102
+ density
103
+ }, multiple ? multiSelect : selectTokens);
104
+ const tokens = token();
105
+ let placeholderText = placeholder;
106
+ let multipleSelectionProps = {
107
+ itemToKey,
108
+ initialSelectedItems: multiple ? initialSelectedOptions : initialSelectedOptions[0] ? [initialSelectedOptions[0]] : []
109
+ };
110
+ if (multiple) {
111
+ multipleSelectionProps = {
112
+ ...multipleSelectionProps,
113
+ onSelectedItemsChange: changes => {
114
+ if (onOptionsChange) {
115
+ let selectedItems = changes.selectedItems.filter(item => item !== AllSymbol || item !== AddSymbol);
116
+ if (itemCompare) {
117
+ selectedItems = inputOptions.filter(item => selectedItems.some(compare => itemCompare(item, compare)));
118
+ }
119
+ onOptionsChange({
120
+ selectedItems
121
+ });
122
+ }
123
+ }
124
+ };
125
+ if (isControlled) {
126
+ multipleSelectionProps = {
127
+ ...multipleSelectionProps,
128
+ selectedItems: selectedOptions
129
+ };
130
+ }
131
+ }
132
+ const {
133
+ getDropdownProps,
134
+ addSelectedItem,
135
+ removeSelectedItem,
136
+ selectedItems,
137
+ setSelectedItems
138
+ } = useMultipleSelection(multipleSelectionProps);
139
+ // MARK: select all logic
140
+ const enabledItems = useMemo(() => {
141
+ const disabledItemsSet = new Set(inputOptions.filter(optionDisabled));
142
+ return inputOptions.filter(x => !disabledItemsSet.has(x));
143
+ }, [inputOptions, optionDisabled]);
144
+ const allDisabled = enabledItems.length === 0;
145
+ const selectedDisabledItemsSet = useMemo(() => new Set(selectedItems.filter(x => x !== null && optionDisabled(x))), [selectedItems, optionDisabled]);
146
+ const selectedEnabledItems = useMemo(() => selectedItems.filter(x => !selectedDisabledItemsSet.has(x)), [selectedItems, selectedDisabledItemsSet]);
147
+ const allSelectedState = useMemo(() => {
148
+ if (!enabledItems || !selectedEnabledItems) return 'NONE';
149
+ if (enabledItems.length === selectedEnabledItems.length) return 'ALL';
150
+ if (enabledItems.length != selectedEnabledItems.length && selectedEnabledItems.length > 0) return 'SOME';
151
+ return 'NONE';
152
+ }, [enabledItems, selectedEnabledItems]);
153
+ const toggleAllSelected = () => {
154
+ if (selectedEnabledItems.length === enabledItems.length) {
155
+ setSelectedItems([...selectedDisabledItemsSet]);
156
+ } else {
157
+ setSelectedItems([...enabledItems, ...selectedDisabledItemsSet]);
158
+ }
159
+ };
160
+
161
+ // MARK: getLabel
162
+ const getLabel = useCallback(item => {
163
+ //note: non strict check for null or undefined to allow 0
164
+ if (item == null) {
165
+ return '';
166
+ }
167
+ if (optionLabel) {
168
+ return optionLabel(item);
169
+ } else if (typeof item === 'object') {
170
+ throw new Error('Missing label. When using objects for options make sure to define the `optionLabel` property');
171
+ }
172
+ if (typeof item === 'string') {
173
+ return item;
174
+ }
175
+ try {
176
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
177
+ return item?.toString();
178
+ } catch {
179
+ throw new Error('Unable to find label, make sure your are using options as documented');
180
+ }
181
+ }, [optionLabel]);
182
+
183
+ // MARK: setup virtualizer
184
+ const scrollContainer = useRef(null);
185
+ const rowVirtualizer = useVirtualizer({
186
+ count: availableItems.length,
187
+ getScrollElement: () => scrollContainer.current,
188
+ estimateSize: useCallback(() => {
189
+ return parseInt(token().entities.label.minHeight);
190
+ }, [token]),
191
+ overscan: 25
192
+ });
193
+
194
+ //https://github.com/TanStack/virtual/discussions/379#discussioncomment-3501037
195
+ useIsomorphicLayoutEffect(() => {
196
+ rowVirtualizer?.measure?.();
197
+ }, [rowVirtualizer, density]);
198
+
199
+ // MARK: downshift state
200
+ let comboBoxProps = {
201
+ items: availableItems,
202
+ //can not pass readonly type to downshift so we cast it to regular T[]
203
+ initialSelectedItem: initialSelectedOptions[0],
204
+ isItemDisabled(item) {
205
+ if (item === AddSymbol) return !typedInputValue.trim();
206
+ return optionDisabled(item);
207
+ },
208
+ itemToKey,
209
+ itemToString: getLabel,
210
+ onInputValueChange: ({
211
+ inputValue
212
+ }) => {
213
+ onInputChange && onInputChange(inputValue);
214
+ setAvailableItems(options.filter(item => {
215
+ if (optionsFilter) {
216
+ return optionsFilter(item, inputValue);
217
+ }
218
+ return getLabel(item).toLowerCase().includes(inputValue.toLowerCase());
219
+ }));
220
+ },
221
+ onHighlightedIndexChange({
222
+ highlightedIndex
223
+ }) {
224
+ if (highlightedIndex >= 0 && rowVirtualizer.getVirtualItems) {
225
+ const visibleIndexes = rowVirtualizer.getVirtualItems().map(v => v.index);
226
+ if (!visibleIndexes.includes(highlightedIndex)) {
227
+ rowVirtualizer.scrollToIndex(highlightedIndex, {
228
+ align: allowSelectAll ? 'center' : 'auto'
229
+ });
230
+ }
231
+ }
232
+ if (typeof rowVirtualizer.scrollOffset === 'number') {
233
+ setLastScrollOffset(rowVirtualizer.scrollOffset);
234
+ }
235
+ },
236
+ onIsOpenChange: ({
237
+ selectedItem
238
+ }) => {
239
+ if (!multiple && selectedItem !== null) {
240
+ setAvailableItems(options);
241
+ setTimeout(() => {
242
+ if (controlledHighlightedIndex === 0) {
243
+ rowVirtualizer.scrollToOffset?.(0);
244
+ } else if (rowVirtualizer.scrollToOffset && lastScrollOffset > 0) {
245
+ rowVirtualizer.scrollToOffset(lastScrollOffset);
246
+ }
247
+ const visibleIndexes = rowVirtualizer.getVirtualItems?.().map(v => v.index) || [];
248
+ if (!visibleIndexes.includes(controlledHighlightedIndex)) {
249
+ rowVirtualizer.scrollToIndex(controlledHighlightedIndex, {
250
+ align: allowSelectAll ? 'center' : 'auto'
251
+ });
252
+ }
253
+ }, 10);
254
+ }
255
+ },
256
+ onStateChange: ({
257
+ type,
258
+ selectedItem
259
+ }) => {
260
+ switch (type) {
261
+ case useCombobox.stateChangeTypes.InputChange:
262
+ case useCombobox.stateChangeTypes.InputBlur:
263
+ break;
264
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
265
+ case useCombobox.stateChangeTypes.ItemClick:
266
+ //note: non strict check for null or undefined to allow 0
267
+ if (selectedItem != null && !optionDisabled(selectedItem)) {
268
+ if (selectedItem === AllSymbol) {
269
+ toggleAllSelected();
270
+ } else if (selectedItem === AddSymbol && typedInputValue.trim()) {
271
+ onAddNewOption?.(typedInputValue);
272
+ } else if (multiple) {
273
+ const shouldRemove = itemCompare ? selectedItems.some(i => itemCompare(selectedItem, i)) : selectedItems.includes(selectedItem);
274
+ if (shouldRemove) {
275
+ removeSelectedItem(selectedItem);
276
+ } else {
277
+ addSelectedItem(selectedItem);
278
+ }
279
+ } else {
280
+ setSelectedItems([selectedItem]);
281
+ }
282
+ }
283
+ break;
284
+ }
285
+ }
286
+ };
287
+ // MARK: singleselect specific
288
+ if (!multiple) {
289
+ comboBoxProps = {
290
+ ...comboBoxProps,
291
+ onSelectedItemChange: changes => {
292
+ if (changes.selectedItem === AddSymbol) return;
293
+ const idx = getSelectedIndex(changes.selectedItem);
294
+ setControlledHighlightedIndex(idx >= 0 ? idx : 0);
295
+ if (onOptionsChange) {
296
+ let {
297
+ selectedItem
298
+ } = changes;
299
+ if (itemCompare) {
300
+ selectedItem = inputOptions.find(item => itemCompare(item, selectedItem));
301
+ }
302
+ onOptionsChange({
303
+ selectedItems: selectedItem ? [selectedItem] : []
304
+ });
305
+ }
306
+ },
307
+ stateReducer: (state, actionAndChanges) => {
308
+ const {
309
+ changes,
310
+ type
311
+ } = actionAndChanges;
312
+ switch (type) {
313
+ case useCombobox.stateChangeTypes.InputClick:
314
+ return {
315
+ ...changes,
316
+ isOpen: !(disabled || readOnly),
317
+ highlightedIndex: controlledHighlightedIndex
318
+ };
319
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
320
+ case useCombobox.stateChangeTypes.ItemClick:
321
+ {
322
+ if (changes.selectedItem === AddSymbol) {
323
+ return {
324
+ ...changes,
325
+ inputValue: ''
326
+ };
327
+ }
328
+ const idx = getSelectedIndex(changes.selectedItem);
329
+ setControlledHighlightedIndex(idx >= 0 ? idx : 0);
330
+ return {
331
+ ...changes,
332
+ highlightedIndex: idx >= 0 ? idx : 0
333
+ };
334
+ }
335
+ case useCombobox.stateChangeTypes.InputBlur:
336
+ return {
337
+ ...changes,
338
+ inputValue: changes.selectedItem ? getLabel(changes.selectedItem) : ''
339
+ };
340
+ case useCombobox.stateChangeTypes.InputChange:
341
+ setTypedInputValue(changes.inputValue);
342
+ return {
343
+ ...changes
344
+ };
345
+ case useCombobox.stateChangeTypes.InputKeyDownArrowDown:
346
+ if (readOnly) {
347
+ return {
348
+ ...changes,
349
+ isOpen: false
350
+ };
351
+ }
352
+ if (state.isOpen === false) {
353
+ return {
354
+ ...changes,
355
+ isOpen: true,
356
+ highlightedIndex: controlledHighlightedIndex
357
+ };
358
+ }
359
+ return {
360
+ ...changes,
361
+ highlightedIndex: findNextIndex({
362
+ index: changes.highlightedIndex,
363
+ availableItems,
364
+ optionDisabled,
365
+ allDisabled
366
+ })
367
+ };
368
+ case useCombobox.stateChangeTypes.InputKeyDownHome:
369
+ if (readOnly) {
370
+ return {
371
+ ...changes,
372
+ isOpen: false
373
+ };
374
+ }
375
+ return {
376
+ ...changes,
377
+ highlightedIndex: findNextIndex({
378
+ index: 0,
379
+ availableItems,
380
+ optionDisabled,
381
+ allDisabled
382
+ })
383
+ };
384
+ case useCombobox.stateChangeTypes.InputKeyDownArrowUp:
385
+ if (readOnly) {
386
+ return {
387
+ ...changes,
388
+ isOpen: false
389
+ };
390
+ }
391
+ if (state.isOpen === false) {
392
+ return {
393
+ ...changes,
394
+ isOpen: true,
395
+ highlightedIndex: controlledHighlightedIndex
396
+ };
397
+ }
398
+ return {
399
+ ...changes,
400
+ highlightedIndex: findPrevIndex({
401
+ index: changes.highlightedIndex,
402
+ availableItems,
403
+ optionDisabled,
404
+ allDisabled
405
+ })
406
+ };
407
+ case useCombobox.stateChangeTypes.InputKeyDownEnd:
408
+ if (readOnly) {
409
+ return {
410
+ ...changes,
411
+ isOpen: false
412
+ };
413
+ }
414
+ return {
415
+ ...changes,
416
+ highlightedIndex: findPrevIndex({
417
+ index: availableItems.length - 1,
418
+ availableItems,
419
+ optionDisabled,
420
+ allDisabled
421
+ })
422
+ };
423
+ case useCombobox.stateChangeTypes.ControlledPropUpdatedSelectedItem:
424
+ setSelectedItems([changes.selectedItem]);
425
+ return {
426
+ ...changes,
427
+ highlightedIndex: controlledHighlightedIndex
428
+ };
429
+ default:
430
+ return changes;
431
+ }
432
+ }
433
+ };
434
+ if (isControlled) {
435
+ comboBoxProps = {
436
+ ...comboBoxProps,
437
+ selectedItem: selectedOptions[0] || null
438
+ };
439
+ }
440
+ }
441
+ // MARK: multiselect specific
442
+ if (multiple) {
443
+ const showPlaceholder = placeholderText && selectedItems.length === 0;
444
+ const optionCount = totalOptions || inputOptions.length;
445
+ placeholderText = showPlaceholder ? placeholderText : `${selectedItems.length}/${optionCount} selected`;
446
+ if (selectionDisplay === 'chips') placeholderText = placeholder;
447
+ comboBoxProps = {
448
+ ...comboBoxProps,
449
+ selectedItem: null,
450
+ stateReducer: (state, actionAndChanges) => {
451
+ const {
452
+ changes,
453
+ type
454
+ } = actionAndChanges;
455
+ switch (type) {
456
+ case useCombobox.stateChangeTypes.InputClick:
457
+ return {
458
+ ...changes,
459
+ isOpen: !(disabled || readOnly)
460
+ };
461
+ case useCombobox.stateChangeTypes.InputKeyDownArrowDown:
462
+ case useCombobox.stateChangeTypes.InputKeyDownHome:
463
+ if (readOnly) {
464
+ return {
465
+ ...changes,
466
+ isOpen: false
467
+ };
468
+ }
469
+ return {
470
+ ...changes,
471
+ highlightedIndex: findNextIndex({
472
+ index: changes.highlightedIndex,
473
+ availableItems,
474
+ optionDisabled,
475
+ allDisabled
476
+ })
477
+ };
478
+ case useCombobox.stateChangeTypes.InputKeyDownArrowUp:
479
+ case useCombobox.stateChangeTypes.InputKeyDownEnd:
480
+ if (readOnly) {
481
+ return {
482
+ ...changes,
483
+ isOpen: false
484
+ };
485
+ }
486
+ return {
487
+ ...changes,
488
+ highlightedIndex: findPrevIndex({
489
+ index: changes.highlightedIndex,
490
+ availableItems,
491
+ optionDisabled,
492
+ allDisabled
493
+ })
494
+ };
495
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
496
+ case useCombobox.stateChangeTypes.ItemClick:
497
+ if (clearSearchOnChange) {
498
+ setTypedInputValue('');
499
+ }
500
+ return {
501
+ ...changes,
502
+ isOpen: true,
503
+ // keep menu open after selection.
504
+ highlightedIndex: state.highlightedIndex,
505
+ inputValue: !clearSearchOnChange ? typedInputValue : ''
506
+ };
507
+ case useCombobox.stateChangeTypes.InputChange:
508
+ setTypedInputValue(changes.inputValue);
509
+ return {
510
+ ...changes
511
+ };
512
+ case useCombobox.stateChangeTypes.InputBlur:
513
+ setTypedInputValue('');
514
+ return {
515
+ ...changes,
516
+ inputValue: ''
517
+ };
518
+ case useCombobox.stateChangeTypes.ControlledPropUpdatedSelectedItem:
519
+ return {
520
+ ...changes,
521
+ inputValue: !clearSearchOnChange ? typedInputValue : changes.inputValue
522
+ };
523
+ default:
524
+ return changes;
525
+ }
526
+ }
527
+ };
528
+ }
529
+ const _comboBoxProps = useCombobox(comboBoxProps);
530
+ const clear = () => {
531
+ if (onClear) onClear();
532
+ _comboBoxProps.reset();
533
+ //dont clear items if they are selected and disabled
534
+ setSelectedItems([...selectedDisabledItemsSet]);
535
+ setTypedInputValue('');
536
+ inputRef.current?.focus();
537
+ };
538
+ const inputProps = _comboBoxProps.getInputProps(getDropdownProps({
539
+ preventKeyAction: multiple ? _comboBoxProps.isOpen : undefined,
540
+ disabled,
541
+ ref: inputRef
542
+ }));
543
+ const consolidatedEvents = mergeEventsFromRight(other, inputProps);
544
+ const selectedItemsLabels = useMemo(() => selectedItems.map(getLabel), [selectedItems, getLabel]);
545
+ return {
546
+ ..._comboBoxProps,
547
+ getDropdownProps,
548
+ addSelectedItem,
549
+ removeSelectedItem,
550
+ selectedItems,
551
+ setSelectedItems,
552
+ clear,
553
+ availableItems,
554
+ getLabel,
555
+ scrollContainer,
556
+ rowVirtualizer,
557
+ allSelectedState,
558
+ toggleAllSelected,
559
+ typedInputValue,
560
+ inputRef,
561
+ token,
562
+ tokens,
563
+ placeholderText,
564
+ readOnly,
565
+ inputProps,
566
+ consolidatedEvents,
567
+ multiple,
568
+ disabled,
569
+ optionDisabled,
570
+ onAddNewOption,
571
+ options,
572
+ totalOptions,
573
+ label,
574
+ meta,
575
+ className,
576
+ style,
577
+ loading,
578
+ hideClearButton,
579
+ onOptionsChange,
580
+ onInputChange,
581
+ selectedOptions,
582
+ selectionDisplay,
583
+ itemToKey,
584
+ itemCompare,
585
+ allowSelectAll,
586
+ initialSelectedOptions,
587
+ optionsFilter,
588
+ autoWidth,
589
+ placeholder,
590
+ optionLabel,
591
+ clearSearchOnChange,
592
+ multiline,
593
+ dropdownHeight,
594
+ optionComponent,
595
+ helperText,
596
+ helperIcon,
597
+ noOptionsText,
598
+ variant,
599
+ onClear,
600
+ selectedItemsLabels,
601
+ restHtmlProps: other
602
+ };
603
+ };
604
+
605
+ export { useAutocomplete };
@@ -0,0 +1,93 @@
1
+ import pickBy from '../../node_modules/.pnpm/ramda@0.32.0/node_modules/ramda/es/pickBy.js';
2
+ import mergeWith from '../../node_modules/.pnpm/ramda@0.32.0/node_modules/ramda/es/mergeWith.js';
3
+
4
+ const findIndex = ({
5
+ calc,
6
+ index,
7
+ optionDisabled,
8
+ availableItems
9
+ }) => {
10
+ const nextItem = availableItems[index];
11
+ if (optionDisabled(nextItem) && index >= 0 && index < availableItems.length) {
12
+ const nextIndex = calc(index);
13
+ return findIndex({
14
+ calc,
15
+ index: nextIndex,
16
+ availableItems,
17
+ optionDisabled
18
+ });
19
+ }
20
+ return index;
21
+ };
22
+ const findNextIndex = ({
23
+ index,
24
+ optionDisabled,
25
+ availableItems,
26
+ allDisabled
27
+ }) => {
28
+ if (allDisabled) return 0;
29
+ const options = {
30
+ index,
31
+ optionDisabled,
32
+ availableItems,
33
+ calc: num => num + 1
34
+ };
35
+ const nextIndex = findIndex(options);
36
+ if (nextIndex > availableItems.length - 1) {
37
+ // jump to start of list
38
+ return findIndex({
39
+ ...options,
40
+ index: 0
41
+ });
42
+ }
43
+ return nextIndex;
44
+ };
45
+ const findPrevIndex = ({
46
+ index,
47
+ optionDisabled,
48
+ availableItems,
49
+ allDisabled
50
+ }) => {
51
+ if (allDisabled) return 0;
52
+ const options = {
53
+ index,
54
+ optionDisabled,
55
+ availableItems,
56
+ calc: num => num - 1
57
+ };
58
+ const prevIndex = findIndex(options);
59
+ if (prevIndex < 0) {
60
+ // jump to end of list
61
+ return findIndex({
62
+ ...options,
63
+ index: availableItems.length - 1
64
+ });
65
+ }
66
+ return prevIndex;
67
+ };
68
+ const isEvent = (val, key) => /^on[A-Z](.*)/.test(key) && typeof val === 'function';
69
+ function mergeEventsFromRight(props1, props2) {
70
+ const events1 = pickBy(isEvent, props1);
71
+ const events2 = pickBy(isEvent, props2);
72
+ return mergeWith((event1, event2) => {
73
+ return (...args) => {
74
+ event1(...args);
75
+ event2(...args);
76
+ };
77
+ }, events1, events2);
78
+ }
79
+
80
+ /*When a user clicks the StyledList scrollbar, the input loses focus which breaks downshift
81
+ * keyboard navigation in the list. This code returns focus to the input on mouseUp
82
+ */
83
+ const handleListFocus = e => {
84
+ e.preventDefault();
85
+ e.stopPropagation();
86
+ window?.addEventListener('mouseup', () => {
87
+ e.relatedTarget?.focus();
88
+ }, {
89
+ once: true
90
+ });
91
+ };
92
+
93
+ export { findNextIndex, findPrevIndex, handleListFocus, mergeEventsFromRight };