UNPKG

material-ui

Version:

Material Design UI components built with React

314 lines (276 loc) 7.97 kB
const React = require('react'); const PureRenderMixin = require('react-addons-pure-render-mixin'); const StylePropable = require('./mixins/style-propable'); const Colors = require('./styles/colors'); const Children = require('./utils/children'); const Events = require('./utils/events'); const KeyCode = require('./utils/key-code'); const FocusRipple = require('./ripples/focus-ripple'); const TouchRipple = require('./ripples/touch-ripple'); const DefaultRawTheme = require('./styles/raw-themes/light-raw-theme'); const ThemeManager = require('./styles/theme-manager'); let styleInjected = false; let listening = false; let tabPressed = false; function injectStyle() { if (!styleInjected) { // Remove inner padding and border in Firefox 4+. let style = document.createElement("style"); style.innerHTML = ` button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } `; document.body.appendChild(style); styleInjected = true; } } function listenForTabPresses() { if (!listening) { Events.on(window, 'keydown', (e) =>{ tabPressed = e.keyCode === KeyCode.TAB; }); listening = true; } } const EnhancedButton = React.createClass({ mixins: [PureRenderMixin, StylePropable], contextTypes: { muiTheme: React.PropTypes.object, }, //for passing default theme context to children childContextTypes: { muiTheme: React.PropTypes.object, }, getChildContext () { return { muiTheme: this.state.muiTheme, }; }, propTypes: { centerRipple: React.PropTypes.bool, containerElement: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.element, ]), disabled: React.PropTypes.bool, disableFocusRipple: React.PropTypes.bool, disableKeyboardFocus: React.PropTypes.bool, disableTouchRipple: React.PropTypes.bool, keyboardFocused: React.PropTypes.bool, linkButton: React.PropTypes.bool, focusRippleColor: React.PropTypes.string, touchRippleColor: React.PropTypes.string, focusRippleOpacity: React.PropTypes.number, touchRippleOpacity: React.PropTypes.number, onBlur: React.PropTypes.func, onFocus: React.PropTypes.func, onKeyboardFocus: React.PropTypes.func, onKeyDown: React.PropTypes.func, onKeyUp: React.PropTypes.func, onTouchTap: React.PropTypes.func, tabIndex: React.PropTypes.number, }, getDefaultProps() { return { containerElement: 'button', onBlur: () => {}, onFocus: () => {}, onKeyboardFocus: () => {}, onKeyDown: () => {}, onKeyUp: () => {}, onTouchTap: () => {}, tabIndex: 0, type: 'button', }; }, getInitialState() { return { isKeyboardFocused: !this.props.disabled && this.props.keyboardFocused && !this.props.disableKeyboardFocus, muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme), }; }, componentWillReceiveProps(nextProps, nextContext) { let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme; this.setState({muiTheme: newMuiTheme}); if ((nextProps.disabled || nextProps.disableKeyboardFocus) && this.state.isKeyboardFocused) { this.setState({isKeyboardFocused: false}); if (nextProps.onKeyboardFocus) { nextProps.onKeyboardFocus(null, false); } } }, componentDidMount() { injectStyle(); listenForTabPresses(); }, render() { const { centerRipple, children, containerElement, disabled, disableFocusRipple, disableKeyboardFocus, disableTouchRipple, focusRippleColor, focusRippleOpacity, linkButton, touchRippleColor, touchRippleOpacity, onBlur, onFocus, onKeyUp, onKeyDown, onTouchTap, style, tabIndex, type, ...other, } = this.props; const mergedStyles = this.prepareStyles({ border: 10, background: 'none', boxSizing: 'border-box', display: 'inline-block', font: 'inherit', fontFamily: this.state.muiTheme.rawTheme.fontFamily, tapHighlightColor: Colors.transparent, appearance: linkButton ? null : 'button', cursor: disabled ? 'default' : 'pointer', textDecoration: 'none', outline: 'none', }, style); if (disabled && linkButton) { return ( <span {...other} style={mergedStyles}> {children} </span> ); } const buttonProps = { ...other, style: mergedStyles, disabled: disabled, onBlur: this._handleBlur, onFocus: this._handleFocus, onTouchTap: this._handleTouchTap, onKeyUp: this._handleKeyUp, onKeyDown: this._handleKeyDown, tabIndex: tabIndex, type: type, }; const buttonChildren = this._createButtonChildren(); return React.isValidElement(containerElement) ? React.cloneElement(containerElement, buttonProps, buttonChildren) : React.createElement(linkButton ? 'a' : containerElement, buttonProps, buttonChildren); }, isKeyboardFocused() { return this.state.isKeyboardFocused; }, removeKeyboardFocus(e) { if (this.state.isKeyboardFocused) { this.setState({isKeyboardFocused: false}); this.props.onKeyboardFocus(e, false); } }, setKeyboardFocus(e) { if (!this.state.isKeyboardFocused) { this.setState({isKeyboardFocused: true}); this.props.onKeyboardFocus(e, true); } }, _cancelFocusTimeout() { if (this._focusTimeout) { clearTimeout(this._focusTimeout); this._focusTimeout = null; } }, _createButtonChildren() { const { centerRipple, children, disabled, disableFocusRipple, disableKeyboardFocus, disableTouchRipple, focusRippleColor, focusRippleOpacity, touchRippleColor, touchRippleOpacity, } = this.props; const { isKeyboardFocused } = this.state; //Focus Ripple const focusRipple = isKeyboardFocused && !disabled && !disableFocusRipple && !disableKeyboardFocus ? ( <FocusRipple color={focusRippleColor} opacity={focusRippleOpacity} show={isKeyboardFocused} /> ) : undefined; //Touch Ripple const touchRipple = !disabled && !disableTouchRipple ? ( <TouchRipple centerRipple={centerRipple} color={touchRippleColor} opacity={touchRippleOpacity}> {children} </TouchRipple> ) : undefined; return Children.create({ focusRipple, touchRipple, children: touchRipple ? undefined : children, }); }, _handleKeyDown(e) { if (!this.props.disabled && !this.props.disableKeyboardFocus) { if (e.keyCode === KeyCode.ENTER && this.state.isKeyboardFocused) { this._handleTouchTap(e); } } this.props.onKeyDown(e); }, _handleKeyUp(e) { if (!this.props.disabled && e.keyCode === KeyCode.SPACE && this.state.isKeyboardFocused) { this._handleTouchTap(e); } this.props.onKeyUp(e); }, _handleBlur(e) { this._cancelFocusTimeout(); this.removeKeyboardFocus(e); this.props.onBlur(e); }, _handleFocus(e) { if (!this.props.disabled && !this.props.disableKeyboardFocus) { //setTimeout is needed because the focus event fires first //Wait so that we can capture if this was a keyboard focus //or touch focus this._focusTimeout = setTimeout(() => { if (tabPressed) { this.setKeyboardFocus(e); } }, 150); this.props.onFocus(e); } }, _handleTouchTap(e) { this._cancelFocusTimeout(); if (!this.props.disabled) { tabPressed = false; this.removeKeyboardFocus(e); this.props.onTouchTap(e); } }, }); module.exports = EnhancedButton;