@capillarytech/blaze-ui 0.1.6-alpha.60 → 0.1.6-alpha.61
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/.DS_Store +0 -0
- package/CapUnifiedSelect/CapUnifiedSelect.js +303 -442
- package/package.json +1 -1
package/.DS_Store
ADDED
|
Binary file
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Enhanced CapUnifiedSelect supporting 4 scenarios with advanced features in a single TreeSelect
|
|
2
1
|
import React, { useState, useEffect, useMemo, useCallback, memo } from 'react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
3
|
import classnames from 'classnames';
|
|
@@ -14,6 +13,121 @@ const StyledTreeSelect = styled(TreeSelect)`
|
|
|
14
13
|
${selectStyles}
|
|
15
14
|
`;
|
|
16
15
|
|
|
16
|
+
const NoResult = memo(({ noResultCustomText, className, showUpload, options, noResultCustomIcon }) => (
|
|
17
|
+
<CapRow
|
|
18
|
+
className={classnames(className, 'cap-unified-select-no-result')}
|
|
19
|
+
align="middle"
|
|
20
|
+
gap={8}
|
|
21
|
+
>
|
|
22
|
+
<CapIcon type={noResultCustomIcon} size="m" />
|
|
23
|
+
<CapLabel className="cap-unified-select-no-result-text">
|
|
24
|
+
{showUpload && options?.length === 0
|
|
25
|
+
? noResultCustomText
|
|
26
|
+
: 'No results found'}
|
|
27
|
+
</CapLabel>
|
|
28
|
+
</CapRow>
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
const SelectAllCheckbox = memo(({ currentItems, tempValue, setTempValue, processTreeData }) => {
|
|
32
|
+
const { leafValues } = processTreeData(currentItems);
|
|
33
|
+
const totalAvailable = leafValues.length;
|
|
34
|
+
const leafSet = new Set(leafValues);
|
|
35
|
+
const selectedInScope = Array.isArray(tempValue)
|
|
36
|
+
? tempValue.filter((v) => leafSet.has(v)).length
|
|
37
|
+
: 0;
|
|
38
|
+
|
|
39
|
+
const allChecked = totalAvailable > 0 && selectedInScope === totalAvailable;
|
|
40
|
+
const indeterminate = selectedInScope > 0 && selectedInScope < totalAvailable;
|
|
41
|
+
|
|
42
|
+
const handleChange = (e) => {
|
|
43
|
+
if (e.target.checked) {
|
|
44
|
+
const merged = new Set(Array.isArray(tempValue) ? tempValue : []);
|
|
45
|
+
leafValues.forEach((v) => merged.add(v));
|
|
46
|
+
setTempValue(Array.from(merged));
|
|
47
|
+
} else {
|
|
48
|
+
const toRemove = new Set(leafValues);
|
|
49
|
+
const next = (Array.isArray(tempValue) ? tempValue : []).filter(
|
|
50
|
+
(v) => !toRemove.has(v)
|
|
51
|
+
);
|
|
52
|
+
setTempValue(next);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<CapRow className="cap-unified-select-select-all-container" align="middle">
|
|
58
|
+
<Checkbox
|
|
59
|
+
className="cap-unified-select-select-all-checkbox"
|
|
60
|
+
checked={allChecked}
|
|
61
|
+
indeterminate={indeterminate}
|
|
62
|
+
onChange={handleChange}
|
|
63
|
+
>
|
|
64
|
+
<CapLabel type="label14" className="cap-unified-select-select-all-label">Select all</CapLabel>
|
|
65
|
+
</Checkbox>
|
|
66
|
+
</CapRow>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const buildTreeMaps = (nodes) => {
|
|
71
|
+
const result = {
|
|
72
|
+
leafValues: [],
|
|
73
|
+
parentChildMap: {},
|
|
74
|
+
nodeMap: {},
|
|
75
|
+
};
|
|
76
|
+
if (!nodes) return result;
|
|
77
|
+
|
|
78
|
+
const traverse = (items) => {
|
|
79
|
+
items.forEach((item) => {
|
|
80
|
+
result.nodeMap[item.value] = item;
|
|
81
|
+
if (item.children && item.children.length > 0) {
|
|
82
|
+
result.parentChildMap[item.value] = item.children.map(child => child.value);
|
|
83
|
+
traverse(item.children);
|
|
84
|
+
} else {
|
|
85
|
+
result.leafValues.push(item.value);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
traverse(nodes);
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const countSelectedLeaves = (treeMaps, selectedValues) => {
|
|
94
|
+
if (!Array.isArray(selectedValues) || !selectedValues.length) return 0;
|
|
95
|
+
const expandedSet = new Set(selectedValues);
|
|
96
|
+
const processNode = (value) => {
|
|
97
|
+
const children = treeMaps.parentChildMap[value];
|
|
98
|
+
if (!children) return;
|
|
99
|
+
children.forEach(childValue => {
|
|
100
|
+
expandedSet.add(childValue);
|
|
101
|
+
processNode(childValue);
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
selectedValues.forEach(processNode);
|
|
105
|
+
return treeMaps.leafValues.reduce((count, leaf) => expandedSet.has(leaf) ? count + 1 : count, 0);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const filterTreeData = (data, search, searchBasedOn) => {
|
|
109
|
+
if (!data?.length || !search) return data;
|
|
110
|
+
const searchLower = search.toLowerCase();
|
|
111
|
+
const nodeMatchesSearch = (node) => {
|
|
112
|
+
const target = searchBasedOn === 'value'
|
|
113
|
+
? String(node.value ?? '')
|
|
114
|
+
: searchBasedOn === 'key'
|
|
115
|
+
? String(node.key ?? '')
|
|
116
|
+
: String(node.label ?? node.title ?? '');
|
|
117
|
+
return target.toLowerCase().includes(searchLower);
|
|
118
|
+
};
|
|
119
|
+
const loop = (items) =>
|
|
120
|
+
items.reduce((acc, item) => {
|
|
121
|
+
if (!item) return acc;
|
|
122
|
+
const children = item.children?.length ? loop(item.children) : [];
|
|
123
|
+
if (nodeMatchesSearch(item) || children.length) {
|
|
124
|
+
acc.push({ ...item, children });
|
|
125
|
+
}
|
|
126
|
+
return acc;
|
|
127
|
+
}, []);
|
|
128
|
+
return loop(data);
|
|
129
|
+
};
|
|
130
|
+
|
|
17
131
|
const CapUnifiedSelect = ({
|
|
18
132
|
type,
|
|
19
133
|
options = [],
|
|
@@ -38,7 +152,6 @@ const CapUnifiedSelect = ({
|
|
|
38
152
|
searchBasedOn = 'label',
|
|
39
153
|
onConfirm,
|
|
40
154
|
onCancel,
|
|
41
|
-
size = 'm',
|
|
42
155
|
noResultCustomText = 'No results found',
|
|
43
156
|
noResultCustomIcon = 'warning',
|
|
44
157
|
...rest
|
|
@@ -48,142 +161,17 @@ const CapUnifiedSelect = ({
|
|
|
48
161
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
49
162
|
|
|
50
163
|
useEffect(() => {
|
|
51
|
-
|
|
164
|
+
const isEqual = Array.isArray(value) && Array.isArray(tempValue)
|
|
165
|
+
? value.length === tempValue.length && value.every((v) => tempValue.includes(v))
|
|
166
|
+
: value === tempValue;
|
|
167
|
+
if (!isEqual) setTempValue(value);
|
|
52
168
|
}, [value]);
|
|
53
169
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
listItemHeight: 32,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const NoResult = ({ noResultCustomText, className, showUpload, options }) => (
|
|
60
|
-
<CapRow
|
|
61
|
-
className={classnames(className, 'cap-unified-select-no-result')}
|
|
62
|
-
align="middle"
|
|
63
|
-
gap={8}
|
|
64
|
-
>
|
|
65
|
-
<CapIcon type={noResultCustomIcon} size="m" />
|
|
66
|
-
<CapLabel className="cap-unified-select-no-result-text">
|
|
67
|
-
{showUpload && options?.length === 0
|
|
68
|
-
? noResultCustomText
|
|
69
|
-
: 'No results found'}
|
|
70
|
-
</CapLabel>
|
|
71
|
-
</CapRow>
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const getFilteredTreeData = useCallback(
|
|
75
|
-
(data, search) => {
|
|
76
|
-
if (!search || !data || data.length === 0) return data;
|
|
77
|
-
const searchLower = search.toLowerCase();
|
|
78
|
-
|
|
79
|
-
const filterNode = (node) => {
|
|
80
|
-
if (!node) return false;
|
|
81
|
-
|
|
82
|
-
let textToSearch = '';
|
|
83
|
-
|
|
84
|
-
if (searchBasedOn === 'value') {
|
|
85
|
-
textToSearch = String(node.value || '').toLowerCase();
|
|
86
|
-
} else if (searchBasedOn === 'key') {
|
|
87
|
-
textToSearch = String(node.key || '').toLowerCase();
|
|
88
|
-
} else {
|
|
89
|
-
textToSearch = String(node.label || node.title || '').toLowerCase();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return textToSearch.includes(searchLower);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const loop = (data) => {
|
|
96
|
-
if (!data) return [];
|
|
97
|
-
|
|
98
|
-
return data
|
|
99
|
-
.map((item) => {
|
|
100
|
-
if (!item) return null;
|
|
101
|
-
|
|
102
|
-
const children =
|
|
103
|
-
item.children && item.children.length > 0
|
|
104
|
-
? loop(item.children)
|
|
105
|
-
: [];
|
|
106
|
-
|
|
107
|
-
if (filterNode(item) || children.length > 0) {
|
|
108
|
-
return { ...item, children };
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
})
|
|
112
|
-
.filter(Boolean);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return loop(data);
|
|
116
|
-
},
|
|
117
|
-
[searchBasedOn],
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
const processTreeData = useCallback((nodes, selectedValues = null) => {
|
|
121
|
-
const result = {
|
|
122
|
-
leafValues: [],
|
|
123
|
-
parentChildMap: {},
|
|
124
|
-
nodeMap: {},
|
|
125
|
-
selectedCount: 0,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
if (!nodes) return result;
|
|
129
|
-
|
|
130
|
-
const traverse = (items) => {
|
|
131
|
-
items.forEach((item) => {
|
|
132
|
-
result.nodeMap[item.value] = item;
|
|
133
|
-
|
|
134
|
-
if (item.children && item.children.length > 0) {
|
|
135
|
-
result.parentChildMap[item.value] = item.children.map(
|
|
136
|
-
(child) => child.value,
|
|
137
|
-
);
|
|
138
|
-
traverse(item.children);
|
|
139
|
-
} else {
|
|
140
|
-
result.leafValues.push(item.value);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
};
|
|
144
|
-
traverse(nodes);
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
selectedValues &&
|
|
148
|
-
Array.isArray(selectedValues) &&
|
|
149
|
-
selectedValues.length > 0
|
|
150
|
-
) {
|
|
151
|
-
const expandedSet = new Set(selectedValues);
|
|
152
|
-
|
|
153
|
-
const processNode = (value) => {
|
|
154
|
-
const children = result.parentChildMap[value];
|
|
155
|
-
if (!children) return;
|
|
156
|
-
|
|
157
|
-
children.forEach((childValue) => {
|
|
158
|
-
expandedSet.add(childValue);
|
|
159
|
-
processNode(childValue);
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
selectedValues.forEach(processNode);
|
|
164
|
-
|
|
165
|
-
result.leafValues.forEach((value) => {
|
|
166
|
-
if (expandedSet.has(value)) result.selectedCount++;
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return result;
|
|
171
|
-
}, []);
|
|
172
|
-
|
|
173
|
-
const isMulti = useMemo(
|
|
174
|
-
() => type === 'multiSelect' || type === 'multiTreeSelect',
|
|
175
|
-
[type],
|
|
176
|
-
);
|
|
177
|
-
const isTree = useMemo(
|
|
178
|
-
() => type === 'treeSelect' || type === 'multiTreeSelect',
|
|
179
|
-
[type],
|
|
180
|
-
);
|
|
170
|
+
const isMulti = useMemo(() => type === 'multiSelect' || type === 'multiTreeSelect', [type]);
|
|
171
|
+
const isTree = useMemo(() => type === 'treeSelect' || type === 'multiTreeSelect', [type]);
|
|
181
172
|
|
|
182
173
|
const dataSource = useMemo(() => {
|
|
183
|
-
|
|
184
|
-
if (!options || options.length === 0) return [];
|
|
185
|
-
|
|
186
|
-
// Only transform if not a tree select
|
|
174
|
+
if (!options?.length) return [];
|
|
187
175
|
return isTree
|
|
188
176
|
? options
|
|
189
177
|
: options.map((opt) => ({
|
|
@@ -193,88 +181,69 @@ const CapUnifiedSelect = ({
|
|
|
193
181
|
}));
|
|
194
182
|
}, [isTree, options]);
|
|
195
183
|
|
|
196
|
-
const filteredTree = useMemo(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return getFilteredTreeData(dataSource, searchText);
|
|
201
|
-
}, [dataSource, searchText, getFilteredTreeData]);
|
|
202
|
-
|
|
203
|
-
const handleConfirm = useCallback(() => {
|
|
204
|
-
if (onChange) onChange(tempValue);
|
|
205
|
-
setDropdownOpen(false);
|
|
206
|
-
if (onConfirm) onConfirm(tempValue);
|
|
207
|
-
}, [onChange, onConfirm, tempValue]);
|
|
208
|
-
|
|
209
|
-
const handleCancel = useCallback(() => {
|
|
210
|
-
setTempValue(value);
|
|
211
|
-
setDropdownOpen(false);
|
|
212
|
-
if (onCancel) onCancel();
|
|
213
|
-
}, [value, onCancel]);
|
|
184
|
+
const filteredTree = useMemo(
|
|
185
|
+
() => filterTreeData(dataSource, searchText, searchBasedOn),
|
|
186
|
+
[dataSource, searchText, searchBasedOn]
|
|
187
|
+
);
|
|
214
188
|
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
}, []);
|
|
189
|
+
const treeMaps = useMemo(() => buildTreeMaps(options), [options]);
|
|
190
|
+
const selectedLeafCount = useMemo(() => countSelectedLeaves(treeMaps, tempValue), [treeMaps, tempValue]);
|
|
218
191
|
|
|
219
|
-
const
|
|
220
|
-
(open) => {
|
|
221
|
-
if (open === false && !customPopupRender) {
|
|
222
|
-
if (onChange) onChange(tempValue);
|
|
223
|
-
} else if (open === false) {
|
|
224
|
-
setTempValue(value);
|
|
225
|
-
}
|
|
226
|
-
setDropdownOpen(open);
|
|
227
|
-
},
|
|
228
|
-
[value, onChange, tempValue, customPopupRender],
|
|
229
|
-
);
|
|
192
|
+
const displayValue = dropdownOpen ? tempValue : value;
|
|
230
193
|
|
|
231
194
|
const suffix = useMemo(() => {
|
|
232
|
-
const
|
|
233
|
-
const showMore = isMulti && Array.isArray(displayValue) && displayValue.length > 1;
|
|
195
|
+
const count = Array.isArray(displayValue) ? displayValue.length : (displayValue ? 1 : 0);
|
|
234
196
|
return (
|
|
235
197
|
<>
|
|
236
|
-
{
|
|
237
|
-
<CapIcon
|
|
198
|
+
{isMulti && count > 1 && <span>+{count - 1} more </span>}
|
|
199
|
+
<CapIcon
|
|
200
|
+
className="cap-unified-select-suffix-icon"
|
|
201
|
+
type={dropdownOpen ? 'up' : 'down'}
|
|
202
|
+
size="s"
|
|
203
|
+
/>
|
|
238
204
|
</>
|
|
239
205
|
);
|
|
240
|
-
}, [isMulti,
|
|
206
|
+
}, [isMulti, displayValue, dropdownOpen]);
|
|
241
207
|
|
|
242
208
|
const prefix = useMemo(() => {
|
|
243
|
-
if (isMulti) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const firstSelectedOption = options?.find(
|
|
247
|
-
(opt) => opt?.value === firstSelectedValue,
|
|
248
|
-
);
|
|
249
|
-
return firstSelectedOption?.label || null;
|
|
250
|
-
} else if (Array.isArray(value) && value?.length > 0) {
|
|
251
|
-
const firstSelectedValue = value[0];
|
|
252
|
-
const firstSelectedOption = options?.find(
|
|
253
|
-
(opt) => opt?.value === firstSelectedValue,
|
|
254
|
-
);
|
|
255
|
-
return firstSelectedOption?.label || null;
|
|
256
|
-
}
|
|
209
|
+
if (isMulti && Array.isArray(displayValue) && displayValue.length > 0) {
|
|
210
|
+
const firstLeafValue = displayValue.find(val => treeMaps.leafValues.includes(val));
|
|
211
|
+
return treeMaps.nodeMap[firstLeafValue]?.label || treeMaps.nodeMap[firstLeafValue]?.title || null;
|
|
257
212
|
}
|
|
258
213
|
return null;
|
|
259
|
-
}, [isMulti,
|
|
214
|
+
}, [isMulti, displayValue, treeMaps]);
|
|
215
|
+
|
|
216
|
+
const handleConfirm = useCallback(() => {
|
|
217
|
+
onChange?.(tempValue);
|
|
218
|
+
setDropdownOpen(false);
|
|
219
|
+
setSearchText('');
|
|
220
|
+
onConfirm?.(tempValue);
|
|
221
|
+
}, [onChange, onConfirm, tempValue]);
|
|
222
|
+
|
|
223
|
+
const handleCancel = useCallback(() => {
|
|
224
|
+
setTempValue(value);
|
|
225
|
+
setDropdownOpen(false);
|
|
226
|
+
onCancel?.();
|
|
227
|
+
}, [value, onCancel]);
|
|
228
|
+
|
|
229
|
+
const handleDropdownVisibilityChange = useCallback((open) => {
|
|
230
|
+
if (!open && !customPopupRender) {
|
|
231
|
+
onChange?.(tempValue);
|
|
232
|
+
} else if (!open) {
|
|
233
|
+
setTempValue(value);
|
|
234
|
+
}
|
|
235
|
+
setDropdownOpen(open);
|
|
236
|
+
}, [customPopupRender, value, onChange, tempValue]);
|
|
260
237
|
|
|
261
|
-
const renderHeader =
|
|
238
|
+
const renderHeader = useMemo(() => {
|
|
262
239
|
if (!headerLabel && !tooltip) return null;
|
|
263
240
|
return (
|
|
264
241
|
<>
|
|
265
|
-
<HeaderWrapper
|
|
266
|
-
className={classnames(
|
|
267
|
-
disabled ? 'disabled' : '',
|
|
268
|
-
'cap-unified-select-header',
|
|
269
|
-
)}
|
|
270
|
-
>
|
|
242
|
+
<HeaderWrapper className={classnames(disabled && 'disabled', 'cap-unified-select-header')}>
|
|
271
243
|
{headerLabel && (
|
|
272
244
|
<CapLabel
|
|
273
245
|
type="label16"
|
|
274
|
-
className={classnames(
|
|
275
|
-
disabled ? 'disabled' : '',
|
|
276
|
-
'cap-unified-select-header-label',
|
|
277
|
-
)}
|
|
246
|
+
className={classnames(disabled && 'disabled', 'cap-unified-select-header-label')}
|
|
278
247
|
>
|
|
279
248
|
{headerLabel}
|
|
280
249
|
</CapLabel>
|
|
@@ -282,10 +251,7 @@ const CapUnifiedSelect = ({
|
|
|
282
251
|
{tooltip && (
|
|
283
252
|
<CapTooltipWithInfo
|
|
284
253
|
title={tooltip}
|
|
285
|
-
className={classnames(
|
|
286
|
-
disabled ? 'disabled' : '',
|
|
287
|
-
'cap-unified-select-header-tooltip',
|
|
288
|
-
)}
|
|
254
|
+
className={classnames(disabled && 'disabled', 'cap-unified-select-header-tooltip')}
|
|
289
255
|
iconProps={{ disabled }}
|
|
290
256
|
/>
|
|
291
257
|
)}
|
|
@@ -293,10 +259,7 @@ const CapUnifiedSelect = ({
|
|
|
293
259
|
{bylineText && (
|
|
294
260
|
<div className="cap-unified-select-header-byline-text">
|
|
295
261
|
<CapLabel
|
|
296
|
-
className={classnames(
|
|
297
|
-
disabled ? 'disabled' : '',
|
|
298
|
-
'cap-unified-select-header-byline-text',
|
|
299
|
-
)}
|
|
262
|
+
className={classnames(disabled && 'disabled', 'cap-unified-select-header-byline-text')}
|
|
300
263
|
>
|
|
301
264
|
{bylineText}
|
|
302
265
|
</CapLabel>
|
|
@@ -306,253 +269,153 @@ const CapUnifiedSelect = ({
|
|
|
306
269
|
);
|
|
307
270
|
}, [headerLabel, tooltip, bylineText, disabled]);
|
|
308
271
|
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
272
|
+
const renderCustomDropdown = useCallback(
|
|
273
|
+
(menu) => {
|
|
274
|
+
if (!customPopupRender) return menu;
|
|
275
|
+
const currentItems = filteredTree;
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<div className={classnames(popoverClassName, `${type}-popup-container`)}>
|
|
279
|
+
{showSearch && (
|
|
280
|
+
<CapRow className="cap-unified-select-search-container" align="middle">
|
|
281
|
+
<Input
|
|
282
|
+
prefix={<CapIcon type="search" size="s" style={{ color: styledVars.CAP_G06 }} />}
|
|
283
|
+
placeholder="Search"
|
|
284
|
+
variant="borderless"
|
|
285
|
+
value={searchText}
|
|
286
|
+
onChange={(e) => setSearchText(e.target.value)}
|
|
287
|
+
allowClear
|
|
288
|
+
/>
|
|
289
|
+
</CapRow>
|
|
290
|
+
)}
|
|
291
|
+
|
|
292
|
+
{isMulti && showUpload && (
|
|
293
|
+
<CapRow className="cap-unified-select-upload-container" align="middle" onClick={onUpload}>
|
|
294
|
+
<CapIcon type="upload" size="s" style={{ color: styledVars.CAP_SECONDARY.base }} />
|
|
295
|
+
<CapLabel type="label14" className="cap-unified-select-upload-label">Upload</CapLabel>
|
|
296
|
+
</CapRow>
|
|
297
|
+
)}
|
|
298
|
+
|
|
299
|
+
{isMulti && currentItems.length > 0 && (
|
|
300
|
+
<SelectAllCheckbox
|
|
301
|
+
currentItems={currentItems}
|
|
302
|
+
tempValue={tempValue}
|
|
303
|
+
setTempValue={setTempValue}
|
|
304
|
+
processTreeData={buildTreeMaps}
|
|
305
|
+
/>
|
|
306
|
+
)}
|
|
307
|
+
|
|
308
|
+
{currentItems.length === 0 ? (
|
|
309
|
+
<NoResult
|
|
310
|
+
noResultCustomText={noResultCustomText}
|
|
311
|
+
className={className}
|
|
312
|
+
showUpload={showUpload}
|
|
313
|
+
options={options}
|
|
314
|
+
noResultCustomIcon={noResultCustomIcon}
|
|
315
|
+
/>
|
|
316
|
+
) : (
|
|
317
|
+
menu
|
|
318
|
+
)}
|
|
319
|
+
|
|
320
|
+
{currentItems.length > 0 && isMulti && (
|
|
321
|
+
<div className="cap-unified-select-confirm-container">
|
|
322
|
+
<div className="cap-unified-select-confirm-button-group">
|
|
323
|
+
<Button
|
|
324
|
+
type="primary"
|
|
325
|
+
size="small"
|
|
326
|
+
className="cap-unified-select-confirm-button"
|
|
327
|
+
onClick={handleConfirm}
|
|
361
328
|
>
|
|
362
|
-
|
|
329
|
+
Confirm
|
|
330
|
+
</Button>
|
|
331
|
+
<Button
|
|
332
|
+
type="text"
|
|
333
|
+
className="cap-unified-select-cancel-button"
|
|
334
|
+
size="small"
|
|
335
|
+
onClick={handleCancel}
|
|
336
|
+
>
|
|
337
|
+
Cancel
|
|
338
|
+
</Button>
|
|
339
|
+
<CapLabel className="cap-unified-select-selected-count">
|
|
340
|
+
{selectedLeafCount} selected
|
|
363
341
|
</CapLabel>
|
|
364
|
-
</CapRow>
|
|
365
|
-
)}
|
|
366
|
-
{isMulti &&
|
|
367
|
-
currentItems.length > 0 &&
|
|
368
|
-
(() => {
|
|
369
|
-
const { leafValues } = processTreeData(currentItems);
|
|
370
|
-
const totalAvailable = leafValues.length;
|
|
371
|
-
const selectedInScope = processTreeData(
|
|
372
|
-
currentItems,
|
|
373
|
-
tempValue,
|
|
374
|
-
).selectedCount;
|
|
375
|
-
|
|
376
|
-
return (
|
|
377
|
-
<CapRow
|
|
378
|
-
className={classnames(
|
|
379
|
-
'cap-unified-select-select-all-container',
|
|
380
|
-
)}
|
|
381
|
-
align="middle"
|
|
382
|
-
>
|
|
383
|
-
<Checkbox
|
|
384
|
-
className={classnames(
|
|
385
|
-
'cap-unified-select-select-all-checkbox',
|
|
386
|
-
)}
|
|
387
|
-
checked={
|
|
388
|
-
totalAvailable > 0 && selectedInScope === totalAvailable
|
|
389
|
-
}
|
|
390
|
-
indeterminate={
|
|
391
|
-
selectedInScope > 0 && selectedInScope < totalAvailable
|
|
392
|
-
}
|
|
393
|
-
onChange={(e) => {
|
|
394
|
-
setTempValue(e.target.checked ? leafValues : []);
|
|
395
|
-
}}
|
|
396
|
-
>
|
|
397
|
-
<CapLabel
|
|
398
|
-
type="label14"
|
|
399
|
-
className={classnames(
|
|
400
|
-
'cap-unified-select-select-all-label',
|
|
401
|
-
)}
|
|
402
|
-
>
|
|
403
|
-
Select all
|
|
404
|
-
</CapLabel>
|
|
405
|
-
</Checkbox>
|
|
406
|
-
</CapRow>
|
|
407
|
-
);
|
|
408
|
-
})()}
|
|
409
|
-
|
|
410
|
-
{currentItems.length === 0 ? (
|
|
411
|
-
<NoResult
|
|
412
|
-
noResultCustomText={noResultCustomText}
|
|
413
|
-
className={classnames(
|
|
414
|
-
className,
|
|
415
|
-
'cap-unified-select-no-result',
|
|
416
|
-
)}
|
|
417
|
-
showUpload={showUpload}
|
|
418
|
-
options={options}
|
|
419
|
-
/>
|
|
420
|
-
) : (
|
|
421
|
-
menu
|
|
422
|
-
)}
|
|
423
|
-
|
|
424
|
-
{currentItems.length > 0 && isMulti && (
|
|
425
|
-
<div className="cap-unified-select-confirm-container">
|
|
426
|
-
<div className="cap-unified-select-confirm-button-group">
|
|
427
|
-
<Button
|
|
428
|
-
type="primary"
|
|
429
|
-
size="small"
|
|
430
|
-
className="cap-unified-select-confirm-button"
|
|
431
|
-
onClick={handleConfirm}
|
|
432
|
-
>
|
|
433
|
-
Confirm
|
|
434
|
-
</Button>
|
|
435
|
-
<Button
|
|
436
|
-
type="text"
|
|
437
|
-
className="cap-unified-select-cancel-button"
|
|
438
|
-
size="small"
|
|
439
|
-
onClick={handleCancel}
|
|
440
|
-
>
|
|
441
|
-
Cancel
|
|
442
|
-
</Button>
|
|
443
|
-
<CapLabel className="cap-unified-select-selected-count">
|
|
444
|
-
{selectedCount} selected
|
|
445
|
-
</CapLabel>
|
|
446
|
-
</div>
|
|
447
342
|
</div>
|
|
448
|
-
|
|
449
|
-
</div>
|
|
450
|
-
);
|
|
451
|
-
},
|
|
452
|
-
[
|
|
453
|
-
customPopupRender,
|
|
454
|
-
popoverClassName,
|
|
455
|
-
type,
|
|
456
|
-
showSearch,
|
|
457
|
-
searchText,
|
|
458
|
-
isMulti,
|
|
459
|
-
showUpload,
|
|
460
|
-
currentItems,
|
|
461
|
-
tempValue,
|
|
462
|
-
className,
|
|
463
|
-
noResultCustomText,
|
|
464
|
-
onUpload,
|
|
465
|
-
handleConfirm,
|
|
466
|
-
handleCancel,
|
|
467
|
-
processTreeData,
|
|
468
|
-
],
|
|
469
|
-
);
|
|
470
|
-
|
|
471
|
-
return (
|
|
472
|
-
<>
|
|
473
|
-
<StyledTreeSelect
|
|
474
|
-
type={type}
|
|
475
|
-
treeData={filteredTree}
|
|
476
|
-
value={customPopupRender ? tempValue : value}
|
|
477
|
-
onChange={onChange}
|
|
478
|
-
placeholder={placeholder}
|
|
479
|
-
showSearch={false}
|
|
480
|
-
maxTagCount={0}
|
|
481
|
-
maxTagPlaceholder={() => null}
|
|
482
|
-
prefix={tempValue?.length > 0 ? prefix : undefined}
|
|
483
|
-
suffixIcon={suffix}
|
|
484
|
-
className={classnames(
|
|
485
|
-
containerClassName,
|
|
486
|
-
`cap-unified-tree-select`,
|
|
487
|
-
className,
|
|
343
|
+
</div>
|
|
488
344
|
)}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
);
|
|
517
|
-
}, [
|
|
518
|
-
filteredTree,
|
|
519
|
-
tempValue,
|
|
520
|
-
value,
|
|
521
|
-
prefix,
|
|
522
|
-
suffix,
|
|
523
|
-
className,
|
|
524
|
-
style,
|
|
525
|
-
isError,
|
|
526
|
-
errorMessage,
|
|
527
|
-
allowClear,
|
|
528
|
-
isMulti,
|
|
529
|
-
isTree,
|
|
530
|
-
dropdownOpen,
|
|
531
|
-
customPopupRender,
|
|
532
|
-
handleTempChange,
|
|
533
|
-
onChange,
|
|
534
|
-
disabled,
|
|
535
|
-
handleDropdownVisibilityChange,
|
|
536
|
-
treeSelectVirtualizationProps,
|
|
537
|
-
dataSource,
|
|
538
|
-
processTreeData,
|
|
539
|
-
]);
|
|
345
|
+
</div>
|
|
346
|
+
);
|
|
347
|
+
},
|
|
348
|
+
[
|
|
349
|
+
customPopupRender,
|
|
350
|
+
filteredTree,
|
|
351
|
+
searchText,
|
|
352
|
+
isMulti,
|
|
353
|
+
showUpload,
|
|
354
|
+
onUpload,
|
|
355
|
+
noResultCustomText,
|
|
356
|
+
noResultCustomIcon,
|
|
357
|
+
options,
|
|
358
|
+
type,
|
|
359
|
+
tempValue,
|
|
360
|
+
handleConfirm,
|
|
361
|
+
handleCancel,
|
|
362
|
+
popoverClassName,
|
|
363
|
+
className,
|
|
364
|
+
selectedLeafCount,
|
|
365
|
+
]
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
const combinedClassName = useMemo(
|
|
369
|
+
() => classnames(containerClassName, 'cap-unified-tree-select', className),
|
|
370
|
+
[containerClassName, className]
|
|
371
|
+
);
|
|
540
372
|
|
|
541
373
|
return (
|
|
542
374
|
<CapRow className={classnames(className, 'cap-unified-select-container')}>
|
|
543
|
-
{renderHeader
|
|
544
|
-
|
|
375
|
+
{renderHeader}
|
|
376
|
+
<StyledTreeSelect
|
|
377
|
+
type={type}
|
|
378
|
+
treeData={filteredTree}
|
|
379
|
+
value={customPopupRender ? tempValue : value}
|
|
380
|
+
onChange={isMulti ? setTempValue : onChange}
|
|
381
|
+
placeholder={placeholder}
|
|
382
|
+
showSearch={false}
|
|
383
|
+
maxTagCount={0}
|
|
384
|
+
maxTagPlaceholder={() => null}
|
|
385
|
+
prefix={prefix || undefined}
|
|
386
|
+
suffixIcon={suffix}
|
|
387
|
+
className={combinedClassName}
|
|
388
|
+
classNames={{
|
|
389
|
+
popup: { root: classnames('custom-popup-container', className) },
|
|
390
|
+
}}
|
|
391
|
+
style={style}
|
|
392
|
+
status={isError ? 'error' : ''}
|
|
393
|
+
allowClear={allowClear}
|
|
394
|
+
multiple={isMulti}
|
|
395
|
+
treeCheckable={isMulti}
|
|
396
|
+
treeCheckStrictly={false}
|
|
397
|
+
showCheckedStrategy={TreeSelect.SHOW_CHILD}
|
|
398
|
+
open={dropdownOpen}
|
|
399
|
+
onOpenChange={handleDropdownVisibilityChange}
|
|
400
|
+
virtual
|
|
401
|
+
disabled={disabled}
|
|
402
|
+
filterTreeNode={false}
|
|
403
|
+
listHeight={256}
|
|
404
|
+
listItemHeight={32}
|
|
405
|
+
popupRender={renderCustomDropdown}
|
|
406
|
+
{...rest}
|
|
407
|
+
/>
|
|
408
|
+
{isError && (
|
|
409
|
+
<CapLabel className="cap-unified-select-status" style={{ color: 'red' }}>
|
|
410
|
+
{errorMessage}
|
|
411
|
+
</CapLabel>
|
|
412
|
+
)}
|
|
545
413
|
</CapRow>
|
|
546
414
|
);
|
|
547
415
|
};
|
|
548
416
|
|
|
549
417
|
CapUnifiedSelect.propTypes = {
|
|
550
|
-
type: PropTypes.oneOf([
|
|
551
|
-
'select',
|
|
552
|
-
'multiSelect',
|
|
553
|
-
'treeSelect',
|
|
554
|
-
'multiTreeSelect',
|
|
555
|
-
]),
|
|
418
|
+
type: PropTypes.oneOf(['select', 'multiSelect', 'treeSelect', 'multiTreeSelect']),
|
|
556
419
|
options: PropTypes.array,
|
|
557
420
|
value: PropTypes.any,
|
|
558
421
|
onChange: PropTypes.func,
|
|
@@ -573,7 +436,6 @@ CapUnifiedSelect.propTypes = {
|
|
|
573
436
|
popupClassName: PropTypes.string,
|
|
574
437
|
showUpload: PropTypes.bool,
|
|
575
438
|
onUpload: PropTypes.func,
|
|
576
|
-
size: PropTypes.oneOf(['s', 'm', 'l', 'xl']),
|
|
577
439
|
};
|
|
578
440
|
|
|
579
441
|
CapUnifiedSelect.defaultProps = {
|
|
@@ -583,7 +445,6 @@ CapUnifiedSelect.defaultProps = {
|
|
|
583
445
|
noResultCustomText: 'No results found',
|
|
584
446
|
noResultCustomIcon: 'warning',
|
|
585
447
|
options: [],
|
|
586
|
-
size: 'm',
|
|
587
448
|
allowClear: false,
|
|
588
449
|
customPopupRender: true,
|
|
589
450
|
showSearch: true,
|
package/package.json
CHANGED