diff --git a/.csscomb.json b/.csscomb.json
new file mode 100644
index 00000000..88b1ef1a
--- /dev/null
+++ b/.csscomb.json
@@ -0,0 +1,308 @@
+{
+ "always-semicolon": true,
+ "block-indent": 2,
+ "color-case": "lower",
+ "color-shorthand": true,
+ "element-case": "lower",
+ "eof-newline": true,
+ "leading-zero": false,
+ "remove-empty-rulesets": true,
+ "space-after-colon": 1,
+ "space-after-combinator": 1,
+ "space-before-selector-delimiter": 0,
+ "space-between-declarations": "\n",
+ "space-after-opening-brace": "\n",
+ "space-before-closing-brace": "\n",
+ "space-before-colon": 0,
+ "space-before-combinator": 1,
+ "space-before-opening-brace": 1,
+ "strip-spaces": true,
+ "unitless-zero": true,
+ "vendor-prefix-align": true,
+ "sort-order": [
+ [
+ "$variable",
+ "$extend",
+ "$include",
+ "position",
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "z-index",
+ "-webkit-box-sizing",
+ "-moz-box-sizing",
+ "box-sizing",
+ "display",
+ "float",
+ "width",
+ "min-width",
+ "max-width",
+ "height",
+ "min-height",
+ "max-height",
+ "flex",
+ "flex-direction",
+ "flex-flow",
+ "flex-order",
+ "flex-pack",
+ "flex-align",
+ "padding",
+ "padding-top",
+ "padding-right",
+ "padding-bottom",
+ "padding-left",
+ "margin",
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left",
+ "overflow",
+ "overflow-x",
+ "overflow-y",
+ "-webkit-overflow-scrolling",
+ "-ms-overflow-x",
+ "-ms-overflow-y",
+ "-ms-overflow-style",
+ "clip",
+ "clear",
+ "font",
+ "font-family",
+ "font-size",
+ "font-style",
+ "font-weight",
+ "font-variant",
+ "font-size-adjust",
+ "font-stretch",
+ "font-effect",
+ "font-emphasize",
+ "font-emphasize-position",
+ "font-emphasize-style",
+ "font-smooth",
+ "-webkit-hyphens",
+ "-moz-hyphens",
+ "hyphens",
+ "line-height",
+ "color",
+ "text-align",
+ "-webkit-text-align-last",
+ "-moz-text-align-last",
+ "-ms-text-align-last",
+ "text-align-last",
+ "text-emphasis",
+ "text-emphasis-color",
+ "text-emphasis-style",
+ "text-emphasis-position",
+ "text-decoration",
+ "text-indent",
+ "text-justify",
+ "text-outline",
+ "-ms-text-overflow",
+ "text-overflow",
+ "text-overflow-ellipsis",
+ "text-overflow-mode",
+ "text-shadow",
+ "text-transform",
+ "text-wrap",
+ "-webkit-text-size-adjust",
+ "-ms-text-size-adjust",
+ "letter-spacing",
+ "-ms-word-break",
+ "word-break",
+ "word-spacing",
+ "-ms-word-wrap",
+ "word-wrap",
+ "-moz-tab-size",
+ "-o-tab-size",
+ "tab-size",
+ "white-space",
+ "vertical-align",
+ "list-style",
+ "list-style-position",
+ "list-style-type",
+ "list-style-image",
+ "pointer-events",
+ "-ms-touch-action",
+ "touch-action",
+ "cursor",
+ "visibility",
+ "zoom",
+ "table-layout",
+ "empty-cells",
+ "caption-side",
+ "border-spacing",
+ "border-collapse",
+ "content",
+ "quotes",
+ "counter-reset",
+ "counter-increment",
+ "resize",
+ "-webkit-user-select",
+ "-moz-user-select",
+ "-ms-user-select",
+ "-o-user-select",
+ "user-select",
+ "nav-index",
+ "nav-up",
+ "nav-right",
+ "nav-down",
+ "nav-left",
+ "background",
+ "background-color",
+ "background-image",
+ "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
+ "filter:progid:DXImageTransform.Microsoft.gradient",
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
+ "filter",
+ "background-repeat",
+ "background-attachment",
+ "background-position",
+ "background-position-x",
+ "background-position-y",
+ "-webkit-background-clip",
+ "-moz-background-clip",
+ "background-clip",
+ "background-origin",
+ "-webkit-background-size",
+ "-moz-background-size",
+ "-o-background-size",
+ "background-size",
+ "border",
+ "border-color",
+ "border-style",
+ "border-width",
+ "border-top",
+ "border-top-color",
+ "border-top-style",
+ "border-top-width",
+ "border-right",
+ "border-right-color",
+ "border-right-style",
+ "border-right-width",
+ "border-bottom",
+ "border-bottom-color",
+ "border-bottom-style",
+ "border-bottom-width",
+ "border-left",
+ "border-left-color",
+ "border-left-style",
+ "border-left-width",
+ "border-radius",
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "border-bottom-right-radius",
+ "border-bottom-left-radius",
+ "-webkit-border-image",
+ "-moz-border-image",
+ "-o-border-image",
+ "border-image",
+ "-webkit-border-image-source",
+ "-moz-border-image-source",
+ "-o-border-image-source",
+ "border-image-source",
+ "-webkit-border-image-slice",
+ "-moz-border-image-slice",
+ "-o-border-image-slice",
+ "border-image-slice",
+ "-webkit-border-image-width",
+ "-moz-border-image-width",
+ "-o-border-image-width",
+ "border-image-width",
+ "-webkit-border-image-outset",
+ "-moz-border-image-outset",
+ "-o-border-image-outset",
+ "border-image-outset",
+ "-webkit-border-image-repeat",
+ "-moz-border-image-repeat",
+ "-o-border-image-repeat",
+ "border-image-repeat",
+ "outline",
+ "outline-width",
+ "outline-style",
+ "outline-color",
+ "outline-offset",
+ "-webkit-box-shadow",
+ "-moz-box-shadow",
+ "box-shadow",
+ "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
+ "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
+ "opacity",
+ "-ms-interpolation-mode",
+ "-webkit-transition",
+ "-moz-transition",
+ "-ms-transition",
+ "-o-transition",
+ "transition",
+ "-webkit-transition-delay",
+ "-moz-transition-delay",
+ "-ms-transition-delay",
+ "-o-transition-delay",
+ "transition-delay",
+ "-webkit-transition-timing-function",
+ "-moz-transition-timing-function",
+ "-ms-transition-timing-function",
+ "-o-transition-timing-function",
+ "transition-timing-function",
+ "-webkit-transition-duration",
+ "-moz-transition-duration",
+ "-ms-transition-duration",
+ "-o-transition-duration",
+ "transition-duration",
+ "-webkit-transition-property",
+ "-moz-transition-property",
+ "-ms-transition-property",
+ "-o-transition-property",
+ "transition-property",
+ "-webkit-transform",
+ "-moz-transform",
+ "-ms-transform",
+ "-o-transform",
+ "transform",
+ "-webkit-transform-origin",
+ "-moz-transform-origin",
+ "-ms-transform-origin",
+ "-o-transform-origin",
+ "transform-origin",
+ "-webkit-animation",
+ "-moz-animation",
+ "-ms-animation",
+ "-o-animation",
+ "animation",
+ "-webkit-animation-name",
+ "-moz-animation-name",
+ "-ms-animation-name",
+ "-o-animation-name",
+ "animation-name",
+ "-webkit-animation-duration",
+ "-moz-animation-duration",
+ "-ms-animation-duration",
+ "-o-animation-duration",
+ "animation-duration",
+ "-webkit-animation-play-state",
+ "-moz-animation-play-state",
+ "-ms-animation-play-state",
+ "-o-animation-play-state",
+ "animation-play-state",
+ "-webkit-animation-timing-function",
+ "-moz-animation-timing-function",
+ "-ms-animation-timing-function",
+ "-o-animation-timing-function",
+ "animation-timing-function",
+ "-webkit-animation-delay",
+ "-moz-animation-delay",
+ "-ms-animation-delay",
+ "-o-animation-delay",
+ "animation-delay",
+ "-webkit-animation-iteration-count",
+ "-moz-animation-iteration-count",
+ "-ms-animation-iteration-count",
+ "-o-animation-iteration-count",
+ "animation-iteration-count",
+ "-webkit-animation-direction",
+ "-moz-animation-direction",
+ "-ms-animation-direction",
+ "-o-animation-direction",
+ "animation-direction"
+ ]
+ ]
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..5d126348
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.eslintrc b/.eslintrc
index fdaf2a6e..07a8a70e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -55,7 +55,7 @@
"max-statements": [0, 10],
"new-parens": [2],
"new-cap": [2, {
- "capIsNewExceptions": ["ToInteger", "ToObject", "ToPrimitive", "ToUint32"]
+ "capIsNewExceptions": ["CSSModules", "ToInteger", "ToObject", "ToPrimitive", "ToUint32"]
}],
"newline-after-var": [0],
"no-alert": [2],
diff --git a/.scss-lint.yml b/.scss-lint.yml
new file mode 100644
index 00000000..52e8fec0
--- /dev/null
+++ b/.scss-lint.yml
@@ -0,0 +1,458 @@
+scss_files: "./components/**/*.scss"
+
+linters:
+ BangFormat:
+ enabled: true
+ space_before_bang: true
+ space_after_bang: false
+
+ BorderZero:
+ enabled: true
+
+ ColorKeyword:
+ enabled: true
+
+ ColorVariable:
+ enabled: false
+
+ Comment:
+ enabled: true
+ exclude: []
+
+ DebugStatement:
+ enabled: true
+
+ DeclarationOrder:
+ enabled: false
+
+ DuplicateProperty:
+ enabled: true
+ exclude: []
+
+ ElsePlacement:
+ enabled: true
+ style: same_line # or 'new_line'
+
+ EmptyLineBetweenBlocks:
+ enabled: false
+ ignore_single_line_blocks: true
+
+ EmptyRule:
+ enabled: true
+
+ FinalNewline:
+ enabled: true
+ present: true
+
+ HexLength:
+ enabled: true
+ style: short # or 'long'
+
+ HexNotation:
+ enabled: true
+ style: lowercase # or 'uppercase'
+
+ HexValidation:
+ enabled: true
+
+ IdSelector:
+ enabled: true
+
+ ImportantRule:
+ enabled: false
+
+ ImportPath:
+ enabled: true
+ leading_underscore: false
+ filename_extension: false
+
+ Indentation:
+ enabled: true
+ character: space # or 'tab'
+ width: 2
+
+ LeadingZero:
+ enabled: false
+ style: exclude_zero # or 'include_zero'
+
+ MergeableSelector:
+ enabled: false
+ force_nesting: true
+
+ NameFormat:
+ enabled: true
+ allow_leading_underscore: true
+ convention: hyphenated_lowercase # or 'BEM', or a regex pattern
+
+ NestingDepth:
+ enabled: false
+
+ PlaceholderInExtend:
+ enabled: false
+
+ PropertySortOrder:
+ enabled: true
+ ignore_unspecified: false
+ severity: warning
+ exclude: []
+ order: [
+ "position",
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "z-index",
+ "-webkit-box-sizing",
+ "-moz-box-sizing",
+ "box-sizing",
+ "display",
+ "float",
+ "width",
+ "min-width",
+ "max-width",
+ "height",
+ "min-height",
+ "max-height",
+ "flex",
+ "flex-direction",
+ "flex-flow",
+ "flex-order",
+ "flex-pack",
+ "flex-align",
+ "padding",
+ "padding-top",
+ "padding-right",
+ "padding-bottom",
+ "padding-left",
+ "margin",
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left",
+ "overflow",
+ "overflow-x",
+ "overflow-y",
+ "-webkit-overflow-scrolling",
+ "-ms-overflow-x",
+ "-ms-overflow-y",
+ "-ms-overflow-style",
+ "clip",
+ "clear",
+ "font",
+ "font-family",
+ "font-size",
+ "font-style",
+ "font-weight",
+ "font-variant",
+ "font-size-adjust",
+ "font-stretch",
+ "font-effect",
+ "font-emphasize",
+ "font-emphasize-position",
+ "font-emphasize-style",
+ "font-smooth",
+ "-webkit-hyphens",
+ "-moz-hyphens",
+ "hyphens",
+ "line-height",
+ "color",
+ "text-align",
+ "-webkit-text-align-last",
+ "-moz-text-align-last",
+ "-ms-text-align-last",
+ "text-align-last",
+ "text-emphasis",
+ "text-emphasis-color",
+ "text-emphasis-style",
+ "text-emphasis-position",
+ "text-decoration",
+ "text-indent",
+ "text-justify",
+ "text-outline",
+ "-ms-text-overflow",
+ "text-overflow",
+ "text-overflow-ellipsis",
+ "text-overflow-mode",
+ "text-shadow",
+ "text-transform",
+ "text-wrap",
+ "-webkit-text-size-adjust",
+ "-ms-text-size-adjust",
+ "letter-spacing",
+ "-ms-word-break",
+ "word-break",
+ "word-spacing",
+ "-ms-word-wrap",
+ "word-wrap",
+ "-moz-tab-size",
+ "-o-tab-size",
+ "tab-size",
+ "white-space",
+ "vertical-align",
+ "list-style",
+ "list-style-position",
+ "list-style-type",
+ "list-style-image",
+ "pointer-events",
+ "-ms-touch-action",
+ "touch-action",
+ "cursor",
+ "visibility",
+ "zoom",
+ "table-layout",
+ "empty-cells",
+ "caption-side",
+ "border-spacing",
+ "border-collapse",
+ "content",
+ "quotes",
+ "counter-reset",
+ "counter-increment",
+ "resize",
+ "-webkit-user-select",
+ "-moz-user-select",
+ "-ms-user-select",
+ "-o-user-select",
+ "user-select",
+ "nav-index",
+ "nav-up",
+ "nav-right",
+ "nav-down",
+ "nav-left",
+ "background",
+ "background-color",
+ "background-image",
+ "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
+ "filter:progid:DXImageTransform.Microsoft.gradient",
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
+ "filter",
+ "background-repeat",
+ "background-attachment",
+ "background-position",
+ "background-position-x",
+ "background-position-y",
+ "-webkit-background-clip",
+ "-moz-background-clip",
+ "background-clip",
+ "background-origin",
+ "-webkit-background-size",
+ "-moz-background-size",
+ "-o-background-size",
+ "background-size",
+ "border",
+ "border-color",
+ "border-style",
+ "border-width",
+ "border-top",
+ "border-top-color",
+ "border-top-style",
+ "border-top-width",
+ "border-right",
+ "border-right-color",
+ "border-right-style",
+ "border-right-width",
+ "border-bottom",
+ "border-bottom-color",
+ "border-bottom-style",
+ "border-bottom-width",
+ "border-left",
+ "border-left-color",
+ "border-left-style",
+ "border-left-width",
+ "border-radius",
+ "border-top-left-radius",
+ "border-top-right-radius",
+ "border-bottom-right-radius",
+ "border-bottom-left-radius",
+ "-webkit-border-image",
+ "-moz-border-image",
+ "-o-border-image",
+ "border-image",
+ "-webkit-border-image-source",
+ "-moz-border-image-source",
+ "-o-border-image-source",
+ "border-image-source",
+ "-webkit-border-image-slice",
+ "-moz-border-image-slice",
+ "-o-border-image-slice",
+ "border-image-slice",
+ "-webkit-border-image-width",
+ "-moz-border-image-width",
+ "-o-border-image-width",
+ "border-image-width",
+ "-webkit-border-image-outset",
+ "-moz-border-image-outset",
+ "-o-border-image-outset",
+ "border-image-outset",
+ "-webkit-border-image-repeat",
+ "-moz-border-image-repeat",
+ "-o-border-image-repeat",
+ "border-image-repeat",
+ "outline",
+ "outline-width",
+ "outline-style",
+ "outline-color",
+ "outline-offset",
+ "-webkit-box-shadow",
+ "-moz-box-shadow",
+ "box-shadow",
+ "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
+ "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
+ "opacity",
+ "-ms-interpolation-mode",
+ "-webkit-transition",
+ "-moz-transition",
+ "-ms-transition",
+ "-o-transition",
+ "transition",
+ "-webkit-transition-delay",
+ "-moz-transition-delay",
+ "-ms-transition-delay",
+ "-o-transition-delay",
+ "transition-delay",
+ "-webkit-transition-timing-function",
+ "-moz-transition-timing-function",
+ "-ms-transition-timing-function",
+ "-o-transition-timing-function",
+ "transition-timing-function",
+ "-webkit-transition-duration",
+ "-moz-transition-duration",
+ "-ms-transition-duration",
+ "-o-transition-duration",
+ "transition-duration",
+ "-webkit-transition-property",
+ "-moz-transition-property",
+ "-ms-transition-property",
+ "-o-transition-property",
+ "transition-property",
+ "-webkit-transform",
+ "-moz-transform",
+ "-ms-transform",
+ "-o-transform",
+ "transform",
+ "-webkit-transform-origin",
+ "-moz-transform-origin",
+ "-ms-transform-origin",
+ "-o-transform-origin",
+ "transform-origin",
+ "-webkit-animation",
+ "-moz-animation",
+ "-ms-animation",
+ "-o-animation",
+ "animation",
+ "-webkit-animation-name",
+ "-moz-animation-name",
+ "-ms-animation-name",
+ "-o-animation-name",
+ "animation-name",
+ "-webkit-animation-duration",
+ "-moz-animation-duration",
+ "-ms-animation-duration",
+ "-o-animation-duration",
+ "animation-duration",
+ "-webkit-animation-play-state",
+ "-moz-animation-play-state",
+ "-ms-animation-play-state",
+ "-o-animation-play-state",
+ "animation-play-state",
+ "-webkit-animation-timing-function",
+ "-moz-animation-timing-function",
+ "-ms-animation-timing-function",
+ "-o-animation-timing-function",
+ "animation-timing-function",
+ "-webkit-animation-delay",
+ "-moz-animation-delay",
+ "-ms-animation-delay",
+ "-o-animation-delay",
+ "animation-delay",
+ "-webkit-animation-iteration-count",
+ "-moz-animation-iteration-count",
+ "-ms-animation-iteration-count",
+ "-o-animation-iteration-count",
+ "animation-iteration-count",
+ "-webkit-animation-direction",
+ "-moz-animation-direction",
+ "-ms-animation-direction",
+ "-o-animation-direction",
+ "animation-direction"
+ ]
+
+ PropertySpelling:
+ enabled: true
+ extra_properties: [composes]
+
+ QualifyingElement:
+ enabled: false
+ allow_element_with_attribute: false
+ allow_element_with_class: false
+ allow_element_with_id: false
+
+ SelectorDepth:
+ enabled: false
+
+ SelectorFormat:
+ enabled: true
+ convention: hyphenated_lowercase # or 'BEM', or 'snake_case', or 'camel_case', or a regex pattern
+
+ Shorthand:
+ enabled: true
+
+ SingleLinePerProperty:
+ enabled: true
+ allow_single_line_rule_sets: true
+
+ SingleLinePerSelector:
+ enabled: false
+
+ SpaceAfterComma:
+ enabled: false
+
+ SpaceAfterPropertyColon:
+ enabled: true
+ style: at_least_one_space # or 'no_space', or 'at_least_one_space', or 'aligned'
+
+ SpaceAfterPropertyName:
+ enabled: true
+
+ SpaceBeforeBrace:
+ enabled: true
+ style: space
+ allow_single_line_padding: true
+
+ SpaceBetweenParens:
+ enabled: true
+ spaces: 0
+
+ StringQuotes:
+ enabled: true
+ style: double_quotes
+
+ TrailingSemicolon:
+ enabled: true
+
+ TrailingZero:
+ enabled: false
+
+ UnnecessaryMantissa:
+ enabled: true
+
+ UnnecessaryParentReference:
+ enabled: true
+
+ UrlFormat:
+ enabled: true
+
+ UrlQuotes:
+ enabled: true
+
+ VendorPrefixes:
+ enabled: true
+ identifier_list: base
+ include: []
+ exclude: []
+
+ ZeroUnit:
+ enabled: true
+
+ Compass::*:
+ enabled: false
diff --git a/components/animations/index.js b/components/animations/index.js
new file mode 100644
index 00000000..ccaa2b15
--- /dev/null
+++ b/components/animations/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+ SlideLeft: require('./slide-left'),
+ SlideRight: require('./slide-right')
+};
diff --git a/components/animations/slide-left.scss b/components/animations/slide-left.scss
new file mode 100644
index 00000000..f6df6ec0
--- /dev/null
+++ b/components/animations/slide-left.scss
@@ -0,0 +1,28 @@
+@import "../variables";
+
+.enter, .leave {
+ position: absolute;
+ transition-timing-function: ease-in-out;
+ transition-duration: .35s;
+ transition-property: transform, opacity;
+}
+
+.enter {
+ opacity: 0;
+ transform: translate3d(-100%, 0, 0);
+
+ &.enterActive {
+ opacity: 1;
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+.leave {
+ opacity: 1;
+ transform: translate3d(0, 0, 0);
+
+ &.leaveActive {
+ opacity: 0;
+ transform: translate3d(100%, 0, 0);
+ }
+}
diff --git a/components/animations/slide-right.scss b/components/animations/slide-right.scss
new file mode 100644
index 00000000..5402c845
--- /dev/null
+++ b/components/animations/slide-right.scss
@@ -0,0 +1,28 @@
+@import "../variables";
+
+.enter, .leave {
+ position: absolute;
+ transition-timing-function: ease-in-out;
+ transition-duration: .35s;
+ transition-property: transform, opacity;
+}
+
+.enter {
+ opacity: 0;
+ transform: translate3d(100%, 0, 0);
+
+ &.enterActive {
+ opacity: 1;
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+.leave {
+ opacity: 1;
+ transform: translate3d(0, 0, 0);
+
+ &.leaveActive {
+ opacity: 0;
+ transform: translate3d(-100%, 0, 0);
+ }
+}
diff --git a/components/autocomplete/autocomplete.md b/components/autocomplete/autocomplete.md
index 8794065f..6be2dd8a 100644
--- a/components/autocomplete/autocomplete.md
+++ b/components/autocomplete/autocomplete.md
@@ -26,7 +26,6 @@ var data = [
| **multiple** | Bool | true | If true, component can hold multiple values.|
| **onChange** | Function | | Callback function that is fired when the components's value changes.|
| **required** | Boolean | | If true, component needs has a value.|
-| **type** | String | "text" | Type of the component, overwrite this property if you need set a different stylesheet.|
| **value** | String | | Default value using JSON data.|
## Methods
diff --git a/components/autocomplete/index.jsx b/components/autocomplete/index.jsx
index 1503c3d0..fc811f5e 100644
--- a/components/autocomplete/index.jsx
+++ b/components/autocomplete/index.jsx
@@ -1,12 +1,12 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../utils';
import Input from '../input';
+import style from './style';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Autocomplete',
@@ -19,7 +19,6 @@ export default React.createClass({
multiple: React.PropTypes.bool,
onChange: React.PropTypes.func,
required: React.PropTypes.bool,
- type: React.PropTypes.string,
value: React.PropTypes.any
},
@@ -27,8 +26,7 @@ export default React.createClass({
return {
className: '',
dataSource: {},
- multiple: true,
- type: 'text'
+ multiple: true
};
},
@@ -37,12 +35,17 @@ export default React.createClass({
dataSource: this._indexDataSource(this.props.dataSource),
focus: false,
query: '',
- values: new Map()
+ up: false,
+ values: new Map(),
+ width: undefined
};
},
componentDidMount () {
if (this.props.value) this.setValue(this.props.value);
+ this.setState({
+ width: ReactDOM.findDOMNode(this).getBoundingClientRect().width
+ });
},
componentWillReceiveProps (props) {
@@ -77,8 +80,15 @@ export default React.createClass({
},
handleFocus () {
- this.refs.suggestions.getDOMNode().scrollTop = 0;
- this.setState({active: '', focus: true});
+ let client = event.target.getBoundingClientRect();
+ let screen_height = window.innerHeight || document.documentElement.offsetHeight;
+
+ this.refs.suggestions.scrollTop = 0;
+ this.setState({
+ active: '',
+ up: client.top > ((screen_height / 2) + client.height),
+ focus: true
+ });
},
handleBlur () {
@@ -162,40 +172,54 @@ export default React.createClass({
renderSelected () {
if (this.props.multiple) {
return (
-
+
{[...this.state.values].map(([key, value]) => {
- return (- {value}
);
+ return (- {value}
);
})}
);
}
},
+ renderSuggestions () {
+ return [...this._getSuggestions()].map(([key, value]) => {
+ let className = style.suggestion;
+ if (this.state.active === key) className += ` ${style.active}`;
+ return - {value}
;
+ });
+ },
+
render () {
- let className = `${css.root} ${this.props.className}`;
- if (this.props.type) className += ` ${this.props.type}`;
- if (this.state.focus) className += ' focus';
+ let className = style.root;
+ if (this.props.className) className += ` ${this.props.className}`;
+ if (this.state.focus) className += ` ${style.focus}`;
+
+ let suggestionsClassName = style.suggestions;
+ if (this.state.up) suggestionsClassName += ` ${style.up}`;
+ let suggestionsStyle = {width: this.state.width};
return (
- {this.props.label ? (
) : ''}
+ {this.props.label ?
: ''}
{this.renderSelected()}
-
-
);
diff --git a/components/autocomplete/style.scss b/components/autocomplete/style.scss
new file mode 100644
index 00000000..92356338
--- /dev/null
+++ b/components/autocomplete/style.scss
@@ -0,0 +1,75 @@
+@import "../variables";
+@import "../mixins";
+
+$autocomplete-color-primary: unquote("rgb(#{$color-primary})");
+$autocomplete-color-primary-contrast: unquote("rgb(#{$color-primary-contrast})");
+$autocomplete-color-white: unquote("rgb(#{$color-white})");
+$autocomplete-suggestion-color-active: unquote("rgb(#{$palette-grey-200})");
+
+.root {
+ position: relative;
+
+ &.focus {
+ .label {
+ color: $autocomplete-color-primary;
+ }
+
+ .suggestions {
+ max-height: $items-overflow-max-height;
+ visibility: visible;
+ box-shadow: $zdepth-shadow-1;
+ }
+ }
+}
+
+.label {
+ font-size: $font-size-tiny;
+ color: $color-text-secondary;
+ transition: color $animation-duration $animation-curve-default;
+}
+
+.value {
+ display: inline-block;
+ padding: $unit * .5 $unit * .75;
+ margin: $unit * .25 $unit * .5 $unit * .25 0;
+ font-size: $font-size-tiny;
+ color: $autocomplete-color-primary-contrast;
+ cursor: pointer;
+ background-color: $autocomplete-color-primary;
+ border-radius: 3px;
+}
+
+.suggestions {
+ position: absolute;
+ z-index: 2;
+ max-height: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ visibility: hidden;
+ background-color: $autocomplete-color-white;
+ transition-timing-function: $animation-curve-default;
+ transition-duration: $animation-duration;
+ transition-property: max-height, box-shadow;
+
+ &:not(.up) {
+ bottom: auto;
+ }
+
+ &.up {
+ top: auto;
+ bottom: 0;
+ }
+}
+
+.suggestion {
+ padding: $unit;
+ cursor: pointer;
+
+ &.active {
+ background-color: $autocomplete-suggestion-color-active;
+ }
+}
+
+.input {
+ padding-bottom: 0;
+}
diff --git a/components/autocomplete/style.styl b/components/autocomplete/style.styl
deleted file mode 100644
index ff8d88af..00000000
--- a/components/autocomplete/style.styl
+++ /dev/null
@@ -1,47 +0,0 @@
-@import '../constants'
-
-:local(.values)
- > *
- display : inline-block
- margin : 0 (SPACE / 2) (SPACE / 2) 0
- padding : (SPACE / 4) (SPACE / 2)
- font-size : FONT_SIZE_SMALL
- color : WHITE
- background-color : PRIMARY
- border-radius : (SPACE / 8)
- cursor : pointer
-
-:local(.suggestions)
- z-index : 2
- position : absolute
- width : 100%
- height : 0
- max-height : 50vh
- overflow-x : hidden
- overflow-y : scroll
- margin-top : -(SPACE)
- background-color : WHITE
- opacity : 0
- transform : translateY(-(INPUT_HEIGHT / 2))
- transition-property : height, box-shadow, opacity, transform
- transition-duration : ANIMATION_DURATION
- transition-timing-function : ANIMATION_EASE
- > *
- cursor : pointer
- padding : (SPACE / 2)
- &.active
- color : WHITE
- background-color : PRIMARY_LIGHT
-
-:local(.root)
- position : relative
- > label
- font-size : FONT_SIZE_TINY
- color : PRIMARY
- // -- Overrides
- &.focus
- > :local(.suggestions)
- height : auto
- opacity : 1
- transform : translateY(0%)
- box-shadow : ZDEPTH_SHADOW_1
diff --git a/components/button/index.jsx b/components/button/index.jsx
index 232fab30..77a54f62 100644
--- a/components/button/index.jsx
+++ b/components/button/index.jsx
@@ -1,12 +1,12 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import FontIcon from '../font_icon';
import Ripple from '../ripple';
+import style from './style.scss';
+import events from '../utils/events';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Button',
@@ -14,6 +14,8 @@ export default React.createClass({
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
icon: React.PropTypes.string,
+ primary: React.PropTypes.bool,
+ accent: React.PropTypes.bool,
label: React.PropTypes.string,
loading: React.PropTypes.bool,
ripple: React.PropTypes.bool,
@@ -32,26 +34,29 @@ export default React.createClass({
return { loading: this.props.loading };
},
- handleClick (event) {
- if (this.props.onClick) this.props.onClick(event, this);
+ handleMouseDown (event) {
+ events.pauseEvent(event);
+ this.refs.ripple.start(event);
},
render () {
- let className = this.props.className;
- if (this.props.type) className += ` ${this.props.type}`;
- if (this.state.focused) className += ' focused';
+ let className = style[this.props.type];
+ if (this.props.className) className += ` ${this.props.className}`;
return (
);
},
diff --git a/components/button/style.scss b/components/button/style.scss
new file mode 100644
index 00000000..7780b564
--- /dev/null
+++ b/components/button/style.scss
@@ -0,0 +1,185 @@
+@import "../variables";
+@import "../mixins";
+
+$button-default-text-color: unquote("rgb(#{$color-black})") !default;
+$button-flat-color-hover: unquote("rgba(#{$color-black}, 0.26)") !default;
+$button-disabled-text-color: unquote("rgba(#{$color-black}, 0.26)") !default;
+$button-solid-background-color: unquote("rgba(#{$palette-grey-500}, 0.20)") !default;
+$button-solid-disabled-background-color: unquote("rgba(#{$color-black}, 0.12)") !default;
+$button-primary-color: unquote("rgb(#{$color-primary})") !default;
+$button-primary-color-contrast: unquote("rgb(#{$color-primary-contrast})") !default;
+$button-primary-color-hover: unquote("rgba(#{$color-primary}, 0.20)") !default;
+$button-accent-color: unquote("rgb(#{$color-accent})") !default;
+$button-accent-color-hover: unquote("rgba(#{$color-accent}, 0.20)") !default;
+$button-accent-color-active: unquote("rgba(#{$color-accent}, 0.40)") !default;
+$button-accent-color-contrast: unquote("rgb(#{$color-primary-contrast})") !default;
+$button-height: $unit * 3.6;
+$button-floating-height: $unit * 5.6;
+$button-floating-height-mini: $unit * 4;
+
+%button {
+ position: relative;
+ z-index: 1;
+ display: inline-block;
+ height: $button-height;
+ flex-direction: row;
+ overflow: hidden;
+ color: $button-default-text-color;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap;
+ cursor: pointer;
+ border: 0;
+ outline: none;
+ transition: box-shadow .2s $animation-curve-fast-out-linear-in,
+ background-color .2s $animation-curve-default,
+ color .2s $animation-curve-default;
+ align-content: center;
+ align-items: center;
+ justify-content: center;
+
+ &::-moz-focus-inner {
+ border: 0;
+ }
+}
+
+%squared {
+ min-width: 9 * $unit;
+ padding: 0 $unit * 1.2;
+ border-radius: $border-radius;
+
+ .icon {
+ margin-right: $unit * .6;
+ font-size: 120%;
+ vertical-align: middle;
+ }
+}
+
+%disabled {
+ color: $button-disabled-text-color;
+ pointer-events: none;
+ cursor: auto;
+}
+
+//-- Local styles
+.label {
+ @include typo-button();
+ line-height: $button-height;
+}
+
+.flat {
+ @extend %button;
+ @extend %squared;
+ background: transparent;
+
+ &:hover {
+ background: $button-flat-color-hover;
+ }
+
+ &:focus:not(:active) {
+ background: $button-flat-color-hover;
+ }
+
+ &[disabled] {
+ @extend %disabled;
+ }
+}
+
+.raised {
+ @extend %button;
+ @extend %squared;
+ @include shadow-2dp();
+ background: $button-solid-background-color;
+
+ &:active {
+ @include shadow-4dp();
+ }
+
+ &:focus:not(:active) {
+ @include focus-shadow();
+ }
+
+ &[disabled] {
+ @extend %disabled;
+ @include shadow-2dp();
+ background-color: $button-solid-disabled-background-color;
+ }
+}
+
+.floating {
+ @extend %button;
+ width: $button-floating-height;
+ height: $button-floating-height;
+ font-size: $unit * 2.4;
+ background: $button-solid-background-color;
+ border-radius: 50%;
+ box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, .12), 0 1px 1px 0 rgba(0, 0, 0, .24);
+
+ &:active {
+ @include shadow-4dp();
+ }
+
+ &:focus:not(:active) {
+ @include focus-shadow();
+ }
+
+ &[disabled] {
+ @extend %disabled;
+ @include shadow-2dp();
+ background-color: $button-solid-disabled-background-color;
+ }
+
+ .icon {
+ line-height: $button-floating-height;
+ }
+}
+
+:global(.primary):not([disabled]) {
+ &.raised, &.floating {
+ color: $button-primary-color-contrast;
+ background: $button-primary-color;
+ }
+
+ &.flat {
+ color: $button-primary-color;
+
+ &:hover {
+ background: $button-primary-color-hover;
+ }
+
+ &:focus:not(:active) {
+ background: $button-primary-color-hover;
+ }
+ }
+}
+
+:global(.accent):not([disabled]) {
+ &.raised, &.floating {
+ color: $button-accent-color-contrast;
+ background-color: $button-accent-color;
+ }
+
+ &.flat {
+ color: $button-accent-color;
+
+ &:hover {
+ background: $button-accent-color-hover;
+ }
+
+ &:focus:not(:active) {
+ background: $button-accent-color-hover;
+ }
+ }
+}
+
+:global(.mini) {
+ &.floating {
+ width: $button-floating-height-mini;
+ height: $button-floating-height-mini;
+ font-size: ($button-floating-height-mini / 2.25);
+
+ .icon {
+ line-height: $button-floating-height-mini;
+ }
+ }
+}
diff --git a/components/button/style.styl b/components/button/style.styl
deleted file mode 100644
index 91fa44d1..00000000
--- a/components/button/style.styl
+++ /dev/null
@@ -1,85 +0,0 @@
-@import '../constants'
-
-:local(.root)
- z-index : 1
- display : inline-block
- position : relative
- overflow : hidden
- font-weight : FONT_WEIGHT_NORMAL
- text-align : center
- text-decoration : none
- white-space : nowrap
- border : none
- transition-property : background-color, box-shadow
- transition-duration : ANIMATION_DURATION
- transition-timing-function : ANIMATION_EASE
-
- &.raised, &.flat
- padding : (SPACE / 2) (SPACE / 1.25)
- font-size : FONT_SIZE_SMALL
- text-transform : uppercase
- border-radius : (SPACE / 8)
- > *
- vertical-align : middle
- > [data-react-toolbox='icon']
- font-size : FONT_SIZE_BIG
- margin-right : (SPACE / 2)
- > abbr
- font-weight : FONT_WEIGHT_BOLD
- &.anchor
- width : 100%
-
- &.flat
- background-color : transparent
- &:not(.primary):not(.accent)
- > [data-react-toolbox='ripple']
- background-color : alpha(TEXT, 12.5%)
- &.primary
- color : PRIMARY
- > [data-react-toolbox='ripple']
- background-color : alpha(PRIMARY, 12.5%)
- &.accent
- color : ACCENT
- > [data-react-toolbox='ripple']
- background-color : alpha(ACCENT, 12.5%)
-
- &.floating
- width : BUTTON_CIRCLE_HEIGHT
- height : BUTTON_CIRCLE_HEIGHT
- font-size : (BUTTON_CIRCLE_HEIGHT / 2.25)
- border-radius : 50%
- > [data-react-toolbox='icon']
- line-height : BUTTON_CIRCLE_HEIGHT
-
- &.mini
- width : BUTTON_CIRCLE_MINI_HEIGHT
- height : BUTTON_CIRCLE_MINI_HEIGHT
- > [data-react-toolbox='icon']
- line-height : BUTTON_CIRCLE_MINI_HEIGHT
-
- // Overrides
- &[disabled]
- color : darken(DIVIDER, 25%)
- background-color : DIVIDER
- pointer-events : none
-
- &:not([disabled])
- cursor : pointer
- &:hover, &:active, &:focus
- outline : 0
- &:not(.flat)
- box-shadow ZDEPTH_SHADOW_1
- &:not(.primary):not(.accent)
- color : TEXT
- background-color : WHITE
- &:active
- box-shadow : ZDEPTH_SHADOW_2, inset 0 0 0 UNIT alpha(WHITE, 10%)
- &.primary, &.accent
- color : WHITE
- &.primary
- background-color : PRIMARY
- &.accent
- background-color : ACCENT
-
- &:not(.primary):not(.accent) > [data-react-toolbox='ripple']
- background-color : DIVIDER
diff --git a/components/calendar/day.jsx b/components/calendar/day.jsx
index 58c4c9e7..0609e87e 100644
--- a/components/calendar/day.jsx
+++ b/components/calendar/day.jsx
@@ -1,11 +1,10 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import style from './style';
import time from '../utils/time';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Day',
@@ -33,7 +32,7 @@ export default React.createClass({
render () {
return (
-
+
{this.props.day}
);
diff --git a/components/calendar/index.jsx b/components/calendar/index.jsx
index a6ad79b2..df4b0f8b 100644
--- a/components/calendar/index.jsx
+++ b/components/calendar/index.jsx
@@ -1,15 +1,15 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
-import utils from '../utils';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import CSSTransitionGroup from 'react-addons-css-transition-group';
+import { SlideLeft, SlideRight } from '../animations';
import FontIcon from '../font_icon';
+import Ripple from '../ripple';
import Month from './month';
-
-const { CSSTransitionGroup: CTG } = React.addons;
+import style from './style';
+import utils from '../utils';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Calendar',
@@ -40,26 +40,27 @@ export default React.createClass({
}
},
- onDayClick (event) {
- let newDate = utils.time.setDay(this.state.viewDate, parseInt(event.target.textContent));
+ onDayClick (day) {
+ let newDate = utils.time.setDay(this.state.viewDate, day);
this.setState({selectedDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
},
- onYearClick (event) {
- let newDate = utils.time.setYear(this.state.selectedDate, parseInt(event.target.textContent));
+ onYearClick (year) {
+ let newDate = utils.time.setYear(this.state.selectedDate, year);
this.setState({selectedDate: newDate, viewDate: newDate});
if (this.props.onChange) this.props.onChange(newDate);
},
scrollToActive () {
- this.refs.years.getDOMNode().scrollTop =
- this.refs.activeYear.getDOMNode().offsetTop -
- this.refs.years.getDOMNode().offsetHeight / 2 +
- this.refs.activeYear.getDOMNode().offsetHeight / 2;
+ this.refs.years.scrollTop =
+ this.refs.activeYear.offsetTop -
+ this.refs.years.offsetHeight / 2 +
+ this.refs.activeYear.offsetHeight / 2;
},
incrementViewMonth () {
+ this.refs.rippleRight.start(event);
this.setState({
direction: 'right',
viewDate: utils.time.addMonths(this.state.viewDate, 1)
@@ -67,6 +68,7 @@ export default React.createClass({
},
decrementViewMonth () {
+ this.refs.rippleLeft.start(event);
this.setState({
direction: 'left',
viewDate: utils.time.addMonths(this.state.viewDate, -1)
@@ -75,9 +77,9 @@ export default React.createClass({
renderYear (year) {
let props = {
- className: year === this.state.viewDate.getFullYear() ? 'active' : '',
- key: `year-${year}`,
- onClick: this.onYearClick
+ className: year === this.state.viewDate.getFullYear() ? style.active : '',
+ key: year,
+ onClick: this.onYearClick.bind(this, year)
};
if (year === this.state.viewDate.getFullYear()) {
@@ -89,31 +91,36 @@ export default React.createClass({
renderYears () {
return (
-
+
{ utils.range(1900, 2100).map(i => { return this.renderYear(i); })}
);
},
renderMonths () {
+ let animation = this.state.direction === 'left' ? SlideLeft : SlideRight;
return (
-
-
-
-
+
+
+
+
+
+
+
+
-
+
);
},
render () {
return (
-
+
{ this.props.display === 'months' ? this.renderMonths() : this.renderYears() }
);
diff --git a/components/calendar/month.jsx b/components/calendar/month.jsx
index b39ee232..fb8c5b0e 100644
--- a/components/calendar/month.jsx
+++ b/components/calendar/month.jsx
@@ -1,12 +1,11 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
-import utils from '../utils';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import Day from './day';
+import style from './style';
+import utils from '../utils';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Month',
@@ -16,36 +15,38 @@ export default React.createClass({
viewDate: React.PropTypes.object
},
+ handleDayClick (day) {
+ if (this.props.onDayClick) this.props.onDayClick(day);
+ },
+
renderWeeks () {
return utils.range(0, 7).map(i => {
- return (
-
- { utils.time.getFullDayOfWeek(i).charAt(0) }
-
- );
+ return
{ utils.time.getFullDayOfWeek(i).charAt(0) };
});
},
renderDays () {
return utils.range(1, utils.time.getDaysInMonth(this.props.viewDate) + 1).map(i => {
return (
-
+ viewDate={this.props.viewDate}
+ />
);
});
},
render () {
return (
-
-
+
+
{ utils.time.getFullMonth(this.props.viewDate)} {this.props.viewDate.getFullYear() }
-
{ this.renderWeeks() }
-
{ this.renderDays() }
+
{ this.renderWeeks() }
+
{ this.renderDays() }
);
}
diff --git a/components/calendar/style.scss b/components/calendar/style.scss
new file mode 100644
index 00000000..27b2dc80
--- /dev/null
+++ b/components/calendar/style.scss
@@ -0,0 +1,114 @@
+@import "../variables";
+
+$calendar-primary: $color-primary;
+$calendar-primary-contrast: $color-primary-contrast;
+$calendar-primary-color: unquote("rgb(#{$calendar-primary})") !default;
+$calendar-primary-contrast-color: unquote("rgb(#{$calendar-primary-contrast})") !default;
+$calendar-primary-hover-color: unquote("rgba(#{$calendar-primary}, 0.21)") !default;
+$calendar-arrows-color: unquote("rgb(#{$palette-grey-600})") !default;
+$calendar-row-height: 3 * $unit;
+$calendar-day-padding: .2 * $unit;
+$calendar-total-height: $calendar-row-height * 8 + $calendar-day-padding * 12;
+
+.root {
+ position: relative;
+ height: $calendar-total-height;
+ font-size: 1.4 * $unit;
+ line-height: $calendar-row-height;
+ text-align: center;
+ background: $calendar-primary-contrast-color;
+
+ .prev, .next {
+ position: absolute;
+ top: 0;
+ z-index: $z-index-high;
+ width: $calendar-row-height;
+ height: $calendar-row-height;
+ font-size: 2 * $unit;
+ line-height: $calendar-row-height;
+ color: $calendar-arrows-color;
+ text-align: center;
+ cursor: pointer;
+ opacity: .7;
+ }
+
+ .prev {
+ left: 0;
+ }
+
+ .next {
+ right: 0;
+ }
+}
+
+.title {
+ font-weight: 500;
+}
+
+.years {
+ height: 100%;
+ overflow: scroll;
+ font-size: 1.8 * $unit;
+
+ > li {
+ line-height: 2.4;
+ cursor: pointer;
+
+ &.active {
+ font-size: 2.4 * $unit;
+ color: $calendar-primary-color;
+ }
+ }
+}
+
+.week {
+ display: flex;
+ height: $calendar-row-height;
+ font-size: 1.3 * $unit;
+ line-height: $calendar-row-height;
+ opacity: .5;
+ flex-wrap: wrap;
+
+ > span {
+ flex: 0 0 (100% / 7);
+ }
+}
+
+.days {
+ display: flex;
+ font-size: 13px;
+ flex-wrap: wrap;
+}
+
+:local(.day) {
+ flex: 0 0 (100% / 7);
+ padding: $calendar-day-padding;
+
+ > span {
+ display: inline-block;
+ width: $calendar-row-height;
+ height: $calendar-row-height;
+ line-height: $calendar-row-height;
+ cursor: pointer;
+ border-radius: 50%;
+ }
+
+ &:hover:not(.active) > span {
+ color: $calendar-primary-contrast-color;
+ background: $calendar-primary-hover-color;
+ }
+
+ &.active > span {
+ color: $calendar-primary-contrast-color;
+ background: $calendar-primary-color;
+ }
+}
+
+.month {
+ background-color: $calendar-primary-contrast-color;
+}
+
+.ripple {
+ opacity: .5;
+ transition-duration: 450ms;
+}
diff --git a/components/calendar/style.styl b/components/calendar/style.styl
deleted file mode 100644
index f74ee088..00000000
--- a/components/calendar/style.styl
+++ /dev/null
@@ -1,118 +0,0 @@
-@import '../constants'
-
-// -- Calendar sizes
-ROW_HEIGHT = 40px
-DAY_PADDING = 2px
-TOTAL_HEIGHT = ROW_HEIGHT * 8 + DAY_PADDING * 12
-
-:local(.root)
- background : WHITE
- height : TOTAL_HEIGHT
- font-size : 14px
- overflow : hidden
- position : relative
- line-height : ROW_HEIGHT
- text-align : center
-
-:local(.prev), :local(.next)
- color : lighten(TEXT, 15%)
- cursor : pointer
- font-size : 26px
- height : ROW_HEIGHT
- line-height : ROW_HEIGHT
- opacity : .7
- position : absolute
- text-align : center
- top : 0
- width : ROW_HEIGHT
- z-index : Z_INDEX_HIGH
-
-:local(.title)
- font-weight : 500
-
-:local(.prev)
- left : 0
-
-:local(.next)
- right : 0
-
-:local(.week)
- display : flex
- flex-wrap : wrap
- font-size : 13px
- height : ROW_HEIGHT
- line-height : ROW_HEIGHT
- opacity : .5
-
- > span
- flex : 0 0 (100/7)%
-
-:local(.days)
- display : flex
- flex-wrap : wrap
- font-size : 13px
-
-:local(.day)
- flex : 0 0 (100/7)%
- padding : DAY_PADDING
-
- > span
- border-radius : 50%
- cursor : pointer
- display : inline-block
- height : ROW_HEIGHT
- line-height : ROW_HEIGHT
- width : ROW_HEIGHT
-
- &:hover:not(.active) > span
- background : lighten(ACCENT, 65%)
- color : WHITE
-
- &.active > span
- background : ACCENT
- color : WHITE
-
-// -- Transitions
-:local(.root) .slide-horizontal-enter, :local(.root) .slide-horizontal-leave
- transition : all .5s
-
-:local(.root) .right
- .slide-horizontal-enter
- position : absolute
- transform : translateX(100%)
- opacity : 0
-
- .slide-horizontal-leave, .slide-horizontal-enter-active
- transform : translateX(0)
- opacity : 1
-
- .slide-horizontal-leave-active
- transform : translateX(-100%)
- opacity : 0
-
-:local(.root) .left
- .slide-horizontal-enter
- position : absolute
- transform : translateX(-100%)
- opacity : 0
-
- .slide-horizontal-leave, .slide-horizontal-enter-active
- transform : translateX(0)
- opacity : 1
-
- .slide-horizontal-leave-active
- transform : translateX(100%)
- opacity : 0
-
-:local(.years)
- font-size : 18px
- height : 100%
- overflow : scroll
-
- > li
- cursor : pointer
- line-height : 2.4
-
- &.active
- color : ACCENT
- font-size : 24px
diff --git a/components/card/index.jsx b/components/card/index.jsx
index 5f6ec4e5..44436f6f 100644
--- a/components/card/index.jsx
+++ b/components/card/index.jsx
@@ -1,12 +1,11 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import style from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import Navigation from '../navigation';
import Ripple from '../ripple';
+import style from './style.scss';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Card',
@@ -15,7 +14,6 @@ export default React.createClass({
color: React.PropTypes.string,
image: React.PropTypes.string,
text: React.PropTypes.string,
- legend: React.PropTypes.string,
loading: React.PropTypes.bool,
onClick: React.PropTypes.func,
title: React.PropTypes.string,
@@ -36,42 +34,66 @@ export default React.createClass({
};
},
- onClick (event) {
+ handleMouseDown (event) {
if (this.props.onClick) {
event.preventDefault();
+ this.refs.ripple.start(event);
this.props.onClick(event, this);
}
},
- renderHeading () {
- let headingStyle = {};
- if (this.props.image) headingStyle.backgroundImage = `url(${this.props.image})`;
- if (this.props.color) headingStyle.backgroundColor = this.props.color;
+ renderTitle () {
+ let styleFigure = {}, styleOverflow = {};
+ if (this.props.image) styleFigure.backgroundImage = `url(${this.props.image})`;
+ if (this.props.color) {
+ styleFigure.backgroundColor = this.props.color;
+ styleOverflow.backgroundColor = this.props.color;
+ }
+
if (this.props.title || this.props.image) {
return (
-
+
{ this.props.subtitle ? {this.props.subtitle} : null }
- { this.props.title ? {this.props.title}
: null }
+ { this.props.title ? {this.props.title}
: null }
+ { this.props.color ? : null }
);
}
},
+ renderActions () {
+ if (this.props.actions) {
+ return (
+
+ );
+ }
+ },
+
render () {
let className = `${style.root} ${this.props.className}`;
- if (this.props.type) className += ` ${this.props.type}`;
- if (this.props.onClick) className += ' touch';
- if (this.props.image) className += ' image';
- if (this.props.color) className += ' color';
- if (this.state.loading) className += ' loading';
+ if (this.props.type) className += ` ${style[this.props.type]}`;
+ if (this.props.onClick) className += ` ${style.touch}`;
+ if (this.props.image || this.props.color) className += ` ${style.contrast}`;
+ if (this.props.color) className += ` ${style.color}`;
+ if (this.state.loading) className += ` ${style.loading}`;
return (
-
- { this.renderHeading() }
- { this.props.text ?
{this.props.text}
: null }
- { this.props.legend ?
{this.props.legend} : null}
- { this.props.actions ?
: null }
- {
}
+
+ { this.renderTitle() }
+ { this.props.text ?
{this.props.text}
: null }
+ { this.renderActions() }
+
);
},
diff --git a/components/card/style.scss b/components/card/style.scss
new file mode 100644
index 00000000..62a13ace
--- /dev/null
+++ b/components/card/style.scss
@@ -0,0 +1,129 @@
+@import "../variables";
+@import "../mixins";
+
+$card-color-white: unquote("rgb(#{$color-white})") !default;
+$card-title-height: 17.6 * $unit;
+$card-width-normal: 32 * $unit;
+$card-width-large: 51.2 * $unit;
+$card-text-overlay: unquote("rgba(#{$color-black}, 0.2)");
+
+.figure {
+ position: relative;
+ display: flex;
+ min-height: $card-title-height;
+ flex-direction: column;
+ background-position: center center;
+ background-size: cover;
+ justify-content: flex-end;
+
+ > *:not(.overflow) {
+ z-index: 1;
+ font-weight: $font-weight-normal;
+ }
+
+ > .overflow {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 0;
+ width: 100%;
+ height: 100%;
+ opacity: .75;
+ }
+}
+
+.text {
+ font-size: $font-size-small;
+ line-height: 1.8 * $unit;
+ color: $color-text-secondary;
+}
+
+.navigation {
+ $offset: ($offset / 2);
+ padding: $offset;
+
+ > * {
+ min-width: 0;
+ padding-right: $offset;
+ padding-left: $offset;
+ }
+}
+
+.ripple {
+ background-color: $color-text-secondary;
+}
+
+.root {
+ @include shadow-2dp();
+ position: relative;
+ display: flex;
+ width: $card-width-normal;
+ flex-direction: column;
+ overflow: hidden;
+ vertical-align: top;
+ background: $color-background;
+
+ // -- Children
+ > *:not(.navigation) {
+ padding: $offset;
+ }
+
+ &:not(.color) > *:not(.figure), > *:not(:last-child) {
+ box-shadow: 0 1px $color-divider;
+ }
+}
+
+.touch {
+ cursor: pointer;
+}
+
+.contrast {
+ .figure {
+ color: $card-color-white;
+ text-shadow: 0;
+ }
+
+ .ripple {
+ background-color: $card-color-white;
+ }
+}
+
+.loading {
+ pointer-events: none;
+ cursor: none;
+ filter: grayscale(100%);
+
+ .ripple {
+ @include ripple-loading(cardloading, 2 * $card-width-normal, 2 * $card-width-normal);
+ width: 2 * $card-width-normal;
+ height: 2 * $card-width-normal;
+ animation-name: cardloading;
+ }
+}
+
+.image {
+ &, .figure {
+ height: $card-width-normal;
+ }
+
+ .figure {
+ padding: 0;
+
+ > h5 {
+ padding: $offset;
+ font-size: $font-size-small;
+ font-weight: $font-weight-bold;
+ background-color: $card-text-overlay;
+ }
+ }
+}
+
+.event {
+ .figure {
+ justify-content: flex-start;
+ }
+}
+
+.wide {
+ width: $card-width-large;
+}
diff --git a/components/card/style.styl b/components/card/style.styl
deleted file mode 100644
index cf3a4f53..00000000
--- a/components/card/style.styl
+++ /dev/null
@@ -1,70 +0,0 @@
-@import '../constants'
-
-SIZE = (5 * UNIT)
-OFFSET = (SPACE / 1.25)
-
-:local(.navigation)
- padding : OFFSET = (OFFSET / 2)
- > *
- padding-left : OFFSET
- padding-right : OFFSET
- box-shadow : none !important
- &:hover
- background-color : rgba(0,0,0,0.1) !important
-
-:local(.figure)
- display-flex()
- flex-direction : column
- justify-content : flex-end
- flex-grow : 2
- min-height : (SIZE / 2)
- background-size : cover
- > *
- font-weight : FONT_WEIGHT_NORMAL
-
-:local(.root)
- display-flex()
- flex-direction column
- position : relative
- overflow : hidden
- width : SIZE
- box-shadow : ZDEPTH_SHADOW_1
- background : WHITE
-
- // -- Children
- > *:not(:local(.ripple)):not(:local(.navigation))
- padding : OFFSET
- &:not(.color):not(.image) > :local(.ripple)
- background-color : red
- &:not(.color) > *:not(figure), > *:not(:last-child)
- box-shadow : 0 1px darken(BACKGROUND, 5%)
- > :local(.figure)
-
- // -- Overrides
- &.touch
- cursor : pointer
- &:hover, &:active
- box-shadow : ZDEPTH_SHADOW_2
- &.image > :local(.figure)
- text-shadow : ZDEPTH_SHADOW_1
- &.image, &.color
- > :local(.figure)
- color : WHITE
- &.loading
- cursor : none
- pointer-events : none
- -webkit-filter : grayscale(100%)
- &, &:hover
- box-shadow : 0 0 0 1px DIVIDER
- :local(.ripple)
- width : SIZE = (SIZE * 2)
- height : SIZE
- &.small > :local(.figure)
- min-height : 0px
- &.square
- height : SIZE
- &.wide
- width : (SIZE * 2)
-
-:local(.ripple)
- background-color: #888
diff --git a/components/checkbox/index.jsx b/components/checkbox/index.jsx
new file mode 100644
index 00000000..06565535
--- /dev/null
+++ b/components/checkbox/index.jsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import Ripple from '../ripple';
+import style from './style';
+import events from '../utils/events';
+
+export default React.createClass({
+ mixins: [PureRenderMixin],
+
+ displayName: 'Checkbox',
+
+ propTypes: {
+ checked: React.PropTypes.bool,
+ className: React.PropTypes.string,
+ disabled: React.PropTypes.bool,
+ label: React.PropTypes.string,
+ name: React.PropTypes.string,
+ onBlur: React.PropTypes.func,
+ onChange: React.PropTypes.func,
+ onFocus: React.PropTypes.func
+ },
+
+ getDefaultProps () {
+ return {
+ checked: false,
+ 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);
+ },
+
+ handleInputClick (event) {
+ events.pauseEvent(event);
+ },
+
+ render () {
+ let fieldClassName = style.field;
+ let checkboxClassName = style.check;
+ if (this.props.disabled) fieldClassName += ` ${style.disabled}`;
+ if (this.props.className) fieldClassName += ` ${this.props.className}`;
+ if (this.state.checked) checkboxClassName += ` ${style.checked}`;
+
+ return (
+
+ );
+ },
+
+ blur () {
+ this.refs.input.blur();
+ },
+
+ focus () {
+ this.refs.input.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..d09ff58a
--- /dev/null
+++ b/components/checkbox/style.scss
@@ -0,0 +1,135 @@
+@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;
+$check-focus-color: unquote("rgba(#{$color-black}, 0.1)") !default;
+$checked-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: $check-focus-color;
+ border-radius: 50%;
+ }
+
+ &.checked:before {
+ background-color: $checked-focus-color;
+ }
+ }
+}
+
+.check {
+ position: relative;
+ display: inline-block;
+ width: $checkbox-size;
+ height: $checkbox-size;
+ vertical-align: top;
+ cursor: pointer;
+ border-color: $checkbox-text-color;
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 2px;
+ transition-timing-function: $animation-curve-default;
+ transition-duration: $checkbox-transition-duration;
+ transition-property: background-color;
+
+ &.checked {
+ 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 {
+ > .text {
+ 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/clock/face.jsx b/components/clock/face.jsx
index 1a0dd720..fce97630 100644
--- a/components/clock/face.jsx
+++ b/components/clock/face.jsx
@@ -1,10 +1,9 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import style from './style';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Face',
@@ -33,10 +32,14 @@ export default React.createClass({
},
renderNumber (number, idx) {
+ let className = style.number;
+ if (number === this.props.active) className += ` ${style.active}`;
return (
-
+
{ this.props.twoDigits ? ('0' + number).slice(-2) : number }
);
@@ -44,11 +47,13 @@ export default React.createClass({
render () {
return (
-
+
{ this.props.numbers.map(this.renderNumber)}
);
diff --git a/components/clock/hand.jsx b/components/clock/hand.jsx
index 23dcdf12..f1ceaef7 100644
--- a/components/clock/hand.jsx
+++ b/components/clock/hand.jsx
@@ -1,11 +1,10 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import style from './style';
import utils from '../utils';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Hand',
@@ -30,7 +29,7 @@ export default React.createClass({
},
componentDidMount () {
- this.setState({knobWidth: this.refs.knob.getDOMNode().offsetWidth});
+ this.setState({knobWidth: this.refs.knob.offsetWidth});
},
getMouseEventMap () {
@@ -100,14 +99,15 @@ export default React.createClass({
},
render () {
- let style = utils.prefixer({
+ const className = `${style.hand} ${this.props.className}`;
+ let handStyle = utils.prefixer({
height: this.props.length - this.state.knobWidth / 2,
transform: `rotate(${this.props.angle}deg)`
});
return (
-
-
+
);
}
diff --git a/components/clock/hours.jsx b/components/clock/hours.jsx
index e95d62a0..552e26d8 100644
--- a/components/clock/hours.jsx
+++ b/components/clock/hours.jsx
@@ -1,16 +1,16 @@
-/* global React */
-
-import { addons } from 'react/addons';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../utils';
import Face from './face';
import Hand from './hand';
const outerNumbers = [0, ...utils.range(13, 24)];
const innerNumbers = [12, ...utils.range(1, 12)];
+const innerSpacing = 1.7;
const step = 360 / 12;
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Hours',
@@ -28,10 +28,13 @@ export default React.createClass({
},
onHandMove (degrees, radius) {
- let currentInner = radius < this.props.radius - this.props.spacing * 2;
- this.props.onChange(this.valueFromDegrees(degrees));
+ let currentInner = radius < this.props.radius - this.props.spacing * innerSpacing;
if (this.props.format === '24hr' && this.state.inner !== currentInner) {
- this.setState({inner: currentInner});
+ this.setState({inner: currentInner}, () => {
+ this.props.onChange(this.valueFromDegrees(degrees));
+ });
+ } else {
+ this.props.onChange(this.valueFromDegrees(degrees));
}
},
@@ -60,7 +63,8 @@ export default React.createClass({
numbers={innerNumbers}
spacing={this.props.spacing}
radius={innerRadius}
- active={this.props.selected} />
+ active={this.props.selected}
+ />
);
}
},
@@ -78,15 +82,17 @@ export default React.createClass({
spacing={spacing}
radius={radius}
twoDigits={is24hr}
- active={is24hr ? selected : (selected % 12 || 12)} />
- { this.renderInnerFace(radius - spacing * 2) }
+ active={is24hr ? selected : (selected % 12 || 12)}
+ />
+ { this.renderInnerFace(radius - spacing * innerSpacing) }
+ step={step}
+ />
);
}
diff --git a/components/clock/index.jsx b/components/clock/index.jsx
index d7669784..c27f87f4 100644
--- a/components/clock/index.jsx
+++ b/components/clock/index.jsx
@@ -1,13 +1,12 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import style from './style';
import time from '../utils/time';
import Hours from './hours';
import Minutes from './minutes';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Clock',
@@ -80,7 +79,7 @@ export default React.createClass({
},
calculateShape () {
- let { top, left, width } = this.refs.wrapper.getDOMNode().getBoundingClientRect();
+ let { top, left, width } = this.refs.wrapper.getBoundingClientRect();
this.setState({
center: { x: left + width / 2, y: top + width / 2 },
radius: width / 2
@@ -95,7 +94,8 @@ export default React.createClass({
onChange={this.onHourChange}
radius={this.state.radius}
selected={this.state.time.getHours()}
- spacing={this.state.radius * 0.16} />
+ spacing={this.state.radius * 0.18}
+ />
);
},
@@ -106,14 +106,15 @@ export default React.createClass({
onChange={this.onMinuteChange}
radius={this.state.radius}
selected={this.state.time.getMinutes()}
- spacing={this.state.radius * 0.16} />
+ spacing={this.state.radius * 0.18}
+ />
);
},
render () {
return (
-
-
+
+
{ this.props.display === 'hours' ? this.renderHours() : '' }
{ this.props.display === 'minutes' ? this.renderMinutes() : '' }
diff --git a/components/clock/minutes.jsx b/components/clock/minutes.jsx
index 00128be1..27191c7c 100644
--- a/components/clock/minutes.jsx
+++ b/components/clock/minutes.jsx
@@ -1,7 +1,7 @@
-/* global React */
-
-import { addons } from 'react/addons';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
import utils from '../utils';
+import style from './style';
import Face from './face';
import Hand from './hand';
@@ -9,7 +9,7 @@ const minutes = utils.range(0, 60, 5);
const step = 360 / 60;
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'Minutes',
@@ -47,14 +47,16 @@ export default React.createClass({
spacing={this.props.spacing}
radius={this.props.radius}
twoDigits={true}
- active={this.props.selected} />
+ active={this.props.selected}
+ />
+ step={step}
+ />
);
}
diff --git a/components/clock/style.scss b/components/clock/style.scss
new file mode 100644
index 00000000..76dee8e5
--- /dev/null
+++ b/components/clock/style.scss
@@ -0,0 +1,113 @@
+@import "../variables";
+
+$clock-primary: $color-primary;
+$clock-primary-contrast: $color-primary-contrast;
+$clock-primary-dark: $color-primary-dark;
+$clock-primary-color: unquote("rgb(#{$clock-primary})") !default;
+$clock-primary-hover-color: unquote("rgba(#{$clock-primary}, 0.20)") !default;
+$clock-primary-contrast-color: unquote("rgb(#{$clock-primary-contrast})") !default;
+$clock-primary-dark-color: unquote("rgb(#{$clock-primary-dark})") !default;
+$clock-number-size: 2 * $unit;
+$clock-hand-width: .4 * $unit;
+$clock-hand-dot-size: 1 * $unit;
+$clock-knob-size: 3.4 * $unit;
+$clock-knob-small-size: 1.2 * $unit;
+
+.root {
+ padding: 1.5 * $unit 2 * $unit;
+}
+
+.wrapper {
+ position: relative;
+ background-color: $color-divider;
+ border-radius: 50%;
+}
+
+.face {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ z-index: $z-index-high;
+ cursor: pointer;
+ border-radius: 50%;
+ transform: translateX(-50%) translateY(-50%);
+}
+
+.number {
+ position: relative;
+ width: $clock-number-size;
+ height: $clock-number-size;
+ margin-top: - $clock-number-size / 2;
+ margin-left: - $clock-number-size / 2;
+ text-align: center;
+ pointer-events: none;
+ user-select: none;
+
+ &.active {
+ color: $clock-primary-contrast-color;
+ }
+}
+
+.hand {
+ position: absolute;
+ bottom: 50%;
+ left: 50%;
+ display: block;
+ width: $clock-hand-width;
+ margin-left: - $clock-hand-width / 2;
+ background-color: $clock-primary-color;
+ transform-origin: 50% 100%;
+
+ &:before {
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ width: $clock-hand-dot-size;
+ height: $clock-hand-dot-size;
+ margin-bottom: - $clock-hand-dot-size / 2;
+ margin-left: - $clock-hand-dot-size / 2;
+ content: "";
+ background-color: $clock-primary-color;
+ border-radius: 50%;
+ }
+
+ &.small > .knob {
+ background-color: $clock-primary-hover-color;
+
+ &:after {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: $clock-knob-small-size;
+ height: $clock-knob-small-size;
+ margin-top: - $clock-knob-small-size / 2;
+ margin-left: - $clock-knob-small-size / 2;
+ content: "";
+ background: $clock-primary-color;
+ border-radius: 50%;
+ }
+
+ &:before {
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ width: $clock-hand-width;
+ height: $clock-knob-size - $clock-knob-small-size;
+ margin-left: - $clock-hand-width / 2;
+ content: "";
+ background: $clock-primary-color;
+ }
+ }
+}
+
+.knob {
+ position: absolute;
+ top: - $clock-knob-size;
+ left: 50%;
+ width: $clock-knob-size;
+ height: $clock-knob-size;
+ margin-left: - $clock-knob-size / 2;
+ cursor: pointer;
+ background-color: $clock-primary-color;
+ border-radius: 50%;
+}
diff --git a/components/clock/style.styl b/components/clock/style.styl
deleted file mode 100644
index c30841f9..00000000
--- a/components/clock/style.styl
+++ /dev/null
@@ -1,98 +0,0 @@
-@import '../constants'
-
-NUMBER_SIZE = 20px
-HAND_WIDTH = 4px
-HAND_DOT_SIZE = 10px
-KNOB_SIZE = 34px
-SMALL_KNOB_SIZE = 12px
-
-:local(.root)
- padding : 15px
-
-:local(.wrapper)
- background-color : DIVIDER
- border-radius : 50%
- position : relative
-
-:local(.face)
- border-radius : 50%
- cursor : pointer
- position : relative
- z-index : Z_INDEX_HIGH
-
-:local(.number)
- height : NUMBER_SIZE
- margin-left : -(NUMBER_SIZE/2)
- margin-top : -(NUMBER_SIZE/2)
- pointer-events : none
- position : relative
- text-align : center
- user-select : none
- width : NUMBER_SIZE
-
- &.active
- color : WHITE
-
-:local(.face)
- position : absolute
- top : 50%
- left : 50%
- transform : translateX(-50%) translateY(-50%)
-
-:local(.hand)
- background-color : ACCENT
- bottom : 50%
- display : block
- left : 50%
- margin-left : -(HAND_WIDTH/2)
- position : absolute
- transform-origin : 50% 100%
- width : HAND_WIDTH
-
- &:before
- background-color : ACCENT
- border-radius : 50%
- bottom : 0
- content : ''
- height : HAND_DOT_SIZE
- left : 50%
- margin-bottom : -(HAND_DOT_SIZE/2)
- margin-left : -(HAND_DOT_SIZE/2)
- position : absolute
- width : HAND_DOT_SIZE
-
- &.smallKnob :local(.knob)
- background-color: lighten(ACCENT, 70%)
-
- &:after
- background : ACCENT
- border-radius : 50%
- content : ''
- height : SMALL_KNOB_SIZE
- left : 50%
- margin-left : -(SMALL_KNOB_SIZE/2)
- margin-top : -(SMALL_KNOB_SIZE/2)
- position : absolute
- top : 50%
- width : SMALL_KNOB_SIZE
-
- &:before
- background : ACCENT
- bottom : 0
- content : ''
- height : KNOB_SIZE - SMALL_KNOB_SIZE
- left : 50%
- margin-left : -(HAND_WIDTH/2)
- position : absolute
- width : HAND_WIDTH
-
-:local(.knob)
- background-color : ACCENT
- border-radius : 50%
- cursor : pointer
- height : KNOB_SIZE
- left : 50%
- margin-left : -(KNOB_SIZE/2)
- position : absolute
- top : -(KNOB_SIZE)
- width : KNOB_SIZE
diff --git a/components/colors.scss b/components/colors.scss
new file mode 100644
index 00000000..26539ea9
--- /dev/null
+++ b/components/colors.scss
@@ -0,0 +1,163 @@
+//-- Color definitions taken from Material Design Lite
+$palette-indigo:
+"232,234,246"
+"197,202,233"
+"159,168,218"
+"121,134,203"
+"92,107,192"
+"63,81,181"
+"57,73,171"
+"48,63,159"
+"40,53,147"
+"26,35,126"
+"140,158,255"
+"83,109,254"
+"61,90,254"
+"48,79,254";
+
+$palette-indigo-50: nth($palette-indigo, 1);
+$palette-indigo-100: nth($palette-indigo, 2);
+$palette-indigo-200: nth($palette-indigo, 3);
+$palette-indigo-300: nth($palette-indigo, 4);
+$palette-indigo-400: nth($palette-indigo, 5);
+$palette-indigo-500: nth($palette-indigo, 6);
+$palette-indigo-600: nth($palette-indigo, 7);
+$palette-indigo-700: nth($palette-indigo, 8);
+$palette-indigo-800: nth($palette-indigo, 9);
+$palette-indigo-900: nth($palette-indigo, 10);
+$palette-indigo-a100: nth($palette-indigo, 11);
+$palette-indigo-a200: nth($palette-indigo, 12);
+$palette-indigo-a400: nth($palette-indigo, 13);
+$palette-indigo-a700: nth($palette-indigo, 14);
+
+$palette-pink:
+"252,228,236"
+"248,187,208"
+"244,143,177"
+"240,98,146"
+"236,64,122"
+"233,30,99"
+"216,27,96"
+"194,24,91"
+"173,20,87"
+"136,14,79"
+"255,128,171"
+"255,64,129"
+"245,0,87"
+"197,17,98";
+
+$palette-pink-50: nth($palette-pink, 1);
+$palette-pink-100: nth($palette-pink, 2);
+$palette-pink-200: nth($palette-pink, 3);
+$palette-pink-300: nth($palette-pink, 4);
+$palette-pink-400: nth($palette-pink, 5);
+$palette-pink-500: nth($palette-pink, 6);
+$palette-pink-600: nth($palette-pink, 7);
+$palette-pink-700: nth($palette-pink, 8);
+$palette-pink-800: nth($palette-pink, 9);
+$palette-pink-900: nth($palette-pink, 10);
+$palette-pink-a100: nth($palette-pink, 11);
+$palette-pink-a200: nth($palette-pink, 12);
+$palette-pink-a400: nth($palette-pink, 13);
+$palette-pink-a700: nth($palette-pink, 14);
+
+$palette-grey:
+"250,250,250"
+"245,245,245"
+"238,238,238"
+"224,224,224"
+"189,189,189"
+"158,158,158"
+"117,117,117"
+"97,97,97"
+"66,66,66"
+"33,33,33";
+
+$palette-grey-50: nth($palette-grey, 1);
+$palette-grey-100: nth($palette-grey, 2);
+$palette-grey-200: nth($palette-grey, 3);
+$palette-grey-300: nth($palette-grey, 4);
+$palette-grey-400: nth($palette-grey, 5);
+$palette-grey-500: nth($palette-grey, 6);
+$palette-grey-600: nth($palette-grey, 7);
+$palette-grey-700: nth($palette-grey, 8);
+$palette-grey-800: nth($palette-grey, 9);
+$palette-grey-900: nth($palette-grey, 10);
+
+$palette-blue:
+"227,242,253"
+"187,222,251"
+"144,202,249"
+"100,181,246"
+"66,165,245"
+"33,150,243"
+"30,136,229"
+"25,118,210"
+"21,101,192"
+"13,71,161"
+"130,177,255"
+"68,138,255"
+"41,121,255"
+"41,98,255";
+
+$palette-blue-50: nth($palette-blue, 1);
+$palette-blue-100: nth($palette-blue, 2);
+$palette-blue-200: nth($palette-blue, 3);
+$palette-blue-300: nth($palette-blue, 4);
+$palette-blue-400: nth($palette-blue, 5);
+$palette-blue-500: nth($palette-blue, 6);
+$palette-blue-600: nth($palette-blue, 7);
+$palette-blue-700: nth($palette-blue, 8);
+$palette-blue-800: nth($palette-blue, 9);
+$palette-blue-900: nth($palette-blue, 10);
+$palette-blue-a100: nth($palette-blue, 11);
+$palette-blue-a200: nth($palette-blue, 12);
+$palette-blue-a400: nth($palette-blue, 13);
+$palette-blue-a700: nth($palette-blue, 14);
+
+$palette-light-blue:
+"225,245,254"
+"179,229,252"
+"129,212,250"
+"79,195,247"
+"41,182,246"
+"3,169,244"
+"3,155,229"
+"2,136,209"
+"2,119,189"
+"1,87,155"
+"128,216,255"
+"64,196,255"
+"0,176,255"
+"0,145,234";
+
+$palette-blue-grey:
+"236,239,241"
+"207,216,220"
+"176,190,197"
+"144,164,174"
+"120,144,156"
+"96,125,139"
+"84,110,122"
+"69,90,100"
+"55,71,79"
+"38,50,56";
+
+$palette-blue-grey-50: nth($palette-blue-grey, 1);
+$palette-blue-grey-100: nth($palette-blue-grey, 2);
+$palette-blue-grey-200: nth($palette-blue-grey, 3);
+$palette-blue-grey-300: nth($palette-blue-grey, 4);
+$palette-blue-grey-400: nth($palette-blue-grey, 5);
+$palette-blue-grey-500: nth($palette-blue-grey, 6);
+$palette-blue-grey-600: nth($palette-blue-grey, 7);
+$palette-blue-grey-700: nth($palette-blue-grey, 8);
+$palette-blue-grey-800: nth($palette-blue-grey, 9);
+$palette-blue-grey-900: nth($palette-blue-grey, 10);
+
+$color-black: "0,0,0";
+$color-white: "255,255,255";
+
+//-- The two possible colors for overlayed text.
+$styleguide-generate-template: false !default;
+$color-dark-contrast: $color-white !default;
+$color-light-contrast: $color-black !default;
diff --git a/components/commons.scss b/components/commons.scss
new file mode 100644
index 00000000..c108995d
--- /dev/null
+++ b/components/commons.scss
@@ -0,0 +1,200 @@
+@import url('http://fonts.googleapis.com/css?family=Roboto:300,400,500,700');
+@import "normalize.css";
+@import "./mixins";
+
+//-- App
+html {
+ font-size: 62.5%;
+}
+
+body {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ font-family: Roboto, sans-serif;
+ font-size: 1.6rem;
+ user-select: none;
+ -webkit-touch-callout: none;
+ * {
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
+ }
+}
+
+a, abbr, address, article, aside, audio, b, blockquote, body, caption, cite,
+code, dd, del, dfn, dialog, div, dl, dt, em, fieldset, figure, footer, form, h1,
+h2, h3, h4, h5, h6, header, hgroup, hr, html, i, iframe, img, ins, kbd, label,
+legend, li, mark, menu, nav, object, ol, p, pre, q, samp, section, small, span,
+strong, sub, sup, table, tbody, td, tfoot, th, thead, time, tr, ul, var, video {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ outline: 0;
+}
+
+*, *:before, *:after {
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6, label, p, button, abbr, a, span, small {
+ font-smoothing: antialiased;
+ text-size-adjust: 100%;
+}
+
+a {
+ text-decoration: none;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+}
+
+input:not([type="checkbox"]):not([type="radio"]), button {
+ outline: none;
+ appearance: none;
+ -webkit-touch-callout: none;
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
+}
+
+//-- App wrapper to allow overlays to block scroll
+[data-react-toolbox-app] {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ overflow-y: scroll;
+}
+
+// -- Material design font sizes
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small {
+ @include typo-display-3($color-contrast: true);
+}
+
+h1 {
+ @include typo-display-3;
+}
+
+h2 {
+ @include typo-display-2;
+}
+
+h3 {
+ @include typo-display-1;
+}
+
+h4 {
+ @include typo-headline;
+}
+
+h5 {
+ @include typo-title;
+}
+
+h6 {
+ @include typo-subhead;
+}
+
+p {
+ @include typo-body-1;
+}
+
+//-- Flex
+[data-flex] {
+ display: flex;
+}
+
+body[data-flex] {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ overflow: hidden;
+}
+
+// -- Direction
+[data-flex^="horizontal"] {
+ flex-direction: row;
+}
+
+[data-flex^="vertical"] {
+ flex-direction: column;
+}
+
+
+// -- Size {
+[data-flex*="grow"] {
+ > *:not([data-column]):not([data-flex-grow]) {
+ flex-grow: 1;
+ }
+}
+
+[data-flex-grow="min"] {
+ flex-grow: 0;
+}
+
+[data-flex-grow="max"] {
+ flex-grow: 2;
+}
+
+// -- Container properties
+[data-flex*="wrap"] {
+ flex-wrap: wrap;
+}
+
+[data-flex*="center"] {
+ justify-content: center;
+ align-content: center;
+ align-items: center;
+}
+
+[data-flex-justify="start"] {
+ justify-content: flex-start;
+}
+
+[data-flex-justify="center"] {
+ justify-content: center;
+}
+
+[data-flex-justify="end"] {
+ justify-content: flex-end;
+}
+
+[data-flex-content="start"] {
+ align-content: flex-start;
+}
+
+[data-flex-content="center"] {
+ align-content: center;
+}
+
+[data-flex-content="end"] {
+ align-content: flex-end;
+}
+
+[data-flex-items="center"] {
+ align-items: center;
+}
+
+[data-flex-items="start"] {
+ align-items: flex-start;
+}
+
+[data-flex-items="end"] {
+ align-items: flex-end;
+}
+
+// -- Children properties
+[data-flex-order="first"] {
+ order: -1;
+}
+
+[data-flex-order="last"] {
+ order: 999999;
+}
diff --git a/components/commons.styl b/components/commons.styl
deleted file mode 100644
index b77b7a5e..00000000
--- a/components/commons.styl
+++ /dev/null
@@ -1,119 +0,0 @@
-@import url('http://fonts.googleapis.com/css?family=Roboto:300,400,500,700')
-@import './vendor.styl'
-@import './normalize.styl'
-
-// -- App ----------------------------------------------------------------------
-body
- position: absolute
- height: 100%
- width: 100%
- margin: 0
- padding: 0
- font-family Roboto, sans-serif
- -webkit-touch-callout: none
- -webkit-user-select: none
- -moz-user-select: moz-none
- user-select: none
- *
- -webkit-tap-highlight-color: rgba(255, 255, 255, 0)
-
-[data-toolbox]
- position: absolute
- left: 0
- top: 0
- width: 100vw
- height: 100vh
- overflow-y: scroll
-
-a,abbr,address,article,aside,audio,b,blockquote,body,caption,cite,code,dd,del,dfn,dialog,div,dl,dt,em,fieldset,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,samp,section,small,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,time,tr,ul,var,video
- border: 0
- margin: 0
- outline: 0
- padding: 0
-
-*, *:before, *:after
- margin: 0
- padding: 0
- box-sizing: border-box
-
-h1, h2, h3, h4, h5, h6, label, p, button, abbr, a, span, small
- -webkit-font-smoothing: RENDER = antialiased
- font-smoothing: RENDER
- -webkit-text-size-adjust: 100%
- -ms-text-size-adjust: 100%
- text-size-adjust: 100%
-
-a
- text-decoration: none
- -webkit-tap-highlight-color: rgba(0,0,0,0)
-
-::-webkit-scrollbar
- width: 0px
- height: 0px
-
-input:not([type="checkbox"]):not([type="radio"]), button
- -webkit-appearance: none
- -moz-appearance: none
- appearance: none
- -webkit-touch-callout: none
- -webkit-tap-highlight-color: rgba(255, 255, 255, 0)
- outline: none
-
-// -- Data-Flex ----------------------------------------------------------------
-[data-flex]
- display-flex()
- body&
- position : absolute
- left : 0
- top : 0
- bottom : 0
- width : 100%
- overflow : hidden
-
-// -- Direction
-[data-flex^="horizontal"]
- flex-direction row
-[data-flex^="vertical"]
- flex-direction column
-
-// -- Size
-[data-flex*="grow"]
- > *:not([data-column]):not([data-flex-grow])
- flex-grow 1
-[data-flex-grow="min"]
- flex-grow 0
-[data-flex-grow="max"]
- flex-grow 2
-
-// -- Container properties
-[data-flex*="wrap"]
- flex-wrap wrap
-[data-flex*="center"]
- justify-content center
- align-content center
- align-items center
-[data-flex-justify="start"]
- justify-content flex-start
-[data-flex-justify="center"]
- justify-content center
-[data-flex-justify="end"]
- justify-content flex-end
-[data-flex-content="start"]
- align-content flex-start
-[data-flex-content="center"]
- align-content center
-[data-flex-content="end"]
- align-content flex-end
-[data-flex-items="center"]
- align-items center
-[data-flex-items="start"]
- align-items flex-start
-[data-flex-items="end"]
- align-items flex-end
-
-// -- Children properties
-[data-flex-order="first"]
- order: -1
-
-[data-flex-order="last"]
- order: 999999
diff --git a/components/constants.styl b/components/constants.styl
deleted file mode 100644
index 5e16d289..00000000
--- a/components/constants.styl
+++ /dev/null
@@ -1,60 +0,0 @@
-@import './vendor.styl'
-
-// -- Colors
-PRIMARY = #E91E63
-PRIMARY_DARK = darken(PRIMARY, 25%)
-PRIMARY_LIGHT = lighten(PRIMARY, 25%)
-ACCENT = #03A9F4
-
-TEXT = #212121
-TEXT_ACCENT = #727272
-
-DIVIDER = lighten(#B6B6B6, 75%)
-BACKGROUND = #ffffff
-WHITE = #ffffff
-SUCCESS = #4CAF50
-CANCEL = #F44336
-WARNING = #FFC107
-
-// -- Fonts
-FONT_FAMILY = "Roboto", "Helvetica Neue", "Helvetica", "sans-serif"
-FONT_SIZE = 16px
-FONT_SIZE_TINY = 80%
-FONT_SIZE_SMALL = 90%
-FONT_SIZE_NORMAL = 100%
-FONT_SIZE_BIG = 120%
-FONT_WEIGHT_THIN = 300
-FONT_WEIGHT_NORMAL = 400
-FONT_WEIGHT_BOLD = 700
-
-// -- Sizes
-UNIT = 4rem
-SPACE = (UNIT * 0.29)
-OFFSET = (SPACE * 1.75)
-MENU_WIDTH = (3.85 * UNIT)
-HEADER_HEIGHT = (1.65 * UNIT)
-INPUT_HEIGHT = (2 * SPACE)
-BUTTON_HEIGHT = (2.5 * SPACE)
-BUTTON_CIRCLE_HEIGHT = (2.75 * SPACE)
-BUTTON_CIRCLE_MINI_HEIGHT = (2 * SPACE)
-LOADING_HEIGHT = (1.5 * UNIT)
-PROGRESS_BAR_HEIGHT = (SPACE / 4)
-
-// -- Shadows
-ZDEPTH_SHADOW_1 = 0 1px 6px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.24)
-ZDEPTH_SHADOW_2 = 0 3px 10px rgba(0,0,0,0.16), 0 3px 10px rgba(0,0,0,0.23)
-ZDEPTH_SHADOW_3 = 0 10px 30px rgba(0,0,0,0.19), 0 6px 10px rgba(0,0,0,0.23)
-ZDEPTH_SHADOW_4 = 0 14px 45px rgba(0,0,0,0.25), 0 10px 18px rgba(0,0,0,0.22)
-ZDEPTH_SHADOW_5 = 0 19px 60px rgba(0,0,0,0.30), 0 15px 20px rgba(0,0,0,0.22)
-
-// -- Animations
-ANIMATION_DURATION = 450ms
-ANIMATION_EASE = cubic-bezier(.55,0,.1,1)
-ANIMATION_DELAY = (ANIMATION_DURATION / 5)
-
-// -- Z Indexes
-Z_INDEX_HIGHER = 200
-Z_INDEX_HIGH = 100
-Z_INDEX_NORMAL = 1
-Z_INDEX_LOW = -100
-Z_INDEX_LOWER = -200
diff --git a/components/date_picker/dialog.jsx b/components/date_picker/dialog.jsx
index 91bbd25f..f1628443 100644
--- a/components/date_picker/dialog.jsx
+++ b/components/date_picker/dialog.jsx
@@ -1,13 +1,12 @@
-/* global React */
-
-import { addons } from 'react/addons';
-import css from './style';
+import React from 'react';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import style from './style';
import time from '../utils/time';
import Calendar from '../calendar';
import Dialog from '../dialog';
export default React.createClass({
- mixins: [addons.PureRenderMixin],
+ mixins: [PureRenderMixin],
displayName: 'CalendarDialog',
@@ -27,8 +26,8 @@ export default React.createClass({
date: this.props.initialDate,
display: 'months',
actions: [
- { label: 'Cancel', type: 'flat accent', onClick: this.onDateCancel },
- { label: 'Ok', type: 'flat accent', onClick: this.onDateSelected }
+ { label: 'Cancel', className: style.button, onClick: this.onDateCancel },
+ { label: 'Ok', className: style.button, onClick: this.onDateSelected }
]
};
},
@@ -59,28 +58,30 @@ export default React.createClass({
},
render () {
- const className = `display-${this.state.display}`;
+ const display = `display-${this.state.display}`;
+ const headerClassName = `${style.header} ${style[display]}`;
+
return (
-