Update Button component with iconBefore and iconAfter, clean up Icons component

This commit is contained in:
Cassie Tarakajian 2020-05-19 12:31:36 -04:00
parent f359dcec4a
commit 9d68de8dd2
7 changed files with 71 additions and 49 deletions

View file

@ -150,8 +150,10 @@ const StyledIconButton = styled.button`
* A Button performs an primary action
*/
const Button = ({
children, href, kind, 'aria-label': ariaLabel, to, type, ...props
children, href, kind, iconBefore, iconAfter, 'aria-label': ariaLabel, to, type, ...props
}) => {
const hasChildren = React.Children.count(children) > 0;
const content = <>{iconBefore}{hasChildren && <span>{children}</span>}{iconAfter}</>;
let StyledComponent = StyledButton;
if (kind === kinds.inline) {
@ -161,19 +163,31 @@ const Button = ({
}
if (href) {
return <StyledComponent kind={kind} as="a" aria-label={ariaLabel} href={href} {...props}>{children}</StyledComponent>;
return (
<StyledComponent
kind={kind}
as="a"
aria-label={ariaLabel}
href={href}
{...props}
>
{content}
</StyledComponent>
);
}
if (to) {
return <StyledComponent kind={kind} as={Link} aria-label={ariaLabel} to={to} {...props}>{children}</StyledComponent>;
return <StyledComponent kind={kind} as={Link} aria-label={ariaLabel} to={to} {...props}>{content}</StyledComponent>;
}
return <StyledComponent kind={kind} aria-label={ariaLabel} type={type} {...props}>{children}</StyledComponent>;
return <StyledComponent kind={kind} aria-label={ariaLabel} type={type} {...props}>{content}</StyledComponent>;
};
Button.defaultProps = {
'children': null,
'disabled': false,
'iconAfter': null,
'iconBefore': null,
'kind': kinds.block,
'href': null,
'aria-label': null,
@ -193,6 +207,14 @@ Button.propTypes = {
If the button can be activated or not
*/
'disabled': PropTypes.bool,
/**
* SVG icon to place after child content
*/
'iconAfter': PropTypes.element,
/**
* SVG icon to place before child content
*/
'iconBefore': PropTypes.element,
/**
* The kind of button - determines how it appears visually
*/

View file

@ -3,9 +3,7 @@ import { action } from '@storybook/addon-actions';
import { boolean, text } from '@storybook/addon-knobs';
import Button from './Button';
import Icons from './Icons';
const { Github, DropdownArrow, Plus } = Icons;
import { GithubIcon, DropdownArrowIcon, PlusIcon } from './Icons';
export default {
title: 'Common/Button',
@ -39,28 +37,34 @@ export const ReactRouterLink = () => (
);
export const ButtonWithIconBefore = () => (
<Button>
<Github aria-label="Github logo" />
<span>Create</span>
<Button
iconBefore={<GithubIcon aria-label="Github logo" />}
>
Create
</Button>
);
export const ButtonWithIconAfter = () => (
<Button>
<span>Create</span>
<Github aria-label="Github logo" />
<Button
iconAfter={<GithubIcon aria-label="Github logo" />}
>
Create
</Button>
);
export const InlineButtonWithIconAfter = () => (
<Button kind={Button.kinds.inline}>
<span>File name</span>
<DropdownArrow />
<Button
iconAfter={<DropdownArrowIcon />}
kind={Button.kinds.inline}
>
File name
</Button>
);
export const InlineIconOnlyButton = () => (
<Button kind={Button.kinds.inline} aria-label="Add to collection">
<Plus />
</Button>
<Button
aria-label="Add to collection"
iconBefore={<PlusIcon />}
kind={Button.kinds.inline}
/>
);

View file

@ -13,43 +13,39 @@ import DropdownArrow from '../images/down-filled-triangle.svg';
// could also give these a default size, color, etc. based on the theme
// Need to add size to these - like small icon, medium icon, large icon. etc.
function withLabel(Icon) {
const render = (props) => {
function withLabel(SvgComponent) {
const Icon = (props) => {
const { 'aria-label': ariaLabel } = props;
if (ariaLabel) {
return (<Icon
return (<SvgComponent
{...props}
aria-label={ariaLabel}
role="img"
focusable="false"
/>);
}
return (<Icon
return (<SvgComponent
{...props}
aria-hidden
focusable="false"
/>);
};
render.propTypes = {
Icon.propTypes = {
'aria-label': PropTypes.string
};
render.defaultProps = {
Icon.defaultProps = {
'aria-label': null
};
return render;
return Icon;
}
const Icons = {
SortArrowUp: withLabel(SortArrowUp),
SortArrowDown: withLabel(SortArrowDown),
Github: withLabel(Github),
Google: withLabel(Google),
Plus: withLabel(Plus),
Close: withLabel(Close),
DropdownArrow: withLabel(DropdownArrow)
};
export default Icons;
export const SortArrowUpIcon = withLabel(SortArrowUp);
export const SortArrowDownIcon = withLabel(SortArrowDown);
export const GithubIcon = withLabel(Github);
export const GoogleIcon = withLabel(Google);
export const PlusIcon = withLabel(Plus);
export const CloseIcon = withLabel(Close);
export const DropdownArrowIcon = withLabel(DropdownArrow);

View file

@ -1,7 +1,7 @@
import React from 'react';
import { select } from '@storybook/addon-knobs';
import Icons from './Icons';
import * as Icons from './Icons';
export default {
title: 'Common/Icons',

View file

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import Button from '../../../common/Button';
import Icons from '../../../common/Icons';
import { PlusIcon } from '../../../common/Icons';
import CopyableInput from '../../IDE/components/CopyableInput';
import APIKeyList from './APIKeyList';
@ -82,11 +82,11 @@ class APIKeyForm extends React.Component {
/>
<Button
disabled={this.state.keyLabel === ''}
type="submit"
iconBefore={<PlusIcon />}
label="Create new key"
type="submit"
>
<Icons.Plus />
<span>Create</span>
Create
</Button>
</form>

View file

@ -8,7 +8,7 @@ import { bindActionCreators } from 'redux';
import classNames from 'classnames';
import Button from '../../../common/Button';
import Icons from '../../../common/Icons';
import { DropdownArrowIcon } from '../../../common/Icons';
import * as ProjectActions from '../../IDE/actions/project';
import * as ProjectsActions from '../../IDE/actions/projects';
import * as CollectionsActions from '../../IDE/actions/collections';
@ -54,9 +54,9 @@ const ShareURL = ({ value }) => {
<div className="collection-share" ref={node}>
<Button
onClick={() => setShowURL(!showURL)}
iconAfter={<DropdownArrowIcon />}
>
Share
<Icons.DropdownArrow />
</Button>
{ showURL &&
<div className="collection__share-dropdown">

View file

@ -4,7 +4,7 @@ import styled from 'styled-components';
import { remSize } from '../../../theme';
import Icons from '../../../common/Icons';
import { GithubIcon, GoogleIcon } from '../../../common/Icons';
import Button from '../../../common/Button';
const authUrls = {
@ -18,8 +18,8 @@ const labels = {
};
const icons = {
github: Icons.Github,
google: Icons.Google
github: GithubIcon,
google: GoogleIcon
};
const services = {
@ -35,10 +35,10 @@ function SocialAuthButton({ service }) {
const ServiceIcon = icons[service];
return (
<StyledButton
iconBefore={<ServiceIcon aria-label={`${service} logo`} />}
href={authUrls[service]}
>
<ServiceIcon aria-label={`${service} logo`} />
<span>{labels[service]}</span>
{labels[service]}
</StyledButton>
);
}