Skip to content

Commit a2145ad

Browse files
committed
Inline button style (with/without icons)
1 parent 7cf3a0b commit a2145ad

File tree

2 files changed

+104
-9
lines changed

2 files changed

+104
-9
lines changed

Diff for: client/common/Button.jsx

+96-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import { Link } from 'react-router';
66
import { remSize, prop } from '../theme';
77
import Icon, { ValidIconNameType } from './Icon';
88

9+
const kinds = {
10+
block: 'block',
11+
icon: 'icon',
12+
inline: 'inline',
13+
};
14+
915
// The '&&&' will increase the specificity of the
1016
// component's CSS so that it overrides the more
1117
// general global styles
@@ -41,8 +47,74 @@ const StyledButton = styled.button`
4147
cursor: not-allowed;
4248
}
4349
44-
> *:not(:last-child) {
45-
margin-right: ${remSize(8)};
50+
> * + * {
51+
margin-left: ${remSize(8)};
52+
}
53+
}
54+
`;
55+
56+
const StyledInlineButton = styled.button`
57+
&&& {
58+
display: flex;
59+
justify-content: center;
60+
align-items: center;
61+
62+
text-decoration: none;
63+
64+
color: ${prop('primaryTextColor')};
65+
cursor: pointer;
66+
border: none;
67+
line-height: 1;
68+
69+
svg * {
70+
fill: ${prop('primaryTextColor')};
71+
}
72+
73+
&:disabled {
74+
cursor: not-allowed;
75+
}
76+
77+
> * + * {
78+
margin-left: ${remSize(8)};
79+
}
80+
}
81+
`;
82+
83+
const StyledIconButton = styled.button`
84+
&&& {
85+
display: flex;
86+
justify-content: center;
87+
align-items: center;
88+
89+
width: ${remSize(32)}px;
90+
height: ${remSize(32)}px;
91+
text-decoration: none;
92+
93+
background-color: ${prop('buttonColorBackground')};
94+
color: ${prop('buttonColor')};
95+
cursor: pointer;
96+
border: 1px solid transparen;
97+
border-radius: 50%;
98+
padding: ${remSize(8)} ${remSize(25)};
99+
line-height: 1;
100+
101+
&:hover:not(:disabled) {
102+
color: ${prop('buttonHoverColor')};
103+
background-color: ${prop('buttonHoverColorBackground')};
104+
105+
svg * {
106+
fill: ${prop('buttonHoverColor')};
107+
}
108+
}
109+
110+
&:disabled {
111+
color: ${prop('buttonDisabledColor')};
112+
background-color: ${prop('buttonDisabledColorBackground')};
113+
cursor: not-allowed;
114+
}
115+
116+
> * + * {
117+
margin-left: ${remSize(8)};
46118
}
47119
}
48120
`;
@@ -51,42 +123,54 @@ const StyledButton = styled.button`
51123
* A Button performs an primary action
52124
*/
53125
const Button = ({
54-
children, href, iconAfterName, iconBeforeName, label, to, type, ...props
126+
children, href, iconAfterName, iconBeforeName, kind, label, to, type, ...props
55127
}) => {
56128
const iconAfter = iconAfterName && <Icon name={iconAfterName} />;
57129
const iconBefore = iconBeforeName && <Icon name={iconBeforeName} />;
130+
const hasChildren = React.Children.count(children) > 0;
131+
132+
const content = <>{iconBefore}{hasChildren && <span>{children}</span>}{iconAfter}</>;
58133

59-
const content = <>{iconBefore}<span>{children}</span>{iconAfter}</>;
134+
let StyledComponent = StyledButton;
135+
136+
if (kind === kinds.inline) {
137+
StyledComponent = StyledInlineButton;
138+
} else if (kind === kinds.icon) {
139+
StyledComponent = StyledIconButton;
140+
}
60141

61142
if (href) {
62-
return <StyledButton as="a" aria-label={label} href={href} {...props}>{content}</StyledButton>;
143+
return <StyledComponent kind={kind} as="a" aria-label={label} href={href} {...props}>{content}</StyledComponent>;
63144
}
64145

65146
if (to) {
66-
return <StyledButton as={Link} aria-label={label} to={to} {...props}>{content}</StyledButton>;
147+
return <StyledComponent kind={kind} as={Link} aria-label={label} to={to} {...props}>{content}</StyledComponent>;
67148
}
68149

69-
return <StyledButton aria-label={label} type={type} {...props}>{content}</StyledButton>;
150+
return <StyledComponent kind={kind} aria-label={label} type={type} {...props}>{content}</StyledComponent>;
70151
};
71152

72153
Button.defaultProps = {
154+
children: null,
73155
disabled: false,
74156
iconAfterName: null,
75157
iconBeforeName: null,
158+
kind: kinds.block,
76159
href: null,
77160
label: null,
78161
to: null,
79162
type: 'button',
80163
};
81164

82165
Button.iconNames = Icon.names;
166+
Button.kinds = kinds;
83167

84168
Button.propTypes = {
85169
/**
86170
* The visible part of the button, telling the user what
87171
* the action is
88172
*/
89-
children: PropTypes.element.isRequired,
173+
children: PropTypes.element,
90174
/**
91175
If the button can be activated or not
92176
*/
@@ -95,11 +179,14 @@ Button.propTypes = {
95179
* Name of icon to place before child content
96180
*/
97181
iconAfterName: ValidIconNameType,
98-
99182
/**
100183
* Name of icon to place after child content
101184
*/
102185
iconBeforeName: ValidIconNameType,
186+
/**
187+
* The kind of button - determines how it appears visually
188+
*/
189+
kind: PropTypes.oneOf(Object.values(kinds)),
103190
/**
104191
* Specifying an href will use an <a> to link to the URL
105192
*/

Diff for: client/common/Button.stories.jsx

+8
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,11 @@ export const ButtonWithIconBefore = () => (
4242
export const ButtonWithIconAfter = () => (
4343
<Button iconAfterName={Button.iconNames.github}>Create</Button>
4444
);
45+
46+
export const InlineButtonWithIconAfter = () => (
47+
<Button kind={Button.kinds.inline} iconAfterName={Button.iconNames.sortArrowDown}>File name</Button>
48+
);
49+
50+
export const InlineIconOnlyButton = () => (
51+
<Button kind={Button.kinds.inline} iconAfterName={Button.iconNames.plus} label="Add to collection" />
52+
);

0 commit comments

Comments
 (0)