@snack-uikit/list 0.20.0 → 0.21.1-preview-d1a63029.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 +12 -0
- package/README.md +17 -1
- package/dist/cjs/components/Items/BaseItem/BaseItem.js +4 -2
- package/dist/cjs/components/Items/NextListItem/NextListItem.js +4 -3
- package/dist/cjs/components/Items/SearchItem/SearchItem.js +4 -2
- package/dist/cjs/components/Items/hooks.js +11 -9
- package/dist/cjs/components/Items/utils.js +5 -3
- package/dist/cjs/components/Lists/Droplist/DropList.js +12 -7
- package/dist/cjs/components/Lists/List/List.d.ts +7 -1
- package/dist/cjs/components/Lists/List/List.js +19 -11
- package/dist/cjs/components/Lists/ListPrivate/ListPrivate.d.ts +3 -2
- package/dist/cjs/components/Lists/ListPrivate/ListPrivate.js +17 -3
- package/dist/cjs/components/Lists/contexts/NewListProvider.d.ts +2 -4
- package/dist/cjs/components/Lists/contexts/NewListProvider.js +7 -3
- package/dist/cjs/components/Lists/hooks.d.ts +6 -1
- package/dist/cjs/components/Lists/hooks.js +32 -18
- package/dist/cjs/components/Lists/types.d.ts +12 -3
- package/dist/cjs/constants.d.ts +8 -0
- package/dist/cjs/constants.js +14 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/utils.d.ts +16 -0
- package/dist/cjs/utils.js +25 -0
- package/dist/esm/components/Items/BaseItem/BaseItem.js +3 -3
- package/dist/esm/components/Items/NextListItem/NextListItem.js +2 -1
- package/dist/esm/components/Items/SearchItem/SearchItem.js +3 -2
- package/dist/esm/components/Items/hooks.js +6 -4
- package/dist/esm/components/Items/utils.js +5 -3
- package/dist/esm/components/Lists/Droplist/DropList.js +20 -4
- package/dist/esm/components/Lists/List/List.d.ts +7 -1
- package/dist/esm/components/Lists/List/List.js +23 -6
- package/dist/esm/components/Lists/ListPrivate/ListPrivate.d.ts +3 -2
- package/dist/esm/components/Lists/ListPrivate/ListPrivate.js +12 -4
- package/dist/esm/components/Lists/contexts/NewListProvider.d.ts +2 -4
- package/dist/esm/components/Lists/contexts/NewListProvider.js +4 -2
- package/dist/esm/components/Lists/hooks.d.ts +6 -1
- package/dist/esm/components/Lists/hooks.js +29 -19
- package/dist/esm/components/Lists/types.d.ts +12 -3
- package/dist/esm/constants.d.ts +8 -0
- package/dist/esm/constants.js +8 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/utils.d.ts +16 -0
- package/dist/esm/utils.js +16 -0
- package/package.json +8 -8
- package/src/components/Items/BaseItem/BaseItem.tsx +4 -4
- package/src/components/Items/NextListItem/NextListItem.tsx +2 -1
- package/src/components/Items/SearchItem/SearchItem.tsx +3 -2
- package/src/components/Items/hooks.tsx +6 -4
- package/src/components/Items/utils.ts +5 -3
- package/src/components/Lists/Droplist/DropList.tsx +20 -3
- package/src/components/Lists/List/List.tsx +25 -5
- package/src/components/Lists/ListPrivate/ListPrivate.tsx +13 -3
- package/src/components/Lists/contexts/NewListProvider.tsx +6 -2
- package/src/components/Lists/hooks.ts +35 -20
- package/src/components/Lists/types.ts +11 -3
- package/src/constants.ts +8 -0
- package/src/index.ts +3 -0
- package/src/utils.ts +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.21.0 (2024-10-31)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **PDS-438:** add keyboardNavigationRef, hasListInFocusChain props; export ids for navigation ([4472173](https://github.com/cloud-ru-tech/snack-uikit/commit/447217313b3aaf71196f20ce3298ce129a49a750))
|
|
12
|
+
* **PDS-438:** add scrollToSelectedItem prop ([ffc168f](https://github.com/cloud-ru-tech/snack-uikit/commit/ffc168f2201891a48b50d638ee0f4de91df18aa6))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
# 0.20.0 (2024-10-28)
|
|
7
19
|
|
|
8
20
|
|
package/README.md
CHANGED
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
| search | `SearchState` | - | Настройки поисковой строки |
|
|
75
75
|
| collapse | `CollapseState` | {} | Настройки раскрытия элементов |
|
|
76
76
|
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
77
|
+
| scrollToSelectedItem | `boolean` | - | Флаг, отвещающий за прокручивание до выбранного элемента |
|
|
77
78
|
| selection | `SelectionSingleState \| SelectionMultipleState` | - | |
|
|
78
79
|
| size | "s" \| "m" \| "l" | s | Размер списка |
|
|
79
80
|
| marker | `boolean` | true | Отображать ли маркер у выбранного жлемента списка |
|
|
@@ -97,12 +98,15 @@
|
|
|
97
98
|
| pinBottom | `Item[]` | - | Элементы списка, закрепленные снизу |
|
|
98
99
|
| footer | `ReactNode ;` | - | Кастомизируемый элемент в конце списка |
|
|
99
100
|
| footerActiveElementsRefs | `RefObject<HTMLElement>[]` | - | Список ссылок на кастомные элементы, помещенные в специальную секцию внизу списка |
|
|
101
|
+
| keyboardNavigationRef | `RefObject<{ focusItem(id: ItemId): void; }>` | - | Ссылка на управление навигацией листа с клавиатуры |
|
|
100
102
|
| search | `SearchState` | - | Настройки поисковой строки |
|
|
101
103
|
| tabIndex | `number` | - | Tab Index |
|
|
102
104
|
| collapse | `CollapseState` | {} | Настройки раскрытия элементов |
|
|
103
105
|
| className | `string` | - | CSS-класс |
|
|
104
|
-
| onKeyDown | `(e: KeyboardEvent<HTMLElement>) => void` | - | |
|
|
105
106
|
| loading | `boolean` | - | Флаг, отвещающий за состояние загрузки списка |
|
|
107
|
+
| onKeyDown | `(e: KeyboardEvent<HTMLElement>) => void` | - | Обработчик события по нажатию клавиш |
|
|
108
|
+
| hasListInFocusChain | `boolean` | true | Флаг, отвещающий за включение самого родительского контейнера листа в цепочку фокусирующихся элементов |
|
|
109
|
+
| scrollToSelectedItem | `boolean` | - | Флаг, отвещающий за прокручивание до выбранного элемента |
|
|
106
110
|
| selection | `SelectionSingleState \| SelectionMultipleState` | - | |
|
|
107
111
|
| size | "s" \| "m" \| "l" | s | Размер списка |
|
|
108
112
|
| marker | `boolean` | true | Отображать ли маркер у выбранного жлемента списка |
|
|
@@ -129,6 +133,18 @@
|
|
|
129
133
|
| truncate | `TruncateProps` | - | |
|
|
130
134
|
| disabled | `boolean` | - | |
|
|
131
135
|
| className | `string` | - | CSS-класс |
|
|
136
|
+
## getFooterItemId
|
|
137
|
+
`helper`
|
|
138
|
+
|
|
139
|
+
Возвращает id для элемента футера
|
|
140
|
+
## getItemAutoId
|
|
141
|
+
`helper`
|
|
142
|
+
|
|
143
|
+
Возвращает id для элемента, подставляя перфикс
|
|
144
|
+
## getDefaultItemId
|
|
145
|
+
`helper`
|
|
146
|
+
|
|
147
|
+
Возвращает id для дефолтного элемента
|
|
132
148
|
|
|
133
149
|
|
|
134
150
|
[//]: DOCUMENTATION_SECTION_END
|
|
@@ -57,7 +57,9 @@ function BaseItem(_a) {
|
|
|
57
57
|
const {
|
|
58
58
|
size = 's',
|
|
59
59
|
marker,
|
|
60
|
-
contentRender
|
|
60
|
+
contentRender,
|
|
61
|
+
firstItemId,
|
|
62
|
+
focusFlattenItems
|
|
61
63
|
} = (0, contexts_1.useNewListContext)();
|
|
62
64
|
const {
|
|
63
65
|
level = 0
|
|
@@ -146,7 +148,7 @@ function BaseItem(_a) {
|
|
|
146
148
|
"data-size": size,
|
|
147
149
|
onClick: handleItemClick,
|
|
148
150
|
onMouseDown: handleItemMouseDown,
|
|
149
|
-
tabIndex: -1,
|
|
151
|
+
tabIndex: id === focusFlattenItems[firstItemId].originalId ? 0 : -1,
|
|
150
152
|
"data-non-pointer": inactive && !onClick,
|
|
151
153
|
"data-variant": mode || undefined,
|
|
152
154
|
"data-open": open || undefined,
|
|
@@ -16,12 +16,13 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
16
16
|
const react_1 = require("react");
|
|
17
17
|
const dropdown_1 = require("@snack-uikit/dropdown");
|
|
18
18
|
const icons_1 = require("@snack-uikit/icons");
|
|
19
|
+
const constants_1 = require("../../../constants");
|
|
19
20
|
const contexts_1 = require("../../Lists/contexts");
|
|
20
21
|
const ListPrivate_1 = require("../../Lists/ListPrivate");
|
|
21
22
|
const BaseItem_1 = require("../BaseItem");
|
|
22
23
|
const hooks_1 = require("../hooks");
|
|
23
24
|
const utils_1 = require("../utils");
|
|
24
|
-
const
|
|
25
|
+
const constants_2 = require("./constants");
|
|
25
26
|
function NextListItem(_a) {
|
|
26
27
|
var {
|
|
27
28
|
items,
|
|
@@ -92,7 +93,7 @@ function NextListItem(_a) {
|
|
|
92
93
|
allChildIds
|
|
93
94
|
});
|
|
94
95
|
const handleOutsideClick = (0, react_1.useCallback)(() => {
|
|
95
|
-
forceUpdateActiveItemId === null || forceUpdateActiveItemId === void 0 ? void 0 : forceUpdateActiveItemId(
|
|
96
|
+
forceUpdateActiveItemId === null || forceUpdateActiveItemId === void 0 ? void 0 : forceUpdateActiveItemId(constants_1.ITEM_PREFIXES.dropFocus);
|
|
96
97
|
setOpen(false);
|
|
97
98
|
return true;
|
|
98
99
|
}, [forceUpdateActiveItemId]);
|
|
@@ -103,7 +104,7 @@ function NextListItem(_a) {
|
|
|
103
104
|
const listRef = (0, react_1.useRef)(null);
|
|
104
105
|
return (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, {
|
|
105
106
|
outsideClick: handleOutsideClick,
|
|
106
|
-
fallbackPlacements:
|
|
107
|
+
fallbackPlacements: constants_2.FALLBACK_PLACEMENTS,
|
|
107
108
|
content: (0, jsx_runtime_1.jsx)(ListPrivate_1.ListPrivate, {
|
|
108
109
|
onKeyDown: handleListKeyDown,
|
|
109
110
|
items: items,
|
|
@@ -12,6 +12,7 @@ exports.SearchItem = SearchItem;
|
|
|
12
12
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
13
13
|
const classnames_1 = __importDefault(require("classnames"));
|
|
14
14
|
const search_private_1 = require("@snack-uikit/search-private");
|
|
15
|
+
const constants_1 = require("../../../constants");
|
|
15
16
|
const contexts_1 = require("../../Lists/contexts");
|
|
16
17
|
const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
|
|
17
18
|
const styles_module_scss_2 = __importDefault(require('./styles.module.css'));
|
|
@@ -21,7 +22,8 @@ function SearchItem(_ref) {
|
|
|
21
22
|
itemRef
|
|
22
23
|
} = _ref;
|
|
23
24
|
const {
|
|
24
|
-
size = 's'
|
|
25
|
+
size = 's',
|
|
26
|
+
firstItemId
|
|
25
27
|
} = (0, contexts_1.useNewListContext)();
|
|
26
28
|
const handleKeyDown = e => {
|
|
27
29
|
if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
|
|
@@ -40,7 +42,7 @@ function SearchItem(_ref) {
|
|
|
40
42
|
"data-test-id": 'list__search-item',
|
|
41
43
|
children: (0, jsx_runtime_1.jsx)(search_private_1.SearchPrivate, Object.assign({
|
|
42
44
|
size: size,
|
|
43
|
-
tabIndex: -1,
|
|
45
|
+
tabIndex: constants_1.ITEM_PREFIXES.search === firstItemId ? 0 : -1,
|
|
44
46
|
onKeyDown: handleKeyDown,
|
|
45
47
|
onFocus: handleFocus
|
|
46
48
|
}, search, {
|
|
@@ -8,13 +8,15 @@ exports.useCreateBaseItems = useCreateBaseItems;
|
|
|
8
8
|
exports.useGroupItemSelection = useGroupItemSelection;
|
|
9
9
|
const react_1 = require("react");
|
|
10
10
|
const react_2 = require("react");
|
|
11
|
+
const constants_1 = require("../../constants");
|
|
12
|
+
const utils_1 = require("../../utils");
|
|
11
13
|
const contexts_1 = require("../Lists/contexts");
|
|
12
14
|
const AccordionItem_1 = require("./AccordionItem");
|
|
13
15
|
const BaseItem_1 = require("./BaseItem");
|
|
14
16
|
const GroupItem_1 = require("./GroupItem");
|
|
15
17
|
const GroupSelectItem_1 = require("./GroupSelectItem");
|
|
16
18
|
const NextListItem_1 = require("./NextListItem");
|
|
17
|
-
const
|
|
19
|
+
const utils_2 = require("./utils");
|
|
18
20
|
function useRenderItems(focusCloseChildIds) {
|
|
19
21
|
const {
|
|
20
22
|
focusFlattenItems,
|
|
@@ -35,27 +37,27 @@ function useRenderItems(focusCloseChildIds) {
|
|
|
35
37
|
items
|
|
36
38
|
} = focusFlattenItems[id];
|
|
37
39
|
const flattenItem = flattenItems[originalId];
|
|
38
|
-
if ((0,
|
|
40
|
+
if ((0, utils_2.isGroupItem)(flattenItem) || !isSelectionMultiple && (0, utils_2.isGroupSelectItem)(flattenItem)) {
|
|
39
41
|
return (0, react_1.createElement)(GroupItem_1.GroupItem, Object.assign({}, flattenItem, {
|
|
40
42
|
items: items,
|
|
41
43
|
key: key
|
|
42
44
|
}));
|
|
43
45
|
}
|
|
44
|
-
if ((0,
|
|
46
|
+
if ((0, utils_2.isGroupSelectItem)(flattenItem)) {
|
|
45
47
|
return (0, react_1.createElement)(GroupSelectItem_1.GroupSelectItem, Object.assign({}, flattenItem, {
|
|
46
48
|
items: items,
|
|
47
49
|
itemRef: itemRef,
|
|
48
50
|
key: key
|
|
49
51
|
}));
|
|
50
52
|
}
|
|
51
|
-
if ((0,
|
|
53
|
+
if ((0, utils_2.isAccordionItem)(flattenItem)) {
|
|
52
54
|
return (0, react_1.createElement)(AccordionItem_1.AccordionItem, Object.assign({}, flattenItem, {
|
|
53
55
|
items: items,
|
|
54
56
|
itemRef: itemRef,
|
|
55
57
|
key: key
|
|
56
58
|
}));
|
|
57
59
|
}
|
|
58
|
-
if ((0,
|
|
60
|
+
if ((0, utils_2.isNextListItem)(flattenItem)) {
|
|
59
61
|
return (0, react_1.createElement)(NextListItem_1.NextListItem, Object.assign({}, flattenItem, {
|
|
60
62
|
focusId: id,
|
|
61
63
|
items: items,
|
|
@@ -79,15 +81,15 @@ function useCreateBaseItems(_ref) {
|
|
|
79
81
|
return {
|
|
80
82
|
searchItem: {
|
|
81
83
|
itemRef: (0, react_2.createRef)(),
|
|
82
|
-
id:
|
|
83
|
-
parentId:
|
|
84
|
+
id: constants_1.ITEM_PREFIXES.search,
|
|
85
|
+
parentId: constants_1.ITEM_PREFIXES.default,
|
|
84
86
|
items: [],
|
|
85
87
|
allChildIds: []
|
|
86
88
|
},
|
|
87
89
|
footerItems: (_a = footerActiveElementsRefs === null || footerActiveElementsRefs === void 0 ? void 0 : footerActiveElementsRefs.map((itemRef, idx) => ({
|
|
88
|
-
id:
|
|
90
|
+
id: (0, utils_1.getFooterItemId)(idx),
|
|
89
91
|
itemRef,
|
|
90
|
-
parentId:
|
|
92
|
+
parentId: constants_1.ITEM_PREFIXES.default,
|
|
91
93
|
items: [],
|
|
92
94
|
allChildIds: []
|
|
93
95
|
}))) !== null && _a !== void 0 ? _a : []
|
|
@@ -21,6 +21,8 @@ exports.isContentItem = isContentItem;
|
|
|
21
21
|
exports.kindFlattenItems = kindFlattenItems;
|
|
22
22
|
exports.extractActiveItems = extractActiveItems;
|
|
23
23
|
const react_1 = require("react");
|
|
24
|
+
const constants_1 = require("../../constants");
|
|
25
|
+
const utils_1 = require("../../utils");
|
|
24
26
|
function isBaseItem(item) {
|
|
25
27
|
return item && !('items' in item);
|
|
26
28
|
}
|
|
@@ -56,10 +58,10 @@ function kindFlattenItems(_ref) {
|
|
|
56
58
|
item,
|
|
57
59
|
idx,
|
|
58
60
|
prefix,
|
|
59
|
-
parentId =
|
|
61
|
+
parentId = constants_1.ITEM_PREFIXES.default
|
|
60
62
|
} = _ref2;
|
|
61
63
|
var _a, _b;
|
|
62
|
-
const autoId = prefix !== undefined ?
|
|
64
|
+
const autoId = prefix !== undefined ? (0, utils_1.getItemAutoId)(prefix, idx) : String(idx);
|
|
63
65
|
const itemId = (_a = !isGroupItem(item) ? item.id : undefined) !== null && _a !== void 0 ? _a : autoId;
|
|
64
66
|
if (isBaseItem(item)) {
|
|
65
67
|
flattenItems[itemId] = Object.assign(Object.assign({}, item), {
|
|
@@ -92,7 +94,7 @@ function kindFlattenItems(_ref) {
|
|
|
92
94
|
items
|
|
93
95
|
} = item,
|
|
94
96
|
rest = __rest(item, ["items"]);
|
|
95
|
-
const childActiveParent = isGroupItem(item) ? parentId !== null && parentId !== void 0 ? parentId :
|
|
97
|
+
const childActiveParent = isGroupItem(item) ? parentId !== null && parentId !== void 0 ? parentId : constants_1.ITEM_PREFIXES.default : autoId;
|
|
96
98
|
const filteredItems = items.filter(item => !item.hidden);
|
|
97
99
|
for (let idx = 0; idx < filteredItems.length; idx++) {
|
|
98
100
|
const {
|
|
@@ -23,6 +23,7 @@ const merge_refs_1 = __importDefault(require("merge-refs"));
|
|
|
23
23
|
const react_1 = require("react");
|
|
24
24
|
const dropdown_1 = require("@snack-uikit/dropdown");
|
|
25
25
|
const utils_1 = require("@snack-uikit/utils");
|
|
26
|
+
const constants_1 = require("../../../constants");
|
|
26
27
|
const Items_1 = require("../../Items");
|
|
27
28
|
const contexts_1 = require("../contexts");
|
|
28
29
|
const hooks_1 = require("../hooks");
|
|
@@ -75,18 +76,18 @@ function Droplist(_a) {
|
|
|
75
76
|
const _b = (0, react_1.useMemo)(() => {
|
|
76
77
|
const pinTop = (0, Items_1.kindFlattenItems)({
|
|
77
78
|
items: pinTopProp,
|
|
78
|
-
prefix:
|
|
79
|
-
parentId:
|
|
79
|
+
prefix: constants_1.ITEM_PREFIXES.pinTop,
|
|
80
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
80
81
|
});
|
|
81
82
|
const items = (0, Items_1.kindFlattenItems)({
|
|
82
83
|
items: itemsProp,
|
|
83
|
-
prefix:
|
|
84
|
-
parentId:
|
|
84
|
+
prefix: constants_1.ITEM_PREFIXES.default,
|
|
85
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
85
86
|
});
|
|
86
87
|
const pinBottom = (0, Items_1.kindFlattenItems)({
|
|
87
88
|
items: pinBottomProp,
|
|
88
|
-
prefix:
|
|
89
|
-
parentId:
|
|
89
|
+
prefix: constants_1.ITEM_PREFIXES.pinBottom,
|
|
90
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
90
91
|
});
|
|
91
92
|
const flattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.flattenItems), pinBottom.flattenItems), items.flattenItems);
|
|
92
93
|
const focusFlattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.focusFlattenItems), pinBottom.focusFlattenItems), items.focusFlattenItems);
|
|
@@ -150,6 +151,7 @@ function Droplist(_a) {
|
|
|
150
151
|
}, [footerItems, hasSearch, memorizedItems, openCollapseItems, searchItem.id, selection === null || selection === void 0 ? void 0 : selection.mode]);
|
|
151
152
|
const triggerElemRef = (0, react_1.useRef)(null);
|
|
152
153
|
const listRef = (0, react_1.useRef)(null);
|
|
154
|
+
const firstItemId = ids[0];
|
|
153
155
|
const {
|
|
154
156
|
handleListKeyDownFactory,
|
|
155
157
|
resetActiveItemId,
|
|
@@ -157,7 +159,9 @@ function Droplist(_a) {
|
|
|
157
159
|
forceUpdateActiveItemId
|
|
158
160
|
} = (0, hooks_1.useNewKeyboardNavigation)({
|
|
159
161
|
mainRef: triggerElemRefProp !== null && triggerElemRefProp !== void 0 ? triggerElemRefProp : triggerElemRef,
|
|
160
|
-
focusFlattenItems
|
|
162
|
+
focusFlattenItems,
|
|
163
|
+
hasListInFocusChain: true,
|
|
164
|
+
firstItemId
|
|
161
165
|
});
|
|
162
166
|
const handleListKeyDown = (0, react_1.useCallback)(e => handleListKeyDownFactory(ids, expandedIds)(e), [handleListKeyDownFactory, ids, expandedIds]);
|
|
163
167
|
const handleOpenChange = (0, react_1.useCallback)(open => {
|
|
@@ -203,6 +207,7 @@ function Droplist(_a) {
|
|
|
203
207
|
contentRender: contentRender,
|
|
204
208
|
size: size,
|
|
205
209
|
marker: marker,
|
|
210
|
+
firstItemId: firstItemId,
|
|
206
211
|
children: (0, jsx_runtime_1.jsx)(contexts_1.SelectionProvider, Object.assign({}, selection, {
|
|
207
212
|
children: (0, jsx_runtime_1.jsx)(contexts_1.CollapseContext.Provider, {
|
|
208
213
|
value: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { KeyboardEvent } from 'react';
|
|
2
|
+
import { ItemId } from '../../Items';
|
|
2
3
|
export declare const List: import("react").ForwardRefExoticComponent<{
|
|
3
4
|
'data-test-id'?: string;
|
|
4
5
|
} & import("react").AriaAttributes & {
|
|
@@ -7,10 +8,15 @@ export declare const List: import("react").ForwardRefExoticComponent<{
|
|
|
7
8
|
pinBottom?: import("../../Items").Item[];
|
|
8
9
|
footer?: import("react").ReactNode;
|
|
9
10
|
footerActiveElementsRefs?: import("react").RefObject<HTMLElement>[];
|
|
11
|
+
keyboardNavigationRef?: import("react").RefObject<{
|
|
12
|
+
focusItem(id: ItemId): void;
|
|
13
|
+
}>;
|
|
10
14
|
search?: import("../../..").SearchState;
|
|
11
15
|
tabIndex?: number;
|
|
12
16
|
collapse?: import("../contexts").CollapseState;
|
|
13
17
|
className?: string;
|
|
14
|
-
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
15
18
|
loading?: boolean;
|
|
19
|
+
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
20
|
+
hasListInFocusChain?: boolean;
|
|
21
|
+
scrollToSelectedItem?: boolean;
|
|
16
22
|
} & import("../contexts").SelectionState & import("../contexts").PublicListContextType & import("../../../types").ScrollProps & import("../types").EmptyState & import("react").RefAttributes<HTMLElement>>;
|
|
@@ -22,6 +22,7 @@ const classnames_1 = __importDefault(require("classnames"));
|
|
|
22
22
|
const merge_refs_1 = __importDefault(require("merge-refs"));
|
|
23
23
|
const react_1 = require("react");
|
|
24
24
|
const utils_1 = require("@snack-uikit/utils");
|
|
25
|
+
const constants_1 = require("../../../constants");
|
|
25
26
|
const helperComponents_1 = require("../../../helperComponents");
|
|
26
27
|
const Items_1 = require("../../Items");
|
|
27
28
|
const contexts_1 = require("../contexts");
|
|
@@ -42,9 +43,11 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
42
43
|
selection,
|
|
43
44
|
contentRender,
|
|
44
45
|
size = 's',
|
|
45
|
-
marker = true
|
|
46
|
+
marker = true,
|
|
47
|
+
keyboardNavigationRef,
|
|
48
|
+
hasListInFocusChain = true
|
|
46
49
|
} = _a,
|
|
47
|
-
props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "onKeyDown", "tabIndex", "className", "collapse", "selection", "contentRender", "size", "marker"]);
|
|
50
|
+
props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "onKeyDown", "tabIndex", "className", "collapse", "selection", "contentRender", "size", "marker", "keyboardNavigationRef", "hasListInFocusChain"]);
|
|
48
51
|
const hasSearch = (0, react_1.useMemo)(() => Boolean(search), [search]);
|
|
49
52
|
const [openCollapseItems = [], setOpenCollapsedItems] = (0, utils_1.useValueControl)(collapse);
|
|
50
53
|
const toggleOpenCollapseItem = (0, react_1.useCallback)(id => setOpenCollapsedItems(items => (items === null || items === void 0 ? void 0 : items.includes(id)) ? items.filter(item => item !== id) : (items !== null && items !== void 0 ? items : []).concat([id])), [setOpenCollapsedItems]);
|
|
@@ -60,18 +63,18 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
60
63
|
const _b = (0, react_1.useMemo)(() => {
|
|
61
64
|
const pinTop = (0, Items_1.kindFlattenItems)({
|
|
62
65
|
items: pinTopProp,
|
|
63
|
-
prefix:
|
|
64
|
-
parentId:
|
|
66
|
+
prefix: constants_1.ITEM_PREFIXES.pinTop,
|
|
67
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
65
68
|
});
|
|
66
69
|
const items = (0, Items_1.kindFlattenItems)({
|
|
67
70
|
items: itemsProp,
|
|
68
|
-
prefix:
|
|
69
|
-
parentId:
|
|
71
|
+
prefix: constants_1.ITEM_PREFIXES.default,
|
|
72
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
70
73
|
});
|
|
71
74
|
const pinBottom = (0, Items_1.kindFlattenItems)({
|
|
72
75
|
items: pinBottomProp,
|
|
73
|
-
prefix:
|
|
74
|
-
parentId:
|
|
76
|
+
prefix: constants_1.ITEM_PREFIXES.pinBottom,
|
|
77
|
+
parentId: constants_1.ITEM_PREFIXES.default
|
|
75
78
|
});
|
|
76
79
|
const flattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.flattenItems), pinBottom.flattenItems), items.flattenItems);
|
|
77
80
|
const focusFlattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.focusFlattenItems), pinBottom.focusFlattenItems), items.focusFlattenItems);
|
|
@@ -135,6 +138,7 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
135
138
|
}, [footerItems, hasSearch, memorizedItems, openCollapseItems, searchItem.id, selection === null || selection === void 0 ? void 0 : selection.mode]);
|
|
136
139
|
const listRef = (0, react_1.useRef)(null);
|
|
137
140
|
const btnRef = (0, react_1.useRef)(null);
|
|
141
|
+
const firstItemId = ids[0];
|
|
138
142
|
const {
|
|
139
143
|
handleListKeyDownFactory,
|
|
140
144
|
activeItemId,
|
|
@@ -143,7 +147,10 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
143
147
|
} = (0, hooks_1.useNewKeyboardNavigation)({
|
|
144
148
|
mainRef: listRef,
|
|
145
149
|
btnRef,
|
|
146
|
-
focusFlattenItems
|
|
150
|
+
focusFlattenItems,
|
|
151
|
+
keyboardNavigationRef,
|
|
152
|
+
hasListInFocusChain,
|
|
153
|
+
firstItemId
|
|
147
154
|
});
|
|
148
155
|
const handleListKeyDown = (0, react_1.useCallback)(e => handleListKeyDownFactory(ids, expandedIds)(e), [handleListKeyDownFactory, ids, expandedIds]);
|
|
149
156
|
const isActive = (0, utils_1.isBrowser)() && listRef.current === document.activeElement && activeItemId === undefined;
|
|
@@ -160,6 +167,7 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
160
167
|
contentRender: contentRender,
|
|
161
168
|
size: size,
|
|
162
169
|
marker: marker,
|
|
170
|
+
firstItemId: firstItemId,
|
|
163
171
|
children: (0, jsx_runtime_1.jsx)(contexts_1.SelectionProvider, Object.assign({}, selection, {
|
|
164
172
|
children: (0, jsx_runtime_1.jsx)(contexts_1.CollapseContext.Provider, {
|
|
165
173
|
value: {
|
|
@@ -183,10 +191,10 @@ exports.List = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
183
191
|
ref: (0, merge_refs_1.default)(ref, listRef),
|
|
184
192
|
onFocus: handleOnFocus,
|
|
185
193
|
onKeyDown: mergedHandlerKeyDown,
|
|
186
|
-
tabIndex: tabIndex,
|
|
194
|
+
tabIndex: hasListInFocusChain ? tabIndex : undefined,
|
|
187
195
|
search: search,
|
|
188
196
|
nested: false
|
|
189
|
-
})), (0, jsx_runtime_1.jsx)(helperComponents_1.HiddenTabButton, {
|
|
197
|
+
})), hasListInFocusChain && (0, jsx_runtime_1.jsx)(helperComponents_1.HiddenTabButton, {
|
|
190
198
|
ref: btnRef,
|
|
191
199
|
listRef: listRef,
|
|
192
200
|
tabIndex: tabIndex
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { FlattenBaseItem } from '../../Items';
|
|
2
|
+
export declare const ListPrivate: import("react").ForwardRefExoticComponent<Omit<import("../types").ListProps, "items" | "hasListInFocusChain" | "pinTop" | "pinBottom"> & {
|
|
2
3
|
nested?: boolean;
|
|
3
4
|
active?: boolean;
|
|
4
5
|
tabIndex?: number;
|
|
@@ -6,7 +7,7 @@ export declare const ListPrivate: import("react").ForwardRefExoticComponent<Omit
|
|
|
6
7
|
onBlur?(e: import("react").FocusEvent<HTMLElement>): void;
|
|
7
8
|
onKeyDown?(e: import("react").KeyboardEvent<HTMLElement>): void;
|
|
8
9
|
limitedScrollHeight?: boolean;
|
|
9
|
-
searchItem?:
|
|
10
|
+
searchItem?: FlattenBaseItem;
|
|
10
11
|
pinTop?: import("../../Items").ItemId[];
|
|
11
12
|
items: import("../../Items").ItemId[];
|
|
12
13
|
pinBottom?: import("../../Items").ItemId[];
|
|
@@ -54,12 +54,19 @@ exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
54
54
|
noResultsState,
|
|
55
55
|
errorDataState,
|
|
56
56
|
dataError,
|
|
57
|
-
dataFiltered
|
|
57
|
+
dataFiltered,
|
|
58
|
+
scrollToSelectedItem
|
|
58
59
|
} = _a,
|
|
59
|
-
props = __rest(_a, ["items", "pinTop", "pinBottom", "onKeyDown", "onBlur", "onFocus", "tabIndex", "active", "scroll", "nested", "search", "searchItem", "scrollRef", "scrollContainerRef", "onScroll", "footer", "loading", "limitedScrollHeight", "untouchableScrollbars", "className", "noDataState", "noResultsState", "errorDataState", "dataError", "dataFiltered"]);
|
|
60
|
+
props = __rest(_a, ["items", "pinTop", "pinBottom", "onKeyDown", "onBlur", "onFocus", "tabIndex", "active", "scroll", "nested", "search", "searchItem", "scrollRef", "scrollContainerRef", "onScroll", "footer", "loading", "limitedScrollHeight", "untouchableScrollbars", "className", "noDataState", "noResultsState", "errorDataState", "dataError", "dataFiltered", "scrollToSelectedItem"]);
|
|
60
61
|
const {
|
|
61
|
-
size = 's'
|
|
62
|
+
size = 's',
|
|
63
|
+
flattenItems
|
|
62
64
|
} = (0, contexts_1.useNewListContext)();
|
|
65
|
+
const {
|
|
66
|
+
value,
|
|
67
|
+
isSelectionSingle
|
|
68
|
+
} = (0, contexts_1.useSelectionContext)();
|
|
69
|
+
const selectedItem = isSelectionSingle && value ? flattenItems[value] : undefined;
|
|
63
70
|
const itemsJSX = (0, Items_1.useRenderItems)(items);
|
|
64
71
|
const itemsPinTopJSX = (0, Items_1.useRenderItems)(pinTop);
|
|
65
72
|
const itemsPinBottomJSX = (0, Items_1.useRenderItems)(pinBottom);
|
|
@@ -90,6 +97,12 @@ exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
90
97
|
dataFiltered: dataFiltered !== null && dataFiltered !== void 0 ? dataFiltered : Boolean(search === null || search === void 0 ? void 0 : search.value)
|
|
91
98
|
})]
|
|
92
99
|
}), [dataError, dataFiltered, emptyStates, hasNoItems, itemsJSX, loading, loadingJSX, search === null || search === void 0 ? void 0 : search.value]);
|
|
100
|
+
const onScrollInitialized = () => {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
if (scrollToSelectedItem) {
|
|
103
|
+
(_b = (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.itemRef) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.scrollIntoView();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
93
106
|
const listJSX = (0, jsx_runtime_1.jsxs)("ul", Object.assign({
|
|
94
107
|
className: (0, classnames_1.default)(styles_module_scss_1.default.listContainer, className),
|
|
95
108
|
ref: ref,
|
|
@@ -115,6 +128,7 @@ exports.ListPrivate = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
115
128
|
ref: scrollContainerRef,
|
|
116
129
|
untouchableScrollbars: untouchableScrollbars,
|
|
117
130
|
onScroll: onScroll,
|
|
131
|
+
onInitialized: onScrollInitialized,
|
|
118
132
|
children: [content, (0, jsx_runtime_1.jsx)("div", {
|
|
119
133
|
className: styles_module_scss_2.default.scrollStub,
|
|
120
134
|
ref: scrollRef
|
|
@@ -19,15 +19,13 @@ export type PublicListContextType = {
|
|
|
19
19
|
export type PrivateListContextType = {
|
|
20
20
|
flattenItems: Record<string, FlattenItem>;
|
|
21
21
|
focusFlattenItems: Record<string, FocusFlattenItem>;
|
|
22
|
+
firstItemId: ItemId;
|
|
22
23
|
};
|
|
23
24
|
type Child = {
|
|
24
25
|
children: ReactNode;
|
|
25
26
|
};
|
|
26
27
|
type ListContextType = PublicListContextType & PrivateListContextType;
|
|
27
|
-
export declare const ListContext: import("react").Context<
|
|
28
|
-
flattenItems: {};
|
|
29
|
-
focusFlattenItems: {};
|
|
30
|
-
}>;
|
|
28
|
+
export declare const ListContext: import("react").Context<ListContextType>;
|
|
31
29
|
export declare function useNewListContext(): ListContextType;
|
|
32
30
|
export declare function NewListContextProvider({ children, ...props }: ListContextType & Child): import("react/jsx-runtime").JSX.Element;
|
|
33
31
|
export {};
|
|
@@ -16,9 +16,11 @@ exports.useNewListContext = useNewListContext;
|
|
|
16
16
|
exports.NewListContextProvider = NewListContextProvider;
|
|
17
17
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
18
18
|
const react_1 = require("react");
|
|
19
|
+
const constants_1 = require("../../../constants");
|
|
19
20
|
exports.ListContext = (0, react_1.createContext)({
|
|
20
21
|
flattenItems: {},
|
|
21
|
-
focusFlattenItems: {}
|
|
22
|
+
focusFlattenItems: {},
|
|
23
|
+
firstItemId: constants_1.ITEM_PREFIXES.default
|
|
22
24
|
});
|
|
23
25
|
function useNewListContext() {
|
|
24
26
|
return (0, react_1.useContext)(exports.ListContext);
|
|
@@ -29,14 +31,16 @@ function extractListProps(_ref) {
|
|
|
29
31
|
marker,
|
|
30
32
|
flattenItems,
|
|
31
33
|
focusFlattenItems,
|
|
32
|
-
contentRender
|
|
34
|
+
contentRender,
|
|
35
|
+
firstItemId
|
|
33
36
|
} = _ref;
|
|
34
37
|
return {
|
|
35
38
|
size,
|
|
36
39
|
marker,
|
|
37
40
|
contentRender,
|
|
38
41
|
flattenItems,
|
|
39
|
-
focusFlattenItems
|
|
42
|
+
focusFlattenItems,
|
|
43
|
+
firstItemId
|
|
40
44
|
};
|
|
41
45
|
}
|
|
42
46
|
function NewListContextProvider(_a) {
|
|
@@ -4,8 +4,13 @@ type UseNewKeyboardNavigationProps<T extends HTMLElement> = {
|
|
|
4
4
|
mainRef?: RefObject<T>;
|
|
5
5
|
btnRef?: RefObject<HTMLButtonElement>;
|
|
6
6
|
focusFlattenItems: Record<string, FocusFlattenItem>;
|
|
7
|
+
keyboardNavigationRef?: RefObject<{
|
|
8
|
+
focusItem(item: ItemId): void;
|
|
9
|
+
}>;
|
|
10
|
+
hasListInFocusChain: boolean;
|
|
11
|
+
firstItemId: ItemId;
|
|
7
12
|
};
|
|
8
|
-
export declare function useNewKeyboardNavigation<T extends HTMLElement>({ mainRef, btnRef, focusFlattenItems, }: UseNewKeyboardNavigationProps<T>): {
|
|
13
|
+
export declare function useNewKeyboardNavigation<T extends HTMLElement>({ mainRef, btnRef, focusFlattenItems, keyboardNavigationRef, hasListInFocusChain, firstItemId, }: UseNewKeyboardNavigationProps<T>): {
|
|
9
14
|
resetActiveItemId: () => void;
|
|
10
15
|
activeItemId: ItemId | undefined;
|
|
11
16
|
forceUpdateActiveItemId: (itemId: ItemId) => void;
|
|
@@ -5,14 +5,23 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.useNewKeyboardNavigation = useNewKeyboardNavigation;
|
|
7
7
|
const react_1 = require("react");
|
|
8
|
+
const constants_1 = require("../../constants");
|
|
8
9
|
function useNewKeyboardNavigation(_ref) {
|
|
9
10
|
let {
|
|
10
11
|
mainRef,
|
|
11
12
|
btnRef,
|
|
12
|
-
focusFlattenItems
|
|
13
|
+
focusFlattenItems,
|
|
14
|
+
keyboardNavigationRef,
|
|
15
|
+
hasListInFocusChain,
|
|
16
|
+
firstItemId
|
|
13
17
|
} = _ref;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
18
|
+
const defaultActiveItemId = hasListInFocusChain ? undefined : firstItemId;
|
|
19
|
+
const [activeItemId, setActiveItemId] = (0, react_1.useState)(() => defaultActiveItemId);
|
|
20
|
+
const activeItemIdRef = (0, react_1.useRef)(defaultActiveItemId);
|
|
21
|
+
const resetActiveItemId = (0, react_1.useCallback)(() => {
|
|
22
|
+
setActiveItemId(defaultActiveItemId);
|
|
23
|
+
activeItemIdRef.current = defaultActiveItemId;
|
|
24
|
+
}, [defaultActiveItemId]);
|
|
16
25
|
const handleListKeyDownFactory = (0, react_1.useCallback)((ids, expandedIds) => e => {
|
|
17
26
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
18
27
|
switch (e.key) {
|
|
@@ -44,11 +53,13 @@ function useNewKeyboardNavigation(_ref) {
|
|
|
44
53
|
case 'ArrowUp':
|
|
45
54
|
{
|
|
46
55
|
if (ids[0] === activeItemIdRef.current) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
if (hasListInFocusChain) {
|
|
57
|
+
const item = focusFlattenItems[ids[0]];
|
|
58
|
+
if (item.parentId === constants_1.ITEM_PREFIXES.default) {
|
|
59
|
+
activeItemIdRef.current = undefined;
|
|
60
|
+
setActiveItemId(undefined);
|
|
61
|
+
(_e = mainRef === null || mainRef === void 0 ? void 0 : mainRef.current) === null || _e === void 0 ? void 0 : _e.focus();
|
|
62
|
+
}
|
|
52
63
|
}
|
|
53
64
|
} else if (activeItemIdRef.current !== undefined) {
|
|
54
65
|
const activeIndex = ids.findIndex(id => id === activeItemIdRef.current);
|
|
@@ -85,11 +96,15 @@ function useNewKeyboardNavigation(_ref) {
|
|
|
85
96
|
case 'Tab':
|
|
86
97
|
{
|
|
87
98
|
if (activeItemIdRef.current !== undefined) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
if (hasListInFocusChain) {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
e.stopPropagation();
|
|
102
|
+
activeItemIdRef.current = undefined;
|
|
103
|
+
setActiveItemId(undefined);
|
|
104
|
+
(_h = mainRef === null || mainRef === void 0 ? void 0 : mainRef.current) === null || _h === void 0 ? void 0 : _h.focus();
|
|
105
|
+
} else {
|
|
106
|
+
resetActiveItemId();
|
|
107
|
+
}
|
|
93
108
|
} else {
|
|
94
109
|
btnRef && !e.shiftKey ? (_j = btnRef === null || btnRef === void 0 ? void 0 : btnRef.current) === null || _j === void 0 ? void 0 : _j.focus() : (_k = mainRef === null || mainRef === void 0 ? void 0 : mainRef.current) === null || _k === void 0 ? void 0 : _k.focus();
|
|
95
110
|
}
|
|
@@ -100,11 +115,7 @@ function useNewKeyboardNavigation(_ref) {
|
|
|
100
115
|
return;
|
|
101
116
|
}
|
|
102
117
|
}
|
|
103
|
-
}, [focusFlattenItems, mainRef, btnRef]);
|
|
104
|
-
const resetActiveItemId = (0, react_1.useCallback)(() => {
|
|
105
|
-
setActiveItemId(undefined);
|
|
106
|
-
activeItemIdRef.current = undefined;
|
|
107
|
-
}, []);
|
|
118
|
+
}, [focusFlattenItems, hasListInFocusChain, mainRef, resetActiveItemId, btnRef]);
|
|
108
119
|
const forceUpdateActiveItemId = (0, react_1.useCallback)(itemId => {
|
|
109
120
|
var _a, _b;
|
|
110
121
|
setActiveItemId(itemId);
|
|
@@ -112,6 +123,9 @@ function useNewKeyboardNavigation(_ref) {
|
|
|
112
123
|
const item = focusFlattenItems[itemId];
|
|
113
124
|
(_b = (_a = item === null || item === void 0 ? void 0 : item.itemRef) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.focus();
|
|
114
125
|
}, [focusFlattenItems]);
|
|
126
|
+
(0, react_1.useImperativeHandle)(keyboardNavigationRef, () => ({
|
|
127
|
+
focusItem: forceUpdateActiveItemId
|
|
128
|
+
}), [forceUpdateActiveItemId]);
|
|
115
129
|
return {
|
|
116
130
|
resetActiveItemId,
|
|
117
131
|
activeItemId,
|