Skip to content

Commit 3d95ecf

Browse files
change select group
1 parent 8a35fbf commit 3d95ecf

File tree

6 files changed

+588
-0
lines changed

6 files changed

+588
-0
lines changed

src/DTableGroupSelect/index.css

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
.group-select {
2+
position: relative;
3+
}
4+
5+
.group-select.custom-select {
6+
display: flex;
7+
padding: 5px 10px;
8+
border-radius: 3px;
9+
align-items: center;
10+
justify-content: space-between;
11+
max-width: 900px;
12+
user-select: none;
13+
text-align: left;
14+
border-color: 1px solid rgba(0, 40, 100, 0.12);
15+
height: auto;
16+
min-height: 38px;
17+
cursor: pointer;
18+
}
19+
20+
.group-select.custom-select:focus,
21+
.group-select.custom-select.focus {
22+
border-color: #1991eb !important;
23+
box-shadow: 0 0 0 2px rgba(70, 127, 207, 0.25);
24+
}
25+
26+
.group-select.custom-select.disabled:focus,
27+
.group-select.custom-select.focus.disabled,
28+
.group-select.custom-select.disabled:hover {
29+
border-color: rgba(0, 40, 100, 0.12) !important;
30+
box-shadow: unset;
31+
cursor: default;
32+
}
33+
34+
.group-select .sf3-font-down {
35+
display: inline-block;
36+
color: #999;
37+
transform: translateY(2px);
38+
transition: all 0.1s;
39+
font-size: 14px !important;
40+
}
41+
42+
.group-select .sf3-font-down:hover {
43+
color: #666;
44+
}
45+
46+
.group-select .selected-option {
47+
display: flex;
48+
flex: 1;
49+
overflow: hidden;
50+
flex-wrap: nowrap;
51+
align-items: center;
52+
justify-content: space-between;
53+
background: #fff;
54+
}
55+
56+
.group-select.selector-collaborator .option-group .option-group-content {
57+
padding: 10px;
58+
}
59+
60+
.group-select.custom-select.selector-collaborator .option-group .option-group-content {
61+
padding: 10px 0;
62+
}
63+
64+
.group-select.custom-select.selector-collaborator .option {
65+
padding: 5px 0 5px 10px !important;
66+
line-height: 20px;
67+
}
68+
69+
.group-select .select-placeholder {
70+
line-height: 1;
71+
font-size: 14px;
72+
white-space: nowrap;
73+
}
74+
75+
.group-select .selected-option-show {
76+
display: flex;
77+
flex-wrap: wrap;
78+
gap: 4px;
79+
}
80+
81+
.group-select .selected-option-show .selected-option-item {
82+
background-color: rgb(240, 240, 240);
83+
border-radius: 16px;
84+
display: flex;
85+
align-items: center;
86+
}
87+
88+
.group-select .selected-option-show .selected-option-item .selected-option-item-name {
89+
font-size: 13px;
90+
color: #212529;
91+
}
92+
93+
.group-select .selected-option-show .selected-option-item .dtable-icon-x {
94+
cursor: pointer;
95+
color: rgb(103, 103, 103);
96+
}

