convert buttons to React hooks
Summary: Converted Buttons to hooks, to make it easier to use context in the future. No further changes. Reviewed By: cekkaewnumchai Differential Revision: D23812921 fbshipit-source-id: 3739ad49e734dbe4d903a23d58da7cc267f6e109
This commit is contained in:
committed by
Facebook GitHub Bot
parent
fdd2151532
commit
b256bc68fa
@@ -7,16 +7,15 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {useContext, useState, useRef, useCallback} from 'react';
|
||||
import electron, {MenuItemConstructorOptions} from 'electron';
|
||||
import styled from '@emotion/styled';
|
||||
import {colors} from './colors';
|
||||
import {connect} from 'react-redux';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {keyframes} from 'emotion';
|
||||
import {State as Store} from '../../reducers/index';
|
||||
import Glyph, {IconSize} from './Glyph';
|
||||
import {ButtonGroupContext} from './ButtonGroup';
|
||||
import {useStore} from '../../utils/useStore';
|
||||
|
||||
type ButtonType = 'primary' | 'success' | 'warning' | 'danger';
|
||||
|
||||
@@ -190,7 +189,7 @@ const Icon = styled(Glyph)<{hasText: boolean}>(({hasText}) => ({
|
||||
}));
|
||||
Icon.displayName = 'Button:Icon';
|
||||
|
||||
type OwnProps = {
|
||||
type Props = {
|
||||
/**
|
||||
* onMouseUp handler.
|
||||
*/
|
||||
@@ -257,46 +256,39 @@ type OwnProps = {
|
||||
padded?: boolean;
|
||||
} & React.HTMLProps<HTMLDivElement>;
|
||||
|
||||
type State = {
|
||||
active: boolean;
|
||||
wasClosed: boolean;
|
||||
};
|
||||
|
||||
type StateFromProps = {windowIsFocused: boolean};
|
||||
type Props = OwnProps & StateFromProps;
|
||||
|
||||
/**
|
||||
* A simple button, used in many parts of the application.
|
||||
*/
|
||||
class Button extends React.Component<Props, State> {
|
||||
static contextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
export default function Button(props: Props) {
|
||||
const windowIsFocused = useStore(
|
||||
(state) => state.application.windowIsFocused,
|
||||
);
|
||||
const inButtonGroup = useContext(ButtonGroupContext);
|
||||
const [active, setActive] = useState(false);
|
||||
const [wasClosed, setWasClosed] = useState(false);
|
||||
|
||||
state = {
|
||||
active: false,
|
||||
wasClosed: false,
|
||||
};
|
||||
const _ref = useRef<React.Component<typeof StyledButton>>();
|
||||
|
||||
_ref = React.createRef<React.Component<typeof StyledButton>>();
|
||||
const onMouseDown = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
setActive(true);
|
||||
setWasClosed(false);
|
||||
props.onMouseDown?.(e);
|
||||
},
|
||||
[props.onMouseDown],
|
||||
);
|
||||
|
||||
onMouseDown = (e: React.MouseEvent) => {
|
||||
this.setState({active: true, wasClosed: false});
|
||||
if (this.props.onMouseDown != null) {
|
||||
this.props.onMouseDown(e);
|
||||
}
|
||||
};
|
||||
onMouseUp = () => {
|
||||
if (this.props.disabled === true) {
|
||||
const onMouseUp = useCallback(() => {
|
||||
if (props.disabled === true) {
|
||||
return;
|
||||
}
|
||||
if (this.props.dropdown && !this.state.wasClosed) {
|
||||
const menu = electron.remote.Menu.buildFromTemplate(this.props.dropdown);
|
||||
if (props.dropdown && !wasClosed) {
|
||||
const menu = electron.remote.Menu.buildFromTemplate(props.dropdown);
|
||||
const position: {
|
||||
x?: number;
|
||||
y?: number;
|
||||
} = {};
|
||||
const {current} = this._ref;
|
||||
const {current} = _ref;
|
||||
if (current) {
|
||||
const node = findDOMNode(current);
|
||||
if (node instanceof Element) {
|
||||
@@ -311,36 +303,28 @@ class Button extends React.Component<Props, State> {
|
||||
async: true,
|
||||
...position,
|
||||
callback: () => {
|
||||
this.setState({wasClosed: true});
|
||||
setWasClosed(true);
|
||||
},
|
||||
});
|
||||
}
|
||||
this.setState({active: false, wasClosed: false});
|
||||
};
|
||||
setActive(false);
|
||||
setWasClosed(false);
|
||||
}, [props.disabled, props.dropdown, wasClosed]);
|
||||
|
||||
onClick = (e: React.MouseEvent) => {
|
||||
if (this.props.disabled === true) {
|
||||
const onClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
if (props.disabled === true) {
|
||||
return;
|
||||
}
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick(e);
|
||||
props.onClick?.(e);
|
||||
if (props.href != null) {
|
||||
electron.shell.openExternal(props.href);
|
||||
}
|
||||
if (this.props.href != null) {
|
||||
electron.shell.openExternal(this.props.href);
|
||||
}
|
||||
};
|
||||
},
|
||||
[props.disabled, props.onClick, props.href],
|
||||
);
|
||||
|
||||
render() {
|
||||
const {
|
||||
icon,
|
||||
children,
|
||||
selected,
|
||||
iconSize,
|
||||
windowIsFocused,
|
||||
iconVariant,
|
||||
...props
|
||||
} = this.props;
|
||||
const {active} = this.state;
|
||||
const {icon, children, selected, iconSize, iconVariant, ...restProps} = props;
|
||||
|
||||
let color = colors.macOSTitleBarIcon;
|
||||
if (props.disabled === true) {
|
||||
@@ -362,7 +346,7 @@ class Button extends React.Component<Props, State> {
|
||||
iconComponent = (
|
||||
<Icon
|
||||
name={icon}
|
||||
size={iconSize || (this.props.compact === true ? 12 : 16)}
|
||||
size={iconSize || (props.compact === true ? 12 : 16)}
|
||||
color={color}
|
||||
variant={iconVariant || 'filled'}
|
||||
hasText={Boolean(children)}
|
||||
@@ -372,22 +356,15 @@ class Button extends React.Component<Props, State> {
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
{...props}
|
||||
ref={this._ref as any}
|
||||
{...restProps}
|
||||
ref={_ref as any}
|
||||
windowIsFocused={windowIsFocused}
|
||||
onClick={this.onClick}
|
||||
onMouseDown={this.onMouseDown}
|
||||
onMouseUp={this.onMouseUp}
|
||||
inButtonGroup={this.context.inButtonGroup}>
|
||||
onClick={onClick}
|
||||
onMouseDown={onMouseDown}
|
||||
onMouseUp={onMouseUp}
|
||||
inButtonGroup={inButtonGroup}>
|
||||
{iconComponent}
|
||||
{children}
|
||||
</StyledButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect<StateFromProps, {}, OwnProps, Store>(
|
||||
({application: {windowIsFocused}}) => ({
|
||||
windowIsFocused,
|
||||
}),
|
||||
)(Button);
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
*/
|
||||
|
||||
import styled from '@emotion/styled';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {createContext} from 'react';
|
||||
|
||||
const ButtonGroupContainer = styled.div({
|
||||
display: 'inline-flex',
|
||||
@@ -20,6 +19,8 @@ const ButtonGroupContainer = styled.div({
|
||||
});
|
||||
ButtonGroupContainer.displayName = 'ButtonGroup:ButtonGroupContainer';
|
||||
|
||||
export const ButtonGroupContext = createContext(false);
|
||||
|
||||
/**
|
||||
* Group a series of buttons together.
|
||||
*
|
||||
@@ -31,18 +32,10 @@ ButtonGroupContainer.displayName = 'ButtonGroup:ButtonGroupContainer';
|
||||
* </ButtonGroup>
|
||||
* ```
|
||||
*/
|
||||
export default class ButtonGroup extends Component<{
|
||||
children: React.ReactNode;
|
||||
}> {
|
||||
static childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {inButtonGroup: true};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <ButtonGroupContainer>{this.props.children}</ButtonGroupContainer>;
|
||||
}
|
||||
export default function ButtonGroup({children}: {children: React.ReactNode}) {
|
||||
return (
|
||||
<ButtonGroupContext.Provider value={true}>
|
||||
<ButtonGroupContainer>{children}</ButtonGroupContainer>
|
||||
</ButtonGroupContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import Glyph from './Glyph';
|
||||
import {ButtonGroupContext} from './ButtonGroup';
|
||||
|
||||
const IconContainer = styled.div({
|
||||
width: 0,
|
||||
@@ -68,19 +68,9 @@ type Props = {
|
||||
* </ButtonGroupChain>
|
||||
* ```
|
||||
*/
|
||||
export default class ButtonGroupChain extends Component<Props> {
|
||||
static childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {inButtonGroup: true};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {children, iconSize, icon} = this.props;
|
||||
|
||||
export default function ButtonGroupChain({children, iconSize, icon}: Props) {
|
||||
return (
|
||||
<ButtonGroupContext.Provider value={true}>
|
||||
<ButtonGroupChainContainer iconSize={iconSize}>
|
||||
{React.Children.map(children, (child, idx) => {
|
||||
if (idx === 0) {
|
||||
@@ -96,6 +86,6 @@ export default class ButtonGroupChain extends Component<Props> {
|
||||
);
|
||||
})}
|
||||
</ButtonGroupChainContainer>
|
||||
</ButtonGroupContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user