diff --git a/components/checkbox/index.jsx b/components/checkbox/index.jsx
new file mode 100644
index 00000000..e1900b13
--- /dev/null
+++ b/components/checkbox/index.jsx
@@ -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 (
+
+ );
+ },
+
+ blur () {
+ this.refs.input.getDOMNode().blur();
+ },
+
+ focus () {
+ this.refs.input.getDOMNode().focus();
+ },
+
+ getValue () {
+ return this.state.checked;
+ },
+
+ setValue (value) {
+ this.setState({checked: value});
+ }
+});
diff --git a/components/checkbox/style.scss b/components/checkbox/style.scss
new file mode 100644
index 00000000..103b2b88
--- /dev/null
+++ b/components/checkbox/style.scss
@@ -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;
+ }
+}
diff --git a/components/ripple/style.scss b/components/ripple/style.scss
index f7f188c5..86f3d83b 100644
--- a/components/ripple/style.scss
+++ b/components/ripple/style.scss
@@ -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 {
diff --git a/components/variables.scss b/components/variables.scss
index f29fae44..370487b9 100644
--- a/components/variables.scss
+++ b/components/variables.scss
@@ -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;
diff --git a/package.json b/package.json
index 34ef7e77..896ee5e6 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/spec/components/checkbox.jsx b/spec/components/checkbox.jsx
new file mode 100644
index 00000000..49487533
--- /dev/null
+++ b/spec/components/checkbox.jsx
@@ -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 (
+
+ Checkbox
+ Lorem ipsum...
+
+
+
+
+ );
+ }
+});