@snack-uikit/tree 0.6.26-preview-eb3592d8.0 → 0.6.26-preview-1b7c1817.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/components/Tree/Tree.js +1 -1
- package/dist/contexts/TreeContext.d.ts +5 -2
- package/dist/contexts/TreeContext.js +1 -1
- package/dist/helperComponents/TreeNode/TreeNode.js +5 -4
- package/dist/types.d.ts +2 -1
- package/package.json +3 -3
- package/src/components/Tree/Tree.tsx +1 -0
- package/src/contexts/TreeContext.tsx +10 -3
- package/src/helperComponents/TreeNode/TreeNode.tsx +23 -17
- package/src/types.ts +2 -1
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ const [selectedNodes, setSelected] = useState<TreeNodeId[]>([]);
|
|
|
55
55
|
| selectionMode | "single" \| "multi" | - | Режим выбора элементов: <br> - `Single` - одиночный выбор <br> - `Multi` - множественный выбор <br> - `undefined` - без выбора |
|
|
56
56
|
| selected | `string \| string[]` | - | Состояние для выбраных элементов: <br> - При <strong>selectionMode</strong>=`Multi` - принимает массив строк <br> - При <strong>selectionMode</strong>=`Single` - принимает строку |
|
|
57
57
|
| onSelect | `((selectedKeys: string[], node: TreeNodeProps) => void) \| ((selectedKey: string, node: TreeNodeProps) => void)` | - | Колбэк при изменении выбраных элементов: <br> - При <strong>selectionMode</strong>=`Multi` - возвращает массив строк <br> - При <strong>selectionMode</strong>=`Single` - возвращает строку |
|
|
58
|
+
| showToggleInSingleMode | `boolean` | - | |
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
[//]: DOCUMENTATION_SECTION_END
|
|
@@ -18,7 +18,7 @@ import styles from './styles.module.css';
|
|
|
18
18
|
import { extractSelectableProps } from './utils';
|
|
19
19
|
export function Tree(_a) {
|
|
20
20
|
var { data, onNodeClick, onExpand, expandedNodes, nodeActions, parentActions, onDataLoad, showLines = true, showIcons = true, className } = _a, rest = __rest(_a, ["data", "onNodeClick", "onExpand", "expandedNodes", "nodeActions", "parentActions", "onDataLoad", "showLines", "showIcons", "className"]);
|
|
21
|
-
return (_jsx("div", Object.assign({ className: cn(styles.tree, className), role: 'tree' }, extractSupportProps(rest), { children: _jsx(TreeContextProvider, { value: Object.assign({ data,
|
|
21
|
+
return (_jsx("div", Object.assign({ className: cn(styles.tree, className), role: 'tree' }, extractSupportProps(rest), { children: _jsx(TreeContextProvider, { value: Object.assign({ showToggleInSingleMode: rest.selectionMode === 'single' && rest.showToggleInSingleMode, data,
|
|
22
22
|
expandedNodes,
|
|
23
23
|
onNodeClick,
|
|
24
24
|
onExpand,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
2
|
import { OnNodeClick, ParentNode, TreeBaseProps, TreeNodeId, TreeNodeProps } from '../types';
|
|
3
|
-
type
|
|
3
|
+
type TreeContextBaseProps = TreeBaseProps & {
|
|
4
|
+
showToggleInSingleMode?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type TreeContextProps = Omit<TreeContextBaseProps, 'onSelect' | 'onExpand' | 'onNodeClick' | 'selected' | 'selectionMode'> & {
|
|
4
7
|
onExpand(node: TreeNodeProps): void;
|
|
5
8
|
onSelect(node: Pick<TreeNodeProps, 'id' | 'nested' | 'disabled'>, parentNode?: ParentNode): void;
|
|
6
9
|
selected?: TreeNodeId[] | TreeNodeId;
|
|
@@ -16,7 +19,7 @@ type TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeCli
|
|
|
16
19
|
};
|
|
17
20
|
type TreeContextProviderProps = {
|
|
18
21
|
children: ReactNode;
|
|
19
|
-
value:
|
|
22
|
+
value: TreeContextBaseProps;
|
|
20
23
|
};
|
|
21
24
|
export declare const TreeContext: import("react").Context<TreeContextProps>;
|
|
22
25
|
export declare function TreeContextProvider({ children, value }: TreeContextProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -47,7 +47,7 @@ export function TreeContextProvider({ children, value }) {
|
|
|
47
47
|
if (!isSelectable || node.disabled)
|
|
48
48
|
return;
|
|
49
49
|
if (isSingleSelect) {
|
|
50
|
-
onSelectHandler(node.id, node);
|
|
50
|
+
onSelectHandler(node.id === selectedNodes ? undefined : node.id, node);
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
if (Array.isArray(selectedNodes)) {
|
|
@@ -27,16 +27,16 @@ import styles from './styles.module.css';
|
|
|
27
27
|
import { stopPropagationClick } from './utils';
|
|
28
28
|
export function TreeNode(_a) {
|
|
29
29
|
var { id, title, icon = _jsx(FileSVG, { size: 24 }), expandedIcon = _jsx(FolderOpenSVG, { size: 24 }), collapsedIcon = _jsx(FolderSVG, { size: 24 }), disabled, onClick, nested, className, onChevronClick, onKeyDown, isLoading, parentNode, tabIndexAvailable } = _a, rest = __rest(_a, ["id", "title", "icon", "expandedIcon", "collapsedIcon", "disabled", "onClick", "nested", "className", "onChevronClick", "onKeyDown", "isLoading", "parentNode", "tabIndexAvailable"]);
|
|
30
|
-
const { isMultiSelect, isSelectable, onNodeClick, selected, expandedNodes, onSelect, nodeActions, parentActions, setFocusPosition, resetFocusPosition, focusedNodeId, setFocusIndex, focusableNodeIds, showLines, showIcons, } = useTreeContext();
|
|
30
|
+
const { isMultiSelect, isSelectable, onNodeClick, selected, expandedNodes, onSelect, nodeActions, parentActions, setFocusPosition, resetFocusPosition, focusedNodeId, setFocusIndex, focusableNodeIds, showToggleInSingleMode, showLines, showIcons, } = useTreeContext();
|
|
31
31
|
const [isDroplistOpen, setDroplistOpen] = useState(false);
|
|
32
32
|
const [isDroplistTriggerFocused, setFocusDroplistTrigger] = useState(false);
|
|
33
33
|
const ref = useRef(null);
|
|
34
34
|
const isExpandable = Array.isArray(nested);
|
|
35
35
|
const isExpanded = isExpandable ? expandedNodes === null || expandedNodes === void 0 ? void 0 : expandedNodes.includes(id) : undefined;
|
|
36
36
|
const nestedNodesSelection = useMemo(() => {
|
|
37
|
-
if (!nested || !
|
|
37
|
+
if (!nested || !selected)
|
|
38
38
|
return undefined;
|
|
39
|
-
return checkNestedNodesSelection(nested, selected);
|
|
39
|
+
return checkNestedNodesSelection(nested, Array.isArray(selected) ? selected : [selected]);
|
|
40
40
|
}, [nested, selected]);
|
|
41
41
|
const isSelected = (Array.isArray(selected) ? selected.includes(id) || (nestedNodesSelection === null || nestedNodesSelection === void 0 ? void 0 : nestedNodesSelection.allSelected) : selected === id) || false;
|
|
42
42
|
const isFocused = focusedNodeId === id;
|
|
@@ -139,7 +139,8 @@ export function TreeNode(_a) {
|
|
|
139
139
|
}
|
|
140
140
|
};
|
|
141
141
|
const getNodeActions = Boolean(nested) ? parentActions : nodeActions;
|
|
142
|
-
return (_jsxs("div", Object.assign({ role: 'presentation', className: cn(styles.treeNode, className) }, extractSupportProps(rest), { "data-node-id": id, children: [parentNode && (_jsx(TreeLine, { halfWidth: Boolean(nested), horizontal: true, visible: showLines, "data-test-id": TEST_IDS.line })), !parentNode && !Boolean(nested) && _jsx(TreeLine, { visible: false }), isExpandable && (_jsx(ButtonFunction, { size: 'xs', icon: _jsx(ChevronRightSVG, {}), disabled: disabled, loading: isLoading, onClick: onChevronClick, "data-expanded": isExpanded || undefined, className: styles.treeNodeExpandButton, tabIndex: -1, "data-test-id": TEST_IDS.chevron })), _jsxs("div", { role: 'treeitem', "aria-expanded": isExpanded, "aria-selected": isSelectable ? isSelected : undefined, "aria-disabled": disabled, "data-multiselect": isMultiSelect || undefined, "data-droplist-active": isDroplistOpen || isDroplistTriggerFocused || undefined, onClick: handleClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: resetFocusPosition, tabIndex: tabIndexAvailable ? 0 : -1, className: styles.treeNodeContent, "data-test-id": TEST_IDS.item, ref: ref, children: [isMultiSelect
|
|
142
|
+
return (_jsxs("div", Object.assign({ role: 'presentation', className: cn(styles.treeNode, className) }, extractSupportProps(rest), { "data-node-id": id, children: [parentNode && (_jsx(TreeLine, { halfWidth: Boolean(nested), horizontal: true, visible: showLines, "data-test-id": TEST_IDS.line })), !parentNode && !Boolean(nested) && _jsx(TreeLine, { visible: false }), isExpandable && (_jsx(ButtonFunction, { size: 'xs', icon: _jsx(ChevronRightSVG, {}), disabled: disabled, loading: isLoading, onClick: onChevronClick, "data-expanded": isExpanded || undefined, className: styles.treeNodeExpandButton, tabIndex: -1, "data-test-id": TEST_IDS.chevron })), _jsxs("div", { role: 'treeitem', "aria-expanded": isExpanded, "aria-selected": isSelectable ? isSelected : undefined, "aria-disabled": disabled, "data-multiselect": isMultiSelect || undefined, "data-droplist-active": isDroplistOpen || isDroplistTriggerFocused || undefined, onClick: handleClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: resetFocusPosition, tabIndex: tabIndexAvailable ? 0 : -1, className: styles.treeNodeContent, "data-test-id": TEST_IDS.item, ref: ref, children: [isMultiSelect ||
|
|
143
|
+
(showToggleInSingleMode && (_jsx("div", { className: styles.treeNodeCheckboxWrap, children: _jsx(Checkbox, { size: 's', disabled: disabled, checked: isSelected, indeterminate: !isSelected && (nestedNodesSelection === null || nestedNodesSelection === void 0 ? void 0 : nestedNodesSelection.someSelected), onChange: handleSelect, onClick: stopPropagationClick, "data-test-id": TEST_IDS.checkbox, tabIndex: -1 }) }))), treeNodeIcon && (_jsx("div", { className: styles.treeNodeIcon, "data-test-id": TEST_IDS.icon, children: treeNodeIcon })), _jsx(Typography.SansBodyM, { tag: 'div', className: styles.treeNodeTitle, children: typeof title === 'string' ? (_jsx(TruncateString, { text: title, "data-test-id": TEST_IDS.title })) : (title(Object.assign({ id, title, onClick, className, disabled }, extractSupportProps(rest)))) }), getNodeActions && (_jsx(TreeNodeActions, { getNodeActions: getNodeActions, node: {
|
|
143
144
|
id,
|
|
144
145
|
title,
|
|
145
146
|
disabled,
|
package/dist/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type BaseTreeNode = WithSupportProps<{
|
|
|
8
8
|
/** Идентификатор элемента */
|
|
9
9
|
id: TreeNodeId;
|
|
10
10
|
/** Имя элемента */
|
|
11
|
-
title: string;
|
|
11
|
+
title: string | ((value: BaseTreeNode) => ReactNode);
|
|
12
12
|
/** Является ли элемент деактивированным */
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
/** Обработчик клика по элементу */
|
|
@@ -81,6 +81,7 @@ export type TreeSingleSelect = Omit<TreeCommonProps, 'selected'> & {
|
|
|
81
81
|
selected?: TreeNodeId;
|
|
82
82
|
/** <br> - При <strong>selectionMode</strong>=`Single` - возвращает строку */
|
|
83
83
|
onSelect?(selectedKey: TreeNodeId, node: TreeNodeProps): void;
|
|
84
|
+
showToggleInSingleMode?: boolean;
|
|
84
85
|
};
|
|
85
86
|
export type TreeMultiSelect = Omit<TreeCommonProps, 'selected'> & {
|
|
86
87
|
selectionMode: 'multi';
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Tree",
|
|
7
|
-
"version": "0.6.26-preview-
|
|
7
|
+
"version": "0.6.26-preview-1b7c1817.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@snack-uikit/button": "0.17.5",
|
|
36
36
|
"@snack-uikit/icons": "0.22.1",
|
|
37
|
-
"@snack-uikit/list": "0.17.
|
|
37
|
+
"@snack-uikit/list": "0.17.0",
|
|
38
38
|
"@snack-uikit/toggles": "0.10.4",
|
|
39
39
|
"@snack-uikit/truncate-string": "0.4.24",
|
|
40
40
|
"@snack-uikit/typography": "0.6.3",
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"react-transition-state": "2.1.1",
|
|
44
44
|
"uncontrollable": "8.0.4"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "fcec27b4b06ab5c700cc50bb4c0e9520aba50cb7"
|
|
47
47
|
}
|
|
@@ -27,6 +27,7 @@ export function Tree({
|
|
|
27
27
|
<div className={cn(styles.tree, className)} role='tree' {...extractSupportProps(rest)}>
|
|
28
28
|
<TreeContextProvider
|
|
29
29
|
value={{
|
|
30
|
+
showToggleInSingleMode: rest.selectionMode === 'single' && rest.showToggleInSingleMode,
|
|
30
31
|
data,
|
|
31
32
|
expandedNodes,
|
|
32
33
|
onNodeClick,
|
|
@@ -5,7 +5,14 @@ import { SELECTION_MODE } from '../constants';
|
|
|
5
5
|
import { findAllExpandedChildNodeIds, lookupTreeForSelectedNodes } from '../helpers';
|
|
6
6
|
import { OnNodeClick, ParentNode, TreeBaseProps, TreeNodeId, TreeNodeProps } from '../types';
|
|
7
7
|
|
|
8
|
-
type
|
|
8
|
+
type TreeContextBaseProps = TreeBaseProps & {
|
|
9
|
+
showToggleInSingleMode?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type TreeContextProps = Omit<
|
|
13
|
+
TreeContextBaseProps,
|
|
14
|
+
'onSelect' | 'onExpand' | 'onNodeClick' | 'selected' | 'selectionMode'
|
|
15
|
+
> & {
|
|
9
16
|
onExpand(node: TreeNodeProps): void;
|
|
10
17
|
onSelect(node: Pick<TreeNodeProps, 'id' | 'nested' | 'disabled'>, parentNode?: ParentNode): void;
|
|
11
18
|
selected?: TreeNodeId[] | TreeNodeId;
|
|
@@ -22,7 +29,7 @@ type TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeCli
|
|
|
22
29
|
|
|
23
30
|
type TreeContextProviderProps = {
|
|
24
31
|
children: ReactNode;
|
|
25
|
-
value:
|
|
32
|
+
value: TreeContextBaseProps;
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
export const TreeContext = createContext<TreeContextProps>({
|
|
@@ -81,7 +88,7 @@ export function TreeContextProvider({ children, value }: TreeContextProviderProp
|
|
|
81
88
|
if (!isSelectable || node.disabled) return;
|
|
82
89
|
|
|
83
90
|
if (isSingleSelect) {
|
|
84
|
-
onSelectHandler(node.id, node);
|
|
91
|
+
onSelectHandler(node.id === selectedNodes ? undefined : node.id, node);
|
|
85
92
|
return;
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -58,6 +58,7 @@ export function TreeNode({
|
|
|
58
58
|
focusedNodeId,
|
|
59
59
|
setFocusIndex,
|
|
60
60
|
focusableNodeIds,
|
|
61
|
+
showToggleInSingleMode,
|
|
61
62
|
showLines,
|
|
62
63
|
showIcons,
|
|
63
64
|
} = useTreeContext();
|
|
@@ -71,9 +72,9 @@ export function TreeNode({
|
|
|
71
72
|
const isExpanded = isExpandable ? expandedNodes?.includes(id) : undefined;
|
|
72
73
|
|
|
73
74
|
const nestedNodesSelection = useMemo(() => {
|
|
74
|
-
if (!nested || !
|
|
75
|
+
if (!nested || !selected) return undefined;
|
|
75
76
|
|
|
76
|
-
return checkNestedNodesSelection(nested, selected);
|
|
77
|
+
return checkNestedNodesSelection(nested, Array.isArray(selected) ? selected : [selected]);
|
|
77
78
|
}, [nested, selected]);
|
|
78
79
|
|
|
79
80
|
const isSelected =
|
|
@@ -247,20 +248,21 @@ export function TreeNode({
|
|
|
247
248
|
data-test-id={TEST_IDS.item}
|
|
248
249
|
ref={ref}
|
|
249
250
|
>
|
|
250
|
-
{isMultiSelect
|
|
251
|
-
|
|
252
|
-
<
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
251
|
+
{isMultiSelect ||
|
|
252
|
+
(showToggleInSingleMode && (
|
|
253
|
+
<div className={styles.treeNodeCheckboxWrap}>
|
|
254
|
+
<Checkbox
|
|
255
|
+
size='s'
|
|
256
|
+
disabled={disabled}
|
|
257
|
+
checked={isSelected}
|
|
258
|
+
indeterminate={!isSelected && nestedNodesSelection?.someSelected}
|
|
259
|
+
onChange={handleSelect}
|
|
260
|
+
onClick={stopPropagationClick}
|
|
261
|
+
data-test-id={TEST_IDS.checkbox}
|
|
262
|
+
tabIndex={-1}
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
))}
|
|
264
266
|
|
|
265
267
|
{treeNodeIcon && (
|
|
266
268
|
<div className={styles.treeNodeIcon} data-test-id={TEST_IDS.icon}>
|
|
@@ -269,7 +271,11 @@ export function TreeNode({
|
|
|
269
271
|
)}
|
|
270
272
|
|
|
271
273
|
<Typography.SansBodyM tag='div' className={styles.treeNodeTitle}>
|
|
272
|
-
|
|
274
|
+
{typeof title === 'string' ? (
|
|
275
|
+
<TruncateString text={title} data-test-id={TEST_IDS.title} />
|
|
276
|
+
) : (
|
|
277
|
+
title({ id, title, onClick, className, disabled, ...extractSupportProps(rest) })
|
|
278
|
+
)}
|
|
273
279
|
</Typography.SansBodyM>
|
|
274
280
|
|
|
275
281
|
{getNodeActions && (
|
package/src/types.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type BaseTreeNode = WithSupportProps<{
|
|
|
13
13
|
/** Идентификатор элемента */
|
|
14
14
|
id: TreeNodeId;
|
|
15
15
|
/** Имя элемента */
|
|
16
|
-
title: string;
|
|
16
|
+
title: string | ((value: BaseTreeNode) => ReactNode);
|
|
17
17
|
/** Является ли элемент деактивированным */
|
|
18
18
|
disabled?: boolean;
|
|
19
19
|
/** Обработчик клика по элементу */
|
|
@@ -92,6 +92,7 @@ export type TreeSingleSelect = Omit<TreeCommonProps, 'selected'> & {
|
|
|
92
92
|
selected?: TreeNodeId;
|
|
93
93
|
/** <br> - При <strong>selectionMode</strong>=`Single` - возвращает строку */
|
|
94
94
|
onSelect?(selectedKey: TreeNodeId, node: TreeNodeProps): void;
|
|
95
|
+
showToggleInSingleMode?: boolean;
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
export type TreeMultiSelect = Omit<TreeCommonProps, 'selected'> & {
|