Button components
Summary: _typescript_ Reviewed By: passy, bnelo12 Differential Revision: D16830539 fbshipit-source-id: a44ad0914b2581648b06e421476e0ba31ae96992
This commit is contained in:
committed by
Facebook Github Bot
parent
eaceddbb32
commit
5cb12c3b1f
@@ -5,15 +5,16 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import Glyph from './Glyph.tsx';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import electron from 'electron';
|
||||
import styled from '../styled/index.js';
|
||||
import {colors} from './colors.tsx';
|
||||
import electron, {MenuItemConstructorOptions} from 'electron';
|
||||
import styled from 'react-emotion';
|
||||
import {colors} from './colors';
|
||||
import {connect} from 'react-redux';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {keyframes} from 'react-emotion';
|
||||
import {State as Store} from '../../reducers/index';
|
||||
import Glyph, {IconSize} from './Glyph';
|
||||
|
||||
const borderColor = props => {
|
||||
if (!props.windowIsFocused) {
|
||||
@@ -84,7 +85,16 @@ const pulse = keyframes({
|
||||
},
|
||||
});
|
||||
|
||||
const StyledButton = styled('div')(props => ({
|
||||
const StyledButton = styled('div')(
|
||||
(props: {
|
||||
windowIsFocused?: boolean;
|
||||
compact?: boolean;
|
||||
inButtonGroup?: boolean;
|
||||
padded?: boolean;
|
||||
pulse?: boolean;
|
||||
disabled?: boolean;
|
||||
dropdown?: Array<MenuItemConstructorOptions>;
|
||||
}) => ({
|
||||
backgroundColor: !props.windowIsFocused
|
||||
? colors.macOSTitleBarButtonBackgroundBlur
|
||||
: colors.white,
|
||||
@@ -110,7 +120,8 @@ const StyledButton = styled('div')(props => ({
|
||||
props.pulse && props.windowIsFocused
|
||||
? `0 0 0 ${colors.macOSTitleBarIconSelected}`
|
||||
: '',
|
||||
animation: props.pulse && props.windowIsFocused ? `${pulse} 1s infinite` : '',
|
||||
animation:
|
||||
props.pulse && props.windowIsFocused ? `${pulse} 1s infinite` : '',
|
||||
|
||||
'&:not(:first-child)': {
|
||||
borderTopLeftRadius: props.inButtonGroup === true ? 0 : 4,
|
||||
@@ -156,91 +167,92 @@ const StyledButton = styled('div')(props => ({
|
||||
colors.macOSTitleBarIcon
|
||||
} transparent transparent transparent`,
|
||||
},
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
||||
const Icon = styled(Glyph)(({hasText}) => ({
|
||||
const Icon = styled(Glyph)(({hasText}: {hasText: boolean}) => ({
|
||||
marginRight: hasText ? 3 : 0,
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
type OwnProps = {
|
||||
/**
|
||||
* onMouseUp handler.
|
||||
*/
|
||||
onMouseDown?: (event: SyntheticMouseEvent<>) => any,
|
||||
onMouseDown?: (event: React.MouseEvent) => any;
|
||||
/**
|
||||
* onClick handler.
|
||||
*/
|
||||
onClick?: (event: SyntheticMouseEvent<>) => any,
|
||||
onClick?: (event: React.MouseEvent) => any;
|
||||
/**
|
||||
* Whether this button is disabled.
|
||||
*/
|
||||
disabled?: boolean,
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* Whether this button is large. Increases padding and line-height.
|
||||
*/
|
||||
large?: boolean,
|
||||
large?: boolean;
|
||||
/**
|
||||
* Whether this button is compact. Decreases padding and line-height.
|
||||
*/
|
||||
compact?: boolean,
|
||||
compact?: boolean;
|
||||
/**
|
||||
* Type of button.
|
||||
*/
|
||||
type?: 'primary' | 'success' | 'warning' | 'danger',
|
||||
type?: 'primary' | 'success' | 'warning' | 'danger';
|
||||
/**
|
||||
* Children.
|
||||
*/
|
||||
children?: React$Node,
|
||||
children?: React.ReactNode;
|
||||
/**
|
||||
* Dropdown menu template shown on click.
|
||||
*/
|
||||
dropdown?: Array<MenuItemConstructorOptions>,
|
||||
dropdown?: Array<MenuItemConstructorOptions>;
|
||||
/**
|
||||
* Name of the icon dispalyed next to the text
|
||||
*/
|
||||
icon?: string,
|
||||
icon?: string;
|
||||
/**
|
||||
* Size of the icon in pixels.
|
||||
*/
|
||||
iconSize?: number,
|
||||
iconSize?: IconSize;
|
||||
/**
|
||||
* For toggle buttons, if the button is selected
|
||||
*/
|
||||
selected?: boolean,
|
||||
selected?: boolean;
|
||||
/**
|
||||
* Button is pulsing
|
||||
*/
|
||||
pulse?: boolean,
|
||||
pulse?: boolean;
|
||||
/**
|
||||
* URL to open in the browser on click
|
||||
*/
|
||||
href?: string,
|
||||
href?: string;
|
||||
/**
|
||||
* Whether the button should render depressed into its socket
|
||||
*/
|
||||
depressed?: boolean,
|
||||
depressed?: boolean;
|
||||
/**
|
||||
* Style of the icon. `filled` is the default
|
||||
*/
|
||||
iconVariant?: 'filled' | 'outline',
|
||||
iconVariant?: 'filled' | 'outline';
|
||||
/**
|
||||
* Whether the button should have additional padding left and right.
|
||||
*/
|
||||
padded?: boolean,
|
||||
padded?: boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
active: boolean,
|
||||
wasClosed: boolean,
|
||||
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 & {windowIsFocused: boolean},
|
||||
State,
|
||||
> {
|
||||
class Button extends React.Component<Props, State> {
|
||||
static contextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
@@ -250,9 +262,9 @@ class Button extends React.Component<
|
||||
wasClosed: false,
|
||||
};
|
||||
|
||||
_ref = React.createRef();
|
||||
_ref = React.createRef<React.Component<typeof StyledButton>>();
|
||||
|
||||
onMouseDown = (e: SyntheticMouseEvent<>) => {
|
||||
onMouseDown = (e: React.MouseEvent) => {
|
||||
this.setState({active: true, wasClosed: false});
|
||||
if (this.props.onMouseDown != null) {
|
||||
this.props.onMouseDown(e);
|
||||
@@ -264,18 +276,22 @@ class Button extends React.Component<
|
||||
}
|
||||
if (this.props.dropdown && !this.state.wasClosed) {
|
||||
const menu = electron.remote.Menu.buildFromTemplate(this.props.dropdown);
|
||||
const position = {};
|
||||
const position: {
|
||||
x?: number;
|
||||
y?: number;
|
||||
} = {};
|
||||
const {current} = this._ref;
|
||||
if (current) {
|
||||
const node = findDOMNode(current);
|
||||
if (node instanceof Element) {
|
||||
const {left, bottom} = node.getBoundingClientRect();
|
||||
position.x = parseInt(left, 10);
|
||||
position.y = parseInt(bottom + 6, 10);
|
||||
position.x = left;
|
||||
position.y = bottom + 6;
|
||||
}
|
||||
}
|
||||
menu.popup({
|
||||
window: electron.remote.getCurrentWindow(),
|
||||
// @ts-ignore: async is private API in electron
|
||||
async: true,
|
||||
...position,
|
||||
callback: () => {
|
||||
@@ -286,7 +302,7 @@ class Button extends React.Component<
|
||||
this.setState({active: false, wasClosed: false});
|
||||
};
|
||||
|
||||
onClick = (e: SyntheticMouseEvent<>) => {
|
||||
onClick = (e: React.MouseEvent) => {
|
||||
if (this.props.disabled === true) {
|
||||
return;
|
||||
}
|
||||
@@ -341,7 +357,7 @@ class Button extends React.Component<
|
||||
return (
|
||||
<StyledButton
|
||||
{...props}
|
||||
ref={this._ref}
|
||||
ref={this._ref as any}
|
||||
windowIsFocused={windowIsFocused}
|
||||
onClick={this.onClick}
|
||||
onMouseDown={this.onMouseDown}
|
||||
@@ -354,9 +370,8 @@ class Button extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
const ConnectedButton = connect(({application: {windowIsFocused}}) => ({
|
||||
export default connect<StateFromProps, {}, OwnProps, Store>(
|
||||
({application: {windowIsFocused}}) => ({
|
||||
windowIsFocused,
|
||||
}))(Button);
|
||||
|
||||
// $FlowFixMe
|
||||
export default (ConnectedButton: StyledComponent<Props>);
|
||||
}),
|
||||
)(Button);
|
||||
@@ -5,9 +5,8 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import styled from '../styled/index.js';
|
||||
import {Component} from 'react';
|
||||
|
||||
import styled from 'react-emotion';
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const ButtonGroupContainer = styled('div')({
|
||||
@@ -30,8 +29,12 @@ const ButtonGroupContainer = styled('div')({
|
||||
* ```
|
||||
*/
|
||||
export default class ButtonGroup extends Component<{
|
||||
children: React$Node,
|
||||
children: React.ReactNode;
|
||||
}> {
|
||||
static childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {inButtonGroup: true};
|
||||
}
|
||||
@@ -40,7 +43,3 @@ export default class ButtonGroup extends Component<{
|
||||
return <ButtonGroupContainer>{this.props.children}</ButtonGroupContainer>;
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup.childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
@@ -6,9 +6,8 @@
|
||||
*/
|
||||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import styled from '../styled/index.js';
|
||||
import Glyph from './Glyph.tsx';
|
||||
import styled from 'react-emotion';
|
||||
import Glyph from './Glyph';
|
||||
|
||||
const IconContainer = styled('div')({
|
||||
width: 0,
|
||||
@@ -18,7 +17,8 @@ const IconContainer = styled('div')({
|
||||
pointerEvents: 'none',
|
||||
});
|
||||
|
||||
const ButtonGroupChainContainer = styled('div')(props => ({
|
||||
const ButtonGroupChainContainer = styled('div')(
|
||||
(props: {iconSize: number}) => ({
|
||||
display: 'inline-flex',
|
||||
marginLeft: 10,
|
||||
'&:first-child>*:not(:first-child):nth-child(odd)': {
|
||||
@@ -34,21 +34,22 @@ const ButtonGroupChainContainer = styled('div')(props => ({
|
||||
'&:first-child>:last-child': {
|
||||
borderRightStyle: 'solid',
|
||||
},
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
* Children.
|
||||
*/
|
||||
children: React$Node,
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Size of the button seperator icon in pixels.
|
||||
*/
|
||||
iconSize: 8 | 10 | 12 | 16 | 18 | 20 | 24 | 32,
|
||||
iconSize: 8 | 10 | 12 | 16 | 18 | 20 | 24 | 32;
|
||||
/**
|
||||
* Name of the icon seperating the buttons. Defaults to 'chevron-right'.
|
||||
*/
|
||||
icon?: string,
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -65,6 +66,10 @@ type Props = {
|
||||
* ```
|
||||
*/
|
||||
export default class ButtonGroupChain extends Component<Props> {
|
||||
static childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {inButtonGroup: true};
|
||||
}
|
||||
@@ -91,7 +96,3 @@ export default class ButtonGroupChain extends Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroupChain.childContextTypes = {
|
||||
inButtonGroup: PropTypes.bool,
|
||||
};
|
||||
@@ -5,22 +5,23 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import ButtonGroup from './ButtonGroup.js';
|
||||
import Button from './Button.js';
|
||||
import ButtonGroup from './ButtonGroup';
|
||||
import Button from './Button';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Button group to navigate back and forth.
|
||||
*/
|
||||
export default function ButtonNavigationGroup(props: {|
|
||||
export default function ButtonNavigationGroup(props: {
|
||||
/** Back button is enabled */
|
||||
canGoBack: boolean,
|
||||
canGoBack: boolean;
|
||||
/** Forwards button is enabled */
|
||||
canGoForward: boolean,
|
||||
canGoForward: boolean;
|
||||
/** Callback when back button is clicked */
|
||||
onBack: () => void,
|
||||
onBack: () => void;
|
||||
/** Callback when forwards button is clicked */
|
||||
onForward: () => void,
|
||||
|}) {
|
||||
onForward: () => void;
|
||||
}) {
|
||||
return (
|
||||
<ButtonGroup>
|
||||
<Button disabled={!props.canGoBack} onClick={props.onBack}>
|
||||
@@ -6,13 +6,13 @@
|
||||
*/
|
||||
|
||||
export {default as styled} from 'react-emotion';
|
||||
export {default as Button} from './components/Button.js';
|
||||
export {default as Button} from './components/Button.tsx';
|
||||
export {default as ToggleButton} from './components/ToggleSwitch.tsx';
|
||||
export {
|
||||
default as ButtonNavigationGroup,
|
||||
} from './components/ButtonNavigationGroup.js';
|
||||
export {default as ButtonGroup} from './components/ButtonGroup.js';
|
||||
export {default as ButtonGroupChain} from './components/ButtonGroupChain.js';
|
||||
} from './components/ButtonNavigationGroup.tsx';
|
||||
export {default as ButtonGroup} from './components/ButtonGroup.tsx';
|
||||
export {default as ButtonGroupChain} from './components/ButtonGroupChain.tsx';
|
||||
|
||||
//
|
||||
export {colors, darkColors, brandColors} from './components/colors.tsx';
|
||||
|
||||
Reference in New Issue
Block a user