@khanacademy/wonder-blocks-button 4.1.9 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/es/index.js +201 -66
- package/dist/index.js +201 -68
- package/dist/themes/default.d.ts +112 -0
- package/dist/themes/khanmigo.d.ts +97 -0
- package/dist/themes/themed-button.d.ts +108 -0
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/custom-snapshot.test.tsx.snap +180 -180
- package/src/components/button-core.tsx +126 -71
- package/src/components/button.tsx +6 -3
- package/src/themes/default.ts +133 -0
- package/src/themes/khanmigo.ts +35 -0
- package/src/themes/themed-button.tsx +42 -0
- package/tsconfig-build.json +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
package/dist/es/index.js
CHANGED
|
@@ -4,11 +4,10 @@ import { isClientSideUrl, getClickableBehavior } from '@khanacademy/wonder-block
|
|
|
4
4
|
import { StyleSheet } from 'aphrodite';
|
|
5
5
|
import { Link } from 'react-router-dom';
|
|
6
6
|
import { LabelSmall, LabelLarge } from '@khanacademy/wonder-blocks-typography';
|
|
7
|
-
import Color, { SemanticColor, mix, fade } from '@khanacademy/wonder-blocks-color';
|
|
8
7
|
import { addStyle } from '@khanacademy/wonder-blocks-core';
|
|
9
8
|
import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
|
|
10
9
|
import Icon from '@khanacademy/wonder-blocks-icon';
|
|
11
|
-
import
|
|
10
|
+
import { tokens, mergeTheme, createThemeContext, ThemeSwitcherContext, useScopedTheme, useStyles } from '@khanacademy/wonder-blocks-theming';
|
|
12
11
|
|
|
13
12
|
function _extends() {
|
|
14
13
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
@@ -38,11 +37,151 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
38
37
|
return target;
|
|
39
38
|
}
|
|
40
39
|
|
|
40
|
+
const theme$1 = {
|
|
41
|
+
color: {
|
|
42
|
+
bg: {
|
|
43
|
+
action: {
|
|
44
|
+
default: tokens.color.blue,
|
|
45
|
+
active: tokens.color.activeBlue,
|
|
46
|
+
inverse: tokens.color.fadedBlue
|
|
47
|
+
},
|
|
48
|
+
critical: {
|
|
49
|
+
default: tokens.color.red,
|
|
50
|
+
active: tokens.color.activeRed,
|
|
51
|
+
inverse: tokens.color.fadedRed
|
|
52
|
+
},
|
|
53
|
+
primary: {
|
|
54
|
+
default: tokens.color.white,
|
|
55
|
+
disabled: tokens.color.offBlack32,
|
|
56
|
+
inverse: tokens.color.darkBlue
|
|
57
|
+
},
|
|
58
|
+
secondary: {
|
|
59
|
+
default: "none",
|
|
60
|
+
inverse: "none",
|
|
61
|
+
focus: tokens.color.white,
|
|
62
|
+
active: tokens.color.fadedBlue
|
|
63
|
+
},
|
|
64
|
+
tertiary: {
|
|
65
|
+
hover: tokens.color.white
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
text: {
|
|
69
|
+
disabled: tokens.color.offBlack32,
|
|
70
|
+
inverse: tokens.color.white,
|
|
71
|
+
primary: {
|
|
72
|
+
disabled: tokens.color.white64
|
|
73
|
+
},
|
|
74
|
+
secondary: {
|
|
75
|
+
inverse: tokens.color.white50
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
border: {
|
|
79
|
+
disabled: tokens.color.offBlack32,
|
|
80
|
+
primary: {
|
|
81
|
+
inverse: tokens.color.white
|
|
82
|
+
},
|
|
83
|
+
secondary: {
|
|
84
|
+
action: tokens.color.offBlack50,
|
|
85
|
+
critical: tokens.color.offBlack50,
|
|
86
|
+
inverse: tokens.color.white50
|
|
87
|
+
},
|
|
88
|
+
tertiary: {
|
|
89
|
+
inverse: tokens.color.white
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
border: {
|
|
94
|
+
width: {
|
|
95
|
+
secondary: tokens.border.width.hairline,
|
|
96
|
+
focused: tokens.border.width.thin,
|
|
97
|
+
disabled: tokens.border.width.thin
|
|
98
|
+
},
|
|
99
|
+
radius: {
|
|
100
|
+
default: tokens.border.radius.small_3,
|
|
101
|
+
tertiary: tokens.border.radius.xSmall_2,
|
|
102
|
+
small: tokens.border.radius.small_3,
|
|
103
|
+
large: tokens.border.radius.large_6
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
size: {
|
|
107
|
+
width: {
|
|
108
|
+
medium: tokens.spacing.large_24,
|
|
109
|
+
large: tokens.spacing.xLarge_32
|
|
110
|
+
},
|
|
111
|
+
height: {
|
|
112
|
+
tertiaryHover: tokens.spacing.xxxxSmall_2,
|
|
113
|
+
small: tokens.spacing.xLarge_32,
|
|
114
|
+
medium: 40,
|
|
115
|
+
large: 56
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
padding: {
|
|
119
|
+
small: tokens.spacing.xSmall_8,
|
|
120
|
+
medium: tokens.spacing.small_12,
|
|
121
|
+
large: tokens.spacing.medium_16,
|
|
122
|
+
xLarge: tokens.spacing.xLarge_32
|
|
123
|
+
},
|
|
124
|
+
font: {
|
|
125
|
+
size: {
|
|
126
|
+
large: 18
|
|
127
|
+
},
|
|
128
|
+
lineHeight: {
|
|
129
|
+
large: tokens.font.lineHeight.medium
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const theme = mergeTheme(theme$1, {
|
|
135
|
+
color: {
|
|
136
|
+
bg: {
|
|
137
|
+
secondary: {
|
|
138
|
+
default: tokens.color.offWhite,
|
|
139
|
+
active: tokens.color.fadedBlue8,
|
|
140
|
+
focus: tokens.color.offWhite
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
border: {
|
|
144
|
+
secondary: {
|
|
145
|
+
action: tokens.color.fadedBlue,
|
|
146
|
+
critical: tokens.color.fadedRed
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
border: {
|
|
151
|
+
radius: {
|
|
152
|
+
default: tokens.border.radius.xLarge_12,
|
|
153
|
+
small: tokens.border.radius.large_6,
|
|
154
|
+
large: tokens.border.radius.xLarge_12
|
|
155
|
+
},
|
|
156
|
+
width: {
|
|
157
|
+
focused: tokens.border.width.hairline
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const themes = {
|
|
163
|
+
default: theme$1,
|
|
164
|
+
khanmigo: theme
|
|
165
|
+
};
|
|
166
|
+
const ButtonThemeContext = createThemeContext(theme$1);
|
|
167
|
+
function ThemedButton(props) {
|
|
168
|
+
const currentTheme = React.useContext(ThemeSwitcherContext);
|
|
169
|
+
const theme = themes[currentTheme] || theme$1;
|
|
170
|
+
return React.createElement(ButtonThemeContext.Provider, {
|
|
171
|
+
value: theme
|
|
172
|
+
}, props.children);
|
|
173
|
+
}
|
|
174
|
+
|
|
41
175
|
const _excluded$1 = ["children", "skipClientNav", "color", "disabled", "focused", "hovered", "href", "kind", "light", "pressed", "size", "style", "testId", "type", "spinner", "icon", "id", "waiting"];
|
|
42
176
|
const StyledAnchor = addStyle("a");
|
|
43
177
|
const StyledButton = addStyle("button");
|
|
44
178
|
const StyledLink = addStyle(Link);
|
|
45
179
|
const ButtonCore = React.forwardRef(function ButtonCore(props, ref) {
|
|
180
|
+
const {
|
|
181
|
+
theme,
|
|
182
|
+
themeName
|
|
183
|
+
} = useScopedTheme(ButtonThemeContext);
|
|
184
|
+
const sharedStyles = useStyles(themedSharedStyles, theme);
|
|
46
185
|
const renderInner = router => {
|
|
47
186
|
const {
|
|
48
187
|
children,
|
|
@@ -64,9 +203,8 @@ const ButtonCore = React.forwardRef(function ButtonCore(props, ref) {
|
|
|
64
203
|
id
|
|
65
204
|
} = props,
|
|
66
205
|
restProps = _objectWithoutPropertiesLoose(props, _excluded$1);
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const buttonStyles = _generateStyles(buttonColor, kind, light, iconWidth, size);
|
|
206
|
+
const iconWidth = icon ? size === "small" ? theme.size.width.medium : theme.size.width.large : 0;
|
|
207
|
+
const buttonStyles = _generateStyles(color, kind, light, iconWidth, size, theme, themeName);
|
|
70
208
|
const disabled = spinner || disabledProp;
|
|
71
209
|
const defaultStyle = [sharedStyles.shared, disabled && sharedStyles.disabled, icon && sharedStyles.withIcon, buttonStyles.default, disabled && buttonStyles.disabled, kind !== "tertiary" && !disabled && (pressed ? buttonStyles.active : (hovered || focused) && buttonStyles.focus), kind === "tertiary" && !pressed && focused && [buttonStyles.focus, disabled && buttonStyles.disabledFocus], size === "small" && sharedStyles.small, size === "large" && sharedStyles.large];
|
|
72
210
|
const commonProps = _extends({
|
|
@@ -118,19 +256,19 @@ const ButtonCore = React.forwardRef(function ButtonCore(props, ref) {
|
|
|
118
256
|
};
|
|
119
257
|
return React.createElement(__RouterContext.Consumer, null, router => renderInner(router));
|
|
120
258
|
});
|
|
121
|
-
const
|
|
259
|
+
const themedSharedStyles = theme => ({
|
|
122
260
|
shared: {
|
|
123
261
|
position: "relative",
|
|
124
262
|
display: "inline-flex",
|
|
125
263
|
alignItems: "center",
|
|
126
264
|
justifyContent: "center",
|
|
127
|
-
height:
|
|
265
|
+
height: theme.size.height.medium,
|
|
128
266
|
paddingTop: 0,
|
|
129
267
|
paddingBottom: 0,
|
|
130
|
-
paddingLeft:
|
|
131
|
-
paddingRight:
|
|
268
|
+
paddingLeft: theme.padding.large,
|
|
269
|
+
paddingRight: theme.padding.large,
|
|
132
270
|
border: "none",
|
|
133
|
-
borderRadius:
|
|
271
|
+
borderRadius: theme.border.radius.default,
|
|
134
272
|
cursor: "pointer",
|
|
135
273
|
outline: "none",
|
|
136
274
|
textDecoration: "none",
|
|
@@ -142,17 +280,18 @@ const sharedStyles = StyleSheet.create({
|
|
|
142
280
|
}
|
|
143
281
|
},
|
|
144
282
|
withIcon: {
|
|
145
|
-
paddingLeft:
|
|
283
|
+
paddingLeft: theme.padding.medium
|
|
146
284
|
},
|
|
147
285
|
disabled: {
|
|
148
286
|
cursor: "auto"
|
|
149
287
|
},
|
|
150
288
|
small: {
|
|
151
|
-
|
|
289
|
+
borderRadius: theme.border.radius.small,
|
|
290
|
+
height: theme.size.height.small
|
|
152
291
|
},
|
|
153
292
|
large: {
|
|
154
|
-
borderRadius:
|
|
155
|
-
height:
|
|
293
|
+
borderRadius: theme.border.radius.large,
|
|
294
|
+
height: theme.size.height.large
|
|
156
295
|
},
|
|
157
296
|
text: {
|
|
158
297
|
alignItems: "center",
|
|
@@ -164,8 +303,8 @@ const sharedStyles = StyleSheet.create({
|
|
|
164
303
|
pointerEvents: "none"
|
|
165
304
|
},
|
|
166
305
|
largeText: {
|
|
167
|
-
fontSize:
|
|
168
|
-
lineHeight:
|
|
306
|
+
fontSize: theme.font.size.large,
|
|
307
|
+
lineHeight: theme.font.lineHeight.large
|
|
169
308
|
},
|
|
170
309
|
textWithFocus: {
|
|
171
310
|
position: "relative"
|
|
@@ -177,85 +316,81 @@ const sharedStyles = StyleSheet.create({
|
|
|
177
316
|
position: "absolute"
|
|
178
317
|
},
|
|
179
318
|
icon: {
|
|
180
|
-
paddingRight:
|
|
319
|
+
paddingRight: theme.padding.small
|
|
181
320
|
}
|
|
182
321
|
});
|
|
183
322
|
const styles = {};
|
|
184
|
-
const _generateStyles = (
|
|
185
|
-
const
|
|
323
|
+
const _generateStyles = (buttonColor = "default", kind, light, iconWidth, size, theme, themeName) => {
|
|
324
|
+
const color = buttonColor === "destructive" ? theme.color.bg.critical.default : theme.color.bg.action.default;
|
|
325
|
+
const buttonType = `${color}-${kind}-${light}-${iconWidth}-${size}-${themeName}`;
|
|
186
326
|
if (styles[buttonType]) {
|
|
187
327
|
return styles[buttonType];
|
|
188
328
|
}
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
white64,
|
|
193
|
-
offBlack32,
|
|
194
|
-
offBlack50,
|
|
195
|
-
darkBlue
|
|
196
|
-
} = Color;
|
|
197
|
-
const fadedColor = mix(fade(color, 0.32), white);
|
|
198
|
-
const activeColor = mix(offBlack32, color);
|
|
199
|
-
const padding = size === "large" ? Spacing.xLarge_32 : Spacing.medium_16;
|
|
329
|
+
const fadedColor = buttonColor === "destructive" ? theme.color.bg.critical.inverse : theme.color.bg.action.inverse;
|
|
330
|
+
const activeColor = buttonColor === "destructive" ? theme.color.bg.critical.active : theme.color.bg.action.active;
|
|
331
|
+
const padding = size === "large" ? theme.padding.xLarge : theme.padding.large;
|
|
200
332
|
let newStyles = {};
|
|
201
333
|
if (kind === "primary") {
|
|
334
|
+
const boxShadowInnerColor = light ? theme.color.bg.primary.inverse : theme.color.bg.primary.default;
|
|
202
335
|
newStyles = {
|
|
203
336
|
default: {
|
|
204
|
-
background: light ?
|
|
205
|
-
color: light ? color :
|
|
337
|
+
background: light ? theme.color.bg.primary.default : color,
|
|
338
|
+
color: light ? color : theme.color.text.inverse,
|
|
206
339
|
paddingLeft: padding,
|
|
207
340
|
paddingRight: padding
|
|
208
341
|
},
|
|
209
342
|
focus: {
|
|
210
|
-
boxShadow: `0 0 0 1px ${
|
|
343
|
+
boxShadow: `0 0 0 1px ${boxShadowInnerColor}, 0 0 0 3px ${light ? theme.color.bg.primary.default : color}`
|
|
211
344
|
},
|
|
212
345
|
active: {
|
|
213
|
-
boxShadow: `0 0 0 1px ${
|
|
346
|
+
boxShadow: `0 0 0 1px ${boxShadowInnerColor}, 0 0 0 3px ${light ? fadedColor : activeColor}`,
|
|
214
347
|
background: light ? fadedColor : activeColor,
|
|
215
348
|
color: light ? activeColor : fadedColor
|
|
216
349
|
},
|
|
217
350
|
disabled: {
|
|
218
|
-
background: light ? fadedColor :
|
|
219
|
-
color: light ? color :
|
|
351
|
+
background: light ? fadedColor : theme.color.bg.primary.disabled,
|
|
352
|
+
color: light ? color : theme.color.text.primary.disabled,
|
|
220
353
|
cursor: "default",
|
|
221
354
|
":focus": {
|
|
222
|
-
boxShadow: `0 0 0 1px ${light ?
|
|
355
|
+
boxShadow: `0 0 0 1px ${light ? theme.color.bg.primary.disabled : theme.color.bg.primary.default}, 0 0 0 3px ${light ? fadedColor : theme.color.bg.primary.disabled}`
|
|
223
356
|
}
|
|
224
357
|
}
|
|
225
358
|
};
|
|
226
359
|
} else if (kind === "secondary") {
|
|
360
|
+
const horizontalPadding = padding - (theme.border.width.focused - 1);
|
|
361
|
+
const secondaryBorderColor = buttonColor === "destructive" ? theme.color.border.secondary.critical : theme.color.border.secondary.action;
|
|
227
362
|
newStyles = {
|
|
228
363
|
default: {
|
|
229
|
-
background:
|
|
230
|
-
color: light ?
|
|
231
|
-
borderColor: light ?
|
|
364
|
+
background: light ? theme.color.bg.secondary.inverse : theme.color.bg.secondary.default,
|
|
365
|
+
color: light ? theme.color.text.inverse : color,
|
|
366
|
+
borderColor: light ? theme.color.border.secondary.inverse : secondaryBorderColor,
|
|
232
367
|
borderStyle: "solid",
|
|
233
|
-
borderWidth:
|
|
368
|
+
borderWidth: theme.border.width.secondary,
|
|
234
369
|
paddingLeft: padding,
|
|
235
370
|
paddingRight: padding
|
|
236
371
|
},
|
|
237
372
|
focus: {
|
|
238
|
-
background: light ?
|
|
239
|
-
borderColor: light ?
|
|
240
|
-
borderWidth:
|
|
241
|
-
paddingLeft:
|
|
242
|
-
paddingRight:
|
|
373
|
+
background: light ? theme.color.bg.secondary.inverse : theme.color.bg.secondary.focus,
|
|
374
|
+
borderColor: light ? theme.color.border.primary.inverse : color,
|
|
375
|
+
borderWidth: theme.border.width.focused,
|
|
376
|
+
paddingLeft: horizontalPadding,
|
|
377
|
+
paddingRight: horizontalPadding
|
|
243
378
|
},
|
|
244
379
|
active: {
|
|
245
|
-
background: light ? activeColor :
|
|
380
|
+
background: light ? activeColor : theme.color.bg.secondary.active,
|
|
246
381
|
color: light ? fadedColor : activeColor,
|
|
247
382
|
borderColor: light ? fadedColor : activeColor,
|
|
248
|
-
borderWidth:
|
|
249
|
-
paddingLeft:
|
|
250
|
-
paddingRight:
|
|
383
|
+
borderWidth: theme.border.width.focused,
|
|
384
|
+
paddingLeft: horizontalPadding,
|
|
385
|
+
paddingRight: horizontalPadding
|
|
251
386
|
},
|
|
252
387
|
disabled: {
|
|
253
|
-
color: light ?
|
|
254
|
-
borderColor: light ? fadedColor :
|
|
388
|
+
color: light ? theme.color.text.secondary.inverse : theme.color.text.disabled,
|
|
389
|
+
borderColor: light ? fadedColor : theme.color.border.disabled,
|
|
255
390
|
cursor: "default",
|
|
256
391
|
":focus": {
|
|
257
|
-
borderColor: light ?
|
|
258
|
-
borderWidth:
|
|
392
|
+
borderColor: light ? theme.color.border.secondary.inverse : theme.color.border.disabled,
|
|
393
|
+
borderWidth: theme.border.width.disabled,
|
|
259
394
|
paddingLeft: padding - 1,
|
|
260
395
|
paddingRight: padding - 1
|
|
261
396
|
}
|
|
@@ -265,7 +400,7 @@ const _generateStyles = (color, kind, light, iconWidth, size) => {
|
|
|
265
400
|
newStyles = {
|
|
266
401
|
default: {
|
|
267
402
|
background: "none",
|
|
268
|
-
color: light ?
|
|
403
|
+
color: light ? theme.color.text.inverse : color,
|
|
269
404
|
paddingLeft: 0,
|
|
270
405
|
paddingRight: 0
|
|
271
406
|
},
|
|
@@ -273,24 +408,24 @@ const _generateStyles = (color, kind, light, iconWidth, size) => {
|
|
|
273
408
|
":after": {
|
|
274
409
|
content: "''",
|
|
275
410
|
position: "absolute",
|
|
276
|
-
height:
|
|
411
|
+
height: theme.size.height.tertiaryHover,
|
|
277
412
|
width: "100%",
|
|
278
413
|
right: 0,
|
|
279
414
|
bottom: 0,
|
|
280
|
-
background: light ?
|
|
281
|
-
borderRadius:
|
|
415
|
+
background: light ? theme.color.bg.tertiary.hover : color,
|
|
416
|
+
borderRadius: theme.border.radius.tertiary
|
|
282
417
|
}
|
|
283
418
|
},
|
|
284
419
|
focus: {
|
|
285
420
|
":after": {
|
|
286
421
|
content: "''",
|
|
287
422
|
position: "absolute",
|
|
288
|
-
width: `calc(100% + ${
|
|
289
|
-
height: `calc(100% - ${
|
|
423
|
+
width: `calc(100% + ${theme.border.width.focused * 2}px)`,
|
|
424
|
+
height: `calc(100% - ${theme.border.width.focused * 2}px)`,
|
|
290
425
|
borderStyle: "solid",
|
|
291
|
-
borderColor: light ?
|
|
292
|
-
borderWidth:
|
|
293
|
-
borderRadius:
|
|
426
|
+
borderColor: light ? theme.color.border.tertiary.inverse : color,
|
|
427
|
+
borderWidth: theme.border.width.focused,
|
|
428
|
+
borderRadius: theme.border.radius.default
|
|
294
429
|
}
|
|
295
430
|
},
|
|
296
431
|
active: {
|
|
@@ -301,12 +436,12 @@ const _generateStyles = (color, kind, light, iconWidth, size) => {
|
|
|
301
436
|
}
|
|
302
437
|
},
|
|
303
438
|
disabled: {
|
|
304
|
-
color: light ? fadedColor :
|
|
439
|
+
color: light ? fadedColor : theme.color.text.disabled,
|
|
305
440
|
cursor: "default"
|
|
306
441
|
},
|
|
307
442
|
disabledFocus: {
|
|
308
443
|
":after": {
|
|
309
|
-
borderColor: light ?
|
|
444
|
+
borderColor: light ? theme.color.border.tertiary.inverse : theme.color.border.disabled
|
|
310
445
|
}
|
|
311
446
|
}
|
|
312
447
|
};
|
|
@@ -380,7 +515,7 @@ const Button = React.forwardRef(function Button(props, ref) {
|
|
|
380
515
|
}, renderProp);
|
|
381
516
|
}
|
|
382
517
|
};
|
|
383
|
-
return React.createElement(__RouterContext.Consumer, null, router => renderClickableBehavior(router));
|
|
518
|
+
return React.createElement(ThemedButton, null, React.createElement(__RouterContext.Consumer, null, router => renderClickableBehavior(router)));
|
|
384
519
|
});
|
|
385
520
|
|
|
386
521
|
export { Button as default };
|