@snack-uikit/tree 0.3.4 → 0.5.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 CHANGED
@@ -3,6 +3,28 @@
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.5.0 (2024-01-18)
7
+
8
+
9
+ ### Features
10
+
11
+ * **FF-4126:** selectionMode is optional, and tree may be unselectable ([1540e26](https://github.com/cloud-ru-tech/snack-uikit/commit/1540e266b9351a92f1619c399a904fd6bd25518f))
12
+
13
+
14
+
15
+
16
+
17
+ # 0.4.0 (2024-01-11)
18
+
19
+
20
+ ### Features
21
+
22
+ * **FF-4018:** add showIcons prop to disable tree node icon ([eecda7f](https://github.com/cloud-ru-tech/snack-uikit/commit/eecda7f35fc98efeea2770098acfe7241b44b57a))
23
+
24
+
25
+
26
+
27
+
6
28
  ## 0.3.4 (2023-12-28)
7
29
 
8
30
  ### Only dependencies have been changed
package/README.md CHANGED
@@ -43,15 +43,16 @@ const [selectedNodes, setSelected] = useState<TreeNodeId[]>([]);
43
43
  | name | type | default value | description |
44
44
  |------|------|---------------|-------------|
45
45
  | data* | `TreeNodeProps[]` | - | Данные для отрисовки |
46
- | selectionMode | "single" \| "multi" | - | Режим выбора элементов: <br> - `Single` - одиночный выбор <br> - `Multi` - множественный выбор |
47
46
  | onNodeClick | `OnNodeClick` | - | Обработчик клика по элементу дерева |
48
47
  | expandedNodes | `string[]` | - | Состояние для раскрытых элементов |
49
48
  | onExpand | `(expandedKeys: string[], nodeId: string) => void` | - | Колбэк при раскрытии/закрытии элементов |
50
49
  | onDataLoad | `(node: TreeNodeProps) => Promise<unknown>` | - | Колбэк для асинхронной загрузки данных при раскрытии дерева |
51
50
  | parentActions | `(node: TreeNodeProps) => DroplistItemSingleProps[]` | - | Дополнительные действия для элемента-родителя |
52
51
  | nodeActions | `(node: TreeNodeProps) => DroplistItemSingleProps[]` | - | Дополнительные действия для элемента-потомка |
52
+ | showIcons | `boolean` | true | Флаг отвечающий за отображение иконок у элементов дерева |
53
53
  | showLines | `boolean` | true | Флаг отвечающий за отображение линий вложенности |
54
54
  | className | `string` | - | CSS-класс |
55
+ | selectionMode | "single" \| "multi" | - | Режим выбора элементов: <br> - `Single` - одиночный выбор <br> - `Multi` - множественный выбор <br> - `undefined` - без выбора |
55
56
  | selected | `string \| string[]` | - | Состояние для выбраных элементов: <br> - При <strong>selectionMode</strong>=`Multi` - принимает массив строк <br> - При <strong>selectionMode</strong>=`Single` - принимает строку |
56
57
  | onSelect | `((selectedKeys: string[], node: TreeNodeProps) => void) \| ((selectedKey: string, node: TreeNodeProps) => void)` | - | Колбэк при изменении выбраных элементов: <br> - При <strong>selectionMode</strong>=`Multi` - возвращает массив строк <br> - При <strong>selectionMode</strong>=`Single` - возвращает строку |
57
58
 
@@ -1,4 +1,4 @@
1
1
  import { WithSupportProps } from '@snack-uikit/utils';
2
2
  import { TreeBaseProps } from '../../types';
3
3
  export type TreeProps = WithSupportProps<TreeBaseProps>;
4
- export declare function Tree({ data, selected, selectionMode, onSelect, onNodeClick, onExpand, expandedNodes, nodeActions, parentActions, onDataLoad, showLines, className, ...rest }: TreeProps): import("react/jsx-runtime").JSX.Element;
4
+ export declare function Tree({ data, onNodeClick, onExpand, expandedNodes, nodeActions, parentActions, onDataLoad, showLines, showIcons, className, ...rest }: TreeProps): import("react/jsx-runtime").JSX.Element;
@@ -15,13 +15,10 @@ import { extractSupportProps } from '@snack-uikit/utils';
15
15
  import { TreeContextProvider } from '../../contexts/TreeContext';
16
16
  import { TreeItem } from '../../helperComponents';
17
17
  import styles from './styles.module.css';
18
+ import { extractSelectableProps } from './utils';
18
19
  export function Tree(_a) {
19
- var { data, selected, selectionMode, onSelect, onNodeClick, onExpand, expandedNodes, nodeActions, parentActions, onDataLoad, showLines = true, className } = _a, rest = __rest(_a, ["data", "selected", "selectionMode", "onSelect", "onNodeClick", "onExpand", "expandedNodes", "nodeActions", "parentActions", "onDataLoad", "showLines", "className"]);
20
- return (_jsx("div", Object.assign({ className: cn(styles.tree, className), role: 'tree' }, extractSupportProps(rest), { children: _jsx(TreeContextProvider, { value: {
21
- data,
22
- selected: selected,
23
- selectionMode: selectionMode,
24
- onSelect: onSelect,
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,
25
22
  expandedNodes,
26
23
  onNodeClick,
27
24
  onExpand,
@@ -29,5 +26,5 @@ export function Tree(_a) {
29
26
  parentActions,
30
27
  onDataLoad,
31
28
  showLines,
32
- }, children: data.map((node, index) => (_jsx(TreeItem, { node: node, tabIndexAvailable: index === 0 || index === data.length - 1 }, node.id))) }) })));
29
+ showIcons }, extractSelectableProps(rest)), children: data.map((node, index) => (_jsx(TreeItem, { node: node, tabIndexAvailable: index === 0 || index === data.length - 1 }, node.id))) }) })));
33
30
  }
