Skip to content

Commit 82ca669

Browse files
RylanBotgithub-actions[bot]uyarn
authored
fix(Tree): update checked state logic to consider indeterminate nodes (#3828)
* fix(Tree): update checked state logic to consider indeterminate nodes * chore: update demo * fix(Tree): update disableCheck logic * chore: update snapshots * chore: update CHANGELOG.md * docs: add checkable and strictly mode switches to lazy example * chore: update CHANGELOG.md * chore: sync common * chore: update common * chore: demo * fix(Tree): improve checked state logic in handleChange * chore: update snapshot --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: wū yāng <[email protected]>
1 parent 17eb52f commit 82ca669

File tree

9 files changed

+194
-46
lines changed

9 files changed

+194
-46
lines changed

packages/components/tree/Tree.tsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
import React, {
22
forwardRef,
3-
useState,
3+
MouseEvent,
4+
RefObject,
5+
useCallback,
46
useImperativeHandle,
57
useMemo,
6-
RefObject,
7-
MouseEvent,
88
useRef,
9-
useCallback,
9+
useState,
1010
} from 'react';
1111
import { CSSTransition, TransitionGroup } from 'react-transition-group';
1212
import classNames from 'classnames';
1313
import { get } from 'lodash-es';
1414

15-
import TreeNode from '@tdesign/common-js/tree-v1/tree-node';
1615
import log from '@tdesign/common-js/log/index';
16+
import TreeNode from '@tdesign/common-js/tree-v1/tree-node';
1717
import type {
1818
TreeNodeState,
1919
TreeNodeValue,
2020
TypeTreeNodeData,
2121
TypeTreeNodeModel,
2222
} from '@tdesign/common-js/tree-v1/types';
23-
import { TreeOptionData, StyledProps, ComponentScrollToElementParams } from '../common';
24-
import { TreeItemProps } from './interface';
25-
import TreeItem from './TreeItem';
2623

24+
import parseTNode from '../_util/parseTNode';
25+
import useDefaultProps from '../hooks/useDefaultProps';
26+
import { usePersistFn } from '../hooks/usePersistFn';
27+
import { treeDefaultProps } from './defaultProps';
28+
import { TreeDraggableContext } from './hooks/TreeDraggableContext';
2729
import useControllable from './hooks/useControllable';
2830
import { useStore } from './hooks/useStore';
2931
import { useTreeConfig } from './hooks/useTreeConfig';
30-
import { TreeDraggableContext } from './hooks/TreeDraggableContext';
31-
import parseTNode from '../_util/parseTNode';
32-
import { usePersistFn } from '../hooks/usePersistFn';
3332
import useTreeVirtualScroll from './hooks/useTreeVirtualScroll';
33+
import TreeItem from './TreeItem';
3434

35-
import type { TreeInstanceFunctions, TdTreeProps } from './type';
36-
import { treeDefaultProps } from './defaultProps';
37-
import useDefaultProps from '../hooks/useDefaultProps';
35+
import type { ComponentScrollToElementParams, StyledProps, TreeOptionData } from '../common';
36+
import type { TreeItemProps } from './interface';
37+
import type { TdTreeProps, TreeInstanceFunctions } from './type';
3838

3939
export type TreeProps = TdTreeProps & StyledProps;
4040

@@ -179,11 +179,12 @@ const Tree = forwardRef<TreeInstanceFunctions<TreeOptionData>, TreeProps>((origi
179179
};
180180

181181
const handleChange: TreeItemProps['onChange'] = (node, ctx) => {
182-
if (!node || disabled || node.disabled) {
183-
return;
184-
}
185-
setChecked(node, !node.isChecked(), { ...ctx, trigger: 'node-click' });
182+
if (!node || disabled || node.disabled) return;
183+
const checked = node.toggleChecked();
184+
const treeNodeModel = node?.getModel();
185+
onChange?.(checked, { node: treeNodeModel, ...ctx, trigger: 'node-click' });
186186
};
187+
187188
const handleScrollToElement = useCallback(
188189
(params: ComponentScrollToElementParams) => {
189190
let { index } = params;

packages/components/tree/TreeItem.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ const TreeItem = forwardRef(
5050
expandOnClickNode,
5151
activable,
5252
checkProps,
53-
disableCheck,
5453
operations,
5554
onClick,
5655
onChange,
@@ -242,32 +241,20 @@ const TreeItem = forwardRef(
242241
});
243242

244243
if (node.isCheckable()) {
245-
let checkboxDisabled: boolean;
246-
if (typeof disableCheck === 'function') {
247-
checkboxDisabled = disableCheck(node.getModel());
248-
} else {
249-
checkboxDisabled = !!disableCheck;
250-
}
251-
252-
if (node.isDisabled()) {
253-
checkboxDisabled = true;
254-
}
255-
256244
let checkboxProps: CheckboxProps;
257245
if (typeof checkProps === 'function') {
258246
checkboxProps = checkProps(node.getModel());
259247
} else {
260248
checkboxProps = checkProps;
261249
}
262-
263250
return (
264251
<Checkbox
265252
ref={setRefCurrent}
266253
checked={node.checked}
267254
indeterminate={node.indeterminate}
268-
disabled={checkboxDisabled}
255+
disabled={node.disabled}
269256
name={String(node.value)}
270-
onChange={(checked, ctx) => onChange(node, ctx)}
257+
onChange={(_, ctx) => onChange(node, ctx)}
271258
className={labelClasses}
272259
stopLabelTrigger={expandOnClickNode && !!node.children}
273260
{...checkboxProps}

packages/components/tree/_example/lazy.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from 'react';
2-
import { Tree } from 'tdesign-react';
1+
import React, { useState } from 'react';
2+
import { Space, Switch, Tree } from 'tdesign-react';
33
import type { TreeProps } from 'tdesign-react';
44

55
const items = [
@@ -14,6 +14,9 @@ const items = [
1414
];
1515

1616
export default () => {
17+
const [checkable, setCheckable] = useState(true);
18+
const [strictly, setStrictly] = useState(false);
19+
1720
const load: TreeProps['load'] = (node) =>
1821
new Promise((resolve) => {
1922
setTimeout(() => {
@@ -38,5 +41,23 @@ export default () => {
3841
console.log('on load:', state);
3942
};
4043

41-
return <Tree data={items} hover expandAll load={load} onLoad={handleLoad} />;
44+
return (
45+
<Space direction="vertical">
46+
<Space>
47+
可选: <Switch value={checkable} onChange={(value) => setCheckable(value)} />
48+
</Space>
49+
<Space>
50+
严格模式: <Switch value={checkable} onChange={(value) => setStrictly(value)} />
51+
</Space>
52+
<Tree
53+
hover
54+
valueMode="all"
55+
data={items}
56+
checkable={checkable}
57+
checkStrictly={strictly}
58+
load={load}
59+
onLoad={handleLoad}
60+
/>
61+
</Space>
62+
);
4263
};

packages/components/tree/_example/operations.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const items = [
88
},
99
{
1010
value: 'node2',
11+
disabled: true,
1112
},
1213
];
1314

@@ -21,6 +22,7 @@ export default () => {
2122
const [expandParent, setExpandParent] = useState(false);
2223
const [filterText, setFilterText] = useState('');
2324
const [activeIds, setActiveIds] = useState([]);
25+
const [checkStrictly, setCheckStrictly] = useState(false);
2426

2527
const getLabelContent = (node: TreeNodeModel) => {
2628
const pathNodes = node.getPath();
@@ -114,6 +116,22 @@ export default () => {
114116
}
115117
};
116118

119+
const canToggleDisable = (node: TreeNodeModel) => {
120+
const parent = node.getParent?.();
121+
const isCheckStrictly = false; // 默认关闭
122+
if (!isCheckStrictly && parent?.disabled) {
123+
return false; // 父节点被禁用时,子节点状态不支持手动改变
124+
}
125+
return true;
126+
};
127+
128+
const toggleDisable = (node: TreeNodeModel) => {
129+
treeRef.current.setItem(node.value, {
130+
disabled: !node.disabled,
131+
});
132+
console.log(treeRef.current.getItems(node.value));
133+
};
134+
117135
const remove = (node: TreeNodeModel) => {
118136
treeRef.current.remove(node.value);
119137
};
@@ -129,6 +147,16 @@ export default () => {
129147
<Button style={{ marginLeft: '10px' }} size="small" variant="outline" onClick={() => insertAfter(node)}>
130148
后插节点
131149
</Button>
150+
<Button
151+
style={{ marginLeft: '10px' }}
152+
size="small"
153+
variant="base"
154+
theme={node.disabled ? 'success' : 'warning'}
155+
disabled={!canToggleDisable(node)}
156+
onClick={() => toggleDisable(node)}
157+
>
158+
{node.disabled ? 'enable' : 'disable'}
159+
</Button>
132160
<Button style={{ marginLeft: '10px' }} size="small" variant="base" theme="danger" onClick={() => remove(node)}>
133161
删除
134162
</Button>
@@ -291,6 +319,10 @@ export default () => {
291319
<Space direction="vertical">
292320
<style>{`.tdesign-tree-operations .t-is-active .t-tree__label { background-color: rgba(0, 0, 255, 0.2);}`}</style>
293321
<Space direction="vertical">
322+
<Space>
323+
<span>严格模式</span>
324+
<Switch<boolean> value={checkStrictly} onChange={setCheckStrictly} />
325+
</Space>
294326
<Space>
295327
<span>允许多个节点同时高亮</span>
296328
<Switch<boolean> value={activeMultiple} onChange={setActiveMultiple} />
@@ -316,7 +348,7 @@ export default () => {
316348
expandAll
317349
activable
318350
checkable
319-
checkStrictly
351+
checkStrictly={checkStrictly}
320352
line
321353
allowFoldNodeOnFilter
322354
data={items}

packages/components/tree/hooks/useStore.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export function useStore(
2929
activeMultiple,
3030
actived,
3131
disabled,
32+
disableCheck,
3233
draggable,
3334
checkable,
3435
value,
@@ -109,6 +110,7 @@ export function useStore(
109110
expandMutex,
110111
expandParent,
111112
disabled,
113+
disableCheck,
112114
draggable,
113115
load,
114116
lazy,
@@ -185,6 +187,7 @@ export function useStore(
185187
activable,
186188
activeMultiple,
187189
disabled,
190+
disableCheck,
188191
checkable,
189192
draggable,
190193
checkStrictly,
@@ -201,6 +204,7 @@ export function useStore(
201204
draggable,
202205
checkable,
203206
disabled,
207+
disableCheck,
204208
expandAll,
205209
expandLevel,
206210
expandMutex,

packages/tdesign-react/CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ spline: explain
9292
### 🐞 Bug Fixes
9393
- `Tree`: @RylanBot ([#3756](https://github.com/Tencent/tdesign-react/pull/3756))
9494
- 修正节点属性 `date-target` 单词拼写为 `data-target`,之前有使用该属性的业务请注意此变更 ⚠️
95-
- 修复拖拽后展开收起图标展示异常的问题
95+
- 修复拖拽后展开收起图标展示异常的问题
9696
- `MessagePlugin`: 修复 `content``''` / `undefined` / `null` 时产生的报错 @RylanBot ([#3778](https://github.com/Tencent/tdesign-react/pull/3778))
97-
- `Table`: 修复未开启 `<React.StrictMode>` 时,`Loading` 挂载导致的页面闪烁问题 @RylanBot ([#3775](https://github.com/Tencent/tdesign-react/pull/3775))
97+
- `Table`:
98+
- 修复未开启 `<React.StrictMode>` 时,`Loading` 挂载导致的页面闪烁问题 @RylanBot ([#3775](https://github.com/Tencent/tdesign-react/pull/3775))
99+
- 修复 `size='small'``firstFullRow` 尺寸比 `size='medium'` 大的异常 ([#common2253](https://github.com/Tencent/tdesign-common/pull/2253))
98100
- `Upload`: 修复拖拽模式下 `status` 更新错误 @RSS1102 ([#3801](https://github.com/Tencent/tdesign-react/pull/3801))
99101
- `Input`: 修复在开启 `readonly` 或者禁用 `allowInput` 情况下没有触发 `onFocus``onBlur` 的问题 @RylanBot ([#3800](https://github.com/Tencent/tdesign-react/pull/3800))
100102
- `Cascader`:

0 commit comments

Comments
 (0)