@capillarytech/blaze-ui 0.1.6-alpha.21 → 0.1.6-alpha.23
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/CapTestSelect/CapTestSelect.js +47 -0
- package/CapTestSelect/index.js +1 -0
- package/components/CapInput/CapInput.js +67 -0
- package/components/CapInput/Number.js +38 -0
- package/components/CapInput/Search.js +32 -0
- package/components/CapInput/TextArea.js +45 -0
- package/components/CapInput/index.js +10 -0
- package/components/CapInput/messages.js +27 -0
- package/components/CapInput/styles.js +81 -0
- package/components/CapSkeleton/CapSkeleton.js +17 -0
- package/components/CapSkeleton/index.js +1 -0
- package/components/CapSpin/CapSpin.js +23 -0
- package/components/CapSpin/index.js +1 -0
- package/components/CapTable/CapTable.js +146 -0
- package/components/CapTable/index.js +3 -0
- package/components/CapTable/loadable.js +13 -0
- package/components/CapTable/styles.js +134 -0
- package/components/CapTestSelect/CapTestSelect.js +47 -0
- package/components/CapTestSelect/index.js +1 -0
- package/components/CapUnifiedSelect/CapUnifiedSelect.js +374 -0
- package/components/CapUnifiedSelect/index.js +1 -0
- package/components/CapUnifiedSelect/messages.js +24 -0
- package/components/CapUnifiedSelect/styles.js +111 -0
- package/components/LocaleHoc/index.js +38 -0
- package/components/index.js +14 -0
- package/components/styled/index.js +6 -0
- package/components/styled/variables.js +89 -0
- package/components/translations/en.js +331 -0
- package/dist/CapTestSelect/CapTestSelect.js +40 -0
- package/dist/CapTestSelect/index.js +13 -0
- package/dist/components/CapInput/CapInput.js +66 -0
- package/dist/components/CapInput/Number.js +42 -0
- package/dist/components/CapInput/Search.js +35 -0
- package/dist/components/CapInput/TextArea.js +42 -0
- package/dist/components/CapInput/index.js +15 -0
- package/dist/components/CapInput/messages.js +32 -0
- package/dist/components/CapInput/styles.js +11 -0
- package/dist/components/CapSkeleton/CapSkeleton.js +29 -0
- package/dist/components/CapSkeleton/index.js +13 -0
- package/dist/components/CapSpin/CapSpin.js +35 -0
- package/dist/components/CapSpin/index.js +13 -0
- package/dist/components/CapTable/CapTable.js +148 -0
- package/dist/components/CapTable/index.js +9 -0
- package/dist/components/CapTable/loadable.js +23 -0
- package/dist/components/CapTable/styles.js +26 -0
- package/dist/components/CapTestSelect/CapTestSelect.js +40 -0
- package/dist/components/CapTestSelect/index.js +13 -0
- package/dist/components/CapUnifiedSelect/CapUnifiedSelect.js +405 -0
- package/dist/components/CapUnifiedSelect/index.js +13 -0
- package/dist/components/CapUnifiedSelect/messages.js +29 -0
- package/dist/components/CapUnifiedSelect/styles.js +39 -0
- package/dist/components/LocaleHoc/index.js +40 -0
- package/dist/components/index.js +66 -0
- package/dist/components/styled/index.js +22 -0
- package/dist/components/styled/variables.js +94 -0
- package/dist/components/translations/en.js +335 -0
- package/dist/esm/CapTestSelect/CapTestSelect.js +34 -0
- package/dist/esm/CapTestSelect/index.js +1 -0
- package/dist/esm/components/CapInput/CapInput.js +57 -0
- package/dist/esm/components/CapInput/Number.js +35 -0
- package/dist/esm/components/CapInput/Search.js +28 -0
- package/dist/esm/components/CapInput/TextArea.js +35 -0
- package/dist/esm/components/CapInput/index.js +8 -0
- package/dist/esm/components/CapInput/messages.js +25 -0
- package/dist/esm/components/CapInput/styles.js +3 -0
- package/dist/esm/components/CapSkeleton/CapSkeleton.js +22 -0
- package/dist/esm/components/CapSkeleton/index.js +1 -0
- package/dist/esm/components/CapSpin/CapSpin.js +28 -0
- package/dist/esm/components/CapSpin/index.js +1 -0
- package/dist/esm/components/CapTable/CapTable.js +140 -0
- package/dist/esm/components/CapTable/index.js +2 -0
- package/dist/esm/components/CapTable/loadable.js +12 -0
- package/dist/esm/components/CapTable/styles.js +17 -0
- package/dist/esm/components/CapTestSelect/CapTestSelect.js +34 -0
- package/dist/esm/components/CapTestSelect/index.js +1 -0
- package/dist/esm/components/CapUnifiedSelect/CapUnifiedSelect.js +398 -0
- package/dist/esm/components/CapUnifiedSelect/index.js +1 -0
- package/dist/esm/components/CapUnifiedSelect/messages.js +23 -0
- package/dist/esm/components/CapUnifiedSelect/styles.js +31 -0
- package/dist/esm/components/LocaleHoc/index.js +31 -0
- package/dist/esm/components/index.js +15 -0
- package/dist/esm/components/styled/index.js +5 -0
- package/dist/esm/components/styled/variables.js +88 -0
- package/dist/esm/components/translations/en.js +329 -0
- package/dist/esm/index.js +1 -11
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/withStyles.js +23 -0
- package/dist/esm/withStyles.js +23 -0
- package/dist/index.js +3 -29
- package/dist/utils/index.js +13 -0
- package/dist/utils/withStyles.js +29 -0
- package/dist/withStyles.js +29 -0
- package/index.js +5 -1
- package/package.json +1 -1
- package/utils/index.js +1 -0
- package/utils/withStyles.js +24 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Select } from 'antd';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test component to verify Ant Design v5 Select integration
|
|
7
|
+
* This is a simple wrapper for testing purposes only
|
|
8
|
+
*/
|
|
9
|
+
const CapTestSelect = (props) => {
|
|
10
|
+
return <Select {...props} />;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
CapTestSelect.propTypes = {
|
|
14
|
+
// Common Select props from antd
|
|
15
|
+
allowClear: PropTypes.bool,
|
|
16
|
+
defaultValue: PropTypes.oneOfType([
|
|
17
|
+
PropTypes.string,
|
|
18
|
+
PropTypes.number,
|
|
19
|
+
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))
|
|
20
|
+
]),
|
|
21
|
+
disabled: PropTypes.bool,
|
|
22
|
+
loading: PropTypes.bool,
|
|
23
|
+
mode: PropTypes.oneOf(['multiple', 'tags']),
|
|
24
|
+
placeholder: PropTypes.string,
|
|
25
|
+
showSearch: PropTypes.bool,
|
|
26
|
+
value: PropTypes.oneOfType([
|
|
27
|
+
PropTypes.string,
|
|
28
|
+
PropTypes.number,
|
|
29
|
+
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))
|
|
30
|
+
]),
|
|
31
|
+
options: PropTypes.arrayOf(
|
|
32
|
+
PropTypes.shape({
|
|
33
|
+
label: PropTypes.node,
|
|
34
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
35
|
+
disabled: PropTypes.bool
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
CapTestSelect.defaultProps = {
|
|
41
|
+
allowClear: false,
|
|
42
|
+
disabled: false,
|
|
43
|
+
loading: false,
|
|
44
|
+
showSearch: false
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default CapTestSelect;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './CapTestSelect';
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
// Enhanced CapUnifiedSelect supporting 4 scenarios with advanced features
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import classnames from 'classnames';
|
|
5
|
+
import { Select, TreeSelect, Tooltip, Input, Button } from 'antd';
|
|
6
|
+
import { InfoCircleOutlined, SearchOutlined, WarningFilled, DownOutlined } from '@ant-design/icons';
|
|
7
|
+
import { SelectWrapper, HeaderWrapper, selectStyles } from './styles';
|
|
8
|
+
import withStyles from '../../utils/withStyles';
|
|
9
|
+
import styled from 'styled-components';
|
|
10
|
+
|
|
11
|
+
const CapUnifiedSelect = ({
|
|
12
|
+
type,
|
|
13
|
+
options = [],
|
|
14
|
+
treeData,
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
placeholder = 'Select an option',
|
|
18
|
+
className,
|
|
19
|
+
style,
|
|
20
|
+
status,
|
|
21
|
+
statusMessage,
|
|
22
|
+
allowClear = false,
|
|
23
|
+
label,
|
|
24
|
+
tooltip,
|
|
25
|
+
disabled = false,
|
|
26
|
+
treeCheckable = false,
|
|
27
|
+
customPopupRender = false,
|
|
28
|
+
onConfirm,
|
|
29
|
+
onCancel
|
|
30
|
+
}) => {
|
|
31
|
+
const StyledSelect = styled(Select)`
|
|
32
|
+
${selectStyles}
|
|
33
|
+
`;
|
|
34
|
+
const StyledTreeSelect = styled(TreeSelect)`
|
|
35
|
+
${selectStyles}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const [searchText, setSearchText] = useState('');
|
|
39
|
+
const [tempValue, setTempValue] = useState(value);
|
|
40
|
+
const [allSelected, setAllSelected] = useState(false);
|
|
41
|
+
|
|
42
|
+
// Update tempValue when value changes
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
setTempValue(value);
|
|
45
|
+
}, [value]);
|
|
46
|
+
|
|
47
|
+
const selectVirtualizationProps = {
|
|
48
|
+
listHeight: 256,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const treeSelectVirtualizationProps = {
|
|
52
|
+
listHeight: 256,
|
|
53
|
+
listItemHeight: 32,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// No results component
|
|
57
|
+
const NoResult = () => (
|
|
58
|
+
<div style={{
|
|
59
|
+
display: 'flex',
|
|
60
|
+
flexDirection: 'column',
|
|
61
|
+
alignItems: 'center',
|
|
62
|
+
justifyContent: 'center',
|
|
63
|
+
height: 200,
|
|
64
|
+
color: '#8c8c8c',
|
|
65
|
+
fontSize: 14
|
|
66
|
+
}}>
|
|
67
|
+
<WarningFilled style={{ fontSize: 36, marginBottom: 8, color: '#bfbfbf' }} />
|
|
68
|
+
<div style={{ fontWeight: 500 }}>No results found</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Filter tree data based on search text
|
|
73
|
+
const getFilteredTreeData = (data, search) => {
|
|
74
|
+
if (!search) return data;
|
|
75
|
+
|
|
76
|
+
const filterNode = node => {
|
|
77
|
+
const titleText = node.title?.toLowerCase() || '';
|
|
78
|
+
const labelText = node.label?.toLowerCase() || '';
|
|
79
|
+
return titleText.includes(search.toLowerCase()) || labelText.includes(search.toLowerCase());
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const loop = data =>
|
|
83
|
+
data.map(item => {
|
|
84
|
+
const children = item.children ? loop(item.children) : [];
|
|
85
|
+
if (filterNode(item) || children.length) {
|
|
86
|
+
return { ...item, children };
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}).filter(Boolean);
|
|
90
|
+
|
|
91
|
+
return loop(data);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Get all leaf node values from tree data
|
|
95
|
+
const flattenedLeafValues = (nodes) =>
|
|
96
|
+
nodes?.flatMap((node) =>
|
|
97
|
+
node.children ? flattenedLeafValues(node.children) : [node.value]
|
|
98
|
+
) || [];
|
|
99
|
+
|
|
100
|
+
const filteredTree = getFilteredTreeData(treeData || options, searchText);
|
|
101
|
+
const filteredOptions = !searchText ? options : options.filter(opt =>
|
|
102
|
+
opt.label?.toLowerCase().includes(searchText.toLowerCase())
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// All available leaf values for the current filtered tree data
|
|
106
|
+
const leafValues = flattenedLeafValues(filteredTree);
|
|
107
|
+
|
|
108
|
+
// Handles select all checkbox click
|
|
109
|
+
const handleSelectAll = (isTree = false) => {
|
|
110
|
+
const availableValues = isTree ? leafValues : filteredOptions.map(opt => opt.value);
|
|
111
|
+
|
|
112
|
+
if (allSelected) {
|
|
113
|
+
setTempValue([]);
|
|
114
|
+
} else {
|
|
115
|
+
setTempValue(availableValues);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
setAllSelected(!allSelected);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Update allSelected state when value changes
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
const isMultipleMode = type === 'multiSelect' || type === 'multiTreeSelect';
|
|
124
|
+
if (isMultipleMode && Array.isArray(tempValue)) {
|
|
125
|
+
const availableValues = type.includes('tree') ? leafValues : filteredOptions.map(opt => opt.value);
|
|
126
|
+
setAllSelected(tempValue.length > 0 && tempValue.length === availableValues.length);
|
|
127
|
+
}
|
|
128
|
+
}, [tempValue, filteredOptions, leafValues, type]);
|
|
129
|
+
|
|
130
|
+
// Handle confirmation
|
|
131
|
+
const handleConfirm = () => {
|
|
132
|
+
if (onConfirm) {
|
|
133
|
+
onConfirm(tempValue);
|
|
134
|
+
} else {
|
|
135
|
+
onChange(tempValue);
|
|
136
|
+
}
|
|
137
|
+
setSearchText('');
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Handle cancellation
|
|
141
|
+
const handleCancel = () => {
|
|
142
|
+
if (onCancel) {
|
|
143
|
+
onCancel();
|
|
144
|
+
}
|
|
145
|
+
setTempValue(value);
|
|
146
|
+
setSearchText('');
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Handle temporary value change
|
|
150
|
+
const handleTempChange = (newValue) => {
|
|
151
|
+
setTempValue(newValue);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const suffix =
|
|
155
|
+
(type === "multiTreeSelect" || type === "multiSelect") && Array.isArray(value) && value.length > 1 ? (
|
|
156
|
+
<>
|
|
157
|
+
<span>
|
|
158
|
+
+{value.length - 1} more
|
|
159
|
+
<DownOutlined />
|
|
160
|
+
</span>
|
|
161
|
+
</>
|
|
162
|
+
) : (
|
|
163
|
+
<DownOutlined />
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const prefix = () => {
|
|
167
|
+
if((type === "multiTreeSelect" || type === "multiSelect") && Array.isArray(value) && value.length > 0) {
|
|
168
|
+
const selectedLabels = options
|
|
169
|
+
.filter((opt) => value.includes(opt.value))
|
|
170
|
+
.map((opt) => opt.label);
|
|
171
|
+
|
|
172
|
+
return selectedLabels[0];
|
|
173
|
+
} else {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const renderHeader = () => {
|
|
179
|
+
if (!label && !tooltip) return null;
|
|
180
|
+
return (
|
|
181
|
+
<HeaderWrapper className={disabled ? 'disabled' : ''}>
|
|
182
|
+
{label && <label type="label16" className={disabled ? 'disabled' : ''}>{label}</label>}
|
|
183
|
+
{tooltip && (
|
|
184
|
+
<Tooltip title={tooltip}>
|
|
185
|
+
<InfoCircleOutlined className={disabled ? 'disabled' : ''} style={{ color: '#B3BAC5' }}/>
|
|
186
|
+
</Tooltip>
|
|
187
|
+
)}
|
|
188
|
+
</HeaderWrapper>
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const renderDropdown = () => {
|
|
193
|
+
const isMultipleSelect = type === 'multiSelect' || type === 'multiTreeSelect';
|
|
194
|
+
const isTreeMode = type === 'treeSelect' || type === 'multiTreeSelect';
|
|
195
|
+
const currentItems = isTreeMode ? filteredTree : filteredOptions;
|
|
196
|
+
const selectedCount = Array.isArray(tempValue) ? tempValue.length : (tempValue ? 1 : 0);
|
|
197
|
+
|
|
198
|
+
// Custom dropdown render for both Select and TreeSelect
|
|
199
|
+
const renderCustomDropdown = (menu) => {
|
|
200
|
+
if (!customPopupRender) return menu;
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<>
|
|
204
|
+
<div style={{ borderBottom: '1px solid #f0f0f0'}}>
|
|
205
|
+
<Input
|
|
206
|
+
prefix={<SearchOutlined style={{ color: "#B3BAC5" }} />}
|
|
207
|
+
placeholder="Search"
|
|
208
|
+
variant="borderless"
|
|
209
|
+
value={searchText}
|
|
210
|
+
onChange={(e) => setSearchText(e.target.value)}
|
|
211
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
212
|
+
/>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
{isMultipleSelect && currentItems.length > 0 && (
|
|
216
|
+
<div style={{
|
|
217
|
+
padding: '8px 12px',
|
|
218
|
+
cursor: 'pointer',
|
|
219
|
+
display: 'flex',
|
|
220
|
+
alignItems: 'center',
|
|
221
|
+
borderBottom: '1px solid #f0f0f0'
|
|
222
|
+
}}
|
|
223
|
+
onClick={(e) => {
|
|
224
|
+
// Prevent event propagation to keep dropdown open
|
|
225
|
+
e.stopPropagation();
|
|
226
|
+
handleSelectAll(isTreeMode);
|
|
227
|
+
}}>
|
|
228
|
+
<input
|
|
229
|
+
type="checkbox"
|
|
230
|
+
checked={allSelected}
|
|
231
|
+
readOnly
|
|
232
|
+
style={{ cursor: 'pointer' }}
|
|
233
|
+
onClick={(e) => e.stopPropagation()}
|
|
234
|
+
/>
|
|
235
|
+
<label style={{ marginLeft: 8, cursor: 'pointer' }}>Select all</label>
|
|
236
|
+
</div>
|
|
237
|
+
)}
|
|
238
|
+
|
|
239
|
+
{currentItems.length === 0 ? <NoResult /> : menu}
|
|
240
|
+
|
|
241
|
+
{currentItems.length > 0 && isMultipleSelect && (
|
|
242
|
+
<div style={{
|
|
243
|
+
display: 'flex',
|
|
244
|
+
justifyContent: 'space-between',
|
|
245
|
+
alignItems: 'center',
|
|
246
|
+
padding: '8px 12px',
|
|
247
|
+
borderTop: '1px solid #f0f0f0'
|
|
248
|
+
}}>
|
|
249
|
+
<div>
|
|
250
|
+
<Button
|
|
251
|
+
type="primary"
|
|
252
|
+
size="small"
|
|
253
|
+
style={{ marginRight: 8 }}
|
|
254
|
+
onClick={(e) => {
|
|
255
|
+
e.stopPropagation();
|
|
256
|
+
handleConfirm();
|
|
257
|
+
}}>
|
|
258
|
+
Confirm
|
|
259
|
+
</Button>
|
|
260
|
+
<Button
|
|
261
|
+
type="text"
|
|
262
|
+
size="small"
|
|
263
|
+
onClick={(e) => {
|
|
264
|
+
e.stopPropagation();
|
|
265
|
+
handleCancel();
|
|
266
|
+
}}>
|
|
267
|
+
Cancel
|
|
268
|
+
</Button>
|
|
269
|
+
</div>
|
|
270
|
+
{selectedCount > 0 && (
|
|
271
|
+
<span style={{ color: '#8c8c8c', fontSize: '14px' }}>
|
|
272
|
+
{selectedCount} selected
|
|
273
|
+
</span>
|
|
274
|
+
)}
|
|
275
|
+
</div>
|
|
276
|
+
)}
|
|
277
|
+
</>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
if (type === 'treeSelect' || type === 'multiTreeSelect') {
|
|
282
|
+
return (
|
|
283
|
+
<>
|
|
284
|
+
<StyledTreeSelect
|
|
285
|
+
treeData={filteredTree}
|
|
286
|
+
value={customPopupRender ? tempValue : value}
|
|
287
|
+
onChange={customPopupRender ? handleTempChange : onChange}
|
|
288
|
+
placeholder={placeholder}
|
|
289
|
+
maxTagCount={0}
|
|
290
|
+
maxTagPlaceholder={() => null}
|
|
291
|
+
prefix={type === "multiTreeSelect" && value.length > 0 && prefix()}
|
|
292
|
+
suffixIcon={suffix}
|
|
293
|
+
className={classnames(`cap-unified-tree-select ${className || ''}`)}
|
|
294
|
+
style={style}
|
|
295
|
+
status={status}
|
|
296
|
+
allowClear={allowClear}
|
|
297
|
+
showSearch={false}
|
|
298
|
+
multiple={type === 'multiTreeSelect'}
|
|
299
|
+
treeCheckable={treeCheckable}
|
|
300
|
+
showCheckedStrategy={TreeSelect.SHOW_PARENT}
|
|
301
|
+
virtual
|
|
302
|
+
disabled={disabled}
|
|
303
|
+
filterTreeNode={false}
|
|
304
|
+
{...treeSelectVirtualizationProps}
|
|
305
|
+
popupRender={renderCustomDropdown}
|
|
306
|
+
/>
|
|
307
|
+
{status === 'error' && <div style={{ color: '#E83135' }} className="cap-unified-select-status">{statusMessage}</div>}
|
|
308
|
+
</>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<StyledSelect
|
|
315
|
+
options={filteredOptions}
|
|
316
|
+
value={customPopupRender ? tempValue : value}
|
|
317
|
+
onChange={customPopupRender ? handleTempChange : onChange}
|
|
318
|
+
placeholder={placeholder}
|
|
319
|
+
maxTagCount={0}
|
|
320
|
+
maxTagPlaceholder={() => null}
|
|
321
|
+
prefix={type === "multiSelect" && value.length > 0 && prefix()}
|
|
322
|
+
suffixIcon={suffix}
|
|
323
|
+
className={classnames('cap-unified-select', className)}
|
|
324
|
+
style={style}
|
|
325
|
+
allowClear={allowClear}
|
|
326
|
+
showSearch={false}
|
|
327
|
+
mode={type === 'multiSelect' ? 'multiple' : undefined}
|
|
328
|
+
virtual
|
|
329
|
+
disabled={disabled}
|
|
330
|
+
status={status}
|
|
331
|
+
{...selectVirtualizationProps}
|
|
332
|
+
popupRender={renderCustomDropdown}
|
|
333
|
+
/>
|
|
334
|
+
{status === 'error' && <div style={{ color: '#E83135' }} className="cap-unified-select-status">{statusMessage}</div>}
|
|
335
|
+
</>
|
|
336
|
+
);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<SelectWrapper className={classnames(`cap-unified-select-container ${className || ''}`)}>
|
|
341
|
+
{renderHeader()}
|
|
342
|
+
{renderDropdown()}
|
|
343
|
+
</SelectWrapper>
|
|
344
|
+
);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
CapUnifiedSelect.propTypes = {
|
|
348
|
+
type: PropTypes.oneOf(['select', 'multiSelect', 'treeSelect', 'multiTreeSelect']),
|
|
349
|
+
options: PropTypes.array,
|
|
350
|
+
treeData: PropTypes.array,
|
|
351
|
+
value: PropTypes.any,
|
|
352
|
+
onChange: PropTypes.func,
|
|
353
|
+
placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
354
|
+
className: PropTypes.string,
|
|
355
|
+
style: PropTypes.object,
|
|
356
|
+
allowClear: PropTypes.bool,
|
|
357
|
+
label: PropTypes.string,
|
|
358
|
+
tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
359
|
+
disabled: PropTypes.bool,
|
|
360
|
+
treeCheckable: PropTypes.bool,
|
|
361
|
+
customPopupRender: PropTypes.bool,
|
|
362
|
+
onConfirm: PropTypes.func,
|
|
363
|
+
onCancel: PropTypes.func,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
CapUnifiedSelect.defaultProps = {
|
|
367
|
+
type: 'select',
|
|
368
|
+
allowClear: false,
|
|
369
|
+
customPopupRender: false,
|
|
370
|
+
treeCheckable: false,
|
|
371
|
+
className: '',
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
export default withStyles(CapUnifiedSelect, selectStyles);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './CapUnifiedSelect';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
|
|
3
|
+
export default defineMessages({
|
|
4
|
+
selectPlaceholder: {
|
|
5
|
+
id: 'cap.unified.select.placeholder',
|
|
6
|
+
defaultMessage: 'Select an option',
|
|
7
|
+
},
|
|
8
|
+
searchPlaceholder: {
|
|
9
|
+
id: 'cap.unified.select.search.placeholder',
|
|
10
|
+
defaultMessage: 'Search...',
|
|
11
|
+
},
|
|
12
|
+
noData: {
|
|
13
|
+
id: 'cap.unified.select.no.data',
|
|
14
|
+
defaultMessage: 'No data',
|
|
15
|
+
},
|
|
16
|
+
loading: {
|
|
17
|
+
id: 'cap.unified.select.loading',
|
|
18
|
+
defaultMessage: 'Loading...',
|
|
19
|
+
},
|
|
20
|
+
selected: {
|
|
21
|
+
id: 'cap.unified.select.selected',
|
|
22
|
+
defaultMessage: '{count} items selected',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components';
|
|
2
|
+
import * as styledVars from '../styled/variables';
|
|
3
|
+
|
|
4
|
+
export const SelectWrapper = styled.div`
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
gap: 8px;
|
|
8
|
+
width: 100%;
|
|
9
|
+
|
|
10
|
+
&.disabled {
|
|
11
|
+
cursor: not-allowed;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const HeaderWrapper = styled.div`
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: 4px;
|
|
19
|
+
|
|
20
|
+
&.disabled {
|
|
21
|
+
opacity: 0.5;
|
|
22
|
+
cursor: not-allowed;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export const DropdownFooter = styled.div`
|
|
27
|
+
display: flex;
|
|
28
|
+
justify-content: space-between;
|
|
29
|
+
align-items: center;
|
|
30
|
+
padding: 8px;
|
|
31
|
+
border-top: 1px solid #f0f0f0;
|
|
32
|
+
|
|
33
|
+
.footer-buttons {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 8px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.total-count {
|
|
40
|
+
color: #8c8c8c;
|
|
41
|
+
font-size: 12px;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
export const SearchInputWrapper = styled.div`
|
|
46
|
+
padding: 8px;
|
|
47
|
+
border-bottom: 1px solid #f0f0f0;
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
export const SelectAllCheckbox = styled.div`
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
padding: 8px 12px;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
font-weight: 500;
|
|
56
|
+
border-bottom: 1px solid #f0f0f0;
|
|
57
|
+
user-select: none;
|
|
58
|
+
|
|
59
|
+
input[type="checkbox"] {
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
export const NoResultWrapper = styled.div`
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
align-items: center;
|
|
68
|
+
justify-content: center;
|
|
69
|
+
height: 200px;
|
|
70
|
+
color: #8c8c8c;
|
|
71
|
+
font-size: 14px;
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
export const StyledInfoIcon = styled.span`
|
|
77
|
+
color: ${styledVars.CAP_G05};
|
|
78
|
+
font-size: 16px;
|
|
79
|
+
cursor: help;
|
|
80
|
+
margin-left: 4px;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
|
|
84
|
+
&:hover {
|
|
85
|
+
color: ${styledVars.CAP_G03};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&.disabled {
|
|
89
|
+
cursor: not-allowed;
|
|
90
|
+
&:hover {
|
|
91
|
+
color: ${styledVars.CAP_G05};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
export const selectStyles = css`
|
|
97
|
+
&.cap-unified-select {
|
|
98
|
+
width: 100%;
|
|
99
|
+
font-family: ${styledVars.FONT_FAMILY};
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
&.cap-unified-select-container {
|
|
103
|
+
.ant-select-prefix{
|
|
104
|
+
margin-left: -5px !important;
|
|
105
|
+
font-size: 14px !important;
|
|
106
|
+
font-weight: 400 !important;
|
|
107
|
+
color: #091E42 !important;
|
|
108
|
+
line-height: 20px !important;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { injectIntl } from 'react-intl';
|
|
3
|
+
import enTranslation from '../translations/en';
|
|
4
|
+
|
|
5
|
+
const prefix = `blaze.components`;
|
|
6
|
+
|
|
7
|
+
const LocaleHoc = (WrapperComponent, customProps) => {
|
|
8
|
+
const Wrapper = (props) => {
|
|
9
|
+
const componentName = customProps.key;
|
|
10
|
+
const translatedDefaults = enTranslation[componentName];
|
|
11
|
+
const { intl } = props;
|
|
12
|
+
|
|
13
|
+
const translatedProps = useMemo(() => {
|
|
14
|
+
if(!translatedDefaults) return {};
|
|
15
|
+
return Object.keys(translatedDefaults).reduce((acc, key) => {
|
|
16
|
+
const id = `${prefix}.${componentName}.${key}`
|
|
17
|
+
const defaultMessage = translatedDefaults[key]
|
|
18
|
+
try{
|
|
19
|
+
acc[key] = intl.formatMessage({ id, defaultMessage });
|
|
20
|
+
}catch(err){
|
|
21
|
+
acc[key] = defaultMessage;
|
|
22
|
+
}
|
|
23
|
+
return acc;
|
|
24
|
+
}, {});
|
|
25
|
+
}, [translatedDefaults, intl]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<WrapperComponent
|
|
29
|
+
{...translatedProps}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return injectIntl(Wrapper);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default LocaleHoc;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Import and export all components
|
|
2
|
+
export { default as CapInput } from './CapInput';
|
|
3
|
+
export { default as CapTable } from './CapTable';
|
|
4
|
+
export { default as CapTestSelect } from './CapTestSelect'; // Test component for Ant Design v5 integration
|
|
5
|
+
|
|
6
|
+
// Export utilities
|
|
7
|
+
export { default as LocaleHoc } from './LocaleHoc';
|
|
8
|
+
|
|
9
|
+
// Export styled utilities
|
|
10
|
+
export * as styledVars from './styled/variables';
|
|
11
|
+
export { default as styled } from './styled';
|
|
12
|
+
|
|
13
|
+
// Export utils
|
|
14
|
+
export * from '../utils';
|