@@ -0,0 +1,2 @@
1
+ import { TreeBaseProps, TreeMultiSelect, TreeSingleSelect, TreeView } from '../../types';
2
+ export declare function extractSelectableProps({ selectionMode, selected, onSelect, }: Pick<TreeBaseProps, 'selectionMode' | 'selected' | 'onSelect'>): Pick<TreeSingleSelect, "selected" | "selectionMode" | "onSelect"> | Pick<TreeMultiSelect, "selected" | "selectionMode" | "onSelect"> | Pick<TreeView, "selected" | "selectionMode" | "onSelect">;
@@ -0,0 +1,20 @@
1
+ import { SELECTION_MODE } from '../../constants';
2
+ export function extractSelectableProps({ selectionMode, selected, onSelect, }) {
3
+ switch (selectionMode) {
4
+ case SELECTION_MODE.Single:
5
+ return {
6
+ selectionMode,
7
+ selected,
8
+ onSelect,
9
+ };
10
+ case SELECTION_MODE.Multi:
11
+ return {
12
+ selectionMode,
13
+ selected,
14
+ onSelect,
15
+ };
16
+ case undefined:
17
+ default:
18
+ return {};
19
+ }
20
+ }
@@ -7,6 +7,7 @@ type TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeCli
7
7
  onNodeClick: OnNodeClick;
8
8
  isMultiSelect: boolean;
9
9
  isSingleSelect: boolean;
10
+ isSelectable: boolean;
10
11
  focusedNodeId?: TreeNodeId;
11
12
  setFocusPosition(id: TreeNodeId): void;
12
13
  resetFocusPosition(): void;
@@ -29,11 +29,13 @@ export const TreeContext = createContext({
29
29
  focusableNodeIds: [],
30
30
  isMultiSelect: false,
31
31
  isSingleSelect: false,
32
+ isSelectable: false,
32
33
  });
