Files
goTorrent/goTorrentWebUI/node_modules/material-ui/ButtonBase/ButtonBase.js.flow

395 lines
8.8 KiB
Plaintext

// @flow weak
import React from 'react';
import type { ElementType, Node } from 'react';
import { findDOMNode } from 'react-dom';
import classNames from 'classnames';
import keycode from 'keycode';
import withStyles from '../styles/withStyles';
import { listenForFocusKeys, detectKeyboardFocus, focusKeyPressed } from '../utils/keyboardFocus';
import TouchRipple from './TouchRipple';
import createRippleHandler from './createRippleHandler';
export const styles = (theme: Object) => ({
root: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
// Remove grey highlight
WebkitTapHighlightColor: theme.palette.common.transparent,
backgroundColor: 'transparent', // Reset default value
outline: 'none',
border: 0,
borderRadius: 0,
cursor: 'pointer',
userSelect: 'none',
appearance: 'none',
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',
},
});
type ProvidedProps = {
classes: Object,
};
export type Props = {
/**
* If `true`, the ripples will be centered.
* They won't start at the cursor interaction position.
*/
centerRipple?: boolean,
/**
* The content of the component.
*/
children?: Node,
/**
* Useful to extend the style applied to components.
*/
classes?: Object,
/**
* @ignore
*/
className?: string,
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
* The default value is a `button`.
*/
component?: ElementType,
/**
* If `true`, the base button will be disabled.
*/
disabled?: boolean,
/**
* If `true`, the ripple effect will be disabled.
*/
disableRipple?: boolean,
/**
* If `true`, the base button will have a keyboard focus ripple.
* `disableRipple` must also be `false`.
*/
focusRipple?: boolean,
/**
* The CSS class applied while the component is keyboard focused.
*/
keyboardFocusedClassName?: string,
/**
* @ignore
*/
onBlur?: Function,
/**
* @ignore
*/
onClick?: Function,
/**
* @ignore
*/
onFocus?: Function,
/**
* Callback fired when the component is focused with a keyboard.
* We trigger a `onFocus` callback too.
*/
onKeyboardFocus?: (event: SyntheticEvent<>) => void,
/**
* @ignore
*/
onKeyDown?: Function,
/**
* @ignore
*/
onKeyUp?: Function,
/**
* @ignore
*/
onMouseDown?: Function,
/**
* @ignore
*/
onMouseLeave?: Function,
/**
* @ignore
*/
onMouseUp?: Function,
/**
* @ignore
*/
onTouchEnd?: Function,
/**
* @ignore
*/
onTouchMove?: Function,
/**
* @ignore
*/
onTouchStart?: Function,
/**
* @ignore
*/
role?: string,
/**
* Use that property to pass a ref callback to the root component.
*/
rootRef?: Function,
/**
* @ignore
*/
tabIndex?: number | string,
/**
* @ignore
*/
type: string,
};
type State = {
keyboardFocused: boolean,
};
class ButtonBase extends React.Component<ProvidedProps & Props, State> {
static defaultProps = {
centerRipple: false,
focusRipple: false,
disableRipple: false,
tabIndex: 0,
type: 'button',
};
state = {
keyboardFocused: false,
};
componentDidMount() {
this.button = findDOMNode(this);
listenForFocusKeys();
}
componentWillUpdate(nextProps, nextState) {
if (
this.props.focusRipple &&
nextState.keyboardFocused &&
!this.state.keyboardFocused &&
!this.props.disableRipple
) {
this.ripple.pulsate();
}
}
componentWillUnmount() {
this.button = null;
clearTimeout(this.keyboardFocusTimeout);
}
onKeyboardFocusHandler = event => {
this.keyDown = false;
this.setState({ keyboardFocused: true });
if (this.props.onKeyboardFocus) {
this.props.onKeyboardFocus(event);
}
};
ripple = null;
keyDown = false; // Used to help track keyboard activation keyDown
button = null;
keyboardFocusTimeout = null;
keyboardFocusCheckTime = 30;
keyboardFocusMaxCheckTimes = 5;
handleKeyDown = event => {
const { component, focusRipple, onKeyDown, onClick } = this.props;
const key = keycode(event);
// Check if key is already down to avoid repeats being counted as multiple activations
if (focusRipple && !this.keyDown && this.state.keyboardFocused && key === 'space') {
this.keyDown = true;
event.persist();
this.ripple.stop(event, () => {
this.ripple.start(event);
});
}
if (onKeyDown) {
onKeyDown(event);
}
// Keyboard accessibility for non interactive elements
if (
event.target === this.button &&
onClick &&
component &&
component !== 'a' &&
component !== 'button' &&
(key === 'space' || key === 'enter')
) {
event.preventDefault();
onClick(event);
}
};
handleKeyUp = event => {
if (this.props.focusRipple && keycode(event) === 'space' && this.state.keyboardFocused) {
this.keyDown = false;
event.persist();
this.ripple.stop(event, () => this.ripple.pulsate(event));
}
if (this.props.onKeyUp) {
this.props.onKeyUp(event);
}
};
handleMouseDown = createRippleHandler(this, 'MouseDown', 'start', () => {
clearTimeout(this.keyboardFocusTimeout);
focusKeyPressed(false);
if (this.state.keyboardFocused) {
this.setState({ keyboardFocused: false });
}
});
handleMouseUp = createRippleHandler(this, 'MouseUp', 'stop');
handleMouseLeave = createRippleHandler(this, 'MouseLeave', 'stop', event => {
if (this.state.keyboardFocused) {
event.preventDefault();
}
});
handleTouchStart = createRippleHandler(this, 'TouchStart', 'start');
handleTouchEnd = createRippleHandler(this, 'TouchEnd', 'stop');
handleTouchMove = createRippleHandler(this, 'TouchEnd', 'stop');
handleBlur = createRippleHandler(this, 'Blur', 'stop', () => {
clearTimeout(this.keyboardFocusTimeout);
focusKeyPressed(false);
this.setState({ keyboardFocused: false });
});
handleFocus = event => {
if (this.props.disabled) {
return;
}
// Fix for https://github.com/facebook/react/issues/7769
if (!this.button) {
this.button = event.currentTarget;
}
event.persist();
const keyboardFocusCallback = this.onKeyboardFocusHandler.bind(this, event);
detectKeyboardFocus(this, this.button, keyboardFocusCallback);
if (this.props.onFocus) {
this.props.onFocus(event);
}
};
renderRipple() {
if (!this.props.disableRipple && !this.props.disabled) {
return (
<TouchRipple
innerRef={node => {
this.ripple = node;
}}
center={this.props.centerRipple}
/>
);
}
return null;
}
render() {
const {
centerRipple,
children,
classes,
className: classNameProp,
component,
disabled,
disableRipple,
focusRipple,
keyboardFocusedClassName,
onBlur,
onFocus,
onKeyboardFocus,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseLeave,
onMouseUp,
onTouchEnd,
onTouchMove,
onTouchStart,
rootRef,
tabIndex,
type,
...other
} = this.props;
const className = classNames(
classes.root,
{
[classes.disabled]: disabled,
[keyboardFocusedClassName || '']: this.state.keyboardFocused,
},
classNameProp,
);
const buttonProps = {};
let ComponentProp = component;
if (!ComponentProp) {
if (other.href) {
ComponentProp = 'a';
} else {
ComponentProp = 'button';
}
}
if (ComponentProp === 'button') {
buttonProps.type = type || 'button';
}
if (ComponentProp !== 'a') {
buttonProps.role = buttonProps.role || 'button';
buttonProps.disabled = disabled;
}
return (
<ComponentProp
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}
{...buttonProps}
{...other}
ref={rootRef}
>
{children}
{this.renderRipple()}
</ComponentProp>
);
}
}
export default withStyles(styles, { name: 'MuiButtonBase' })(ButtonBase);