@khanacademy/wonder-blocks-button 4.1.9 → 4.2.1
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 +14 -0
- package/dist/es/index.js +217 -67
- package/dist/index.js +217 -69
- package/dist/themes/default.d.ts +118 -0
- package/dist/themes/khanmigo.d.ts +103 -0
- package/dist/themes/themed-button.d.ts +114 -0
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/custom-snapshot.test.tsx.snap +264 -264
- package/src/components/button-core.tsx +129 -72
- package/src/components/button.tsx +6 -3
- package/src/themes/default.ts +139 -0
- package/src/themes/khanmigo.ts +43 -0
- package/src/themes/themed-button.tsx +42 -0
- package/tsconfig-build.json +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {StyleSheet} from "aphrodite";
|
|
2
|
+
import {CSSProperties, StyleSheet} from "aphrodite";
|
|
3
3
|
import {Link} from "react-router-dom";
|
|
4
4
|
import {__RouterContext} from "react-router";
|
|
5
5
|
|
|
6
6
|
import {LabelLarge, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
7
|
-
import Color, {
|
|
8
|
-
SemanticColor,
|
|
9
|
-
mix,
|
|
10
|
-
fade,
|
|
11
|
-
} from "@khanacademy/wonder-blocks-color";
|
|
12
7
|
import {addStyle} from "@khanacademy/wonder-blocks-core";
|
|
13
8
|
import {CircularSpinner} from "@khanacademy/wonder-blocks-progress-spinner";
|
|
14
9
|
import Icon from "@khanacademy/wonder-blocks-icon";
|
|
15
|
-
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
16
10
|
import {isClientSideUrl} from "@khanacademy/wonder-blocks-clickable";
|
|
11
|
+
import {
|
|
12
|
+
ThemedStylesFn,
|
|
13
|
+
useScopedTheme,
|
|
14
|
+
useStyles,
|
|
15
|
+
} from "@khanacademy/wonder-blocks-theming";
|
|
17
16
|
|
|
18
17
|
import type {
|
|
19
18
|
ChildrenProps,
|
|
20
19
|
ClickableState,
|
|
21
20
|
} from "@khanacademy/wonder-blocks-clickable";
|
|
22
21
|
import type {SharedProps} from "./button";
|
|
22
|
+
import {ButtonThemeContext, ButtonThemeContract} from "../themes/themed-button";
|
|
23
23
|
|
|
24
24
|
type Props = SharedProps & ChildrenProps & ClickableState;
|
|
25
25
|
|
|
@@ -34,6 +34,9 @@ const ButtonCore: React.ForwardRefExoticComponent<
|
|
|
34
34
|
typeof Link | HTMLButtonElement | HTMLAnchorElement,
|
|
35
35
|
Props
|
|
36
36
|
>(function ButtonCore(props: Props, ref) {
|
|
37
|
+
const {theme, themeName} = useScopedTheme(ButtonThemeContext);
|
|
38
|
+
const sharedStyles = useStyles(themedSharedStyles, theme);
|
|
39
|
+
|
|
37
40
|
const renderInner = (router: any): React.ReactNode => {
|
|
38
41
|
const {
|
|
39
42
|
children,
|
|
@@ -57,18 +60,19 @@ const ButtonCore: React.ForwardRefExoticComponent<
|
|
|
57
60
|
...restProps
|
|
58
61
|
} = props;
|
|
59
62
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
?
|
|
63
|
-
:
|
|
64
|
-
|
|
65
|
-
const iconWidth = icon ? (size === "small" ? 16 : 24) + 8 : 0;
|
|
63
|
+
const iconWidth = icon
|
|
64
|
+
? size === "small"
|
|
65
|
+
? theme.size.width.medium
|
|
66
|
+
: theme.size.width.large
|
|
67
|
+
: 0;
|
|
66
68
|
const buttonStyles = _generateStyles(
|
|
67
|
-
|
|
69
|
+
color,
|
|
68
70
|
kind,
|
|
69
71
|
light,
|
|
70
72
|
iconWidth,
|
|
71
73
|
size,
|
|
74
|
+
theme,
|
|
75
|
+
themeName,
|
|
72
76
|
);
|
|
73
77
|
|
|
74
78
|
const disabled = spinner || disabledProp;
|
|
@@ -200,19 +204,19 @@ const ButtonCore: React.ForwardRefExoticComponent<
|
|
|
200
204
|
|
|
201
205
|
export default ButtonCore;
|
|
202
206
|
|
|
203
|
-
const
|
|
207
|
+
const themedSharedStyles: ThemedStylesFn<ButtonThemeContract> = (theme) => ({
|
|
204
208
|
shared: {
|
|
205
209
|
position: "relative",
|
|
206
210
|
display: "inline-flex",
|
|
207
211
|
alignItems: "center",
|
|
208
212
|
justifyContent: "center",
|
|
209
|
-
height:
|
|
213
|
+
height: theme.size.height.medium,
|
|
210
214
|
paddingTop: 0,
|
|
211
215
|
paddingBottom: 0,
|
|
212
|
-
paddingLeft:
|
|
213
|
-
paddingRight:
|
|
216
|
+
paddingLeft: theme.padding.large,
|
|
217
|
+
paddingRight: theme.padding.large,
|
|
214
218
|
border: "none",
|
|
215
|
-
borderRadius:
|
|
219
|
+
borderRadius: theme.border.radius.default,
|
|
216
220
|
cursor: "pointer",
|
|
217
221
|
outline: "none",
|
|
218
222
|
textDecoration: "none",
|
|
@@ -228,21 +232,22 @@ const sharedStyles = StyleSheet.create({
|
|
|
228
232
|
},
|
|
229
233
|
withIcon: {
|
|
230
234
|
// The left padding for the button with icon should have 4px less padding
|
|
231
|
-
paddingLeft:
|
|
235
|
+
paddingLeft: theme.padding.medium,
|
|
232
236
|
},
|
|
233
237
|
disabled: {
|
|
234
238
|
cursor: "auto",
|
|
235
239
|
},
|
|
236
240
|
small: {
|
|
237
|
-
|
|
241
|
+
borderRadius: theme.border.radius.small,
|
|
242
|
+
height: theme.size.height.small,
|
|
238
243
|
},
|
|
239
244
|
large: {
|
|
240
|
-
borderRadius:
|
|
241
|
-
height:
|
|
245
|
+
borderRadius: theme.border.radius.large,
|
|
246
|
+
height: theme.size.height.large,
|
|
242
247
|
},
|
|
243
248
|
text: {
|
|
244
249
|
alignItems: "center",
|
|
245
|
-
fontWeight:
|
|
250
|
+
fontWeight: theme.font.weight.default,
|
|
246
251
|
whiteSpace: "nowrap",
|
|
247
252
|
overflow: "hidden",
|
|
248
253
|
textOverflow: "ellipsis",
|
|
@@ -250,8 +255,8 @@ const sharedStyles = StyleSheet.create({
|
|
|
250
255
|
pointerEvents: "none", // fix Safari bug where the browser was eating mouse events
|
|
251
256
|
},
|
|
252
257
|
largeText: {
|
|
253
|
-
fontSize:
|
|
254
|
-
lineHeight:
|
|
258
|
+
fontSize: theme.font.size.large,
|
|
259
|
+
lineHeight: theme.font.lineHeight.large,
|
|
255
260
|
},
|
|
256
261
|
textWithFocus: {
|
|
257
262
|
position: "relative", // allows the tertiary button border to use the label width
|
|
@@ -263,36 +268,53 @@ const sharedStyles = StyleSheet.create({
|
|
|
263
268
|
position: "absolute",
|
|
264
269
|
},
|
|
265
270
|
icon: {
|
|
266
|
-
paddingRight:
|
|
271
|
+
paddingRight: theme.padding.small,
|
|
267
272
|
},
|
|
268
273
|
});
|
|
269
274
|
|
|
270
275
|
const styles: Record<string, any> = {};
|
|
271
276
|
|
|
272
277
|
const _generateStyles = (
|
|
273
|
-
|
|
278
|
+
buttonColor = "default",
|
|
274
279
|
kind: "primary" | "secondary" | "tertiary",
|
|
275
280
|
light: boolean,
|
|
276
281
|
iconWidth: number,
|
|
277
282
|
size: "large" | "medium" | "small",
|
|
283
|
+
theme: ButtonThemeContract,
|
|
284
|
+
themeName: string,
|
|
278
285
|
) => {
|
|
279
|
-
const
|
|
280
|
-
|
|
286
|
+
const color: string =
|
|
287
|
+
buttonColor === "destructive"
|
|
288
|
+
? theme.color.bg.critical.default
|
|
289
|
+
: theme.color.bg.action.default;
|
|
290
|
+
|
|
291
|
+
const buttonType = `${color}-${kind}-${light}-${iconWidth}-${size}-${themeName}`;
|
|
292
|
+
|
|
281
293
|
if (styles[buttonType]) {
|
|
282
294
|
return styles[buttonType];
|
|
283
295
|
}
|
|
284
296
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
297
|
+
const fadedColor =
|
|
298
|
+
buttonColor === "destructive"
|
|
299
|
+
? theme.color.bg.critical.inverse
|
|
300
|
+
: theme.color.bg.action.inverse;
|
|
301
|
+
const activeColor =
|
|
302
|
+
buttonColor === "destructive"
|
|
303
|
+
? theme.color.bg.critical.active
|
|
304
|
+
: theme.color.bg.action.active;
|
|
305
|
+
const padding =
|
|
306
|
+
size === "large" ? theme.padding.xLarge : theme.padding.large;
|
|
289
307
|
|
|
290
|
-
let newStyles: Record<string,
|
|
308
|
+
let newStyles: Record<string, CSSProperties> = {};
|
|
291
309
|
if (kind === "primary") {
|
|
310
|
+
const boxShadowInnerColor: string = light
|
|
311
|
+
? theme.color.bg.primary.inverse
|
|
312
|
+
: theme.color.bg.primary.default;
|
|
313
|
+
|
|
292
314
|
newStyles = {
|
|
293
315
|
default: {
|
|
294
|
-
background: light ?
|
|
295
|
-
color: light ? color :
|
|
316
|
+
background: light ? theme.color.bg.primary.default : color,
|
|
317
|
+
color: light ? color : theme.color.text.inverse,
|
|
296
318
|
paddingLeft: padding,
|
|
297
319
|
paddingRight: padding,
|
|
298
320
|
},
|
|
@@ -301,63 +323,90 @@ const _generateStyles = (
|
|
|
301
323
|
// a background of darkBlue for the light version. The inner
|
|
302
324
|
// box shadow/ring is also small enough for a slight variation
|
|
303
325
|
// in the background color not to matter too much.
|
|
304
|
-
boxShadow: `0 0 0 1px ${
|
|
305
|
-
light ?
|
|
326
|
+
boxShadow: `0 0 0 1px ${boxShadowInnerColor}, 0 0 0 3px ${
|
|
327
|
+
light ? theme.color.bg.primary.default : color
|
|
306
328
|
}`,
|
|
307
329
|
},
|
|
308
330
|
active: {
|
|
309
|
-
boxShadow: `0 0 0 1px ${
|
|
331
|
+
boxShadow: `0 0 0 1px ${boxShadowInnerColor}, 0 0 0 3px ${
|
|
310
332
|
light ? fadedColor : activeColor
|
|
311
333
|
}`,
|
|
312
334
|
background: light ? fadedColor : activeColor,
|
|
313
335
|
color: light ? activeColor : fadedColor,
|
|
314
336
|
},
|
|
315
337
|
disabled: {
|
|
316
|
-
background: light
|
|
317
|
-
|
|
338
|
+
background: light
|
|
339
|
+
? fadedColor
|
|
340
|
+
: theme.color.bg.primary.disabled,
|
|
341
|
+
color: light ? color : theme.color.text.primary.disabled,
|
|
318
342
|
cursor: "default",
|
|
319
343
|
":focus": {
|
|
320
344
|
boxShadow: `0 0 0 1px ${
|
|
321
|
-
light
|
|
322
|
-
|
|
345
|
+
light
|
|
346
|
+
? theme.color.bg.primary.disabled
|
|
347
|
+
: theme.color.bg.primary.default
|
|
348
|
+
}, 0 0 0 3px ${
|
|
349
|
+
light ? fadedColor : theme.color.bg.primary.disabled
|
|
350
|
+
}`,
|
|
323
351
|
},
|
|
324
352
|
},
|
|
325
353
|
};
|
|
326
354
|
} else if (kind === "secondary") {
|
|
355
|
+
const horizontalPadding = padding - (theme.border.width.focused - 1);
|
|
356
|
+
const secondaryBorderColor =
|
|
357
|
+
buttonColor === "destructive"
|
|
358
|
+
? theme.color.border.secondary.critical
|
|
359
|
+
: theme.color.border.secondary.action;
|
|
360
|
+
const secondaryActiveColor =
|
|
361
|
+
buttonColor === "destructive"
|
|
362
|
+
? theme.color.bg.secondary.active.critical
|
|
363
|
+
: theme.color.bg.secondary.active.action;
|
|
364
|
+
|
|
327
365
|
newStyles = {
|
|
328
366
|
default: {
|
|
329
|
-
background:
|
|
330
|
-
|
|
331
|
-
|
|
367
|
+
background: light
|
|
368
|
+
? theme.color.bg.secondary.inverse
|
|
369
|
+
: theme.color.bg.secondary.default,
|
|
370
|
+
color: light ? theme.color.text.inverse : color,
|
|
371
|
+
borderColor: light
|
|
372
|
+
? theme.color.border.secondary.inverse
|
|
373
|
+
: secondaryBorderColor,
|
|
332
374
|
borderStyle: "solid",
|
|
333
|
-
borderWidth:
|
|
375
|
+
borderWidth: theme.border.width.secondary,
|
|
334
376
|
paddingLeft: padding,
|
|
335
377
|
paddingRight: padding,
|
|
336
378
|
},
|
|
337
379
|
focus: {
|
|
338
|
-
background: light
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
380
|
+
background: light
|
|
381
|
+
? theme.color.bg.secondary.inverse
|
|
382
|
+
: theme.color.bg.secondary.focus,
|
|
383
|
+
borderColor: light ? theme.color.border.primary.inverse : color,
|
|
384
|
+
borderWidth: theme.border.width.focused,
|
|
385
|
+
paddingLeft: horizontalPadding,
|
|
386
|
+
paddingRight: horizontalPadding,
|
|
343
387
|
},
|
|
388
|
+
|
|
344
389
|
active: {
|
|
345
|
-
background: light ? activeColor :
|
|
390
|
+
background: light ? activeColor : secondaryActiveColor,
|
|
346
391
|
color: light ? fadedColor : activeColor,
|
|
347
392
|
borderColor: light ? fadedColor : activeColor,
|
|
348
|
-
borderWidth:
|
|
393
|
+
borderWidth: theme.border.width.focused,
|
|
349
394
|
// We need to reduce padding to offset the difference
|
|
350
395
|
// caused by the border becoming thicker on focus.
|
|
351
|
-
paddingLeft:
|
|
352
|
-
paddingRight:
|
|
396
|
+
paddingLeft: horizontalPadding,
|
|
397
|
+
paddingRight: horizontalPadding,
|
|
353
398
|
},
|
|
354
399
|
disabled: {
|
|
355
|
-
color: light
|
|
356
|
-
|
|
400
|
+
color: light
|
|
401
|
+
? theme.color.text.secondary.inverse
|
|
402
|
+
: theme.color.text.disabled,
|
|
403
|
+
borderColor: light ? fadedColor : theme.color.border.disabled,
|
|
357
404
|
cursor: "default",
|
|
358
405
|
":focus": {
|
|
359
|
-
borderColor: light
|
|
360
|
-
|
|
406
|
+
borderColor: light
|
|
407
|
+
? theme.color.border.secondary.inverse
|
|
408
|
+
: theme.color.border.disabled,
|
|
409
|
+
borderWidth: theme.border.width.disabled,
|
|
361
410
|
// We need to reduce padding to offset the difference
|
|
362
411
|
// caused by the border becoming thicker on focus.
|
|
363
412
|
paddingLeft: padding - 1,
|
|
@@ -369,7 +418,7 @@ const _generateStyles = (
|
|
|
369
418
|
newStyles = {
|
|
370
419
|
default: {
|
|
371
420
|
background: "none",
|
|
372
|
-
color: light ?
|
|
421
|
+
color: light ? theme.color.text.inverse : color,
|
|
373
422
|
paddingLeft: 0,
|
|
374
423
|
paddingRight: 0,
|
|
375
424
|
},
|
|
@@ -377,12 +426,12 @@ const _generateStyles = (
|
|
|
377
426
|
":after": {
|
|
378
427
|
content: "''",
|
|
379
428
|
position: "absolute",
|
|
380
|
-
height:
|
|
429
|
+
height: theme.size.height.tertiaryHover,
|
|
381
430
|
width: "100%",
|
|
382
431
|
right: 0,
|
|
383
432
|
bottom: 0,
|
|
384
|
-
background: light ?
|
|
385
|
-
borderRadius:
|
|
433
|
+
background: light ? theme.color.bg.tertiary.hover : color,
|
|
434
|
+
borderRadius: theme.border.radius.tertiary,
|
|
386
435
|
},
|
|
387
436
|
},
|
|
388
437
|
focus: {
|
|
@@ -392,12 +441,18 @@ const _generateStyles = (
|
|
|
392
441
|
// calculate the width/height and use absolute position to
|
|
393
442
|
// prevent other elements from being shifted around.
|
|
394
443
|
position: "absolute",
|
|
395
|
-
|
|
396
|
-
|
|
444
|
+
// Keeps the button at the same size when applying the
|
|
445
|
+
// borderWidth property, so we can apply the correct value
|
|
446
|
+
// per theme for each side (left and right).
|
|
447
|
+
width: `calc(100% + ${theme.border.width.focused * 2}px)`,
|
|
448
|
+
// Same as above, but for the height (top and bottom).
|
|
449
|
+
height: `calc(100% - ${theme.border.width.focused * 2}px)`,
|
|
397
450
|
borderStyle: "solid",
|
|
398
|
-
borderColor: light
|
|
399
|
-
|
|
400
|
-
|
|
451
|
+
borderColor: light
|
|
452
|
+
? theme.color.border.tertiary.inverse
|
|
453
|
+
: color,
|
|
454
|
+
borderWidth: theme.border.width.focused,
|
|
455
|
+
borderRadius: theme.border.radius.default,
|
|
401
456
|
},
|
|
402
457
|
},
|
|
403
458
|
active: {
|
|
@@ -408,12 +463,14 @@ const _generateStyles = (
|
|
|
408
463
|
},
|
|
409
464
|
},
|
|
410
465
|
disabled: {
|
|
411
|
-
color: light ? fadedColor :
|
|
466
|
+
color: light ? fadedColor : theme.color.text.disabled,
|
|
412
467
|
cursor: "default",
|
|
413
468
|
},
|
|
414
469
|
disabledFocus: {
|
|
415
470
|
":after": {
|
|
416
|
-
borderColor: light
|
|
471
|
+
borderColor: light
|
|
472
|
+
? theme.color.border.tertiary.inverse
|
|
473
|
+
: theme.color.border.disabled,
|
|
417
474
|
},
|
|
418
475
|
},
|
|
419
476
|
};
|
|
@@ -10,6 +10,7 @@ import type {AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
|
|
|
10
10
|
import type {IconAsset} from "@khanacademy/wonder-blocks-icon";
|
|
11
11
|
import {Link} from "react-router-dom";
|
|
12
12
|
import ButtonCore from "./button-core";
|
|
13
|
+
import ThemedButton from "../themes/themed-button";
|
|
13
14
|
|
|
14
15
|
export type SharedProps =
|
|
15
16
|
/**
|
|
@@ -287,9 +288,11 @@ const Button: React.ForwardRefExoticComponent<
|
|
|
287
288
|
};
|
|
288
289
|
|
|
289
290
|
return (
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
|
|
291
|
+
<ThemedButton>
|
|
292
|
+
<__RouterContext.Consumer>
|
|
293
|
+
{(router) => renderClickableBehavior(router)}
|
|
294
|
+
</__RouterContext.Consumer>
|
|
295
|
+
</ThemedButton>
|
|
293
296
|
);
|
|
294
297
|
});
|
|
295
298
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {tokens} from "@khanacademy/wonder-blocks-theming";
|
|
2
|
+
|
|
3
|
+
const theme = {
|
|
4
|
+
color: {
|
|
5
|
+
bg: {
|
|
6
|
+
/**
|
|
7
|
+
* Color
|
|
8
|
+
*/
|
|
9
|
+
// color="default"
|
|
10
|
+
action: {
|
|
11
|
+
default: tokens.color.blue,
|
|
12
|
+
active: tokens.color.activeBlue,
|
|
13
|
+
inverse: tokens.color.fadedBlue,
|
|
14
|
+
},
|
|
15
|
+
// color="destructive"
|
|
16
|
+
critical: {
|
|
17
|
+
default: tokens.color.red,
|
|
18
|
+
active: tokens.color.activeRed,
|
|
19
|
+
inverse: tokens.color.fadedRed,
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Kind
|
|
24
|
+
*/
|
|
25
|
+
primary: {
|
|
26
|
+
default: tokens.color.white,
|
|
27
|
+
disabled: tokens.color.offBlack32,
|
|
28
|
+
// used in boxShadow
|
|
29
|
+
inverse: tokens.color.darkBlue,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
secondary: {
|
|
33
|
+
default: "none",
|
|
34
|
+
inverse: "none",
|
|
35
|
+
focus: tokens.color.white,
|
|
36
|
+
active: {
|
|
37
|
+
action: tokens.color.fadedBlue,
|
|
38
|
+
critical: tokens.color.fadedRed,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
tertiary: {
|
|
43
|
+
hover: tokens.color.white,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
text: {
|
|
47
|
+
/**
|
|
48
|
+
* Default
|
|
49
|
+
*/
|
|
50
|
+
// kind="secondary, tertiary", disabled=true, light=false
|
|
51
|
+
disabled: tokens.color.offBlack32,
|
|
52
|
+
// kind="primary", light=false | kind="secondary, tertiary", light=true
|
|
53
|
+
inverse: tokens.color.white,
|
|
54
|
+
/**
|
|
55
|
+
* Kind
|
|
56
|
+
*/
|
|
57
|
+
primary: {
|
|
58
|
+
disabled: tokens.color.white64,
|
|
59
|
+
},
|
|
60
|
+
secondary: {
|
|
61
|
+
inverse: tokens.color.white50,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
border: {
|
|
65
|
+
/**
|
|
66
|
+
* Default
|
|
67
|
+
*/
|
|
68
|
+
// kind="secondary", light=false | kind="tertiary", light=false
|
|
69
|
+
disabled: tokens.color.offBlack32,
|
|
70
|
+
/**
|
|
71
|
+
* Kind
|
|
72
|
+
*/
|
|
73
|
+
primary: {
|
|
74
|
+
inverse: tokens.color.white,
|
|
75
|
+
},
|
|
76
|
+
secondary: {
|
|
77
|
+
action: tokens.color.offBlack50,
|
|
78
|
+
critical: tokens.color.offBlack50,
|
|
79
|
+
inverse: tokens.color.white50,
|
|
80
|
+
},
|
|
81
|
+
tertiary: {
|
|
82
|
+
inverse: tokens.color.white,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
border: {
|
|
87
|
+
width: {
|
|
88
|
+
// secondary (resting)
|
|
89
|
+
secondary: tokens.border.width.hairline,
|
|
90
|
+
// secondary (resting, focus, active), tertiary (focus)
|
|
91
|
+
focused: tokens.border.width.thin,
|
|
92
|
+
// secondary (disabled)
|
|
93
|
+
disabled: tokens.border.width.thin,
|
|
94
|
+
},
|
|
95
|
+
radius: {
|
|
96
|
+
// default
|
|
97
|
+
default: tokens.border.radius.medium_4,
|
|
98
|
+
// tertiary
|
|
99
|
+
tertiary: tokens.border.radius.xSmall_2,
|
|
100
|
+
// small button
|
|
101
|
+
small: tokens.border.radius.small_3,
|
|
102
|
+
// large button
|
|
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
|
+
// NOTE: These height tokens are specific to this component.
|
|
115
|
+
medium: 40,
|
|
116
|
+
large: 56,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
padding: {
|
|
120
|
+
small: tokens.spacing.xSmall_8,
|
|
121
|
+
medium: tokens.spacing.small_12,
|
|
122
|
+
large: tokens.spacing.medium_16,
|
|
123
|
+
xLarge: tokens.spacing.xLarge_32,
|
|
124
|
+
},
|
|
125
|
+
font: {
|
|
126
|
+
size: {
|
|
127
|
+
// NOTE: This token is specific to this button size.
|
|
128
|
+
large: 18,
|
|
129
|
+
},
|
|
130
|
+
lineHeight: {
|
|
131
|
+
large: tokens.font.lineHeight.medium,
|
|
132
|
+
},
|
|
133
|
+
weight: {
|
|
134
|
+
default: tokens.font.weight.bold,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default theme;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {mergeTheme, tokens} from "@khanacademy/wonder-blocks-theming";
|
|
2
|
+
import defaultTheme from "./default";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The overrides for the Khanmigo theme.
|
|
6
|
+
*/
|
|
7
|
+
const theme = mergeTheme(defaultTheme, {
|
|
8
|
+
color: {
|
|
9
|
+
bg: {
|
|
10
|
+
secondary: {
|
|
11
|
+
default: tokens.color.offWhite,
|
|
12
|
+
active: {
|
|
13
|
+
action: tokens.color.fadedBlue8,
|
|
14
|
+
critical: tokens.color.fadedRed8,
|
|
15
|
+
},
|
|
16
|
+
focus: tokens.color.offWhite,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
border: {
|
|
20
|
+
secondary: {
|
|
21
|
+
action: tokens.color.fadedBlue,
|
|
22
|
+
critical: tokens.color.fadedRed,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
border: {
|
|
27
|
+
radius: {
|
|
28
|
+
default: tokens.border.radius.xLarge_12,
|
|
29
|
+
small: tokens.border.radius.large_6,
|
|
30
|
+
large: tokens.border.radius.xLarge_12,
|
|
31
|
+
},
|
|
32
|
+
width: {
|
|
33
|
+
focused: tokens.border.width.hairline,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
font: {
|
|
37
|
+
weight: {
|
|
38
|
+
default: tokens.font.weight.regular,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export default theme;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
createThemeContext,
|
|
4
|
+
ThemeSwitcherContext,
|
|
5
|
+
} from "@khanacademy/wonder-blocks-theming";
|
|
6
|
+
|
|
7
|
+
import defaultTheme from "./default";
|
|
8
|
+
import khanmigoTheme from "./khanmigo";
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The themes available to the Button component.
|
|
16
|
+
*/
|
|
17
|
+
const themes = {
|
|
18
|
+
default: defaultTheme,
|
|
19
|
+
khanmigo: khanmigoTheme,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ButtonThemeContract = typeof defaultTheme;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The context that provides the theme to the Button component.
|
|
26
|
+
* This is generally consumed via the `useScopedTheme` hook.
|
|
27
|
+
*/
|
|
28
|
+
export const ButtonThemeContext = createThemeContext(defaultTheme);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* ThemedButton is a component that provides a theme to the <Button/> component.
|
|
32
|
+
*/
|
|
33
|
+
export default function ThemedButton(props: Props) {
|
|
34
|
+
const currentTheme = React.useContext(ThemeSwitcherContext);
|
|
35
|
+
|
|
36
|
+
const theme = themes[currentTheme as keyof typeof themes] || defaultTheme;
|
|
37
|
+
return (
|
|
38
|
+
<ButtonThemeContext.Provider value={theme}>
|
|
39
|
+
{props.children}
|
|
40
|
+
</ButtonThemeContext.Provider>
|
|
41
|
+
);
|
|
42
|
+
}
|
package/tsconfig-build.json
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
{"path": "../wonder-blocks-icon/tsconfig-build.json"},
|
|
13
13
|
{"path": "../wonder-blocks-progress-spinner/tsconfig-build.json"},
|
|
14
14
|
{"path": "../wonder-blocks-spacing/tsconfig-build.json"},
|
|
15
|
+
{"path": "../wonder-blocks-theming/tsconfig-build.json"},
|
|
15
16
|
{"path": "../wonder-blocks-typography/tsconfig-build.json"},
|
|
16
17
|
]
|
|
17
18
|
}
|