@workday/canvas-kit-react 6.0.0-alpha.0-next.27 → 6.0.0-alpha.0-next.31

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.
Files changed (53) hide show
  1. package/button/lib/PrimaryButton.tsx +110 -32
  2. package/button/lib/SecondaryButton.tsx +31 -16
  3. package/button/lib/TertiaryButton.tsx +45 -36
  4. package/button/lib/parts/ButtonContainer.tsx +18 -5
  5. package/button/lib/parts/ButtonLabelIcon.tsx +34 -14
  6. package/button/lib/types.ts +11 -0
  7. package/dist/commonjs/button/lib/PrimaryButton.d.ts +80 -6
  8. package/dist/commonjs/button/lib/PrimaryButton.d.ts.map +1 -1
  9. package/dist/commonjs/button/lib/PrimaryButton.js +80 -26
  10. package/dist/commonjs/button/lib/SecondaryButton.d.ts +8 -5
  11. package/dist/commonjs/button/lib/SecondaryButton.d.ts.map +1 -1
  12. package/dist/commonjs/button/lib/SecondaryButton.js +22 -12
  13. package/dist/commonjs/button/lib/TertiaryButton.d.ts +8 -4
  14. package/dist/commonjs/button/lib/TertiaryButton.d.ts.map +1 -1
  15. package/dist/commonjs/button/lib/TertiaryButton.js +24 -20
  16. package/dist/commonjs/button/lib/parts/ButtonContainer.d.ts +5 -3
  17. package/dist/commonjs/button/lib/parts/ButtonContainer.d.ts.map +1 -1
  18. package/dist/commonjs/button/lib/parts/ButtonContainer.js +7 -9
  19. package/dist/commonjs/button/lib/parts/ButtonLabelIcon.d.ts +7 -4
  20. package/dist/commonjs/button/lib/parts/ButtonLabelIcon.d.ts.map +1 -1
  21. package/dist/commonjs/button/lib/parts/ButtonLabelIcon.js +28 -13
  22. package/dist/commonjs/button/lib/types.d.ts +9 -0
  23. package/dist/commonjs/button/lib/types.d.ts.map +1 -1
  24. package/dist/es6/button/lib/PrimaryButton.d.ts +80 -6
  25. package/dist/es6/button/lib/PrimaryButton.d.ts.map +1 -1
  26. package/dist/es6/button/lib/PrimaryButton.js +81 -27
  27. package/dist/es6/button/lib/SecondaryButton.d.ts +8 -5
  28. package/dist/es6/button/lib/SecondaryButton.d.ts.map +1 -1
  29. package/dist/es6/button/lib/SecondaryButton.js +22 -12
  30. package/dist/es6/button/lib/TertiaryButton.d.ts +8 -4
  31. package/dist/es6/button/lib/TertiaryButton.d.ts.map +1 -1
  32. package/dist/es6/button/lib/TertiaryButton.js +25 -21
  33. package/dist/es6/button/lib/parts/ButtonContainer.d.ts +5 -3
  34. package/dist/es6/button/lib/parts/ButtonContainer.d.ts.map +1 -1
  35. package/dist/es6/button/lib/parts/ButtonContainer.js +7 -9
  36. package/dist/es6/button/lib/parts/ButtonLabelIcon.d.ts +7 -4
  37. package/dist/es6/button/lib/parts/ButtonLabelIcon.d.ts.map +1 -1
  38. package/dist/es6/button/lib/parts/ButtonLabelIcon.js +28 -13
  39. package/dist/es6/button/lib/types.d.ts +9 -0
  40. package/dist/es6/button/lib/types.d.ts.map +1 -1
  41. package/package.json +5 -5
  42. package/ts3.5/dist/commonjs/button/lib/PrimaryButton.d.ts +80 -6
  43. package/ts3.5/dist/commonjs/button/lib/SecondaryButton.d.ts +8 -5
  44. package/ts3.5/dist/commonjs/button/lib/TertiaryButton.d.ts +8 -4
  45. package/ts3.5/dist/commonjs/button/lib/parts/ButtonContainer.d.ts +5 -3
  46. package/ts3.5/dist/commonjs/button/lib/parts/ButtonLabelIcon.d.ts +7 -4
  47. package/ts3.5/dist/commonjs/button/lib/types.d.ts +9 -0
  48. package/ts3.5/dist/es6/button/lib/PrimaryButton.d.ts +80 -6
  49. package/ts3.5/dist/es6/button/lib/SecondaryButton.d.ts +8 -5
  50. package/ts3.5/dist/es6/button/lib/TertiaryButton.d.ts +8 -4
  51. package/ts3.5/dist/es6/button/lib/parts/ButtonContainer.d.ts +5 -3
  52. package/ts3.5/dist/es6/button/lib/parts/ButtonLabelIcon.d.ts +7 -4
  53. package/ts3.5/dist/es6/button/lib/types.d.ts +9 -0
