@@ -6,6 +6,12 @@ import { Link } from 'react-router';
6
6
import { remSize , prop } from '../theme' ;
7
7
import Icon , { ValidIconNameType } from './Icon' ;
8
8
9
+ const kinds = {
10
+ block : 'block' ,
11
+ icon : 'icon' ,
12
+ inline : 'inline' ,
13
+ } ;
14
+
9
15
// The '&&&' will increase the specificity of the
10
16
// component's CSS so that it overrides the more
11
17
// general global styles
@@ -41,8 +47,74 @@ const StyledButton = styled.button`
41
47
cursor: not-allowed;
42
48
}
43
49
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 ) } ;
46
118
}
47
119
}
48
120
` ;
@@ -51,42 +123,54 @@ const StyledButton = styled.button`
51
123
* A Button performs an primary action
52
124
*/
53
125
const Button = ( {
54
- children, href, iconAfterName, iconBeforeName, label, to, type, ...props
126
+ children, href, iconAfterName, iconBeforeName, kind , label, to, type, ...props
55
127
} ) => {
56
128
const iconAfter = iconAfterName && < Icon name = { iconAfterName } /> ;
57
129
const iconBefore = iconBeforeName && < Icon name = { iconBeforeName } /> ;
130
+ const hasChildren = React . Children . count ( children ) > 0 ;
131
+
132
+ const content = < > { iconBefore } { hasChildren && < span > { children } </ span > } { iconAfter } </ > ;
58
133
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
+ }
60
141
61
142
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 > ;
63
144
}
64
145
65
146
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 > ;
67
148
}
68
149
69
- return < StyledButton aria-label = { label } type = { type } { ...props } > { content } </ StyledButton > ;
150
+ return < StyledComponent kind = { kind } aria-label = { label } type = { type } { ...props } > { content } </ StyledComponent > ;
70
151
} ;
71
152
72
153
Button . defaultProps = {
154
+ children : null ,
73
155
disabled : false ,
74
156
iconAfterName : null ,
75
157
iconBeforeName : null ,
158
+ kind : kinds . block ,
76
159
href : null ,
77
160
label : null ,
78
161
to : null ,
79
162
type : 'button' ,
80
163
} ;
81
164
82
165
Button . iconNames = Icon . names ;
166
+ Button . kinds = kinds ;
83
167
84
168
Button . propTypes = {
85
169
/**
86
170
* The visible part of the button, telling the user what
87
171
* the action is
88
172
*/
89
- children : PropTypes . element . isRequired ,
173
+ children : PropTypes . element ,
90
174
/**
91
175
If the button can be activated or not
92
176
*/
@@ -95,11 +179,14 @@ Button.propTypes = {
95
179
* Name of icon to place before child content
96
180
*/
97
181
iconAfterName : ValidIconNameType ,
98
-
99
182
/**
100
183
* Name of icon to place after child content
101
184
*/
102
185
iconBeforeName : ValidIconNameType ,
186
+ /**
187
+ * The kind of button - determines how it appears visually
188
+ */
189
+ kind : PropTypes . oneOf ( Object . values ( kinds ) ) ,
103
190
/**
104
191
* Specifying an href will use an <a> to link to the URL
105
192
*/
0 commit comments