@snack-uikit/fields 0.17.13 → 0.17.14-preview-b0dbf1fa.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 (34) hide show
  1. package/dist/components/FieldSelect/FieldSelectMultiple.js +27 -51
  2. package/dist/components/FieldSelect/FieldSelectSingle.js +34 -43
  3. package/dist/components/FieldSelect/hooks.d.ts +3 -1
  4. package/dist/components/FieldSelect/hooks.js +8 -2
  5. package/dist/components/FieldSelect/types.d.ts +4 -1
  6. package/dist/components/FieldSelect/utils/extractListProps.d.ts +3 -0
  7. package/dist/components/FieldSelect/utils/extractListProps.js +17 -0
  8. package/dist/components/FieldSelect/utils/getArrowIcon.d.ts +8 -0
  9. package/dist/components/FieldSelect/utils/getArrowIcon.js +8 -0
  10. package/dist/components/FieldSelect/utils/index.d.ts +5 -0
  11. package/dist/components/FieldSelect/utils/index.js +5 -0
  12. package/dist/components/FieldSelect/utils/options.d.ts +8 -0
  13. package/dist/components/FieldSelect/utils/options.js +56 -0
  14. package/dist/components/FieldSelect/utils/typeGuards.d.ts +7 -0
  15. package/dist/components/FieldSelect/utils/typeGuards.js +24 -0
  16. package/dist/components/FieldSelect/utils/updateItems.d.ts +32 -0
  17. package/dist/components/FieldSelect/utils/updateItems.js +67 -0
  18. package/dist/helperComponents/FieldContainerPrivate/styles.module.css +4 -7
  19. package/dist/hooks/useValueControl.d.ts +1 -1
  20. package/package.json +7 -7
  21. package/src/components/FieldSelect/FieldSelectMultiple.tsx +28 -68
  22. package/src/components/FieldSelect/FieldSelectSingle.tsx +51 -46
  23. package/src/components/FieldSelect/hooks.ts +12 -2
  24. package/src/components/FieldSelect/types.ts +4 -1
  25. package/src/components/FieldSelect/utils/extractListProps.ts +30 -0
  26. package/src/components/FieldSelect/utils/getArrowIcon.ts +9 -0
  27. package/src/components/FieldSelect/utils/index.ts +5 -0
  28. package/src/components/FieldSelect/utils/options.ts +87 -0
  29. package/src/components/FieldSelect/utils/typeGuards.ts +38 -0
  30. package/src/components/FieldSelect/utils/updateItems.ts +105 -0
  31. package/src/helperComponents/FieldContainerPrivate/styles.module.scss +6 -6
  32. package/dist/components/FieldSelect/utils.d.ts +0 -22
  33. package/dist/components/FieldSelect/utils.js +0 -122
  34. package/src/components/FieldSelect/utils.ts +0 -187
@@ -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, useLayoutEffect, 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';
@@ -23,58 +23,35 @@ import { FieldDecorator } from '../FieldDecorator';
23
23
  import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
24
24
  import { useButtons, useHandleDeleteItem, useHandleOnKeyDown, useSearchInput } from './hooks';
25
25
  import styles from './styles.module.css';
26
- import { extractListProps, findSelectedOptions, getArrowIcon, mapOptionToAppearance, transformOptionsToItems, } from './utils';
26
+ import { extractListProps, getArrowIcon, updateMultipleItems } from './utils';
27
27
  const BASE_MIN_WIDTH = 4;
