Skip to content

Commit 6193365

Browse files
committed
feat: supplement maxCount logic for complicated cases
1 parent a1284ba commit 6193365

File tree

4 files changed

+76
-3
lines changed

4 files changed

+76
-3
lines changed

examples/mutiple-with-maxCount.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ export default () => {
2020
key: '1-2',
2121
value: '1-2',
2222
title: '1-2',
23+
disabled: true,
24+
children: [
25+
{
26+
key: '1-2-1',
27+
value: '1-2-1',
28+
title: '1-2-1',
29+
disabled: true,
30+
},
31+
{
32+
key: '1-2-2',
33+
value: '1-2-2',
34+
title: '1-2-2',
35+
},
36+
],
2337
},
2438
{
2539
key: '1-3',
@@ -70,8 +84,7 @@ export default () => {
7084
multiple
7185
treeCheckable
7286
// showCheckedStrategy="SHOW_ALL"
73-
showCheckedStrategy="SHOW_PARENT"
74-
// showCheckedStrategy="SHOW_CHILD"
87+
// showCheckedStrategy="SHOW_PARENT"
7588
maxCount={4}
7689
treeData={treeData}
7790
onChange={onChange}

src/OptionList.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import TreeSelectContext from './TreeSelectContext';
1212
import type { DataNode, Key, SafeKey } from './interface';
1313
import { getAllKeys, isCheckDisabled } from './utils/valueUtil';
1414
import { useEvent } from 'rc-util';
15+
import { formatStrategyValues } from './utils/strategyUtil';
16+
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
1517

1618
const HIDDEN_STYLE = {
1719
width: 0,
@@ -49,6 +51,8 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
4951
onPopupScroll,
5052
displayValues,
5153
isOverMaxCount,
54+
maxCount,
55+
showCheckedStrategy,
5256
} = React.useContext(TreeSelectContext);
5357

5458
const {
@@ -164,7 +168,57 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
164168
}, [searchValue]);
165169

166170
const nodeDisabled = useEvent((node: DataNode) => {
167-
return isOverMaxCount && !memoRawValues.includes(node[fieldNames.value]);
171+
// Always enable selected nodes
172+
if (checkedKeys.includes(node[fieldNames.value])) {
173+
return false;
174+
}
175+
176+
// Get all selectable keys under current node considering conduction rules
177+
const getSelectableKeys = (nodes: DataNode[]) => {
178+
const keys: Key[] = [];
179+
const traverse = (n: DataNode) => {
180+
if (!n.disabled) {
181+
keys.push(n[fieldNames.value]);
182+
// Only traverse children if node is not disabled
183+
if (Array.isArray(n.children)) {
184+
n.children.forEach(traverse);
185+
}
186+
}
187+
};
188+
nodes.forEach(traverse);
189+
return keys;
190+
};
191+
192+
const selectableNodeValues = getSelectableKeys([node]);
193+
194+
// Simulate checked state after selecting current node
195+
const simulatedCheckedKeys = [...checkedKeys, ...selectableNodeValues];
196+
197+
const { checkedKeys: conductedKeys } = conductCheck(simulatedCheckedKeys, true, keyEntities);
198+
199+
// Calculate display keys based on strategy
200+
const simulatedDisplayKeys = formatStrategyValues(
201+
conductedKeys as SafeKey[],
202+
showCheckedStrategy,
203+
keyEntities,
204+
fieldNames,
205+
);
206+
207+
const currentDisplayKeys = formatStrategyValues(
208+
checkedKeys as SafeKey[],
209+
showCheckedStrategy,
210+
keyEntities,
211+
fieldNames,
212+
);
213+
214+
const newDisplayValuesCount = simulatedDisplayKeys.length - currentDisplayKeys.length;
215+
216+
// Check if selecting this node would exceed maxCount
217+
if (isOverMaxCount || memoRawValues.length + newDisplayValuesCount > maxCount) {
218+
return true;
219+
}
220+
221+
return false;
168222
});
169223

170224
// ========================== Get First Selectable Node ==========================

src/TreeSelect.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
625625
onPopupScroll,
626626
displayValues: cachedDisplayValues,
627627
isOverMaxCount,
628+
maxCount,
629+
showCheckedStrategy: mergedShowCheckedStrategy,
628630
};
629631
}, [
630632
virtual,
@@ -641,6 +643,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
641643
maxCount,
642644
cachedDisplayValues,
643645
mergedMultiple,
646+
mergedShowCheckedStrategy,
644647
]);
645648

646649
// ======================= Legacy Context =======================

src/TreeSelectContext.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import type { ExpandAction } from 'rc-tree/lib/Tree';
33
import type { DataNode, FieldNames, Key, LabeledValueType } from './interface';
4+
import { CheckedStrategy } from './utils/strategyUtil';
45

56
export interface TreeSelectContextProps {
67
virtual?: boolean;
@@ -16,6 +17,8 @@ export interface TreeSelectContextProps {
1617
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
1718
displayValues?: LabeledValueType[];
1819
isOverMaxCount?: boolean;
20+
maxCount?: number;
21+
showCheckedStrategy?: CheckedStrategy;
1922
}
2023

2124
const TreeSelectContext = React.createContext<TreeSelectContextProps>(null as any);

0 commit comments

Comments
 (0)