UNPKG

@material-ui/core

Version:

React components that implement Google's Material Design.

538 lines (441 loc) 17.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.styles = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactDom = _interopRequireDefault(require("react-dom")); var _classnames = _interopRequireDefault(require("classnames")); var _keycode = _interopRequireDefault(require("keycode")); var _ownerWindow = _interopRequireDefault(require("../utils/ownerWindow")); var _withStyles = _interopRequireDefault(require("../styles/withStyles")); var _focusVisible = require("./focusVisible"); var _TouchRipple = _interopRequireDefault(require("./TouchRipple")); var _createRippleHandler = _interopRequireDefault(require("./createRippleHandler")); var styles = { /* Styles applied to the root element. */ root: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', position: 'relative', // Remove grey highlight WebkitTapHighlightColor: 'transparent', backgroundColor: 'transparent', // Reset default value // We disable the focus ring for mouse, touch and keyboard users. outline: 'none', border: 0, margin: 0, // Remove the margin in Safari borderRadius: 0, padding: 0, // Remove the padding in Firefox cursor: 'pointer', userSelect: 'none', verticalAlign: 'middle', '-moz-appearance': 'none', // Reset '-webkit-appearance': 'none', // Reset textDecoration: 'none', // So we take precedent over the style of a native <a /> element. color: 'inherit', '&::-moz-focus-inner': { borderStyle: 'none' // Remove Firefox dotted outline. }, '&$disabled': { pointerEvents: 'none', // Disable link interactions cursor: 'default' } }, /* Styles applied to the root element if `disabled={true}`. */ disabled: {}, /* Styles applied to the root element if keyboard focused. */ focusVisible: {} }; /* istanbul ignore if */ exports.styles = styles; if (process.env.NODE_ENV !== 'production' && !_react.default.createContext) { throw new Error('Material-UI: react@16.3.0 or greater is required.'); } /** * `ButtonBase` contains as few styles as possible. * It aims to be a simple building block for creating a button. * It contains a load of style reset and some focus/ripple logic. */ var ButtonBase = /*#__PURE__*/ function (_React$Component) { (0, _inherits2.default)(ButtonBase, _React$Component); function ButtonBase() { var _getPrototypeOf2; var _this; (0, _classCallCheck2.default)(this, ButtonBase); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(ButtonBase)).call.apply(_getPrototypeOf2, [this].concat(args))); _this.state = {}; _this.keyDown = false; _this.focusVisibleCheckTime = 50; _this.focusVisibleMaxCheckTimes = 5; _this.handleMouseDown = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseDown', 'start', function () { clearTimeout(_this.focusVisibleTimeout); if (_this.state.focusVisible) { _this.setState({ focusVisible: false }); } }); _this.handleMouseUp = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseUp', 'stop'); _this.handleMouseLeave = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'MouseLeave', 'stop', function (event) { if (_this.state.focusVisible) { event.preventDefault(); } }); _this.handleTouchStart = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchStart', 'start'); _this.handleTouchEnd = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchEnd', 'stop'); _this.handleTouchMove = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'TouchMove', 'stop'); _this.handleBlur = (0, _createRippleHandler.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), 'Blur', 'stop', function () { clearTimeout(_this.focusVisibleTimeout); if (_this.state.focusVisible) { _this.setState({ focusVisible: false }); } }); _this.onRippleRef = function (node) { _this.ripple = node; }; _this.onFocusVisibleHandler = function (event) { _this.keyDown = false; _this.setState({ focusVisible: true }); if (_this.props.onFocusVisible) { _this.props.onFocusVisible(event); } }; _this.handleKeyDown = function (event) { var _this$props = _this.props, component = _this$props.component, focusRipple = _this$props.focusRipple, onKeyDown = _this$props.onKeyDown, onClick = _this$props.onClick; var key = (0, _keycode.default)(event); // Check if key is already down to avoid repeats being counted as multiple activations if (focusRipple && !_this.keyDown && _this.state.focusVisible && _this.ripple && key === 'space') { _this.keyDown = true; event.persist(); _this.ripple.stop(event, function () { _this.ripple.start(event); }); } if (onKeyDown) { onKeyDown(event); } // Keyboard accessibility for non interactive elements if (event.target === event.currentTarget && component && component !== 'button' && (key === 'space' || key === 'enter') && !(_this.button.tagName === 'A' && _this.button.href)) { event.preventDefault(); if (onClick) { onClick(event); } } }; _this.handleKeyUp = function (event) { if (_this.props.focusRipple && (0, _keycode.default)(event) === 'space' && _this.ripple && _this.state.focusVisible) { _this.keyDown = false; event.persist(); _this.ripple.stop(event, function () { _this.ripple.pulsate(event); }); } if (_this.props.onKeyUp) { _this.props.onKeyUp(event); } }; _this.handleFocus = function (event) { if (_this.props.disabled) { return; } // Fix for https://github.com/facebook/react/issues/7769 if (!_this.button) { _this.button = event.currentTarget; } event.persist(); (0, _focusVisible.detectFocusVisible)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), _this.button, function () { _this.onFocusVisibleHandler(event); }); if (_this.props.onFocus) { _this.props.onFocus(event); } }; return _this; } (0, _createClass2.default)(ButtonBase, [{ key: "componentDidMount", value: function componentDidMount() { var _this2 = this; this.button = _reactDom.default.findDOMNode(this); (0, _focusVisible.listenForFocusKeys)((0, _ownerWindow.default)(this.button)); if (this.props.action) { this.props.action({ focusVisible: function focusVisible() { _this2.setState({ focusVisible: true }); _this2.button.focus(); } }); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps, prevState) { if (this.props.focusRipple && !this.props.disableRipple && !prevState.focusVisible && this.state.focusVisible) { this.ripple.pulsate(); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { clearTimeout(this.focusVisibleTimeout); } }, { key: "render", value: function render() { var _classNames; var _this$props2 = this.props, action = _this$props2.action, buttonRef = _this$props2.buttonRef, centerRipple = _this$props2.centerRipple, children = _this$props2.children, classes = _this$props2.classes, classNameProp = _this$props2.className, component = _this$props2.component, disabled = _this$props2.disabled, disableRipple = _this$props2.disableRipple, disableTouchRipple = _this$props2.disableTouchRipple, focusRipple = _this$props2.focusRipple, focusVisibleClassName = _this$props2.focusVisibleClassName, onBlur = _this$props2.onBlur, onFocus = _this$props2.onFocus, onFocusVisible = _this$props2.onFocusVisible, onKeyDown = _this$props2.onKeyDown, onKeyUp = _this$props2.onKeyUp, onMouseDown = _this$props2.onMouseDown, onMouseLeave = _this$props2.onMouseLeave, onMouseUp = _this$props2.onMouseUp, onTouchEnd = _this$props2.onTouchEnd, onTouchMove = _this$props2.onTouchMove, onTouchStart = _this$props2.onTouchStart, tabIndex = _this$props2.tabIndex, TouchRippleProps = _this$props2.TouchRippleProps, type = _this$props2.type, other = (0, _objectWithoutProperties2.default)(_this$props2, ["action", "buttonRef", "centerRipple", "children", "classes", "className", "component", "disabled", "disableRipple", "disableTouchRipple", "focusRipple", "focusVisibleClassName", "onBlur", "onFocus", "onFocusVisible", "onKeyDown", "onKeyUp", "onMouseDown", "onMouseLeave", "onMouseUp", "onTouchEnd", "onTouchMove", "onTouchStart", "tabIndex", "TouchRippleProps", "type"]); var className = (0, _classnames.default)(classes.root, (_classNames = {}, (0, _defineProperty2.default)(_classNames, classes.disabled, disabled), (0, _defineProperty2.default)(_classNames, classes.focusVisible, this.state.focusVisible), (0, _defineProperty2.default)(_classNames, focusVisibleClassName, this.state.focusVisible), _classNames), classNameProp); var buttonProps = {}; var ComponentProp = component; if (ComponentProp === 'button' && other.href) { ComponentProp = 'a'; } if (ComponentProp === 'button') { buttonProps.type = type || 'button'; buttonProps.disabled = disabled; } else { buttonProps.role = 'button'; } return _react.default.createElement(ComponentProp, (0, _extends2.default)({ onBlur: this.handleBlur, onFocus: this.handleFocus, onKeyDown: this.handleKeyDown, onKeyUp: this.handleKeyUp, onMouseDown: this.handleMouseDown, onMouseLeave: this.handleMouseLeave, onMouseUp: this.handleMouseUp, onTouchEnd: this.handleTouchEnd, onTouchMove: this.handleTouchMove, onTouchStart: this.handleTouchStart, tabIndex: disabled ? '-1' : tabIndex, className: className, ref: buttonRef }, buttonProps, other), children, !disableRipple && !disabled ? _react.default.createElement(_TouchRipple.default, (0, _extends2.default)({ innerRef: this.onRippleRef, center: centerRipple }, TouchRippleProps)) : null); } }], [{ key: "getDerivedStateFromProps", value: function getDerivedStateFromProps(nextProps, prevState) { if (typeof prevState.focusVisible === 'undefined') { return { focusVisible: false, lastDisabled: nextProps.disabled }; } // The blur won't fire when the disabled state is set on a focused input. // We need to book keep the focused state manually. if (!prevState.prevState && nextProps.disabled && prevState.focusVisible) { return { focusVisible: false, lastDisabled: nextProps.disabled }; } return { lastDisabled: nextProps.disabled }; } }]); return ButtonBase; }(_react.default.Component); ButtonBase.propTypes = process.env.NODE_ENV !== "production" ? { /** * Callback fired when the component mounts. * This is useful when you want to trigger an action programmatically. * It currently only supports `focusVisible()` action. * * @param {object} actions This object contains all possible actions * that can be triggered programmatically. */ action: _propTypes.default.func, /** * Use that property to pass a ref callback to the native button component. */ buttonRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]), /** * If `true`, the ripples will be centered. * They won't start at the cursor interaction position. */ centerRipple: _propTypes.default.bool, /** * The content of the component. */ children: _propTypes.default.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css-api) below for more details. */ classes: _propTypes.default.object.isRequired, /** * @ignore */ className: _propTypes.default.string, /** * The component used for the root node. * Either a string to use a DOM element or a component. */ component: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.object]), /** * If `true`, the base button will be disabled. */ disabled: _propTypes.default.bool, /** * If `true`, the ripple effect will be disabled. */ disableRipple: _propTypes.default.bool, /** * If `true`, the touch ripple effect will be disabled. */ disableTouchRipple: _propTypes.default.bool, /** * If `true`, the base button will have a keyboard focus ripple. * `disableRipple` must also be `false`. */ focusRipple: _propTypes.default.bool, /** * This property can help a person know which element has the keyboard focus. * The class name will be applied when the element gain the focus through a keyboard interaction. * It's a polyfill for the [CSS :focus-visible feature](https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo). * The rational for using this feature [is explain here](https://github.com/WICG/focus-visible/blob/master/explainer.md). */ focusVisibleClassName: _propTypes.default.string, /** * @ignore */ onBlur: _propTypes.default.func, /** * @ignore */ onClick: _propTypes.default.func, /** * @ignore */ onFocus: _propTypes.default.func, /** * Callback fired when the component is focused with a keyboard. * We trigger a `onFocus` callback too. */ onFocusVisible: _propTypes.default.func, /** * @ignore */ onKeyDown: _propTypes.default.func, /** * @ignore */ onKeyUp: _propTypes.default.func, /** * @ignore */ onMouseDown: _propTypes.default.func, /** * @ignore */ onMouseLeave: _propTypes.default.func, /** * @ignore */ onMouseUp: _propTypes.default.func, /** * @ignore */ onTouchEnd: _propTypes.default.func, /** * @ignore */ onTouchMove: _propTypes.default.func, /** * @ignore */ onTouchStart: _propTypes.default.func, /** * @ignore */ role: _propTypes.default.string, /** * @ignore */ tabIndex: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]), /** * Properties applied to the `TouchRipple` element. */ TouchRippleProps: _propTypes.default.object, /** * Used to control the button's purpose. * This property passes the value to the `type` attribute of the native button component. * Valid property values include `button`, `submit`, and `reset`. */ type: _propTypes.default.string } : {}; ButtonBase.defaultProps = { centerRipple: false, component: 'button', disableRipple: false, disableTouchRipple: false, focusRipple: false, tabIndex: '0', type: 'button' }; var _default = (0, _withStyles.default)(styles, { name: 'MuiButtonBase' })(ButtonBase); exports.default = _default;