@snack-uikit/list 0.3.5 → 0.4.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 +23 -0
- package/README.md +28 -10
- package/dist/components/Items/AccordionItem/AccordionItem.js +3 -6
- package/dist/components/Items/BaseItem/BaseItem.js +1 -1
- package/dist/components/Items/BaseItem/styles.module.css +7 -11
- package/dist/components/Items/hooks.js +10 -10
- package/dist/components/Items/styles.module.css +5 -5
- package/dist/components/Items/types.d.ts +1 -0
- package/dist/components/Items/utils.js +5 -4
- package/dist/components/Lists/Droplist/DropList.js +8 -11
- package/dist/components/Lists/List/List.d.ts +3 -5
- package/dist/components/Lists/List/List.js +1 -6
- package/dist/components/Lists/ListPrivate/ListPrivate.d.ts +3 -5
- package/dist/components/Lists/ListPrivate/ListPrivate.js +10 -10
- package/dist/components/Lists/contexts/SelectionProvider.d.ts +3 -3
- package/dist/components/Lists/contexts/SelectionProvider.js +14 -11
- package/dist/components/Lists/index.d.ts +1 -1
- package/dist/components/Lists/styles.module.css +0 -14
- package/dist/components/Lists/types.d.ts +23 -10
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/helperComponents/ListEmptyState/ListEmptyState.d.ts +14 -0
- package/dist/helperComponents/ListEmptyState/ListEmptyState.js +9 -0
- package/dist/helperComponents/ListEmptyState/hooks.d.ts +10 -0
- package/dist/helperComponents/ListEmptyState/hooks.js +16 -0
- package/dist/helperComponents/ListEmptyState/index.d.ts +2 -0
- package/dist/helperComponents/ListEmptyState/index.js +2 -0
- package/dist/helperComponents/ListEmptyState/styles.module.css +8 -0
- package/dist/helperComponents/index.d.ts +1 -0
- package/dist/helperComponents/index.js +1 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +29 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +17 -0
- package/package.json +11 -2
- package/src/components/Items/AccordionItem/AccordionItem.tsx +4 -7
- package/src/components/Items/BaseItem/BaseItem.tsx +1 -0
- package/src/components/Items/BaseItem/styles.module.scss +3 -6
- package/src/components/Items/hooks.tsx +13 -10
- package/src/components/Items/styles.module.scss +2 -2
- package/src/components/Items/types.ts +2 -0
- package/src/components/Items/utils.ts +5 -3
- package/src/components/Lists/Droplist/DropList.tsx +13 -12
- package/src/components/Lists/List/List.tsx +1 -5
- package/src/components/Lists/ListPrivate/ListPrivate.tsx +50 -48
- package/src/components/Lists/contexts/SelectionProvider.tsx +11 -8
- package/src/components/Lists/index.ts +3 -0
- package/src/components/Lists/styles.module.scss +0 -12
- package/src/components/Lists/types.ts +27 -10
- package/src/components/index.ts +2 -0
- package/src/helperComponents/ListEmptyState/ListEmptyState.tsx +35 -0
- package/src/helperComponents/ListEmptyState/hooks.ts +42 -0
- package/src/helperComponents/ListEmptyState/index.ts +2 -0
- package/src/helperComponents/ListEmptyState/styles.module.scss +11 -0
- package/src/helperComponents/index.ts +1 -0
- package/src/hooks.ts +45 -0
- package/src/index.ts +3 -0
- package/src/utils.ts +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
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.4.0 (2024-02-23)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **FF-4221:** fix keygen for items ([1d542c0](https://github.com/cloud-ru-tech/snack-uikit/commit/1d542c055c3a8a89b875bdb1e3cb4c1fcacd0a5a))
|
|
12
|
+
* **FF-4221:** fix selection/clean with disabled items; remove useless toggle-group ([d630d3c](https://github.com/cloud-ru-tech/snack-uikit/commit/d630d3c01c818c74eb30d6ec92c577476e847cb2))
|
|
13
|
+
* **FF-4221:** fix some select bugs; add some type exports ([e5435f1](https://github.com/cloud-ru-tech/snack-uikit/commit/e5435f18fb766456ae74452d529e797e9df36f20))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **FF-4221:** add ListEmptyState with translations ([83b3758](https://github.com/cloud-ru-tech/snack-uikit/commit/83b375876ff9a9b0ac294a67199a8b4d4ccbe799))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### BREAKING CHANGES
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
* **FF-4221:** remove noData/noResults props; instead added: noDataState,noResultsState,errorDataState, dataError, dataFiltered; replace local "info-block" ([5b18ea2](https://github.com/cloud-ru-tech/snack-uikit/commit/5b18ea209ca33b7773f356e52c3ab3d95da1cfe1))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
## 0.3.5 (2024-02-22)
|
|
7
30
|
|
|
8
31
|
### Only dependencies have been changed
|
package/README.md
CHANGED
|
@@ -8,6 +8,18 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: DOCUMENTATION_SECTION_START
|
|
10
10
|
[//]: THIS_SECTION_IS_AUTOGENERATED_PLEASE_DONT_EDIT_IT
|
|
11
|
+
## extractChildIds
|
|
12
|
+
### Props
|
|
13
|
+
| name | type | default value | description |
|
|
14
|
+
|------|------|---------------|-------------|
|
|
15
|
+
| items* | `ItemProps[]` | - | |
|
|
16
|
+
## useGroupItemSelection
|
|
17
|
+
### Props
|
|
18
|
+
| name | type | default value | description |
|
|
19
|
+
|------|------|---------------|-------------|
|
|
20
|
+
| items* | `ItemProps[]` | - | |
|
|
21
|
+
| id | `string \| number` | - | |
|
|
22
|
+
| disabled | `boolean` | - | |
|
|
11
23
|
## isSelectionSingleProps
|
|
12
24
|
### Props
|
|
13
25
|
| name | type | default value | description |
|
|
@@ -21,29 +33,32 @@
|
|
|
21
33
|
| name | type | default value | description |
|
|
22
34
|
|------|------|---------------|-------------|
|
|
23
35
|
| items* | `ItemProps[]` | - | Основные элементы списка |
|
|
36
|
+
| children* | `ReactNode \| ({onKeyDown}) => ReactNode * Рендер функция принимает аргументы `onKeyDown` - хендлер ввода, для поддержки управления с клавиатуры` | - | Триггер для дроплиста |
|
|
24
37
|
| triggerElemRef | `RefObject<HTMLElement>` | - | Ссылка на элемент-триггер для дроплиста |
|
|
25
|
-
| children | `ReactNode` | - | Триггер для дроплиста |
|
|
26
38
|
| open | `boolean` | - | Управляет состоянием показан/не показан. |
|
|
27
39
|
| onOpenChange | `(isOpen: boolean) => void` | - | Колбек отображения компонента. Срабатывает при изменении состояния open. |
|
|
28
40
|
| widthStrategy | enum PopoverWidthStrategy: `"auto"`, `"gte"`, `"eq"` | auto | Стратегия управления шириной контейнера поповера <br> - `auto` - соответствует ширине контента, <br> - `gte` - Great Than or Equal, равен ширине таргета или больше ее, если контент в поповере шире, <br> - `eq` - Equal, строго равен ширине таргета. |
|
|
29
41
|
| trigger | enum Trigger: `"click"`, `"hover"`, `"focusVisible"`, `"focus"`, `"hoverAndFocusVisible"`, `"hoverAndFocus"`, `"clickAndFocusVisible"` | - | Условие отображения поповера: <br> - `click` - открывать по клику <br> - `hover` - открывать по ховеру <br> - `focusVisible` - открывать по focus-visible <br> - `focus` - открывать по фокусу <br> - `hoverAndFocusVisible` - открывать по ховеру и focus-visible <br> - `hoverAndFocus` - открывать по ховеру и фокусу <br> - `clickAndFocusVisible` - открывать по клику и focus-visible |
|
|
30
42
|
| placement | enum Placement: `"left"`, `"left-start"`, `"left-end"`, `"right"`, `"right-start"`, `"right-end"`, `"top"`, `"top-start"`, `"top-end"`, `"bottom"`, `"bottom-start"`, `"bottom-end"` | top | Положение поповера относительно своего триггера (children). |
|
|
31
43
|
| className | `string` | - | CSS-класс |
|
|
44
|
+
| size | "s" \| "m" \| "l" | - | Размер списка |
|
|
32
45
|
| pinTop | `ItemProps[]` | - | Элементы списка, закрепленные сверху |
|
|
33
46
|
| pinBottom | `ItemProps[]` | - | Элементы списка, закрепленные снизу |
|
|
34
|
-
| footer | `
|
|
47
|
+
| footer | `ReactNode ;` | - | Кастомизируемый элемент в конце списка |
|
|
35
48
|
| footerActiveElementsRefs | `RefObject<HTMLElement>[]` | - | Список ссылок на кастомные элементы, помещенные в специальную секцию внизу списка |
|
|
36
49
|
| search | `SearchState` | - | Настройки поисковой строки |
|
|
37
|
-
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
38
|
-
| noData | `string` | - | Текст для состояния "Отсутсвие данных" |
|
|
39
|
-
| noResults | `string` | - | Текст для состояния "Отсутсвие результата" при поиске |
|
|
40
50
|
| collapse | `CollapseState` | {} | Настройки раскрытия элементов |
|
|
51
|
+
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
41
52
|
| selection | `SelectionSingleState \| SelectionMultipleState` | - | |
|
|
42
|
-
| size | "s" \| "m" \| "l" | - | Размер списка |
|
|
43
53
|
| marker | `boolean` | - | Отображать ли маркер у выбранного жлемента списка |
|
|
44
54
|
| scroll | `boolean` | - | Включить ли скролл для основной части списка |
|
|
45
55
|
| scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
|
|
46
56
|
| scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
|
|
57
|
+
| dataFiltered | `boolean` | - | |
|
|
58
|
+
| dataError | `boolean` | - | |
|
|
59
|
+
| noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
|
|
60
|
+
| noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
|
|
61
|
+
| errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
|
|
47
62
|
## List
|
|
48
63
|
### Props
|
|
49
64
|
| name | type | default value | description |
|
|
@@ -51,22 +66,25 @@
|
|
|
51
66
|
| items* | `ItemProps[]` | - | Основные элементы списка |
|
|
52
67
|
| pinTop | `ItemProps[]` | - | Элементы списка, закрепленные сверху |
|
|
53
68
|
| pinBottom | `ItemProps[]` | - | Элементы списка, закрепленные снизу |
|
|
54
|
-
| footer | `
|
|
69
|
+
| footer | `ReactNode ;` | - | Кастомизируемый элемент в конце списка |
|
|
55
70
|
| footerActiveElementsRefs | `RefObject<HTMLElement>[]` | - | Список ссылок на кастомные элементы, помещенные в специальную секцию внизу списка |
|
|
56
71
|
| search | `SearchState` | - | Настройки поисковой строки |
|
|
57
|
-
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
58
|
-
| noData | `string` | - | Текст для состояния "Отсутсвие данных" |
|
|
59
|
-
| noResults | `string` | - | Текст для состояния "Отсутсвие результата" при поиске |
|
|
60
72
|
| tabIndex | `number` | - | Tab Index |
|
|
61
73
|
| collapse | `CollapseState` | {} | Настройки раскрытия элементов |
|
|
62
74
|
| className | `string` | - | CSS-класс |
|
|
63
75
|
| onKeyDown | `(e: KeyboardEvent<HTMLElement>) => void` | - | |
|
|
76
|
+
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
64
77
|
| selection | `SelectionSingleState \| SelectionMultipleState` | - | |
|
|
65
78
|
| size | "s" \| "m" \| "l" | - | Размер списка |
|
|
66
79
|
| marker | `boolean` | - | Отображать ли маркер у выбранного жлемента списка |
|
|
67
80
|
| scroll | `boolean` | - | Включить ли скролл для основной части списка |
|
|
68
81
|
| scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
|
|
69
82
|
| scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
|
|
83
|
+
| dataFiltered | `boolean` | - | |
|
|
84
|
+
| dataError | `boolean` | - | |
|
|
85
|
+
| noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
|
|
86
|
+
| noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
|
|
87
|
+
| errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
|
|
70
88
|
| ref | `Ref<HTMLElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom |
|
|
71
89
|
| key | `Key` | - | |
|
|
72
90
|
|
|
@@ -11,7 +11,6 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
import { ChevronDownSVG, ChevronUpSVG } from '@snack-uikit/icons';
|
|
14
|
-
import { useToggleGroup } from '@snack-uikit/toggles';
|
|
15
14
|
import { CollapseBlockPrivate } from '../../../helperComponents';
|
|
16
15
|
import { CollapseContext, useCollapseContext, useParentListContext } from '../../Lists/contexts';
|
|
17
16
|
import { BaseItem } from '../BaseItem';
|
|
@@ -19,12 +18,11 @@ import { useGroupItemSelection, useRenderItems } from '../hooks';
|
|
|
19
18
|
export function AccordionItem(_a) {
|
|
20
19
|
var { items: itemsProp, id, disabled } = _a, option = __rest(_a, ["items", "id", "disabled"]);
|
|
21
20
|
const { level = 1 } = useCollapseContext();
|
|
22
|
-
const { toggleOpenCollapsedItems } = useParentListContext();
|
|
21
|
+
const { toggleOpenCollapsedItems, openCollapsedItems } = useParentListContext();
|
|
23
22
|
const { isIndeterminate, checked, handleOnSelect } = useGroupItemSelection({ items: itemsProp, id, disabled });
|
|
24
|
-
const
|
|
23
|
+
const isOpen = Boolean(openCollapsedItems === null || openCollapsedItems === void 0 ? void 0 : openCollapsedItems.includes(id !== null && id !== void 0 ? id : ''));
|
|
25
24
|
const handleKeyDown = (e) => {
|
|
26
25
|
if (e.key === 'ArrowRight') {
|
|
27
|
-
handleChange();
|
|
28
26
|
toggleOpenCollapsedItems === null || toggleOpenCollapsedItems === void 0 ? void 0 : toggleOpenCollapsedItems(id !== null && id !== void 0 ? id : '');
|
|
29
27
|
e.preventDefault();
|
|
30
28
|
e.stopPropagation();
|
|
@@ -33,9 +31,8 @@ export function AccordionItem(_a) {
|
|
|
33
31
|
const itemsJSX = useRenderItems(itemsProp);
|
|
34
32
|
const handleItemClick = (e) => {
|
|
35
33
|
var _a;
|
|
36
|
-
handleChange();
|
|
37
34
|
toggleOpenCollapsedItems === null || toggleOpenCollapsedItems === void 0 ? void 0 : toggleOpenCollapsedItems(id !== null && id !== void 0 ? id : '');
|
|
38
35
|
(_a = option.onClick) === null || _a === void 0 ? void 0 : _a.call(option, e);
|
|
39
36
|
};
|
|
40
|
-
return (_jsx(CollapseBlockPrivate, { header: _jsx(BaseItem, Object.assign({}, option, { id: id, disabled: disabled, expandIcon:
|
|
37
|
+
return (_jsx(CollapseBlockPrivate, { header: _jsx(BaseItem, Object.assign({}, option, { id: id, disabled: disabled, expandIcon: isOpen ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}), onClick: handleItemClick, isParentNode: true, onKeyDown: handleKeyDown, indeterminate: isIndeterminate && !checked, onSelect: !disabled ? handleOnSelect : undefined })), expanded: isOpen, "data-test-id": `list__accordion-item-${id}`, children: _jsx(CollapseContext.Provider, { value: { level: level + 1 }, children: itemsJSX }) }));
|
|
41
38
|
}
|
|
@@ -70,7 +70,7 @@ export function BaseItem(_a) {
|
|
|
70
70
|
e.stopPropagation();
|
|
71
71
|
};
|
|
72
72
|
const props = extractSupportProps(rest);
|
|
73
|
-
const item = (_jsxs("li", { role: 'menuitem', "data-test-id": props['data-test-id'] || 'list__base-item_' + id, ref: itemRef, className: cn(commonStyles.listItem, styles.droplistItem, className), "data-size": size, onClick: handleItemClick, tabIndex: -1, "data-non-pointer": inactive && !onClick, "data-inactive": inactive || undefined, "data-checked": (isParentNode && (indeterminate || isChecked)) || (isChecked && !switchProp) || undefined, "data-variant": mode || undefined, "data-open": open || undefined, "aria-disabled": disabled || undefined, "data-parent": parent || 'list', onKeyDown: handleItemKeyDown, onFocus: handleItemFocus, style: { '--level': level }, children: [!switchProp && isSelectionSingle && marker && !isParentNode && interactive && (_jsx("div", { className: styles.markerContainer, "data-test-id": 'list__base-item-marker' })), !switchProp && isSelectionMultiple && interactive && (_jsx("div", { className: styles.checkbox, children: _jsx(Checkbox, { size: CHECKBOX_SIZE_MAP[size !== null && size !== void 0 ? size : 's'], disabled: disabled, tabIndex: -1, onChange: handleCheckboxChange, checked: isChecked, "data-test-id": 'list__base-item-checkbox', onClick: handleCheckboxClick, indeterminate: indeterminate }) })), beforeContent && _jsx("div", { className: styles.beforeContent, children: beforeContent }), _jsxs("div", { className: styles.content, children: [_jsxs("div", { className: styles.headline, children: [_jsx("span", { className: styles.option, children: _jsx(TruncateString, { text: option, maxLines: 1 }) }), caption && _jsx("span", { className: styles.caption, children: caption })] }), description && (_jsx("div", { className: styles.description, children: _jsx(TruncateString, { text: description, maxLines: 2 }) }))] }), afterContent, switchProp && interactive && (_jsx(Switch, { disabled: disabled, checked: isChecked, "data-test-id": 'list__base-item-switch' })), !switchProp && expandIcon && _jsx("span", { className: styles.expandableIcon, children: expandIcon })] }));
|
|
73
|
+
const item = (_jsxs("li", { role: 'menuitem', "data-test-id": props['data-test-id'] || 'list__base-item_' + id, ref: itemRef, className: cn(commonStyles.listItem, styles.droplistItem, className), "data-size": size, onClick: handleItemClick, tabIndex: -1, "data-non-pointer": inactive && !onClick, "data-inactive": inactive || undefined, "data-checked": (isParentNode && (indeterminate || isChecked)) || (isChecked && !switchProp) || undefined, "data-variant": mode || undefined, "data-open": open || undefined, "data-disabled": disabled || undefined, "aria-disabled": disabled || undefined, "data-parent": parent || 'list', onKeyDown: handleItemKeyDown, onFocus: handleItemFocus, style: { '--level': level }, children: [!switchProp && isSelectionSingle && marker && !isParentNode && interactive && (_jsx("div", { className: styles.markerContainer, "data-test-id": 'list__base-item-marker' })), !switchProp && isSelectionMultiple && interactive && (_jsx("div", { className: styles.checkbox, children: _jsx(Checkbox, { size: CHECKBOX_SIZE_MAP[size !== null && size !== void 0 ? size : 's'], disabled: disabled, tabIndex: -1, onChange: handleCheckboxChange, checked: isChecked, "data-test-id": 'list__base-item-checkbox', onClick: handleCheckboxClick, indeterminate: indeterminate }) })), beforeContent && _jsx("div", { className: styles.beforeContent, children: beforeContent }), _jsxs("div", { className: styles.content, children: [_jsxs("div", { className: styles.headline, children: [_jsx("span", { className: styles.option, children: _jsx(TruncateString, { text: option, maxLines: 1 }) }), caption && _jsx("span", { className: styles.caption, children: caption })] }), description && (_jsx("div", { className: styles.description, children: _jsx(TruncateString, { text: description, maxLines: 2 }) }))] }), afterContent, switchProp && interactive && (_jsx(Switch, { disabled: disabled, checked: isChecked, "data-test-id": 'list__base-item-switch' })), !switchProp && expandIcon && _jsx("span", { className: styles.expandableIcon, children: expandIcon })] }));
|
|
74
74
|
if (!itemWrapRender) {
|
|
75
75
|
return item;
|
|
76
76
|
}
|
|
@@ -184,13 +184,13 @@
|
|
|
184
184
|
.droplistItem[aria-disabled] .option,
|
|
185
185
|
.droplistItem[aria-disabled] .description,
|
|
186
186
|
.droplistItem[aria-disabled] .caption,
|
|
187
|
-
.droplistItem[aria-disabled] .expandableIcon, .droplistItem
|
|
188
|
-
.droplistItem
|
|
189
|
-
.droplistItem
|
|
190
|
-
.droplistItem
|
|
187
|
+
.droplistItem[aria-disabled] .expandableIcon, .droplistItem[data-disabled] .option,
|
|
188
|
+
.droplistItem[data-disabled] .description,
|
|
189
|
+
.droplistItem[data-disabled] .caption,
|
|
190
|
+
.droplistItem[data-disabled] .expandableIcon{
|
|
191
191
|
color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
192
192
|
}
|
|
193
|
-
.droplistItem[aria-disabled] .beforeContent, .droplistItem
|
|
193
|
+
.droplistItem[aria-disabled] .beforeContent, .droplistItem[data-disabled] .beforeContent{
|
|
194
194
|
opacity:var(--opacity-a064, 0.64);
|
|
195
195
|
}
|
|
196
196
|
.droplistItem[data-has-checked][data-variant=single]::after, .droplistItem[data-checked][data-variant=single]::after{
|
|
@@ -205,15 +205,11 @@
|
|
|
205
205
|
background-color:var(--sys-primary-accent-default, #794ed3);
|
|
206
206
|
}
|
|
207
207
|
.droplistItem[data-has-checked]:focus-visible[data-variant=single], .droplistItem[data-checked]:focus-visible[data-variant=single]{
|
|
208
|
-
background-color:var(--sys-primary-background, #f6effe);
|
|
209
208
|
outline-color:var(--sys-primary-accent-default, #794ed3);
|
|
210
209
|
}
|
|
211
|
-
.droplistItem[data-has-checked]
|
|
212
|
-
background-color:var(--sys-neutral-background1-level, #fafafc);
|
|
213
|
-
}
|
|
214
|
-
.droplistItem[data-has-checked]:disabled[data-variant=single]::before, .droplistItem[data-checked]:disabled[data-variant=single]::before{
|
|
210
|
+
.droplistItem[data-has-checked][data-disabled][data-variant=single]::before, .droplistItem[data-checked][data-disabled][data-variant=single]::before{
|
|
215
211
|
display:none;
|
|
216
212
|
}
|
|
217
|
-
.droplistItem[data-has-checked]
|
|
213
|
+
.droplistItem[data-has-checked][data-disabled] .markerContainer:before, .droplistItem[data-checked][data-disabled] .markerContainer:before{
|
|
218
214
|
background-color:var(--sys-neutral-text-disabled, #b3b6bf);
|
|
219
215
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createElement as _createElement } from "react";
|
|
2
2
|
import { createRef, useEffect, useMemo } from 'react';
|
|
3
|
-
import { extractChildIds } from '../../utils';
|
|
3
|
+
import { extractAllChildIds, extractChildIds } from '../../utils';
|
|
4
4
|
import { useSelectionContext } from '../Lists/contexts';
|
|
5
5
|
import { AccordionItem } from './AccordionItem';
|
|
6
6
|
import { BaseItem } from './BaseItem';
|
|
@@ -8,17 +8,17 @@ import { GroupItem } from './GroupItem';
|
|
|
8
8
|
import { NextListItem } from './NextListItem';
|
|
9
9
|
import { addItemsIds, isAccordionItemProps, isGroupItemProps, isNextListItemProps } from './utils';
|
|
10
10
|
export function useRenderItems(items) {
|
|
11
|
-
return useMemo(() => items.map(
|
|
11
|
+
return useMemo(() => items.map(item => {
|
|
12
12
|
if (isGroupItemProps(item)) {
|
|
13
|
-
return _createElement(GroupItem, Object.assign({}, item, { key: item.
|
|
13
|
+
return _createElement(GroupItem, Object.assign({}, item, { key: item.label }));
|
|
14
14
|
}
|
|
15
15
|
if (isAccordionItemProps(item)) {
|
|
16
|
-
return _createElement(AccordionItem, Object.assign({}, item, { key:
|
|
16
|
+
return _createElement(AccordionItem, Object.assign({}, item, { key: item.key }));
|
|
17
17
|
}
|
|
18
18
|
if (isNextListItemProps(item)) {
|
|
19
|
-
return _createElement(NextListItem, Object.assign({}, item, { key: item.
|
|
19
|
+
return _createElement(NextListItem, Object.assign({}, item, { key: item.key }));
|
|
20
20
|
}
|
|
21
|
-
return _createElement(BaseItem, Object.assign({}, item, { key: item.
|
|
21
|
+
return _createElement(BaseItem, Object.assign({}, item, { key: item.key }));
|
|
22
22
|
}), [items]);
|
|
23
23
|
}
|
|
24
24
|
export function useItemsWithIds({ search, footerActiveElementsRefs }) {
|
|
@@ -31,11 +31,11 @@ export function useItemsWithIds({ search, footerActiveElementsRefs }) {
|
|
|
31
31
|
}
|
|
32
32
|
export function useGroupItemSelection({ id, items, disabled }) {
|
|
33
33
|
const { value, setValue, isSelectionMultiple } = useSelectionContext();
|
|
34
|
-
const childIds = useMemo(() => extractChildIds({ items }), [items]);
|
|
34
|
+
const { childIds, allChildIds } = useMemo(() => ({ childIds: extractChildIds({ items }), allChildIds: extractAllChildIds({ items }) }), [items]);
|
|
35
35
|
const isIndeterminate = isSelectionMultiple
|
|
36
|
-
?
|
|
37
|
-
:
|
|
38
|
-
const checked = isSelectionMultiple ?
|
|
36
|
+
? allChildIds.some(childId => value === null || value === void 0 ? void 0 : value.includes(childId))
|
|
37
|
+
: allChildIds.includes(value !== null && value !== void 0 ? value : '');
|
|
38
|
+
const checked = isSelectionMultiple ? allChildIds.every(childId => value === null || value === void 0 ? void 0 : value.includes(childId)) : undefined;
|
|
39
39
|
useEffect(() => {
|
|
40
40
|
if (isSelectionMultiple) {
|
|
41
41
|
if (checked && !(value === null || value === void 0 ? void 0 : value.includes(id))) {
|
|
@@ -50,23 +50,23 @@
|
|
|
50
50
|
height:100%;
|
|
51
51
|
background-color:transparent;
|
|
52
52
|
}
|
|
53
|
-
.listItem:disabled{
|
|
53
|
+
.listItem[data-disabled], .listItem:disabled{
|
|
54
54
|
cursor:not-allowed;
|
|
55
55
|
background-color:transparent;
|
|
56
56
|
outline:none;
|
|
57
57
|
}
|
|
58
|
-
.listItem:disabled::before{
|
|
58
|
+
.listItem[data-disabled]::before, .listItem:disabled::before{
|
|
59
59
|
display:none;
|
|
60
60
|
}
|
|
61
|
-
.listItem:disabled::after{
|
|
61
|
+
.listItem[data-disabled]::after, .listItem:disabled::after{
|
|
62
62
|
cursor:not-allowed;
|
|
63
63
|
background-color:transparent;
|
|
64
64
|
}
|
|
65
|
-
.listItem:not([data-inactive])[data-open]::after, .listItem:not([data-inactive])[data-focused]::after, .listItem:not([data-inactive]):hover::after, .listItem:not([data-inactive]):focus-visible::after{
|
|
65
|
+
.listItem:not([data-inactive], [data-disabled])[data-open]::after, .listItem:not([data-inactive], [data-disabled])[data-focused]::after, .listItem:not([data-inactive], [data-disabled]):hover::after, .listItem:not([data-inactive], [data-disabled]):focus-visible::after{
|
|
66
66
|
opacity:var(--opacity-a008, 0.08);
|
|
67
67
|
background-color:var(--sys-neutral-accent-default, #6f717c);
|
|
68
68
|
}
|
|
69
|
-
.listItem:not([data-inactive])[data-focused], .listItem:not([data-inactive]):focus-visible{
|
|
69
|
+
.listItem:not([data-inactive], [data-disabled])[data-focused], .listItem:not([data-inactive], [data-disabled]):focus-visible{
|
|
70
70
|
outline-width:var(--border-state-focus-s-border-width, 2px);
|
|
71
71
|
outline-style:var(--border-state-focus-s-border-style, solid);
|
|
72
72
|
outline-color:var(--border-state-focus-s-border-color, );
|
|
@@ -48,6 +48,7 @@ export type BaseItemProps = WithSupportProps<{
|
|
|
48
48
|
* Флаг отображения состояния выбранного элемента через switch
|
|
49
49
|
*/
|
|
50
50
|
switch?: boolean;
|
|
51
|
+
key?: string | number;
|
|
51
52
|
itemWrapRender?(item: ReactNode): ReactNode;
|
|
52
53
|
}>;
|
|
53
54
|
type BaseItemsWithoutNonGroupProps = Omit<BaseItemProps, 'switch' | 'inactive'>;
|
|
@@ -30,13 +30,14 @@ export function getSlicedItems({ items, hasSearch, pinTop, pinBottom, footerRefs
|
|
|
30
30
|
export function addItemsIds(itemsProp, prefix) {
|
|
31
31
|
return itemsProp.map((item, idx) => {
|
|
32
32
|
var _a;
|
|
33
|
-
const
|
|
33
|
+
const autoId = prefix !== undefined ? [prefix, idx].join('-') : String(idx);
|
|
34
|
+
const itemId = (_a = item.id) !== null && _a !== void 0 ? _a : autoId;
|
|
34
35
|
if (isGroupItemProps(item)) {
|
|
35
|
-
return Object.assign(Object.assign({}, item), { id: itemId, items: addItemsIds(item.items, itemId) });
|
|
36
|
+
return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, items: addItemsIds(item.items, itemId) });
|
|
36
37
|
}
|
|
37
38
|
if (isAccordionItemProps(item) || isNextListItemProps(item)) {
|
|
38
|
-
return Object.assign(Object.assign({}, item), { id: itemId, items: addItemsIds(item.items, itemId), itemRef: item.itemRef || createRef() });
|
|
39
|
+
return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, items: addItemsIds(item.items, itemId), itemRef: item.itemRef || createRef() });
|
|
39
40
|
}
|
|
40
|
-
return Object.assign(Object.assign({}, item), { id: itemId, itemRef: item.itemRef || createRef() });
|
|
41
|
+
return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, itemRef: item.itemRef || createRef() });
|
|
41
42
|
});
|
|
42
43
|
}
|
|
@@ -23,12 +23,7 @@ export function Droplist(_a) {
|
|
|
23
23
|
var { items: itemsProp, search, pinBottom, pinTop, footerActiveElementsRefs, children, trigger, placement, widthStrategy, triggerElemRef: triggerElemRefProp, open: openProp, onOpenChange, collapse = {} } = _a, props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "children", "trigger", "placement", "widthStrategy", "triggerElemRef", "open", "onOpenChange", "collapse"]);
|
|
24
24
|
const hasSearch = useMemo(() => Boolean(search), [search]);
|
|
25
25
|
const memorizedItems = useMemo(() => addItemsIds((pinBottom !== null && pinBottom !== void 0 ? pinBottom : []).concat(itemsProp).concat(pinTop !== null && pinTop !== void 0 ? pinTop : [])), [itemsProp, pinBottom, pinTop]);
|
|
26
|
-
const [openCollapsedItems, setOpenCollapsedItems] = useUncontrolledProp(collapse.value, (_b = collapse.defaultValue) !== null && _b !== void 0 ? _b : [], collapse.onChange
|
|
27
|
-
? cb => {
|
|
28
|
-
var _a;
|
|
29
|
-
(_a = collapse.onChange) === null || _a === void 0 ? void 0 : _a.call(collapse, cb(collapse.value));
|
|
30
|
-
}
|
|
31
|
-
: undefined);
|
|
26
|
+
const [openCollapsedItems, setOpenCollapsedItems] = useUncontrolledProp(collapse.value, (_b = collapse.defaultValue) !== null && _b !== void 0 ? _b : [], collapse.onChange);
|
|
32
27
|
const { search: searchItem, footerRefs } = useItemsWithIds({
|
|
33
28
|
search: hasSearch,
|
|
34
29
|
footerActiveElementsRefs,
|
|
@@ -52,11 +47,9 @@ export function Droplist(_a) {
|
|
|
52
47
|
const { activeFocusIndex, setActiveFocusIndex, openNestedIndex, handleListKeyDown, resetNestedIndex, resetActiveFocusIndex, } = useKeyboardNavigation({ ids, expandedIds, parentRef: triggerElemRefProp !== null && triggerElemRefProp !== void 0 ? triggerElemRefProp : triggerElemRef, itemRefs });
|
|
53
48
|
const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
|
|
54
49
|
const handleOpenChange = (open) => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
setOpenCollapsedItems([]);
|
|
59
|
-
}
|
|
50
|
+
resetNestedIndex();
|
|
51
|
+
resetActiveFocusIndex();
|
|
52
|
+
setOpenCollapsedItems([]);
|
|
60
53
|
setOpen(open);
|
|
61
54
|
};
|
|
62
55
|
const onKeyDown = useCallback((e, cb) => {
|
|
@@ -79,6 +72,9 @@ export function Droplist(_a) {
|
|
|
79
72
|
onKeyDown(e, (_a = children.props) === null || _a === void 0 ? void 0 : _a.onKeyDown);
|
|
80
73
|
} }));
|
|
81
74
|
}
|
|
75
|
+
if (typeof children === 'function') {
|
|
76
|
+
return children({ onKeyDown });
|
|
77
|
+
}
|
|
82
78
|
return children;
|
|
83
79
|
}, [onKeyDown, children]);
|
|
84
80
|
return (
|
|
@@ -94,6 +90,7 @@ export function Droplist(_a) {
|
|
|
94
90
|
parentRef: listRef,
|
|
95
91
|
parentResetNestedIndex: resetNestedIndex,
|
|
96
92
|
parentResetActiveFocusIndex: resetActiveFocusIndex,
|
|
93
|
+
openCollapsedItems,
|
|
97
94
|
toggleOpenCollapsedItems: id => setOpenCollapsedItems((items = []) => items.includes(id) ? items.filter(item => item !== id) : items === null || items === void 0 ? void 0 : items.concat([id])),
|
|
98
95
|
}, children: _jsx(Dropdown, Object.assign({ content: _jsx(ListPrivate, Object.assign({}, slicedItems, props, { onKeyDown: handleListKeyDown, tabIndex: 0, ref: listRef, search: search, limitedScrollHeight: true, parent: 'droplist' })), trigger: trigger, placement: placement, widthStrategy: widthStrategy }, (triggerElemRefProp
|
|
99
96
|
? {}
|
|
@@ -7,10 +7,7 @@ export declare const List: import("react").ForwardRefExoticComponent<{
|
|
|
7
7
|
pinBottom?: import("../../Items").ItemProps[] | undefined;
|
|
8
8
|
footer?: import("react").ReactNode;
|
|
9
9
|
footerActiveElementsRefs?: import("react").RefObject<HTMLElement>[] | undefined;
|
|
10
|
-
search?: import("
|
|
11
|
-
loading?: boolean | undefined;
|
|
12
|
-
noData?: string | undefined;
|
|
13
|
-
noResults?: string | undefined;
|
|
10
|
+
search?: import("../../..").SearchState | undefined;
|
|
14
11
|
tabIndex?: number | undefined;
|
|
15
12
|
collapse?: {
|
|
16
13
|
value?: (string | number)[] | undefined;
|
|
@@ -19,4 +16,5 @@ export declare const List: import("react").ForwardRefExoticComponent<{
|
|
|
19
16
|
} | undefined;
|
|
20
17
|
className?: string | undefined;
|
|
21
18
|
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
22
|
-
|
|
19
|
+
loading?: boolean | undefined;
|
|
20
|
+
} & import("../contexts").SelectionState & import("../contexts").ListContextType & import("../../../types").ScrollProps & import("../types").EmptyState & import("react").RefAttributes<HTMLElement>>;
|
|
@@ -26,12 +26,7 @@ export const List = forwardRef((_a, ref) => {
|
|
|
26
26
|
var { items: itemsProp, search, pinBottom, pinTop, footerActiveElementsRefs, onKeyDown, tabIndex = 0, className, collapse = {} } = _a, props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "onKeyDown", "tabIndex", "className", "collapse"]);
|
|
27
27
|
const hasSearch = useMemo(() => Boolean(search), [search]);
|
|
28
28
|
const memorizedItems = useMemo(() => addItemsIds((pinTop !== null && pinTop !== void 0 ? pinTop : []).concat(itemsProp).concat(pinBottom !== null && pinBottom !== void 0 ? pinBottom : [])), [itemsProp, pinBottom, pinTop]);
|
|
29
|
-
const [openCollapsedItems, setOpenCollapsedItems] = useUncontrolledProp(collapse.value, (_b = collapse.defaultValue) !== null && _b !== void 0 ? _b : [], collapse.onChange
|
|
30
|
-
? cb => {
|
|
31
|
-
var _a;
|
|
32
|
-
(_a = collapse.onChange) === null || _a === void 0 ? void 0 : _a.call(collapse, cb(collapse.value));
|
|
33
|
-
}
|
|
34
|
-
: undefined);
|
|
29
|
+
const [openCollapsedItems, setOpenCollapsedItems] = useUncontrolledProp(collapse.value, (_b = collapse.defaultValue) !== null && _b !== void 0 ? _b : [], collapse.onChange);
|
|
35
30
|
const { search: searchItem, footerRefs } = useItemsWithIds({
|
|
36
31
|
search: hasSearch,
|
|
37
32
|
footerActiveElementsRefs,
|
|
@@ -7,10 +7,7 @@ export declare const ListPrivate: import("react").ForwardRefExoticComponent<{
|
|
|
7
7
|
pinBottom?: import("../../Items").ItemProps[] | undefined;
|
|
8
8
|
footer?: import("react").ReactNode;
|
|
9
9
|
footerActiveElementsRefs?: RefObject<HTMLElement>[] | undefined;
|
|
10
|
-
search?: import("
|
|
11
|
-
loading?: boolean | undefined;
|
|
12
|
-
noData?: string | undefined;
|
|
13
|
-
noResults?: string | undefined;
|
|
10
|
+
search?: import("../../..").SearchState | undefined;
|
|
14
11
|
tabIndex?: number | undefined;
|
|
15
12
|
collapse?: {
|
|
16
13
|
value?: (string | number)[] | undefined;
|
|
@@ -19,7 +16,8 @@ export declare const ListPrivate: import("react").ForwardRefExoticComponent<{
|
|
|
19
16
|
} | undefined;
|
|
20
17
|
className?: string | undefined;
|
|
21
18
|
onKeyDown?(e: import("react").KeyboardEvent<HTMLElement>): void;
|
|
22
|
-
|
|
19
|
+
loading?: boolean | undefined;
|
|
20
|
+
} & import("../contexts").SelectionState & import("../contexts").ListContextType & import("../../../types").ScrollProps & import("../types").EmptyState & import("../contexts").ListContextPrivateType & {
|
|
23
21
|
nested?: boolean | undefined;
|
|
24
22
|
active?: boolean | undefined;
|
|
25
23
|
tabIndex?: number | undefined;
|
|
@@ -14,26 +14,26 @@ import cn from 'classnames';
|
|
|
14
14
|
import { forwardRef, useMemo } from 'react';
|
|
15
15
|
import { Spinner } from '@snack-uikit/loaders';
|
|
16
16
|
import { Scroll } from '@snack-uikit/scroll';
|
|
17
|
-
import { ToggleGroup } from '@snack-uikit/toggles';
|
|
18
17
|
import { extractSupportProps } from '@snack-uikit/utils';
|
|
18
|
+
import { ListEmptyState, useEmptyState } from '../../../helperComponents';
|
|
19
19
|
import { PinBottomGroupItem, PinTopGroupItem, SearchItem, useRenderItems } from '../../Items';
|
|
20
20
|
import { ListContextProvider } from '../contexts';
|
|
21
21
|
import commonStyles from '../styles.module.css';
|
|
22
22
|
import styles from './styles.module.css';
|
|
23
23
|
export const ListPrivate = forwardRef((_a, ref) => {
|
|
24
|
-
var
|
|
25
|
-
var { items, pinTop, pinBottom, onKeyDown, onBlur, onFocus, tabIndex, active, scroll, nested, search, scrollRef, scrollContainerRef, footer, loading, noData = 'No data', noResults = 'No results', size = 's', marker, limitedScrollHeight, className, parent = 'list' } = _a, props = __rest(_a, ["items", "pinTop", "pinBottom", "onKeyDown", "onBlur", "onFocus", "tabIndex", "active", "scroll", "nested", "search", "scrollRef", "scrollContainerRef", "footer", "loading", "noData", "noResults", "size", "marker", "limitedScrollHeight", "className", "parent"]);
|
|
24
|
+
var { items, pinTop, pinBottom, onKeyDown, onBlur, onFocus, tabIndex, active, scroll, nested, search, scrollRef, scrollContainerRef, footer, loading, size = 's', marker = true, limitedScrollHeight, className, parent = 'list', noDataState, noResultsState, errorDataState, dataError, dataFiltered } = _a, props = __rest(_a, ["items", "pinTop", "pinBottom", "onKeyDown", "onBlur", "onFocus", "tabIndex", "active", "scroll", "nested", "search", "scrollRef", "scrollContainerRef", "footer", "loading", "size", "marker", "limitedScrollHeight", "className", "parent", "noDataState", "noResultsState", "errorDataState", "dataError", "dataFiltered"]);
|
|
26
25
|
const itemsJSX = useRenderItems(items);
|
|
27
26
|
const itemsPinTopJSX = useRenderItems(pinTop !== null && pinTop !== void 0 ? pinTop : []);
|
|
28
27
|
const itemsPinBottomJSX = useRenderItems(pinBottom !== null && pinBottom !== void 0 ? pinBottom : []);
|
|
29
|
-
const
|
|
28
|
+
const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
|
|
29
|
+
const hasNoItems = items.length === 0;
|
|
30
30
|
const loadingJSX = useMemo(() => loading && (_jsx("div", { role: 'spinbutton', tabIndex: -1, className: styles.loader, "data-size": size, "data-no-items": hasNoItems || undefined, "data-test-id": 'list__loader', children: _jsx(Spinner, { size: size === 'l' ? 's' : 'xs' }) })), [hasNoItems, loading, size]);
|
|
31
|
-
const content = useMemo(() => (_jsxs("div", { className: styles.content, children: [itemsJSX, loadingJSX,
|
|
32
|
-
const listJSX = (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
const content = useMemo(() => (_jsxs("div", { className: styles.content, children: [itemsJSX, loadingJSX, _jsx(ListEmptyState, { loading: loading, dataError: dataError, emptyStates: emptyStates, itemsLength: items.length, dataFiltered: dataFiltered !== null && dataFiltered !== void 0 ? dataFiltered : Boolean(search === null || search === void 0 ? void 0 : search.value) })] })), [dataError, dataFiltered, emptyStates, items.length, itemsJSX, loading, loadingJSX, search === null || search === void 0 ? void 0 : search.value]);
|
|
32
|
+
const listJSX = (_jsxs("ul", Object.assign({ className: cn(commonStyles.listContainer, className), ref: ref, onKeyDown: onKeyDown, tabIndex: tabIndex, onFocus: !nested ? onFocus : undefined, onBlur: onBlur, "data-active": active || undefined, role: 'menu' }, extractSupportProps(props), { children: [(Number(pinTop === null || pinTop === void 0 ? void 0 : pinTop.length) > 0 || search) && (_jsxs(PinTopGroupItem, { children: [search && _jsx(SearchItem, { search: search }), Number(pinTop === null || pinTop === void 0 ? void 0 : pinTop.length) > 0 && itemsPinTopJSX] })), scroll ? (_jsxs(Scroll, { className: cn({
|
|
33
|
+
[commonStyles.scrollContainerS]: scroll && limitedScrollHeight && size === 's',
|
|
34
|
+
[commonStyles.scrollContainerM]: scroll && limitedScrollHeight && size === 'm',
|
|
35
|
+
[commonStyles.scrollContainerL]: scroll && limitedScrollHeight && size === 'l',
|
|
36
|
+
}), barHideStrategy: 'never', size: size === 's' ? 's' : 'm', ref: scrollContainerRef, children: [content, _jsx("div", { className: styles.scrollStub, ref: scrollRef })] })) : (_jsx(_Fragment, { children: content })), Number(pinBottom === null || pinBottom === void 0 ? void 0 : pinBottom.length) > 0 && _jsx(PinBottomGroupItem, { children: itemsPinBottomJSX }), footer && _jsx("div", { className: styles.footer, children: footer })] })));
|
|
37
37
|
if (!nested) {
|
|
38
38
|
return (_jsx(ListContextProvider, { size: size, marker: marker, parent: parent, children: listJSX }));
|
|
39
39
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
type SelectionSingleValueType = string | number | undefined;
|
|
3
|
-
type SelectionSingleState = {
|
|
2
|
+
export type SelectionSingleValueType = string | number | undefined;
|
|
3
|
+
export type SelectionSingleState = {
|
|
4
4
|
/** Начальное состояние */
|
|
5
5
|
defaultValue?: SelectionSingleValueType;
|
|
6
6
|
/** Controlled состояние */
|
|
@@ -17,7 +17,7 @@ export type SelectionSingleProps = {
|
|
|
17
17
|
/** Режим выбора multi */
|
|
18
18
|
isSelectionMultiple: false;
|
|
19
19
|
} & SelectionSingleState;
|
|
20
|
-
type SelectionMultipleState = {
|
|
20
|
+
export type SelectionMultipleState = {
|
|
21
21
|
/** Начальное состояние */
|
|
22
22
|
defaultValue?: SelectionSingleValueType[];
|
|
23
23
|
/** Controlled состояние */
|
|
@@ -45,18 +45,21 @@ function SelectionSingleProvider({ value: valueProp, defaultValue, onChange: onC
|
|
|
45
45
|
}, children: children }));
|
|
46
46
|
}
|
|
47
47
|
function SelectionMultipleProvider({ value: valueProp, defaultValue, onChange: onChangeProp, children, }) {
|
|
48
|
-
const [value, setValue] = useUncontrolledProp(valueProp, defaultValue,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
const [value, setValue] = useUncontrolledProp(valueProp, defaultValue, onChangeProp);
|
|
49
|
+
const onChange = useCallback((newValue) => {
|
|
50
|
+
setValue((oldValues) => {
|
|
51
|
+
if (Array.isArray(oldValues)) {
|
|
52
|
+
if (oldValues.includes(newValue)) {
|
|
53
|
+
return oldValues.filter(oldValue => oldValue !== newValue);
|
|
54
|
+
}
|
|
55
|
+
return oldValues.concat(newValue);
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (oldValues === undefined) {
|
|
58
|
+
return Array.isArray(newValue) ? newValue : [newValue];
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
});
|
|
62
|
+
}, [setValue]);
|
|
60
63
|
return (_jsx(SelectionContext.Provider, { value: {
|
|
61
64
|
value,
|
|
62
65
|
onChange,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './Droplist';
|
|
2
2
|
export * from './List';
|
|
3
3
|
export type { ListProps, DroplistProps } from './types';
|
|
4
|
-
export type { SelectionSingleProps, SelectionMultipleProps, isSelectionSingleProps, isSelectionMultipleProps, } from './contexts';
|
|
4
|
+
export type { SelectionSingleState, SelectionMultipleState, SelectionSingleProps, SelectionMultipleProps, isSelectionSingleProps, isSelectionMultipleProps, SelectionSingleValueType, } from './contexts';
|
|
@@ -57,18 +57,4 @@
|
|
|
57
57
|
.scrollContainerL{
|
|
58
58
|
height:auto;
|
|
59
59
|
max-height:calc(var(--dimension-1m, 8px) * 48);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.infoBlock{
|
|
63
|
-
font-family:var(--sans-body-s-font-family, SB Sans Interface);
|
|
64
|
-
font-weight:var(--sans-body-s-font-weight, Regular);
|
|
65
|
-
line-height:var(--sans-body-s-line-height, 16px);
|
|
66
|
-
font-size:var(--sans-body-s-font-size, 12px);
|
|
67
|
-
letter-spacing:var(--sans-body-s-letter-spacing, 0.1px);
|
|
68
|
-
paragraph-spacing:var(--sans-body-s-paragraph-spacing, 6.6px);
|
|
69
|
-
display:flex;
|
|
70
|
-
align-items:center;
|
|
71
|
-
justify-content:center;
|
|
72
|
-
padding:var(--dimension-1m, 8px);
|
|
73
|
-
color:var(--sys-neutral-text-support, #656771);
|
|
74
60
|
}
|