@@ -6,17 +6,27 @@ import {
6
6
  Themeable,
7
7
  EmotionCanvasTheme,
8
8
  createComponent,
9
+ focusRing,
9
10
  } from '@workday/canvas-kit-react/common';
11
+ import {colors} from '@workday/canvas-kit-react/tokens';
10
12
  import {CanvasSystemIcon} from '@workday/design-assets-types';
11
- import {ButtonColors} from './types';
13
+
12
14
  import {ButtonContainer, ButtonLabel, ButtonLabelData, ButtonLabelIcon} from './parts';
15
+ import {ButtonSizes, IconPositions} from './types';
13
16
 
14
17
  export interface PrimaryButtonProps extends Themeable, GrowthBehavior {
15
18
  /**
16
- * The size of the Button.
19
+ * The variant of the PrimaryButton.
20
+ * @default undefined
21
+ */
22
+ variant?: 'inverse';
23
+ /**
24
+ * There are four button sizes: `extraSmall`, `small`, `medium`, and `large`.
25
+ * If no size is provided, it will default to `medium`.
26
+ *
17
27
  * @default 'medium'
18
28
  */
19
- size?: 'small' | 'medium' | 'large';
29
+ size?: ButtonSizes;
20
30
  /**
21
31
  * The data label of the Button.
22
32
  * Note: not displayed at `small` size
@@ -28,10 +38,11 @@ export interface PrimaryButtonProps extends Themeable, GrowthBehavior {
28
38
  */
29
39
  icon?: CanvasSystemIcon;
30
40
  /**
31
- * The position of the TertiaryButton icon.
41
+ * Button icon positions can either be `left` or `right`.
42
+ * If no value is provided, it defaults to `left`.
32
43
  * @default 'left'
33
44
  */
34
- iconPosition?: 'left' | 'right';
45
+ iconPosition?: IconPositions;
35
46
  /**
36
47
  * If set to `true`, transform the icon's x-axis to mirror the graphic
37
48
  * @default false
@@ -40,6 +51,16 @@ export interface PrimaryButtonProps extends Themeable, GrowthBehavior {
40
51
  children?: React.ReactNode;
41
52
  }
42
53
 
54
+ // Button sizes where data labels are enabled
55
+ const dataLabelSizes = ['medium', 'large'];
56
+ // All disabled buttons are set to 40% opacity.
57
+ // This will eventually live in the ButtonContainer styles, but for now we're scoping it to Primary, Secondary, and Tertiary buttons.
58
+ const disabledButtonOpacity = {
59
+ '&:disabled, &:disabled:active': {
60
+ opacity: 0.4,
61
+ },
62
+ };
63
+
43
64
  export const PrimaryButton = createComponent('button')({
44
65
  displayName: 'PrimaryButton',
45
66
  Component: (
@@ -49,6 +70,7 @@ export const PrimaryButton = createComponent('button')({
49
70
  theme = useTheme(),
50
71
  size = 'medium',
51
72
  iconPosition = 'left',
73
+ variant,
52
74
  dataLabel,
53
75
  icon,
54
76
  shouldMirrorIcon = false,
@@ -61,11 +83,12 @@ export const PrimaryButton = createComponent('button')({
61
83
  <ButtonContainer
62
84
  ref={ref}
63
85
  as={Element}
64
- colors={getPrimaryButtonColors(theme)}
86
+ colors={getPrimaryButtonColors(variant, theme)}
65
87
  size={size}
88
+ extraStyles={disabledButtonOpacity}
66
89
  {...elemProps}
67
90
  >
68
- {icon && size !== 'small' && iconPosition === 'left' && (
91
+ {icon && iconPosition === 'left' && (
69
92
  <ButtonLabelIcon
70
93
  size={size}
71
94
  iconPosition={iconPosition}
@@ -74,8 +97,8 @@ export const PrimaryButton = createComponent('button')({
74
97
  />
75
98
  )}
76
99
  <ButtonLabel>{children}</ButtonLabel>
77
- {dataLabel && size !== 'small' && <ButtonLabelData>{dataLabel}</ButtonLabelData>}
78
- {icon && size !== 'small' && iconPosition === 'right' && (
100
+ {dataLabel && dataLabelSizes.includes(size) && <ButtonLabelData>{dataLabel}</ButtonLabelData>}
101
+ {icon && iconPosition === 'right' && (
79
102
  <ButtonLabelIcon
80
103
  size={size}
81
104
  iconPosition={iconPosition}
@@ -87,26 +110,81 @@ export const PrimaryButton = createComponent('button')({
87
110
  ),
88
111
  });
89
112
 
90
- export const getPrimaryButtonColors = ({
91
- canvas: {
92
- palette: {primary: themePrimary},
93
- },
94
- }: EmotionCanvasTheme): ButtonColors => ({
95
- default: {
96
- background: themePrimary.main,
97
- icon: themePrimary.contrast,
98
- label: themePrimary.contrast,
99
- },
100
- hover: {
101
- background: themePrimary.dark,
102
- },
103
- active: {
104
- background: themePrimary.darkest,
105
- },
106
- focus: {
107
- background: themePrimary.main,
108
- },
109
- disabled: {
110
- background: themePrimary.light,
111
- },
112
- });
113
+ export const getPrimaryButtonColors = (
114
+ variant: 'inverse' | undefined,
115
+ theme: EmotionCanvasTheme
116
+ ) => {
117
+ const {
118
+ canvas: {
119
+ palette: {primary: themePrimary},
120
+ },
121
+ } = theme;
122
+
123
+ switch (variant) {
124
+ case undefined:
125
+ default:
126
+ return {
127
+ default: {
128
+ background: themePrimary.main,
129
+ icon: themePrimary.contrast,
130
+ label: themePrimary.contrast,
131
+ },
132
+ hover: {
133
+ background: themePrimary.dark,
134
+ },
135
+ active: {
136
+ background: themePrimary.darkest,
137
+ },
138
+ focus: {
139
+ background: themePrimary.main,
140
+ },
141
+ disabled: {
142
+ background: themePrimary.main,
143
+ },
144
+ };
145
+
146
+ case 'inverse':
147
+ return {
148
+ default: {
149
+ background: colors.frenchVanilla100,
150
+ icon: colors.blackPepper400,
151
+ label: colors.blackPepper400,
152
+ labelData: colors.blackPepper400,
153
+ },
154
+ hover: {
155
+ background: colors.soap300,
156
+ icon: colors.blackPepper500,
157
+ label: colors.blackPepper500,
158
+ labelData: colors.blackPepper500,
159
+ },
160
+ active: {
161
+ background: colors.soap300,
162
+ icon: colors.blackPepper500,
163
+ label: colors.blackPepper500,
164
+ labelData: colors.blackPepper500,
165
+ },
166
+ focus: {
167
+ background: colors.frenchVanilla100,
168
+ border: colors.blackPepper400,
169
+ icon: colors.blackPepper400,
170
+ label: colors.blackPepper400,
171
+ labelData: colors.blackPepper400,
172
+ focusRing: focusRing(
173
+ {
174
+ separation: 1,
175
+ innerColor: colors.blackPepper500,
176
+ outerColor: colors.frenchVanilla100,
177
+ },
178
+ theme
179
+ ),
180
+ },
181
+ // Identical to inverse 'default' styles. ButtonContainer will set opacity to 40%
182
+ disabled: {
183
+ background: colors.frenchVanilla100,
184
+ icon: colors.blackPepper400,
185
+ label: colors.blackPepper400,
186
+ labelData: colors.blackPepper400,
187
+ },
188
+ };
189
+ }
190
+ };
@@ -10,7 +10,7 @@ import {
10
10
  focusRing,
11
11
  } from '@workday/canvas-kit-react/common';
12
12
  import {CanvasSystemIcon} from '@workday/design-assets-types';
13
- import {ButtonColors} from './types';
13
+ import {ButtonColors, ButtonSizes, IconPositions} from './types';
14
14
  import {ButtonContainer, ButtonLabel, ButtonLabelData, ButtonLabelIcon} from './parts';
15
15
 
16
16
  export interface SecondaryButtonProps extends Themeable, GrowthBehavior {
@@ -20,10 +20,12 @@ export interface SecondaryButtonProps extends Themeable, GrowthBehavior {
20
20
  */
21
21
  variant?: 'inverse' | undefined;
22
22
  /**
23
- * The size of the Button.
23
+ * There are four button sizes: `extraSmall`, `small`, `medium`, and `large`.
24
+ * If no size is provided, it will default to `medium`.
25
+ *
24
26
  * @default 'medium'
25
27
  */
26
- size?: 'small' | 'medium' | 'large';
28
+ size?: ButtonSizes;
27
29
  /**
28
30
  * The data label of the Button.
29
31
  * Note: not displayed at `small` size
@@ -35,10 +37,11 @@ export interface SecondaryButtonProps extends Themeable, GrowthBehavior {
35
37
  */
36
38
  icon?: CanvasSystemIcon;
37
39
  /**
38
- * The position of the TertiaryButton icon.
40
+ * Button icon positions can either be `left` or `right`.
41
+ * If no value is provided, it defaults to `left`.
39
42
  * @default 'left'
40
43
  */
41
- iconPosition?: 'left' | 'right';
44
+ iconPosition?: IconPositions;
42
45
  /**
43
46
  * If set to `true`, transform the icon's x-axis to mirror the graphic
44
47
  * @default false
@@ -47,6 +50,16 @@ export interface SecondaryButtonProps extends Themeable, GrowthBehavior {
47
50
  children?: React.ReactNode;
48
51
  }
49
52
 
53
+ // Button sizes where data labels are enabled
54
+ const dataLabelSizes = ['medium', 'large'];
55
+ // All disabled buttons are set to 40% opacity.
56
+ // This will eventually live in the ButtonContainer styles, but for now we're scoping it to Primary, Secondary, and Tertiary buttons.
57
+ const disabledButtonOpacity = {
58
+ '&:disabled, &:disabled:active': {
59
+ opacity: 0.4,
60
+ },
61
+ };
62
+
50
63
  export const SecondaryButton = createComponent('button')({
51
64
  displayName: 'SecondaryButton',
52
65
  Component: (
@@ -71,9 +84,10 @@ export const SecondaryButton = createComponent('button')({
71
84
  as={Element}
72
85
  colors={getSecondaryButtonColors(variant, theme)}
73
86
  size={size}
87
+ extraStyles={disabledButtonOpacity}
74
88
  {...elemProps}
75
89
  >
76
- {icon && size !== 'small' && iconPosition === 'left' && (
90
+ {icon && iconPosition === 'left' && (
77
91
  <ButtonLabelIcon
78
92
  size={size}
79
93
  iconPosition={iconPosition}
@@ -82,8 +96,8 @@ export const SecondaryButton = createComponent('button')({
82
96
  />
83
97
  )}
84
98
  <ButtonLabel>{children}</ButtonLabel>
85
- {dataLabel && size !== 'small' && <ButtonLabelData>{dataLabel}</ButtonLabelData>}
86
- {icon && size !== 'small' && iconPosition === 'right' && (
99
+ {dataLabel && dataLabelSizes.includes(size) && <ButtonLabelData>{dataLabel}</ButtonLabelData>}
100
+ {icon && iconPosition === 'right' && (
87
101
  <ButtonLabelIcon
88
102
  size={size}
89
103
  iconPosition={iconPosition}
@@ -136,12 +150,13 @@ export const getSecondaryButtonColors = (
136
150
  label: colors.blackPepper400,
137
151
  labelData: colors.blackPepper400,
138
152
  },
153
+ // Identical to 'default' styles. ButtonContainer will set opacity to 40%
139
154
  disabled: {
140
155
  background: 'transparent',
141
- border: 'rgba(30, 30, 30, 0.4)', // Black Pepper 400 @ 40%
142
- icon: 'rgba(30, 30, 30, 0.4)', // Black Pepper 400 @ 40%
143
- label: 'rgba(30, 30, 30, 0.4)', // Black Pepper 400 @ 40%
144
- labelData: 'rgba(30, 30, 30, 0.4)', // Black Pepper 400 @ 40%
156
+ border: colors.blackPepper400,
157
+ icon: colors.blackPepper400,
158
+ label: colors.blackPepper400,
159
+ labelData: colors.blackPepper400,
145
160
  },
146
161
  };
147
162
  case 'inverse':
@@ -180,12 +195,12 @@ export const getSecondaryButtonColors = (
180
195
  theme
181
196
  ),
182
197
  },
198
+ // Identical to inverse 'default' styles. ButtonContainer will set opacity to 40%
183
199
  disabled: {
184
200
  background: 'transparent',
185
- border: 'rgba(255, 255, 255, 0.4)', // French Vanilla 400 @ 40%
186
- icon: 'rgba(255, 255, 255, 0.4)', // French Vanilla 400 @ 40%
187
- label: 'rgba(255, 255, 255, 0.4)', // French Vanilla 400 @ 40%
188
- labelData: 'rgba(255, 255, 255, 0.4)', // French Vanilla 400 @ 40%
201
+ border: colors.frenchVanilla100,
202
+ icon: colors.frenchVanilla100,
203
+ label: colors.frenchVanilla100,
189
204
  },
190
205
  };
191
206
  }
@@ -7,9 +7,9 @@ import {
7
7
  EmotionCanvasTheme,
8
8
  createComponent,
9
9
  } from '@workday/canvas-kit-react/common';
10
- import {colors, space, type, borderRadius} from '@workday/canvas-kit-react/tokens';
10
+ import {colors, space, borderRadius} from '@workday/canvas-kit-react/tokens';
11
11
  import {CanvasSystemIcon} from '@workday/design-assets-types';
12
- import {ButtonColors} from './types';
12
+ import {ButtonColors, TertiaryButtonSizes, IconPositions} from './types';
13
13
  import {ButtonContainer, ButtonLabelIcon, ButtonLabel} from './parts';
14
14
 
15
15
  export interface TertiaryButtonProps extends Themeable {
@@ -19,15 +19,18 @@ export interface TertiaryButtonProps extends Themeable {
19
19
  */
20
20
  variant?: 'inverse' | undefined;
21
21
  /**
22
- * The size of the TertiaryButton.
22
+ * There are three button sizes: `extraSmall`, `small`, and `medium`.
23
+ * If no size is provided, it will default to `medium`.
24
+ *
23
25
  * @default 'medium'
24
26
  */
25
- size?: 'small' | 'medium';
27
+ size?: TertiaryButtonSizes;
26
28
  /**
27
- * The position of the TertiaryButton icon.
29
+ * Button icon positions can either be `left` or `right`.
30
+ * If no value is provided, it defaults to `left`.
28
31
  * @default 'left'
29
32
  */
30
- iconPosition?: 'left' | 'right';
33
+ iconPosition?: IconPositions;
31
34
  /**
32
35
  * The icon of the TertiaryButton.
33
36
  */
@@ -87,8 +90,8 @@ const getTertiaryButtonColors = (
87
90
  },
88
91
  disabled: {
89
92
  background: 'transparent',
90
- icon: 'rgba(255, 255, 255, 0.5)',
91
- label: 'rgba(255, 255, 255, 0.5)',
93
+ icon: colors.frenchVanilla100,
94
+ label: colors.frenchVanilla100,
92
95
  },
93
96
  };
