Skip to content

Commit 1a359fe

Browse files
committed
Merge branch 'feature/improve-select-list'
2 parents e4392e4 + 8212512 commit 1a359fe

File tree

4 files changed

+118
-196
lines changed

4 files changed

+118
-196
lines changed

src/react-chayns-selectlist/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ You can set the following props on a SelectList element:
4141
|--------------|-------------------------------------------------------------------------------|-------------|--------------|
4242
| onChange | Callback that will be triggered when the selection changes | function | |
4343
| defaultValue | Sets the id of an element that should be preselected | string, int | |
44-
| selectFirst | Automatically select the first entry, triggers onChange-callback | boolean | false |
44+
| selectFirst | Automatically select the first entry, triggers onChange-callback (deprecated) | boolean | false |
4545
| className | Sets the css-class of the selectlist | boolean | false |
4646

4747

src/react-chayns-selectlist/component/SelectItem.jsx

+81-25
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,100 @@
1-
import React from 'react';
1+
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
3+
import { CSSTransitionGroup } from 'react-transition-group';
34

4-
5-
export default class SelectItem extends React.Component {
6-
static componentName = 'SelectItem';
7-
5+
export default class SelectItem extends Component {
86
static propTypes = {
9-
id: PropTypes.oneOfType([ // eslint-disable-line react/no-unused-prop-types
10-
PropTypes.string,
11-
PropTypes.number
12-
]),
13-
name: PropTypes.oneOfType([ // eslint-disable-line react/no-unused-prop-types
7+
id: PropTypes.number,
8+
changeListItem: PropTypes.func,
9+
selectListId: PropTypes.oneOfType([
10+
PropTypes.number,
1411
PropTypes.string,
15-
PropTypes.node,
16-
PropTypes.arrayOf(PropTypes.node),
17-
]),
18-
value: PropTypes.oneOfType([ // eslint-disable-line react/no-unused-prop-types
12+
]).isRequired,
13+
className: PropTypes.string,
14+
disabled: PropTypes.bool,
15+
children: PropTypes.node,
16+
name: PropTypes.string,
17+
value: PropTypes.oneOfType([
1918
PropTypes.object,
2019
PropTypes.array,
2120
]),
22-
disabled: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types
23-
className: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
24-
children: PropTypes.node,
21+
selectListSelectedId: PropTypes.number,
2522
};
2623

2724
static defaultProps = {
2825
id: null,
29-
name: null,
30-
value: null,
31-
disabled: null,
32-
className: null,
26+
className: '',
27+
disabled: false,
3328
children: null,
29+
changeListItem: null,
30+
name: '',
31+
value: null,
32+
selectListSelectedId: null,
3433
};
3534

35+
constructor(props) {
36+
super(props);
37+
38+
this.radioId = this._getRadioId(props.id);
39+
}
40+
41+
_handleChange = () => {
42+
const { changeListItem, id, value } = this.props;
43+
44+
if (changeListItem) {
45+
changeListItem(id, value);
46+
}
47+
};
48+
49+
_getRadioId(id) {
50+
const { selectListId } = this.props;
51+
52+
return `${selectListId}-${id}`;
53+
}
54+
3655
render() {
37-
const { children } = this.props;
56+
const {
57+
id,
58+
className,
59+
selectListId,
60+
disabled,
61+
name,
62+
selectListSelectedId,
63+
children,
64+
} = this.props;
65+
66+
const checked = (id === selectListSelectedId);
67+
68+
return (
69+
<div
70+
key={id}
71+
className={className}
72+
>
73+
<input
74+
name={selectListId}
75+
type="radio"
76+
className="radio"
77+
id={this.radioId}
78+
checked={checked}
79+
onChange={this._handleChange}
80+
disabled={disabled}
81+
/>
82+
83+
<label htmlFor={this.radioId}>
84+
{name}
85+
</label>
3886

39-
return(
40-
<div className="selectlist__selectitem">
41-
{children}
87+
<CSSTransitionGroup
88+
transitionName="react-fade"
89+
transitionEnterTimeout={500}
90+
transitionLeaveTimeout={500}
91+
>
92+
{checked && children && (
93+
<div className="selectlist__selectitem">
94+
{children}
95+
</div>
96+
)}
97+
</CSSTransitionGroup>
4298
</div>
4399
);
44100
}

src/react-chayns-selectlist/component/SelectList.jsx

+36-70
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33

4-
import SelectItem from './SelectItem';
5-
import SelectItemInternal from './internal/SelectItemInternal';
6-
74
const ANIMATION_TIMEOUT = 500;
85

96
export default class SelectList extends React.Component {
@@ -19,6 +16,10 @@ export default class SelectList extends React.Component {
1916
PropTypes.string,
2017
PropTypes.number
2118
]),
19+
children: PropTypes.oneOfType([
20+
PropTypes.node,
21+
PropTypes.arrayOf(PropTypes.node)
22+
]),
2223
selectFirst: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types
2324
className: PropTypes.string,
2425
};
@@ -29,14 +30,14 @@ export default class SelectList extends React.Component {
2930
value: null,
3031
onChange: null,
3132
selectFirst: null,
33+
children: null,
3234
};
3335

3436
constructor(props) {
3537
super(props);
3638

3739
this.state = {
3840
selectedId: props.defaultValue || 0,
39-
children: []
4041
};
4142

4243
if(props.defaultValue && props.onChange) {
@@ -48,7 +49,10 @@ export default class SelectList extends React.Component {
4849
this.selectListId = `cc_selectlist__${SelectList.maxId}`;
4950
SelectList.maxId += 1;
5051

51-
this._cleanChildren(this.props);
52+
const { children, selectFirst } = this.props;
53+
if (selectFirst) {
54+
this.calculateFirst(children);
55+
}
5256
}
5357

5458
componentWillReceiveProps(nextProps) {
@@ -59,8 +63,6 @@ export default class SelectList extends React.Component {
5963
selectedId: nextProps.value,
6064
});
6165
}
62-
63-
this._cleanChildren(nextProps);
6466
}
6567

6668
_changeActiveItem = (id, value) => {
@@ -91,83 +93,47 @@ export default class SelectList extends React.Component {
9193
});
9294
};
9395

94-
_cleanChildren(props) {
95-
const { selectedId } = this.state;
96-
const children = [];
97-
98-
if(window.chayns.utils.isArray(props.children)) {
99-
props.children.map((child) => {
100-
if(child && child.type && child.type.componentName === SelectItem.componentName) {
101-
if (child.props
102-
&& (child.props.id || child.props.id === 0)
103-
&& child.props.name) {
104-
children.push(child);
105-
}
106-
}
107-
});
108-
}
109-
110-
if(selectedId === 0 && props.selectFirst && children.length > 0) {
111-
this._selectFirstItem(children);
96+
calculateFirst(children) {
97+
if (!children) {
98+
return;
11299
}
113100

114-
this.setState({
115-
children
116-
});
117-
}
101+
let firstItemId = 0;
118102

119-
_selectFirstItem(children) {
120-
for(let i = 0, z = children.length; i < z; i += 1) {
121-
const { props } = children[i];
122-
123-
if(!props.disabled) {
124-
this._changeActiveItem(props.id, props.value);
125-
return;
103+
for (let i = 0, z = children.length; i < z; i += 1) {
104+
const child = children[i];
105+
if (React.isValidElement(child)) {
106+
if (child && child.props && child.props.id && !child.props.disabled) {
107+
firstItemId = child.props.id;
108+
break;
109+
}
126110
}
127111
}
128-
}
129-
130-
_renderChildren(children) {
131-
if(children.length === 1) return children;
132-
const { selectedId } = this.state;
133-
134-
return children.map((child) => {
135-
const {
136-
id,
137-
disabled,
138-
className,
139-
name,
140-
value,
141-
} = child.props;
142112

143-
return (
144-
<SelectItemInternal
145-
id={id}
146-
selectListId={this.selectListId}
147-
onChange={this._changeActiveItem}
148-
checked={id === selectedId}
149-
disabled={disabled}
150-
key={id}
151-
name={name}
152-
className={className}
153-
value={value}
154-
>
155-
156-
{child}
157-
</SelectItemInternal>
158-
);
113+
this.setState({
114+
selectedId: firstItemId,
159115
});
160116
}
161117

162-
163118
render() {
164-
const { className } = this.props;
165-
const { children } = this.state;
119+
const { className, children } = this.props;
120+
const { selectedId } = this.state;
121+
166122

167123
if(children.length > 0) {
168124
return (
169125
<div className={className}>
170-
{this._renderChildren(children)}
126+
{React.Children.map(children, (child) => {
127+
if (!React.isValidElement(child)) {
128+
return null;
129+
}
130+
131+
return React.cloneElement(child, {
132+
changeListItem: this._changeActiveItem,
133+
selectListId: this.selectListId,
134+
selectListSelectedId: selectedId,
135+
});
136+
})}
171137
</div>
172138
);
173139
}

0 commit comments

Comments
 (0)