Inline button style (with/without icons)

This commit is contained in:
Andrew Nicolaou 2020-04-27 10:12:34 +02:00
parent 7cf3a0bea0
commit a2145ad979
2 changed files with 104 additions and 9 deletions

View File

@ -6,6 +6,12 @@ import { Link } from 'react-router';
import { remSize, prop } from '../theme';
import Icon, { ValidIconNameType } from './Icon';
const kinds = {
block: 'block',
icon: 'icon',
inline: 'inline',
};
// The '&&&' will increase the specificity of the
// component's CSS so that it overrides the more
// general global styles
@ -41,8 +47,74 @@ const StyledButton = styled.button`
cursor: not-allowed;
}
> *:not(:last-child) {
margin-right: ${remSize(8)};
> * + * {
margin-left: ${remSize(8)};
}
}
`;
const StyledInlineButton = styled.button`
&&& {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: ${prop('primaryTextColor')};
cursor: pointer;
border: none;
line-height: 1;
svg * {
fill: ${prop('primaryTextColor')};
}
&:disabled {
cursor: not-allowed;
}
> * + * {
margin-left: ${remSize(8)};
}
}
`;
const StyledIconButton = styled.button`
&&& {
display: flex;
justify-content: center;
align-items: center;
width: ${remSize(32)}px;
height: ${remSize(32)}px;
text-decoration: none;
background-color: ${prop('buttonColorBackground')};
color: ${prop('buttonColor')};
cursor: pointer;
border: 1px solid transparen;
border-radius: 50%;
padding: ${remSize(8)} ${remSize(25)};
line-height: 1;
&:hover:not(:disabled) {
color: ${prop('buttonHoverColor')};
background-color: ${prop('buttonHoverColorBackground')};
svg * {
fill: ${prop('buttonHoverColor')};
}
}
&:disabled {
color: ${prop('buttonDisabledColor')};
background-color: ${prop('buttonDisabledColorBackground')};
cursor: not-allowed;
}
> * + * {
margin-left: ${remSize(8)};
}
}
`;
@ -51,28 +123,39 @@ const StyledButton = styled.button`
* A Button performs an primary action
*/
const Button = ({
children, href, iconAfterName, iconBeforeName, label, to, type, ...props
children, href, iconAfterName, iconBeforeName, kind, label, to, type, ...props
}) => {
const iconAfter = iconAfterName && <Icon name={iconAfterName} />;
const iconBefore = iconBeforeName && <Icon name={iconBeforeName} />;
const hasChildren = React.Children.count(children) > 0;
const content = <>{iconBefore}<span>{children}</span>{iconAfter}</>;
const content = <>{iconBefore}{hasChildren && <span>{children}</span>}{iconAfter}</>;
let StyledComponent = StyledButton;
if (kind === kinds.inline) {
StyledComponent = StyledInlineButton;
} else if (kind === kinds.icon) {
StyledComponent = StyledIconButton;
}
if (href) {
return <StyledButton as="a" aria-label={label} href={href} {...props}>{content}</StyledButton>;
return <StyledComponent kind={kind} as="a" aria-label={label} href={href} {...props}>{content}</StyledComponent>;
}
if (to) {
return <StyledButton as={Link} aria-label={label} to={to} {...props}>{content}</StyledButton>;
return <StyledComponent kind={kind} as={Link} aria-label={label} to={to} {...props}>{content}</StyledComponent>;
}
return <StyledButton aria-label={label} type={type} {...props}>{content}</StyledButton>;
return <StyledComponent kind={kind} aria-label={label} type={type} {...props}>{content}</StyledComponent>;
};
Button.defaultProps = {
children: null,
disabled: false,
iconAfterName: null,
iconBeforeName: null,
kind: kinds.block,
href: null,
label: null,
to: null,
@ -80,13 +163,14 @@ Button.defaultProps = {
};
Button.iconNames = Icon.names;
Button.kinds = kinds;
Button.propTypes = {
/**
* The visible part of the button, telling the user what
* the action is
*/
children: PropTypes.element.isRequired,
children: PropTypes.element,
/**
If the button can be activated or not
*/
@ -95,11 +179,14 @@ Button.propTypes = {
* Name of icon to place before child content
*/
iconAfterName: ValidIconNameType,
/**
* Name of icon to place after child content
*/
iconBeforeName: ValidIconNameType,
/**
* The kind of button - determines how it appears visually
*/
kind: PropTypes.oneOf(Object.values(kinds)),
/**
* Specifying an href will use an <a> to link to the URL
*/

View File

@ -42,3 +42,11 @@ export const ButtonWithIconBefore = () => (
export const ButtonWithIconAfter = () => (
<Button iconAfterName={Button.iconNames.github}>Create</Button>
);
export const InlineButtonWithIconAfter = () => (
<Button kind={Button.kinds.inline} iconAfterName={Button.iconNames.sortArrowDown}>File name</Button>
);
export const InlineIconOnlyButton = () => (
<Button kind={Button.kinds.inline} iconAfterName={Button.iconNames.plus} label="Add to collection" />
);