@snack-uikit/fields 0.53.2-preview-0be0d183.0 → 0.54.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 +11 -0
- package/README.md +2 -2
- package/dist/cjs/components/FieldSelect/FieldSelectMultiple.d.ts +2 -2
- package/dist/cjs/components/FieldSelect/FieldSelectMultiple.js +9 -11
- package/dist/cjs/components/FieldSelect/FieldSelectSingle.js +9 -10
- package/dist/cjs/components/FieldSelect/{hooks.d.ts → hooks/common.d.ts} +1 -6
- package/dist/cjs/components/FieldSelect/{hooks.js → hooks/common.js} +4 -18
- package/dist/cjs/components/FieldSelect/hooks/customOption.d.ts +26 -0
- package/dist/cjs/components/FieldSelect/hooks/customOption.js +69 -0
- package/dist/cjs/components/FieldSelect/hooks/index.d.ts +2 -0
- package/dist/cjs/components/FieldSelect/hooks/index.js +26 -0
- package/dist/cjs/components/FieldSelect/index.d.ts +1 -1
- package/dist/cjs/components/FieldSelect/types.d.ts +3 -3
- package/dist/cjs/components/FieldSelect/utils/customOption.d.ts +4 -0
- package/dist/cjs/components/FieldSelect/utils/index.d.ts +2 -1
- package/dist/cjs/components/FieldSelect/utils/index.js +2 -1
- package/dist/esm/components/FieldSelect/FieldSelectMultiple.d.ts +2 -2
- package/dist/esm/components/FieldSelect/FieldSelectMultiple.js +6 -11
- package/dist/esm/components/FieldSelect/FieldSelectSingle.js +7 -11
- package/dist/esm/components/FieldSelect/{hooks.d.ts → hooks/common.d.ts} +1 -6
- package/dist/esm/components/FieldSelect/{hooks.js → hooks/common.js} +3 -12
- package/dist/esm/components/FieldSelect/hooks/customOption.d.ts +26 -0
- package/dist/esm/components/FieldSelect/hooks/customOption.js +38 -0
- package/dist/esm/components/FieldSelect/hooks/index.d.ts +2 -0
- package/dist/esm/components/FieldSelect/hooks/index.js +2 -0
- package/dist/esm/components/FieldSelect/index.d.ts +1 -1
- package/dist/esm/components/FieldSelect/types.d.ts +3 -3
- package/dist/esm/components/FieldSelect/utils/customOption.d.ts +4 -0
- package/dist/esm/components/FieldSelect/utils/index.d.ts +2 -1
- package/dist/esm/components/FieldSelect/utils/index.js +2 -1
- package/package.json +2 -2
- package/src/components/FieldSelect/FieldSelectMultiple.tsx +7 -22
- package/src/components/FieldSelect/FieldSelectSingle.tsx +8 -22
- package/src/components/FieldSelect/{hooks.ts → hooks/common.ts} +4 -23
- package/src/components/FieldSelect/hooks/customOption.ts +90 -0
- package/src/components/FieldSelect/hooks/index.ts +2 -0
- package/src/components/FieldSelect/index.ts +1 -1
- package/src/components/FieldSelect/types.ts +6 -3
- package/src/components/FieldSelect/utils/customOption.ts +23 -0
- package/src/components/FieldSelect/utils/index.ts +2 -1
- package/dist/cjs/components/FieldSelect/utils/getCustomOptionTriggerByCode.d.ts +0 -4
- package/dist/esm/components/FieldSelect/utils/getCustomOptionTriggerByCode.d.ts +0 -4
- package/src/components/FieldSelect/utils/getCustomOptionTriggerByCode.ts +0 -23
- /package/dist/cjs/components/FieldSelect/utils/{getCustomOptionTriggerByCode.js → customOption.js} +0 -0
- /package/dist/esm/components/FieldSelect/utils/{getCustomOptionTriggerByCode.js → customOption.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
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.54.0 (2026-04-21)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **IAM-6423:** support triggers for custom field option ([1865a13](https://github.com/cloud-ru-tech/snack-uikit/commit/1865a13f6e270de961295a96ad7c8d80c7cb147d))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## 0.53.1 (2026-04-02)
|
|
7
18
|
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -741,12 +741,12 @@ FieldStepper в основном предназначен для работы с
|
|
|
741
741
|
| noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
|
|
742
742
|
| noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
|
|
743
743
|
| errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
|
|
744
|
-
| addCustomOptionTriggers | `FieldSelectSingleAddCustomOptionTrigger[] \|
|
|
744
|
+
| addCustomOptionTriggers | `FieldSelectSingleAddCustomOptionTrigger[] \| FieldSelectMultipleAddCustomOptionTrigger[]` | - | Триггеры фиксации произвольного значения из строки поиска в режиме `single`. Если передан, имеет приоритет над устаревшим `addOptionByEnter`. Триггеры фиксации произвольного значения из строки поиска в режиме `multiple`. Если передан, имеет приоритет над устаревшим `addOptionByEnter`. |
|
|
745
745
|
| selection | "single" \| "multiple" | - | |
|
|
746
746
|
| ref | `LegacyRef<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 {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
|
|
747
747
|
| key | `Key` | - | |
|
|
748
748
|
| removeByBackspace | `boolean` | - | |
|
|
749
|
-
##
|
|
749
|
+
## FieldSelectMultipleAddCustomOptionTrigger
|
|
750
750
|
События, по которым произвольное значение из строки поиска фиксируется в значении поля
|
|
751
751
|
### Props
|
|
752
752
|
| name | type | default value | description |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SelectedOptionFormatter } from './types';
|
|
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;
|
|
@@ -29,5 +29,5 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
|
|
|
29
29
|
onOpenChange?(open: boolean): void;
|
|
30
30
|
selectedOptionFormatter?: SelectedOptionFormatter;
|
|
31
31
|
} & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState">, "showCopyButton" | "onCopyButtonClick"> & {
|
|
32
|
-
addCustomOptionTriggers?:
|
|
32
|
+
addCustomOptionTriggers?: import("./types").FieldSelectMultipleAddCustomOptionTrigger[];
|
|
33
33
|
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -103,19 +103,17 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
|
|
|
103
103
|
selectedOptionFormatter,
|
|
104
104
|
resetSearchOnOptionSelection
|
|
105
105
|
}));
|
|
106
|
-
const
|
|
106
|
+
const {
|
|
107
|
+
resolvedAddCustomOptionTriggers,
|
|
108
|
+
tryCommitCustomOptionFromInput
|
|
109
|
+
} = (0, hooks_2.useFieldSelectMultipleCustomOption)({
|
|
107
110
|
addCustomOptionTriggers,
|
|
108
|
-
addOptionByEnter
|
|
111
|
+
addOptionByEnter,
|
|
112
|
+
inputValue,
|
|
113
|
+
value,
|
|
114
|
+
setValue,
|
|
115
|
+
updateInputValue
|
|
109
116
|
});
|
|
110
|
-
const tryCommitCustomOptionFromInput = (0, react_1.useCallback)(trigger => {
|
|
111
|
-
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (!(value !== null && value !== void 0 ? value : []).includes(inputValue)) {
|
|
115
|
-
setValue(prev => (prev !== null && prev !== void 0 ? prev : []).concat(inputValue));
|
|
116
|
-
updateInputValue();
|
|
117
|
-
}
|
|
118
|
-
}, [resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue]);
|
|
119
117
|
const prefixSettings = (0, hooks_1.usePrefix)({
|
|
120
118
|
prefix,
|
|
121
119
|
disabled
|
|
@@ -100,10 +100,6 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
|
|
|
100
100
|
resetSearchOnOptionSelection,
|
|
101
101
|
selectedOptionFormatter
|
|
102
102
|
}));
|
|
103
|
-
const resolvedAddCustomOptionTriggers = (0, hooks_2.useResolvedAddCustomOptionTriggers)({
|
|
104
|
-
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
105
|
-
addOptionByEnter
|
|
106
|
-
});
|
|
107
103
|
const prevSelectedItem = (0, react_1.useRef)(selectedItem);
|
|
108
104
|
const prefixSettings = (0, hooks_1.usePrefix)({
|
|
109
105
|
prefix,
|
|
@@ -178,12 +174,15 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
|
|
|
178
174
|
setValue(newValue);
|
|
179
175
|
}
|
|
180
176
|
}, [setOpen, setValue]);
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
const {
|
|
178
|
+
resolvedAddCustomOptionTriggers,
|
|
179
|
+
tryCommitCustomOptionFromInput
|
|
180
|
+
} = (0, hooks_2.useFieldSelectSingleCustomOption)({
|
|
181
|
+
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
182
|
+
addOptionByEnter,
|
|
183
|
+
inputValue,
|
|
184
|
+
handleSelectionChange
|
|
185
|
+
});
|
|
187
186
|
const handleBlur = e => {
|
|
188
187
|
var _a;
|
|
189
188
|
if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KeyboardEvent, KeyboardEventHandler, MouseEvent, RefObject } from 'react';
|
|
2
2
|
import { Handler } from 'uncontrollable';
|
|
3
3
|
import { ItemProps } from '@snack-uikit/list';
|
|
4
|
-
import {
|
|
4
|
+
import { ItemWithId, SearchState, SelectedOptionFormatter } from '../types';
|
|
5
5
|
type UseHandleOnKeyDownProps = {
|
|
6
6
|
inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
|
|
7
7
|
onInputKeyDownProp: KeyboardEventHandler<HTMLInputElement> | undefined;
|
|
@@ -38,9 +38,4 @@ export declare function useHandleDeleteItem(setValue: Handler): (item?: ItemWith
|
|
|
38
38
|
* Четкий и нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
|
|
39
39
|
*/
|
|
40
40
|
export declare function useSearch(items: ItemProps[], enableFuzzySearch?: boolean): (search: string) => import("@snack-uikit/list/dist/esm/components/Items").Item[];
|
|
41
|
-
type UseResolvedAddCustomOptionTriggersProps = {
|
|
42
|
-
addCustomOptionTriggers?: FieldSelectAddCustomOptionTrigger[];
|
|
43
|
-
addOptionByEnter: boolean;
|
|
44
|
-
};
|
|
45
|
-
export declare function useResolvedAddCustomOptionTriggers({ addCustomOptionTriggers, addOptionByEnter, }: UseResolvedAddCustomOptionTriggersProps): FieldSelectAddCustomOptionTrigger[];
|
|
46
41
|
export {};
|
|
@@ -13,15 +13,13 @@ exports.useButtons = useButtons;
|
|
|
13
13
|
exports.useSearchInput = useSearchInput;
|
|
14
14
|
exports.useHandleDeleteItem = useHandleDeleteItem;
|
|
15
15
|
exports.useSearch = useSearch;
|
|
16
|
-
exports.useResolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers;
|
|
17
16
|
const fuzzy_search_1 = __importDefault(require("fuzzy-search"));
|
|
18
17
|
const react_1 = require("react");
|
|
19
18
|
const input_private_1 = require("@snack-uikit/input-private");
|
|
20
19
|
const list_1 = require("@snack-uikit/list");
|
|
21
|
-
const hooks_1 = require("
|
|
22
|
-
const legacy_1 = require("
|
|
23
|
-
const utils_1 = require("
|
|
24
|
-
const filterItemsByFlattenIds_1 = require("./utils/filterItemsByFlattenIds");
|
|
20
|
+
const hooks_1 = require("../../../hooks");
|
|
21
|
+
const legacy_1 = require("../legacy");
|
|
22
|
+
const utils_1 = require("../utils");
|
|
25
23
|
function useHandleOnKeyDown(_ref) {
|
|
26
24
|
let {
|
|
27
25
|
setOpen,
|
|
@@ -174,19 +172,7 @@ function useSearch(items) {
|
|
|
174
172
|
}, [enableFuzzySearch, flattenItems]);
|
|
175
173
|
const filterFunction = (0, react_1.useCallback)(search => {
|
|
176
174
|
const filteredIds = filterFlattenFunction(search).map(item => item.id);
|
|
177
|
-
return (0,
|
|
175
|
+
return (0, utils_1.filterItemsByFlattenIds)(items, filteredIds);
|
|
178
176
|
}, [filterFlattenFunction, items]);
|
|
179
177
|
return (0, react_1.useCallback)(search => search.length >= DEFAULT_MIN_SEARCH_INPUT_LENGTH ? filterFunction(search) : items, [filterFunction, items]);
|
|
180
|
-
}
|
|
181
|
-
function useResolvedAddCustomOptionTriggers(_ref4) {
|
|
182
|
-
let {
|
|
183
|
-
addCustomOptionTriggers,
|
|
184
|
-
addOptionByEnter
|
|
185
|
-
} = _ref4;
|
|
186
|
-
return (0, react_1.useMemo)(() => {
|
|
187
|
-
if (addCustomOptionTriggers !== undefined) {
|
|
188
|
-
return addCustomOptionTriggers;
|
|
189
|
-
}
|
|
190
|
-
return addOptionByEnter ? ['enter'] : [];
|
|
191
|
-
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
192
178
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Handler } from 'uncontrollable';
|
|
2
|
+
import { SelectionSingleValueType } from '@snack-uikit/list';
|
|
3
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
4
|
+
type UseResolvedAddCustomOptionTriggersParams = {
|
|
5
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
6
|
+
addOptionByEnter: boolean;
|
|
7
|
+
};
|
|
8
|
+
type UseFieldSelectMultipleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
9
|
+
inputValue: string;
|
|
10
|
+
value: SelectionSingleValueType[] | undefined;
|
|
11
|
+
setValue: Handler;
|
|
12
|
+
updateInputValue: () => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function useFieldSelectMultipleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, value, setValue, updateInputValue, }: UseFieldSelectMultipleCustomOptionParams): {
|
|
15
|
+
resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
16
|
+
tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
|
|
17
|
+
};
|
|
18
|
+
type UseFieldSelectSingleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
19
|
+
inputValue: string;
|
|
20
|
+
handleSelectionChange: (value: SelectionSingleValueType) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function useFieldSelectSingleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, handleSelectionChange, }: UseFieldSelectSingleCustomOptionParams): {
|
|
23
|
+
resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
24
|
+
tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useFieldSelectMultipleCustomOption = useFieldSelectMultipleCustomOption;
|
|
7
|
+
exports.useFieldSelectSingleCustomOption = useFieldSelectSingleCustomOption;
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
function useResolvedAddCustomOptionTriggers(_ref) {
|
|
10
|
+
let {
|
|
11
|
+
addCustomOptionTriggers,
|
|
12
|
+
addOptionByEnter
|
|
13
|
+
} = _ref;
|
|
14
|
+
return (0, react_1.useMemo)(() => {
|
|
15
|
+
if (addCustomOptionTriggers !== undefined) {
|
|
16
|
+
return addCustomOptionTriggers;
|
|
17
|
+
}
|
|
18
|
+
return addOptionByEnter ? ['enter'] : [];
|
|
19
|
+
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
20
|
+
}
|
|
21
|
+
function useFieldSelectMultipleCustomOption(_ref2) {
|
|
22
|
+
let {
|
|
23
|
+
addCustomOptionTriggers,
|
|
24
|
+
addOptionByEnter,
|
|
25
|
+
inputValue,
|
|
26
|
+
value,
|
|
27
|
+
setValue,
|
|
28
|
+
updateInputValue
|
|
29
|
+
} = _ref2;
|
|
30
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
31
|
+
addCustomOptionTriggers,
|
|
32
|
+
addOptionByEnter
|
|
33
|
+
});
|
|
34
|
+
const tryCommitCustomOptionFromInput = (0, react_1.useCallback)(trigger => {
|
|
35
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!(value !== null && value !== void 0 ? value : []).includes(inputValue)) {
|
|
39
|
+
setValue(prev => (prev !== null && prev !== void 0 ? prev : []).concat(inputValue));
|
|
40
|
+
updateInputValue();
|
|
41
|
+
}
|
|
42
|
+
}, [resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue]);
|
|
43
|
+
return {
|
|
44
|
+
resolvedAddCustomOptionTriggers,
|
|
45
|
+
tryCommitCustomOptionFromInput
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function useFieldSelectSingleCustomOption(_ref3) {
|
|
49
|
+
let {
|
|
50
|
+
addCustomOptionTriggers,
|
|
51
|
+
addOptionByEnter,
|
|
52
|
+
inputValue,
|
|
53
|
+
handleSelectionChange
|
|
54
|
+
} = _ref3;
|
|
55
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
56
|
+
addCustomOptionTriggers,
|
|
57
|
+
addOptionByEnter
|
|
58
|
+
});
|
|
59
|
+
const tryCommitCustomOptionFromInput = (0, react_1.useCallback)(trigger => {
|
|
60
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
handleSelectionChange(inputValue);
|
|
64
|
+
}, [resolvedAddCustomOptionTriggers, inputValue, handleSelectionChange]);
|
|
65
|
+
return {
|
|
66
|
+
resolvedAddCustomOptionTriggers,
|
|
67
|
+
tryCommitCustomOptionFromInput
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return m[k];
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
} : function (o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
});
|
|
19
|
+
var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", {
|
|
23
|
+
value: true
|
|
24
|
+
});
|
|
25
|
+
__exportStar(require("./common"), exports);
|
|
26
|
+
__exportStar(require("./customOption"), exports);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { FieldSelect } from './FieldSelect';
|
|
2
|
-
export type {
|
|
2
|
+
export type { FieldSelectMultipleAddCustomOptionTrigger, FieldSelectSingleAddCustomOptionTrigger, FieldSelectSingleProps, FieldSelectMultipleProps, FieldSelectProps, OptionProps, BaseOptionProps, AccordionOptionProps, NestListOptionProps, GroupOptionProps, SelectedOptionFormatter, } from './types';
|
|
@@ -32,8 +32,8 @@ export type SearchState = {
|
|
|
32
32
|
onChange?(value: string): void;
|
|
33
33
|
};
|
|
34
34
|
/** События, по которым произвольное значение из строки поиска фиксируется в значении поля */
|
|
35
|
-
export type
|
|
36
|
-
export type FieldSelectSingleAddCustomOptionTrigger = Extract<
|
|
35
|
+
export type FieldSelectMultipleAddCustomOptionTrigger = 'enter' | 'blur' | 'space' | 'comma';
|
|
36
|
+
export type FieldSelectSingleAddCustomOptionTrigger = Extract<FieldSelectMultipleAddCustomOptionTrigger, 'enter' | 'blur'>;
|
|
37
37
|
export type FieldSelectPrivateProps = InputProps & WrapperProps & {
|
|
38
38
|
options: OptionProps[];
|
|
39
39
|
loading?: boolean;
|
|
@@ -95,7 +95,7 @@ export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
|
95
95
|
* Триггеры фиксации произвольного значения из строки поиска в режиме `multiple`.
|
|
96
96
|
* Если передан, имеет приоритет над устаревшим `addOptionByEnter`.
|
|
97
97
|
*/
|
|
98
|
-
addCustomOptionTriggers?:
|
|
98
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
99
99
|
};
|
|
100
100
|
export type FieldSelectProps = (FieldSelectSingleProps & {
|
|
101
101
|
selection?: 'single';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { KeyboardEvent } from 'react';
|
|
2
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
3
|
+
export declare const getCustomOptionTriggerByCode: (code: KeyboardEvent<HTMLInputElement>["code"]) => FieldSelectMultipleAddCustomOptionTrigger | undefined;
|
|
4
|
+
export declare const shouldHandleCustomOptionTrigger: (trigger: FieldSelectMultipleAddCustomOptionTrigger | undefined, availableTriggers: FieldSelectMultipleAddCustomOptionTrigger[]) => trigger is FieldSelectMultipleAddCustomOptionTrigger;
|
|
@@ -5,4 +5,5 @@ export * from './updateItems';
|
|
|
5
5
|
export * from './getArrowIcon';
|
|
6
6
|
export * from './getValueByPath';
|
|
7
7
|
export * from './checkisSearchUnavailable';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './customOption';
|
|
9
|
+
export * from './filterItemsByFlattenIds';
|
|
@@ -29,4 +29,5 @@ __exportStar(require("./updateItems"), exports);
|
|
|
29
29
|
__exportStar(require("./getArrowIcon"), exports);
|
|
30
30
|
__exportStar(require("./getValueByPath"), exports);
|
|
31
31
|
__exportStar(require("./checkisSearchUnavailable"), exports);
|
|
32
|
-
__exportStar(require("./
|
|
32
|
+
__exportStar(require("./customOption"), exports);
|
|
33
|
+
__exportStar(require("./filterItemsByFlattenIds"), exports);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SelectedOptionFormatter } from './types';
|
|
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;
|
|
@@ -29,5 +29,5 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
|
|
|
29
29
|
onOpenChange?(open: boolean): void;
|
|
30
30
|
selectedOptionFormatter?: SelectedOptionFormatter;
|
|
31
31
|
} & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState">, "showCopyButton" | "onCopyButtonClick"> & {
|
|
32
|
-
addCustomOptionTriggers?:
|
|
32
|
+
addCustomOptionTriggers?: import("./types").FieldSelectMultipleAddCustomOptionTrigger[];
|
|
33
33
|
} & import("react").RefAttributes<HTMLInputElement>>;
|
|
@@ -22,7 +22,7 @@ import { usePostfix, usePrefix, useValueControl } from '../../hooks';
|
|
|
22
22
|
import { getValidationState } from '../../utils/getValidationState';
|
|
23
23
|
import { FieldDecorator } from '../FieldDecorator';
|
|
24
24
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
25
|
-
import { useButtons, useHandleDeleteItem, useHandleOnKeyDown,
|
|
25
|
+
import { useButtons, useFieldSelectMultipleCustomOption, useHandleDeleteItem, useHandleOnKeyDown, useSearch, useSearchInput, } from './hooks';
|
|
26
26
|
import styles from './styles.module.css';
|
|
27
27
|
import { checkisSearchUnavailable, extractListProps, getArrowIcon, getCustomOptionTriggerByCode, shouldHandleCustomOptionTrigger, updateMultipleItems, } from './utils';
|
|
28
28
|
const BASE_MIN_WIDTH = 4;
|
|
@@ -45,19 +45,14 @@ export const FieldSelectMultiple = forwardRef((props, ref) => {
|
|
|
45
45
|
const [{ selectedItems, items = [] }, setItems] = useState(() => updateMultipleItems({ options, value, currentItems: [], selectedItems: undefined }));
|
|
46
46
|
const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '', selectedOptionFormatter,
|
|
47
47
|
resetSearchOnOptionSelection }));
|
|
48
|
-
const resolvedAddCustomOptionTriggers =
|
|
48
|
+
const { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput } = useFieldSelectMultipleCustomOption({
|
|
49
49
|
addCustomOptionTriggers,
|
|
50
50
|
addOptionByEnter,
|
|
51
|
+
inputValue,
|
|
52
|
+
value,
|
|
53
|
+
setValue,
|
|
54
|
+
updateInputValue,
|
|
51
55
|
});
|
|
52
|
-
const tryCommitCustomOptionFromInput = useCallback((trigger) => {
|
|
53
|
-
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (!(value !== null && value !== void 0 ? value : []).includes(inputValue)) {
|
|
57
|
-
setValue((prev) => (prev !== null && prev !== void 0 ? prev : []).concat(inputValue));
|
|
58
|
-
updateInputValue();
|
|
59
|
-
}
|
|
60
|
-
}, [resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue]);
|
|
61
56
|
const prefixSettings = usePrefix({ prefix, disabled });
|
|
62
57
|
const postfixSettings = usePostfix({ postfix, disabled });
|
|
63
58
|
useLayoutEffect(() => {
|
|
@@ -21,7 +21,7 @@ import { usePostfix, usePrefix, useValueControl } from '../../hooks';
|
|
|
21
21
|
import { getValidationState } from '../../utils/getValidationState';
|
|
22
22
|
import { FieldDecorator } from '../FieldDecorator';
|
|
23
23
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
24
|
-
import { useButtons,
|
|
24
|
+
import { useButtons, useFieldSelectSingleCustomOption, useHandleOnKeyDown, useSearch, useSearchInput } from './hooks';
|
|
25
25
|
import styles from './styles.module.css';
|
|
26
26
|
import { checkisSearchUnavailable, extractListProps, getArrowIcon, shouldHandleCustomOptionTrigger, updateItems, } from './utils';
|
|
27
27
|
const defaultSelectedOptionFormatter = item =>
|
|
@@ -40,10 +40,6 @@ export const FieldSelectSingle = forwardRef((props, ref) => {
|
|
|
40
40
|
const [{ selectedItem, items = [] }, setItems] = useState(() => updateItems({ options, value, currentItems: [], selectedItem: undefined }));
|
|
41
41
|
const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: selectedOptionFormatter(selectedItem), resetSearchOnOptionSelection,
|
|
42
42
|
selectedOptionFormatter }));
|
|
43
|
-
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
44
|
-
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
45
|
-
addOptionByEnter,
|
|
46
|
-
});
|
|
47
43
|
const prevSelectedItem = useRef(selectedItem);
|
|
48
44
|
const prefixSettings = usePrefix({ prefix, disabled });
|
|
49
45
|
const postfixSettings = usePostfix({ postfix, disabled });
|
|
@@ -94,12 +90,12 @@ export const FieldSelectSingle = forwardRef((props, ref) => {
|
|
|
94
90
|
setValue(newValue);
|
|
95
91
|
}
|
|
96
92
|
}, [setOpen, setValue]);
|
|
97
|
-
const tryCommitCustomOptionFromInput =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
handleSelectionChange
|
|
102
|
-
}
|
|
93
|
+
const { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput } = useFieldSelectSingleCustomOption({
|
|
94
|
+
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
95
|
+
addOptionByEnter,
|
|
96
|
+
inputValue,
|
|
97
|
+
handleSelectionChange,
|
|
98
|
+
});
|
|
103
99
|
const handleBlur = (e) => {
|
|
104
100
|
var _a;
|
|
105
101
|
if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KeyboardEvent, KeyboardEventHandler, MouseEvent, RefObject } from 'react';
|
|
2
2
|
import { Handler } from 'uncontrollable';
|
|
3
3
|
import { ItemProps } from '@snack-uikit/list';
|
|
4
|
-
import {
|
|
4
|
+
import { ItemWithId, SearchState, SelectedOptionFormatter } from '../types';
|
|
5
5
|
type UseHandleOnKeyDownProps = {
|
|
6
6
|
inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
|
|
7
7
|
onInputKeyDownProp: KeyboardEventHandler<HTMLInputElement> | undefined;
|
|
@@ -38,9 +38,4 @@ export declare function useHandleDeleteItem(setValue: Handler): (item?: ItemWith
|
|
|
38
38
|
* Четкий и нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
|
|
39
39
|
*/
|
|
40
40
|
export declare function useSearch(items: ItemProps[], enableFuzzySearch?: boolean): (search: string) => import("@snack-uikit/list/dist/esm/components/Items").Item[];
|
|
41
|
-
type UseResolvedAddCustomOptionTriggersProps = {
|
|
42
|
-
addCustomOptionTriggers?: FieldSelectAddCustomOptionTrigger[];
|
|
43
|
-
addOptionByEnter: boolean;
|
|
44
|
-
};
|
|
45
|
-
export declare function useResolvedAddCustomOptionTriggers({ addCustomOptionTriggers, addOptionByEnter, }: UseResolvedAddCustomOptionTriggersProps): FieldSelectAddCustomOptionTrigger[];
|
|
46
41
|
export {};
|
|
@@ -2,10 +2,9 @@ import FuzzySearch from 'fuzzy-search';
|
|
|
2
2
|
import { useCallback, useMemo, useRef } from 'react';
|
|
3
3
|
import { useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
|
|
4
4
|
import { isAccordionItemProps, isNextListItemProps, kindFlattenItems, } from '@snack-uikit/list';
|
|
5
|
-
import { useCopyButton, useValueControl } from '
|
|
6
|
-
import { extractChildIds } from '
|
|
7
|
-
import { getValueByPath, isBaseOptionProps } from '
|
|
8
|
-
import { filterItemsByFlattenIds } from './utils/filterItemsByFlattenIds';
|
|
5
|
+
import { useCopyButton, useValueControl } from '../../../hooks';
|
|
6
|
+
import { extractChildIds } from '../legacy';
|
|
7
|
+
import { filterItemsByFlattenIds, getValueByPath, isBaseOptionProps } from '../utils';
|
|
9
8
|
export function useHandleOnKeyDown({ setOpen, inputKeyDownNavigationHandler, onInputKeyDownProp, }) {
|
|
10
9
|
return useCallback((onKeyDown) => (e) => {
|
|
11
10
|
if (e.code === 'Space') {
|
|
@@ -117,11 +116,3 @@ export function useSearch(items, enableFuzzySearch = true) {
|
|
|
117
116
|
}, [filterFlattenFunction, items]);
|
|
118
117
|
return useCallback((search) => (search.length >= DEFAULT_MIN_SEARCH_INPUT_LENGTH ? filterFunction(search) : items), [filterFunction, items]);
|
|
119
118
|
}
|
|
120
|
-
export function useResolvedAddCustomOptionTriggers({ addCustomOptionTriggers, addOptionByEnter, }) {
|
|
121
|
-
return useMemo(() => {
|
|
122
|
-
if (addCustomOptionTriggers !== undefined) {
|
|
123
|
-
return addCustomOptionTriggers;
|
|
124
|
-
}
|
|
125
|
-
return addOptionByEnter ? ['enter'] : [];
|
|
126
|
-
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
127
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Handler } from 'uncontrollable';
|
|
2
|
+
import { SelectionSingleValueType } from '@snack-uikit/list';
|
|
3
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
4
|
+
type UseResolvedAddCustomOptionTriggersParams = {
|
|
5
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
6
|
+
addOptionByEnter: boolean;
|
|
7
|
+
};
|
|
8
|
+
type UseFieldSelectMultipleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
9
|
+
inputValue: string;
|
|
10
|
+
value: SelectionSingleValueType[] | undefined;
|
|
11
|
+
setValue: Handler;
|
|
12
|
+
updateInputValue: () => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function useFieldSelectMultipleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, value, setValue, updateInputValue, }: UseFieldSelectMultipleCustomOptionParams): {
|
|
15
|
+
resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
16
|
+
tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
|
|
17
|
+
};
|
|
18
|
+
type UseFieldSelectSingleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
19
|
+
inputValue: string;
|
|
20
|
+
handleSelectionChange: (value: SelectionSingleValueType) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function useFieldSelectSingleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, handleSelectionChange, }: UseFieldSelectSingleCustomOptionParams): {
|
|
23
|
+
resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
24
|
+
tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
function useResolvedAddCustomOptionTriggers({ addCustomOptionTriggers, addOptionByEnter, }) {
|
|
3
|
+
return useMemo(() => {
|
|
4
|
+
if (addCustomOptionTriggers !== undefined) {
|
|
5
|
+
return addCustomOptionTriggers;
|
|
6
|
+
}
|
|
7
|
+
return addOptionByEnter ? ['enter'] : [];
|
|
8
|
+
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
9
|
+
}
|
|
10
|
+
export function useFieldSelectMultipleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, value, setValue, updateInputValue, }) {
|
|
11
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
12
|
+
addCustomOptionTriggers,
|
|
13
|
+
addOptionByEnter,
|
|
14
|
+
});
|
|
15
|
+
const tryCommitCustomOptionFromInput = useCallback((trigger) => {
|
|
16
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!(value !== null && value !== void 0 ? value : []).includes(inputValue)) {
|
|
20
|
+
setValue((prev) => (prev !== null && prev !== void 0 ? prev : []).concat(inputValue));
|
|
21
|
+
updateInputValue();
|
|
22
|
+
}
|
|
23
|
+
}, [resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue]);
|
|
24
|
+
return { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput };
|
|
25
|
+
}
|
|
26
|
+
export function useFieldSelectSingleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, handleSelectionChange, }) {
|
|
27
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
28
|
+
addCustomOptionTriggers,
|
|
29
|
+
addOptionByEnter,
|
|
30
|
+
});
|
|
31
|
+
const tryCommitCustomOptionFromInput = useCallback((trigger) => {
|
|
32
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
handleSelectionChange(inputValue);
|
|
36
|
+
}, [resolvedAddCustomOptionTriggers, inputValue, handleSelectionChange]);
|
|
37
|
+
return { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput };
|
|
38
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { FieldSelect } from './FieldSelect';
|
|
2
|
-
export type {
|
|
2
|
+
export type { FieldSelectMultipleAddCustomOptionTrigger, FieldSelectSingleAddCustomOptionTrigger, FieldSelectSingleProps, FieldSelectMultipleProps, FieldSelectProps, OptionProps, BaseOptionProps, AccordionOptionProps, NestListOptionProps, GroupOptionProps, SelectedOptionFormatter, } from './types';
|
|
@@ -32,8 +32,8 @@ export type SearchState = {
|
|
|
32
32
|
onChange?(value: string): void;
|
|
33
33
|
};
|
|
34
34
|
/** События, по которым произвольное значение из строки поиска фиксируется в значении поля */
|
|
35
|
-
export type
|
|
36
|
-
export type FieldSelectSingleAddCustomOptionTrigger = Extract<
|
|
35
|
+
export type FieldSelectMultipleAddCustomOptionTrigger = 'enter' | 'blur' | 'space' | 'comma';
|
|
36
|
+
export type FieldSelectSingleAddCustomOptionTrigger = Extract<FieldSelectMultipleAddCustomOptionTrigger, 'enter' | 'blur'>;
|
|
37
37
|
export type FieldSelectPrivateProps = InputProps & WrapperProps & {
|
|
38
38
|
options: OptionProps[];
|
|
39
39
|
loading?: boolean;
|
|
@@ -95,7 +95,7 @@ export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
|
95
95
|
* Триггеры фиксации произвольного значения из строки поиска в режиме `multiple`.
|
|
96
96
|
* Если передан, имеет приоритет над устаревшим `addOptionByEnter`.
|
|
97
97
|
*/
|
|
98
|
-
addCustomOptionTriggers?:
|
|
98
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
99
99
|
};
|
|
100
100
|
export type FieldSelectProps = (FieldSelectSingleProps & {
|
|
101
101
|
selection?: 'single';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { KeyboardEvent } from 'react';
|
|
2
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
3
|
+
export declare const getCustomOptionTriggerByCode: (code: KeyboardEvent<HTMLInputElement>["code"]) => FieldSelectMultipleAddCustomOptionTrigger | undefined;
|
|
4
|
+
export declare const shouldHandleCustomOptionTrigger: (trigger: FieldSelectMultipleAddCustomOptionTrigger | undefined, availableTriggers: FieldSelectMultipleAddCustomOptionTrigger[]) => trigger is FieldSelectMultipleAddCustomOptionTrigger;
|
|
@@ -5,4 +5,5 @@ export * from './updateItems';
|
|
|
5
5
|
export * from './getArrowIcon';
|
|
6
6
|
export * from './getValueByPath';
|
|
7
7
|
export * from './checkisSearchUnavailable';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './customOption';
|
|
9
|
+
export * from './filterItemsByFlattenIds';
|
|
@@ -5,4 +5,5 @@ export * from './updateItems';
|
|
|
5
5
|
export * from './getArrowIcon';
|
|
6
6
|
export * from './getValueByPath';
|
|
7
7
|
export * from './checkisSearchUnavailable';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './customOption';
|
|
9
|
+
export * from './filterItemsByFlattenIds';
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.54.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"@snack-uikit/locale": "*"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "91f67a065fb1a5b9b57c9c03374c752e3acf3a0f"
|
|
70
70
|
}
|
|
@@ -23,19 +23,14 @@ import { FieldDecorator } from '../FieldDecorator';
|
|
|
23
23
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
24
24
|
import {
|
|
25
25
|
useButtons,
|
|
26
|
+
useFieldSelectMultipleCustomOption,
|
|
26
27
|
useHandleDeleteItem,
|
|
27
28
|
useHandleOnKeyDown,
|
|
28
|
-
useResolvedAddCustomOptionTriggers,
|
|
29
29
|
useSearch,
|
|
30
30
|
useSearchInput,
|
|
31
31
|
} from './hooks';
|
|
32
32
|
import styles from './styles.module.scss';
|
|
33
|
-
import {
|
|
34
|
-
FieldSelectAddCustomOptionTrigger,
|
|
35
|
-
FieldSelectMultipleProps,
|
|
36
|
-
ItemWithId,
|
|
37
|
-
SelectedOptionFormatter,
|
|
38
|
-
} from './types';
|
|
33
|
+
import { FieldSelectMultipleProps, ItemWithId, SelectedOptionFormatter } from './types';
|
|
39
34
|
import {
|
|
40
35
|
checkisSearchUnavailable,
|
|
41
36
|
extractListProps,
|
|
@@ -109,25 +104,15 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
|
|
|
109
104
|
resetSearchOnOptionSelection,
|
|
110
105
|
});
|
|
111
106
|
|
|
112
|
-
const resolvedAddCustomOptionTriggers =
|
|
107
|
+
const { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput } = useFieldSelectMultipleCustomOption({
|
|
113
108
|
addCustomOptionTriggers,
|
|
114
109
|
addOptionByEnter,
|
|
110
|
+
inputValue,
|
|
111
|
+
value,
|
|
112
|
+
setValue,
|
|
113
|
+
updateInputValue,
|
|
115
114
|
});
|
|
116
115
|
|
|
117
|
-
const tryCommitCustomOptionFromInput = useCallback(
|
|
118
|
-
(trigger: FieldSelectAddCustomOptionTrigger) => {
|
|
119
|
-
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!(value ?? []).includes(inputValue)) {
|
|
124
|
-
setValue((prev: SelectionSingleValueType[]) => (prev ?? []).concat(inputValue));
|
|
125
|
-
updateInputValue();
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
[resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue],
|
|
129
|
-
);
|
|
130
|
-
|
|
131
116
|
const prefixSettings = usePrefix({ prefix, disabled });
|
|
132
117
|
const postfixSettings = usePostfix({ postfix, disabled });
|
|
133
118
|
|
|
@@ -20,14 +20,9 @@ import { usePostfix, usePrefix, useValueControl } from '../../hooks';
|
|
|
20
20
|
import { getValidationState } from '../../utils/getValidationState';
|
|
21
21
|
import { FieldDecorator } from '../FieldDecorator';
|
|
22
22
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
23
|
-
import { useButtons,
|
|
23
|
+
import { useButtons, useFieldSelectSingleCustomOption, useHandleOnKeyDown, useSearch, useSearchInput } from './hooks';
|
|
24
24
|
import styles from './styles.module.scss';
|
|
25
|
-
import {
|
|
26
|
-
FieldSelectAddCustomOptionTrigger,
|
|
27
|
-
FieldSelectSingleProps,
|
|
28
|
-
ItemWithId,
|
|
29
|
-
SelectedOptionFormatter,
|
|
30
|
-
} from './types';
|
|
25
|
+
import { FieldSelectSingleProps, ItemWithId, SelectedOptionFormatter } from './types';
|
|
31
26
|
import {
|
|
32
27
|
checkisSearchUnavailable,
|
|
33
28
|
extractListProps,
|
|
@@ -96,11 +91,6 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
96
91
|
selectedOptionFormatter,
|
|
97
92
|
});
|
|
98
93
|
|
|
99
|
-
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
100
|
-
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
101
|
-
addOptionByEnter,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
94
|
const prevSelectedItem = useRef<ItemWithId | undefined>(selectedItem);
|
|
105
95
|
|
|
106
96
|
const prefixSettings = usePrefix({ prefix, disabled });
|
|
@@ -166,16 +156,12 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
166
156
|
[setOpen, setValue],
|
|
167
157
|
);
|
|
168
158
|
|
|
169
|
-
const tryCommitCustomOptionFromInput =
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
handleSelectionChange(inputValue);
|
|
176
|
-
},
|
|
177
|
-
[resolvedAddCustomOptionTriggers, inputValue, handleSelectionChange],
|
|
178
|
-
);
|
|
159
|
+
const { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput } = useFieldSelectSingleCustomOption({
|
|
160
|
+
addCustomOptionTriggers: addCustomOptionTriggersProp,
|
|
161
|
+
addOptionByEnter,
|
|
162
|
+
inputValue,
|
|
163
|
+
handleSelectionChange,
|
|
164
|
+
});
|
|
179
165
|
|
|
180
166
|
const handleBlur = (e: FocusEvent<HTMLInputElement>) => {
|
|
181
167
|
if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
|
|
@@ -11,11 +11,10 @@ import {
|
|
|
11
11
|
SelectionSingleValueType,
|
|
12
12
|
} from '@snack-uikit/list';
|
|
13
13
|
|
|
14
|
-
import { useCopyButton, useValueControl } from '
|
|
15
|
-
import { extractChildIds } from '
|
|
16
|
-
import {
|
|
17
|
-
import { getValueByPath, isBaseOptionProps } from '
|
|
18
|
-
import { filterItemsByFlattenIds } from './utils/filterItemsByFlattenIds';
|
|
14
|
+
import { useCopyButton, useValueControl } from '../../../hooks';
|
|
15
|
+
import { extractChildIds } from '../legacy';
|
|
16
|
+
import { ItemWithId, SearchState, SelectedOptionFormatter } from '../types';
|
|
17
|
+
import { filterItemsByFlattenIds, getValueByPath, isBaseOptionProps } from '../utils';
|
|
19
18
|
|
|
20
19
|
type UseHandleOnKeyDownProps = {
|
|
21
20
|
inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
|
|
@@ -218,21 +217,3 @@ export function useSearch(items: ItemProps[], enableFuzzySearch: boolean = true)
|
|
|
218
217
|
[filterFunction, items],
|
|
219
218
|
);
|
|
220
219
|
}
|
|
221
|
-
|
|
222
|
-
type UseResolvedAddCustomOptionTriggersProps = {
|
|
223
|
-
addCustomOptionTriggers?: FieldSelectAddCustomOptionTrigger[];
|
|
224
|
-
addOptionByEnter: boolean;
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
export function useResolvedAddCustomOptionTriggers({
|
|
228
|
-
addCustomOptionTriggers,
|
|
229
|
-
addOptionByEnter,
|
|
230
|
-
}: UseResolvedAddCustomOptionTriggersProps): FieldSelectAddCustomOptionTrigger[] {
|
|
231
|
-
return useMemo(() => {
|
|
232
|
-
if (addCustomOptionTriggers !== undefined) {
|
|
233
|
-
return addCustomOptionTriggers;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return addOptionByEnter ? ['enter'] : [];
|
|
237
|
-
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
238
|
-
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { Handler } from 'uncontrollable';
|
|
3
|
+
|
|
4
|
+
import { SelectionSingleValueType } from '@snack-uikit/list';
|
|
5
|
+
|
|
6
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
7
|
+
|
|
8
|
+
type UseResolvedAddCustomOptionTriggersParams = {
|
|
9
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
10
|
+
addOptionByEnter: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function useResolvedAddCustomOptionTriggers({
|
|
14
|
+
addCustomOptionTriggers,
|
|
15
|
+
addOptionByEnter,
|
|
16
|
+
}: UseResolvedAddCustomOptionTriggersParams): FieldSelectMultipleAddCustomOptionTrigger[] {
|
|
17
|
+
return useMemo(() => {
|
|
18
|
+
if (addCustomOptionTriggers !== undefined) {
|
|
19
|
+
return addCustomOptionTriggers;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return addOptionByEnter ? ['enter'] : [];
|
|
23
|
+
}, [addCustomOptionTriggers, addOptionByEnter]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type UseFieldSelectMultipleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
27
|
+
inputValue: string;
|
|
28
|
+
value: SelectionSingleValueType[] | undefined;
|
|
29
|
+
setValue: Handler;
|
|
30
|
+
updateInputValue: () => void;
|
|
31
|
+
};
|
|
32
|
+
export function useFieldSelectMultipleCustomOption({
|
|
33
|
+
addCustomOptionTriggers,
|
|
34
|
+
addOptionByEnter,
|
|
35
|
+
inputValue,
|
|
36
|
+
value,
|
|
37
|
+
setValue,
|
|
38
|
+
updateInputValue,
|
|
39
|
+
}: UseFieldSelectMultipleCustomOptionParams) {
|
|
40
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
41
|
+
addCustomOptionTriggers,
|
|
42
|
+
addOptionByEnter,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const tryCommitCustomOptionFromInput = useCallback(
|
|
46
|
+
(trigger: FieldSelectMultipleAddCustomOptionTrigger) => {
|
|
47
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!(value ?? []).includes(inputValue)) {
|
|
52
|
+
setValue((prev: SelectionSingleValueType[]) => (prev ?? []).concat(inputValue));
|
|
53
|
+
updateInputValue();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
[resolvedAddCustomOptionTriggers, inputValue, value, setValue, updateInputValue],
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type UseFieldSelectSingleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
|
|
63
|
+
inputValue: string;
|
|
64
|
+
handleSelectionChange: (value: SelectionSingleValueType) => void;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function useFieldSelectSingleCustomOption({
|
|
68
|
+
addCustomOptionTriggers,
|
|
69
|
+
addOptionByEnter,
|
|
70
|
+
inputValue,
|
|
71
|
+
handleSelectionChange,
|
|
72
|
+
}: UseFieldSelectSingleCustomOptionParams) {
|
|
73
|
+
const resolvedAddCustomOptionTriggers = useResolvedAddCustomOptionTriggers({
|
|
74
|
+
addCustomOptionTriggers,
|
|
75
|
+
addOptionByEnter,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const tryCommitCustomOptionFromInput = useCallback(
|
|
79
|
+
(trigger: FieldSelectMultipleAddCustomOptionTrigger) => {
|
|
80
|
+
if (!resolvedAddCustomOptionTriggers.includes(trigger) || inputValue === '') {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
handleSelectionChange(inputValue);
|
|
85
|
+
},
|
|
86
|
+
[resolvedAddCustomOptionTriggers, inputValue, handleSelectionChange],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return { resolvedAddCustomOptionTriggers, tryCommitCustomOptionFromInput };
|
|
90
|
+
}
|
|
@@ -71,8 +71,11 @@ export type SearchState = {
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
/** События, по которым произвольное значение из строки поиска фиксируется в значении поля */
|
|
74
|
-
export type
|
|
75
|
-
export type FieldSelectSingleAddCustomOptionTrigger = Extract<
|
|
74
|
+
export type FieldSelectMultipleAddCustomOptionTrigger = 'enter' | 'blur' | 'space' | 'comma';
|
|
75
|
+
export type FieldSelectSingleAddCustomOptionTrigger = Extract<
|
|
76
|
+
FieldSelectMultipleAddCustomOptionTrigger,
|
|
77
|
+
'enter' | 'blur'
|
|
78
|
+
>;
|
|
76
79
|
|
|
77
80
|
export type FieldSelectPrivateProps = InputProps &
|
|
78
81
|
WrapperProps & {
|
|
@@ -170,7 +173,7 @@ export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
|
170
173
|
* Триггеры фиксации произвольного значения из строки поиска в режиме `multiple`.
|
|
171
174
|
* Если передан, имеет приоритет над устаревшим `addOptionByEnter`.
|
|
172
175
|
*/
|
|
173
|
-
addCustomOptionTriggers?:
|
|
176
|
+
addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
|
|
174
177
|
};
|
|
175
178
|
|
|
176
179
|
export type FieldSelectProps =
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { KeyboardEvent } from 'react';
|
|
2
|
+
|
|
3
|
+
import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
|
|
4
|
+
|
|
5
|
+
export const getCustomOptionTriggerByCode = (
|
|
6
|
+
code: KeyboardEvent<HTMLInputElement>['code'],
|
|
7
|
+
): FieldSelectMultipleAddCustomOptionTrigger | undefined => {
|
|
8
|
+
switch (code) {
|
|
9
|
+
case 'Enter':
|
|
10
|
+
return 'enter';
|
|
11
|
+
case 'Space':
|
|
12
|
+
return 'space';
|
|
13
|
+
case 'Comma':
|
|
14
|
+
return 'comma';
|
|
15
|
+
default:
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const shouldHandleCustomOptionTrigger = (
|
|
21
|
+
trigger: FieldSelectMultipleAddCustomOptionTrigger | undefined,
|
|
22
|
+
availableTriggers: FieldSelectMultipleAddCustomOptionTrigger[],
|
|
23
|
+
): trigger is FieldSelectMultipleAddCustomOptionTrigger => (trigger ? availableTriggers.includes(trigger) : false);
|
|
@@ -5,4 +5,5 @@ export * from './updateItems';
|
|
|
5
5
|
export * from './getArrowIcon';
|
|
6
6
|
export * from './getValueByPath';
|
|
7
7
|
export * from './checkisSearchUnavailable';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './customOption';
|
|
9
|
+
export * from './filterItemsByFlattenIds';
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { KeyboardEvent } from 'react';
|
|
2
|
-
import { FieldSelectAddCustomOptionTrigger } from '../types';
|
|
3
|
-
export declare const getCustomOptionTriggerByCode: (code: KeyboardEvent<HTMLInputElement>["code"]) => FieldSelectAddCustomOptionTrigger | undefined;
|
|
4
|
-
export declare const shouldHandleCustomOptionTrigger: (trigger: FieldSelectAddCustomOptionTrigger | undefined, availableTriggers: FieldSelectAddCustomOptionTrigger[]) => trigger is FieldSelectAddCustomOptionTrigger;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { KeyboardEvent } from 'react';
|
|
2
|
-
import { FieldSelectAddCustomOptionTrigger } from '../types';
|
|
3
|
-
export declare const getCustomOptionTriggerByCode: (code: KeyboardEvent<HTMLInputElement>["code"]) => FieldSelectAddCustomOptionTrigger | undefined;
|
|
4
|
-
export declare const shouldHandleCustomOptionTrigger: (trigger: FieldSelectAddCustomOptionTrigger | undefined, availableTriggers: FieldSelectAddCustomOptionTrigger[]) => trigger is FieldSelectAddCustomOptionTrigger;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { KeyboardEvent } from 'react';
|
|
2
|
-
|
|
3
|
-
import { FieldSelectAddCustomOptionTrigger } from '../types';
|
|
4
|
-
|
|
5
|
-
export const getCustomOptionTriggerByCode = (
|
|
6
|
-
code: KeyboardEvent<HTMLInputElement>['code'],
|
|
7
|
-
): FieldSelectAddCustomOptionTrigger | undefined => {
|
|
8
|
-
switch (code) {
|
|
9
|
-
case 'Enter':
|
|
10
|
-
return 'enter';
|
|
11
|
-
case 'Space':
|
|
12
|
-
return 'space';
|
|
13
|
-
case 'Comma':
|
|
14
|
-
return 'comma';
|
|
15
|
-
default:
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const shouldHandleCustomOptionTrigger = (
|
|
21
|
-
trigger: FieldSelectAddCustomOptionTrigger | undefined,
|
|
22
|
-
availableTriggers: FieldSelectAddCustomOptionTrigger[],
|
|
23
|
-
): trigger is FieldSelectAddCustomOptionTrigger => (trigger ? availableTriggers.includes(trigger) : false);
|
/package/dist/cjs/components/FieldSelect/utils/{getCustomOptionTriggerByCode.js → customOption.js}
RENAMED
|
File without changes
|
/package/dist/esm/components/FieldSelect/utils/{getCustomOptionTriggerByCode.js → customOption.js}
RENAMED
|
File without changes
|