diff --git a/docs/src/app/components/pages/components/buttons.jsx b/docs/src/app/components/pages/components/buttons.jsx
index dc187e1d7343e2..360c493bc2f477 100644
--- a/docs/src/app/components/pages/components/buttons.jsx
+++ b/docs/src/app/components/pages/components/buttons.jsx
@@ -16,13 +16,13 @@ var ButtonPage = React.createClass({
'\n' +
'\n' +
'\n' +
- ' Choose an Image\n' +
+ ' Choose an Image\n' +
' \n' +
'\n' +
'
\n' +
' \n' +
' \n' +
- ' Github\n' +
+ ' Github\n' +
' \n' +
'
\n' +
'\n\n' +
@@ -172,14 +172,14 @@ var ButtonPage = React.createClass({
- Choose an Image
+ Choose an Image
- Github
+ Github
diff --git a/docs/src/less/pages/components/buttons.less b/docs/src/less/pages/components/buttons.less
index 23adb1c0202bed..66f0bd33893a77 100644
--- a/docs/src/less/pages/components/buttons.less
+++ b/docs/src/less/pages/components/buttons.less
@@ -18,7 +18,7 @@
}
.example-icon-button-label {
- padding-left: 8px;
+ padding: 0px 8px;
}
}
@@ -34,6 +34,7 @@
margin-top: 24px;
margin-right: auto;
margin-left: auto;
+ padding: 0px 8px;
}
.example-image-input {
@@ -53,7 +54,7 @@
display: inline-block;
vertical-align: middle;
float: left;
- padding-left: 12px;
+ padding: 0px 8px;
line-height: 36px;
}
diff --git a/src/js/enhanced-button.jsx b/src/js/enhanced-button.jsx
index 084f7b070d6fa5..04441dd70064ee 100644
--- a/src/js/enhanced-button.jsx
+++ b/src/js/enhanced-button.jsx
@@ -120,6 +120,7 @@ var EnhancedButton = React.createClass({
this.setState({
isKeyboardFocused: false
});
+ this.props.onKeyboardFocus(false);
if (this.props.onBlur) this.props.onBlur(e);
},
@@ -133,6 +134,7 @@ var EnhancedButton = React.createClass({
this.setState({
isKeyboardFocused: true
});
+ this.props.onKeyboardFocus(true);
}
}.bind(this), 150);
@@ -144,6 +146,8 @@ var EnhancedButton = React.createClass({
this.setState({
isKeyboardFocused: false
});
+ this.props.onKeyboardFocus(false);
+
if (this.props.onTouchTap) this.props.onTouchTap(e);
}
diff --git a/src/js/flat-button.jsx b/src/js/flat-button.jsx
index db09074139161b..b7107768fabbcc 100644
--- a/src/js/flat-button.jsx
+++ b/src/js/flat-button.jsx
@@ -1,11 +1,14 @@
var React = require('react');
-var Classable = require('./mixins/classable');
+var StylePropable = require('./mixins/style-propable');
+var Transitions = require('./styles/mixins/transitions');
+var CustomVariables = require('./styles/variables/custom-variables');
+var Typography = require('./styles/core/typography');
+var Theme = require('./styles/theme');
var EnhancedButton = require('./enhanced-button');
-var Theme = require('./styles/theme').get();
var FlatButton = React.createClass({
- mixins: [Classable],
+ mixins: [StylePropable],
propTypes: {
className: React.PropTypes.string,
@@ -18,45 +21,123 @@ var FlatButton = React.createClass({
secondary: React.PropTypes.bool
},
- getDefaultProps: function() {
+ getInitialState: function() {
return {
-
+ hovered: false,
};
},
+ /** Styles */
+
+ _getBackgroundColor: function() {
+ return this.props.primary ? CustomVariables.flatButtonPrimaryHoverColor :
+ this.props.secondary ? CustomVariables.flatButtonSecondaryHoverColor :
+ CustomVariables.flatButtonHoverColor;
+ },
+
+ _main: function() {
+
+ var style = {
+ transition: Transitions.easeOut(),
+
+ fontSize: Typography.fontStyleButtonFontSize,
+ letterSpacing: 0,
+ textTransform: 'uppercase',
+
+ fontWeight: Typography.fontWeightMedium,
+
+ borderRadius: 2,
+ userSelect: 'none',
+
+ position: 'relative',
+ overflow: 'hidden',
+ backgroundColor: CustomVariables.flatButtonColor,
+ color: CustomVariables.flatButtonTextColor,
+ lineHeight: CustomVariables.buttonHeight + 'px',
+ minWidth: CustomVariables.buttonMinWidth,
+ padding: 0,
+ margin: 0,
+
+ //This is need so that ripples do not bleed past border radius.
+ //See: http://stackoverflow.com/questions/17298739/css-overflow-hidden-not-working-in-chrome-when-parent-has-border-radius-and-chil
+ transform: 'translate3d(0, 0, 0)',
+
+ color: this.props.disabled ? CustomVariables.flatButtonDisabledTextColor :
+ this.props.primary ? CustomVariables.flatButtonPrimaryTextColor :
+ this.props.secondary ? CustomVariables.flatButtonSecondaryTextColor :
+ Theme.textColor,
+ };
+
+ if (this.state.hovered && !this.props.disabled) {
+ style.backgroundColor = this._getBackgroundColor();
+ }
+
+ return style;
+ },
+
+ _label: function() {
+ return {
+ position: 'relative',
+ padding: '0 ' + CustomVariables.spacing.desktopGutterLess + 'px',
+ };
+ },
+
+
render: function() {
var {
label,
primary,
secondary,
+ onMouseOver,
+ onMouseOut,
...other
} = this.props;
- var classes = this.getClasses('mui-flat-button', {
- 'mui-is-primary': primary,
- 'mui-is-secondary': !primary && secondary
- });
var children = label ?
- {label} :
+ {label} :
this.props.children;
- var focusRippleColor = primary ?
- Theme.accent1Color : secondary ?
- Theme.primary1Color : Theme.textColor;
-
- var touchRippleColor = focusRippleColor;
+ var focusRippleColor = primary ? CustomVariables.flatButtonPrimaryFocusRippleColor :
+ secondary ? CustomVariables.flatButtonSecondaryFocusRippleColor :
+ CustomVariables.flatButtonFocusRippleColor;
+ var touchRippleColor = primary ? CustomVariables.flatButtonPrimaryRippleColor :
+ secondary ? CustomVariables.flatButtonSecondaryRippleColor :
+ CustomVariables.flatButtonRippleColor;
return (
+ touchRippleColor={touchRippleColor}
+ onKeyboardFocus={this._handleKeyboardFocus}>
{children}
);
+ },
+
+ _onMouseOver: function(e) {
+ this.setState({hovered: true});
+ if (this.props.onMouseOver) this.props.onMouseOver(e);
+ },
+
+ _onMouseOut: function(e) {
+ this.setState({hovered: false});
+ if (this.props.onMouseOut) this.props.onMouseOut(e);
+ },
+
+ _handleKeyboardFocus: function(keyboardFocused) {
+
+ if (keyboardFocused && !this.props.disabled) {
+ this.getDOMNode().style.backgroundColor = this._getBackgroundColor();
+ } else {
+ this.getDOMNode().style.backgroundColor = 'transparent';
+ }
}
+
});
-module.exports = FlatButton;
\ No newline at end of file
+module.exports = FlatButton;
diff --git a/src/js/styles/core/typography.js b/src/js/styles/core/typography.js
new file mode 100644
index 00000000000000..86e977fb1a7a57
--- /dev/null
+++ b/src/js/styles/core/typography.js
@@ -0,0 +1,22 @@
+var Colors = require('../colors');
+
+var typography = new (function() {
+
+ // text colors
+ this.textFullBlack = Colors.fullBlack;
+ this.textDarkBlack = Colors.darkBlack;
+ this.textLightBlack = Colors.lightBlack;
+ this.textMinBlack = Colors.minBlack;
+ this.textFullWhite = Colors.fullWhite;
+ this.textDarkWhite = Colors.darkWhite;
+ this.textLightWhite = Colors.lightWhite;
+
+ // font weight
+ this.fontWeightLight = 300;
+ this.fontWeightNormal = 400;
+ this.fontWeightMedium = 500;
+
+ this.fontStyleButtonFontSize = 14;
+});
+
+module.exports = typography;
\ No newline at end of file
diff --git a/src/js/styles/variables/custom-variables.js b/src/js/styles/variables/custom-variables.js
index a8a3aeae680278..0169f041e4d5a6 100644
--- a/src/js/styles/variables/custom-variables.js
+++ b/src/js/styles/variables/custom-variables.js
@@ -1,6 +1,7 @@
var Colors = require('../colors');
var Spacing = require('./spacing');
var Theme = require('../theme').get();
+var ColorManipulator = require('../../utils/color-manipulator');
var customVariables = new (function() {
@@ -39,6 +40,27 @@ var customVariables = new (function() {
// buttons
this.iconButtonSize = Spacing.iconSize * 2;
+ this.buttonHeight = 36;
+ this.buttonMinWidth = 88;
+
+ this.iconButtonSize = Spacing.iconSize * 2;
+
+ this.flatButtonColor = Colors.white;
+ this.flatButtonHoverColor = ColorManipulator.darken(this.flatButtonColor, 0.1);
+ this.flatButtonTextColor = Theme.textColor;
+
+ this.flatButtonRippleColor = 'rgba(0,0,0,0.7)';
+ this.flatButtonFocusRippleColor = ColorManipulator.fade(this.flatButtonRippleColor, 0.7);
+ this.flatButtonPrimaryHoverColor = ColorManipulator.lighten(Theme.accent1Color, 0.32);
+ this.flatButtonPrimaryTextColor = Theme.accent1Color;
+ this.flatButtonPrimaryRippleColor = ColorManipulator.fade(this.flatButtonPrimaryTextColor, 0.8);
+ this.flatButtonPrimaryFocusRippleColor = ColorManipulator.fade(this.flatButtonPrimaryRippleColor, 0.8);
+ this.flatButtonSecondaryHoverColor = ColorManipulator.lighten(Theme.primary1Color, 0.52);
+ this.flatButtonSecondaryTextColor = Theme.primary1Color;
+ this.flatButtonSecondaryRippleColor = ColorManipulator.fade(this.flatButtonSecondaryTextColor, 0.8);
+ this.flatButtonSecondaryFocusRippleColor = ColorManipulator.fade(this.flatButtonSecondaryRippleColor, 0.8);
+ this.flatButtonDisabledTextColor = ColorManipulator.fade(this.flatButtonTextColor, 0.3);
+
// date picker
this.datePickerColor = Theme.primary1Color;
this.datePickerTextColor = Colors.white;
diff --git a/src/js/utils/color-manipulator.js b/src/js/utils/color-manipulator.js
new file mode 100644
index 00000000000000..9521904a428ea8
--- /dev/null
+++ b/src/js/utils/color-manipulator.js
@@ -0,0 +1,98 @@
+module.exports = {
+
+ // additionalValue = An extra value that has been calculated but not included
+ // with the original color object, such as an alpha value.
+ _convertColorToString: function (color, additonalValue) {
+ var str = color.type + '(' +
+ parseInt(color.values[0]) + ',' +
+ parseInt(color.values[1]) + ',' +
+ parseInt(color.values[2]);
+
+ if (additonalValue !== undefined) {
+ str += ',' + additonalValue + ')';
+ } else if (color.values.length == 4) {
+ str += ',' + color.values[3] + ')';
+ } else {
+ str += ')';
+ }
+
+ return str;
+ },
+
+ _convertHexToRGB: function(color) {
+ if (color.length === 4) {
+ var extendedColor = '#';
+ for (var i = 1; i < color.length; i++) {
+ extendedColor += color.charAt(i) + color.charAt(i);
+ }
+ color = extendedColor;
+ }
+
+ var values = {
+ r: parseInt(color.substr(1,2), 16),
+ g: parseInt(color.substr(3,2), 16),
+ b: parseInt(color.substr(5,2), 16),
+ };
+
+ return 'rgb(' + values.r + ',' +
+ values.g + ',' +
+ values.b + ')';
+ },
+
+ _decomposeColor: function(color) {
+ if (color.charAt(0) === '#') {
+ return this._decomposeColor(this._convertHexToRGB(color));
+ }
+
+ var marker = color.indexOf('(');
+ var type = color.substring(0, marker);
+ var values = color.substring(marker + 1, color.length - 1).split(',');
+
+ return {type: type, values: values};
+ },
+
+
+ // Set the absolute transparency of a color.
+ // Any existing alpha values are overwritten.
+ fade: function(color, amount) {
+ var colorObj = this._decomposeColor(color);
+ if (colorObj.type == 'rgb' || colorObj.type == 'hsl') colorObj.type += 'a';
+ return this._convertColorToString(colorObj, amount)
+ },
+
+ // Desaturates rgb and sets opacity to 0.15
+ lighten: function(color, amount) {
+ var colorObj = this._decomposeColor(color);
+
+ if (colorObj.type.indexOf('hsl') > -1) {
+ colorObj.values[2] += amount;
+ return this._decomposeColor(colorObj);
+ } else if (colorObj.type.indexOf('rgb') > -1) {
+ for (var i = 0; i < 3; i++) {
+ colorObj.values[i] *= 1 + amount;
+ if (colorObj.values[i] > 255) colorObj.values[i] = 255;
+ }
+ }
+
+ if (colorObj.type.indexOf('a') <= -1) colorObj.type += 'a';
+
+ return this._convertColorToString(colorObj, '0.15');
+ },
+
+
+ darken: function(color, amount) {
+ var colorObj = this._decomposeColor(color);
+
+ if (colorObj.type.indexOf('hsl') > -1) {
+ colorObj.values[2] += amount;
+ return this._decomposeColor(colorObj);
+ } else if (colorObj.type.indexOf('rgb') > -1) {
+ for (var i = 0; i < 3; i++) {
+ colorObj.values[i] *= 1 - amount;
+ if (colorObj.values[i] < 0) colorObj.values[i] = 0;
+ }
+ }
+
+ return this._convertColorToString(colorObj);
+ },
+};
\ No newline at end of file
diff --git a/src/less/components/components.less b/src/less/components/components.less
index 88719185a1e182..e2ce668aaa9477 100644
--- a/src/less/components/components.less
+++ b/src/less/components/components.less
@@ -2,7 +2,6 @@
@import "card.less";
@import "date-picker/date-picker.less";
@import "enhanced-button.less";
-@import "flat-button.less";
@import "floating-action-button.less";
@import "left-nav.less";
@import "paper.less";
diff --git a/src/less/components/flat-button.less b/src/less/components/flat-button.less
deleted file mode 100644
index 192b0d813c078f..00000000000000
--- a/src/less/components/flat-button.less
+++ /dev/null
@@ -1,93 +0,0 @@
-.mui-flat-button {
-
- .ease-out();
- .mui-font-style-button;
- border-radius: 2px;
- user-select: none;
-
- position: relative;
- overflow: hidden;
- background-color: @flat-button-color;
- color: @flat-button-text-color;
- line-height: @button-height;
- min-width: @button-min-width;
- padding: 0;
- margin: 0;
-
- //This is need so that ripples do not bleed
- //past border radius.
- //See: http://stackoverflow.com/questions/17298739/css-overflow-hidden-not-working-in-chrome-when-parent-has-border-radius-and-chil
- transform: translate3d(0, 0, 0);
-
- .mui-touch-ripple {
- .mui-ripple-circle-inner {
- background-color: @flat-button-ripple-color;
- }
- }
-
- .mui-focus-ripple {
- .mui-focus-ripple-inner {
- background-color: @flat-button-focus-ripple-color;
- }
- }
-
- .mui-flat-button-label {
- position: relative;
- padding: 0 @desktop-gutter-less;
- }
-
- &:hover,
- &.mui-is-keyboard-focused {
- background-color: @flat-button-hover-color;
- }
-
- &.mui-is-disabled {
- color: @flat-button-disabled-text-color;
-
- &:hover {
- background-color: inherit;
- }
- }
-
- &.mui-is-primary {
- color: @flat-button-primary-text-color;
-
- &:hover,
- &.mui-is-keyboard-focused {
- background-color: @flat-button-primary-hover-color;
- }
-
- .mui-touch-ripple {
- .mui-ripple-circle-inner {
- background-color: @flat-button-primary-ripple-color;
- }
- }
-
- .mui-focus-ripple {
- .mui-focus-ripple-inner {
- background-color: @flat-button-primary-focus-ripple-color;
- }
- }
- }
-
- &.mui-is-secondary {
- color: @flat-button-secondary-text-color;
-
- &:hover,
- &.mui-is-keyboard-focused {
- background-color: @flat-button-secondary-hover-color;
- }
-
- .mui-touch-ripple {
- .mui-ripple-circle-inner {
- background-color: @flat-button-secondary-ripple-color;
- }
- }
-
- .mui-focus-ripple {
- .mui-focus-ripple-inner {
- background-color: @flat-button-secondary-focus-ripple-color;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/less/variables/custom-variables.less b/src/less/variables/custom-variables.less
index 524f9eeb7947dd..dcdc80c1c8b769 100644
--- a/src/less/variables/custom-variables.less
+++ b/src/less/variables/custom-variables.less
@@ -48,21 +48,6 @@
@icon-button-size: (@icon-size * 2);
-@flat-button-color: @white;
-@flat-button-hover-color: darken(@flat-button-color, 10%);
-@flat-button-text-color: @body-text-color;
-@flat-button-ripple-color: rgba(0,0,0,0.1);
-@flat-button-focus-ripple-color: fade(@flat-button-ripple-color, 7%);
-@flat-button-primary-hover-color: lighten(@accent-1-color, 32%);
-@flat-button-primary-text-color: @accent-1-color;
-@flat-button-primary-ripple-color: fade(@flat-button-primary-text-color, 20%);
-@flat-button-primary-focus-ripple-color: fade(@flat-button-primary-ripple-color, 20%);
-@flat-button-secondary-hover-color: lighten(@primary-1-color, 52%);
-@flat-button-secondary-text-color: @primary-1-color;
-@flat-button-secondary-ripple-color: fade(@flat-button-secondary-text-color, 20%);
-@flat-button-secondary-focus-ripple-color: fade(@flat-button-secondary-ripple-color, 20%);
-@flat-button-disabled-text-color: fade(@flat-button-text-color, 30%);
-
@raised-button-color: @white;
@raised-button-hover-color: darken(@raised-button-color, 10%);
@raised-button-text-color: @body-text-color;