@capillarytech/blaze-ui 0.1.6-alpha.40 → 0.1.6-alpha.42
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/CapIcon/CapIcon.js +183 -0
- package/CapIcon/index.js +3 -0
- package/CapIcon/styles.js +76 -0
- package/CapLabel/CapLabel.js +126 -0
- package/CapLabel/index.js +3 -0
- package/CapLabel/styles.js +259 -0
- package/CapRow/CapRow.js +123 -0
- package/CapRow/index.js +3 -0
- package/CapRow/styles.js +50 -0
- package/CapTooltip/CapTooltip.js +98 -0
- package/CapTooltip/index.js +3 -0
- package/CapTooltip/styles.js +34 -0
- package/CapUnifiedSelect/CapUnifiedSelect.js +97 -82
- package/CapUnifiedSelect/styles.js +59 -301
- package/index.js +4 -0
- package/package.json +1 -1
package/CapRow/CapRow.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import classnames from 'classnames';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
import { StyledRow, rowStyles } from './styles';
|
|
6
|
+
import withStyles from '../utils/withStyles';
|
|
7
|
+
|
|
8
|
+
const CapRow = ({
|
|
9
|
+
children,
|
|
10
|
+
className = '',
|
|
11
|
+
style = {},
|
|
12
|
+
justify = 'start',
|
|
13
|
+
align = 'top',
|
|
14
|
+
gutter = 0,
|
|
15
|
+
wrap = true,
|
|
16
|
+
type,
|
|
17
|
+
width,
|
|
18
|
+
height,
|
|
19
|
+
margin,
|
|
20
|
+
padding,
|
|
21
|
+
prefixCls = 'ant-row',
|
|
22
|
+
fullWidth = false,
|
|
23
|
+
fullHeight = false,
|
|
24
|
+
fillSpace = false,
|
|
25
|
+
responsive = true,
|
|
26
|
+
vertical = false,
|
|
27
|
+
noWrap = false,
|
|
28
|
+
gap = null,
|
|
29
|
+
...rest
|
|
30
|
+
}) => {
|
|
31
|
+
// Use either the gap property or gutter for spacing
|
|
32
|
+
const gutterValue = gap !== null ? null : gutter;
|
|
33
|
+
const wrapValue = noWrap ? false : wrap;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<StyledRow
|
|
37
|
+
className={classnames(
|
|
38
|
+
'cap-row-v2',
|
|
39
|
+
{
|
|
40
|
+
'with-custom-width': width,
|
|
41
|
+
'with-custom-height': height,
|
|
42
|
+
'fill-space': fillSpace,
|
|
43
|
+
'full-width': fullWidth,
|
|
44
|
+
'full-height': fullHeight,
|
|
45
|
+
'ant-row-no-wrap': noWrap,
|
|
46
|
+
'with-gap': gap !== null,
|
|
47
|
+
},
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
style={{
|
|
51
|
+
...(gap !== null ? { gap: typeof gap === 'number' ? `${gap}px` : gap } : {}),
|
|
52
|
+
...style,
|
|
53
|
+
}}
|
|
54
|
+
justify={justify}
|
|
55
|
+
align={align}
|
|
56
|
+
gutter={gutterValue}
|
|
57
|
+
wrap={wrapValue}
|
|
58
|
+
type={type}
|
|
59
|
+
width={width}
|
|
60
|
+
height={height}
|
|
61
|
+
margin={margin}
|
|
62
|
+
padding={padding}
|
|
63
|
+
prefixCls={prefixCls}
|
|
64
|
+
fullWidth={fullWidth}
|
|
65
|
+
fullHeight={fullHeight}
|
|
66
|
+
fillSpace={fillSpace}
|
|
67
|
+
responsive={responsive}
|
|
68
|
+
vertical={vertical}
|
|
69
|
+
{...rest}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
</StyledRow>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
CapRow.propTypes = {
|
|
77
|
+
children: PropTypes.node,
|
|
78
|
+
className: PropTypes.string,
|
|
79
|
+
style: PropTypes.object,
|
|
80
|
+
justify: PropTypes.oneOf(['start', 'end', 'center', 'space-around', 'space-between', 'space-evenly']),
|
|
81
|
+
align: PropTypes.oneOf(['top', 'middle', 'bottom', 'stretch']),
|
|
82
|
+
gutter: PropTypes.oneOfType([
|
|
83
|
+
PropTypes.number,
|
|
84
|
+
PropTypes.object,
|
|
85
|
+
PropTypes.arrayOf(PropTypes.number),
|
|
86
|
+
]),
|
|
87
|
+
wrap: PropTypes.bool,
|
|
88
|
+
type: PropTypes.string,
|
|
89
|
+
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
90
|
+
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
91
|
+
margin: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
92
|
+
padding: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
93
|
+
prefixCls: PropTypes.string,
|
|
94
|
+
fullWidth: PropTypes.bool,
|
|
95
|
+
fullHeight: PropTypes.bool,
|
|
96
|
+
fillSpace: PropTypes.bool,
|
|
97
|
+
responsive: PropTypes.bool,
|
|
98
|
+
vertical: PropTypes.bool,
|
|
99
|
+
noWrap: PropTypes.bool,
|
|
100
|
+
gap: PropTypes.oneOfType([
|
|
101
|
+
PropTypes.number,
|
|
102
|
+
PropTypes.arrayOf(PropTypes.number),
|
|
103
|
+
PropTypes.string,
|
|
104
|
+
]),
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
CapRow.defaultProps = {
|
|
108
|
+
className: '',
|
|
109
|
+
style: {},
|
|
110
|
+
justify: 'start',
|
|
111
|
+
align: 'top',
|
|
112
|
+
gutter: 0,
|
|
113
|
+
wrap: true,
|
|
114
|
+
prefixCls: 'ant-row',
|
|
115
|
+
fullWidth: false,
|
|
116
|
+
fullHeight: false,
|
|
117
|
+
fillSpace: false,
|
|
118
|
+
responsive: true,
|
|
119
|
+
vertical: false,
|
|
120
|
+
noWrap: false,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export default withStyles(CapRow, rowStyles);
|
package/CapRow/index.js
ADDED
package/CapRow/styles.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components';
|
|
2
|
+
import { Row } from 'antd-v5';
|
|
3
|
+
import * as styledVars from '../styled/variables';
|
|
4
|
+
|
|
5
|
+
export const StyledRow = styled(Row)`
|
|
6
|
+
width: ${({ width, fullWidth }) => (fullWidth ? '100%' : width || 'auto')};
|
|
7
|
+
height: ${({ height, fullHeight }) => (fullHeight ? '100%' : height || 'auto')};
|
|
8
|
+
margin: ${({ margin }) => margin || 'inherit'};
|
|
9
|
+
padding: ${({ padding }) => padding || 'inherit'};
|
|
10
|
+
${({ responsive }) => !responsive && css`
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-wrap: wrap;
|
|
13
|
+
`};
|
|
14
|
+
${({ fillSpace }) => fillSpace && css`
|
|
15
|
+
flex: 1;
|
|
16
|
+
`};
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export const rowStyles = css`
|
|
20
|
+
&.cap-row-v2 {
|
|
21
|
+
&.with-custom-width {
|
|
22
|
+
width: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&.with-custom-height {
|
|
26
|
+
height: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.fill-space {
|
|
30
|
+
flex: 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&.full-width {
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.full-height {
|
|
38
|
+
height: 100%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.ant-row-no-wrap {
|
|
42
|
+
flex-wrap: nowrap;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&.with-gap {
|
|
46
|
+
display: grid;
|
|
47
|
+
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Tooltip } from 'antd-v5';
|
|
4
|
+
import classnames from 'classnames';
|
|
5
|
+
import styled from 'styled-components';
|
|
6
|
+
import { tooltipStyles } from './styles';
|
|
7
|
+
import withStyles from '../utils/withStyles';
|
|
8
|
+
|
|
9
|
+
const StyledTooltip = styled(Tooltip)`
|
|
10
|
+
${tooltipStyles}
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
const CapTooltip = ({
|
|
14
|
+
title,
|
|
15
|
+
children,
|
|
16
|
+
placement = 'top',
|
|
17
|
+
visible,
|
|
18
|
+
defaultVisible = false,
|
|
19
|
+
trigger = 'hover',
|
|
20
|
+
destroyTooltipOnHide = false,
|
|
21
|
+
mouseEnterDelay = 0.1,
|
|
22
|
+
mouseLeaveDelay = 0.1,
|
|
23
|
+
overlayClassName = '',
|
|
24
|
+
overlayStyle,
|
|
25
|
+
onVisibleChange,
|
|
26
|
+
align,
|
|
27
|
+
arrowPointAtCenter = false,
|
|
28
|
+
autoAdjustOverflow = true,
|
|
29
|
+
getPopupContainer,
|
|
30
|
+
className = '',
|
|
31
|
+
...rest
|
|
32
|
+
}) => {
|
|
33
|
+
return (
|
|
34
|
+
<StyledTooltip
|
|
35
|
+
title={title}
|
|
36
|
+
placement={placement}
|
|
37
|
+
open={visible}
|
|
38
|
+
defaultOpen={defaultVisible}
|
|
39
|
+
trigger={trigger}
|
|
40
|
+
destroyTooltipOnHide={destroyTooltipOnHide}
|
|
41
|
+
mouseEnterDelay={mouseEnterDelay}
|
|
42
|
+
mouseLeaveDelay={mouseLeaveDelay}
|
|
43
|
+
overlayClassName={classnames('cap-tooltip-overlay-v2', overlayClassName)}
|
|
44
|
+
overlayStyle={overlayStyle}
|
|
45
|
+
onOpenChange={onVisibleChange}
|
|
46
|
+
align={align}
|
|
47
|
+
arrow={{ pointAtCenter: arrowPointAtCenter }}
|
|
48
|
+
autoAdjustOverflow={autoAdjustOverflow}
|
|
49
|
+
getPopupContainer={getPopupContainer}
|
|
50
|
+
className={classnames('cap-tooltip-v2', className)}
|
|
51
|
+
{...rest}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</StyledTooltip>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
CapTooltip.propTypes = {
|
|
59
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
60
|
+
children: PropTypes.node,
|
|
61
|
+
placement: PropTypes.oneOf([
|
|
62
|
+
'top', 'left', 'right', 'bottom',
|
|
63
|
+
'topLeft', 'topRight', 'bottomLeft', 'bottomRight',
|
|
64
|
+
'leftTop', 'leftBottom', 'rightTop', 'rightBottom',
|
|
65
|
+
]),
|
|
66
|
+
visible: PropTypes.bool,
|
|
67
|
+
defaultVisible: PropTypes.bool,
|
|
68
|
+
trigger: PropTypes.oneOfType([
|
|
69
|
+
PropTypes.string,
|
|
70
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
71
|
+
]),
|
|
72
|
+
destroyTooltipOnHide: PropTypes.bool,
|
|
73
|
+
mouseEnterDelay: PropTypes.number,
|
|
74
|
+
mouseLeaveDelay: PropTypes.number,
|
|
75
|
+
overlayClassName: PropTypes.string,
|
|
76
|
+
overlayStyle: PropTypes.object,
|
|
77
|
+
onVisibleChange: PropTypes.func,
|
|
78
|
+
align: PropTypes.object,
|
|
79
|
+
arrowPointAtCenter: PropTypes.bool,
|
|
80
|
+
autoAdjustOverflow: PropTypes.bool,
|
|
81
|
+
getPopupContainer: PropTypes.func,
|
|
82
|
+
className: PropTypes.string,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
CapTooltip.defaultProps = {
|
|
86
|
+
placement: 'top',
|
|
87
|
+
defaultVisible: false,
|
|
88
|
+
trigger: 'hover',
|
|
89
|
+
destroyTooltipOnHide: false,
|
|
90
|
+
mouseEnterDelay: 0.1,
|
|
91
|
+
mouseLeaveDelay: 0.1,
|
|
92
|
+
overlayClassName: '',
|
|
93
|
+
arrowPointAtCenter: false,
|
|
94
|
+
autoAdjustOverflow: true,
|
|
95
|
+
className: '',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default withStyles(CapTooltip, tooltipStyles);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components';
|
|
2
|
+
import * as styledVars from '../styled/variables';
|
|
3
|
+
|
|
4
|
+
export const tooltipStyles = css`
|
|
5
|
+
&.cap-tooltip-overlay-v2 {
|
|
6
|
+
.ant-tooltip-inner {
|
|
7
|
+
background-color: ${styledVars.CAP_G01};
|
|
8
|
+
color: ${styledVars.CAP_WHITE};
|
|
9
|
+
padding: 8px 12px;
|
|
10
|
+
font-size: 14px;
|
|
11
|
+
line-height: 20px;
|
|
12
|
+
border-radius: ${styledVars.RADIUS_04};
|
|
13
|
+
max-width: 300px;
|
|
14
|
+
word-wrap: break-word;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.ant-tooltip-arrow::before {
|
|
18
|
+
background-color: ${styledVars.CAP_G01};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.button-disabled-tooltip-wrapper {
|
|
23
|
+
display: inline-block;
|
|
24
|
+
cursor: not-allowed;
|
|
25
|
+
|
|
26
|
+
.ant-btn[disabled] {
|
|
27
|
+
pointer-events: none;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
export const StyledTooltipWrapper = styled.div`
|
|
33
|
+
display: inline-block;
|
|
34
|
+
`;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
// Enhanced CapUnifiedSelect supporting 4 scenarios with advanced features in a single TreeSelect
|
|
2
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import React, { useState, useEffect, useMemo, useCallback, memo } from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
|
-
import { TreeSelect,
|
|
5
|
+
import { TreeSelect, Input, Button } from 'antd-v5';
|
|
6
6
|
import styled from 'styled-components';
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import { InfoCircleOutlined, SearchOutlined, WarningFilled, DownOutlined } from '@ant-design/icons';
|
|
10
|
-
|
|
7
|
+
import * as styledVars from '../styled/variables';
|
|
8
|
+
import { CapLabel, CapTooltip, CapRow, CapIcon } from '../';
|
|
11
9
|
import withStyles from '../utils/withStyles';
|
|
12
|
-
import { SelectWrapper,
|
|
10
|
+
import { SelectWrapper, selectStyles } from './styles';
|
|
13
11
|
|
|
14
12
|
const StyledTreeSelect = styled(TreeSelect)`
|
|
15
13
|
${selectStyles}
|
|
@@ -55,14 +53,18 @@ const CapUnifiedSelect = ({
|
|
|
55
53
|
listItemHeight: 32,
|
|
56
54
|
};
|
|
57
55
|
|
|
58
|
-
const NoResult = ({ noResultText, className }) => (
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
const NoResult = memo(({ noResultText, className }) => (
|
|
57
|
+
<CapRow
|
|
58
|
+
className={classnames(className, "cap-unified-select-no-result")}
|
|
59
|
+
align="middle"
|
|
60
|
+
gap={8}
|
|
61
|
+
>
|
|
62
|
+
<CapIcon type="warning" size="s" />
|
|
63
|
+
<CapLabel className="cap-unified-select-no-result-text">{noResultText}</CapLabel>
|
|
64
|
+
</CapRow>
|
|
65
|
+
));
|
|
66
|
+
|
|
67
|
+
const getFilteredTreeData = useCallback((data, search) => {
|
|
66
68
|
if (!search) return data;
|
|
67
69
|
|
|
68
70
|
const filterNode = node => {
|
|
@@ -73,7 +75,6 @@ const CapUnifiedSelect = ({
|
|
|
73
75
|
const keyText = String(node.key || '').toLowerCase();
|
|
74
76
|
return keyText.includes(search.toLowerCase());
|
|
75
77
|
} else {
|
|
76
|
-
// Default case, fall back to label
|
|
77
78
|
const labelText = node.label?.toLowerCase() || '';
|
|
78
79
|
return labelText.includes(search.toLowerCase());
|
|
79
80
|
}
|
|
@@ -89,86 +90,91 @@ const CapUnifiedSelect = ({
|
|
|
89
90
|
}).filter(Boolean);
|
|
90
91
|
|
|
91
92
|
return loop(data);
|
|
92
|
-
};
|
|
93
|
+
}, [searchBasedOn]);
|
|
93
94
|
|
|
94
|
-
const flattenLeafValues = nodes =>
|
|
95
|
-
nodes?.flatMap(node => node.children ? flattenLeafValues(node.children) : [node.value]) || [];
|
|
95
|
+
const flattenLeafValues = useCallback(nodes =>
|
|
96
|
+
nodes?.flatMap(node => node.children ? flattenLeafValues(node.children) : [node.value]) || [], []);
|
|
96
97
|
|
|
97
|
-
const isMulti = type === 'multiSelect' || type === 'multiTreeSelect';
|
|
98
|
-
const isTree = type === 'treeSelect' || type === 'multiTreeSelect';
|
|
98
|
+
const isMulti = useMemo(() => type === 'multiSelect' || type === 'multiTreeSelect', [type]);
|
|
99
|
+
const isTree = useMemo(() => type === 'treeSelect' || type === 'multiTreeSelect', [type]);
|
|
99
100
|
|
|
100
|
-
const dataSource =
|
|
101
|
+
const dataSource = useMemo(() => {
|
|
102
|
+
return isTree ? options : options.map(opt => ({ title: opt.label, value: opt.value, key: opt.key || opt.value }));
|
|
103
|
+
}, [isTree, options]);
|
|
101
104
|
|
|
102
|
-
const filteredTree = getFilteredTreeData(dataSource, searchText);
|
|
103
|
-
const leafValues = flattenLeafValues(filteredTree);
|
|
105
|
+
const filteredTree = useMemo(() => getFilteredTreeData(dataSource, searchText), [dataSource, searchText]);
|
|
106
|
+
const leafValues = useMemo(() => flattenLeafValues(filteredTree), [filteredTree]);
|
|
104
107
|
|
|
105
|
-
const handleSelectAll = () => {
|
|
108
|
+
const handleSelectAll = useCallback(() => {
|
|
106
109
|
const availableValues = leafValues;
|
|
107
110
|
if (allSelected) {
|
|
108
|
-
// If currently all selected, then unselect all
|
|
109
111
|
setTempValue([]);
|
|
110
112
|
setAllSelected(false);
|
|
111
113
|
} else {
|
|
112
|
-
// Otherwise select all available options
|
|
113
114
|
setTempValue(availableValues);
|
|
114
115
|
setAllSelected(true);
|
|
115
116
|
}
|
|
116
|
-
};
|
|
117
|
+
}, [allSelected, leafValues]);
|
|
117
118
|
|
|
118
119
|
useEffect(() => {
|
|
119
120
|
if (isMulti && Array.isArray(tempValue)) {
|
|
120
|
-
|
|
121
|
+
const allItemsSelected = tempValue.length > 0 && leafValues.length > 0 && tempValue.length === leafValues.length;
|
|
122
|
+
setAllSelected(allItemsSelected);
|
|
121
123
|
}
|
|
122
124
|
}, [tempValue, leafValues, isMulti]);
|
|
123
125
|
|
|
124
|
-
const handleConfirm = () => {
|
|
125
|
-
console.log('Confirm clicked');
|
|
126
|
+
const handleConfirm = useCallback(() => {
|
|
126
127
|
if (onChange) onChange(tempValue);
|
|
127
|
-
};
|
|
128
|
+
}, [onChange, tempValue]);
|
|
128
129
|
|
|
129
|
-
const handleCancel = () => {
|
|
130
|
-
console.log('Cancel clicked');
|
|
130
|
+
const handleCancel = useCallback(() => {
|
|
131
131
|
setTempValue(value);
|
|
132
|
-
};
|
|
132
|
+
}, [value]);
|
|
133
133
|
|
|
134
|
-
const handleTempChange = newValue => {
|
|
134
|
+
const handleTempChange = useCallback(newValue => {
|
|
135
135
|
setTempValue(newValue);
|
|
136
|
-
};
|
|
136
|
+
}, []);
|
|
137
137
|
|
|
138
|
-
const suffix =
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
const suffix = useMemo(() => {
|
|
139
|
+
return isMulti && Array.isArray(value) && value?.length > 1 ? (
|
|
140
|
+
<>
|
|
141
|
+
<span>+{value.length - 1} more <CapIcon type="down" size="s" /></span>
|
|
142
|
+
</>
|
|
143
|
+
) : (
|
|
144
|
+
<CapIcon type="down" size="s" />
|
|
145
|
+
);
|
|
146
|
+
}, [isMulti, value]);
|
|
145
147
|
|
|
146
|
-
const prefix = () => {
|
|
148
|
+
const prefix = useMemo(() => {
|
|
147
149
|
if (isMulti && Array.isArray(value) && value?.length > 0) {
|
|
148
150
|
const selectedLabels = options.filter(opt => value.includes(opt.value)).map(opt => opt.label);
|
|
149
151
|
return selectedLabels[0];
|
|
150
152
|
}
|
|
151
153
|
return null;
|
|
152
|
-
};
|
|
154
|
+
}, [isMulti, value, options]);
|
|
153
155
|
|
|
154
|
-
const renderHeader = () => {
|
|
156
|
+
const renderHeader = useCallback(() => {
|
|
155
157
|
if (!headerLabel && !tooltip) return null;
|
|
156
158
|
return (
|
|
157
159
|
<>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
+
<CapRow
|
|
161
|
+
className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header')}
|
|
162
|
+
align="middle"
|
|
163
|
+
gap={8}
|
|
164
|
+
>
|
|
165
|
+
{headerLabel && <CapLabel type="label16" className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-label')}>{headerLabel}</CapLabel>}
|
|
160
166
|
{tooltip && (
|
|
161
|
-
<
|
|
162
|
-
<
|
|
163
|
-
</
|
|
167
|
+
<CapTooltip title={tooltip} className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-tooltip')}>
|
|
168
|
+
<CapIcon type="info-circle" size="s" />
|
|
169
|
+
</CapTooltip>
|
|
164
170
|
)}
|
|
165
|
-
</
|
|
171
|
+
</CapRow>
|
|
166
172
|
<div className="cap-unified-select-header-byline-text">
|
|
167
|
-
{bylineText && <
|
|
173
|
+
{bylineText && <CapLabel className={classnames(disabled ? 'disabled' : '', 'cap-unified-select-header-byline-text')}>{bylineText}</CapLabel>}
|
|
168
174
|
</div>
|
|
169
175
|
</>
|
|
170
176
|
);
|
|
171
|
-
};
|
|
177
|
+
}, [headerLabel, tooltip, bylineText, disabled]);
|
|
172
178
|
|
|
173
179
|
const renderDropdown = () => {
|
|
174
180
|
const currentItems = filteredTree;
|
|
@@ -184,53 +190,55 @@ const CapUnifiedSelect = ({
|
|
|
184
190
|
return (
|
|
185
191
|
<div className={classnames(popupClassName, `${type}-popup-container`)}>
|
|
186
192
|
{showSearch && (
|
|
187
|
-
<
|
|
193
|
+
<CapRow className={classnames("cap-unified-select-search-container")} align="middle">
|
|
188
194
|
<Input
|
|
189
|
-
prefix={<
|
|
195
|
+
prefix={<CapIcon type="search" size="s" style={{ color: styledVars.CAP_G06 }} />}
|
|
190
196
|
placeholder="Search"
|
|
191
197
|
variant="borderless"
|
|
192
198
|
value={searchText}
|
|
193
199
|
onChange={e => setSearchText(e.target.value)}
|
|
194
200
|
onKeyDown={e => e.stopPropagation()}
|
|
195
201
|
/>
|
|
196
|
-
</
|
|
202
|
+
</CapRow>
|
|
197
203
|
)}
|
|
198
204
|
{isMulti && showUpload && (
|
|
199
|
-
<
|
|
205
|
+
<CapRow className={classnames("cap-unified-select-upload-container")} align="middle">
|
|
200
206
|
<Button
|
|
201
207
|
type="link"
|
|
202
|
-
icon={<
|
|
208
|
+
icon={<CapIcon type="upload" size="s" />}
|
|
203
209
|
onClick={() => {}}
|
|
204
|
-
|
|
205
|
-
color: '#2466EA', // AntD primary blue
|
|
206
|
-
display: 'flex',
|
|
207
|
-
alignItems: 'center',
|
|
208
|
-
fontSize: '14px',
|
|
209
|
-
fontWeight: '400',
|
|
210
|
-
lineHeight: '20px',
|
|
211
|
-
}}
|
|
210
|
+
className={classnames("cap-unified-select-upload-button")}
|
|
212
211
|
>
|
|
213
212
|
Upload
|
|
214
213
|
</Button>
|
|
215
|
-
</
|
|
214
|
+
</CapRow>
|
|
216
215
|
)}
|
|
217
216
|
{isMulti && currentItems.length > 0 && (
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
<CapRow
|
|
218
|
+
className={classnames("cap-unified-select-select-all-container")}
|
|
219
|
+
onClick={e => { e.stopPropagation(); handleSelectAll(); }}
|
|
220
|
+
align="middle"
|
|
221
|
+
gap={8}
|
|
222
|
+
>
|
|
223
|
+
<input type="checkbox" checked={allSelected} className={classnames("cap-unified-select-select-all-checkbox")} onClick={e => e.stopPropagation()} />
|
|
224
|
+
<CapLabel className={classnames("cap-unified-select-select-all-label")}>Select all</CapLabel>
|
|
225
|
+
</CapRow>
|
|
222
226
|
)}
|
|
223
227
|
|
|
224
228
|
{currentItems.length === 0 ? <NoResult noResultText={noResultText} className={classnames(className, "cap-unified-select-no-result")}/> : menu}
|
|
225
229
|
|
|
226
230
|
{currentItems.length > 0 && isMulti && (
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
231
|
+
<CapRow
|
|
232
|
+
className={classnames("cap-unified-select-confirm-container")}
|
|
233
|
+
justify="space-between"
|
|
234
|
+
align="middle"
|
|
235
|
+
>
|
|
236
|
+
<CapRow gap={8}>
|
|
237
|
+
<Button type="primary" size="small" className={classnames("cap-unified-select-confirm-button")} onClick={e => { e.stopPropagation(); handleConfirm(); }}>Confirm</Button>
|
|
230
238
|
<Button type="text" size="small" onClick={e => { e.stopPropagation(); handleCancel(); }}>Cancel</Button>
|
|
231
|
-
</
|
|
232
|
-
{selectedCount > 0 && <
|
|
233
|
-
</
|
|
239
|
+
</CapRow>
|
|
240
|
+
{selectedCount > 0 && <CapLabel className={classnames("cap-unified-select-selected-count")}>{selectedCount} selected</CapLabel>}
|
|
241
|
+
</CapRow>
|
|
234
242
|
)}
|
|
235
243
|
</div>
|
|
236
244
|
);
|
|
@@ -245,9 +253,10 @@ const CapUnifiedSelect = ({
|
|
|
245
253
|
value={customPopupRender ? tempValue : value}
|
|
246
254
|
onChange={customPopupRender ? handleTempChange : onChange}
|
|
247
255
|
placeholder={placeholder}
|
|
256
|
+
showSearch={false}
|
|
248
257
|
maxTagCount={0}
|
|
249
258
|
maxTagPlaceholder={() => null}
|
|
250
|
-
prefix={isMulti && value.length > 0 && prefix
|
|
259
|
+
prefix={isMulti && value.length > 0 && prefix}
|
|
251
260
|
suffixIcon={suffix}
|
|
252
261
|
className={classnames(`cap-unified-tree-select ${className || ''}`)}
|
|
253
262
|
style={style}
|
|
@@ -262,7 +271,7 @@ const CapUnifiedSelect = ({
|
|
|
262
271
|
{...treeSelectVirtualizationProps}
|
|
263
272
|
popupRender={renderCustomDropdown}
|
|
264
273
|
/>
|
|
265
|
-
{isError && <
|
|
274
|
+
{isError && <CapLabel className={classnames("cap-unified-select-status")} style={{ color: 'red' }}>{errorMessage}</CapLabel>}
|
|
266
275
|
</>
|
|
267
276
|
);
|
|
268
277
|
};
|
|
@@ -300,12 +309,18 @@ CapUnifiedSelect.propTypes = {
|
|
|
300
309
|
|
|
301
310
|
CapUnifiedSelect.defaultProps = {
|
|
302
311
|
type: 'select',
|
|
312
|
+
options: [],
|
|
313
|
+
placeholder: 'Select an option',
|
|
303
314
|
allowClear: false,
|
|
304
|
-
customPopupRender:
|
|
315
|
+
customPopupRender: true,
|
|
305
316
|
showSearch: true,
|
|
306
317
|
searchBasedOn: 'label',
|
|
307
318
|
className: '',
|
|
308
319
|
popupClassName: '',
|
|
320
|
+
disabled: false,
|
|
321
|
+
showUpload: false,
|
|
322
|
+
isError: false,
|
|
323
|
+
noResultText: 'No results found'
|
|
309
324
|
};
|
|
310
325
|
|
|
311
326
|
export default withStyles(CapUnifiedSelect, selectStyles);
|