Use Input component in dropdowns and make it homogeneous
parent
f3bcbf9d3b
commit
2c7d308271
|
@ -1,5 +1,7 @@
|
|||
import React from 'react';
|
||||
import ClassNames from 'classnames';
|
||||
import Input from '../input';
|
||||
import events from '../utils/events';
|
||||
import style from './style';
|
||||
|
||||
class Dropdown extends React.Component {
|
||||
|
@ -7,6 +9,7 @@ class Dropdown extends React.Component {
|
|||
auto: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
disabled: React.PropTypes.bool,
|
||||
error: React.PropTypes.string,
|
||||
label: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
source: React.PropTypes.array.isRequired,
|
||||
|
@ -25,7 +28,8 @@ class Dropdown extends React.Component {
|
|||
up: false
|
||||
};
|
||||
|
||||
handleClick = (event) => {
|
||||
handleMouseDown = (event) => {
|
||||
events.pauseEvent(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;
|
||||
|
@ -49,7 +53,24 @@ class Dropdown extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
renderItem (item, idx) {
|
||||
renderTemplateValue (selected) {
|
||||
const className = ClassNames(style.field, {
|
||||
[style.errored]: this.props.error,
|
||||
[style.disabled]: this.props.disabled
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={className} onMouseDown={this.handleMouseDown}>
|
||||
<div className={`${style.templateValue} ${style.value}`}>
|
||||
{this.props.template(selected)}
|
||||
</div>
|
||||
{this.props.label ? <label className={style.label}>{this.props.label}</label> : null}
|
||||
{this.props.error ? <span className={style.error}>{this.props.error}</span> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderValue (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)}>
|
||||
|
@ -59,6 +80,7 @@ class Dropdown extends React.Component {
|
|||
}
|
||||
|
||||
render () {
|
||||
const {template, source, ...others} = this.props;
|
||||
const selected = this.getSelectedItem();
|
||||
const className = ClassNames(style.root, {
|
||||
[style.up]: this.state.up,
|
||||
|
@ -68,15 +90,18 @@ class Dropdown extends React.Component {
|
|||
|
||||
return (
|
||||
<div data-react-toolbox='dropdown' className={className}>
|
||||
{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))}
|
||||
<Input
|
||||
{...others}
|
||||
className={style.value}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
readOnly
|
||||
type={template ? 'hidden' : null}
|
||||
value={selected.label}
|
||||
/>
|
||||
{template ? this.renderTemplateValue(selected) : null}
|
||||
<ul className={style.values} ref='values'>
|
||||
{source.map(this.renderValue.bind(this))}
|
||||
</ul>
|
||||
|
||||
<div ref='value' className={style.value} onClick={this.handleClick}>
|
||||
{this.props.template ? this.props.template(selected) : <span>{selected.label}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ class DropdownTest extends React.Component {
|
|||
| `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.
|
||||
| `disabled` | `Boolean` | `false` | Set the component as disabled.
|
||||
| `error` | `String` | | Give an error string to display under the field.|
|
||||
| `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.
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
.root {
|
||||
position: relative;
|
||||
width: inherit;
|
||||
margin-bottom: $dropdown-offset;
|
||||
color: $color-text;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid $input-text-bottom-border-color;
|
||||
&:not(.active) {
|
||||
> .values {
|
||||
max-height: 0;
|
||||
|
@ -25,15 +20,6 @@
|
|||
box-shadow: $zdepth-shadow-1;
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
color: $color-text-secondary;
|
||||
pointer-events: none;
|
||||
cursor: normal;
|
||||
border-bottom-style: dotted;
|
||||
> .value:after {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
&:not(.up) > .values {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
|
@ -42,19 +28,84 @@
|
|||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
cursor: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
> input {
|
||||
cursor: pointer;
|
||||
}
|
||||
&:after {
|
||||
$size: ($input-field-height / 7);
|
||||
$border: $size solid transparent;
|
||||
position: absolute;
|
||||
right: ($dropdown-offset / 2);
|
||||
top: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: $size solid $input-text-bottom-border-color;
|
||||
border-right: $border;
|
||||
border-left: $border;
|
||||
transition: transform $animation-duration $animation-curve-default;
|
||||
}
|
||||
}
|
||||
.field {
|
||||
position: relative;
|
||||
padding: $input-padding 0;
|
||||
cursor: pointer;
|
||||
&.errored {
|
||||
padding-bottom: 0;
|
||||
> .label {
|
||||
color: $input-text-error-color;
|
||||
}
|
||||
> .valueWrapper {
|
||||
border-bottom: 1px solid $input-text-error-color;
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
cursor: normal;
|
||||
pointer-events: none;
|
||||
> .templateValue {
|
||||
opacity: .7;
|
||||
border-bottom-style: dotted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.templateValue {
|
||||
border-bottom: 1px solid $input-text-bottom-border-color;
|
||||
color: $color-text;
|
||||
min-height: $input-field-height;
|
||||
background-color: $input-text-background-color;
|
||||
padding: $input-field-padding 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: $font-size-tiny;
|
||||
color: $color-text-secondary;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
font-size: $input-label-font-size;
|
||||
line-height: $input-field-font-size;
|
||||
color: $input-text-label-color;
|
||||
top: $input-focus-label-top;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-bottom: - $input-underline-height;
|
||||
font-size: $input-label-font-size;
|
||||
line-height: $input-underline-height;
|
||||
color: $input-text-error-color;
|
||||
}
|
||||
|
||||
.values {
|
||||
@include no-webkit-scrollbar;
|
||||
z-index: $z-index-high;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
list-style: none;
|
||||
background-color: $dropdown-color-white;
|
||||
|
@ -75,30 +126,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
display: block;
|
||||
> span {
|
||||
display: inline-block;
|
||||
height: $input-field-height;
|
||||
font-size: $input-field-font-size;
|
||||
line-height: $input-field-height;
|
||||
}
|
||||
> :not(span) {
|
||||
margin: ($dropdown-offset / 2) 0;
|
||||
}
|
||||
&:after {
|
||||
$size: ($input-field-height / 7);
|
||||
$border: $size solid transparent;
|
||||
position: absolute;
|
||||
right: ($dropdown-offset / 2);
|
||||
bottom: $dropdown-offset;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: $size solid $input-text-bottom-border-color;
|
||||
border-right: $border;
|
||||
border-left: $border;
|
||||
transition: transform $animation-duration $animation-curve-default;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
$input-padding: 2 * $unit;
|
||||
$input-field-padding: .8 * $unit;
|
||||
$input-field-font-size: 1.6 * $unit;
|
||||
$input-field-height: $input-field-padding * 2 + $input-field-font-size;
|
||||
$input-field-height: $input-field-padding * 2 + $input-field-font-size * 1.4;
|
||||
$input-label-font-size: 1.2 * $unit;
|
||||
$input-focus-label-top: .6 * $unit;
|
||||
$input-text-background-color: transparent !default;
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
.errored {
|
||||
padding-bottom: 0;
|
||||
> .input {
|
||||
margin-top: 1px;
|
||||
border-bottom-color: $input-text-error-color;
|
||||
&:focus {
|
||||
~ .label:not(.fixed) {
|
||||
|
|
|
@ -41,6 +41,7 @@ class DropdownTest extends React.Component {
|
|||
<p>lorem ipsum...</p>
|
||||
|
||||
<Dropdown
|
||||
label="Country"
|
||||
onChange={this.handleChange.bind(this, 'dropdown1')}
|
||||
source={countries}
|
||||
template={this.customDropdownItem}
|
||||
|
@ -48,21 +49,17 @@ class DropdownTest extends React.Component {
|
|||
/>
|
||||
|
||||
<Dropdown
|
||||
label="Countries"
|
||||
onChange={this.handleChange.bind(this, 'dropdown2')}
|
||||
source={countries}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
label="Country"
|
||||
onChange={this.handleChange.bind(this, 'dropdown4')}
|
||||
source={countries}
|
||||
value={this.state.dropdown4}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
source={countries}
|
||||
disabled
|
||||
label="Country"
|
||||
onChange={this.handleChange.bind(this, 'dropdown3')}
|
||||
source={countries}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue