Skip to content

Commit fb8e621

Browse files
committed
feat: TreeSelect support maxCount
1 parent fb1b6bb commit fb8e621

File tree

6 files changed

+80
-4
lines changed

6 files changed

+80
-4
lines changed

docs/demo/mutiple-with-maxCount.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: mutiple-with-maxCount
3+
nav:
4+
title: Demo
5+
path: /demo
6+
---
7+
8+
<code src="../../examples/mutiple-with-maxCount.tsx"></code>

examples/mutiple-with-maxCount.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import TreeSelect from '../src';
3+
4+
export default () => {
5+
const treeData = [
6+
{
7+
key: '1',
8+
value: '1',
9+
title: '1',
10+
children: [
11+
{
12+
key: '1-1',
13+
value: '1-1',
14+
title: '1-1',
15+
},
16+
],
17+
},
18+
{
19+
key: '2',
20+
value: '2',
21+
title: '2',
22+
},
23+
{
24+
key: '3',
25+
value: '3',
26+
title: '3',
27+
},
28+
{
29+
key: '4',
30+
value: '4',
31+
title: '4',
32+
},
33+
];
34+
const onChange = () => {};
35+
36+
return (
37+
<TreeSelect
38+
style={{ width: 300 }}
39+
multiple
40+
maxCount={3}
41+
treeData={treeData}
42+
onChange={onChange}
43+
/>
44+
);
45+
};

src/OptionList.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as React from 'react';
99
import LegacyContext from './LegacyContext';
1010
import TreeSelectContext from './TreeSelectContext';
1111
import type { Key, SafeKey } from './interface';
12-
import { getAllKeys, isCheckDisabled } from './utils/valueUtil';
12+
import { getAllKeys, isCheckDisabled, isValidCount } from './utils/valueUtil';
1313

1414
const HIDDEN_STYLE = {
1515
width: 0,
@@ -45,6 +45,7 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
4545
treeExpandAction,
4646
treeTitleRender,
4747
onPopupScroll,
48+
maxCount,
4849
} = React.useContext(TreeSelectContext);
4950

5051
const {
@@ -76,6 +77,11 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
7677
(prev, next) => next[0] && prev[1] !== next[1],
7778
);
7879

80+
const isOverMaxCount = React.useMemo<boolean>(
81+
() => multiple && isValidCount(maxCount) && checkedKeys.length >= maxCount,
82+
[checkedKeys, maxCount, multiple],
83+
);
84+
7985
// ========================== Active ==========================
8086
const [activeKey, setActiveKey] = React.useState<Key>(null);
8187
const activeEntity = keyEntities[activeKey as SafeKey];
@@ -150,8 +156,13 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
150156
return;
151157
}
152158

159+
const isSelected = !checkedKeys.includes(node.key);
160+
if (maxCount && isSelected && checkedKeys.length >= maxCount) {
161+
return;
162+
}
163+
153164
onSelect(node.key, {
154-
selected: !checkedKeys.includes(node.key),
165+
selected: isSelected,
155166
});
156167

157168
if (!multiple) {
@@ -197,10 +208,10 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
197208
}));
198209

199210
const loadDataFun = useMemo(
200-
() => searchValue ? null : (loadData as any),
211+
() => (searchValue ? null : (loadData as any)),
201212
[searchValue, treeExpandedKeys || expandedKeys],
202213
([preSearchValue], [nextSearchValue, nextExcludeSearchExpandedKeys]) =>
203-
preSearchValue !== nextSearchValue && !!(nextSearchValue || nextExcludeSearchExpandedKeys)
214+
preSearchValue !== nextSearchValue && !!(nextSearchValue || nextExcludeSearchExpandedKeys),
204215
);
205216

206217
// ========================== Render ==========================

src/TreeSelect.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export interface TreeSelectProps<ValueType = any, OptionType extends DataNode =
7272
treeCheckable?: boolean | React.ReactNode;
7373
treeCheckStrictly?: boolean;
7474
labelInValue?: boolean;
75+
maxCount?: number;
7576

7677
// >>> Data
7778
treeData?: OptionType[];
@@ -136,6 +137,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
136137
treeCheckable,
137138
treeCheckStrictly,
138139
labelInValue,
140+
maxCount,
139141

140142
// FieldNames
141143
fieldNames,
@@ -507,6 +509,10 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
507509
// Single mode always set value
508510
triggerChange([selectedValue], { selected: true, triggerValue: selectedValue }, 'option');
509511
} else {
512+
if (maxCount && selected && rawValues.length >= maxCount) {
513+
return;
514+
}
515+
510516
let newRawValues = selected
511517
? [...rawValues, selectedValue]
512518
: rawCheckedValues.filter(v => v !== selectedValue);
@@ -609,6 +615,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
609615
treeExpandAction,
610616
treeTitleRender,
611617
onPopupScroll,
618+
maxCount,
612619
}),
613620
[
614621
virtual,
@@ -622,6 +629,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
622629
treeExpandAction,
623630
treeTitleRender,
624631
onPopupScroll,
632+
maxCount,
625633
],
626634
);
627635

src/TreeSelectContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface TreeSelectContextProps {
1414
treeExpandAction?: ExpandAction;
1515
treeTitleRender?: (node: any) => React.ReactNode;
1616
onPopupScroll?: React.UIEventHandler<HTMLDivElement>;
17+
maxCount?: number;
1718
}
1819

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

src/utils/valueUtil.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ export const getAllKeys = (treeData: DataNode[], fieldNames: FieldNames): SafeKe
3535
};
3636

3737
export const isNil = (val: any): boolean => val === null || val === undefined;
38+
39+
export const isValidCount = (value?: number) =>
40+
typeof value !== 'undefined' && !Number.isNaN(value);

0 commit comments

Comments
 (0)