@snack-uikit/list 0.2.2-preview-0cc330d4.0 → 0.3.1-preview-744f94d0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/components/Items/AccordionItem/AccordionItem.js +1 -1
- package/dist/components/Items/BaseItem/BaseItem.js +2 -2
- package/dist/components/Items/BaseItem/styles.module.css +13 -2
- package/dist/components/Items/NextListItem/NextListItem.js +12 -12
- package/dist/components/Items/NextListItem/hooks.d.ts +2 -2
- package/dist/components/Items/types.d.ts +5 -5
- package/dist/components/Lists/Droplist/DropList.js +1 -1
- package/dist/components/Lists/List/List.js +1 -1
- package/dist/components/Lists/ListPrivate/ListPrivate.d.ts +1 -1
- package/dist/components/Lists/ListPrivate/ListPrivate.js +2 -2
- package/dist/components/Lists/ListPrivate/styles.module.css +0 -3
- package/dist/components/Lists/contexts/ListProvider.d.ts +6 -3
- package/dist/components/Lists/contexts/ListProvider.js +2 -2
- package/dist/components/Lists/contexts/ParentListProvider.d.ts +1 -1
- package/dist/components/Lists/hooks.d.ts +1 -1
- package/dist/components/Lists/types.d.ts +2 -2
- package/dist/utils.d.ts +2 -2
- package/package.json +2 -2
- package/src/components/Items/AccordionItem/AccordionItem.tsx +21 -23
- package/src/components/Items/BaseItem/BaseItem.tsx +61 -60
- package/src/components/Items/BaseItem/styles.module.scss +10 -0
- package/src/components/Items/NextListItem/NextListItem.tsx +48 -50
- package/src/components/Items/NextListItem/hooks.ts +2 -2
- package/src/components/Items/types.ts +5 -5
- package/src/components/Items/utils.ts +2 -2
- package/src/components/Lists/Droplist/DropList.tsx +3 -2
- package/src/components/Lists/List/List.tsx +3 -2
- package/src/components/Lists/ListPrivate/ListPrivate.tsx +2 -1
- package/src/components/Lists/ListPrivate/styles.module.scss +0 -4
- package/src/components/Lists/contexts/ListProvider.tsx +8 -4
- package/src/components/Lists/contexts/ParentListProvider.tsx +1 -1
- package/src/components/Lists/hooks.ts +1 -1
- package/src/components/Lists/types.ts +11 -10
- package/src/utils.ts +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 0.3.0 (2024-02-07)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **FF-4241:** add itemWrapRender ([4efb798](https://github.com/cloud-ru-tech/snack-uikit/commit/4efb79897b8ef129e89bf62a9332b93d79648bbf))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## 0.2.1 (2024-02-05)
|
|
7
18
|
|
|
8
19
|
### Only dependencies have been changed
|
|
@@ -37,5 +37,5 @@ export function AccordionItem(_a) {
|
|
|
37
37
|
toggleOpenCollapsedItems === null || toggleOpenCollapsedItems === void 0 ? void 0 : toggleOpenCollapsedItems(id !== null && id !== void 0 ? id : '');
|
|
38
38
|
(_a = option.onClick) === null || _a === void 0 ? void 0 : _a.call(option, e);
|
|
39
39
|
};
|
|
40
|
-
return (_jsx(
|
|
40
|
+
return (_jsx(CollapseBlockPrivate, { header: _jsx(BaseItem, Object.assign({}, option, { id: id, disabled: disabled, expandIcon: open ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}), onClick: handleItemClick, isParentNode: true, onKeyDown: handleKeyDown, indeterminate: isIndeterminate && !checked, onSelect: !disabled ? handleOnSelect : undefined })), expanded: open, "data-test-id": `list__accordion-item-${id}`, children: _jsx(CollapseContext.Provider, { value: { level: level + 1 }, children: itemsJSX }) }));
|
|
41
41
|
}
|
|
@@ -23,7 +23,7 @@ export function BaseItem(_a) {
|
|
|
23
23
|
const { option, caption, description } = content || {};
|
|
24
24
|
const interactive = !inactive;
|
|
25
25
|
const { parentResetActiveFocusIndex } = useParentListContext();
|
|
26
|
-
const { size, marker } = useListContext();
|
|
26
|
+
const { size, marker, parent } = useListContext();
|
|
27
27
|
const { level = 0 } = useCollapseContext();
|
|
28
28
|
const { value, onChange, mode, isSelectionSingle, isSelectionMultiple } = useSelectionContext();
|
|
29
29
|
const isChecked = isSelectionSingle ? value === id : value === null || value === void 0 ? void 0 : value.includes(id);
|
|
@@ -68,7 +68,7 @@ export function BaseItem(_a) {
|
|
|
68
68
|
e.stopPropagation();
|
|
69
69
|
};
|
|
70
70
|
const props = extractSupportProps(rest);
|
|
71
|
-
const item = (
|
|
71
|
+
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 })] }));
|
|
72
72
|
if (!itemWrapRender) {
|
|
73
73
|
return item;
|
|
74
74
|
}
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
.content{
|
|
75
|
+
overflow:hidden;
|
|
75
76
|
flex-grow:1;
|
|
76
77
|
flex-shrink:1;
|
|
77
78
|
box-sizing:border-box;
|
|
@@ -170,16 +171,26 @@
|
|
|
170
171
|
letter-spacing:var(--sans-body-m-letter-spacing, 0.1px);
|
|
171
172
|
paragraph-spacing:var(--sans-body-m-paragraph-spacing, 7.7px);
|
|
172
173
|
}
|
|
174
|
+
.droplistItem[data-parent=list]{
|
|
175
|
+
width:100%;
|
|
176
|
+
}
|
|
177
|
+
.droplistItem[data-parent=droplist]{
|
|
178
|
+
width:-moz-max-content;
|
|
179
|
+
width:max-content;
|
|
180
|
+
}
|
|
173
181
|
.droplistItem[data-non-pointer]{
|
|
174
182
|
cursor:inherit;
|
|
175
183
|
}
|
|
176
|
-
.droplistItem
|
|
184
|
+
.droplistItem[aria-disabled] .option,
|
|
185
|
+
.droplistItem[aria-disabled] .description,
|
|
186
|
+
.droplistItem[aria-disabled] .caption,
|
|
187
|
+
.droplistItem[aria-disabled] .expandableIcon, .droplistItem:disabled .option,
|
|
177
188
|
.droplistItem:disabled .description,
|
|
178
189
|
.droplistItem:disabled .caption,
|
|
179
190
|
.droplistItem:disabled .expandableIcon{
|
|
180
191
|
color:var(--sys-neutral-text-disabled, #9e9e9e);
|
|
181
192
|
}
|
|
182
|
-
.droplistItem:disabled .beforeContent{
|
|
193
|
+
.droplistItem[aria-disabled] .beforeContent, .droplistItem:disabled .beforeContent{
|
|
183
194
|
opacity:var(--opacity-a064, 0.64);
|
|
184
195
|
}
|
|
185
196
|
.droplistItem[data-has-checked][data-variant=single]::after, .droplistItem[data-checked][data-variant=single]::after{
|
|
@@ -51,16 +51,16 @@ export function NextListItem(_a) {
|
|
|
51
51
|
parentResetActiveFocusIndex === null || parentResetActiveFocusIndex === void 0 ? void 0 : parentResetActiveFocusIndex();
|
|
52
52
|
return true;
|
|
53
53
|
}, [parentResetActiveFocusIndex, parentResetNestedIndex]);
|
|
54
|
-
return (_jsx(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
return (_jsx(Dropdown, { outsideClick: handleOutsideClick, fallbackPlacements: FALLBACK_PLACEMENTS, content: _jsx(ParentListContext.Provider, { value: {
|
|
55
|
+
parentIds: ids,
|
|
56
|
+
parentActiveFocusIndex: activeFocusIndex,
|
|
57
|
+
parentExpandedIds: expandedIds,
|
|
58
|
+
parentItemRefs: itemRefs,
|
|
59
|
+
parentOpenNestedIndex: openNestedIndex,
|
|
60
|
+
triggerRef,
|
|
61
|
+
parentRef: listRef,
|
|
62
|
+
parentResetNestedIndex: resetNestedIndex,
|
|
63
|
+
parentResetActiveFocusIndex: resetActiveFocusIndex,
|
|
64
|
+
toggleOpenCollapsedItems: id => setOpenCollapsedItems(items => items.includes(id) ? items.filter(item => item !== id) : items.concat([id])),
|
|
65
|
+
}, children: _jsx(ListPrivate, { onKeyDown: handleListKeyDown, items: items, nested: true, search: search, scroll: scroll, scrollRef: scrollRef, limitedScrollHeight: true }) }), trigger: 'hover', open: (open || parentIds[parentOpenNestedIndex] === id) && !disabled, onOpenChange: handleOpenChange, placement: placement, children: _jsx(BaseItem, Object.assign({}, option, { disabled: disabled, open: open, expandIcon: _jsx(ChevronRightSVG, {}), id: id, isParentNode: true, indeterminate: isIndeterminate && !checked, onSelect: handleOnSelect })) }));
|
|
66
66
|
}
|
|
@@ -2,7 +2,7 @@ import { KeyboardEvent, RefObject } from 'react';
|
|
|
2
2
|
type UseKeyboardNavigationProps = {
|
|
3
3
|
ids: Array<number | string>;
|
|
4
4
|
expandedIds: Array<number | string>;
|
|
5
|
-
itemRefs?: RefObject<
|
|
5
|
+
itemRefs?: RefObject<HTMLElement>[];
|
|
6
6
|
id?: string | number;
|
|
7
7
|
};
|
|
8
8
|
export declare function useKeyboardNavigation({ ids, expandedIds, itemRefs, id }: UseKeyboardNavigationProps): {
|
|
@@ -12,7 +12,7 @@ export declare function useKeyboardNavigation({ ids, expandedIds, itemRefs, id }
|
|
|
12
12
|
setOpenNestedIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
13
13
|
resetNestedIndex: () => void;
|
|
14
14
|
resetActiveFocusIndex: () => void;
|
|
15
|
-
handleListKeyDown: (e: KeyboardEvent<
|
|
15
|
+
handleListKeyDown: (e: KeyboardEvent<HTMLElement>) => void;
|
|
16
16
|
open: boolean;
|
|
17
17
|
setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
18
18
|
};
|
|
@@ -25,18 +25,18 @@ export type BaseItemProps = WithSupportProps<{
|
|
|
25
25
|
/** Основной контент айтема */
|
|
26
26
|
content: ItemContentProps;
|
|
27
27
|
/** Колбек обработки клика */
|
|
28
|
-
onClick?(e: MouseEvent<
|
|
28
|
+
onClick?(e: MouseEvent<HTMLElement>): void;
|
|
29
29
|
/** Колбек обработки нажатия клавиши */
|
|
30
|
-
onKeyDown?(e: KeyboardEvent<
|
|
30
|
+
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
31
31
|
/** Колбек обработки фокуса */
|
|
32
|
-
onFocus?(e: FocusEvent<
|
|
32
|
+
onFocus?(e: FocusEvent<HTMLElement>): void;
|
|
33
33
|
/** Колбек обработки блюра */
|
|
34
|
-
onBlur?(e: FocusEvent<
|
|
34
|
+
onBlur?(e: FocusEvent<HTMLElement>): void;
|
|
35
35
|
/** Уникальный идентификатор */
|
|
36
36
|
id?: string | number;
|
|
37
37
|
/** Флаг неактивности элемента */
|
|
38
38
|
disabled?: boolean;
|
|
39
|
-
itemRef?: RefObject<
|
|
39
|
+
itemRef?: RefObject<HTMLElement>;
|
|
40
40
|
className?: string;
|
|
41
41
|
/**
|
|
42
42
|
* Флаг отображения отключения реакции на любое css состояние (hover/focus и тд)
|
|
@@ -95,7 +95,7 @@ export function Droplist(_a) {
|
|
|
95
95
|
parentResetNestedIndex: resetNestedIndex,
|
|
96
96
|
parentResetActiveFocusIndex: resetActiveFocusIndex,
|
|
97
97
|
toggleOpenCollapsedItems: id => setOpenCollapsedItems((items = []) => items.includes(id) ? items.filter(item => item !== id) : items === null || items === void 0 ? void 0 : items.concat([id])),
|
|
98
|
-
}, children: _jsx(Dropdown, Object.assign({ content: _jsx(ListPrivate, Object.assign({ onKeyDown: handleListKeyDown, tabIndex: 0, ref: listRef, search: search, limitedScrollHeight: true
|
|
98
|
+
}, 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
99
|
? {}
|
|
100
100
|
: {
|
|
101
101
|
triggerRef: triggerElemRef,
|
|
@@ -87,5 +87,5 @@ export const List = forwardRef((_a, ref) => {
|
|
|
87
87
|
parentResetActiveFocusIndex: resetActiveFocusIndex,
|
|
88
88
|
openCollapsedItems,
|
|
89
89
|
toggleOpenCollapsedItems: id => setOpenCollapsedItems((items = []) => items.includes(id) ? items.filter(item => item !== id) : items === null || items === void 0 ? void 0 : items.concat([id])),
|
|
90
|
-
}, children: _jsxs("div", { className: cn(styles.wrapper, className), "data-active": isActive || undefined, children: [_jsx(ListPrivate, Object.assign({}, props, slicedItems, { ref: mergeRefs(ref, listRef), onFocus: handleOnFocus, onKeyDown: mergedHandlerKeyDown, tabIndex: tabIndex, search: search, nested: false })), _jsx(HiddenTabButton, { ref: btnRef, listRef: listRef, tabIndex: tabIndex })] }) }) })));
|
|
90
|
+
}, children: _jsxs("div", { className: cn(styles.wrapper, className), "data-active": isActive || undefined, children: [_jsx(ListPrivate, Object.assign({}, props, slicedItems, { ref: mergeRefs(ref, listRef), onFocus: handleOnFocus, onKeyDown: mergedHandlerKeyDown, tabIndex: tabIndex, search: search, nested: false, parent: 'list' })), _jsx(HiddenTabButton, { ref: btnRef, listRef: listRef, tabIndex: tabIndex })] }) }) })));
|
|
91
91
|
});
|
|
@@ -19,7 +19,7 @@ export declare const ListPrivate: import("react").ForwardRefExoticComponent<{
|
|
|
19
19
|
} | undefined;
|
|
20
20
|
className?: string | undefined;
|
|
21
21
|
onKeyDown?(e: import("react").KeyboardEvent<HTMLElement>): void;
|
|
22
|
-
} & import("../contexts").SelectionState & import("../contexts").ListContextType & import("../../../types").ScrollProps & {
|
|
22
|
+
} & import("../contexts").SelectionState & import("../contexts").ListContextType & import("../../../types").ScrollProps & import("../contexts").ListContextPrivateType & {
|
|
23
23
|
nested?: boolean | undefined;
|
|
24
24
|
active?: boolean | undefined;
|
|
25
25
|
tabIndex?: number | undefined;
|
|
@@ -22,7 +22,7 @@ import commonStyles from '../styles.module.css';
|
|
|
22
22
|
import styles from './styles.module.css';
|
|
23
23
|
export const ListPrivate = forwardRef((_a, ref) => {
|
|
24
24
|
var _b, _c;
|
|
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 } = _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"]);
|
|
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"]);
|
|
26
26
|
const itemsJSX = useRenderItems(items);
|
|
27
27
|
const itemsPinTopJSX = useRenderItems(pinTop !== null && pinTop !== void 0 ? pinTop : []);
|
|
28
28
|
const itemsPinBottomJSX = useRenderItems(pinBottom !== null && pinBottom !== void 0 ? pinBottom : []);
|
|
@@ -35,7 +35,7 @@ export const ListPrivate = forwardRef((_a, ref) => {
|
|
|
35
35
|
[commonStyles.scrollContainerL]: scroll && limitedScrollHeight && size === 'l',
|
|
36
36
|
}), barHideStrategy: 'leave', 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 || footer) && (_jsxs(PinBottomGroupItem, { children: [Number(pinBottom === null || pinBottom === void 0 ? void 0 : pinBottom.length) > 0 && itemsPinBottomJSX, footer && _jsx("div", { className: styles.footer, children: footer })] }))] }) })));
|
|
37
37
|
if (!nested) {
|
|
38
|
-
return (_jsx(ListContextProvider, { size: size, marker: marker, children: listJSX }));
|
|
38
|
+
return (_jsx(ListContextProvider, { size: size, marker: marker, parent: parent, children: listJSX }));
|
|
39
39
|
}
|
|
40
40
|
return (_jsx("li", { style: { listStyleType: 'none' }, role: 'menuitem', children: listJSX }));
|
|
41
41
|
});
|
|
@@ -5,10 +5,13 @@ export type ListContextType = {
|
|
|
5
5
|
/** Отображать ли маркер у выбранного жлемента списка */
|
|
6
6
|
marker?: boolean;
|
|
7
7
|
};
|
|
8
|
+
export type ListContextPrivateType = {
|
|
9
|
+
parent?: 'list' | 'droplist';
|
|
10
|
+
};
|
|
8
11
|
type Child = {
|
|
9
12
|
children: ReactNode;
|
|
10
13
|
};
|
|
11
|
-
export declare const ListContext: import("react").Context<ListContextType>;
|
|
12
|
-
export declare const useListContext: () => ListContextType;
|
|
13
|
-
export declare function ListContextProvider({ children, ...props }: ListContextType & Child): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const ListContext: import("react").Context<ListContextType & ListContextPrivateType>;
|
|
15
|
+
export declare const useListContext: () => ListContextType & ListContextPrivateType;
|
|
16
|
+
export declare function ListContextProvider({ children, ...props }: ListContextType & Child & ListContextPrivateType): import("react/jsx-runtime").JSX.Element;
|
|
14
17
|
export {};
|
|
@@ -13,8 +13,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
13
13
|
import { createContext, useContext } from 'react';
|
|
14
14
|
export const ListContext = createContext({});
|
|
15
15
|
export const useListContext = () => useContext(ListContext);
|
|
16
|
-
function extractListProps({ size, marker }) {
|
|
17
|
-
return { size, marker };
|
|
16
|
+
function extractListProps({ size, marker, parent }) {
|
|
17
|
+
return { size, marker, parent };
|
|
18
18
|
}
|
|
19
19
|
export function ListContextProvider(_a) {
|
|
20
20
|
var { children } = _a, props = __rest(_a, ["children"]);
|
|
@@ -5,7 +5,7 @@ export type ParentListContextType = {
|
|
|
5
5
|
parentResetActiveFocusIndex?(): void;
|
|
6
6
|
parentIds: Array<string | number>;
|
|
7
7
|
parentExpandedIds: Array<string | number>;
|
|
8
|
-
parentItemRefs: Array<RefObject<
|
|
8
|
+
parentItemRefs: Array<RefObject<HTMLElement>>;
|
|
9
9
|
parentOpenNestedIndex: number;
|
|
10
10
|
parentResetNestedIndex?(): void;
|
|
11
11
|
openCollapsedItems?: Array<string | number>;
|
|
@@ -4,7 +4,7 @@ export type UseKeyboardNavigationProps<T extends HTMLElement> = {
|
|
|
4
4
|
expandedIds: Array<number | string>;
|
|
5
5
|
parentRef?: RefObject<T>;
|
|
6
6
|
btnRef?: RefObject<HTMLButtonElement>;
|
|
7
|
-
itemRefs?: RefObject<
|
|
7
|
+
itemRefs?: RefObject<HTMLElement>[];
|
|
8
8
|
};
|
|
9
9
|
export declare function useKeyboardNavigation<T extends HTMLElement>({ ids, itemRefs, expandedIds, parentRef, btnRef, }: UseKeyboardNavigationProps<T>): {
|
|
10
10
|
activeFocusIndex: number;
|
|
@@ -3,7 +3,7 @@ import { DropdownProps } from '@snack-uikit/dropdown';
|
|
|
3
3
|
import { WithSupportProps } from '@snack-uikit/utils';
|
|
4
4
|
import { ScrollProps, SearchState } from '../../types';
|
|
5
5
|
import { ItemProps } from '../Items';
|
|
6
|
-
import { ListContextType, SelectionState } from './contexts';
|
|
6
|
+
import { ListContextPrivateType, ListContextType, SelectionState } from './contexts';
|
|
7
7
|
type CollapseState = {
|
|
8
8
|
value?: (string | number)[];
|
|
9
9
|
onChange?(value: (string | number)[]): void;
|
|
@@ -45,7 +45,7 @@ export type DroplistProps = {
|
|
|
45
45
|
/** Триггер для дроплиста */
|
|
46
46
|
children?: ReactNode;
|
|
47
47
|
} & Pick<DropdownProps, 'trigger' | 'placement' | 'widthStrategy' | 'open' | 'onOpenChange'> & Omit<ListProps, 'tabIndex' | 'onKeyDown'>;
|
|
48
|
-
export type ListPrivateProps = ListProps & {
|
|
48
|
+
export type ListPrivateProps = ListProps & ListContextPrivateType & {
|
|
49
49
|
nested?: boolean;
|
|
50
50
|
active?: boolean;
|
|
51
51
|
tabIndex?: number;
|
package/dist/utils.d.ts
CHANGED
|
@@ -6,11 +6,11 @@ type WithCollapsedItemsProps = {
|
|
|
6
6
|
};
|
|
7
7
|
export declare function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedItemsProps): {
|
|
8
8
|
items: ItemProps[];
|
|
9
|
-
itemRefs: RefObject<
|
|
9
|
+
itemRefs: RefObject<HTMLElement>[];
|
|
10
10
|
ids: (string | number)[];
|
|
11
11
|
expandedIds: (string | number)[];
|
|
12
12
|
};
|
|
13
|
-
export declare function extractItemRefs(items: ItemProps[]): RefObject<
|
|
13
|
+
export declare function extractItemRefs(items: ItemProps[]): RefObject<HTMLElement>[];
|
|
14
14
|
export declare function extractItemIds(items: ItemProps[]): Array<string | number>;
|
|
15
15
|
export declare function extractChildIds({ items }: {
|
|
16
16
|
items: ItemProps[];
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "List",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.3.1-preview-744f94d0.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"merge-refs": "1.2.2",
|
|
46
46
|
"uncontrollable": "8.0.4"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "66388dea37bc61fd867e4231d413486aa687bc48"
|
|
49
49
|
}
|
|
@@ -16,7 +16,7 @@ export function AccordionItem({ items: itemsProp, id, disabled, ...option }: Acc
|
|
|
16
16
|
|
|
17
17
|
const { isChecked: open, handleClick: handleChange } = useToggleGroup({ value: String(id) });
|
|
18
18
|
|
|
19
|
-
const handleKeyDown = (e: KeyboardEvent<
|
|
19
|
+
const handleKeyDown = (e: KeyboardEvent<HTMLElement>) => {
|
|
20
20
|
if (e.key === 'ArrowRight') {
|
|
21
21
|
handleChange();
|
|
22
22
|
toggleOpenCollapsedItems?.(id ?? '');
|
|
@@ -28,33 +28,31 @@ export function AccordionItem({ items: itemsProp, id, disabled, ...option }: Acc
|
|
|
28
28
|
|
|
29
29
|
const itemsJSX = useRenderItems(itemsProp);
|
|
30
30
|
|
|
31
|
-
const handleItemClick = (e: MouseEvent<
|
|
31
|
+
const handleItemClick = (e: MouseEvent<HTMLElement>) => {
|
|
32
32
|
handleChange();
|
|
33
33
|
toggleOpenCollapsedItems?.(id ?? '');
|
|
34
34
|
option.onClick?.(e);
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
return (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
>
|
|
56
|
-
|
|
57
|
-
</CollapseBlockPrivate>
|
|
58
|
-
</li>
|
|
38
|
+
<CollapseBlockPrivate
|
|
39
|
+
header={
|
|
40
|
+
<BaseItem
|
|
41
|
+
{...option}
|
|
42
|
+
id={id}
|
|
43
|
+
disabled={disabled}
|
|
44
|
+
expandIcon={open ? <ChevronUpSVG /> : <ChevronDownSVG />}
|
|
45
|
+
onClick={handleItemClick}
|
|
46
|
+
isParentNode
|
|
47
|
+
onKeyDown={handleKeyDown}
|
|
48
|
+
indeterminate={isIndeterminate && !checked}
|
|
49
|
+
onSelect={!disabled ? handleOnSelect : undefined}
|
|
50
|
+
/>
|
|
51
|
+
}
|
|
52
|
+
expanded={open}
|
|
53
|
+
data-test-id={`list__accordion-item-${id}`}
|
|
54
|
+
>
|
|
55
|
+
<CollapseContext.Provider value={{ level: level + 1 }}>{itemsJSX}</CollapseContext.Provider>
|
|
56
|
+
</CollapseBlockPrivate>
|
|
59
57
|
);
|
|
60
58
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import cn from 'classnames';
|
|
2
|
-
import { FocusEvent, KeyboardEvent, MouseEvent } from 'react';
|
|
2
|
+
import { FocusEvent, KeyboardEvent, MouseEvent, RefObject } from 'react';
|
|
3
3
|
|
|
4
4
|
import { Checkbox, Switch } from '@snack-uikit/toggles';
|
|
5
5
|
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
@@ -39,7 +39,7 @@ export function BaseItem({
|
|
|
39
39
|
const interactive = !inactive;
|
|
40
40
|
|
|
41
41
|
const { parentResetActiveFocusIndex } = useParentListContext();
|
|
42
|
-
const { size, marker } = useListContext();
|
|
42
|
+
const { size, marker, parent } = useListContext();
|
|
43
43
|
const { level = 0 } = useCollapseContext();
|
|
44
44
|
const { value, onChange, mode, isSelectionSingle, isSelectionMultiple } = useSelectionContext();
|
|
45
45
|
|
|
@@ -49,7 +49,7 @@ export function BaseItem({
|
|
|
49
49
|
onChange?.(id ?? '');
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
const handleItemClick = (e: MouseEvent<
|
|
52
|
+
const handleItemClick = (e: MouseEvent<HTMLElement>) => {
|
|
53
53
|
if (interactive) {
|
|
54
54
|
parentResetActiveFocusIndex?.();
|
|
55
55
|
|
|
@@ -61,7 +61,7 @@ export function BaseItem({
|
|
|
61
61
|
onClick?.(e);
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
const handleItemKeyDown = (e: KeyboardEvent<
|
|
64
|
+
const handleItemKeyDown = (e: KeyboardEvent<HTMLElement>) => {
|
|
65
65
|
onKeyDown?.(e);
|
|
66
66
|
|
|
67
67
|
if (e.code === 'Space' || e.key === 'Enter') {
|
|
@@ -71,14 +71,14 @@ export function BaseItem({
|
|
|
71
71
|
|
|
72
72
|
!isParentNode && handleChange();
|
|
73
73
|
// TODO: should pass an event here?
|
|
74
|
-
!isParentNode && onClick?.(e as unknown as MouseEvent<
|
|
74
|
+
!isParentNode && onClick?.(e as unknown as MouseEvent<HTMLElement>);
|
|
75
75
|
|
|
76
76
|
e.stopPropagation();
|
|
77
77
|
e.preventDefault();
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
const handleItemFocus = (e: FocusEvent<
|
|
81
|
+
const handleItemFocus = (e: FocusEvent<HTMLElement>) => {
|
|
82
82
|
onFocus?.(e);
|
|
83
83
|
e.stopPropagation();
|
|
84
84
|
};
|
|
@@ -98,65 +98,66 @@ export function BaseItem({
|
|
|
98
98
|
const props = extractSupportProps(rest);
|
|
99
99
|
|
|
100
100
|
const item = (
|
|
101
|
-
<li
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
<li
|
|
102
|
+
role={'menuitem'}
|
|
103
|
+
data-test-id={props['data-test-id'] || 'list__base-item_' + id}
|
|
104
|
+
ref={itemRef as unknown as RefObject<HTMLLIElement>}
|
|
105
|
+
className={cn(commonStyles.listItem, styles.droplistItem, className)}
|
|
106
|
+
data-size={size}
|
|
107
|
+
onClick={handleItemClick}
|
|
108
|
+
tabIndex={-1}
|
|
109
|
+
data-non-pointer={inactive && !onClick}
|
|
110
|
+
data-inactive={inactive || undefined}
|
|
111
|
+
data-checked={(isParentNode && (indeterminate || isChecked)) || (isChecked && !switchProp) || undefined}
|
|
112
|
+
data-variant={mode || undefined}
|
|
113
|
+
data-open={open || undefined}
|
|
114
|
+
aria-disabled={disabled || undefined}
|
|
115
|
+
data-parent={parent || 'list'}
|
|
116
|
+
onKeyDown={handleItemKeyDown}
|
|
117
|
+
onFocus={handleItemFocus}
|
|
118
|
+
style={{ '--level': level }}
|
|
119
|
+
>
|
|
120
|
+
{!switchProp && isSelectionSingle && marker && !isParentNode && interactive && (
|
|
121
|
+
<div className={styles.markerContainer} data-test-id='list__base-item-marker' />
|
|
122
|
+
)}
|
|
123
|
+
{!switchProp && isSelectionMultiple && interactive && (
|
|
124
|
+
<div className={styles.checkbox}>
|
|
125
|
+
<Checkbox
|
|
126
|
+
size={CHECKBOX_SIZE_MAP[size ?? 's']}
|
|
127
|
+
disabled={disabled}
|
|
128
|
+
tabIndex={-1}
|
|
129
|
+
onChange={handleCheckboxChange}
|
|
130
|
+
checked={isChecked}
|
|
131
|
+
data-test-id='list__base-item-checkbox'
|
|
132
|
+
onClick={handleCheckboxClick}
|
|
133
|
+
indeterminate={indeterminate}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
<div className={styles.headline}>
|
|
140
|
-
<span className={styles.option}>
|
|
141
|
-
<TruncateString text={option} maxLines={1} />
|
|
142
|
-
</span>
|
|
143
|
-
{caption && <span className={styles.caption}>{caption}</span>}
|
|
144
|
-
</div>
|
|
138
|
+
{beforeContent && <div className={styles.beforeContent}>{beforeContent}</div>}
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
<div className={styles.content}>
|
|
141
|
+
<div className={styles.headline}>
|
|
142
|
+
<span className={styles.option}>
|
|
143
|
+
<TruncateString text={option} maxLines={1} />
|
|
144
|
+
</span>
|
|
145
|
+
{caption && <span className={styles.caption}>{caption}</span>}
|
|
151
146
|
</div>
|
|
152
147
|
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
{description && (
|
|
149
|
+
<div className={styles.description}>
|
|
150
|
+
<TruncateString text={description} maxLines={2} />
|
|
151
|
+
</div>
|
|
157
152
|
)}
|
|
158
|
-
|
|
159
|
-
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
{afterContent}
|
|
156
|
+
|
|
157
|
+
{switchProp && interactive && (
|
|
158
|
+
<Switch disabled={disabled} checked={isChecked} data-test-id='list__base-item-switch' />
|
|
159
|
+
)}
|
|
160
|
+
{!switchProp && expandIcon && <span className={styles.expandableIcon}>{expandIcon}</span>}
|
|
160
161
|
</li>
|
|
161
162
|
);
|
|
162
163
|
|
|
@@ -104,6 +104,7 @@ $typography: (
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
.content {
|
|
107
|
+
overflow: hidden;
|
|
107
108
|
flex-grow: 1;
|
|
108
109
|
flex-shrink: 1;
|
|
109
110
|
box-sizing: border-box;
|
|
@@ -134,10 +135,19 @@ $typography: (
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
&[data-parent='list'] {
|
|
139
|
+
width: 100%;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&[data-parent='droplist'] {
|
|
143
|
+
width: max-content;
|
|
144
|
+
}
|
|
145
|
+
|
|
137
146
|
&[data-non-pointer] {
|
|
138
147
|
cursor: inherit;
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
&[aria-disabled],
|
|
141
151
|
&:disabled {
|
|
142
152
|
.option,
|
|
143
153
|
.description,
|
|
@@ -78,55 +78,53 @@ export function NextListItem({
|
|
|
78
78
|
}, [parentResetActiveFocusIndex, parentResetNestedIndex]);
|
|
79
79
|
|
|
80
80
|
return (
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
</Dropdown>
|
|
130
|
-
</li>
|
|
81
|
+
<Dropdown
|
|
82
|
+
outsideClick={handleOutsideClick}
|
|
83
|
+
fallbackPlacements={FALLBACK_PLACEMENTS}
|
|
84
|
+
content={
|
|
85
|
+
<ParentListContext.Provider
|
|
86
|
+
value={{
|
|
87
|
+
parentIds: ids,
|
|
88
|
+
parentActiveFocusIndex: activeFocusIndex,
|
|
89
|
+
parentExpandedIds: expandedIds,
|
|
90
|
+
parentItemRefs: itemRefs,
|
|
91
|
+
parentOpenNestedIndex: openNestedIndex,
|
|
92
|
+
triggerRef,
|
|
93
|
+
parentRef: listRef,
|
|
94
|
+
parentResetNestedIndex: resetNestedIndex,
|
|
95
|
+
parentResetActiveFocusIndex: resetActiveFocusIndex,
|
|
96
|
+
toggleOpenCollapsedItems: id =>
|
|
97
|
+
setOpenCollapsedItems(items =>
|
|
98
|
+
items.includes(id) ? items.filter(item => item !== id) : items.concat([id]),
|
|
99
|
+
),
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<ListPrivate
|
|
103
|
+
onKeyDown={handleListKeyDown}
|
|
104
|
+
items={items}
|
|
105
|
+
nested
|
|
106
|
+
search={search}
|
|
107
|
+
scroll={scroll}
|
|
108
|
+
scrollRef={scrollRef}
|
|
109
|
+
limitedScrollHeight
|
|
110
|
+
/>
|
|
111
|
+
</ParentListContext.Provider>
|
|
112
|
+
}
|
|
113
|
+
trigger='hover'
|
|
114
|
+
open={(open || parentIds[parentOpenNestedIndex] === id) && !disabled}
|
|
115
|
+
onOpenChange={handleOpenChange}
|
|
116
|
+
placement={placement}
|
|
117
|
+
>
|
|
118
|
+
<BaseItem
|
|
119
|
+
{...option}
|
|
120
|
+
disabled={disabled}
|
|
121
|
+
open={open}
|
|
122
|
+
expandIcon={<ChevronRightSVG />}
|
|
123
|
+
id={id}
|
|
124
|
+
isParentNode
|
|
125
|
+
indeterminate={isIndeterminate && !checked}
|
|
126
|
+
onSelect={handleOnSelect}
|
|
127
|
+
/>
|
|
128
|
+
</Dropdown>
|
|
131
129
|
);
|
|
132
130
|
}
|
|
@@ -5,7 +5,7 @@ import { useParentListContext } from '../../Lists/contexts';
|
|
|
5
5
|
type UseKeyboardNavigationProps = {
|
|
6
6
|
ids: Array<number | string>;
|
|
7
7
|
expandedIds: Array<number | string>;
|
|
8
|
-
itemRefs?: RefObject<
|
|
8
|
+
itemRefs?: RefObject<HTMLElement>[];
|
|
9
9
|
id?: string | number;
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ export function useKeyboardNavigation({ ids, expandedIds, itemRefs, id }: UseKey
|
|
|
17
17
|
const [openNestedIndex, setOpenNestedIndex] = useState<number>(-1);
|
|
18
18
|
const [open, setOpen] = useState<boolean>(false);
|
|
19
19
|
|
|
20
|
-
const handleListKeyDown = (e: KeyboardEvent<
|
|
20
|
+
const handleListKeyDown = (e: KeyboardEvent<HTMLElement>) => {
|
|
21
21
|
switch (e.key) {
|
|
22
22
|
case 'ArrowDown': {
|
|
23
23
|
setActiveFocusIndex(activeIndex => Math.min(activeIndex + 1, ids.length - 1));
|
|
@@ -31,13 +31,13 @@ export type BaseItemProps = WithSupportProps<{
|
|
|
31
31
|
content: ItemContentProps;
|
|
32
32
|
|
|
33
33
|
/** Колбек обработки клика */
|
|
34
|
-
onClick?(e: MouseEvent<
|
|
34
|
+
onClick?(e: MouseEvent<HTMLElement>): void;
|
|
35
35
|
/** Колбек обработки нажатия клавиши */
|
|
36
|
-
onKeyDown?(e: KeyboardEvent<
|
|
36
|
+
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
37
37
|
/** Колбек обработки фокуса */
|
|
38
|
-
onFocus?(e: FocusEvent<
|
|
38
|
+
onFocus?(e: FocusEvent<HTMLElement>): void;
|
|
39
39
|
/** Колбек обработки блюра */
|
|
40
|
-
onBlur?(e: FocusEvent<
|
|
40
|
+
onBlur?(e: FocusEvent<HTMLElement>): void;
|
|
41
41
|
|
|
42
42
|
/** Уникальный идентификатор */
|
|
43
43
|
id?: string | number;
|
|
@@ -45,7 +45,7 @@ export type BaseItemProps = WithSupportProps<{
|
|
|
45
45
|
/** Флаг неактивности элемента */
|
|
46
46
|
disabled?: boolean;
|
|
47
47
|
|
|
48
|
-
itemRef?: RefObject<
|
|
48
|
+
itemRef?: RefObject<HTMLElement>;
|
|
49
49
|
className?: string;
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -60,10 +60,10 @@ export function addItemsIds(itemsProp: ItemProps[], prefix?: string | number): I
|
|
|
60
60
|
...item,
|
|
61
61
|
id: itemId,
|
|
62
62
|
items: addItemsIds(item.items, itemId),
|
|
63
|
-
itemRef: item.itemRef || createRef<
|
|
63
|
+
itemRef: item.itemRef || createRef<HTMLElement>(),
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
return { ...item, id: itemId, itemRef: item.itemRef || createRef<
|
|
67
|
+
return { ...item, id: itemId, itemRef: item.itemRef || createRef<HTMLElement>() };
|
|
68
68
|
});
|
|
69
69
|
}
|
|
@@ -147,13 +147,14 @@ export function Droplist({
|
|
|
147
147
|
<Dropdown
|
|
148
148
|
content={
|
|
149
149
|
<ListPrivate
|
|
150
|
+
{...slicedItems}
|
|
151
|
+
{...props}
|
|
150
152
|
onKeyDown={handleListKeyDown}
|
|
151
153
|
tabIndex={0}
|
|
152
154
|
ref={listRef}
|
|
153
155
|
search={search}
|
|
154
156
|
limitedScrollHeight
|
|
155
|
-
|
|
156
|
-
{...props}
|
|
157
|
+
parent='droplist'
|
|
157
158
|
/>
|
|
158
159
|
}
|
|
159
160
|
trigger={trigger}
|
|
@@ -71,7 +71,7 @@ export const List = forwardRef<HTMLElement, ListProps>(
|
|
|
71
71
|
[items, hasSearch, pinTop, pinBottom, footerRefs],
|
|
72
72
|
);
|
|
73
73
|
|
|
74
|
-
const listRef = useRef<
|
|
74
|
+
const listRef = useRef<HTMLElement>(null);
|
|
75
75
|
const btnRef = useRef<HTMLButtonElement>(null);
|
|
76
76
|
|
|
77
77
|
const { triggerRef } = useParentListContext();
|
|
@@ -93,7 +93,7 @@ export const List = forwardRef<HTMLElement, ListProps>(
|
|
|
93
93
|
|
|
94
94
|
const isActive = listRef.current === document.activeElement && activeFocusIndex === -1 && openNestedIndex === -1;
|
|
95
95
|
|
|
96
|
-
const mergedHandlerKeyDown = (e: KeyboardEvent<
|
|
96
|
+
const mergedHandlerKeyDown = (e: KeyboardEvent<HTMLElement>) => {
|
|
97
97
|
onKeyDown?.(e);
|
|
98
98
|
handleListKeyDown?.(e);
|
|
99
99
|
};
|
|
@@ -141,6 +141,7 @@ export const List = forwardRef<HTMLElement, ListProps>(
|
|
|
141
141
|
tabIndex={tabIndex}
|
|
142
142
|
search={search}
|
|
143
143
|
nested={false}
|
|
144
|
+
parent='list'
|
|
144
145
|
/>
|
|
145
146
|
|
|
146
147
|
<HiddenTabButton ref={btnRef} listRef={listRef} tabIndex={tabIndex} />
|
|
@@ -36,6 +36,7 @@ export const ListPrivate = forwardRef<HTMLElement, ListPrivateProps>(
|
|
|
36
36
|
marker,
|
|
37
37
|
limitedScrollHeight,
|
|
38
38
|
className,
|
|
39
|
+
parent = 'list',
|
|
39
40
|
...props
|
|
40
41
|
},
|
|
41
42
|
ref,
|
|
@@ -135,7 +136,7 @@ export const ListPrivate = forwardRef<HTMLElement, ListPrivateProps>(
|
|
|
135
136
|
|
|
136
137
|
if (!nested) {
|
|
137
138
|
return (
|
|
138
|
-
<ListContextProvider size={size} marker={marker}>
|
|
139
|
+
<ListContextProvider size={size} marker={marker} parent={parent}>
|
|
139
140
|
{listJSX}
|
|
140
141
|
</ListContextProvider>
|
|
141
142
|
);
|
|
@@ -7,18 +7,22 @@ export type ListContextType = {
|
|
|
7
7
|
marker?: boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
export type ListContextPrivateType = {
|
|
11
|
+
parent?: 'list' | 'droplist';
|
|
12
|
+
};
|
|
13
|
+
|
|
10
14
|
type Child = {
|
|
11
15
|
children: ReactNode;
|
|
12
16
|
};
|
|
13
17
|
|
|
14
|
-
export const ListContext = createContext<ListContextType>({});
|
|
18
|
+
export const ListContext = createContext<ListContextType & ListContextPrivateType>({});
|
|
15
19
|
|
|
16
20
|
export const useListContext = () => useContext(ListContext);
|
|
17
21
|
|
|
18
|
-
function extractListProps<T extends ListContextType>({ size, marker }: T) {
|
|
19
|
-
return { size, marker };
|
|
22
|
+
function extractListProps<T extends ListContextType & ListContextPrivateType>({ size, marker, parent }: T) {
|
|
23
|
+
return { size, marker, parent };
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
export function ListContextProvider({ children, ...props }: ListContextType & Child) {
|
|
26
|
+
export function ListContextProvider({ children, ...props }: ListContextType & Child & ListContextPrivateType) {
|
|
23
27
|
return <ListContext.Provider value={extractListProps(props)}>{children}</ListContext.Provider>;
|
|
24
28
|
}
|
|
@@ -7,7 +7,7 @@ export type ParentListContextType = {
|
|
|
7
7
|
|
|
8
8
|
parentIds: Array<string | number>;
|
|
9
9
|
parentExpandedIds: Array<string | number>;
|
|
10
|
-
parentItemRefs: Array<RefObject<
|
|
10
|
+
parentItemRefs: Array<RefObject<HTMLElement>>;
|
|
11
11
|
|
|
12
12
|
parentOpenNestedIndex: number;
|
|
13
13
|
parentResetNestedIndex?(): void;
|
|
@@ -5,7 +5,7 @@ export type UseKeyboardNavigationProps<T extends HTMLElement> = {
|
|
|
5
5
|
expandedIds: Array<number | string>;
|
|
6
6
|
parentRef?: RefObject<T>;
|
|
7
7
|
btnRef?: RefObject<HTMLButtonElement>;
|
|
8
|
-
itemRefs?: RefObject<
|
|
8
|
+
itemRefs?: RefObject<HTMLElement>[];
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export function useKeyboardNavigation<T extends HTMLElement>({
|
|
@@ -5,7 +5,7 @@ import { WithSupportProps } from '@snack-uikit/utils';
|
|
|
5
5
|
|
|
6
6
|
import { ScrollProps, SearchState } from '../../types';
|
|
7
7
|
import { ItemProps } from '../Items';
|
|
8
|
-
import { ListContextType, SelectionState } from './contexts';
|
|
8
|
+
import { ListContextPrivateType, ListContextType, SelectionState } from './contexts';
|
|
9
9
|
|
|
10
10
|
type CollapseState = {
|
|
11
11
|
value?: (string | number)[];
|
|
@@ -56,12 +56,13 @@ export type DroplistProps = {
|
|
|
56
56
|
} & Pick<DropdownProps, 'trigger' | 'placement' | 'widthStrategy' | 'open' | 'onOpenChange'> &
|
|
57
57
|
Omit<ListProps, 'tabIndex' | 'onKeyDown'>;
|
|
58
58
|
|
|
59
|
-
export type ListPrivateProps = ListProps &
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
export type ListPrivateProps = ListProps &
|
|
60
|
+
ListContextPrivateType & {
|
|
61
|
+
nested?: boolean;
|
|
62
|
+
active?: boolean;
|
|
63
|
+
tabIndex?: number;
|
|
64
|
+
onFocus?(e: FocusEvent<HTMLElement>): void;
|
|
65
|
+
onBlur?(e: FocusEvent<HTMLElement>): void;
|
|
66
|
+
onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
|
|
67
|
+
limitedScrollHeight?: boolean;
|
|
68
|
+
};
|
package/src/utils.ts
CHANGED
|
@@ -14,7 +14,7 @@ type WithCollapsedItemsProps = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedItemsProps) {
|
|
17
|
-
let itemRefs: RefObject<
|
|
17
|
+
let itemRefs: RefObject<HTMLElement>[] = [];
|
|
18
18
|
let newItems: ItemProps[] = [];
|
|
19
19
|
let ids: Array<string | number> = [];
|
|
20
20
|
let expandedIds: Array<string | number> = [];
|
|
@@ -68,13 +68,13 @@ export function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedI
|
|
|
68
68
|
return { items, itemRefs, ids, expandedIds };
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export function extractItemRefs(items: ItemProps[]): RefObject<
|
|
72
|
-
return items.reduce((prev: RefObject<
|
|
71
|
+
export function extractItemRefs(items: ItemProps[]): RefObject<HTMLElement>[] {
|
|
72
|
+
return items.reduce((prev: RefObject<HTMLElement>[], item: ItemProps) => {
|
|
73
73
|
if (isGroupItemProps(item)) {
|
|
74
74
|
return prev.concat(extractItemRefs(item.items));
|
|
75
75
|
}
|
|
76
76
|
return item.itemRef ? prev.concat([item.itemRef]) : prev;
|
|
77
|
-
}, [] as RefObject<
|
|
77
|
+
}, [] as RefObject<HTMLElement>[]);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export function extractItemIds(items: ItemProps[]): Array<string | number> {
|