@snack-uikit/fields 0.16.1 → 0.17.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 +18 -0
- package/README.md +11 -0
- package/dist/components/FieldDecorator/utils.d.ts +15 -0
- package/dist/components/FieldDecorator/utils.js +16 -0
- package/dist/components/FieldSelect/FieldSelectMultiple.d.ts +6 -1
- package/dist/components/FieldSelect/FieldSelectMultiple.js +56 -27
- package/dist/components/FieldSelect/FieldSelectSingle.d.ts +4 -1
- package/dist/components/FieldSelect/FieldSelectSingle.js +45 -20
- package/dist/components/FieldSelect/hooks.d.ts +2 -2
- package/dist/components/FieldSelect/hooks.js +11 -11
- package/dist/components/FieldSelect/types.d.ts +10 -3
- package/dist/components/FieldSelect/utils.d.ts +7 -4
- package/dist/components/FieldSelect/utils.js +59 -49
- package/dist/components/FieldSlider/helpers/generateAllowedValues.js +1 -1
- package/dist/hooks/useValueControl.js +1 -1
- package/package.json +5 -5
- package/src/components/FieldDecorator/utils.ts +31 -0
- package/src/components/FieldSelect/FieldSelectMultiple.tsx +90 -60
- package/src/components/FieldSelect/FieldSelectSingle.tsx +54 -39
- package/src/components/FieldSelect/hooks.ts +17 -13
- package/src/components/FieldSelect/types.ts +18 -4
- package/src/components/FieldSelect/utils.ts +89 -65
- package/src/components/FieldSlider/helpers/generateAllowedValues.ts +1 -1
- package/src/hooks/useValueControl.ts +1 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import mergeRefs from 'merge-refs';
|
|
2
|
-
import { forwardRef, KeyboardEvent, KeyboardEventHandler, useEffect, useMemo, useRef
|
|
2
|
+
import { FocusEvent, forwardRef, KeyboardEvent, KeyboardEventHandler, useEffect, useMemo, useRef } from 'react';
|
|
3
3
|
|
|
4
4
|
import { InputPrivate } from '@snack-uikit/input-private';
|
|
5
|
-
import { Droplist, SelectionSingleValueType, useFuzzySearch } from '@snack-uikit/list';
|
|
5
|
+
import { Droplist, ItemProps, SelectionSingleValueType, useFuzzySearch } from '@snack-uikit/list';
|
|
6
6
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
7
7
|
|
|
8
8
|
import { FieldContainerPrivate } from '../../helperComponents';
|
|
9
9
|
import { useValueControl } from '../../hooks';
|
|
10
10
|
import { FieldDecorator } from '../FieldDecorator';
|
|
11
|
+
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
11
12
|
import { useButtons, useHandleOnKeyDown, useSearchInput } from './hooks';
|
|
12
13
|
import styles from './styles.module.scss';
|
|
13
14
|
import { FieldSelectSingleProps } from './types';
|
|
14
|
-
import {
|
|
15
|
+
import { extractListProps, findSelectedOption, getArrowIcon, transformOptionsToItems } from './utils';
|
|
15
16
|
|
|
16
17
|
export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleProps>(
|
|
17
18
|
(
|
|
@@ -24,31 +25,26 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
24
25
|
value: valueProp,
|
|
25
26
|
defaultValue,
|
|
26
27
|
onChange: onChangeProp,
|
|
27
|
-
loading,
|
|
28
28
|
disabled = false,
|
|
29
29
|
readonly = false,
|
|
30
30
|
searchable = true,
|
|
31
31
|
showCopyButton = true,
|
|
32
32
|
showClearButton = true,
|
|
33
33
|
onKeyDown: onInputKeyDownProp,
|
|
34
|
-
label,
|
|
35
|
-
labelTooltip,
|
|
36
|
-
labelTooltipPlacement,
|
|
37
34
|
required = false,
|
|
38
|
-
hint,
|
|
39
|
-
showHintIcon,
|
|
40
35
|
validationState = 'default',
|
|
41
|
-
footer,
|
|
42
36
|
search,
|
|
43
37
|
autocomplete = false,
|
|
44
38
|
prefixIcon,
|
|
45
|
-
|
|
39
|
+
addOptionByEnter = false,
|
|
40
|
+
open: openProp,
|
|
41
|
+
onOpenChange,
|
|
46
42
|
...rest
|
|
47
43
|
},
|
|
48
44
|
ref,
|
|
49
45
|
) => {
|
|
50
46
|
const localRef = useRef<HTMLInputElement>(null);
|
|
51
|
-
const [open, setOpen] =
|
|
47
|
+
const [open = false, setOpen] = useValueControl<boolean>({ value: openProp, onChange: onOpenChange });
|
|
52
48
|
const [value, setValue] = useValueControl<SelectionSingleValueType>({
|
|
53
49
|
value: valueProp,
|
|
54
50
|
defaultValue,
|
|
@@ -56,22 +52,34 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
56
52
|
});
|
|
57
53
|
|
|
58
54
|
const items = useMemo(() => transformOptionsToItems(options), [options]);
|
|
59
|
-
const
|
|
55
|
+
const { selected, itemsWithPlaceholder } = useMemo(() => {
|
|
56
|
+
const [fonded, placeholder] = findSelectedOption(items, value);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
selected: fonded ?? placeholder,
|
|
60
|
+
itemsWithPlaceholder: ((placeholder ? [placeholder] : []) as ItemProps[]).concat(items),
|
|
61
|
+
};
|
|
62
|
+
}, [items, value]);
|
|
60
63
|
|
|
61
64
|
const { inputValue, onInputValueChange, prevInputValue } = useSearchInput({
|
|
62
65
|
...search,
|
|
63
|
-
defaultValue:
|
|
66
|
+
defaultValue: selected?.content.option ?? '',
|
|
64
67
|
});
|
|
65
68
|
|
|
66
69
|
useEffect(() => {
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
if (selected?.content.option && prevInputValue.current !== selected?.content.option) {
|
|
71
|
+
onInputValueChange(selected.content.option);
|
|
72
|
+
prevInputValue.current = selected?.content.option;
|
|
73
|
+
}
|
|
74
|
+
}, [onInputValueChange, selected?.content.option, prevInputValue]);
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
const handleBlur = (e: FocusEvent<HTMLInputElement>) => {
|
|
77
|
+
if (!open && selected?.content.option !== inputValue) {
|
|
78
|
+
onInputValueChange(selected?.content.option ?? '');
|
|
79
|
+
}
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
}
|
|
81
|
+
rest?.onBlur?.(e);
|
|
82
|
+
};
|
|
75
83
|
|
|
76
84
|
const onClear = () => {
|
|
77
85
|
setValue('');
|
|
@@ -86,11 +94,11 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
86
94
|
const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
|
|
87
95
|
readonly,
|
|
88
96
|
size,
|
|
89
|
-
showClearButton: showClearButton && Boolean(value),
|
|
97
|
+
showClearButton: showClearButton && !disabled && !readonly && Boolean(value),
|
|
90
98
|
showCopyButton,
|
|
91
99
|
inputRef: localRef,
|
|
92
100
|
onClear,
|
|
93
|
-
valueToCopy:
|
|
101
|
+
valueToCopy: selected?.content.option ?? '',
|
|
94
102
|
});
|
|
95
103
|
|
|
96
104
|
const commonHandleOnKeyDown = useHandleOnKeyDown({
|
|
@@ -104,6 +112,15 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
104
112
|
setOpen(true);
|
|
105
113
|
}
|
|
106
114
|
|
|
115
|
+
if (e.code === 'Enter') {
|
|
116
|
+
e.stopPropagation();
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
|
|
121
|
+
setValue(inputValue);
|
|
122
|
+
}
|
|
123
|
+
|
|
107
124
|
commonHandleOnKeyDown(onKeyDown)(e);
|
|
108
125
|
};
|
|
109
126
|
|
|
@@ -119,37 +136,34 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
119
136
|
const handleOpenChange = (open: boolean) => {
|
|
120
137
|
if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
|
|
121
138
|
setOpen(open);
|
|
139
|
+
|
|
140
|
+
if (!open) {
|
|
141
|
+
onInputValueChange(selected?.content.option ?? '');
|
|
142
|
+
prevInputValue.current = selected?.content.option ?? '';
|
|
143
|
+
}
|
|
122
144
|
}
|
|
123
145
|
};
|
|
124
146
|
|
|
125
|
-
const fuzzySearch = useFuzzySearch(
|
|
126
|
-
const result =
|
|
147
|
+
const fuzzySearch = useFuzzySearch(itemsWithPlaceholder);
|
|
148
|
+
const result =
|
|
149
|
+
autocomplete || !searchable || prevInputValue.current === inputValue
|
|
150
|
+
? itemsWithPlaceholder
|
|
151
|
+
: fuzzySearch(inputValue);
|
|
127
152
|
|
|
128
153
|
return (
|
|
129
154
|
<FieldDecorator
|
|
130
155
|
{...extractSupportProps(rest)}
|
|
131
|
-
|
|
156
|
+
{...extractFieldDecoratorProps(rest)}
|
|
157
|
+
validationState={validationState}
|
|
132
158
|
required={required}
|
|
133
159
|
readonly={readonly}
|
|
134
|
-
label={label}
|
|
135
|
-
labelTooltip={labelTooltip}
|
|
136
|
-
labelTooltipPlacement={labelTooltipPlacement}
|
|
137
160
|
labelFor={id}
|
|
138
|
-
hint={hint}
|
|
139
161
|
disabled={disabled}
|
|
140
|
-
showHintIcon={showHintIcon}
|
|
141
162
|
size={size}
|
|
142
|
-
validationState={validationState}
|
|
143
163
|
>
|
|
144
164
|
<Droplist
|
|
145
|
-
|
|
146
|
-
placement='bottom'
|
|
147
|
-
data-test-id='field-select__list'
|
|
165
|
+
{...extractListProps(rest)}
|
|
148
166
|
items={result}
|
|
149
|
-
triggerElemRef={localRef}
|
|
150
|
-
scroll
|
|
151
|
-
marker
|
|
152
|
-
footer={footer}
|
|
153
167
|
selection={{
|
|
154
168
|
mode: 'single',
|
|
155
169
|
value: value,
|
|
@@ -158,7 +172,7 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
158
172
|
size={size}
|
|
159
173
|
open={open}
|
|
160
174
|
onOpenChange={handleOpenChange}
|
|
161
|
-
|
|
175
|
+
triggerElemRef={localRef}
|
|
162
176
|
>
|
|
163
177
|
{({ onKeyDown }) => (
|
|
164
178
|
<FieldContainerPrivate
|
|
@@ -184,6 +198,7 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
184
198
|
readonly={!searchable || readonly}
|
|
185
199
|
data-test-id='field-select__input'
|
|
186
200
|
onKeyDown={handleOnKeyDown(onKeyDown)}
|
|
201
|
+
onBlur={handleBlur}
|
|
187
202
|
/>
|
|
188
203
|
|
|
189
204
|
<div className={styles.postfix}>
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { KeyboardEvent, KeyboardEventHandler, RefObject, useCallback, useMemo, useRef } from 'react';
|
|
2
|
-
import { Handler
|
|
2
|
+
import { Handler } from 'uncontrollable';
|
|
3
3
|
|
|
4
4
|
import { useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
extractChildIds,
|
|
7
|
+
isAccordionItemProps,
|
|
8
|
+
isNextListItemProps,
|
|
9
|
+
SelectionSingleValueType,
|
|
10
|
+
} from '@snack-uikit/list';
|
|
7
11
|
|
|
8
|
-
import { useCopyButton } from '../../hooks';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
12
|
+
import { useCopyButton, useValueControl } from '../../hooks';
|
|
13
|
+
import { ItemWithId, SearchState } from './types';
|
|
14
|
+
import { isBaseOptionProps } from './utils';
|
|
11
15
|
|
|
12
16
|
type UseHandleOnKeyDownProps = {
|
|
13
17
|
inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
|
|
@@ -95,7 +99,7 @@ export function useButtons({
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
export function useSearchInput({ value, onChange, defaultValue }: SearchState) {
|
|
98
|
-
const [inputValue, onInputValueChange] =
|
|
102
|
+
const [inputValue = '', onInputValueChange] = useValueControl<string>({ value, onChange, defaultValue });
|
|
99
103
|
|
|
100
104
|
const prevInputValue = useRef<string>(inputValue);
|
|
101
105
|
|
|
@@ -104,20 +108,20 @@ export function useSearchInput({ value, onChange, defaultValue }: SearchState) {
|
|
|
104
108
|
|
|
105
109
|
export function useHandleDeleteItem(setValue: Handler) {
|
|
106
110
|
return useCallback(
|
|
107
|
-
(
|
|
108
|
-
if (!
|
|
111
|
+
(item?: ItemWithId) => () => {
|
|
112
|
+
if (!item) {
|
|
109
113
|
return;
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
if (
|
|
113
|
-
const removeIds = extractChildIds({ items:
|
|
116
|
+
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
117
|
+
const removeIds = extractChildIds({ items: item.items }).concat(item.id ?? '');
|
|
114
118
|
|
|
115
119
|
setValue((value: SelectionSingleValueType[]) => value?.filter(v => !removeIds.includes(v ?? '')));
|
|
116
120
|
return;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
if (isBaseOptionProps(
|
|
120
|
-
setValue((value: SelectionSingleValueType[]) => value?.filter(v => v !==
|
|
123
|
+
if (isBaseOptionProps(item)) {
|
|
124
|
+
setValue((value: SelectionSingleValueType[]) => value?.filter(v => v !== item.id));
|
|
121
125
|
}
|
|
122
126
|
},
|
|
123
127
|
[setValue],
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SelectionMultipleState,
|
|
11
11
|
SelectionSingleState,
|
|
12
12
|
} from '@snack-uikit/list';
|
|
13
|
+
import { TagProps } from '@snack-uikit/tag';
|
|
13
14
|
import { WithSupportProps } from '@snack-uikit/utils';
|
|
14
15
|
|
|
15
16
|
import { FieldDecoratorProps } from '../FieldDecorator';
|
|
@@ -21,7 +22,7 @@ export type OptionProps = BaseOptionProps | AccordionOptionProps | GroupOptionPr
|
|
|
21
22
|
export type OptionWithoutGroup = BaseOptionProps | AccordionOptionProps | NestListOptionProps;
|
|
22
23
|
|
|
23
24
|
export type BaseOptionProps = Pick<BaseItemProps, 'beforeContent' | 'afterContent' | 'disabled'> &
|
|
24
|
-
BaseItemProps['content'] & { value: string | number }
|
|
25
|
+
BaseItemProps['content'] & { value: string | number } & Pick<TagProps, 'appearance'>;
|
|
25
26
|
|
|
26
27
|
export type AccordionOptionProps = Pick<AccordionItemProps, 'type'> & BaseOptionProps & { options: OptionProps[] };
|
|
27
28
|
export type GroupOptionProps = Omit<GroupItemProps, 'items' | 'id'> & { options: OptionProps[] };
|
|
@@ -78,17 +79,30 @@ type FiledSelectCommonProps = WithSupportProps<{
|
|
|
78
79
|
search?: SearchState;
|
|
79
80
|
|
|
80
81
|
autocomplete?: boolean;
|
|
81
|
-
|
|
82
|
+
|
|
83
|
+
addOptionByEnter?: boolean;
|
|
84
|
+
|
|
85
|
+
open?: boolean;
|
|
86
|
+
onOpenChange?(open: boolean): void;
|
|
87
|
+
}> &
|
|
88
|
+
Pick<
|
|
89
|
+
ListProps,
|
|
90
|
+
'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'pinTop' | 'pinBottom' | 'dataFiltered'
|
|
91
|
+
>;
|
|
82
92
|
|
|
83
93
|
export type FieldSelectSingleProps = FieldSelectPrivateProps &
|
|
84
94
|
Omit<SelectionSingleState, 'mode'> &
|
|
85
95
|
WrapperProps &
|
|
86
96
|
FiledSelectCommonProps;
|
|
87
97
|
|
|
88
|
-
export type FieldSelectMultipleProps = FieldSelectPrivateProps &
|
|
89
|
-
|
|
98
|
+
export type FieldSelectMultipleProps = FieldSelectPrivateProps & { removeByBackspace?: boolean } & Omit<
|
|
99
|
+
SelectionMultipleState,
|
|
100
|
+
'mode'
|
|
101
|
+
> &
|
|
90
102
|
Omit<FiledSelectCommonProps, 'showCopyButton'>;
|
|
91
103
|
|
|
92
104
|
export type FieldSelectProps =
|
|
93
105
|
| (FieldSelectSingleProps & { selection?: 'single' })
|
|
94
106
|
| (FieldSelectMultipleProps & { selection: 'multiple' });
|
|
107
|
+
|
|
108
|
+
export type ItemWithId = BaseItemProps | AccordionItemProps | NextListItemProps;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { ChevronDownSVG, ChevronUpSVG } from '@snack-uikit/icons';
|
|
2
2
|
import { ICON_SIZE, SIZE, Size } from '@snack-uikit/input-private';
|
|
3
|
-
import { ItemProps } from '@snack-uikit/list';
|
|
3
|
+
import { DroplistProps, flattenItems, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
4
|
+
import { TagProps } from '@snack-uikit/tag';
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
AccordionOptionProps,
|
|
7
8
|
BaseOptionProps,
|
|
8
9
|
FieldSelectMultipleProps,
|
|
10
|
+
FieldSelectProps,
|
|
9
11
|
FieldSelectSingleProps,
|
|
10
12
|
GroupOptionProps,
|
|
13
|
+
ItemWithId,
|
|
11
14
|
NestListOptionProps,
|
|
12
15
|
OptionProps,
|
|
13
|
-
OptionWithoutGroup,
|
|
14
16
|
} from './types';
|
|
15
17
|
|
|
16
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -33,6 +35,34 @@ export function isGroupOptionProps(option: any): option is GroupOptionProps {
|
|
|
33
35
|
return 'options' in option && option['type'] === undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
export function mapOptionToAppearance(
|
|
39
|
+
options: OptionProps[],
|
|
40
|
+
): Record<string | number, TagProps['appearance'] | undefined> {
|
|
41
|
+
let mapOption2Appearance: Record<string | number, TagProps['appearance'] | undefined> = {};
|
|
42
|
+
|
|
43
|
+
options.forEach(option => {
|
|
44
|
+
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
45
|
+
const { options, value, appearance } = option;
|
|
46
|
+
|
|
47
|
+
mapOption2Appearance = { ...mapOption2Appearance, [value]: appearance, ...mapOptionToAppearance(options) };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (isGroupOptionProps(option)) {
|
|
51
|
+
const { options } = option;
|
|
52
|
+
|
|
53
|
+
mapOption2Appearance = { ...mapOption2Appearance, ...mapOptionToAppearance(options) };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const { value, appearance } = option as BaseOptionProps;
|
|
57
|
+
|
|
58
|
+
if (value !== undefined) {
|
|
59
|
+
mapOption2Appearance = { ...mapOption2Appearance, [value]: appearance };
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return mapOption2Appearance;
|
|
64
|
+
}
|
|
65
|
+
|
|
36
66
|
export function transformOptionsToItems(options: OptionProps[]): ItemProps[] {
|
|
37
67
|
return options.map(option => {
|
|
38
68
|
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
@@ -67,82 +97,49 @@ export function transformOptionsToItems(options: OptionProps[]): ItemProps[] {
|
|
|
67
97
|
});
|
|
68
98
|
}
|
|
69
99
|
|
|
70
|
-
export function
|
|
71
|
-
|
|
72
|
-
value:
|
|
73
|
-
):
|
|
74
|
-
|
|
75
|
-
const option = options[i];
|
|
76
|
-
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
77
|
-
const { value: optionValue } = option;
|
|
78
|
-
|
|
79
|
-
if (optionValue === value) {
|
|
80
|
-
return option;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const selectedOptionFromNestedOptions = extractSelectedOptions(option.options, value);
|
|
84
|
-
|
|
85
|
-
if (selectedOptionFromNestedOptions) {
|
|
86
|
-
return selectedOptionFromNestedOptions;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
100
|
+
export function findSelectedOption(
|
|
101
|
+
items: ItemProps[],
|
|
102
|
+
value: SelectionSingleValueType,
|
|
103
|
+
): [ItemWithId | undefined, ItemWithId | undefined] {
|
|
104
|
+
const flatten: ItemWithId[] = flattenItems(items);
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (selectedOptionFromNestedOptions) {
|
|
94
|
-
return selectedOptionFromNestedOptions;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (isBaseOptionProps(option)) {
|
|
99
|
-
if (option.value === value) {
|
|
100
|
-
return option;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
106
|
+
if (!value) {
|
|
107
|
+
return [undefined, undefined];
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function extractSelectedMultipleOptions(
|
|
109
|
-
options: OptionProps[],
|
|
110
|
-
value?: (string | number | undefined)[],
|
|
111
|
-
): OptionWithoutGroup[] | undefined {
|
|
112
|
-
let selectedOptions: OptionWithoutGroup[] = [];
|
|
110
|
+
const foundItem = flatten.find(item => String(item.id) === String(value));
|
|
111
|
+
const placeholderItem = { id: value, content: { option: String(value) } };
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
117
|
-
const { value: optionValue } = option;
|
|
118
|
-
|
|
119
|
-
if (value?.includes(optionValue)) {
|
|
120
|
-
selectedOptions.push(option);
|
|
121
|
-
}
|
|
113
|
+
return [foundItem, !foundItem ? placeholderItem : undefined];
|
|
114
|
+
}
|
|
122
115
|
|
|
123
|
-
|
|
116
|
+
export function findSelectedOptions(
|
|
117
|
+
items: ItemProps[],
|
|
118
|
+
value: SelectionSingleValueType[] | undefined,
|
|
119
|
+
): [ItemWithId[] | undefined, ItemWithId[] | undefined] {
|
|
120
|
+
const flatten: ItemWithId[] | undefined = flattenItems(items);
|
|
124
121
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
122
|
+
if (!value || !value?.length) {
|
|
123
|
+
return [undefined, undefined];
|
|
124
|
+
}
|
|
129
125
|
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
let foundItems: ItemWithId[] | undefined;
|
|
127
|
+
let placeholderItems: ItemWithId[] | undefined;
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
value.forEach(value => {
|
|
130
|
+
if (flatten) {
|
|
131
|
+
const [found, placeholder] = findSelectedOption(flatten, value);
|
|
132
|
+
if (found || foundItems) {
|
|
133
|
+
foundItems = (foundItems ?? []).concat(found ?? []);
|
|
135
134
|
}
|
|
136
|
-
}
|
|
137
135
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
selectedOptions.push(option);
|
|
136
|
+
if (placeholder || placeholderItems) {
|
|
137
|
+
placeholderItems = (placeholderItems ?? []).concat(placeholder ?? []);
|
|
141
138
|
}
|
|
142
139
|
}
|
|
143
|
-
}
|
|
140
|
+
});
|
|
144
141
|
|
|
145
|
-
return
|
|
142
|
+
return [foundItems, placeholderItems];
|
|
146
143
|
}
|
|
147
144
|
|
|
148
145
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -161,3 +158,30 @@ export function getArrowIcon({ size, open }: { size: Size; open: boolean }) {
|
|
|
161
158
|
arrowIconSize: size === SIZE.S ? ICON_SIZE.Xs : ICON_SIZE.S,
|
|
162
159
|
};
|
|
163
160
|
}
|
|
161
|
+
|
|
162
|
+
export function extractListProps({
|
|
163
|
+
dataError,
|
|
164
|
+
noDataState,
|
|
165
|
+
noResultsState,
|
|
166
|
+
errorDataState,
|
|
167
|
+
pinTop,
|
|
168
|
+
pinBottom,
|
|
169
|
+
dataFiltered,
|
|
170
|
+
loading,
|
|
171
|
+
}: Partial<FieldSelectProps>): Partial<DroplistProps> {
|
|
172
|
+
return {
|
|
173
|
+
dataError,
|
|
174
|
+
noDataState,
|
|
175
|
+
noResultsState,
|
|
176
|
+
errorDataState,
|
|
177
|
+
pinTop,
|
|
178
|
+
pinBottom,
|
|
179
|
+
dataFiltered,
|
|
180
|
+
loading,
|
|
181
|
+
trigger: 'clickAndFocusVisible',
|
|
182
|
+
placement: 'bottom',
|
|
183
|
+
'data-test-id': 'field-select__list',
|
|
184
|
+
scroll: true,
|
|
185
|
+
marker: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -7,7 +7,7 @@ type UseValueControl<TValue> = {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export function useValueControl<TValue>({ value, onChange, defaultValue }: UseValueControl<TValue>) {
|
|
10
|
-
return useUncontrolledProp<TValue>(value,
|
|
10
|
+
return useUncontrolledProp<TValue>(value, defaultValue, (newValue: TValue) => {
|
|
11
11
|
const newState = typeof newValue === 'function' ? newValue(value) : newValue;
|
|
12
12
|
|
|
13
13
|
onChange?.(newState);
|