33
34
  export function TreeContextProvider({ children, value }) {
34
35
  const { onNodeClick: onNodeClickProp, onExpand: onExpandProp, onSelect: onSelectProp, selectionMode, data } = value, props = __rest(value, ["onNodeClick", "onExpand", "onSelect", "selectionMode", "data"]);
35
36
  const isMultiSelect = selectionMode === SELECTION_MODE.Multi;
36
37
  const isSingleSelect = selectionMode === SELECTION_MODE.Single;
38
+ const isSelectable = Boolean(selectionMode);
37
39
  const [expandedNodes, onExpandHandler] = useUncontrolledProp(value.expandedNodes, value.expandedNodes || [], onExpandProp);
38
40
  const onExpand = useCallback(node => {
39
41
  const isExpanded = expandedNodes.includes(node.id);
@@ -42,7 +44,7 @@ export function TreeContextProvider({ children, value }) {
42
44
  }, [expandedNodes, onExpandHandler]);
43
45
  const [selectedNodes, onSelectHandler] = useUncontrolledProp(value.selected, [], onSelectProp);
44
46
  const onSelect = useCallback((node, parentNode) => {
45
- if (node.disabled)
47
+ if (!isSelectable || node.disabled)
46
48
  return;
47
49
  if (isSingleSelect) {
48
50
  onSelectHandler(node.id, node);
@@ -52,7 +54,7 @@ export function TreeContextProvider({ children, value }) {
52
54
  const updatedSelectedNodes = lookupTreeForSelectedNodes({ node, parentNode, selectedNodes });
53
55
  onSelectHandler(updatedSelectedNodes, node);
54
56
  }
55
- }, [isSingleSelect, onSelectHandler, selectedNodes]);
57
+ }, [isSingleSelect, onSelectHandler, selectedNodes, isSelectable]);
56
58
  const focusableNodeIds = useMemo(() => {
57
59
  if (!(expandedNodes === null || expandedNodes === void 0 ? void 0 : expandedNodes.length)) {
58
60
  return data.map(node => node.id);
@@ -86,6 +88,7 @@ export function TreeContextProvider({ children, value }) {
86
88
  }, [isSingleSelect, onSelect, onNodeClickProp]);
87
89
  return (_jsx(TreeContext.Provider, { value: Object.assign(Object.assign({}, props), { data, selected: selectedNodes, isSingleSelect,
88
90
  isMultiSelect,
91
+ isSelectable,
89
92
  expandedNodes,
90
93
  onExpand,
91
94
  onSelect,
@@ -27,7 +27,7 @@ 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, onNodeClick, selected, expandedNodes, onSelect, nodeActions, parentActions, setFocusPosition, resetFocusPosition, focusedNodeId, setFocusIndex, focusableNodeIds, showLines, } = useTreeContext();
30
+ const { isMultiSelect, isSelectable, onNodeClick, selected, expandedNodes, onSelect, nodeActions, parentActions, setFocusPosition, resetFocusPosition, focusedNodeId, setFocusIndex, focusableNodeIds, showLines, showIcons, } = useTreeContext();
31
31
  const [isDroplistOpen, setDroplistOpen] = useState(false);
32
32
  const [isDroplistTriggerFocused, setFocusDroplistTrigger] = useState(false);
33
33
  const ref = useRef(null);
@@ -46,11 +46,13 @@ export function TreeNode(_a) {
46
46
  }
47
47
  }, [isFocused]);
48
48
  const treeNodeIcon = useMemo(() => {
49
+ if (!showIcons)
50
+ return undefined;
49
51
  if (isExpandable) {
50
52
  return isExpanded ? expandedIcon : collapsedIcon;
51
53
  }
52
54
  return icon;
53
- }, [isExpandable, icon, isExpanded, expandedIcon, collapsedIcon]);
55
+ }, [showIcons, isExpandable, icon, isExpanded, expandedIcon, collapsedIcon]);
54
56
  const handleClick = e => {
55
57
  onNodeClick({
56
58
  id,
@@ -137,7 +139,7 @@ export function TreeNode(_a) {
137
139
  }
138
140
  };
139
141
  const getNodeActions = Boolean(nested) ? parentActions : nodeActions;
140
- 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": isSelected, "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 && (_jsx("div", { className: styles.treeNodeCheckboxWrap, children: _jsx(Checkbox, { size: 's', disabled: disabled, checked: !disabled && isSelected, indeterminate: !disabled && !isSelected && (nestedNodesSelection === null || nestedNodesSelection === void 0 ? void 0 : nestedNodesSelection.someSelected), onChange: handleSelect, onClick: stopPropagationClick, "data-test-id": TEST_IDS.checkbox, tabIndex: -1 }) })), _jsx("div", { className: styles.treeNodeIcon, "data-test-id": TEST_IDS.icon, children: treeNodeIcon }), _jsx(Typography.SansBodyM, { tag: 'div', className: styles.treeNodeTitle, children: _jsx(TruncateString, { text: title, "data-test-id": TEST_IDS.title }) }), getNodeActions && (_jsx(TreeNodeActions, { getNodeActions: getNodeActions, node: {
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 && (_jsx("div", { className: styles.treeNodeCheckboxWrap, children: _jsx(Checkbox, { size: 's', disabled: disabled, checked: !disabled && isSelected, indeterminate: !disabled && !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: _jsx(TruncateString, { text: title, "data-test-id": TEST_IDS.title }) }), getNodeActions && (_jsx(TreeNodeActions, { getNodeActions: getNodeActions, node: {
141
143
  id,
142
144
  title,
143
145
  disabled,
@@ -45,7 +45,6 @@
45
45
  align-items:center;
46
46
  box-sizing:border-box;
47
47
  width:100%;
48
- border-radius:var(--radius-tree-item-content-layout, 8px);
49
48
  }
50
49
  .treeNodeContent::before{
51
50
  pointer-events:none;
package/dist/types.d.ts CHANGED
@@ -43,6 +43,7 @@ export type TreeCommonProps = {
43
43
  * Режим выбора элементов:
44
44
  * <br> - `Single` - одиночный выбор
45
45
  * <br> - `Multi` - множественный выбор
46
+ * <br> - `undefined` - без выбора
46
47
  */
47
48
  selectionMode?: SelectionMode;
48
49
  /** Обработчик клика по элементу дерева */
@@ -59,10 +60,20 @@ export type TreeCommonProps = {
59
60
  parentActions?(node: TreeNodeProps): ItemSingleProps[];
60
61
  /** Дополнительные действия для элемента-потомка */
61
62
  nodeActions?(node: TreeNodeProps): ItemSingleProps[];
63
+ /**
64
+ * Флаг отвечающий за отображение иконок у элементов дерева
65
+ * @default true
66
+ */
67
+ showIcons?: boolean;
62
68
  /** Флаг отвечающий за отображение линий вложенности */
63
69
  showLines?: boolean;
64
70
  className?: string;
65
71
  };
72
+ export type TreeView = Omit<TreeCommonProps, 'selected' | 'selectionMode'> & {
73
+ selectionMode?: never;
74
+ selected?: never;
75
+ onSelect?: never;
76
+ };
66
77
  export type TreeSingleSelect = Omit<TreeCommonProps, 'selected'> & {
67
78
  selectionMode: 'single';
68
79
  /** Состояние для выбраного элемента */
@@ -84,4 +95,4 @@ export type TreeMultiSelect = Omit<TreeCommonProps, 'selected'> & {
84
95
  */
85
96
  onSelect?(selectedKeys: TreeNodeId[], node: TreeNodeProps): void;
86
97
  };
87
- export type TreeBaseProps = TreeMultiSelect | TreeSingleSelect;
98
+ export type TreeBaseProps = TreeView | TreeMultiSelect | TreeSingleSelect;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Tree",
7
- "version": "0.3.4",
7
+ "version": "0.5.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -43,5 +43,5 @@
43
43
  "react-transition-state": "2.1.1",
44
44
  "uncontrollable": "8.0.4"
45
45
  },
46
- "gitHead": "57c597a3eebaf6528c0c61b6b27dd244753de1cf"
46
+ "gitHead": "4b0eba6c0cbe808bf637fc77c2b25666e15668e3"
47
47
  }
@@ -2,19 +2,16 @@ import cn from 'classnames';
2
2
 
3
3
  import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
4
4
 
5
- import { SELECTION_MODE } from '../../constants';
6
5
  import { TreeContextProvider } from '../../contexts/TreeContext';
7
6
  import { TreeItem } from '../../helperComponents';
8
- import { SelectionMode, TreeBaseProps, TreeMultiSelect, TreeNodeId, TreeSingleSelect } from '../../types';
7
+ import { TreeBaseProps } from '../../types';
9
8
  import styles from './styles.module.scss';
9
+ import { extractSelectableProps } from './utils';
10
10
 
11
11
  export type TreeProps = WithSupportProps<TreeBaseProps>;
12
12
 
13
13
  export function Tree({
14
14
  data,
15
- selected,
16
- selectionMode,
17
- onSelect,
18
15
  onNodeClick,
19
16
  onExpand,
20
17
  expandedNodes,
@@ -22,6 +19,7 @@ export function Tree({
22
19
  parentActions,
23
20
  onDataLoad,
24
21
  showLines = true,
22
+ showIcons = true,
25
23
  className,
26
24
  ...rest
27
25
  }: TreeProps) {
@@ -30,13 +28,6 @@ export function Tree({
30
28
  <TreeContextProvider
31
29
  value={{
32
30
  data,
33
- selected: selected as SelectionMode extends typeof SELECTION_MODE.Single ? TreeNodeId : TreeNodeId[],
34
- selectionMode: selectionMode as typeof selected extends string
35
- ? typeof SELECTION_MODE.Single
36
- : typeof SELECTION_MODE.Multi,
37
- onSelect: onSelect as SelectionMode extends typeof SELECTION_MODE.Single
38
- ? TreeSingleSelect['onSelect']
39
- : TreeMultiSelect['onSelect'],
40
31
  expandedNodes,
41
32
  onNodeClick,
42
33
  onExpand,
@@ -44,6 +35,8 @@ export function Tree({
44
35
  parentActions,
45
36
  onDataLoad,
46
37
  showLines,
38
+ showIcons,
39
+ ...extractSelectableProps(rest),
47
40
  }}
48
41
  >
49
42
  {data.map((node, index) => (
@@ -0,0 +1,26 @@
1
+ import { SELECTION_MODE } from '../../constants';
2
+ import { TreeBaseProps, TreeMultiSelect, TreeSingleSelect, TreeView } from '../../types';
3
+
4
+ export function extractSelectableProps({
5
+ selectionMode,
6
+ selected,
7
+ onSelect,
8
+ }: Pick<TreeBaseProps, 'selectionMode' | 'selected' | 'onSelect'>) {
9
+ switch (selectionMode) {
10
+ case SELECTION_MODE.Single:
11
+ return {
12
+ selectionMode,
13
+ selected,
14
+ onSelect,
15
+ } as Pick<TreeSingleSelect, 'selectionMode' | 'selected' | 'onSelect'>;
16
+ case SELECTION_MODE.Multi:
17
+ return {
18
+ selectionMode,
19
+ selected,
20
+ onSelect,
21
+ } as Pick<TreeMultiSelect, 'selectionMode' | 'selected' | 'onSelect'>;
22
+ case undefined:
23
+ default:
24
+ return {} as Pick<TreeView, 'selectionMode' | 'selected' | 'onSelect'>;
25
+ }
26
+ }
@@ -12,6 +12,7 @@ type TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeCli
12
12
  onNodeClick: OnNodeClick;
13
13
  isMultiSelect: boolean;
14
14
  isSingleSelect: boolean;
15
+ isSelectable: boolean;
15
16
  focusedNodeId?: TreeNodeId;
16
17
  setFocusPosition(id: TreeNodeId): void;
17
18
  resetFocusPosition(): void;
@@ -39,6 +40,7 @@ export const TreeContext = createContext<TreeContextProps>({
39
40
  focusableNodeIds: [],
40
41
  isMultiSelect: false,
41
42
  isSingleSelect: false,
43
+ isSelectable: false,
42
44
  });
43
45
 
44
46
  export function TreeContextProvider({ children, value }: TreeContextProviderProps) {
@@ -53,6 +55,7 @@ export function TreeContextProvider({ children, value }: TreeContextProviderProp
53
55
 
54
56
  const isMultiSelect = selectionMode === SELECTION_MODE.Multi;
55
57
  const isSingleSelect = selectionMode === SELECTION_MODE.Single;
58
+ const isSelectable = Boolean(selectionMode);
56
59
 
57
60
  const [expandedNodes, onExpandHandler] = useUncontrolledProp<TreeNodeId[]>(
58
61
  value.expandedNodes,
@@ -75,7 +78,7 @@ export function TreeContextProvider({ children, value }: TreeContextProviderProp
75
78
 
76
79
  const onSelect = useCallback<TreeContextProps['onSelect']>(
77
80
  (node, parentNode) => {
78
- if (node.disabled) return;
81
+ if (!isSelectable || node.disabled) return;
79
82
 
80
83
  if (isSingleSelect) {
81
84
  onSelectHandler(node.id, node);
@@ -88,7 +91,7 @@ export function TreeContextProvider({ children, value }: TreeContextProviderProp
88
91
  onSelectHandler(updatedSelectedNodes, node);
89
92
  }
90
93
  },
91
- [isSingleSelect, onSelectHandler, selectedNodes],
94
+ [isSingleSelect, onSelectHandler, selectedNodes, isSelectable],
92
95
  );
93
96
 
94
97
  const focusableNodeIds = useMemo(() => {
@@ -146,6 +149,7 @@ export function TreeContextProvider({ children, value }: TreeContextProviderProp
146
149
  selected: selectedNodes,
147
150
  isSingleSelect,
148
151
  isMultiSelect,
152
+ isSelectable,
149
153
  expandedNodes,
150
154
  onExpand,
151
155
  onSelect,
@@ -46,6 +46,7 @@ export function TreeNode({
46
46
  }: TreeNodeComponentProps) {
47
47
  const {
48
48
  isMultiSelect,
49
+ isSelectable,
49
50
  onNodeClick,
50
51
  selected,
51
52
  expandedNodes,
@@ -58,6 +59,7 @@ export function TreeNode({
58
59
  setFocusIndex,
59
60
  focusableNodeIds,
60
61
  showLines,
62
+ showIcons,
61
63
  } = useTreeContext();
62
64
 
63
65
  const [isDroplistOpen, setDroplistOpen] = useState(false);
@@ -86,12 +88,14 @@ export function TreeNode({
86
88
  }, [isFocused]);
87
89
 
88
90
  const treeNodeIcon = useMemo(() => {
91
+ if (!showIcons) return undefined;
92
+
89
93
  if (isExpandable) {
90
94
  return isExpanded ? expandedIcon : collapsedIcon;
91
95
  }
92
96
 
93
97
  return icon;
94
- }, [isExpandable, icon, isExpanded, expandedIcon, collapsedIcon]);
98
+ }, [showIcons, isExpandable, icon, isExpanded, expandedIcon, collapsedIcon]);
95
99
 
96
100
  const handleClick: TreeNodeProps['onClick'] = e => {
97
101
  onNodeClick(
@@ -230,7 +234,7 @@ export function TreeNode({
230
234
  <div
231
235
  role='treeitem'
232
236
  aria-expanded={isExpanded}
233
- aria-selected={isSelected}
237
+ aria-selected={isSelectable ? isSelected : undefined}
234
238
  aria-disabled={disabled}
235
239
  data-multiselect={isMultiSelect || undefined}
236
240
  data-droplist-active={isDroplistOpen || isDroplistTriggerFocused || undefined}
@@ -258,9 +262,11 @@ export function TreeNode({
258
262
  </div>
259
263
  )}
260
264
 
261
- <div className={styles.treeNodeIcon} data-test-id={TEST_IDS.icon}>
262
- {treeNodeIcon}
263
- </div>
265
+ {treeNodeIcon && (
266
+ <div className={styles.treeNodeIcon} data-test-id={TEST_IDS.icon}>
267
+ {treeNodeIcon}
268
+ </div>
269
+ )}
264
270
 
265
271
  <Typography.SansBodyM tag='div' className={styles.treeNodeTitle}>
266
272
  <TruncateString text={title} data-test-id={TEST_IDS.title} />
@@ -53,8 +53,6 @@
53
53
  box-sizing: border-box;
54
54
  width: 100%;
55
55
 
56
- border-radius: $radius-tree-item-content-layout;
57
-
58
56
  &::before {
59
57
  pointer-events: none;
60
58
  content: '';
package/src/types.ts CHANGED
@@ -52,6 +52,7 @@ export type TreeCommonProps = {
52
52
  * Режим выбора элементов:
53
53
  * <br> - `Single` - одиночный выбор
54
54
  * <br> - `Multi` - множественный выбор
55
+ * <br> - `undefined` - без выбора
55
56
  */
56
57
  selectionMode?: SelectionMode;
57
58
  /** Обработчик клика по элементу дерева */
@@ -68,11 +69,22 @@ export type TreeCommonProps = {
68
69
  parentActions?(node: TreeNodeProps): ItemSingleProps[];
69
70
  /** Дополнительные действия для элемента-потомка */
70
71
  nodeActions?(node: TreeNodeProps): ItemSingleProps[];
72
+ /**
73
+ * Флаг отвечающий за отображение иконок у элементов дерева
74
+ * @default true
75
+ */
76
+ showIcons?: boolean;
71
77
  /** Флаг отвечающий за отображение линий вложенности */
72
78
  showLines?: boolean;
73
79
  className?: string;
74
80
  };
75
81
 
82
+ export type TreeView = Omit<TreeCommonProps, 'selected' | 'selectionMode'> & {
83
+ selectionMode?: never;
84
+ selected?: never;
85
+ onSelect?: never;
86
+ };
87
+
76
88
  export type TreeSingleSelect = Omit<TreeCommonProps, 'selected'> & {
77
89
  selectionMode: 'single';
78
90
  /** Состояние для выбраного элемента */
@@ -96,4 +108,4 @@ export type TreeMultiSelect = Omit<TreeCommonProps, 'selected'> & {
96
108
  onSelect?(selectedKeys: TreeNodeId[], node: TreeNodeProps): void;
97
109
  };
98
110
 
99
- export type TreeBaseProps = TreeMultiSelect | TreeSingleSelect;
111
+ export type TreeBaseProps = TreeView | TreeMultiSelect | TreeSingleSelect;