28
28
  export const FieldSelectMultiple = forwardRef((_a, ref) => {
29
- var _b, _c, _d;
29
+ var _b;
30
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"]);
31
31
  const localRef = useRef(null);
32
32
  const inputPlugRef = useRef(null);
33
33
  const contentRef = useRef(null);
34
34
  const [open = false, setOpen] = useValueControl({ value: openProp, onChange: onOpenChange });
35
- const items = useMemo(() => transformOptionsToItems(options), [options]);
36
- const mapItemsToTagAppearance = useMemo(() => mapOptionToAppearance(options), [options]);
37
35
  const [value, setValue] = useValueControl({
38
36
  value: valueProp,
39
37
  defaultValue,
40
38
  onChange: onChangeProp,
41
39
  });
42
- const { selected, itemsWithPlaceholder, disabledSelected } = useMemo(() => {
43
- const [notSortSelectedOption, placeholder] = findSelectedOptions(items, value);
44
- const selectedWithPlaceholder = notSortSelectedOption || placeholder ? (placeholder !== null && placeholder !== void 0 ? placeholder : []).concat(notSortSelectedOption !== null && notSortSelectedOption !== void 0 ? notSortSelectedOption : []) : undefined;
45
- const selected = selectedWithPlaceholder
46
- ? selectedWithPlaceholder.sort((a, b) => {
47
- if (b.disabled && !a.disabled) {
48
- return 1;
49
- }
50
- if (a.disabled && !b.disabled) {
51
- return -1;
52
- }
53
- return 0;
54
- })
55
- : undefined;
56
- const placeholderItems = placeholder ? placeholder : [];
57
- const disabledSelected = selected === null || selected === void 0 ? void 0 : selected.filter((item) => item.disabled);
58
- return {
59
- selected,
60
- disabledSelected,
61
- itemsWithPlaceholder: placeholderItems.concat(items),
62
- };
63
- }, [items, value]);
64
- const { inputValue, onInputValueChange, prevInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '' }));
40
+ const [{ selectedItems, items = [] }, setItems] = useState(() => updateMultipleItems({ options, value, currentItems: [], selectedItems: undefined }));
41
+ const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '' }));
42
+ useLayoutEffect(() => {
43
+ setItems(({ selectedItems }) => updateMultipleItems({ options, value, selectedItems }));
44
+ }, [options, value]);
65
45
  const onClear = () => {
66
46
  var _a;
67
- const disabledValues = disabledSelected === null || disabledSelected === void 0 ? void 0 : disabledSelected.map(item => item.id);
68
- setValue(disabledValues);
69
- onInputValueChange('');
47
+ setValue(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.filter(item => item.disabled).map(item => item.id));
70
48
  (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
71
- setOpen(true);
72
49
  };
73
50
  const { ArrowIcon, arrowIconSize } = getArrowIcon({ size, open });
74
51
  const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
75
52
  readonly,
76
53
  size,
77
- showClearButton: showClearButton && !disabled && !readonly && ((_b = value === null || value === void 0 ? void 0 : value.length) !== null && _b !== void 0 ? _b : 0) > ((_c = disabledSelected === null || disabledSelected === void 0 ? void 0 : disabledSelected.length) !== null && _c !== void 0 ? _c : 0),
54
+ showClearButton: showClearButton && !disabled && !readonly && Boolean(selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.find(item => !item.disabled)),
78
55
  showCopyButton: false,
79
56
  inputRef: localRef,
80
57
  onClear,
@@ -87,8 +64,8 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
87
64
  const handleItemDelete = useHandleDeleteItem(setValue);
88
65
  const handleOnKeyDown = (onKeyDown) => (e) => {
89
66
  if (removeByBackspace && e.code === 'Backspace' && inputValue === '') {
90
- if ((selected === null || selected === void 0 ? void 0 : selected.length) && !selected.slice(-1)[0].disabled) {
91
- handleItemDelete(selected.pop())();
67
+ if ((selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) && !selectedItems.slice(-1)[0].disabled) {
68
+ handleItemDelete(selectedItems.pop())();
92
69
  }
93
70
  }
94
71
  if (e.code === 'Enter') {
@@ -97,8 +74,7 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
97
74
  }
98
75
  if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
99
76
  setValue((value) => (value !== null && value !== void 0 ? value : []).concat(inputValue));
100
- onInputValueChange('');
101
- prevInputValue.current = '';
77
+ updateInputValue();
102
78
  }
103
79
  if (!open && prevInputValue.current !== inputValue) {
104
80
  setOpen(true);
@@ -109,8 +85,7 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
109
85
  if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
110
86
  setOpen(open);
111
87
  if (!open) {
112
- onInputValueChange('');
113
- prevInputValue.current = '';
88
+ updateInputValue();
114
89
  if (inputPlugRef.current) {
115
90
  inputPlugRef.current.style.width = BASE_MIN_WIDTH + 'px';
116
91
  }
@@ -124,26 +99,27 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
124
99
  };
125
100
  const handleBlur = (e) => {
126
101
  var _a;
127
- if (!open) {
128
- onInputValueChange('');
129
- }
130
102
  (_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
131
103
  };
132
- const fuzzySearch = useFuzzySearch(itemsWithPlaceholder);
133
- const result = autocomplete || !searchable || prevInputValue.current === inputValue
134
- ? itemsWithPlaceholder
135
- : fuzzySearch(inputValue);
104
+ const fuzzySearch = useFuzzySearch(items);
105
+ const result = autocomplete || !searchable || prevInputValue.current === inputValue ? items : fuzzySearch(inputValue);
136
106
  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: {
137
107
  mode: 'multiple',
138
108
  value: value,
139
- onChange: setValue,
140
- }, dataFiltered: (_d = rest.dataFiltered) !== null && _d !== void 0 ? _d : Boolean(inputValue.length), size: size, open: !disabled && !readonly && open, onOpenChange: handleOpenChange, children: ({ onKeyDown }) => {
109
+ onChange: value => {
110
+ updateInputValue();
111
+ setValue(value);
112
+ },
113
+ }, dataFiltered: (_b = rest.dataFiltered) !== null && _b !== void 0 ? _b : Boolean(inputValue.length), size: size, open: !disabled && !readonly && open, onOpenChange: handleOpenChange, children: ({ onKeyDown }) => {
141
114
  var _a, _b, _c, _d;
142
- 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: [selected &&
143
- selected.map(option => (_jsx(Tag, { size: size === 'l' ? 's' : 'xs', tabIndex: -1, label: String(option.content.option), appearance: option.id ? mapItemsToTagAppearance[option === null || option === void 0 ? void 0 : option.id] : 'neutral', onDelete: !option.disabled && !disabled && !readonly ? handleItemDelete(option) : undefined }, option.id))), _jsx("div", { className: styles.inputWrapper, style: {
115
+ 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: [selectedItems &&
116
+ selectedItems.map(option => {
117
+ var _a;
118
+ return (_jsx(Tag, { size: size === 'l' ? 's' : 'xs', tabIndex: -1, label: String(option.content.option), appearance: (_a = option.appearance) !== null && _a !== void 0 ? _a : 'neutral', onDelete: !option.disabled && !disabled && !readonly ? handleItemDelete(option) : undefined }, option.id));
119
+ }), _jsx("div", { className: styles.inputWrapper, style: {
144
120
  minWidth: value
145
121
  ? 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)
146
122
  : '100%',
147
- }, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !selected || !selected.length ? 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 })] }) }));
123
+ }, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !selectedItems || !selectedItems.length ? placeholder : undefined, ref: mergeRefs(ref, localRef), onChange: searchable ? setInputValue : 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 })] }) }));
148
124
  } })) })));
