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;