Add checkbox component

old
Javi Velasco 2015-10-05 09:12:16 +02:00
parent f204ce466f
commit 87265577f2
6 changed files with 273 additions and 10 deletions

View File

@ -0,0 +1,86 @@
/* global React */
import { addons } from 'react/addons';
import Ripple from '../ripple';
import style from './style.scss';
import events from '../utils/events';
export default React.createClass({
mixins: [addons.PureRenderMixin],
displayName: 'Checkbox',
propTypes: {
checked: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
label: React.PropTypes.string,
onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onFocus: React.PropTypes.func
},
getDefaultProps () {
return {
className: '',
disabled: false
};
},
getInitialState () {
return { checked: this.props.checked };
},
handleChange (event) {
this.setState({checked: !this.state.checked});
if (this.props.onChange) this.props.onChange(event, this);
},
handleClick (event) {
events.pauseEvent(event);
if (!this.props.disabled) this.handleChange(event);
},
handleMouseDown (event) {
if (!this.props.disabled) this.refs.ripple.start(event);
},
render () {
let labelClassName = style[this.props.disabled ? 'disabled' : 'field'];
if (this.props.className) labelClassName += ` ${this.props.className}`;
let checkboxClassName = style[this.state.checked ? 'checked' : 'check'];
return (
<label react-toolbox='checkbox' className={labelClassName} onClick={this.handleClick}>
<input
{...this.props}
ref='input'
type='checkbox'
className={style.input}
onChange={this.handleChange}
checked={this.state.checked}
/>
<span role='checkbox' className={checkboxClassName} onMouseDown={this.handleMouseDown}>
<Ripple ref='ripple' role='ripple' className={style.ripple} spread={3} centered />
</span>
{ this.props.label ? <span className={style.text}>{this.props.label}</span> : null }
</label>
);
},
blur () {
this.refs.input.getDOMNode().blur();
},
focus () {
this.refs.input.getDOMNode().focus();
},
getValue () {
return this.state.checked;
},
setValue (value) {
this.setState({checked: value});
}
});

View File

@ -0,0 +1,124 @@
@import "../variables";
$checkbox-total-height: 1.8 * $unit;
$checkbox-size: 1.8 * $unit;
$checkbox-transition-duration: .2s;
$checkbox-focus-size: $checkbox-size * 2.3;
$checkbox-color: unquote("rgb(#{$color-primary})") !default;
$checkbox-text-color: unquote("rgb(#{$color-black})") !default;
$checkbox-disabled-color: unquote("rgba(#{$color-black}, 0.26)") !default;
$checkbox-focus-color: unquote("rgba(#{$color-primary}, 0.26)") !default;
.field {
position: relative;
display: block;
height: $checkbox-size;
margin-bottom: 1.5 * $unit;
white-space: nowrap;
vertical-align: middle;
}
.text {
display: inline-block;
padding-left: $unit;
font-size: 1.4 * $unit;
line-height: $checkbox-size;
color: $checkbox-text-color;
white-space: nowrap;
vertical-align: top;
}
.input {
width: 0;
height: 0;
overflow: hidden;
opacity: 0;
&:focus:not(&:active) + .check:before {
position: absolute;
top: 50%;
left: 50%;
z-index: $z-index-low;
width: $checkbox-focus-size;
height: $checkbox-focus-size;
margin-top: - $checkbox-focus-size / 2;
margin-left: - $checkbox-focus-size / 2;
pointer-events: none;
content: "";
background-color: $checkbox-focus-color;
border-radius: 50%;
}
}
.check {
position: relative;
display: inline-block;
width: $checkbox-size;
height: $checkbox-size;
vertical-align: top;
cursor: pointer;
border: 2px solid $checkbox-text-color;
border-radius: 2px;
transition-timing-function: $animation-curve-default;
transition-duration: $checkbox-transition-duration;
transition-property: background-color;
}
.checked {
@extend .check;
background-color: $checkbox-color;
border-color: $checkbox-color;
&:after {
position: absolute;
top: -.1 * $unit;
left: .4 * $unit;
width: .7 * $unit;
height: 1.2 * $unit;
content: "";
border-color: #fff;
border-style: solid;
border-top: 0;
border-right-width: 2px;
border-bottom-width: 2px;
border-left: 0;
transform: rotate(45deg);
animation: checkmark-expand 140ms ease-out forwards;
}
}
.ripple {
background-color: $checkbox-color;
opacity: .3;
transition-duration: 650ms;
}
.disabled {
color: $checkbox-disabled-color;
.check {
cursor: auto;
border-color: $checkbox-disabled-color;
}
.checked {
cursor: auto;
background-color: $checkbox-disabled-color;
border-color: transparent;
}
}
@keyframes checkmark-expand {
0% {
top: .9 * $unit;
left: .6 * $unit;
width: 0;
height: 0;
}
100% {
top: -.1 * $unit;
left: .4 * $unit;
width: .7 * $unit;
height: 1.2 * $unit;
}
}

View File

@ -1,28 +1,25 @@
@import "../variables";
//-- Variables
$ripple-duration: 1.2s;
$ripple-final-opacity: .3;
$ripple-size: 15 * $unit;
//-- Mixins
%ripple {
position: absolute;
pointer-events: none;
background-color: currentColor;
border-radius: 50%;
transition-timing-function: $animation-curve-linear-out-slow-in;
transition-duration: $ripple-duration;
transition-property: height, width;
transform: translateX(-50%) translateY(-50%);
transform: translate3d(-50%, -50%, 0);
transform-style: preserve-3d;
backface-visibility: hidden;
}
//-- Local Styles
.wrapper {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
}
.normal {
@ -30,6 +27,9 @@ $ripple-size: 15 * $unit;
width: 0;
height: 0;
opacity: $ripple-final-opacity;
transition-timing-function: $animation-curve-linear-out-slow-in;
transition-duration: $ripple-duration;
transition-property: height, width;
&:not(.active) {
opacity: 0;
@ -51,7 +51,7 @@ $ripple-size: 15 * $unit;
animation-name: ripple;
animation-duration: $ripple-duration;
animation-timing-function: $animation-curve-linear-out-slow-in;
animation-iteration-count: infinite;
animation-iteration-count: 1;
}
@keyframes ripple {

View File

@ -30,3 +30,10 @@ $animation-curve-default: $animation-curve-fast-out-slow-in !default;
//-- Input spaces
$input-margin-bottom: $unit * .8;
//-- Indexes
$z-index-higher: 200;
$z-index-high: 100;
$z-index-normal: 1;
$z-index-low: -100;
$z-index-lower: -200;

View File

@ -53,7 +53,6 @@
"normalize.css": "^3.0.3",
"phantomjs-polyfill": "0.0.1",
"postcss-loader": "^0.4.3",
"react-css-modules": "^3.2.3",
"react-hot-loader": "^1.3.0",
"sass-loader": "^2.0.1",
"sinon": "git://github.com/cjohansen/Sinon.JS#sinon-2.0",

View File

@ -0,0 +1,47 @@
/* global React */
import Checkbox from '../../components/checkbox';
export default React.createClass({
handleChange () {
console.log('Changed!');
},
handleFocus () {
console.log('Focused');
},
handleBlur () {
console.log('Blur');
},
render () {
return (
<section>
<h2>Checkbox</h2>
<p style={{marginBottom: '10px'}}>Lorem ipsum...</p>
<Checkbox
label="Checked checkbox"
checked
onChange={this.handleChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
<Checkbox
label="Not checked biatch"
onChange={this.handleChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
<Checkbox
label="Disabled checkbox"
checked
disabled
onChange={this.handleChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
</section>
);
}
});