149
125
  });
@@ -11,7 +11,7 @@ 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, useCallback, useEffect, useLayoutEffect, 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';
@@ -21,7 +21,7 @@ import { FieldDecorator } from '../FieldDecorator';
21
21
  import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
22
22
  import { useButtons, useHandleOnKeyDown, useSearchInput } from './hooks';
23
23
  import styles from './styles.module.css';
24
- import { extractListProps, findSelectedOption, getArrowIcon, transformOptionsToItems } from './utils';
24
+ import { extractListProps, getArrowIcon, updateItems } from './utils';
25
25
  export const FieldSelectSingle = forwardRef((_a, ref) => {
26
26
  var _b, _c;
27
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, addOptionByEnter = false, open: openProp, onOpenChange } = _a, rest = __rest(_a, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showCopyButton", "showClearButton", "onKeyDown", "required", "validationState", "search", "autocomplete", "prefixIcon", "addOptionByEnter", "open", "onOpenChange"]);
@@ -32,35 +32,27 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
32
32
  defaultValue,
33
33
  onChange: onChangeProp,
34
34
  });
35
- const items = useMemo(() => transformOptionsToItems(options), [options]);
36
- const { selected, itemsWithPlaceholder } = useMemo(() => {
37
- const [fonded, placeholder] = findSelectedOption(items, value);
38
- return {
39
- selected: fonded !== null && fonded !== void 0 ? fonded : placeholder,
40
- itemsWithPlaceholder: (placeholder ? [placeholder] : []).concat(items),
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 [{ selectedItem, items = [] }, setItems] = useState(() => updateItems({ options, value, currentItems: [], selectedItem: undefined }));
36
+ const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: (_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.content.option) !== null && _b !== void 0 ? _b : '' }));
37
+ useLayoutEffect(() => {
38
+ setItems(({ selectedItem }) => updateItems({ options, value, selectedItem }));
39
+ }, [options, value]);
44
40
  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]);
41
+ updateInputValue(selectedItem);
42
+ // eslint-disable-next-line react-hooks/exhaustive-deps
43
+ }, [selectedItem]);
50
44
  const handleBlur = (e) => {
51
- var _a, _b;
52
- if (!open && (selected === null || selected === void 0 ? void 0 : selected.content.option) !== inputValue) {
53
- onInputValueChange((_a = selected === null || selected === void 0 ? void 0 : selected.content.option) !== null && _a !== void 0 ? _a : '');
45
+ var _a;
46
+ if (!open) {
47
+ updateInputValue(selectedItem);
54
48
  }
55
- (_b = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _b === void 0 ? void 0 : _b.call(rest, e);
49
+ (_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
56
50
  };
57
- const onClear = () => {
51
+ const onClear = useCallback(() => {
58
52
  var _a;
59
- setValue('');
60
- onInputValueChange('');
53
+ setValue(undefined);
61
54
  (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
62
- setOpen(true);
63
- };
55
+ }, [setValue]);
64
56
  const { ArrowIcon, arrowIconSize } = getArrowIcon({ size, open });
65
57
  const { buttons, inputKeyDownNavigationHandler, buttonsRefs } = useButtons({
66
58
  readonly,
@@ -69,13 +61,21 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
69
61
  showCopyButton,
70
62
  inputRef: localRef,
71
63
  onClear,
72
- valueToCopy: (_c = selected === null || selected === void 0 ? void 0 : selected.content.option) !== null && _c !== void 0 ? _c : '',
64
+ valueToCopy: (_c = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.content.option) !== null && _c !== void 0 ? _c : '',
73
65
  });
74
66
  const commonHandleOnKeyDown = useHandleOnKeyDown({
75
67
  inputKeyDownNavigationHandler,
76
68
  onInputKeyDownProp,
77
69
  setOpen,
78
70
  });
71
+ const handleSelectionChange = useCallback((newValue) => {
72
+ var _a;
73
+ setValue(newValue);
74
+ (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
75
+ if (newValue) {
76
+ setOpen(false);
77
+ }
78
+ }, [setOpen, setValue]);
79
79
  const handleOnKeyDown = (onKeyDown) => (e) => {
80
80
  if (!open && prevInputValue.current !== inputValue) {
81
81
  setOpen(true);
@@ -85,35 +85,26 @@ export const FieldSelectSingle = forwardRef((_a, ref) => {
85
85
  e.preventDefault();
86
86
  }
87
87
  if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
88
- setValue(inputValue);
88
+ handleSelectionChange(inputValue);
89
89
  }
90
90
  commonHandleOnKeyDown(onKeyDown)(e);
91
91
  };
92
- const handleSelectionChange = (newValue) => {
93
- var _a;
94
- setValue(newValue);
95
- (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
96
- if (newValue) {
97
- setOpen(false);
98
- }
99
- };
100
92
  const handleOpenChange = (open) => {
101
- var _a, _b;
102
93
  if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
103
94
  setOpen(open);
104
95
  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 : '';
96
+ updateInputValue(selectedItem);
107
97
  }
108
98
  }
109
99
  };
110
- const fuzzySearch = useFuzzySearch(itemsWithPlaceholder);
111
- const result = autocomplete || !searchable || prevInputValue.current === inputValue
112
- ? itemsWithPlaceholder
113
- : fuzzySearch(inputValue);
100
+ const fuzzySearch = useFuzzySearch(items);
101
+ const result = autocomplete || !searchable || prevInputValue.current === inputValue ? items : fuzzySearch(inputValue);
114
102
  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: {
115
103
  mode: 'single',
116
104
  value: value,
117
105
  onChange: handleSelectionChange,
118
- }, size: size, open: open, onOpenChange: handleOpenChange, triggerElemRef: localRef, 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), onBlur: handleBlur }), _jsxs("div", { className: styles.postfix, children: [buttons, _jsx(ArrowIcon, { size: arrowIconSize, className: styles.arrowIcon })] })] })) })) })));
106
+ }, size: size, open: open, onOpenChange: handleOpenChange, triggerElemRef: localRef, children: ({ onKeyDown }) => {
107
+ var _a;
108
+ return (_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 ? setInputValue : undefined, value: searchable ? inputValue : (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.content.option) !== null && _a !== void 0 ? _a : '', readonly: !searchable || readonly, "data-test-id": 'field-select__input', onKeyDown: handleOnKeyDown(onKeyDown), onBlur: handleBlur }), _jsxs("div", { className: styles.postfix, children: [buttons, _jsx(ArrowIcon, { size: arrowIconSize, className: styles.arrowIcon })] })] }));
109
+ } })) })));
119
110
  });