94
97
  } else {
@@ -113,26 +116,34 @@ const getTertiaryButtonColors = (
113
116
  focusRing: focusRing({}, theme),
114
117
  },
115
118
  disabled: {
116
- background: 'transparent',
117
- icon: themePrimary.light,
118
- label: themePrimary.light,
119
+ icon: themePrimary.main,
120
+ label: themePrimary.main,
119
121
  },
120
122
  };
121
123
  }
122
124
  };
123
125
 
124
- const containerStyles = {
125
- borderRadius: borderRadius.m,
126
- border: '0',
127
- padding: `0 ${space.xxs}`,
128
- minWidth: 'auto',
129
- '.wdc-text-button-label': {
130
- borderBottom: '2px solid transparent',
131
- paddingTop: '2px',
132
- transition: 'border-color 0.3s',
133
- },
134
- '&:hover:not([disabled]) .wdc-text-button-label': {
135
- borderBottomColor: 'currentColor',
126
+ const getPaddingStyles = (
127
+ icon: CanvasSystemIcon | undefined,
128
+ iconPosition: 'left' | 'right'
129
+ ): string => {
130
+ // if there is an icon on the left, add 4px extra padding to the right for visual balance
131
+ if (icon && iconPosition === 'left') {
132
+ return `0 ${space.xs} 0 ${space.xxs}`;
133
+ }
134
+ // if there is an icon on the right, add 4px extra padding to the left for visual balance
135
+ if (icon && iconPosition === 'right') {
136
+ return `0 ${space.xxs} 0 ${space.xs}`;
137
+ }
138
+ // if there is no icon, return the default padding
139
+ return `0 ${space.xxs}`;
140
+ };
141
+
142
+ // All disabled buttons are set to 40% opacity.
143
+ // This will eventually live in the ButtonContainer styles, but for now we're scoping it to Primary, Secondary, and Tertiary buttons.
144
+ const disabledButtonOpacity = {
145
+ '&:disabled, &:disabled:active': {
146
+ opacity: 0.4,
136
147
  },
137
148
  };
138
149
 
@@ -155,19 +166,17 @@ export const TertiaryButton = createComponent('button')({
155
166
  ref,
156
167
  Element
157
168
  ) => {
158
- // Note: We don't use ButtonLabel because the label styles differ from other button types
159
- const allContainerStyles: CSSObject = allCaps
160
- ? {
161
- ...containerStyles,
162
- textTransform: 'uppercase',
163
- fontWeight: type.properties.fontWeights.bold,
164
- fontSize: size === 'medium' ? type.properties.fontSizes[16] : undefined,
165
- letterSpacing: '.5px',
166
- }
167
- : {
168
- ...containerStyles,
169
- fontSize: size === 'medium' ? type.properties.fontSizes[14] : undefined,
170
- };
169
+ const allContainerStyles: CSSObject = {
170
+ borderRadius: borderRadius.m,
171
+ border: '0',
172
+ padding: getPaddingStyles(icon, iconPosition),
173
+ minWidth: 'auto',
174
+ textTransform: allCaps ? 'uppercase' : undefined,
175
+ '.wdc-text-button-label': {
176
+ textDecoration: 'underline',
177
+ },
178
+ ...disabledButtonOpacity,
179
+ };
171
180
 
172
181
  return (
173
182
  <ButtonContainer
@@ -10,7 +10,7 @@ import {
10
10
  EmotionCanvasTheme,
11
11
  StyledType,
12
12
  } from '@workday/canvas-kit-react/common';
13
- import {ButtonColors} from '../types';
13
+ import {ButtonColors, ButtonSizes} from '../types';
14
14
  import {buttonLabelDataClassName} from './ButtonLabelData';
15
15
 
16
16
  export interface ButtonContainerProps
@@ -18,10 +18,12 @@ export interface ButtonContainerProps
18
18
  GrowthBehavior {
19
19
  colors?: ButtonColors;
20
20
  /**
21
- * The size of the Button.
21
+ * There are four button sizes: `extraSmall`, `small`, `medium`, and `large`.
22
+ * If no size is provided, it will default to `medium`.
23
+ *
22
24
  * @default 'medium'
23
25
  */
24
- size?: 'small' | 'medium' | 'large';
26
+ size?: ButtonSizes;
25
27
  /**
26
28
  * The ref to the button that the styled component renders.
27
29
  */
@@ -110,12 +112,13 @@ export const ButtonContainer = styled('button', {
110
112
  switch (size) {
111
113
  case 'large':
112
114
  return {
113
- fontSize: type.properties.fontSizes[16],
115
+ ...type.levels.body.small,
116
+ fontWeight: type.properties.fontWeights.bold,
114
117
  minWidth: '112px',
115
118
  height: '48px',
116
119
  padding: `0 ${space.l}`,
117
120
  '& > * ': {
118
- margin: `0 ${spaceNumbers.xs / 2}px`,
121
+ margin: `0 ${spaceNumbers.xxs / 2}px`,
119
122
  },
120
123
  };
121
124
  case 'medium':
@@ -137,6 +140,16 @@ export const ButtonContainer = styled('button', {
137
140
  margin: `0 ${spaceNumbers.xxxs / 2}px`,
138
141
  },
139
142
  };
143
+ case 'extraSmall':
144
+ return {
145
+ ...type.levels.subtext.medium,
146
+ fontWeight: type.properties.fontWeights.bold,
147
+ height: space.m,
148
+ padding: `0 ${space.xs}`,
149
+ '& > * ': {
150
+ margin: `0 ${spaceNumbers.xxxs / 2}px`,
151
+ },
152
+ };
140
153
  }
141
154
  },
142
155
  ({grow}) => grow && {width: '100%', maxWidth: '100%'},
@@ -5,22 +5,25 @@ import isPropValid from '@emotion/is-prop-valid';
5
5
  import {SystemIcon} from '@workday/canvas-kit-react/icon';
6
6
  import {styled} from '@workday/canvas-kit-react/common';
7
7
 
8
+ import {ButtonSizes, IconPositions} from '../types';
8
9
  export interface ButtonLabelIconProps {
9
10
  /**
10
- * The size of the Button.
11
+ * There are four button sizes: `extraSmall`, `small`, `medium`, and `large`.
12
+ *
11
13
  * @default 'medium'
12
14
  */
13
- size?: 'small' | 'medium' | 'large';
15
+ size?: ButtonSizes;
14
16
  /**
15
17
  * The icon of the Button.
16
18
  * Note: not displayed at `small` size
17
19
  */
18
20
  icon?: CanvasSystemIcon;
19
21
  /**
20
- * The position of the TertiaryButton icon.
22
+ * Button icon positions can either be `left` or `right`.
23
+ * If no value is provided, it defaults to `left`.
21
24
  * @default 'left'
22
25
  */
23
- iconPosition?: 'left' | 'right';
26
+ iconPosition?: IconPositions;
24
27
  /**
25
28
  * If set to `true`, transform the icon's x-axis to mirror the graphic
26
29
  * @default false
@@ -28,8 +31,29 @@ export interface ButtonLabelIconProps {
28
31
  shouldMirrorIcon?: boolean;
29
32
  }
30
33
 
31
- const ICON_SIZE = 24;
32
- const SMALL_ICON_SIZE = 20;
34
+ const iconSizes: Record<ButtonSizes, number> = {
35
+ extraSmall: 18,
36
+ small: 20,
37
+ medium: 20,
38
+ large: 24,
39
+ };
40
+
41
+ const getIconPositionStyles = ({iconPosition, size}: ButtonLabelIconProps) => {
42
+ // Adjust margin values for visual balance, large buttons require 8px
43
+ const balancingMargin = size === 'large' ? space.xxs : space.xxxs;
44
+ // iconPosition can only be "right", "left", or undefined (defaults to "left")
45
+ if (iconPosition === 'right') {
46
+ return {
47
+ marginLeft: undefined,
48
+ marginRight: `-${balancingMargin} !important`,
49
+ };
50
+ } else {
51
+ return {
52
+ marginLeft: `-${balancingMargin} !important`,
53
+ marginRight: undefined,
54
+ };
55
+ }
56
+ };
33
57
 
34
58
  const ButtonLabelIconStyled = styled('span', {
35
59
  shouldForwardProp: prop => isPropValid(prop) && prop !== 'size',
@@ -38,13 +62,10 @@ const ButtonLabelIconStyled = styled('span', {
38
62
  display: 'inline-block',
39
63
  },
40
64
  ({size}) => ({
41
- width: size === 'small' ? SMALL_ICON_SIZE : ICON_SIZE,
42
- height: size === 'small' ? SMALL_ICON_SIZE : ICON_SIZE,
65
+ width: size ? iconSizes[size] : iconSizes.medium,
66
+ height: size ? iconSizes[size] : iconSizes.medium,
43
67
  }),
44
- ({iconPosition}) => ({
45
- marginLeft: iconPosition === 'right' ? undefined : `-${space.xxxs} !important`,
46
- marginRight: iconPosition === 'right' ? `-${space.xxxs} !important` : undefined,
47
- })
68
+ getIconPositionStyles
48
69
  );
49
70
 
50
71
  export const ButtonLabelIcon = ({
@@ -54,12 +75,11 @@ export const ButtonLabelIcon = ({
54
75
  shouldMirrorIcon = false,
55
76
  ...elemProps
56
77
  }: ButtonLabelIconProps) => {
57
- /* istanbul ignore next line for coverage */
58
78
  if (icon === undefined) {
59
79
  return null;
60
80
  }
61
81
 
62
- const iconSize = size === 'small' ? SMALL_ICON_SIZE : undefined;
82
+ const iconSize = size ? iconSizes[size] : undefined;
63
83
 
64
84
  return (
65
85
  <ButtonLabelIconStyled iconPosition={iconPosition} size={size} {...elemProps}>
@@ -20,3 +20,14 @@ export interface ButtonColors {
20
20
  };
21
21
  disabled: ButtonStateColors;
22
22
  }
23
+
24
+ /**
25
+ * There are four button sizes: `extraSmall`, `small`, `medium`, and `large`.
26
+ * If no size is provided, it will default to `medium`.
27
+ *
28
+ * @default 'medium'
29
+ */
30
+ export type ButtonSizes = 'extraSmall' | 'small' | 'medium' | 'large';
31
+ // TODO: Remove TertiaryButtonSizes in favor of button sizes when we add Tertiary large
32
+ export type TertiaryButtonSizes = 'extraSmall' | 'small' | 'medium';
33
+ export type IconPositions = 'left' | 'right';