@snack-uikit/fields 0.18.2-preview-86dac340.0 → 0.18.2-preview-cb79db34.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/README.md +7 -8
- package/dist/components/FieldDate/FieldDate.js +1 -1
- package/dist/components/FieldSelect/FieldSelectMultiple.d.ts +3 -2
- package/dist/components/FieldSelect/FieldSelectMultiple.js +6 -2
- package/dist/components/FieldSelect/FieldSelectSingle.d.ts +3 -2
- package/dist/components/FieldSelect/FieldSelectSingle.js +12 -3
- 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/styles.module.css +18 -8
- package/dist/components/FieldSelect/types.d.ts +7 -11
- package/dist/components/FieldSelect/utils/extractListProps.d.ts +1 -1
- package/dist/components/FieldSelect/utils/extractListProps.js +1 -5
- 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 +6 -2
- package/src/components/FieldSelect/FieldSelectSingle.tsx +10 -2
- 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/styles.module.scss +3 -5
- package/src/components/FieldSelect/types.ts +32 -21
- package/src/components/FieldSelect/utils/extractListProps.ts +0 -8
- 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
|
@@ -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.18.2-preview-
|
|
7
|
+
"version": "0.18.2-preview-cb79db34.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.0",
|
|
36
|
-
"@snack-uikit/calendar": "0.7.
|
|
37
|
-
"@snack-uikit/
|
|
35
|
+
"@snack-uikit/button": "0.17.1-preview-cb79db34.0",
|
|
36
|
+
"@snack-uikit/calendar": "0.7.7-preview-cb79db34.0",
|
|
37
|
+
"@snack-uikit/dropdown": "0.2.2-preview-cb79db34.0",
|
|
38
38
|
"@snack-uikit/icons": "0.20.1",
|
|
39
|
-
"@snack-uikit/input-private": "3.1.
|
|
40
|
-
"@snack-uikit/list": "0.10.0",
|
|
41
|
-
"@snack-uikit/scroll": "0.5.
|
|
42
|
-
"@snack-uikit/slider": "0.1.
|
|
43
|
-
"@snack-uikit/tag": "0.8.3-preview-
|
|
44
|
-
"@snack-uikit/tooltip": "0.13.
|
|
45
|
-
"@snack-uikit/truncate-string": "0.4.
|
|
46
|
-
"@snack-uikit/utils": "3.2.0",
|
|
39
|
+
"@snack-uikit/input-private": "3.1.2-preview-cb79db34.0",
|
|
40
|
+
"@snack-uikit/list": "0.10.1-preview-cb79db34.0",
|
|
41
|
+
"@snack-uikit/scroll": "0.5.3-preview-cb79db34.0",
|
|
42
|
+
"@snack-uikit/slider": "0.1.8-preview-cb79db34.0",
|
|
43
|
+
"@snack-uikit/tag": "0.8.3-preview-cb79db34.0",
|
|
44
|
+
"@snack-uikit/tooltip": "0.13.2-preview-cb79db34.0",
|
|
45
|
+
"@snack-uikit/truncate-string": "0.4.13-preview-cb79db34.0",
|
|
46
|
+
"@snack-uikit/utils": "3.2.1-preview-cb79db34.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": "ec06c40c0ed64aa42d8842734a8c532f5c4603e6"
|
|
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
|
(
|
|
@@ -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;
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AccordionItemProps,
|
|
5
|
+
BaseItemProps,
|
|
6
|
+
isAccordionItemProps,
|
|
7
|
+
isBaseItemProps,
|
|
8
|
+
isGroupItemProps,
|
|
9
|
+
isNextListItemProps,
|
|
10
|
+
ItemProps,
|
|
11
|
+
NextListItemProps,
|
|
12
|
+
} from '@snack-uikit/list';
|
|
13
|
+
|
|
14
|
+
type WithCollapsedItemsProps = {
|
|
15
|
+
items: ItemProps[];
|
|
16
|
+
openCollapsedItems: Array<number | string>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedItemsProps) {
|
|
20
|
+
let itemRefs: RefObject<HTMLElement>[] = [];
|
|
21
|
+
let newItems: ItemProps[] = [];
|
|
22
|
+
let ids: Array<string | number> = [];
|
|
23
|
+
let expandedIds: Array<string | number> = [];
|
|
24
|
+
|
|
25
|
+
items.forEach(item => {
|
|
26
|
+
if (
|
|
27
|
+
((isBaseItemProps(item) && !item.inactive) || isNextListItemProps(item) || isAccordionItemProps(item)) &&
|
|
28
|
+
!item.disabled
|
|
29
|
+
) {
|
|
30
|
+
newItems = newItems.concat([item]);
|
|
31
|
+
ids = ids.concat([item.id ?? '']);
|
|
32
|
+
|
|
33
|
+
if (item.itemRef) {
|
|
34
|
+
itemRefs = itemRefs.concat([item.itemRef]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isNextListItemProps(item) && item.id && !item.disabled) {
|
|
39
|
+
expandedIds = expandedIds.concat(item.id);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (isGroupItemProps(item)) {
|
|
43
|
+
const { itemRefs: nestedItemsRefs, ids: nestedIds } = withCollapsedItems({
|
|
44
|
+
items: item.items,
|
|
45
|
+
openCollapsedItems,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
ids = ids.concat(nestedIds);
|
|
49
|
+
|
|
50
|
+
itemRefs = itemRefs.concat(nestedItemsRefs);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isAccordionItemProps(item) && item.id && openCollapsedItems.includes(item.id)) {
|
|
54
|
+
const {
|
|
55
|
+
itemRefs: nestedItemsRefs,
|
|
56
|
+
ids: nestedIds,
|
|
57
|
+
items: nestedItems,
|
|
58
|
+
expandedIds: nestedExpandedIds,
|
|
59
|
+
} = withCollapsedItems({
|
|
60
|
+
items: item.items,
|
|
61
|
+
openCollapsedItems,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
ids = ids.concat(nestedIds);
|
|
65
|
+
newItems = newItems.concat(nestedItems);
|
|
66
|
+
itemRefs = itemRefs.concat(nestedItemsRefs);
|
|
67
|
+
expandedIds = expandedIds.concat(nestedExpandedIds);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return { items, itemRefs, ids, expandedIds };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Функция возвращает массив id дочерних items
|
|
76
|
+
* @function extractItemIds
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
export function extractItemIds(items: ItemProps[]): Array<string | number> {
|
|
80
|
+
return items.reduce(
|
|
81
|
+
(prev: Array<string | number>, item: ItemProps) => {
|
|
82
|
+
if (isGroupItemProps(item)) {
|
|
83
|
+
return prev.concat(extractItemIds(item.items));
|
|
84
|
+
}
|
|
85
|
+
return item.id ? prev.concat([item.id]) : prev;
|
|
86
|
+
},
|
|
87
|
+
[] as Array<string | number>,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function extractChildIds({ items }: { items: ItemProps[] }): Array<string | number> {
|
|
92
|
+
return items
|
|
93
|
+
.filter(
|
|
94
|
+
item =>
|
|
95
|
+
isAccordionItemProps(item) ||
|
|
96
|
+
isNextListItemProps(item) ||
|
|
97
|
+
isGroupItemProps(item) ||
|
|
98
|
+
(isBaseItemProps(item) && !item.disabled && !item.inactive),
|
|
99
|
+
)
|
|
100
|
+
.reduce(
|
|
101
|
+
(prev: Array<string | number>, item: ItemProps) => {
|
|
102
|
+
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
103
|
+
return prev.concat([item.id ?? '']).concat(extractChildIds({ items: item.items }));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (isGroupItemProps(item)) {
|
|
107
|
+
return prev.concat(extractChildIds({ items: item.items }));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return item.id && !isGroupItemProps(item) ? prev.concat([item.id]) : prev;
|
|
111
|
+
},
|
|
112
|
+
[] as Array<string | number>,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function extractAllChildIds({ items }: { items: ItemProps[] }): Array<string | number> {
|
|
117
|
+
return items
|
|
118
|
+
.filter(
|
|
119
|
+
item =>
|
|
120
|
+
isAccordionItemProps(item) ||
|
|
121
|
+
isNextListItemProps(item) ||
|
|
122
|
+
isGroupItemProps(item) ||
|
|
123
|
+
(isBaseItemProps(item) && !item.inactive),
|
|
124
|
+
)
|
|
125
|
+
.reduce(
|
|
126
|
+
(prev: Array<string | number>, item: ItemProps) => {
|
|
127
|
+
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
128
|
+
return prev.concat([item.id ?? '']).concat(extractAllChildIds({ items: item.items }));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (isGroupItemProps(item)) {
|
|
132
|
+
return prev.concat(extractAllChildIds({ items: item.items }));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return item.id && !isGroupItemProps(item) ? prev.concat([item.id]) : prev;
|
|
136
|
+
},
|
|
137
|
+
[] as Array<string | number>,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Функция разворачивает массив айтемов в плоский список
|
|
143
|
+
* @function flattenItems
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
export function flattenItems(items: ItemProps[]): (BaseItemProps | AccordionItemProps | NextListItemProps)[] {
|
|
147
|
+
const flattenItems: (BaseItemProps | AccordionItemProps | NextListItemProps)[] = [];
|
|
148
|
+
|
|
149
|
+
function flatten(item: ItemProps) {
|
|
150
|
+
if (!isGroupItemProps(item)) {
|
|
151
|
+
flattenItems.push(item);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if ('items' in item) {
|
|
155
|
+
for (const nestedItem of item.items) {
|
|
156
|
+
flatten(nestedItem);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for (const item of items) {
|
|
162
|
+
flatten(item);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return flattenItems;
|
|
166
|
+
}
|
|
@@ -18,12 +18,8 @@ $base-min-width: 4px;
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.contentWrapper {
|
|
21
|
-
position: relative;
|
|
22
|
-
|
|
23
|
-
overflow: hidden;
|
|
24
21
|
display: flex;
|
|
25
22
|
flex-wrap: wrap;
|
|
26
|
-
|
|
27
23
|
width: 100%;
|
|
28
24
|
}
|
|
29
25
|
|
|
@@ -63,7 +59,9 @@ $base-min-width: 4px;
|
|
|
63
59
|
$button-width: simple-var($icons-sizes, $size);
|
|
64
60
|
$postfix-width: calc(var(#{$space-fields-postfix-gap}) + $button-width * 2);
|
|
65
61
|
$margin-right: calc(
|
|
66
|
-
#{simple-var($fields, $containerVariant, $size, 'padding-right')} +
|
|
62
|
+
#{simple-var($fields, $containerVariant, $size, 'padding-right')} +
|
|
63
|
+
#{simple-var($fields, $containerVariant, $size, 'gap')} +
|
|
64
|
+
#{$postfix-width}
|
|
67
65
|
);
|
|
68
66
|
|
|
69
67
|
width: calc(100% - $margin-right);
|
|
@@ -4,8 +4,9 @@ import { InputPrivateProps } from '@snack-uikit/input-private';
|
|
|
4
4
|
import {
|
|
5
5
|
AccordionItemProps,
|
|
6
6
|
BaseItemProps,
|
|
7
|
-
DroplistProps,
|
|
8
7
|
GroupItemProps,
|
|
8
|
+
ItemContentProps,
|
|
9
|
+
ListProps,
|
|
9
10
|
NextListItemProps,
|
|
10
11
|
SelectionMultipleState,
|
|
11
12
|
SelectionSingleState,
|
|
@@ -15,17 +16,33 @@ import { WithSupportProps } from '@snack-uikit/utils';
|
|
|
15
16
|
|
|
16
17
|
import { FieldDecoratorProps } from '../FieldDecorator';
|
|
17
18
|
|
|
18
|
-
// eslint-disable-next-line no-
|
|
19
|
-
export type
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
export type AnyType = any;
|
|
21
|
+
|
|
22
|
+
export type OptionProps =
|
|
23
|
+
// eslint-disable-next-line no-use-before-define
|
|
24
|
+
| BaseOptionProps
|
|
25
|
+
// eslint-disable-next-line no-use-before-define
|
|
26
|
+
| AccordionOptionProps
|
|
27
|
+
// eslint-disable-next-line no-use-before-define
|
|
28
|
+
| GroupOptionProps
|
|
29
|
+
// eslint-disable-next-line no-use-before-define
|
|
30
|
+
| NestListOptionProps;
|
|
20
31
|
|
|
21
32
|
// eslint-disable-next-line no-use-before-define
|
|
22
33
|
export type OptionWithoutGroup = BaseOptionProps | AccordionOptionProps | NestListOptionProps;
|
|
23
34
|
|
|
24
35
|
export type BaseOptionProps = Pick<BaseItemProps, 'beforeContent' | 'afterContent' | 'disabled'> &
|
|
25
|
-
|
|
36
|
+
Pick<ItemContentProps, 'option' | 'caption' | 'description'> & { value: string | number } & Pick<
|
|
37
|
+
TagProps,
|
|
38
|
+
'appearance'
|
|
39
|
+
>;
|
|
26
40
|
|
|
27
41
|
export type AccordionOptionProps = Pick<AccordionItemProps, 'type'> & BaseOptionProps & { options: OptionProps[] };
|
|
28
|
-
|
|
42
|
+
|
|
43
|
+
export type GroupOptionProps = Omit<GroupItemProps, 'items' | 'id'> & {
|
|
44
|
+
options: OptionProps[];
|
|
45
|
+
};
|
|
29
46
|
export type NestListOptionProps = Pick<NextListItemProps, 'type' | 'onSublistOpenChanged' | 'id'> &
|
|
30
47
|
BaseOptionProps & { options: OptionProps[] };
|
|
31
48
|
|
|
@@ -65,6 +82,10 @@ export type FieldSelectPrivateProps = InputProps & WrapperProps & { options: Opt
|
|
|
65
82
|
|
|
66
83
|
type FiledSelectCommonProps = WithSupportProps<{
|
|
67
84
|
options: OptionProps[];
|
|
85
|
+
|
|
86
|
+
pinTop: OptionProps[];
|
|
87
|
+
pinBottom: OptionProps[];
|
|
88
|
+
|
|
68
89
|
searchable?: boolean;
|
|
69
90
|
/** Отображение кнопки Копировать для поля (актуально только для `readonly = true`) */
|
|
70
91
|
showCopyButton?: boolean;
|
|
@@ -81,14 +102,8 @@ type FiledSelectCommonProps = WithSupportProps<{
|
|
|
81
102
|
|
|
82
103
|
/** Иконка-префикс для поля */
|
|
83
104
|
prefixIcon?: ReactElement;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*/
|
|
87
|
-
footer?: DroplistProps['footer'];
|
|
88
|
-
/**
|
|
89
|
-
* Управление шириной выпадающего списка
|
|
90
|
-
*/
|
|
91
|
-
widthStrategy?: DroplistProps['widthStrategy'];
|
|
105
|
+
|
|
106
|
+
footer?: ListProps['footer'];
|
|
92
107
|
|
|
93
108
|
search?: SearchState;
|
|
94
109
|
|
|
@@ -102,20 +117,16 @@ type FiledSelectCommonProps = WithSupportProps<{
|
|
|
102
117
|
|
|
103
118
|
selectedOptionFormatter?: SelectedOptionFormatter;
|
|
104
119
|
}> &
|
|
105
|
-
Pick<
|
|
106
|
-
DroplistProps,
|
|
107
|
-
'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'pinTop' | 'pinBottom' | 'dataFiltered'
|
|
108
|
-
>;
|
|
120
|
+
Pick<ListProps, 'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'dataFiltered'>;
|
|
109
121
|
|
|
110
122
|
export type FieldSelectSingleProps = FieldSelectPrivateProps &
|
|
111
123
|
Omit<SelectionSingleState, 'mode'> &
|
|
112
124
|
WrapperProps &
|
|
113
125
|
FiledSelectCommonProps;
|
|
114
126
|
|
|
115
|
-
export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
> &
|
|
127
|
+
export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
|
|
128
|
+
removeByBackspace?: boolean;
|
|
129
|
+
} & Omit<SelectionMultipleState, 'mode'> &
|
|
119
130
|
Omit<FiledSelectCommonProps, 'showCopyButton'>;
|
|
120
131
|
|
|
121
132
|
export type FieldSelectProps =
|
|
@@ -7,24 +7,16 @@ export function extractListProps({
|
|
|
7
7
|
noDataState,
|
|
8
8
|
noResultsState,
|
|
9
9
|
errorDataState,
|
|
10
|
-
pinTop,
|
|
11
|
-
pinBottom,
|
|
12
10
|
dataFiltered,
|
|
13
11
|
loading,
|
|
14
|
-
footer,
|
|
15
|
-
widthStrategy,
|
|
16
12
|
}: Partial<FieldSelectProps>): Partial<DroplistProps> {
|
|
17
13
|
return {
|
|
18
14
|
dataError,
|
|
19
15
|
noDataState,
|
|
20
16
|
noResultsState,
|
|
21
17
|
errorDataState,
|
|
22
|
-
pinTop,
|
|
23
|
-
pinBottom,
|
|
24
18
|
dataFiltered,
|
|
25
19
|
loading,
|
|
26
|
-
footer,
|
|
27
|
-
widthStrategy,
|
|
28
20
|
trigger: 'clickAndFocusVisible',
|
|
29
21
|
placement: 'bottom',
|
|
30
22
|
'data-test-id': 'field-select__list',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
|
|
2
2
|
import { TagProps } from '@snack-uikit/tag';
|
|
3
3
|
|
|
4
|
+
import { flattenItems } from '../legacy';
|
|
4
5
|
import { BaseOptionProps, ItemWithId, OptionProps } from '../types';
|
|
5
6
|
import { isAccordionOptionProps, isGroupOptionProps, isNextListOptionProps } from './typeGuards';
|
|
6
7
|
|
|
@@ -24,7 +24,7 @@ export function isNextListOptionProps(option: any): option is NestListOptionProp
|
|
|
24
24
|
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
26
|
export function isGroupOptionProps(option: any): option is GroupOptionProps {
|
|
27
|
-
return 'options' in option && option['type'] ===
|
|
27
|
+
return 'options' in option && option['type'] === 'group';
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|