src/DTableGroupSelect/index.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import classnames from 'classnames';
4+
import ModalPortal from '../common/modal-portal.js';
5+
import SelectOptionGroup from './select-option-group.js';
6+
7+
import './index.css';
8+
9+
class DTableGroupSelect extends Component {
10+
11+
constructor(props) {
12+
super(props);
13+
this.state = {
14+
isShowSelectOptions: false
15+
};
16+
}
17+
18+
onSelectToggle = (event) => {
19+
event.preventDefault();
20+
if (this.state.isShowSelectOptions) event.stopPropagation();
21+
let eventClassName = event.target.className;
22+
if (eventClassName.indexOf('dtable-icon-x') > -1 || eventClassName === 'option-group-search') return;
23+
if (event.target.value === '') return;
24+
this.setState({
25+
isShowSelectOptions: !this.state.isShowSelectOptions
26+
});
27+
};
28+
29+
onClickOutside = (event) => {
30+
if (this.props.isShowSelected && event.target.className.includes('icon-fork-number')) {
31+
return;
32+
}
33+
if (!this.selector.contains(event.target)) {
34+
this.closeSelect();
35+
}
36+
};
37+
38+
closeSelect = () => {
39+
this.setState({ isShowSelectOptions: false });
40+
};
41+
42+
UNSAFE_componentWillReceiveProps(nextProps) {
43+
if (nextProps.selectedOptions.length !== this.props.selectedOptions.length) {
44+
// when selectedOptions change and dom rendered, calculate top
45+
setTimeout(() => {
46+
this.forceUpdate();
47+
}, 1);
48+
}
49+
}
50+
51+
getSelectedOptionTop = () => {
52+
if (!this.selector) return 38;
53+
const { height } = this.selector.getBoundingClientRect();
54+
return height;
55+
};
56+
57+
getFilterOptions = (searchValue) => {
58+
const { options } = this.props;
59+
const validSearchVal = searchValue.trim().toLowerCase();
60+
if (!validSearchVal) return options || [];
61+
return options.filter(option => option.name.toLowerCase().includes(validSearchVal));
62+
};
63+
64+
render() {
65+
let { className, selectedOptions, options, placeholder, searchPlaceholder, noOptionsPlaceholder, isInModal } = this.props;
66+
return (
67+
<div
68+
ref={(node) => this.selector = node}
69+
className={classnames('group-select custom-select',
70+
{ 'focus': this.state.isShowSelectOptions },
71+
className
72+
)}
73+
onClick={this.onSelectToggle}>
74+
<div className="selected-option">
75+
{selectedOptions.length > 0 ?
76+
<span className="selected-option-show">
77+
{selectedOptions.map(item =>
78+
<span key={item.id} className="selected-option-item mr-1 pr-1 pl-2">
79+
<span className='selected-option-item-name'>{item.name}</span>
80+
<i className="dtable-font dtable-icon-x ml-1" onClick={() => {this.props.onDeleteOption(item);}}></i>
81+
</span>
82+
)}
83+
</span>
84+
:
85+
<span className="select-placeholder">{placeholder}</span>
86+
}
87+
<i className="sf3-font-down sf3-font"></i>
88+
</div>
89+
{this.state.isShowSelectOptions && !isInModal && (
90+
<SelectOptionGroup
91+
selectedOptions={selectedOptions}
92+
top={this.getSelectedOptionTop()}
93+
options={options}
94+
onSelectOption={this.props.onSelectOption}
95+
searchPlaceholder={searchPlaceholder}
96+
noOptionsPlaceholder={noOptionsPlaceholder}
97+
onClickOutside={this.onClickOutside}
98+
closeSelect={this.closeSelect}
99+
getFilterOptions={this.getFilterOptions}
100+
/>
101+
)}
102+
{this.state.isShowSelectOptions && isInModal && (
103+
<ModalPortal>
104+
<SelectOptionGroup
105+
className={className}
106+
selectedOptions={selectedOptions}
107+
position={this.selector.getBoundingClientRect()}
108+
isInModal={isInModal}
109+
top={this.getSelectedOptionTop()}
110+
options={options}
111+
onSelectOption={this.props.onSelectOption}
112+
searchPlaceholder={searchPlaceholder}
113+
noOptionsPlaceholder={noOptionsPlaceholder}
114+
onClickOutside={this.onClickOutside}
115+
closeSelect={this.closeSelect}
116+
getFilterOptions={this.getFilterOptions}
117+
/>
118+
</ModalPortal>
119+
)}
120+
</div>
121+
);
122+
}
123+
}
124+
125+
DTableGroupSelect.propTypes = {
126+
className: PropTypes.string,
127+
selectedOptions: PropTypes.array,
128+
options: PropTypes.array,
129+
placeholder: PropTypes.string,
130+
onSelectOption: PropTypes.func,
131+
onDeleteOption: PropTypes.func,
132+
searchable: PropTypes.bool,
133+
searchPlaceholder: PropTypes.string,
134+
noOptionsPlaceholder: PropTypes.string,
135+
isInModal: PropTypes.bool, // if select component in a modal (option group need ModalPortal to show)
136+
};
137+
138+
export default DTableGroupSelect;

src/DTableGroupSelect/option.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
5+
class Option extends Component {
6+
7+
onSelectOption = (e) => {
8+
e.stopPropagation();
9+
this.props.onSelectOption(this.props.option);
10+
};
11+
12+
onMouseEnter = () => {
13+
if (!this.props.disableHover) {
14+
this.props.changeIndex(this.props.index);
15+
}
16+
};
17+
18+
onMouseLeave = () => {
19+
if (!this.props.disableHover) {
20+
this.props.changeIndex(-1);
21+
}
22+
};
23+
24+
render() {
25+
return (
26+
<div
27+
className={classNames('d-flex option', { 'option-active': this.props.isActive })}
28+
onClick={this.onSelectOption}
29+
onMouseEnter={this.onMouseEnter}
30+
onMouseLeave={this.onMouseLeave}
31+
>{this.props.children}
32+
</div>
33+
);
34+
}
35+
}
36+
37+
Option.propTypes = {
38+
index: PropTypes.number,
39+
isActive: PropTypes.bool,
40+
changeIndex: PropTypes.func,
41+
option: PropTypes.object,
42+
children: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
43+
onSelectOption: PropTypes.func,
44+
disableHover: PropTypes.bool,
45+
};
46+
47+
export default Option;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
.option-group {
2+
position: absolute;
3+
left: 0;
4+
min-height: 60px;
5+
max-height: 300px;
6+
min-width: 100%;
7+
max-width: 15rem;
8+
padding: 0.5rem 0;
9+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
10+
background: #fff;
11+
border: 1px solid rgba(0, 40, 100, 0.12);
12+
border-radius: 3px;
13+
z-index: 10001;
14+
}
15+
16+
.option-group .option-group-search {
17+
width: 100%;
18+
padding: 6px 10px;
19+
min-width: 170px;
20+
}
21+
22+
.option-group-search .form-control {
23+
height: 31px;
24+
}
25+
26+
.option-group .none-search-result {
27+
height: 100px;
28+
width: 100%;
29+
padding: 10px;
30+
color: #666666;
31+
}
32+
33+
.option-group .option-group-content {
34+
max-height: 252px;
35+
overflow-y: auto;
36+
}
37+
38+
.option {
39+
display: block;
40+
width: 100%;
41+
line-height: 24px;
42+
padding: 6px 10px;
43+
clear: both;
44+
font-weight: 400;
45+
text-align: inherit;
46+
background-color: transparent;
47+
border: 0;
48+
overflow: hidden;
49+
text-overflow: ellipsis;
50+
white-space: nowrap;
51+
display: flex;
52+
align-items: center;
53+
justify-content: space-between;
54+
}
55+
56+
.option .dtable-icon-check-mark {
57+
font-size: 12px;
58+
color: #798d99;
59+
}
60+
61+
.option.option-active {
62+
background-color: #20a0ff;
63+
color: #fff;
64+
cursor: pointer;
65+
}
66+
67+
.option.option-active .dtable-icon-check-mark,
68+
.option.option-active .select-option-name {
69+
color: #fff !important;
70+
}
71+
72+
.option .select-option-name .single-select-option {
73+
margin: 0 0 0 12px;
74+
}
75+
76+
.option .select-option-name .multiple-select-option {
77+
margin: 0;
78+
}
79+
80+
.option-group-selector-single-select .select-option-name {
81+
display: flex;
82+
align-items: center;
83+
justify-content: space-between;
84+
}
85+
86+
.option-group-selector-single-select .option:hover,
87+
.option-group-selector-single-select .option.option-active,
88+
.option-group-selector-multiple-select .option:hover,
89+
.option-group-selector-multiple-select .option.option-active {
90+
background-color: #f5f5f5;
91+
}

0 commit comments

Comments
 (0)