Refactor dropdown and put value state out
parent
7311489ade
commit
459036719e
|
@ -1,28 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Ripple from '../ripple';
|
||||
import style from './style';
|
||||
|
||||
const _selectValue = (value, dataSource) => {
|
||||
let item;
|
||||
if (value) {
|
||||
for (item of dataSource) {
|
||||
if (item.value.toString() === value.toString()) break;
|
||||
}
|
||||
return item;
|
||||
} else {
|
||||
return dataSource[0];
|
||||
}
|
||||
};
|
||||
|
||||
class Dropdown extends React.Component {
|
||||
static propTypes = {
|
||||
auto: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
dataSource: React.PropTypes.array.isRequired,
|
||||
disabled: React.PropTypes.bool,
|
||||
label: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
source: React.PropTypes.array.isRequired,
|
||||
template: React.PropTypes.func,
|
||||
value: React.PropTypes.string
|
||||
};
|
||||
|
@ -35,91 +21,64 @@ class Dropdown extends React.Component {
|
|||
|
||||
state = {
|
||||
active: false,
|
||||
selected: _selectValue(this.props.value, this.props.dataSource),
|
||||
up: false,
|
||||
width: undefined
|
||||
up: false
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.setState({
|
||||
width: ReactDOM.findDOMNode(this).getBoundingClientRect().width
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate (prev_props, prev_state) {
|
||||
if (this.props.onChange && prev_state.selected !== this.state.selected && prev_state.active) {
|
||||
this.props.onChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = (event) => {
|
||||
const client = event.target.getBoundingClientRect();
|
||||
const screen_height = window.innerHeight || document.documentElement.offsetHeight;
|
||||
const up = this.props.auto ? client.top > ((screen_height / 2) + client.height) : false;
|
||||
this.setState({ active: true, up: up });
|
||||
this.setState({active: true, up: up});
|
||||
};
|
||||
|
||||
handleClickValue = (id) => {
|
||||
if (!this.props.disabled) {
|
||||
const value = id.toString();
|
||||
for (const item of this.props.dataSource) {
|
||||
if (item.value.toString() === value) {
|
||||
this.setState({active: false, selected: item});
|
||||
break;
|
||||
}
|
||||
}
|
||||
handleSelect = (item) => {
|
||||
if (!this.props.disabled && this.props.onChange) {
|
||||
this.props.onChange(item);
|
||||
this.setState({active: false});
|
||||
}
|
||||
};
|
||||
|
||||
renderValues () {
|
||||
const items = this.props.dataSource.map((item, index) => {
|
||||
let className;
|
||||
if (item.value === this.state.selected.value) className = ` ${style.selected}`;
|
||||
getSelectedItem = () => {
|
||||
if (this.props.value) {
|
||||
for (const item of this.props.source) {
|
||||
if (item.value === this.props.value) return item;
|
||||
}
|
||||
} else {
|
||||
return this.props.source[0];
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<li
|
||||
key={index}
|
||||
className={className}
|
||||
id={item.value}
|
||||
onClick={this.handleClickValue.bind(this, item.value)}
|
||||
>
|
||||
{ this.props.template ? this.props.template(item) : item.label }
|
||||
<Ripple className={style.ripple}/>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
let className = style.values;
|
||||
const valuesStyle = {width: this.state.width};
|
||||
if (this.state.up) className += ` ${style.up}`;
|
||||
|
||||
return <ul ref='values' className={className} style={valuesStyle}>{ items }</ul>;
|
||||
renderItem (item, idx) {
|
||||
const className = item.value === this.props.value ? style.selected : null;
|
||||
return (
|
||||
<li key={idx} className={className} onMouseDown={this.handleSelect.bind(this, item.value)}>
|
||||
{ this.props.template ? this.props.template(item) : item.label }
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
if (this.props.disabled) className += ` ${style.disabled}`;
|
||||
const selected = this.getSelectedItem();
|
||||
if (this.state.up) className += ` ${style.up}`;
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
if (this.props.disabled) className += ` ${style.disabled}`;
|
||||
if (this.props.className) className += ` ${this.props.className}`;
|
||||
|
||||
return (
|
||||
<div data-react-toolbox='dropdown' className={className}>
|
||||
{this.props.label ? <label className={style.label}>{this.props.label}</label> : null}
|
||||
{ this.renderValues() }
|
||||
{ this.props.label ? <label className={style.label}>{this.props.label}</label> : null }
|
||||
|
||||
<ul ref='values' className={style.values}>
|
||||
{ this.props.source.map(this.renderItem.bind(this)) }
|
||||
</ul>
|
||||
|
||||
<div ref='value' className={style.value} onClick={this.handleClick}>
|
||||
{ this.props.template ? this.props.template(this.state.selected) : <span>{this.state.selected.label}</span> }
|
||||
{ this.props.template ? this.props.template(selected) : <span>{selected.label}</span> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getValue () {
|
||||
return this.state.selected.value;
|
||||
}
|
||||
|
||||
setValue (data) {
|
||||
this.setState({selected: data});
|
||||
}
|
||||
}
|
||||
|
||||
export default Dropdown;
|
||||
|
|
|
@ -13,13 +13,26 @@ const countries: [
|
|||
{ value: 'EN-en', label: 'USA'}
|
||||
];
|
||||
|
||||
const DropdownTest = () => (
|
||||
<Dropdown
|
||||
auto
|
||||
dataSource={countries}
|
||||
value='TH-th'
|
||||
/>
|
||||
);
|
||||
class DropdownTest extends React.Component {
|
||||
state = {
|
||||
value: 'ES-es',
|
||||
};
|
||||
|
||||
handleChange = (value) => {
|
||||
this.setState({value: value});
|
||||
};
|
||||
|
||||
render () {
|
||||
return (
|
||||
<Dropdown
|
||||
auto={true}
|
||||
onChange={this.handleChange}
|
||||
source={countries}
|
||||
value={this.state.value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
@ -28,16 +41,9 @@ const DropdownTest = () => (
|
|||
|:-----|:-----|:-----|:-----|
|
||||
| `auto` | `Boolean` | `true` | If true, the dropdown will open up or down depending on the position in the screen .|
|
||||
| `className` | `String` | `''` | Set the class to give custom styles to the dropdown.
|
||||
| `dataSource` | `Array` | | Array of data objects with the data to represent in the dropdown.
|
||||
| `disabled` | `Boolean` | `false` | Set the component as disabled.
|
||||
| `label` | `String` | | The text string to use for the floating label element.
|
||||
| `onChange` | `Function` | | Callback function that is fired when the component's value changes.
|
||||
| `source` | `Array` | | Array of data objects with the data to represent in the dropdown.
|
||||
| `template` | `Function` | | Callback function that returns a JSX template to represent the element.
|
||||
| `value` | `String` | | Default value using JSON data.
|
||||
|
||||
## Methods
|
||||
|
||||
This component has state to control its value and how is it rendered. It exposes the following instance methods:
|
||||
|
||||
- `getValue` is used to retrieve the current value.
|
||||
- `setValue` to force a new value.
|
||||
|
|
|
@ -34,6 +34,14 @@
|
|||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
&:not(.up) > .values {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
&.up > .values {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
|
@ -44,6 +52,7 @@
|
|||
.values {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
list-style: none;
|
||||
|
@ -64,14 +73,6 @@
|
|||
color: $dropdown-color-primary;
|
||||
}
|
||||
}
|
||||
&:not(.up) {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
&.up {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
|
@ -100,8 +101,3 @@
|
|||
transition: transform $animation-duration $animation-curve-default;
|
||||
}
|
||||
}
|
||||
|
||||
.ripple {
|
||||
z-index: 0;
|
||||
background-color: $color-divider;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class DropdownTest extends React.Component {
|
||||
state = {
|
||||
selected: null
|
||||
selected: 3
|
||||
};
|
||||
|
||||
albums = [
|
||||
|
@ -10,6 +10,10 @@ class DropdownTest extends React.Component {
|
|||
{ value: 4, artist: 'Pixies', album: 'Doolittle', img: 'http://www.resident-music.com/image/cache/data/Emilys_Packshots/Pixies/Pixies_Doolittlke-500x500.jpg' }
|
||||
];
|
||||
|
||||
handleChange = (value) => {
|
||||
this.setState({selected: value});
|
||||
};
|
||||
|
||||
customItem (item) {
|
||||
const style = {
|
||||
width: 36,
|
||||
|
@ -33,7 +37,8 @@ class DropdownTest extends React.Component {
|
|||
return (
|
||||
<Dropdown
|
||||
auto={false}
|
||||
dataSource={this.albums}
|
||||
source={this.albums}
|
||||
onChange={this.handleChange}
|
||||
label='Select your favorite album'
|
||||
template={this.customItem}
|
||||
value={this.state.selected}
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
import React from 'react';
|
||||
import Dropdown from '../../components/dropdown';
|
||||
|
||||
const countries = [
|
||||
{ value: 'EN-gb', label: 'England', img: 'http://' },
|
||||
{ value: 'ES-es', label: 'Spain', img: 'http://' },
|
||||
{ value: 'TH-th', label: 'Thailand', img: 'http://' },
|
||||
{ value: 'EN-en', label: 'USA', img: 'http://' },
|
||||
{ value: 'FR-fr', label: 'France', img: 'http://' }
|
||||
];
|
||||
|
||||
class DropdownTest extends React.Component {
|
||||
state = {
|
||||
countries: [
|
||||
{ value: 'ES-es', label: 'Spain', img: 'http://' },
|
||||
{ value: 'TH-th', label: 'Thailand', img: 'http://' },
|
||||
{ value: 'EN-gb', label: 'England', img: 'http://' },
|
||||
{ value: 'EN-en', label: 'USA', img: 'http://' },
|
||||
{ value: 'FR-fr', label: 'France', img: 'http://' }
|
||||
],
|
||||
selected: 'TH-th'
|
||||
dropdown1: 'ES-es',
|
||||
dropdown4: 'TH-th'
|
||||
};
|
||||
|
||||
handleChange = (dropdown) => {
|
||||
console.log('[DROPDOWN]', dropdown.getValue());
|
||||
handleChange = (dropdown, value) => {
|
||||
const newState = {};
|
||||
newState[dropdown] = value;
|
||||
this.setState(newState);
|
||||
};
|
||||
|
||||
customDropdownItem (data) {
|
||||
|
@ -41,10 +45,31 @@ class DropdownTest extends React.Component {
|
|||
<section>
|
||||
<h5>Dropdown</h5>
|
||||
<p>lorem ipsum...</p>
|
||||
<Dropdown dataSource={this.state.countries} label="Countries" onChange={this.handleChange}/>
|
||||
<Dropdown dataSource={this.state.countries} disabled={true} onChange={this.handleChange}/>
|
||||
<Dropdown dataSource={this.state.countries} value={this.state.selected} onChange={this.handleChange}/>
|
||||
<Dropdown dataSource={this.state.countries} value={this.state.selected} template={this.customDropdownItem} onChange={this.handleChange}/>
|
||||
|
||||
<Dropdown
|
||||
onChange={this.handleChange.bind(this, 'dropdown1')}
|
||||
source={countries}
|
||||
template={this.customDropdownItem}
|
||||
value={this.state.dropdown1}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
label="Countries"
|
||||
onChange={this.handleChange.bind(this, 'dropdown2')}
|
||||
source={countries}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
onChange={this.handleChange.bind(this, 'dropdown4')}
|
||||
source={countries}
|
||||
value={this.state.dropdown4}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
source={countries}
|
||||
disabled={true}
|
||||
onChange={this.handleChange.bind(this, 'dropdown3')}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue