@snack-uikit/tree 0.6.26-preview-4f9628fc.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 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 TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeClick' | 'selected' | 'selectionMode'> & {
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: TreeBaseProps;
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 || !Array.isArray(selected) || !(selected === null || selected === void 0 ? void 0 : selected.length))
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 && (_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: {
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-4f9628fc.0",
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.1-preview-4f9628fc.0",
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": "e3e8e7afe206788b86b25e19eff757fb3e67ce05"
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 TreeContextProps = Omit<TreeBaseProps, 'onSelect' | 'onExpand' | 'onNodeClick' | 'selected' | 'selectionMode'> & {
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: TreeBaseProps;
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 || !Array.isArray(selected) || !selected?.length) return undefined;
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
- <div className={styles.treeNodeCheckboxWrap}>
252
- <Checkbox
253
- size='s'
254
- disabled={disabled}
255
- checked={!disabled && isSelected}
256
- indeterminate={!disabled && !isSelected && nestedNodesSelection?.someSelected}
257
- onChange={handleSelect}
258
- onClick={stopPropagationClick}
259
- data-test-id={TEST_IDS.checkbox}
260
- tabIndex={-1}
261
- />
262
- </div>
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
- <TruncateString text={title} data-test-id={TEST_IDS.title} />
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'> & {