Dropdown SaSS
parent
96c4c5f4fa
commit
39f4d54064
|
@ -1,8 +1,8 @@
|
|||
/* global React */
|
||||
|
||||
import { addons } from 'react/addons';
|
||||
import style from './style';
|
||||
import Ripple from '../ripple';
|
||||
import style from './style';
|
||||
|
||||
export default React.createClass({
|
||||
mixins: [addons.PureRenderMixin],
|
||||
|
@ -16,7 +16,6 @@ export default React.createClass({
|
|||
label: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func,
|
||||
template: React.PropTypes.func,
|
||||
type: React.PropTypes.string,
|
||||
value: React.PropTypes.string
|
||||
},
|
||||
|
||||
|
@ -24,20 +23,21 @@ export default React.createClass({
|
|||
return {
|
||||
className: '',
|
||||
dataSource: [],
|
||||
type: 'normal'
|
||||
up: false
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
active: false,
|
||||
selected: _selectValue(this.props.value, this.props.dataSource)
|
||||
selected: _selectValue(this.props.value, this.props.dataSource),
|
||||
width: undefined
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount () {
|
||||
this.setState({
|
||||
height: this.refs.values.getDOMNode().firstElementChild.getBoundingClientRect().height
|
||||
width: React.findDOMNode(this).getBoundingClientRect().width
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -47,13 +47,17 @@ export default React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
onSelect () {
|
||||
if (!this.props.disabled) {
|
||||
this.setState({active: true});
|
||||
}
|
||||
handleClick (event) {
|
||||
let client = event.target.getBoundingClientRect();
|
||||
let screen_height = window.innerHeight || document.documentElement.offsetHeight;
|
||||
|
||||
this.setState({
|
||||
active: true,
|
||||
up: client.top > ((screen_height / 2) + client.height)
|
||||
});
|
||||
},
|
||||
|
||||
onItem (id) {
|
||||
handleClickValue (id) {
|
||||
if (!this.props.disabled) {
|
||||
let value = id.toString();
|
||||
for (let item of this.props.dataSource) {
|
||||
|
@ -68,24 +72,17 @@ export default React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
render () {
|
||||
let stylesheet;
|
||||
let className = `${style.root} ${this.props.className}`;
|
||||
if (this.props.type) className += ` ${this.props.type}`;
|
||||
if (this.props.disabled) className += ' disabled';
|
||||
if (this.state.active === true) {
|
||||
className += ' active';
|
||||
stylesheet = { height: this.state.height * this.props.dataSource.length };
|
||||
}
|
||||
renderValues () {
|
||||
let items = this.props.dataSource.map((item, index) => {
|
||||
let className;
|
||||
if (item.value === this.state.selected.value) className = ` ${style.selected}`;
|
||||
|
||||
const items = this.props.dataSource.map((item, index) => {
|
||||
return (
|
||||
<li
|
||||
key={index}
|
||||
className={className}
|
||||
id={item.value}
|
||||
onClick={this.onItem.bind(this, item.value)}
|
||||
style={{position: 'relative'}}
|
||||
className={ item.value === this.state.selected.value ? 'selected' : null}
|
||||
onClick={this.handleClickValue.bind(this, item.value)}
|
||||
>
|
||||
{ this.props.template ? this.props.template(item) : item.label }
|
||||
<Ripple className={style.ripple}/>
|
||||
|
@ -93,11 +90,25 @@ export default React.createClass({
|
|||
);
|
||||
});
|
||||
|
||||
let className = style.values;
|
||||
if (this.state.up) className += ` ${style.up}`;
|
||||
let valuesStyle = {width: this.state.width};
|
||||
|
||||
return (
|
||||
<ul ref='values' className={className} style={valuesStyle}>{ items }</ul>
|
||||
)
|
||||
},
|
||||
|
||||
render () {
|
||||
let className = style.root;
|
||||
if (this.props.disabled) className += ` ${style.disabled}`;
|
||||
if (this.state.active) className += ` ${style.active}`;
|
||||
|
||||
return (
|
||||
<div data-react-toolbox='dropdown' className={className}>
|
||||
{this.props.label ? <label>{this.props.label}</label> : null}
|
||||
<ul ref='values' className={style.values} style={stylesheet}>{ items }</ul>
|
||||
<div ref='value' className={style.value} onClick={this.onSelect}>
|
||||
{this.props.label ? <label className={style.label}>{this.props.label}</label> : null}
|
||||
{ this.renderValues() }
|
||||
<div ref='value' className={style.value} onClick={this.handleClick}>
|
||||
{ this.props.template ? this.props.template(this.state.selected) : <span>{this.state.selected.label}</span> }
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
$dropdown-input-height: 3 * $unit;
|
||||
$droppdown-background: unquote("rgb(#{$color-white})");
|
||||
$dropdown-value-background: unquote("rgb(#{$color-primary})");
|
||||
$dropdown-value-color: unquote("rgb(#{$color-primary-contrast})");
|
||||
$dropdown-value-hover-background: unquote("rgb(#{$palette-grey-200})");
|
||||
|
||||
.root {
|
||||
position : relative;
|
||||
margin-bottom : $offset;
|
||||
width : inherit;
|
||||
color : $color-text;
|
||||
border-bottom : 1px solid $color-divider;
|
||||
|
||||
&.active {
|
||||
> .label, > .value {
|
||||
opacity : 0.5;
|
||||
}
|
||||
> .values {
|
||||
transform : translateY(0%);
|
||||
max-height : 40vh;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color : $color-text-secondary;
|
||||
border-bottom-style : dotted;
|
||||
> .value:after {
|
||||
transform : scale(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label, .value {
|
||||
transition: opacity $animation-duration $animation-curve-fast-out-slow-in;
|
||||
}
|
||||
|
||||
.label {
|
||||
position : relative;
|
||||
font-size : $font-size-tiny;
|
||||
color : $color-text-secondary;
|
||||
}
|
||||
|
||||
.values {
|
||||
z-index : 2;
|
||||
position : absolute;
|
||||
top : 0;
|
||||
left : 0;
|
||||
width : auto;
|
||||
max-height : 0;
|
||||
list-style : none;
|
||||
overflow-x : hidden;
|
||||
overflow-y : scroll;
|
||||
width : auto;
|
||||
background-color : $droppdown-background;
|
||||
border-radius : $border-radius;
|
||||
box-shadow: $zdepth-shadow-1;
|
||||
transition-property : max-height, box-shadow, transform;
|
||||
transition-duration : $animation-duration;
|
||||
transition-timing-function : $animation-curve-fast-out-slow-in;
|
||||
> * {
|
||||
position : relative;
|
||||
padding : $unit;
|
||||
overflow : hidden;
|
||||
cursor : pointer;
|
||||
&:hover {
|
||||
background-color: $dropdown-value-hover-background;
|
||||
}
|
||||
&.selected {
|
||||
color: $dropdown-value-background;
|
||||
}
|
||||
}
|
||||
&:not(.up) {
|
||||
top: 1rem;
|
||||
bottom: auto;
|
||||
transform : translateY(-$dropdown-input-height);
|
||||
}
|
||||
&.up {
|
||||
top: auto;
|
||||
bottom: 1rem;
|
||||
transform : translateY($dropdown-input-height);
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
display : block;
|
||||
> span {
|
||||
height : $dropdown-input-height;
|
||||
font-size : $font-size-normal;
|
||||
line-height : $dropdown-input-height;
|
||||
}
|
||||
> :not(span) {
|
||||
margin : ($offset / 2) 0;
|
||||
}
|
||||
&:after {
|
||||
$size : ($dropdown-input-height / 7);
|
||||
$border : $size solid transparent;
|
||||
position : absolute;
|
||||
content : "";
|
||||
right : ($offset / 2);
|
||||
bottom : $offset;
|
||||
width : 0;
|
||||
height : 0;
|
||||
border-left : $border;
|
||||
border-right : $border;
|
||||
border-top : $size solid $color-divider;
|
||||
transition : transform $animation-duration $animation-curve-fast-out-slow-in;
|
||||
}
|
||||
}
|
||||
|
||||
.ripple {
|
||||
background-color : $color-divider;
|
||||
opacity : 1;
|
||||
z-index : 0;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
@import '../constants'
|
||||
|
||||
:local(.values)
|
||||
z-index : 2
|
||||
position : absolute
|
||||
top : 0
|
||||
left : -(OFFSET = (SPACE / 1.25))
|
||||
right : -(OFFSET)
|
||||
width : auto
|
||||
height : 0
|
||||
max-height : 50vh
|
||||
list-style : none
|
||||
opacity : 0
|
||||
overflow : hidden
|
||||
background-color : WHITE
|
||||
border-radius : BORDER_RADIUS
|
||||
transform : translateY(-(INPUT_HEIGHT / 2))
|
||||
transition-property : height, box-shadow, opacity, transform
|
||||
transition-duration : ANIMATION_DURATION
|
||||
transition-timing-function : ANIMATION_EASE
|
||||
> li
|
||||
position : relative
|
||||
padding : (SPACE / 2) OFFSET
|
||||
opacity : 0
|
||||
overflow : hidden
|
||||
cursor : pointer
|
||||
&.selected
|
||||
color : PRIMARY
|
||||
|
||||
:local(.value)
|
||||
display : block
|
||||
> span
|
||||
height : INPUT_HEIGHT
|
||||
font-size : FONT_SIZE_NORMAL
|
||||
line-height : INPUT_HEIGHT
|
||||
> :not(span)
|
||||
margin : (SPACE / 2) 0
|
||||
&:after
|
||||
SIZE = (INPUT_HEIGHT / 7)
|
||||
position : absolute
|
||||
content : ""
|
||||
right : (SPACE / 2)
|
||||
bottom : SPACE
|
||||
width : 0
|
||||
height : 0
|
||||
border-left : BORDER = SIZE solid transparent
|
||||
border-right : BORDER
|
||||
border-top : SIZE solid DIVIDER
|
||||
transition : transform ANIMATION_DURATION ANIMATION_EASE
|
||||
|
||||
:local(.root)
|
||||
position : relative
|
||||
margin-bottom : SPACE
|
||||
width : inherit
|
||||
color : TEXT
|
||||
border-bottom : 1px solid DIVIDER
|
||||
|
||||
// -- Overrides
|
||||
&.active
|
||||
> label, > div
|
||||
opacity : 0
|
||||
transform : translateY((INPUT_HEIGHT / 4))
|
||||
> div:after
|
||||
transform : scale(0)
|
||||
> ul
|
||||
opacity : 1
|
||||
transform : translateY(0%)
|
||||
box-shadow : ZDEPTH_SHADOW_1
|
||||
> li
|
||||
opacity : 1
|
||||
transition : opacity ANIMATION_DURATION ANIMATION_EASE
|
||||
&:not(.active)
|
||||
> *, > * > li
|
||||
transition-delay : ANIMATION_DURATION
|
||||
|
||||
&.disabled
|
||||
color : TEXT_SECONDARY
|
||||
border-bottom-style : dotted
|
||||
> div:after
|
||||
transform : scale(0)
|
||||
|
||||
// -- Children
|
||||
> *
|
||||
width : 100%
|
||||
> label, > div
|
||||
transition-property : opacity, transform
|
||||
transition-duration : ANIMATION_DURATION
|
||||
transition-timing-function : ANIMATION_EASE
|
||||
> label + ul
|
||||
top : SPACE
|
||||
> label
|
||||
position : relative
|
||||
bottom : -(SPACE / 4)
|
||||
font-size : FONT_SIZE_TINY
|
||||
color : TEXT_SECONDARY
|
||||
|
||||
:local(.ripple)
|
||||
background-color : DIVIDER
|
||||
opacity : 1
|
||||
z-index : Z_INDEX_LOW
|
Loading…
Reference in New Issue