@snack-uikit/fields 0.18.3 → 0.19.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 +16 -0
- package/README.md +0 -204
- package/dist/components/FieldDate/FieldDate.js +1 -1
- package/dist/components/FieldSelect/FieldSelectMultiple.d.ts +3 -1
- package/dist/components/FieldSelect/FieldSelectMultiple.js +9 -2
- package/dist/components/FieldSelect/FieldSelectSingle.d.ts +3 -1
- package/dist/components/FieldSelect/FieldSelectSingle.js +16 -4
- package/dist/components/FieldSelect/hooks.js +8 -2
- package/dist/components/FieldSelect/legacy/components/Items/hooks.d.ts +12 -0
- package/dist/components/FieldSelect/legacy/components/Items/hooks.js +33 -0
- package/dist/components/FieldSelect/legacy/components/index.d.ts +1 -0
- package/dist/components/FieldSelect/legacy/components/index.js +1 -0
- package/dist/components/FieldSelect/legacy/hooks.d.ts +5 -0
- package/dist/components/FieldSelect/legacy/hooks.js +19 -0
- package/dist/components/FieldSelect/legacy/index.d.ts +3 -0
- package/dist/components/FieldSelect/legacy/index.js +3 -0
- package/dist/components/FieldSelect/legacy/utils.d.ts +29 -0
- package/dist/components/FieldSelect/legacy/utils.js +107 -0
- package/dist/components/FieldSelect/types.d.ts +6 -3
- package/dist/components/FieldSelect/utils/extractListProps.d.ts +1 -1
- package/dist/components/FieldSelect/utils/extractListProps.js +1 -3
- package/dist/components/FieldSelect/utils/options.js +1 -1
- package/dist/components/FieldSelect/utils/typeGuards.js +1 -1
- package/dist/components/FieldSelect/utils/updateItems.d.ts +6 -6
- package/dist/components/FieldSelect/utils/updateItems.js +12 -3
- package/dist/helperComponents/FieldContainerPrivate/styles.module.css +1 -1
- package/package.json +15 -13
- package/src/components/FieldDate/FieldDate.tsx +1 -1
- package/src/components/FieldSelect/FieldSelectMultiple.tsx +10 -2
- package/src/components/FieldSelect/FieldSelectSingle.tsx +14 -3
- package/src/components/FieldSelect/hooks.ts +11 -2
- package/src/components/FieldSelect/legacy/components/Items/hooks.tsx +53 -0
- package/src/components/FieldSelect/legacy/components/index.ts +1 -0
- package/src/components/FieldSelect/legacy/hooks.ts +32 -0
- package/src/components/FieldSelect/legacy/index.ts +3 -0
- package/src/components/FieldSelect/legacy/utils.ts +166 -0
- package/src/components/FieldSelect/types.ts +29 -12
- package/src/components/FieldSelect/utils/extractListProps.ts +0 -4
- package/src/components/FieldSelect/utils/options.ts +2 -1
- package/src/components/FieldSelect/utils/typeGuards.ts +1 -1
- package/src/components/FieldSelect/utils/updateItems.ts +14 -4
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isAccordionItemProps, isBaseItemProps, isGroupItemProps, isNextListItemProps, } from '@snack-uikit/list';
|
|
2
|
+
export function withCollapsedItems({ items, openCollapsedItems }) {
|
|
3
|
+
let itemRefs = [];
|
|
4
|
+
let newItems = [];
|
|
5
|
+
let ids = [];
|
|
6
|
+
let expandedIds = [];
|
|
7
|
+
items.forEach(item => {
|
|
8
|
+
var _a;
|
|
9
|
+
if (((isBaseItemProps(item) && !item.inactive) || isNextListItemProps(item) || isAccordionItemProps(item)) &&
|
|
10
|
+
!item.disabled) {
|
|
11
|
+
newItems = newItems.concat([item]);
|
|
12
|
+
ids = ids.concat([(_a = item.id) !== null && _a !== void 0 ? _a : '']);
|
|
13
|
+
if (item.itemRef) {
|
|
14
|
+
itemRefs = itemRefs.concat([item.itemRef]);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (isNextListItemProps(item) && item.id && !item.disabled) {
|
|
18
|
+
expandedIds = expandedIds.concat(item.id);
|
|
19
|
+
}
|
|
20
|
+
if (isGroupItemProps(item)) {
|
|
21
|
+
const { itemRefs: nestedItemsRefs, ids: nestedIds } = withCollapsedItems({
|
|
22
|
+
items: item.items,
|
|
23
|
+
openCollapsedItems,
|
|
24
|
+
});
|
|
25
|
+
ids = ids.concat(nestedIds);
|
|
26
|
+
itemRefs = itemRefs.concat(nestedItemsRefs);
|
|
27
|
+
}
|
|
28
|
+
if (isAccordionItemProps(item) && item.id && openCollapsedItems.includes(item.id)) {
|
|
29
|
+
const { itemRefs: nestedItemsRefs, ids: nestedIds, items: nestedItems, expandedIds: nestedExpandedIds, } = withCollapsedItems({
|
|
30
|
+
items: item.items,
|
|
31
|
+
openCollapsedItems,
|
|
32
|
+
});
|
|
33
|
+
ids = ids.concat(nestedIds);
|
|
34
|
+
newItems = newItems.concat(nestedItems);
|
|
35
|
+
itemRefs = itemRefs.concat(nestedItemsRefs);
|
|
36
|
+
expandedIds = expandedIds.concat(nestedExpandedIds);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return { items, itemRefs, ids, expandedIds };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Функция возвращает массив id дочерних items
|
|
43
|
+
* @function extractItemIds
|
|
44
|
+
*/
|
|
45
|
+
export function extractItemIds(items) {
|
|
46
|
+
return items.reduce((prev, item) => {
|
|
47
|
+
if (isGroupItemProps(item)) {
|
|
48
|
+
return prev.concat(extractItemIds(item.items));
|
|
49
|
+
}
|
|
50
|
+
return item.id ? prev.concat([item.id]) : prev;
|
|
51
|
+
}, []);
|
|
52
|
+
}
|
|
53
|
+
export function extractChildIds({ items }) {
|
|
54
|
+
return items
|
|
55
|
+
.filter(item => isAccordionItemProps(item) ||
|
|
56
|
+
isNextListItemProps(item) ||
|
|
57
|
+
isGroupItemProps(item) ||
|
|
58
|
+
(isBaseItemProps(item) && !item.disabled && !item.inactive))
|
|
59
|
+
.reduce((prev, item) => {
|
|
60
|
+
var _a;
|
|
61
|
+
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
62
|
+
return prev.concat([(_a = item.id) !== null && _a !== void 0 ? _a : '']).concat(extractChildIds({ items: item.items }));
|
|
63
|
+
}
|
|
64
|
+
if (isGroupItemProps(item)) {
|
|
65
|
+
return prev.concat(extractChildIds({ items: item.items }));
|
|
66
|
+
}
|
|
67
|
+
return item.id && !isGroupItemProps(item) ? prev.concat([item.id]) : prev;
|
|
68
|
+
}, []);
|
|
69
|
+
}
|
|
70
|
+
export function extractAllChildIds({ items }) {
|
|
71
|
+
return items
|
|
72
|
+
.filter(item => isAccordionItemProps(item) ||
|
|
73
|
+
isNextListItemProps(item) ||
|
|
74
|
+
isGroupItemProps(item) ||
|
|
75
|
+
(isBaseItemProps(item) && !item.inactive))
|
|
76
|
+
.reduce((prev, item) => {
|
|
77
|
+
var _a;
|
|
78
|
+
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
79
|
+
return prev.concat([(_a = item.id) !== null && _a !== void 0 ? _a : '']).concat(extractAllChildIds({ items: item.items }));
|
|
80
|
+
}
|
|
81
|
+
if (isGroupItemProps(item)) {
|
|
82
|
+
return prev.concat(extractAllChildIds({ items: item.items }));
|
|
83
|
+
}
|
|
84
|
+
return item.id && !isGroupItemProps(item) ? prev.concat([item.id]) : prev;
|
|
85
|
+
}, []);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Функция разворачивает массив айтемов в плоский список
|
|
89
|
+
* @function flattenItems
|
|
90
|
+
*/
|
|
91
|
+
export function flattenItems(items) {
|
|
92
|
+
const flattenItems = [];
|
|
93
|
+
function flatten(item) {
|
|
94
|
+
if (!isGroupItemProps(item)) {
|
|
95
|
+
flattenItems.push(item);
|
|
96
|
+
}
|
|
97
|
+
if ('items' in item) {
|
|
98
|
+
for (const nestedItem of item.items) {
|
|
99
|
+
flatten(nestedItem);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const item of items) {
|
|
104
|
+
flatten(item);
|
|
105
|
+
}
|
|
106
|
+
return flattenItems;
|
|
107
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { InputPrivateProps } from '@snack-uikit/input-private';
|
|
3
|
-
import { AccordionItemProps, BaseItemProps, DroplistProps, GroupItemProps, NextListItemProps, SelectionMultipleState, SelectionSingleState } from '@snack-uikit/list';
|
|
3
|
+
import { AccordionItemProps, BaseItemProps, DroplistProps, GroupItemProps, ItemContentProps, NextListItemProps, SelectionMultipleState, SelectionSingleState } from '@snack-uikit/list';
|
|
4
4
|
import { TagProps } from '@snack-uikit/tag';
|
|
5
5
|
import { WithSupportProps } from '@snack-uikit/utils';
|
|
6
6
|
import { FieldDecoratorProps } from '../FieldDecorator';
|
|
7
|
+
export type AnyType = any;
|
|
7
8
|
export type OptionProps = BaseOptionProps | AccordionOptionProps | GroupOptionProps | NestListOptionProps;
|
|
8
9
|
export type OptionWithoutGroup = BaseOptionProps | AccordionOptionProps | NestListOptionProps;
|
|
9
|
-
export type BaseOptionProps = Pick<BaseItemProps, 'beforeContent' | 'afterContent' | 'disabled'> &
|
|
10
|
+
export type BaseOptionProps = Pick<BaseItemProps, 'beforeContent' | 'afterContent' | 'disabled'> & Pick<ItemContentProps, 'option' | 'caption' | 'description'> & {
|
|
10
11
|
value: string | number;
|
|
11
12
|
} & Pick<TagProps, 'appearance'>;
|
|
12
13
|
export type AccordionOptionProps = Pick<AccordionItemProps, 'type'> & BaseOptionProps & {
|
|
@@ -36,6 +37,8 @@ export type FieldSelectPrivateProps = InputProps & WrapperProps & {
|
|
|
36
37
|
};
|
|
37
38
|
type FiledSelectCommonProps = WithSupportProps<{
|
|
38
39
|
options: OptionProps[];
|
|
40
|
+
pinTop: OptionProps[];
|
|
41
|
+
pinBottom: OptionProps[];
|
|
39
42
|
searchable?: boolean;
|
|
40
43
|
/** Отображение кнопки Копировать для поля (актуально только для `readonly = true`) */
|
|
41
44
|
showCopyButton?: boolean;
|
|
@@ -59,7 +62,7 @@ type FiledSelectCommonProps = WithSupportProps<{
|
|
|
59
62
|
open?: boolean;
|
|
60
63
|
onOpenChange?(open: boolean): void;
|
|
61
64
|
selectedOptionFormatter?: SelectedOptionFormatter;
|
|
62
|
-
}> & Pick<DroplistProps, 'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | '
|
|
65
|
+
}> & Pick<DroplistProps, 'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'dataFiltered'>;
|
|
63
66
|
export type FieldSelectSingleProps = FieldSelectPrivateProps & Omit<SelectionSingleState, 'mode'> & WrapperProps & FiledSelectCommonProps;
|
|
64
67
|
export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
65
68
|
removeByBackspace?: boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { DroplistProps } from '@snack-uikit/list';
|
|
2
2
|
import { FieldSelectProps } from '../types';
|
|
3
|
-
export declare function extractListProps({ dataError, noDataState, noResultsState, errorDataState,
|
|
3
|
+
export declare function extractListProps({ dataError, noDataState, noResultsState, errorDataState, dataFiltered, loading, footer, widthStrategy, }: Partial<FieldSelectProps>): Partial<DroplistProps>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
export function extractListProps({ dataError, noDataState, noResultsState, errorDataState,
|
|
1
|
+
export function extractListProps({ dataError, noDataState, noResultsState, errorDataState, dataFiltered, loading, footer, widthStrategy, }) {
|
|
2
2
|
return {
|
|
3
3
|
dataError,
|
|
4
4
|
noDataState,
|
|
5
5
|
noResultsState,
|
|
6
6
|
errorDataState,
|
|
7
|
-
pinTop,
|
|
8
|
-
pinBottom,
|
|
9
7
|
dataFiltered,
|
|
10
8
|
loading,
|
|
11
9
|
footer,
|
|
@@ -9,7 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { flattenItems } from '
|
|
12
|
+
import { flattenItems } from '../legacy';
|
|
13
13
|
import { isAccordionOptionProps, isGroupOptionProps, isNextListOptionProps } from './typeGuards';
|
|
14
14
|
export function transformOptionsToItems(options) {
|
|
15
15
|
return options.map(option => {
|
|
@@ -12,7 +12,7 @@ export function isNextListOptionProps(option) {
|
|
|
12
12
|
}
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
14
|
export function isGroupOptionProps(option) {
|
|
15
|
-
return 'options' in option && option['type'] ===
|
|
15
|
+
return 'options' in option && option['type'] === 'group';
|
|
16
16
|
}
|
|
17
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
18
|
export function isFieldSelectMultipleProps(props) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
1
|
+
import { ItemId, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
2
2
|
import { ItemWithId, OptionProps } from '../types';
|
|
3
3
|
export declare function createPlaceholderItem(value: SelectionSingleValueType): {
|
|
4
|
-
id:
|
|
4
|
+
id: ItemId;
|
|
5
5
|
content: {
|
|
6
6
|
option: string;
|
|
7
7
|
};
|
|
@@ -9,12 +9,12 @@ export declare function createPlaceholderItem(value: SelectionSingleValueType):
|
|
|
9
9
|
};
|
|
10
10
|
export declare function updateItems({ options, value, selectedItem, }: {
|
|
11
11
|
options: OptionProps[];
|
|
12
|
-
value
|
|
12
|
+
value?: ItemId;
|
|
13
13
|
selectedItem?: ItemWithId;
|
|
14
14
|
currentItems?: ItemProps[];
|
|
15
15
|
}): {
|
|
16
16
|
selectedItem: ItemWithId | undefined;
|
|
17
|
-
items:
|
|
17
|
+
items: import("@snack-uikit/list/dist/components/Items").Item[];
|
|
18
18
|
};
|
|
19
19
|
export declare function updateMultipleItems({ options, value, selectedItems, }: {
|
|
20
20
|
options: OptionProps[];
|
|
@@ -23,10 +23,10 @@ export declare function updateMultipleItems({ options, value, selectedItems, }:
|
|
|
23
23
|
currentItems?: ItemProps[];
|
|
24
24
|
}): {
|
|
25
25
|
selectedItems: undefined;
|
|
26
|
-
items: (
|
|
26
|
+
items: (import("@snack-uikit/list/dist/components/Items").Item & {
|
|
27
27
|
appearance?: import("@snack-uikit/tag/dist/types").Appearance | undefined;
|
|
28
28
|
})[];
|
|
29
29
|
} | {
|
|
30
30
|
selectedItems: ItemWithId[];
|
|
31
|
-
items:
|
|
31
|
+
items: import("@snack-uikit/list/dist/components/Items").Item[];
|
|
32
32
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { flattenItems } from '
|
|
1
|
+
import { flattenItems } from '../legacy';
|
|
2
2
|
import { transformOptionsToItems } from './options';
|
|
3
3
|
export function createPlaceholderItem(value) {
|
|
4
4
|
return { id: value, content: { option: String(value) }, placeholder: true };
|
|
@@ -39,11 +39,20 @@ export function updateMultipleItems({ options, value, selectedItems, }) {
|
|
|
39
39
|
items: originalItems,
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
const foundedValue = [];
|
|
42
43
|
let newItems = originalItems;
|
|
43
44
|
let newSelectedItems = selectedItems;
|
|
44
45
|
const flattenOriginalItems = flattenItems(originalItems);
|
|
45
|
-
|
|
46
|
-
const
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
const foundItems = flattenOriginalItems.filter((item) => {
|
|
48
|
+
if (value.includes(item.id) && !foundedValue.includes(item.id)) {
|
|
49
|
+
foundedValue.push(item.id);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const nonFoundValues = value.filter(
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
value => !flattenOriginalItems.find((item) => item.id === value));
|
|
47
56
|
if (nonFoundValues.length) {
|
|
48
57
|
const nonFoundItems = nonFoundValues.map(value => (selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.find(selectedItem => selectedItem.id === value)) || createPlaceholderItem(value));
|
|
49
58
|
newSelectedItems = [...foundItems, ...nonFoundItems];
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
border-style:solid;
|
|
8
8
|
}
|
|
9
9
|
.container[data-validation=default]{
|
|
10
|
-
background-color:var(--sys-neutral-background1-level, #
|
|
10
|
+
background-color:var(--sys-neutral-background1-level, #fdfdff);
|
|
11
11
|
border-color:var(--sys-neutral-decor-default, #dfe2ec);
|
|
12
12
|
}
|
|
13
13
|
.container[data-validation=default]:hover{
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.19.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -32,29 +32,31 @@
|
|
|
32
32
|
"license": "Apache-2.0",
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@snack-uikit/button": "0.17.
|
|
36
|
-
"@snack-uikit/calendar": "0.7.
|
|
37
|
-
"@snack-uikit/
|
|
35
|
+
"@snack-uikit/button": "0.17.1",
|
|
36
|
+
"@snack-uikit/calendar": "0.7.7",
|
|
37
|
+
"@snack-uikit/dropdown": "0.2.2",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
|
-
"@snack-uikit/input-private": "3.1.
|
|
40
|
-
"@snack-uikit/list": "0.11.
|
|
41
|
-
"@snack-uikit/scroll": "0.5.
|
|
42
|
-
"@snack-uikit/slider": "0.1.
|
|
43
|
-
"@snack-uikit/tag": "0.9.
|
|
44
|
-
"@snack-uikit/tooltip": "0.13.
|
|
45
|
-
"@snack-uikit/truncate-string": "0.4.
|
|
46
|
-
"@snack-uikit/utils": "3.
|
|
39
|
+
"@snack-uikit/input-private": "3.1.2",
|
|
40
|
+
"@snack-uikit/list": "0.11.1",
|
|
41
|
+
"@snack-uikit/scroll": "0.5.3",
|
|
42
|
+
"@snack-uikit/slider": "0.1.8",
|
|
43
|
+
"@snack-uikit/tag": "0.9.1",
|
|
44
|
+
"@snack-uikit/tooltip": "0.13.2",
|
|
45
|
+
"@snack-uikit/truncate-string": "0.4.13",
|
|
46
|
+
"@snack-uikit/utils": "3.3.0",
|
|
47
47
|
"classnames": "2.3.2",
|
|
48
48
|
"copy-to-clipboard": "3.3.3",
|
|
49
|
+
"fuzzy-search": "3.2.1",
|
|
49
50
|
"merge-refs": "1.2.2",
|
|
50
51
|
"react-textarea-autosize": "8.5.3",
|
|
51
52
|
"uncontrollable": "8.0.4"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
55
|
+
"@types/fuzzy-search": "2.1.5",
|
|
54
56
|
"@types/merge-refs": "1.0.0"
|
|
55
57
|
},
|
|
56
58
|
"peerDependencies": {
|
|
57
59
|
"@snack-uikit/locale": "*"
|
|
58
60
|
},
|
|
59
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "bf1e1f3cfabccc1ee288c18722e33009bd001798"
|
|
60
62
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { useUncontrolledProp } from 'uncontrollable';
|
|
14
14
|
|
|
15
15
|
import { Calendar, CalendarProps } from '@snack-uikit/calendar';
|
|
16
|
-
import { Dropdown } from '@snack-uikit/
|
|
16
|
+
import { Dropdown } from '@snack-uikit/dropdown';
|
|
17
17
|
import { CalendarSVG } from '@snack-uikit/icons';
|
|
18
18
|
import {
|
|
19
19
|
ICON_SIZE,
|
|
@@ -3,7 +3,7 @@ import mergeRefs from 'merge-refs';
|
|
|
3
3
|
import { FocusEvent, forwardRef, KeyboardEvent, KeyboardEventHandler, useLayoutEffect, useRef, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { InputPrivate } from '@snack-uikit/input-private';
|
|
6
|
-
import { BaseItemProps, Droplist, ItemProps, SelectionSingleValueType
|
|
6
|
+
import { BaseItemProps, Droplist, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
7
7
|
import { Tag } from '@snack-uikit/tag';
|
|
8
8
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
9
9
|
|
|
@@ -12,13 +12,17 @@ import { useValueControl } from '../../hooks';
|
|
|
12
12
|
import { FieldDecorator } from '../FieldDecorator';
|
|
13
13
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
14
14
|
import { useButtons, useHandleDeleteItem, useHandleOnKeyDown, useSearchInput } from './hooks';
|
|
15
|
+
import { useFuzzySearch } from './legacy';
|
|
15
16
|
import styles from './styles.module.scss';
|
|
16
17
|
import { FieldSelectMultipleProps, ItemWithId, SelectedOptionFormatter } from './types';
|
|
17
18
|
import { extractListProps, getArrowIcon, updateMultipleItems } from './utils';
|
|
18
19
|
|
|
19
20
|
const BASE_MIN_WIDTH = 4;
|
|
20
21
|
|
|
21
|
-
const defaultSelectedOptionFormatter: SelectedOptionFormatter = item =>
|
|
22
|
+
const defaultSelectedOptionFormatter: SelectedOptionFormatter = item =>
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
24
|
+
// @ts-expect-error
|
|
25
|
+
item?.content.option || '';
|
|
22
26
|
|
|
23
27
|
export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMultipleProps>(
|
|
24
28
|
(
|
|
@@ -79,6 +83,10 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
|
|
|
79
83
|
const onClear = () => {
|
|
80
84
|
setValue(selectedItems?.filter(item => item.disabled).map(item => item.id));
|
|
81
85
|
localRef.current?.focus();
|
|
86
|
+
|
|
87
|
+
if (rest.required) {
|
|
88
|
+
setOpen(true);
|
|
89
|
+
}
|
|
82
90
|
};
|
|
83
91
|
|
|
84
92
|
const { ArrowIcon, arrowIconSize } = getArrowIcon({ size, open });
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from 'react';
|
|
14
14
|
|
|
15
15
|
import { InputPrivate } from '@snack-uikit/input-private';
|
|
16
|
-
import { Droplist, ItemProps, SelectionSingleValueType
|
|
16
|
+
import { Droplist, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
17
17
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
18
18
|
|
|
19
19
|
import { FieldContainerPrivate } from '../../helperComponents';
|
|
@@ -21,11 +21,15 @@ import { useValueControl } from '../../hooks';
|
|
|
21
21
|
import { FieldDecorator } from '../FieldDecorator';
|
|
22
22
|
import { extractFieldDecoratorProps } from '../FieldDecorator/utils';
|
|
23
23
|
import { useButtons, useHandleOnKeyDown, useSearchInput } from './hooks';
|
|
24
|
+
import { useFuzzySearch } from './legacy';
|
|
24
25
|
import styles from './styles.module.scss';
|
|
25
26
|
import { FieldSelectSingleProps, ItemWithId, SelectedOptionFormatter } from './types';
|
|
26
27
|
import { extractListProps, getArrowIcon, updateItems } from './utils';
|
|
27
28
|
|
|
28
|
-
const defaultSelectedOptionFormatter: SelectedOptionFormatter = item =>
|
|
29
|
+
const defaultSelectedOptionFormatter: SelectedOptionFormatter = item =>
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
31
|
+
// @ts-expect-error
|
|
32
|
+
item?.content.option || '';
|
|
29
33
|
|
|
30
34
|
export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleProps>(
|
|
31
35
|
(
|
|
@@ -72,6 +76,8 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
72
76
|
|
|
73
77
|
const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput({
|
|
74
78
|
...search,
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
80
|
+
// @ts-expect-error
|
|
75
81
|
defaultValue: selectedItem?.content.option ?? '',
|
|
76
82
|
selectedOptionFormatter,
|
|
77
83
|
});
|
|
@@ -86,6 +92,8 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
86
92
|
if (
|
|
87
93
|
prevSelectedItem.current &&
|
|
88
94
|
prevSelectedItem.current.id === selectedItem?.id &&
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
96
|
+
// @ts-expect-error
|
|
89
97
|
prevSelectedItem.current.content.option === selectedItem?.content.option
|
|
90
98
|
) {
|
|
91
99
|
return;
|
|
@@ -100,7 +108,10 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
|
|
|
100
108
|
const onClear = useCallback(() => {
|
|
101
109
|
setValue(undefined);
|
|
102
110
|
localRef.current?.focus();
|
|
103
|
-
|
|
111
|
+
if (required) {
|
|
112
|
+
setOpen(true);
|
|
113
|
+
}
|
|
114
|
+
}, [required, setOpen, setValue]);
|
|
104
115
|
|
|
105
116
|
const { ArrowIcon, arrowIconSize } = getArrowIcon({ size, open });
|
|
106
117
|
|
|
@@ -3,13 +3,14 @@ import { Handler } from 'uncontrollable';
|
|
|
3
3
|
|
|
4
4
|
import { useButtonNavigation, useClearButton } from '@snack-uikit/input-private';
|
|
5
5
|
import {
|
|
6
|
-
extractChildIds,
|
|
6
|
+
// extractChildIds,
|
|
7
7
|
isAccordionItemProps,
|
|
8
8
|
isNextListItemProps,
|
|
9
9
|
SelectionSingleValueType,
|
|
10
10
|
} from '@snack-uikit/list';
|
|
11
11
|
|
|
12
12
|
import { useCopyButton, useValueControl } from '../../hooks';
|
|
13
|
+
import { extractChildIds } from './legacy';
|
|
13
14
|
import { ItemWithId, SearchState, SelectedOptionFormatter } from './types';
|
|
14
15
|
import { isBaseOptionProps } from './utils';
|
|
15
16
|
|
|
@@ -141,7 +142,15 @@ export function useHandleDeleteItem(setValue: Handler) {
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
if (isBaseOptionProps(item)) {
|
|
144
|
-
setValue(
|
|
145
|
+
setValue(
|
|
146
|
+
(value: SelectionSingleValueType[]) =>
|
|
147
|
+
value?.filter(
|
|
148
|
+
v =>
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
150
|
+
// @ts-expect-error
|
|
151
|
+
v !== item.id,
|
|
152
|
+
),
|
|
153
|
+
);
|
|
145
154
|
}
|
|
146
155
|
},
|
|
147
156
|
[setValue],
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ItemProps, useSelectionContext } from '@snack-uikit/list';
|
|
4
|
+
|
|
5
|
+
import { extractAllChildIds, extractChildIds } from '../../utils';
|
|
6
|
+
|
|
7
|
+
type UseGroupItemSelectionProps = {
|
|
8
|
+
items: ItemProps[];
|
|
9
|
+
id?: string | number;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function useLegacyGroupItemSelection({ id = '', items, disabled }: UseGroupItemSelectionProps) {
|
|
14
|
+
const { value, setValue, isSelectionMultiple } = useSelectionContext();
|
|
15
|
+
const { childIds, allChildIds } = useMemo(
|
|
16
|
+
() => ({ childIds: extractChildIds({ items }), allChildIds: extractAllChildIds({ items }) }),
|
|
17
|
+
[items],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const isIndeterminate = isSelectionMultiple
|
|
21
|
+
? allChildIds.some(childId => value?.includes(childId))
|
|
22
|
+
: allChildIds.includes(value ?? '');
|
|
23
|
+
const checked = isSelectionMultiple ? allChildIds.every(childId => value?.includes(childId)) : undefined;
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (isSelectionMultiple) {
|
|
27
|
+
if (checked && !value?.includes(id)) {
|
|
28
|
+
setValue?.((value: Array<number | string>) => (value ?? []).concat([id ?? '']));
|
|
29
|
+
}
|
|
30
|
+
if (!checked && value?.includes(id)) {
|
|
31
|
+
setValue?.((value: Array<number | string>) => (value ?? []).filter(itemId => itemId !== id));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}, [checked, disabled, id, isSelectionMultiple, setValue, value]);
|
|
35
|
+
|
|
36
|
+
const handleOnSelect = () => {
|
|
37
|
+
if (checked) {
|
|
38
|
+
setValue?.((value: Array<string | number>) =>
|
|
39
|
+
(value ?? []).filter(itemId => itemId !== id && !childIds.includes(itemId)),
|
|
40
|
+
);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (isIndeterminate) {
|
|
45
|
+
setValue?.((value: Array<string | number>) => Array.from(new Set([...(value ?? []), ...childIds, id])));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setValue?.((value: Array<string | number>) => (value ?? []).concat([...childIds, id ?? '']));
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return { checked, isIndeterminate, handleOnSelect };
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useLegacyGroupItemSelection } from './Items/hooks';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import FuzzySearch from 'fuzzy-search';
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { ItemProps, kindFlattenItems } from '@snack-uikit/list';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_MIN_SEARCH_INPUT_LENGTH = 2;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
|
|
10
|
+
*/
|
|
11
|
+
export function useFuzzySearch(items: ItemProps[], minSearchInputLength?: number) {
|
|
12
|
+
const flattenItems = useMemo(() => {
|
|
13
|
+
const { flattenItems } = kindFlattenItems({ items });
|
|
14
|
+
|
|
15
|
+
return Object.values(flattenItems);
|
|
16
|
+
}, [items]);
|
|
17
|
+
|
|
18
|
+
return useCallback(
|
|
19
|
+
(search: string) => {
|
|
20
|
+
const searcher = new FuzzySearch(
|
|
21
|
+
flattenItems,
|
|
22
|
+
['content.option', 'content.caption', 'content.description', 'label'],
|
|
23
|
+
{},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return search.length > (minSearchInputLength ?? DEFAULT_MIN_SEARCH_INPUT_LENGTH)
|
|
27
|
+
? searcher.search(search)
|
|
28
|
+
: items;
|
|
29
|
+
},
|
|
30
|
+
[flattenItems, items, minSearchInputLength],
|
|
31
|
+
);
|
|
32
|
+
}
|