@material-ui/core
Version:
React components that implement Google's Material Design.
538 lines (441 loc) • 17.2 kB
JavaScript
"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;