@khanacademy/wonder-blocks-button 4.1.8 → 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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @khanacademy/wonder-blocks-button
2
2
 
3
+ ## 4.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5725703a: Add theming support to the Button component
8
+
9
+ ## 4.1.9
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [4b97b9a2]
14
+ - @khanacademy/wonder-blocks-core@6.2.0
15
+ - @khanacademy/wonder-blocks-clickable@4.0.6
16
+ - @khanacademy/wonder-blocks-icon@2.1.6
17
+ - @khanacademy/wonder-blocks-progress-spinner@2.0.22
18
+ - @khanacademy/wonder-blocks-typography@2.1.8
19
+
3
20
  ## 4.1.8
4
21
 
5
22
  ### Patch Changes
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 Spacing from '@khanacademy/wonder-blocks-spacing';
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 buttonColor = color === "destructive" ? SemanticColor.controlDestructive : SemanticColor.controlDefault;
68
- const iconWidth = icon ? (size === "small" ? 16 : 24) + 8 : 0;
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 sharedStyles = StyleSheet.create({
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: 40,
265
+ height: theme.size.height.medium,
128
266
  paddingTop: 0,
129
267
  paddingBottom: 0,
130
- paddingLeft: 16,
131
- paddingRight: 16,
268
+ paddingLeft: theme.padding.large,
269
+ paddingRight: theme.padding.large,
132
270
  border: "none",
133
- borderRadius: 4,
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: 12
283
+ paddingLeft: theme.padding.medium
146
284
  },
147
285
  disabled: {
148
286
  cursor: "auto"
149
287
  },
150
288
  small: {
151
- height: 32
289
+ borderRadius: theme.border.radius.small,
290
+ height: theme.size.height.small
152
291
  },
153
292
  large: {
154
- borderRadius: Spacing.xxSmall_6,
155
- height: 56
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: 18,
168
- lineHeight: "20px"
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: Spacing.xSmall_8
319
+ paddingRight: theme.padding.small
181
320
  }
182
321
  });
183
322
  const styles = {};
184
- const _generateStyles = (color, kind, light, iconWidth, size) => {
185
- const buttonType = color + kind + light.toString() + iconWidth.toString() + size;
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
- white,
191
- white50,
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 ? white : color,
205
- color: light ? color : white,
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 ${light ? darkBlue : white}, 0 0 0 3px ${light ? white : color}`
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 ${light ? darkBlue : white}, 0 0 0 3px ${light ? fadedColor : activeColor}`,
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 : offBlack32,
219
- color: light ? color : white64,
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 ? offBlack32 : white}, 0 0 0 3px ${light ? fadedColor : offBlack32}`
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: "none",
230
- color: light ? white : color,
231
- borderColor: light ? white50 : offBlack50,
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: 1,
368
+ borderWidth: theme.border.width.secondary,
234
369
  paddingLeft: padding,
235
370
  paddingRight: padding
236
371
  },
237
372
  focus: {
238
- background: light ? "transparent" : white,
239
- borderColor: light ? white : color,
240
- borderWidth: 2,
241
- paddingLeft: padding - 1,
242
- paddingRight: padding - 1
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 : fadedColor,
380
+ background: light ? activeColor : theme.color.bg.secondary.active,
246
381
  color: light ? fadedColor : activeColor,
247
382
  borderColor: light ? fadedColor : activeColor,
248
- borderWidth: 2,
249
- paddingLeft: padding - 1,
250
- paddingRight: padding - 1
383
+ borderWidth: theme.border.width.focused,
384
+ paddingLeft: horizontalPadding,
385
+ paddingRight: horizontalPadding
251
386
  },
252
387
  disabled: {
253
- color: light ? white50 : offBlack32,
254
- borderColor: light ? fadedColor : offBlack32,
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 ? white50 : offBlack32,
258
- borderWidth: 2,
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 ? white : color,
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: 2,
411
+ height: theme.size.height.tertiaryHover,
277
412
  width: "100%",
278
413
  right: 0,
279
414
  bottom: 0,
280
- background: light ? white : color,
281
- borderRadius: 2
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% + ${Spacing.xxxSmall_4}px)`,
289
- height: `calc(100% - ${Spacing.xxxSmall_4}px)`,
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 ? white : color,
292
- borderWidth: Spacing.xxxxSmall_2,
293
- borderRadius: Spacing.xxxSmall_4
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 : offBlack32,
439
+ color: light ? fadedColor : theme.color.text.disabled,
305
440
  cursor: "default"
306
441
  },
307
442
  disabledFocus: {
308
443
  ":after": {
309
- borderColor: light ? white50 : offBlack32
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 };