@snack-uikit/fields 0.16.1-preview-3bc93fc3.0 → 0.16.1
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 +9 -0
- package/README.md +0 -11
- package/dist/components/FieldSelect/FieldSelectMultiple.d.ts +1 -6
- package/dist/components/FieldSelect/FieldSelectMultiple.js +26 -51
- package/dist/components/FieldSelect/FieldSelectSingle.d.ts +1 -4
- package/dist/components/FieldSelect/FieldSelectSingle.js +20 -45
- package/dist/components/FieldSelect/hooks.d.ts +2 -2
- package/dist/components/FieldSelect/hooks.js +11 -11
- package/dist/components/FieldSelect/types.d.ts +2 -8
- package/dist/components/FieldSelect/utils.d.ts +4 -5
- package/dist/components/FieldSelect/utils.js +49 -41
- package/dist/hooks/useValueControl.js +1 -1
- package/package.json +5 -5
- package/src/components/FieldSelect/FieldSelectMultiple.tsx +58 -73
- package/src/components/FieldSelect/FieldSelectSingle.tsx +39 -54
- package/src/components/FieldSelect/hooks.ts +13 -17
- package/src/components/FieldSelect/types.ts +3 -16
- package/src/components/FieldSelect/utils.ts +65 -60
- package/src/hooks/useValueControl.ts +1 -1
- package/dist/components/FieldDecorator/utils.d.ts +0 -15
- package/dist/components/FieldDecorator/utils.js +0 -16
- package/src/components/FieldDecorator/utils.ts +0 -31
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 0.16.1 (2024-02-27)
|
|
7
|
+
|
|
8
|
+
### Only dependencies have been changed
|
|
9
|
+
* [@snack-uikit/list@0.5.0](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/list/CHANGELOG.md)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
# 0.16.0 (2024-02-26)
|
|
7
16
|
|
|
8
17
|
|
package/README.md
CHANGED
|
@@ -337,20 +337,9 @@ const [isOpen, setIsOpen] = useState(false);
|
|
|
337
337
|
| footer | `ReactNode` | - | |
|
|
338
338
|
| search | `SearchState` | - | |
|
|
339
339
|
| autocomplete | `boolean` | - | |
|
|
340
|
-
| addOptionByEnter | `boolean` | - | |
|
|
341
|
-
| open | `boolean` | - | |
|
|
342
|
-
| onOpenChange | `(open: boolean) => void` | - | |
|
|
343
|
-
| dataError | `boolean` | - | |
|
|
344
|
-
| noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
|
|
345
|
-
| noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
|
|
346
|
-
| errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
|
|
347
|
-
| pinTop | `ItemProps[]` | - | Элементы списка, закрепленные сверху |
|
|
348
|
-
| pinBottom | `ItemProps[]` | - | Элементы списка, закрепленные снизу |
|
|
349
|
-
| dataFiltered | `boolean` | - | |
|
|
350
340
|
| selection | "single" \| "multiple" | - | |
|
|
351
341
|
| ref | `Ref<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom |
|
|
352
342
|
| key | `Key` | - | |
|
|
353
|
-
| removeByBackspace | `boolean` | - | |
|
|
354
343
|
## FieldStepper
|
|
355
344
|
### Props
|
|
356
345
|
| name | type | default value | description |
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
export declare const FieldSelectMultiple: import("react").ForwardRefExoticComponent<import("./types").InputProps & import("./types").WrapperProps & {
|
|
3
3
|
options: import("./types").OptionProps[];
|
|
4
4
|
loading?: boolean | undefined;
|
|
5
|
-
} & {
|
|
6
|
-
removeByBackspace?: boolean | undefined;
|
|
7
5
|
} & Omit<import("@snack-uikit/list").SelectionMultipleState, "mode"> & Omit<{
|
|
8
6
|
'data-test-id'?: string | undefined;
|
|
9
7
|
} & import("react").AriaAttributes & {
|
|
@@ -16,7 +14,4 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
|
|
|
16
14
|
footer?: import("react").ReactNode;
|
|
17
15
|
search?: import("./types").SearchState | undefined;
|
|
18
16
|
autocomplete?: boolean | undefined;
|
|
19
|
-
|
|
20
|
-
open?: boolean | undefined;
|
|
21
|
-
onOpenChange?(open: boolean): void;
|
|
22
|
-
} & Pick<import("@snack-uikit/list").ListProps, "dataError" | "noDataState" | "noResultsState" | "errorDataState" | "pinTop" | "pinBottom" | "dataFiltered">, "showCopyButton"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
17
|
+
}, "showCopyButton"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
13
|
import cn from 'classnames';
|
|
14
14
|
import mergeRefs from 'merge-refs';
|
|
15
|
-
import { forwardRef, useMemo, useRef } from 'react';
|
|
15
|
+
import { forwardRef, useMemo, useRef, useState } from 'react';
|
|
16
16
|
import { InputPrivate } from '@snack-uikit/input-private';
|
|
17
17
|
import { Droplist, useFuzzySearch } from '@snack-uikit/list';
|
|
18
18
|
import { Tag } from '@snack-uikit/tag';
|
|
@@ -20,29 +20,26 @@ import { extractSupportProps } from '@snack-uikit/utils';
|
|
|
20
20
|
import { FieldContainerPrivate } from '../../helperComponents';
|
|
21
21
|
import { useValueControl } from '../../hooks';
|
|
22
22
|
import { FieldDecorator } from '../FieldDecorator';
|
|
23
|
-
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
24
23
|
import { useButtons, useHandleDeleteItem, useHandleOnKeyDown, useSearchInput } from './hooks';
|
|
25
24
|
import styles from './styles.module.css';
|
|
26
|
-
import {
|
|
25
|
+
import { extractSelectedMultipleOptions, getArrowIcon, transformOptionsToItems } from './utils';
|
|
27
26
|
const BASE_MIN_WIDTH = 4;
|
|
28
27
|
export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
29
|
-
var
|
|
30
|
-
var { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, disabled = false, readonly = false, searchable = true, showClearButton = true, onKeyDown: onInputKeyDownProp, validationState = 'default', search, autocomplete = false, prefixIcon, removeByBackspace = false, addOptionByEnter = false, open: openProp, onOpenChange } = _a, rest = __rest(_a, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "validationState", "search", "autocomplete", "prefixIcon", "removeByBackspace", "addOptionByEnter", "open", "onOpenChange"]);
|
|
28
|
+
var { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, loading, disabled = false, readonly = false, searchable = true, showClearButton = true, onKeyDown: onInputKeyDownProp, label, labelTooltip, labelTooltipPlacement, required = false, hint, showHintIcon, validationState = 'default', footer, search, autocomplete = false, prefixIcon, error } = _a, rest = __rest(_a, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "loading", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "label", "labelTooltip", "labelTooltipPlacement", "required", "hint", "showHintIcon", "validationState", "footer", "search", "autocomplete", "prefixIcon", "error"]);
|
|
31
29
|
const localRef = useRef(null);
|
|
32
30
|
const inputPlugRef = useRef(null);
|
|
33
31
|
const contentRef = useRef(null);
|
|
34
|
-
const [open
|
|
32
|
+
const [open, setOpen] = useState(false);
|
|
35
33
|
const items = useMemo(() => transformOptionsToItems(options), [options]);
|
|
36
34
|
const [value, setValue] = useValueControl({
|
|
37
35
|
value: valueProp,
|
|
38
36
|
defaultValue,
|
|
39
37
|
onChange: onChangeProp,
|
|
40
38
|
});
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
? selectedWithPlaceholder.sort((a, b) => {
|
|
39
|
+
const selectedOption = useMemo(() => {
|
|
40
|
+
const notSortSelectedOption = extractSelectedMultipleOptions(options, value);
|
|
41
|
+
if (notSortSelectedOption) {
|
|
42
|
+
return notSortSelectedOption.sort((a, b) => {
|
|
46
43
|
if (b.disabled && !a.disabled) {
|
|
47
44
|
return 1;
|
|
48
45
|
}
|
|
@@ -50,15 +47,10 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
50
47
|
return -1;
|
|
51
48
|
}
|
|
52
49
|
return 0;
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
selected,
|
|
58
|
-
itemsWithPlaceholder: placeholderItems.concat(items),
|
|
59
|
-
};
|
|
60
|
-
}, [items, value]);
|
|
61
|
-
const { inputValue, onInputValueChange, prevInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '' }));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}, [options, value]);
|
|
53
|
+
const { inputValue, onInputValueChange, prevInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: String(selectedOption !== null && selectedOption !== void 0 ? selectedOption : '') }));
|
|
62
54
|
const onClear = () => {
|
|
63
55
|
var _a;
|
|
64
56
|
setValue(undefined);
|
|
@@ -70,7 +62,7 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
70
62
|
const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
|
|
71
63
|
readonly,
|
|
72
64
|
size,
|
|
73
|
-
showClearButton: showClearButton &&
|
|
65
|
+
showClearButton: showClearButton && Boolean(value),
|
|
74
66
|
showCopyButton: false,
|
|
75
67
|
inputRef: localRef,
|
|
76
68
|
onClear,
|
|
@@ -82,20 +74,11 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
82
74
|
});
|
|
83
75
|
const handleItemDelete = useHandleDeleteItem(setValue);
|
|
84
76
|
const handleOnKeyDown = (onKeyDown) => (e) => {
|
|
85
|
-
if (
|
|
86
|
-
if ((
|
|
87
|
-
handleItemDelete(
|
|
77
|
+
if (e.code === 'Backspace' && inputValue === '') {
|
|
78
|
+
if ((selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.length) && !selectedOption.slice(-1)[0].disabled) {
|
|
79
|
+
handleItemDelete(selectedOption.pop())();
|
|
88
80
|
}
|
|
89
81
|
}
|
|
90
|
-
if (e.code === 'Enter') {
|
|
91
|
-
e.stopPropagation();
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
}
|
|
94
|
-
if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
|
|
95
|
-
setValue((value) => (value !== null && value !== void 0 ? value : []).concat(inputValue));
|
|
96
|
-
onInputValueChange('');
|
|
97
|
-
prevInputValue.current = '';
|
|
98
|
-
}
|
|
99
82
|
if (!open && prevInputValue.current !== inputValue) {
|
|
100
83
|
setOpen(true);
|
|
101
84
|
}
|
|
@@ -105,16 +88,10 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
105
88
|
if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
|
|
106
89
|
setOpen(open);
|
|
107
90
|
if (!open) {
|
|
108
|
-
|
|
109
|
-
prevInputValue.current = '';
|
|
110
|
-
if (inputPlugRef.current) {
|
|
111
|
-
inputPlugRef.current.style.width = BASE_MIN_WIDTH + 'px';
|
|
112
|
-
}
|
|
91
|
+
prevInputValue.current = inputValue;
|
|
113
92
|
}
|
|
114
93
|
if (open) {
|
|
115
|
-
|
|
116
|
-
inputPlugRef.current.style.width = 'unset';
|
|
117
|
-
}
|
|
94
|
+
prevInputValue.current = '';
|
|
118
95
|
}
|
|
119
96
|
}
|
|
120
97
|
};
|
|
@@ -125,21 +102,19 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
125
102
|
}
|
|
126
103
|
(_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
|
|
127
104
|
};
|
|
128
|
-
const fuzzySearch = useFuzzySearch(
|
|
129
|
-
const result = autocomplete
|
|
130
|
-
|
|
131
|
-
: fuzzySearch(inputValue);
|
|
132
|
-
return (_jsx(FieldDecorator, Object.assign({}, extractSupportProps(rest), extractFieldDecoratorProps(rest), { labelFor: id, size: size, validationState: validationState, children: _jsx(Droplist, Object.assign({}, extractListProps(rest), { items: result, triggerElemRef: localRef, selection: {
|
|
105
|
+
const fuzzySearch = useFuzzySearch(items);
|
|
106
|
+
const result = autocomplete ? items : fuzzySearch(prevInputValue.current !== inputValue ? inputValue : '');
|
|
107
|
+
return (_jsx(FieldDecorator, Object.assign({}, extractSupportProps(rest), { error: error, required: required, readonly: readonly, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, hint: hint, disabled: disabled, showHintIcon: showHintIcon, size: size, validationState: validationState, children: _jsx(Droplist, { trigger: 'clickAndFocusVisible', placement: 'bottom', "data-test-id": 'field-select__list', items: result, triggerElemRef: localRef, scroll: true, marker: true, footer: footer, selection: {
|
|
133
108
|
mode: 'multiple',
|
|
134
109
|
value: value,
|
|
135
110
|
onChange: setValue,
|
|
136
|
-
},
|
|
111
|
+
}, size: size, open: !disabled && !readonly && open, onOpenChange: handleOpenChange, loading: loading, children: ({ onKeyDown }) => {
|
|
137
112
|
var _a, _b, _c, _d;
|
|
138
|
-
return (_jsx(FieldContainerPrivate, { className: cn(styles.container, styles.tagContainer), validationState: validationState, disabled: disabled, readonly: readonly, focused: open, variant: 'single-line-container', inputRef: localRef, size: size, prefix: prefixIcon, children: _jsxs(_Fragment, { children: [_jsxs("div", { className: styles.contentWrapper, ref: contentRef, children: [
|
|
139
|
-
|
|
113
|
+
return (_jsx(FieldContainerPrivate, { className: cn(styles.container, styles.tagContainer), validationState: validationState, disabled: disabled, readonly: readonly, focused: open, variant: 'single-line-container', inputRef: localRef, size: size, prefix: prefixIcon, children: _jsxs(_Fragment, { children: [_jsxs("div", { className: styles.contentWrapper, ref: contentRef, children: [selectedOption &&
|
|
114
|
+
selectedOption.map(option => (_jsx(Tag, { size: size === 'l' ? 's' : 'xs', tabIndex: -1, label: String(option.option), onDelete: !option.disabled && !disabled ? handleItemDelete(option) : undefined }, option.value))), _jsx("div", { className: styles.inputWrapper, style: {
|
|
140
115
|
minWidth: value
|
|
141
116
|
? Math.min((_b = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : BASE_MIN_WIDTH, (_d = (_c = inputPlugRef.current) === null || _c === void 0 ? void 0 : _c.clientWidth) !== null && _d !== void 0 ? _d : BASE_MIN_WIDTH)
|
|
142
117
|
: '100%',
|
|
143
|
-
}, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !
|
|
144
|
-
} })
|
|
118
|
+
}, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !selectedOption ? placeholder : undefined, ref: mergeRefs(ref, localRef), onChange: searchable ? onInputValueChange : undefined, value: searchable ? inputValue : '', readonly: !searchable || readonly, "data-test-id": 'field-select__input', onKeyDown: handleOnKeyDown(onKeyDown), onBlur: handleBlur, className: styles.input }) })] }), _jsxs("div", { className: styles.postfix, children: [buttons, _jsx(ArrowIcon, { size: arrowIconSize, className: styles.arrowIcon })] }), _jsx("span", { ref: inputPlugRef, className: styles.inputPlug, children: inputValue })] }) }));
|
|
119
|
+
} }) })));
|
|
145
120
|
});
|
|
@@ -14,7 +14,4 @@ export declare const FieldSelectSingle: import("react").ForwardRefExoticComponen
|
|
|
14
14
|
footer?: import("react").ReactNode;
|
|
15
15
|
search?: import("./types").SearchState | undefined;
|
|
16
16
|
autocomplete?: boolean | undefined;
|
|
17
|
-
|
|
18
|
-
open?: boolean | undefined;
|
|
19
|
-
onOpenChange?(open: boolean): void;
|
|
20
|
-
} & Pick<import("@snack-uikit/list").ListProps, "dataError" | "noDataState" | "noResultsState" | "errorDataState" | "pinTop" | "pinBottom" | "dataFiltered"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
17
|
+
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -11,49 +11,38 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
import mergeRefs from 'merge-refs';
|
|
14
|
-
import { forwardRef, useEffect, useMemo, useRef } from 'react';
|
|
14
|
+
import { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
|
|
15
15
|
import { InputPrivate } from '@snack-uikit/input-private';
|
|
16
16
|
import { Droplist, useFuzzySearch } from '@snack-uikit/list';
|
|
17
17
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
18
18
|
import { FieldContainerPrivate } from '../../helperComponents';
|
|
19
19
|
import { useValueControl } from '../../hooks';
|
|
20
20
|
import { FieldDecorator } from '../FieldDecorator';
|
|
21
|
-
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
22
21
|
import { useButtons, useHandleOnKeyDown, useSearchInput } from './hooks';
|
|
23
22
|
import styles from './styles.module.css';
|
|
24
|
-
import {
|
|
23
|
+
import { extractSelectedOptions, getArrowIcon, transformOptionsToItems } from './utils';
|
|
25
24
|
export const FieldSelectSingle = forwardRef((_a, ref) => {
|
|
26
|
-
var _b
|
|
27
|
-
var { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, disabled = false, readonly = false, searchable = true, showCopyButton = true, showClearButton = true, onKeyDown: onInputKeyDownProp, required = false, validationState = 'default', search, autocomplete = false, prefixIcon,
|
|
25
|
+
var _b;
|
|
26
|
+
var { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, loading, disabled = false, readonly = false, searchable = true, showCopyButton = true, showClearButton = true, onKeyDown: onInputKeyDownProp, label, labelTooltip, labelTooltipPlacement, required = false, hint, showHintIcon, validationState = 'default', footer, search, autocomplete = false, prefixIcon, error } = _a, rest = __rest(_a, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "loading", "disabled", "readonly", "searchable", "showCopyButton", "showClearButton", "onKeyDown", "label", "labelTooltip", "labelTooltipPlacement", "required", "hint", "showHintIcon", "validationState", "footer", "search", "autocomplete", "prefixIcon", "error"]);
|
|
28
27
|
const localRef = useRef(null);
|
|
29
|
-
const [open
|
|
28
|
+
const [open, setOpen] = useState(false);
|
|
30
29
|
const [value, setValue] = useValueControl({
|
|
31
30
|
value: valueProp,
|
|
32
31
|
defaultValue,
|
|
33
32
|
onChange: onChangeProp,
|
|
34
33
|
});
|
|
35
34
|
const items = useMemo(() => transformOptionsToItems(options), [options]);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}, [items, value]);
|
|
43
|
-
const { inputValue, onInputValueChange, prevInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: (_b = selected === null || selected === void 0 ? void 0 : selected.content.option) !== null && _b !== void 0 ? _b : '' }));
|
|
35
|
+
const selectedOption = useMemo(() => extractSelectedOptions(options, value), [options, value]);
|
|
36
|
+
const { inputValue, onInputValueChange, prevInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: String(selectedOption !== null && selectedOption !== void 0 ? selectedOption : '') }));
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
var _a;
|
|
39
|
+
!open && onInputValueChange(String((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.option) !== null && _a !== void 0 ? _a : ''));
|
|
40
|
+
}, [onInputValueChange, open, selectedOption]);
|
|
44
41
|
useEffect(() => {
|
|
45
|
-
if ((selected === null || selected === void 0 ? void 0 : selected.content.option) && prevInputValue.current !== (selected === null || selected === void 0 ? void 0 : selected.content.option)) {
|
|
46
|
-
onInputValueChange(selected.content.option);
|
|
47
|
-
prevInputValue.current = selected === null || selected === void 0 ? void 0 : selected.content.option;
|
|
48
|
-
}
|
|
49
|
-
}, [onInputValueChange, selected === null || selected === void 0 ? void 0 : selected.content.option, prevInputValue]);
|
|
50
|
-
const handleBlur = (e) => {
|
|
51
42
|
var _a, _b;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(_b = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _b === void 0 ? void 0 : _b.call(rest, e);
|
|
56
|
-
};
|
|
43
|
+
onInputValueChange(String((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.option) !== null && _a !== void 0 ? _a : ''));
|
|
44
|
+
prevInputValue.current = String((_b = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.option) !== null && _b !== void 0 ? _b : '');
|
|
45
|
+
}, [prevInputValue, onInputValueChange, selectedOption]);
|
|
57
46
|
const onClear = () => {
|
|
58
47
|
var _a;
|
|
59
48
|
setValue('');
|
|
@@ -65,11 +54,11 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
|
|
|
65
54
|
const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
|
|
66
55
|
readonly,
|
|
67
56
|
size,
|
|
68
|
-
showClearButton: showClearButton &&
|
|
57
|
+
showClearButton: showClearButton && Boolean(value),
|
|
69
58
|
showCopyButton,
|
|
70
59
|
inputRef: localRef,
|
|
71
60
|
onClear,
|
|
72
|
-
valueToCopy: (
|
|
61
|
+
valueToCopy: String((_b = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.option) !== null && _b !== void 0 ? _b : ''),
|
|
73
62
|
});
|
|
74
63
|
const commonHandleOnKeyDown = useHandleOnKeyDown({
|
|
75
64
|
inputKeyDownNavigationHandler,
|
|
@@ -80,13 +69,6 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
|
|
|
80
69
|
if (!open && prevInputValue.current !== inputValue) {
|
|
81
70
|
setOpen(true);
|
|
82
71
|
}
|
|
83
|
-
if (e.code === 'Enter') {
|
|
84
|
-
e.stopPropagation();
|
|
85
|
-
e.preventDefault();
|
|
86
|
-
}
|
|
87
|
-
if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
|
|
88
|
-
setValue(inputValue);
|
|
89
|
-
}
|
|
90
72
|
commonHandleOnKeyDown(onKeyDown)(e);
|
|
91
73
|
};
|
|
92
74
|
const handleSelectionChange = (newValue) => {
|
|
@@ -98,22 +80,15 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
|
|
|
98
80
|
}
|
|
99
81
|
};
|
|
100
82
|
const handleOpenChange = (open) => {
|
|
101
|
-
var _a, _b;
|
|
102
83
|
if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
|
|
103
84
|
setOpen(open);
|
|
104
|
-
if (!open) {
|
|
105
|
-
onInputValueChange((_a = selected === null || selected === void 0 ? void 0 : selected.content.option) !== null && _a !== void 0 ? _a : '');
|
|
106
|
-
prevInputValue.current = (_b = selected === null || selected === void 0 ? void 0 : selected.content.option) !== null && _b !== void 0 ? _b : '';
|
|
107
|
-
}
|
|
108
85
|
}
|
|
109
86
|
};
|
|
110
|
-
const fuzzySearch = useFuzzySearch(
|
|
111
|
-
const result = autocomplete
|
|
112
|
-
|
|
113
|
-
: fuzzySearch(inputValue);
|
|
114
|
-
return (_jsx(FieldDecorator, Object.assign({}, extractSupportProps(rest), extractFieldDecoratorProps(rest), { validationState: validationState, required: required, readonly: readonly, labelFor: id, disabled: disabled, size: size, children: _jsx(Droplist, Object.assign({}, extractListProps(rest), { items: result, selection: {
|
|
87
|
+
const fuzzySearch = useFuzzySearch(items);
|
|
88
|
+
const result = autocomplete ? items : fuzzySearch(prevInputValue.current !== inputValue ? inputValue : '');
|
|
89
|
+
return (_jsx(FieldDecorator, Object.assign({}, extractSupportProps(rest), { error: error, required: required, readonly: readonly, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, hint: hint, disabled: disabled, showHintIcon: showHintIcon, size: size, validationState: validationState, children: _jsx(Droplist, { trigger: 'clickAndFocusVisible', placement: 'bottom', "data-test-id": 'field-select__list', items: result, triggerElemRef: localRef, scroll: true, marker: true, footer: footer, selection: {
|
|
115
90
|
mode: 'single',
|
|
116
91
|
value: value,
|
|
117
92
|
onChange: handleSelectionChange,
|
|
118
|
-
}, size: size, open: open, onOpenChange: handleOpenChange,
|
|
93
|
+
}, size: size, open: open, onOpenChange: handleOpenChange, loading: loading, children: ({ onKeyDown }) => (_jsxs(FieldContainerPrivate, { className: styles.container, validationState: validationState, disabled: disabled, readonly: readonly, focused: open, variant: 'single-line-container', inputRef: localRef, size: size, prefix: prefixIcon, children: [_jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: placeholder, ref: mergeRefs(ref, localRef), onChange: searchable ? onInputValueChange : undefined, value: inputValue, readonly: !searchable || readonly, "data-test-id": 'field-select__input', onKeyDown: handleOnKeyDown(onKeyDown) }), _jsxs("div", { className: styles.postfix, children: [buttons, _jsx(ArrowIcon, { size: arrowIconSize, className: styles.arrowIcon })] })] })) }) })));
|
|
119
94
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KeyboardEvent, KeyboardEventHandler, RefObject } from 'react';
|
|
2
2
|
import { Handler } from 'uncontrollable';
|
|
3
|
-
import {
|
|
3
|
+
import { OptionProps, SearchState } from './types';
|
|
4
4
|
type UseHandleOnKeyDownProps = {
|
|
5
5
|
inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
|
|
6
6
|
onInputKeyDownProp: KeyboardEventHandler<HTMLInputElement> | undefined;
|
|
@@ -26,5 +26,5 @@ export declare function useSearchInput({ value, onChange, defaultValue }: Search
|
|
|
26
26
|
onInputValueChange: Handler;
|
|
27
27
|
prevInputValue: import("react").MutableRefObject<string>;
|
|
28
28
|
};
|
|
29
|
-
export declare function useHandleDeleteItem(setValue: Handler): (
|
|
29
|
+
export declare function useHandleDeleteItem(setValue: Handler): (option?: OptionProps) => () => void;
|
|
30
30
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
2
3
|
import { useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
|
|
3
|
-
import { extractChildIds
|
|
4
|
-
import { useCopyButton
|
|
5
|
-
import { isBaseOptionProps } from './utils';
|
|
4
|
+
import { extractChildIds } from '@snack-uikit/list/dist/utils';
|
|
5
|
+
import { useCopyButton } from '../../hooks';
|
|
6
|
+
import { isAccordionOptionProps, isBaseOptionProps, isNextListOptionProps, transformOptionsToItems } from './utils';
|
|
6
7
|
export function useHandleOnKeyDown({ setOpen, inputKeyDownNavigationHandler, onInputKeyDownProp, }) {
|
|
7
8
|
return useCallback((onKeyDown) => (e) => {
|
|
8
9
|
if (e.code === 'Space') {
|
|
@@ -50,23 +51,22 @@ export function useButtons({ readonly, showClearButton, showCopyButton, size, on
|
|
|
50
51
|
return { buttons, inputKeyDownNavigationHandler, buttonsRefs };
|
|
51
52
|
}
|
|
52
53
|
export function useSearchInput({ value, onChange, defaultValue }) {
|
|
53
|
-
const [inputValue
|
|
54
|
+
const [inputValue, onInputValueChange] = useUncontrolledProp(value, defaultValue !== null && defaultValue !== void 0 ? defaultValue : '', onChange);
|
|
54
55
|
const prevInputValue = useRef(inputValue);
|
|
55
56
|
return { inputValue, onInputValueChange, prevInputValue };
|
|
56
57
|
}
|
|
57
58
|
export function useHandleDeleteItem(setValue) {
|
|
58
|
-
return useCallback((
|
|
59
|
-
|
|
60
|
-
if (!item) {
|
|
59
|
+
return useCallback((option) => () => {
|
|
60
|
+
if (!option) {
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
if (
|
|
64
|
-
const removeIds = extractChildIds({ items:
|
|
63
|
+
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
64
|
+
const removeIds = extractChildIds({ items: transformOptionsToItems(option.options) }).concat(option.value);
|
|
65
65
|
setValue((value) => value === null || value === void 0 ? void 0 : value.filter(v => !removeIds.includes(v !== null && v !== void 0 ? v : '')));
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
|
-
if (isBaseOptionProps(
|
|
69
|
-
setValue((value) => value === null || value === void 0 ? void 0 : value.filter(v => v !==
|
|
68
|
+
if (isBaseOptionProps(option)) {
|
|
69
|
+
setValue((value) => value === null || value === void 0 ? void 0 : value.filter(v => v !== option.value));
|
|
70
70
|
}
|
|
71
71
|
}, [setValue]);
|
|
72
72
|
}
|
|
@@ -48,18 +48,12 @@ type FiledSelectCommonProps = WithSupportProps<{
|
|
|
48
48
|
footer?: ListProps['footer'];
|
|
49
49
|
search?: SearchState;
|
|
50
50
|
autocomplete?: boolean;
|
|
51
|
-
|
|
52
|
-
open?: boolean;
|
|
53
|
-
onOpenChange?(open: boolean): void;
|
|
54
|
-
}> & Pick<ListProps, 'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'pinTop' | 'pinBottom' | 'dataFiltered'>;
|
|
51
|
+
}>;
|
|
55
52
|
export type FieldSelectSingleProps = FieldSelectPrivateProps & Omit<SelectionSingleState, 'mode'> & WrapperProps & FiledSelectCommonProps;
|
|
56
|
-
export type FieldSelectMultipleProps = FieldSelectPrivateProps &
|
|
57
|
-
removeByBackspace?: boolean;
|
|
58
|
-
} & Omit<SelectionMultipleState, 'mode'> & Omit<FiledSelectCommonProps, 'showCopyButton'>;
|
|
53
|
+
export type FieldSelectMultipleProps = FieldSelectPrivateProps & Omit<SelectionMultipleState, 'mode'> & Omit<FiledSelectCommonProps, 'showCopyButton'>;
|
|
59
54
|
export type FieldSelectProps = (FieldSelectSingleProps & {
|
|
60
55
|
selection?: 'single';
|
|
61
56
|
}) | (FieldSelectMultipleProps & {
|
|
62
57
|
selection: 'multiple';
|
|
63
58
|
});
|
|
64
|
-
export type ItemWithId = BaseItemProps | AccordionItemProps | NextListItemProps;
|
|
65
59
|
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Size } from '@snack-uikit/input-private';
|
|
2
|
-
import {
|
|
3
|
-
import { AccordionOptionProps, BaseOptionProps, FieldSelectMultipleProps,
|
|
2
|
+
import { ItemProps } from '@snack-uikit/list';
|
|
3
|
+
import { AccordionOptionProps, BaseOptionProps, FieldSelectMultipleProps, FieldSelectSingleProps, GroupOptionProps, NestListOptionProps, OptionProps, OptionWithoutGroup } from './types';
|
|
4
4
|
export declare function isBaseOptionProps(option: any): option is BaseOptionProps;
|
|
5
5
|
export declare function isAccordionOptionProps(option: any): option is AccordionOptionProps;
|
|
6
6
|
export declare function isNextListOptionProps(option: any): option is NestListOptionProps;
|
|
7
7
|
export declare function isGroupOptionProps(option: any): option is GroupOptionProps;
|
|
8
8
|
export declare function transformOptionsToItems(options: OptionProps[]): ItemProps[];
|
|
9
|
-
export declare function
|
|
10
|
-
export declare function
|
|
9
|
+
export declare function extractSelectedOptions(options: OptionProps[], value: string | number | undefined): OptionWithoutGroup | undefined;
|
|
10
|
+
export declare function extractSelectedMultipleOptions(options: OptionProps[], value?: (string | number | undefined)[]): OptionWithoutGroup[] | undefined;
|
|
11
11
|
export declare function isFieldSelectMultipleProps(props: any): props is FieldSelectMultipleProps;
|
|
12
12
|
export declare function isFieldSelectSingleProps(props: any): props is FieldSelectSingleProps;
|
|
13
13
|
export declare function getArrowIcon({ size, open }: {
|
|
@@ -17,4 +17,3 @@ export declare function getArrowIcon({ size, open }: {
|
|
|
17
17
|
ArrowIcon: ({ size, ...props }: import("@snack-uikit/icons/dist/components/interface-icons/chevronUp").ISvgIconProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
18
|
arrowIconSize: 16 | 24;
|
|
19
19
|
};
|
|
20
|
-
export declare function extractListProps({ dataError, noDataState, noResultsState, errorDataState, pinTop, pinBottom, dataFiltered, loading, }: Partial<FieldSelectProps>): Partial<DroplistProps>;
|
|
@@ -11,7 +11,6 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { ChevronDownSVG, ChevronUpSVG } from '@snack-uikit/icons';
|
|
13
13
|
import { ICON_SIZE, SIZE } from '@snack-uikit/input-private';
|
|
14
|
-
import { flattenItems } from '@snack-uikit/list';
|
|
15
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
15
|
export function isBaseOptionProps(option) {
|
|
17
16
|
return !('options' in option);
|
|
@@ -42,34 +41,60 @@ export function transformOptionsToItems(options) {
|
|
|
42
41
|
return Object.assign(Object.assign({ 'data-test-id': 'field-select__list-option-' + option.value }, rest), { id: value, content: { option: contentOption, caption, description } });
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
|
-
export function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
export function extractSelectedOptions(options, value) {
|
|
45
|
+
for (let i = 0; i < options.length; i++) {
|
|
46
|
+
const option = options[i];
|
|
47
|
+
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
48
|
+
const { value: optionValue } = option;
|
|
49
|
+
if (optionValue === value) {
|
|
50
|
+
return option;
|
|
51
|
+
}
|
|
52
|
+
const selectedOptionFromNestedOptions = extractSelectedOptions(option.options, value);
|
|
53
|
+
if (selectedOptionFromNestedOptions) {
|
|
54
|
+
return selectedOptionFromNestedOptions;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (isGroupOptionProps(option)) {
|
|
58
|
+
const selectedOptionFromNestedOptions = extractSelectedOptions(option.options, value);
|
|
59
|
+
if (selectedOptionFromNestedOptions) {
|
|
60
|
+
return selectedOptionFromNestedOptions;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (isBaseOptionProps(option)) {
|
|
64
|
+
if (option.value === value) {
|
|
65
|
+
return option;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
49
68
|
}
|
|
50
|
-
|
|
51
|
-
const placeholderItem = { id: value, content: { option: String(value) } };
|
|
52
|
-
return [foundItem, !foundItem ? placeholderItem : undefined];
|
|
69
|
+
return undefined;
|
|
53
70
|
}
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (flatten) {
|
|
63
|
-
const [found, placeholder] = findSelectedOption(flatten, value);
|
|
64
|
-
if (found || foundItems) {
|
|
65
|
-
foundItems = (foundItems !== null && foundItems !== void 0 ? foundItems : []).concat(found !== null && found !== void 0 ? found : []);
|
|
71
|
+
export function extractSelectedMultipleOptions(options, value) {
|
|
72
|
+
let selectedOptions = [];
|
|
73
|
+
for (let i = 0; i < options.length; i++) {
|
|
74
|
+
const option = options[i];
|
|
75
|
+
if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
|
|
76
|
+
const { value: optionValue } = option;
|
|
77
|
+
if (value === null || value === void 0 ? void 0 : value.includes(optionValue)) {
|
|
78
|
+
selectedOptions.push(option);
|
|
66
79
|
}
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
const selectedOptionFromNestedOptions = extractSelectedMultipleOptions(option.options, value);
|
|
81
|
+
if (selectedOptionFromNestedOptions) {
|
|
82
|
+
selectedOptions = selectedOptions.concat(selectedOptionFromNestedOptions);
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
if (isGroupOptionProps(option)) {
|
|
86
|
+
const selectedOptionFromNestedOptions = extractSelectedMultipleOptions(option.options, value);
|
|
87
|
+
if (selectedOptionFromNestedOptions) {
|
|
88
|
+
selectedOptions = selectedOptions.concat(selectedOptionFromNestedOptions);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (isBaseOptionProps(option)) {
|
|
92
|
+
if (value === null || value === void 0 ? void 0 : value.includes(option.value)) {
|
|
93
|
+
selectedOptions.push(option);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return selectedOptions.length ? selectedOptions : undefined;
|
|
73
98
|
}
|
|
74
99
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
100
|
export function isFieldSelectMultipleProps(props) {
|
|
@@ -85,20 +110,3 @@ export function getArrowIcon({ size, open }) {
|
|
|
85
110
|
arrowIconSize: size === SIZE.S ? ICON_SIZE.Xs : ICON_SIZE.S,
|
|
86
111
|
};
|
|
87
112
|
}
|
|
88
|
-
export function extractListProps({ dataError, noDataState, noResultsState, errorDataState, pinTop, pinBottom, dataFiltered, loading, }) {
|
|
89
|
-
return {
|
|
90
|
-
dataError,
|
|
91
|
-
noDataState,
|
|
92
|
-
noResultsState,
|
|
93
|
-
errorDataState,
|
|
94
|
-
pinTop,
|
|
95
|
-
pinBottom,
|
|
96
|
-
dataFiltered,
|
|
97
|
-
loading,
|
|
98
|
-
trigger: 'clickAndFocusVisible',
|
|
99
|
-
placement: 'bottom',
|
|
100
|
-
'data-test-id': 'field-select__list',
|
|
101
|
-
scroll: true,
|
|
102
|
-
marker: true,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useUncontrolledProp } from 'uncontrollable';
|
|
2
2
|
export function useValueControl({ value, onChange, defaultValue }) {
|
|
3
|
-
return useUncontrolledProp(value, defaultValue, (newValue) => {
|
|
3
|
+
return useUncontrolledProp(value, value !== null && value !== void 0 ? value : defaultValue, (newValue) => {
|
|
4
4
|
const newState = typeof newValue === 'function' ? newValue(value) : newValue;
|
|
5
5
|
onChange === null || onChange === void 0 ? void 0 : onChange(newState);
|
|
6
6
|
});
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.16.1
|
|
7
|
+
"version": "0.16.1",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@snack-uikit/button": "0.16.1",
|
|
36
36
|
"@snack-uikit/calendar": "0.7.6",
|
|
37
|
-
"@snack-uikit/droplist": "0.13.
|
|
37
|
+
"@snack-uikit/droplist": "0.13.8",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
39
|
"@snack-uikit/input-private": "3.1.1",
|
|
40
|
-
"@snack-uikit/list": "0.
|
|
40
|
+
"@snack-uikit/list": "0.5.0",
|
|
41
41
|
"@snack-uikit/scroll": "0.5.2",
|
|
42
42
|
"@snack-uikit/slider": "0.1.4",
|
|
43
|
-
"@snack-uikit/tag": "0.8.
|
|
43
|
+
"@snack-uikit/tag": "0.8.0",
|
|
44
44
|
"@snack-uikit/tooltip": "0.12.1",
|
|
45
45
|
"@snack-uikit/truncate-string": "0.4.9",
|
|
46
46
|
"@snack-uikit/utils": "3.2.0",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"@snack-uikit/locale": "*"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "bfdd4a8e3c077eab0d45e177172a62b6dcbda06b"
|
|
60
60
|
}
|