@@ -23,8 +23,10 @@ export declare function useButtons({ readonly, showClearButton, showCopyButton,
23
23
  };
24
24
  export declare function useSearchInput({ value, onChange, defaultValue }: SearchState): {
25
25
  inputValue: string;
26
- onInputValueChange: Handler;
26
+ setInputValue: (value: any, ...args: any[]) => any;
27
27
  prevInputValue: import("react").MutableRefObject<string>;
28
+ onInputValueChange: (value: any, ...args: any[]) => any;
29
+ updateInputValue: (selectedItem?: ItemWithId) => void;
28
30
  };
29
31
  export declare function useHandleDeleteItem(setValue: Handler): (item?: ItemWithId) => (e?: MouseEvent<HTMLButtonElement>) => void;
30
32
  export {};
@@ -50,9 +50,15 @@ export function useButtons({ readonly, showClearButton, showCopyButton, size, on
50
50
  return { buttons, inputKeyDownNavigationHandler, buttonsRefs };
51
51
  }
52
52
  export function useSearchInput({ value, onChange, defaultValue }) {
53
- const [inputValue = '', onInputValueChange] = useValueControl({ value, onChange, defaultValue });
53
+ const [inputValue = '', setInputValue] = useValueControl({ value, onChange, defaultValue });
54
54
  const prevInputValue = useRef(inputValue);
55
- return { inputValue, onInputValueChange, prevInputValue };
55
+ const updateInputValue = useCallback((selectedItem) => {
56
+ var _a;
57
+ const newInputValue = (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.content.option) !== null && _a !== void 0 ? _a : '';
58
+ setInputValue(() => newInputValue);
59
+ prevInputValue.current = newInputValue;
60
+ }, [prevInputValue, setInputValue]);
61
+ return { inputValue, setInputValue, prevInputValue, onInputValueChange: setInputValue, updateInputValue };
56
62
  }
57
63
  export function useHandleDeleteItem(setValue) {
58
64
  return useCallback((item) => (e) => {
@@ -62,5 +62,8 @@ export type FieldSelectProps = (FieldSelectSingleProps & {
62
62
  }) | (FieldSelectMultipleProps & {
63
63
  selection: 'multiple';
64
64
  });
65
- export type ItemWithId = BaseItemProps | AccordionItemProps | NextListItemProps;
65
+ export type ItemWithId = (BaseItemProps | AccordionItemProps | NextListItemProps) & {
66
+ placeholder?: boolean;
67
+ appearance?: TagProps['appearance'];
68
+ };
66
69
  export {};
@@ -0,0 +1,3 @@
1
+ import { DroplistProps } from '@snack-uikit/list';
2
+ import { FieldSelectProps } from '../types';
3
+ export declare function extractListProps({ dataError, noDataState, noResultsState, errorDataState, pinTop, pinBottom, dataFiltered, loading, }: Partial<FieldSelectProps>): Partial<DroplistProps>;
@@ -0,0 +1,17 @@
1
+ export function extractListProps({ dataError, noDataState, noResultsState, errorDataState, pinTop, pinBottom, dataFiltered, loading, }) {
2
+ return {
3
+ dataError,
4
+ noDataState,
5
+ noResultsState,
6
+ errorDataState,
7
+ pinTop,
8
+ pinBottom,
9
+ dataFiltered,
10
+ loading,
11
+ trigger: 'clickAndFocusVisible',
12
+ placement: 'bottom',
13
+ 'data-test-id': 'field-select__list',
14
+ scroll: true,
15
+ marker: true,
16
+ };
17
+ }
@@ -0,0 +1,8 @@
1
+ import { Size } from '@snack-uikit/input-private';
2
+ export declare function getArrowIcon({ size, open }: {
3
+ size: Size;
4
+ open: boolean;
5
+ }): {
6
+ ArrowIcon: ({ size, ...props }: import("@snack-uikit/icons/dist/components/interface-icons/chevronUp").ISvgIconProps) => import("react/jsx-runtime").JSX.Element;
7
+ arrowIconSize: 16 | 24;
8
+ };
@@ -0,0 +1,8 @@
1
+ import { ChevronDownSVG, ChevronUpSVG } from '@snack-uikit/icons';
2
+ import { ICON_SIZE, SIZE } from '@snack-uikit/input-private';
3
+ export function getArrowIcon({ size, open }) {
4
+ return {
5
+ ArrowIcon: open ? ChevronUpSVG : ChevronDownSVG,
6
+ arrowIconSize: size === SIZE.S ? ICON_SIZE.Xs : ICON_SIZE.S,
7
+ };
8
+ }
@@ -0,0 +1,5 @@
1
+ export * from './typeGuards';
2
+ export * from './extractListProps';
3
+ export * from './options';
4
+ export * from './updateItems';
5
+ export * from './getArrowIcon';
@@ -0,0 +1,5 @@
1
+ export * from './typeGuards';
2
+ export * from './extractListProps';
3
+ export * from './options';
4
+ export * from './updateItems';
5
+ export * from './getArrowIcon';
@@ -0,0 +1,8 @@
1
+ import { ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
2
+ import { TagProps } from '@snack-uikit/tag';
3
+ import { ItemWithId, OptionProps } from '../types';
4
+ export declare function transformOptionsToItems(options: OptionProps[]): (ItemProps & {
5
+ appearance?: TagProps['appearance'];
6
+ })[];
7
+ export declare function findSelectedOption(items: ItemProps[], value: SelectionSingleValueType): [ItemWithId | undefined, ItemWithId | undefined];
8
+ export declare function findSelectedOptions(items: ItemProps[], value: SelectionSingleValueType[] | undefined): [ItemWithId[] | undefined, ItemWithId[] | undefined];
@@ -0,0 +1,56 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { flattenItems } from '@snack-uikit/list';
13
+ import { isAccordionOptionProps, isGroupOptionProps, isNextListOptionProps } from './typeGuards';
14
+ export function transformOptionsToItems(options) {
15
+ return options.map(option => {
16
+ if (isAccordionOptionProps(option) || isNextListOptionProps(option)) {
17
+ const { description, option: contentOption, caption, options, value } = option, rest = __rest(option, ["description", "option", "caption", "options", "value"]);
18
+ return Object.assign(Object.assign({ 'data-test-id': 'field-select__list-option-' + option.value }, rest), { id: value, content: { option: contentOption, caption, description }, items: transformOptionsToItems(options) });
19
+ }
20
+ if (isGroupOptionProps(option)) {
21
+ const { options } = option, rest = __rest(option, ["options"]);
22
+ return Object.assign(Object.assign({}, rest), { items: transformOptionsToItems(options) });
23
+ }
24
+ const _a = option, { description, option: contentOption, caption, value, appearance } = _a, rest = __rest(_a, ["description", "option", "caption", "value", "appearance"]);
25
+ return Object.assign(Object.assign({ 'data-test-id': 'field-select__list-option-' + option.value }, rest), { id: value, appearance: appearance, content: { option: contentOption, caption, description } });
26
+ });
27
+ }
28
+ export function findSelectedOption(items, value) {
29
+ const flatten = flattenItems(items);
30
+ if (!value) {
31
+ return [undefined, undefined];
32
+ }
33
+ const foundItem = flatten.find(item => String(item.id) === String(value));
34
+ const placeholderItem = { id: value, content: { option: String(value) } };
35
+ return [foundItem, !foundItem ? placeholderItem : undefined];
36
+ }
37
+ export function findSelectedOptions(items, value) {
38
+ const flatten = flattenItems(items);
39
+ if (!value || !(value === null || value === void 0 ? void 0 : value.length)) {
40
+ return [undefined, undefined];
41
+ }
42
+ let foundItems;
43
+ let placeholderItems;
44
+ value.forEach(value => {
45
+ if (flatten) {
46
+ const [found, placeholder] = findSelectedOption(flatten, value);
47
+ if (found || foundItems) {
48
+ foundItems = (foundItems !== null && foundItems !== void 0 ? foundItems : []).concat(found !== null && found !== void 0 ? found : []);
49
+ }
50
+ if (placeholder || placeholderItems) {
51
+ placeholderItems = (placeholderItems !== null && placeholderItems !== void 0 ? placeholderItems : []).concat(placeholder !== null && placeholder !== void 0 ? placeholder : []);
52
+ }
53
+ }
54
+ });
55
+ return [foundItems, placeholderItems];
56
+ }
@@ -0,0 +1,7 @@
1
+ import { AccordionOptionProps, BaseOptionProps, FieldSelectMultipleProps, FieldSelectSingleProps, GroupOptionProps, NestListOptionProps } from '../types';
2
+ export declare function isBaseOptionProps(option: any): option is BaseOptionProps;
3
+ export declare function isAccordionOptionProps(option: any): option is AccordionOptionProps;
4
+ export declare function isNextListOptionProps(option: any): option is NestListOptionProps;
5
+ export declare function isGroupOptionProps(option: any): option is GroupOptionProps;
6
+ export declare function isFieldSelectMultipleProps(props: any): props is FieldSelectMultipleProps;
7
+ export declare function isFieldSelectSingleProps(props: any): props is FieldSelectSingleProps;
@@ -0,0 +1,24 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export function isBaseOptionProps(option) {
3
+ return !('options' in option);
4
+ }
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ export function isAccordionOptionProps(option) {
7
+ return 'options' in option && option['type'] === 'collapse';
8
+ }
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ export function isNextListOptionProps(option) {
11
+ return 'options' in option && option['type'] === 'next-list';
12
+ }
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ export function isGroupOptionProps(option) {
15
+ return 'options' in option && option['type'] === undefined;
16
+ }
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ export function isFieldSelectMultipleProps(props) {
19
+ return 'selection' in props && props['selection'] === 'multiple';
20
+ }
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ export function isFieldSelectSingleProps(props) {
23
+ return ('selection' in props && props['selection'] === 'single') || props['selection'] === undefined;
24
+ }
@@ -0,0 +1,32 @@
1
+ import { ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
2
+ import { ItemWithId, OptionProps } from '../types';
3
+ export declare function createPlaceholderItem(value: SelectionSingleValueType): {
4
+ id: SelectionSingleValueType;
5
+ content: {
6
+ option: string;
7
+ };
8
+ placeholder: boolean;
9
+ };
10
+ export declare function updateItems({ options, value, selectedItem, }: {
11
+ options: OptionProps[];
12
+ value: SelectionSingleValueType;
13
+ selectedItem?: ItemWithId;
14
+ currentItems?: ItemProps[];
15
+ }): {
16
+ selectedItem: ItemWithId | undefined;
17
+ items: ItemProps[];
18
+ };
19
+ export declare function updateMultipleItems({ options, value, selectedItems, }: {
20
+ options: OptionProps[];
21
+ value?: SelectionSingleValueType[];
22
+ selectedItems?: ItemWithId[];
23
+ currentItems?: ItemProps[];
24
+ }): {
25
+ selectedItems: undefined;
26
+ items: (ItemProps & {
27
+ appearance?: import("@snack-uikit/tag/dist/types").Appearance | undefined;
28
+ })[];
29
+ } | {
30
+ selectedItems: ItemWithId[];
31
+ items: ItemProps[];
32
+ };
@@ -0,0 +1,67 @@
1
+ import { flattenItems } from '@snack-uikit/list';
2
+ import { transformOptionsToItems } from './options';
3
+ export function createPlaceholderItem(value) {
4
+ return { id: value, content: { option: String(value) }, placeholder: true };
5
+ }
6
+ export function updateItems({ options, value, selectedItem, }) {
7
+ const originalItems = transformOptionsToItems(options);
8
+ if (!value) {
9
+ return {
10
+ selectedItem: undefined,
11
+ items: originalItems,
12
+ };
13
+ }
14
+ let newItems = originalItems;
15
+ let newSelectedItem = selectedItem;
16
+ const foundItem = flattenItems(originalItems).find(item => item.id === value);
17
+ if (!foundItem) {
18
+ if (selectedItem && (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === value) {
19
+ newItems = [selectedItem, ...newItems];
20
+ }
21
+ else {
22
+ newSelectedItem = createPlaceholderItem(value);
23
+ newItems = [newSelectedItem, ...newItems];
24
+ }
25
+ }
26
+ else {
27
+ newSelectedItem = foundItem;
28
+ }
29
+ return {
30
+ selectedItem: newSelectedItem,
31
+ items: newItems,
32
+ };
33
+ }
34
+ export function updateMultipleItems({ options, value, selectedItems, }) {
35
+ const originalItems = transformOptionsToItems(options);
36
+ if (!value || !value.length) {
37
+ return {
38
+ selectedItems: undefined,
39
+ items: originalItems,
40
+ };
41
+ }
42
+ let newItems = originalItems;
43
+ let newSelectedItems = selectedItems;
44
+ const flattenOriginalItems = flattenItems(originalItems);
45
+ const foundItems = flattenOriginalItems.filter(item => value.includes(item.id));
46
+ const nonFoundValues = value.filter(value => !flattenOriginalItems.find(item => item.id === value));
47
+ if (nonFoundValues.length) {
48
+ const nonFoundItems = nonFoundValues.map(value => (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.find(selectedItem => selectedItem.id === value)) || createPlaceholderItem(value));
49
+ newSelectedItems = [...foundItems, ...nonFoundItems];
50
+ newItems = [...nonFoundItems, ...newItems];
51
+ }
52
+ else {
53
+ newSelectedItems = foundItems;
54
+ }
55
+ return {
56
+ selectedItems: newSelectedItems.sort((a, b) => {
57
+ if (b.disabled && !a.disabled) {
58
+ return 1;
59
+ }
60
+ if (a.disabled && !b.disabled) {
61
+ return -1;
62
+ }
63
+ return 0;
64
+ }),
65
+ items: newItems,
66
+ };
67
+ }