uikit-react-public 0.50.0 → 0.50.2
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/dist/components/Alert/Alert.d.ts +4 -2
- package/dist/components/Alert/Alert.stories.d.ts +10 -1
- package/dist/components/Button/Button.d.ts +14 -4
- package/dist/components/Button/Button.stories.d.ts +29 -2
- package/dist/components/Button/style/buttonPrimarySubtleStyle.d.ts +1 -1
- package/dist/components/Button/style/buttonPrimarySuccessStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonSecondaryStyle.d.ts +1 -1
- package/dist/components/Button/style/buttonSecondarySubtleStyle.d.ts +1 -1
- package/dist/components/Button/style/buttonTertiaryDestructiveNoPaddingStyle.d.ts +4 -0
- package/dist/components/Button/style/buttonTertiaryDestructiveStyle.d.ts +1 -1
- package/dist/components/Button/style/buttonTertiaryNoPaddingStyle.d.ts +1 -1
- package/dist/components/Button/style/buttonTertiaryStyle.d.ts +1 -1
- package/dist/index.js +4485 -4373
- package/lib/components/Alert/Alert.mdx +13 -1
- package/lib/components/Alert/Alert.stories.tsx +29 -0
- package/lib/components/Alert/Alert.tsx +32 -1
- package/lib/components/Alert/__tests__/Alert.test.tsx +78 -24
- package/lib/components/Button/Button.mdx +57 -9
- package/lib/components/Button/Button.stories.tsx +72 -0
- package/lib/components/Button/Button.tsx +68 -26
- package/lib/components/Button/__tests__/Button.test.tsx +159 -1
- package/lib/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +11 -11
- package/lib/components/Button/style/buttonAccentStyle.ts +2 -0
- package/lib/components/Button/style/buttonPrimaryDestructiveStyle.ts +2 -0
- package/lib/components/Button/style/buttonPrimaryStyle.ts +2 -0
- package/lib/components/Button/style/buttonPrimarySubtleStyle.ts +10 -11
- package/lib/components/Button/style/buttonPrimarySuccessStyle.ts +39 -0
- package/lib/components/Button/style/buttonPrimaryWarningStyle.ts +2 -0
- package/lib/components/Button/style/buttonSecondaryDestructiveStyle.ts +13 -7
- package/lib/components/Button/style/buttonSecondaryStyle.ts +49 -16
- package/lib/components/Button/style/buttonSecondarySubtleStyle.ts +15 -13
- package/lib/components/Button/style/buttonTertiaryDestructiveNoPaddingStyle.ts +34 -0
- package/lib/components/Button/style/buttonTertiaryDestructiveStyle.ts +9 -8
- package/lib/components/Button/style/buttonTertiaryNoPaddingStyle.ts +13 -15
- package/lib/components/Button/style/buttonTertiaryStyle.ts +10 -9
- package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ReactElement,
|
|
5
5
|
ElementType,
|
|
6
6
|
ComponentPropsWithRef,
|
|
7
|
+
cloneElement,
|
|
7
8
|
memo,
|
|
8
9
|
} from 'react';
|
|
9
10
|
import { css, cx } from '@emotion/css';
|
|
@@ -19,7 +20,9 @@ import buttonTertiaryStyle from './style/buttonTertiaryStyle';
|
|
|
19
20
|
import buttonPrimaryDestructiveStyle from './style/buttonPrimaryDestructiveStyle';
|
|
20
21
|
import buttonSecondaryDestructiveStyle from './style/buttonSecondaryDestructiveStyle';
|
|
21
22
|
import buttonTertiaryDestructiveStyle from './style/buttonTertiaryDestructiveStyle';
|
|
23
|
+
import buttonTertiaryDestructiveNoPaddingStyle from './style/buttonTertiaryDestructiveNoPaddingStyle';
|
|
22
24
|
import buttonPrimaryWarningStyle from './style/buttonPrimaryWarningStyle';
|
|
25
|
+
import buttonPrimarySuccessStyle from './style/buttonPrimarySuccessStyle';
|
|
23
26
|
import buttonPrimarySubtleStyle from './style/buttonPrimarySubtleStyle';
|
|
24
27
|
import buttonSecondarySubtleStyle from './style/buttonSecondarySubtleStyle';
|
|
25
28
|
import buttonTertiaryNoPaddingStyle from './style/buttonTertiaryNoPaddingStyle';
|
|
@@ -39,12 +42,15 @@ export type ButtonVariant =
|
|
|
39
42
|
| 'primary-destructive'
|
|
40
43
|
| 'secondary-destructive'
|
|
41
44
|
| 'tertiary-destructive'
|
|
42
|
-
| '
|
|
45
|
+
| 'tertiary-destructive-no-padding'
|
|
46
|
+
| 'primary-warning'
|
|
47
|
+
| 'primary-success';
|
|
43
48
|
|
|
44
49
|
const DESTRUCTIVE_VARIANT_MAP: Partial<Record<ButtonVariant, ButtonVariant>> = {
|
|
45
50
|
primary: 'primary-destructive',
|
|
46
51
|
secondary: 'secondary-destructive',
|
|
47
52
|
tertiary: 'tertiary-destructive',
|
|
53
|
+
'tertiary-no-padding': 'tertiary-destructive-no-padding',
|
|
48
54
|
};
|
|
49
55
|
|
|
50
56
|
// Legacy size values from the old Button API
|
|
@@ -52,13 +58,17 @@ type LegacySize = 'default';
|
|
|
52
58
|
|
|
53
59
|
export interface ButtonBaseProps {
|
|
54
60
|
variant?: ButtonVariant;
|
|
55
|
-
/** @deprecated Use
|
|
61
|
+
/** @deprecated Use a destructive variant directly */
|
|
56
62
|
destructive?: boolean;
|
|
57
63
|
size?: 'xsmall' | 'small' | 'medium' | 'large' | LegacySize;
|
|
64
|
+
/** Whether the button is rendered on a light background */
|
|
65
|
+
onLight?: boolean;
|
|
58
66
|
selected?: boolean;
|
|
59
67
|
disabled?: boolean;
|
|
60
|
-
icon?: ReactElement
|
|
68
|
+
icon?: ReactElement<{ className?: string }>;
|
|
61
69
|
iconPosition?: 'left' | 'right';
|
|
70
|
+
leftIcon?: ReactElement<{ className?: string }>;
|
|
71
|
+
rightIcon?: ReactElement<{ className?: string }>;
|
|
62
72
|
tooltip?: string;
|
|
63
73
|
loading?: boolean;
|
|
64
74
|
fullWidth?: boolean;
|
|
@@ -92,7 +102,7 @@ const normalizeVariantProp = (
|
|
|
92
102
|
|
|
93
103
|
if (!destructiveVariant) {
|
|
94
104
|
console.warn(
|
|
95
|
-
`Button variant '${variant}' does not support the destructive prop. Use a destructive variant explicitly, or use one of: primary, secondary, tertiary.`
|
|
105
|
+
`Button variant '${variant}' does not support the destructive prop. Use a destructive variant explicitly, or use one of: primary, secondary, tertiary, tertiary-no-padding.`
|
|
96
106
|
);
|
|
97
107
|
return variant;
|
|
98
108
|
}
|
|
@@ -102,13 +112,16 @@ const normalizeVariantProp = (
|
|
|
102
112
|
|
|
103
113
|
const Button = <C extends ElementType = 'button'>({
|
|
104
114
|
as,
|
|
105
|
-
variant
|
|
115
|
+
variant,
|
|
106
116
|
destructive = false,
|
|
107
117
|
size = 'medium',
|
|
118
|
+
onLight = true,
|
|
108
119
|
selected = false,
|
|
109
120
|
disabled = false,
|
|
110
121
|
icon,
|
|
111
122
|
iconPosition = 'left',
|
|
123
|
+
leftIcon,
|
|
124
|
+
rightIcon,
|
|
112
125
|
tooltip,
|
|
113
126
|
loading = false,
|
|
114
127
|
fullWidth = false,
|
|
@@ -125,7 +138,10 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
125
138
|
const [isHovered, setIsHovered] = useState(false);
|
|
126
139
|
const [theme] = useTheme();
|
|
127
140
|
|
|
128
|
-
const resolvedVariant = normalizeVariantProp(
|
|
141
|
+
const resolvedVariant = normalizeVariantProp(
|
|
142
|
+
variant ?? (destructive ? 'primary' : 'accent'),
|
|
143
|
+
destructive
|
|
144
|
+
);
|
|
129
145
|
const resolvedSize = normalizeSizeprop(size);
|
|
130
146
|
const buttonTypography = {
|
|
131
147
|
xsmall: theme.typography.body.smMedium,
|
|
@@ -136,7 +152,7 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
136
152
|
|
|
137
153
|
const baseStyle = css`
|
|
138
154
|
all: unset;
|
|
139
|
-
border:
|
|
155
|
+
border: 0;
|
|
140
156
|
display: inline-flex;
|
|
141
157
|
align-items: center;
|
|
142
158
|
justify-content: center;
|
|
@@ -160,14 +176,33 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
160
176
|
}
|
|
161
177
|
`;
|
|
162
178
|
|
|
163
|
-
const
|
|
179
|
+
const contentIconSize = {
|
|
180
|
+
xsmall: 16,
|
|
181
|
+
small: 20,
|
|
182
|
+
medium: 24,
|
|
183
|
+
large: 24,
|
|
184
|
+
}[resolvedSize];
|
|
185
|
+
const iconOnlySize = resolvedSize === 'xsmall' ? 20 : 24;
|
|
186
|
+
const spinnerSize = resolvedSize === 'xsmall' ? 20 : 24;
|
|
164
187
|
const paddingPx = resolvedSize === 'xsmall' ? 8 : 16;
|
|
165
188
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
189
|
+
const iconStyle = css`
|
|
190
|
+
color: var(--ucl-uikit-button-icon-colour, currentColor);
|
|
191
|
+
width: ${children ? contentIconSize : iconOnlySize}px;
|
|
192
|
+
height: ${children ? contentIconSize : iconOnlySize}px;
|
|
170
193
|
`;
|
|
194
|
+
const styleIcon = (iconElement?: ReactElement<{ className?: string }>) =>
|
|
195
|
+
iconElement
|
|
196
|
+
? cloneElement(iconElement, {
|
|
197
|
+
className: cx(iconElement.props.className, iconStyle),
|
|
198
|
+
})
|
|
199
|
+
: undefined;
|
|
200
|
+
const styledLeftIcon = styleIcon(
|
|
201
|
+
leftIcon ?? (iconPosition === 'left' ? icon : undefined)
|
|
202
|
+
);
|
|
203
|
+
const styledRightIcon = styleIcon(
|
|
204
|
+
rightIcon ?? (iconPosition === 'right' ? icon : undefined)
|
|
205
|
+
);
|
|
171
206
|
|
|
172
207
|
const sizeExtraSmallStyle = css`
|
|
173
208
|
height: 32px;
|
|
@@ -196,33 +231,31 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
196
231
|
const variantStyle = {
|
|
197
232
|
accent: buttonAccentStyle(theme, selected, disabled, loading),
|
|
198
233
|
primary: buttonPrimaryStyle(theme, selected, disabled, loading),
|
|
199
|
-
secondary: buttonSecondaryStyle(
|
|
200
|
-
tertiary: buttonTertiaryStyle(
|
|
234
|
+
secondary: buttonSecondaryStyle(
|
|
201
235
|
theme,
|
|
202
236
|
selected,
|
|
203
237
|
disabled,
|
|
204
238
|
loading,
|
|
205
|
-
|
|
239
|
+
onLight
|
|
206
240
|
),
|
|
241
|
+
tertiary: buttonTertiaryStyle(theme, selected, disabled, loading),
|
|
207
242
|
'primary-subtle': buttonPrimarySubtleStyle(
|
|
208
243
|
theme,
|
|
209
244
|
selected,
|
|
210
245
|
disabled,
|
|
211
|
-
loading
|
|
212
|
-
paddingPx
|
|
246
|
+
loading
|
|
213
247
|
),
|
|
214
248
|
'secondary-subtle': buttonSecondarySubtleStyle(
|
|
215
249
|
theme,
|
|
216
250
|
selected,
|
|
217
251
|
disabled,
|
|
218
|
-
loading
|
|
219
|
-
paddingPx
|
|
252
|
+
loading
|
|
220
253
|
),
|
|
221
254
|
'tertiary-no-padding': buttonTertiaryNoPaddingStyle(
|
|
222
255
|
theme,
|
|
223
256
|
disabled,
|
|
224
257
|
loading,
|
|
225
|
-
|
|
258
|
+
onLight
|
|
226
259
|
),
|
|
227
260
|
'primary-destructive': buttonPrimaryDestructiveStyle(
|
|
228
261
|
theme,
|
|
@@ -240,8 +273,12 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
240
273
|
theme,
|
|
241
274
|
selected,
|
|
242
275
|
disabled,
|
|
243
|
-
loading
|
|
244
|
-
|
|
276
|
+
loading
|
|
277
|
+
),
|
|
278
|
+
'tertiary-destructive-no-padding': buttonTertiaryDestructiveNoPaddingStyle(
|
|
279
|
+
theme,
|
|
280
|
+
disabled,
|
|
281
|
+
loading
|
|
245
282
|
),
|
|
246
283
|
'primary-warning': buttonPrimaryWarningStyle(
|
|
247
284
|
theme,
|
|
@@ -249,6 +286,12 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
249
286
|
disabled,
|
|
250
287
|
loading
|
|
251
288
|
),
|
|
289
|
+
'primary-success': buttonPrimarySuccessStyle(
|
|
290
|
+
theme,
|
|
291
|
+
selected,
|
|
292
|
+
disabled,
|
|
293
|
+
loading
|
|
294
|
+
),
|
|
252
295
|
}[resolvedVariant];
|
|
253
296
|
|
|
254
297
|
const commonDisabledStyle = css`
|
|
@@ -271,7 +314,6 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
271
314
|
variantStyle,
|
|
272
315
|
disabled && commonDisabledStyle,
|
|
273
316
|
loading && loadingStyle,
|
|
274
|
-
!children && iconOnlyStyle,
|
|
275
317
|
className
|
|
276
318
|
);
|
|
277
319
|
|
|
@@ -294,15 +336,15 @@ const Button = <C extends ElementType = 'button'>({
|
|
|
294
336
|
>
|
|
295
337
|
{loading ? (
|
|
296
338
|
<Spinner
|
|
297
|
-
size={
|
|
339
|
+
size={spinnerSize}
|
|
298
340
|
strokeWidth={8}
|
|
299
341
|
inheritColour
|
|
300
342
|
/>
|
|
301
343
|
) : (
|
|
302
344
|
<>
|
|
303
|
-
{
|
|
345
|
+
{styledLeftIcon}
|
|
304
346
|
{children}
|
|
305
|
-
{
|
|
347
|
+
{styledRightIcon}
|
|
306
348
|
</>
|
|
307
349
|
)}
|
|
308
350
|
</Component>
|
|
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
|
|
|
3
3
|
import userEvent from '@testing-library/user-event';
|
|
4
4
|
import Button from '../Button';
|
|
5
5
|
import Icon from '../../Icon';
|
|
6
|
-
import { darkTheme, ThemeContextProvider } from '../../../theme';
|
|
6
|
+
import { darkTheme, theme, ThemeContextProvider } from '../../../theme';
|
|
7
7
|
|
|
8
8
|
const hexToRgb = (hex: string) => {
|
|
9
9
|
const value = hex.replace('#', '');
|
|
@@ -79,6 +79,25 @@ describe('Button', () => {
|
|
|
79
79
|
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
test('renders icons on both sides of the label', () => {
|
|
83
|
+
render(
|
|
84
|
+
<ThemeContextProvider>
|
|
85
|
+
<Button
|
|
86
|
+
leftIcon={<Icon.ChevronRight />}
|
|
87
|
+
rightIcon={<Icon.ChevronRight />}
|
|
88
|
+
size='xsmall'
|
|
89
|
+
>
|
|
90
|
+
Action
|
|
91
|
+
</Button>
|
|
92
|
+
</ThemeContextProvider>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const icons = screen.getAllByTestId('ucl-uikit-icon');
|
|
96
|
+
expect(icons).toHaveLength(2);
|
|
97
|
+
expect(icons[0]).toHaveStyle({ width: '16px', height: '16px' });
|
|
98
|
+
expect(icons[1]).toHaveStyle({ width: '16px', height: '16px' });
|
|
99
|
+
});
|
|
100
|
+
|
|
82
101
|
test('snapshot: loading', () => {
|
|
83
102
|
const renderResult = render(
|
|
84
103
|
<ThemeContextProvider>
|
|
@@ -255,6 +274,26 @@ describe('Button', () => {
|
|
|
255
274
|
);
|
|
256
275
|
|
|
257
276
|
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
277
|
+
expect(getComputedStyle(screen.getByRole('button')).backgroundColor).toBe(
|
|
278
|
+
hexToRgb(theme.colour.fill.critical)
|
|
279
|
+
);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('maps legacy destructive prop for the no-padding variant', () => {
|
|
283
|
+
render(
|
|
284
|
+
<ThemeContextProvider>
|
|
285
|
+
<Button
|
|
286
|
+
variant='tertiary-no-padding'
|
|
287
|
+
destructive
|
|
288
|
+
>
|
|
289
|
+
Delete
|
|
290
|
+
</Button>
|
|
291
|
+
</ThemeContextProvider>
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(getComputedStyle(screen.getByRole('button')).color).toBe(
|
|
295
|
+
hexToRgb(theme.colour.text.critical)
|
|
296
|
+
);
|
|
258
297
|
});
|
|
259
298
|
|
|
260
299
|
test('warns when destructive prop is used with unsupported variant', () => {
|
|
@@ -289,6 +328,7 @@ describe('Button', () => {
|
|
|
289
328
|
['accent', darkTheme.colour.text.inverse],
|
|
290
329
|
['primary-destructive', darkTheme.colour.text.inverse],
|
|
291
330
|
['primary-warning', darkTheme.colour.text.caution],
|
|
331
|
+
['primary-success', darkTheme.colour.text.inverse],
|
|
292
332
|
] as const)(
|
|
293
333
|
'uses readable semantic text colour for dark %s variant',
|
|
294
334
|
(variant, expectedColour) => {
|
|
@@ -320,4 +360,122 @@ describe('Button', () => {
|
|
|
320
360
|
`box-shadow:${expectedFocusShadow.replace(/\s/g, '')}`
|
|
321
361
|
);
|
|
322
362
|
});
|
|
363
|
+
|
|
364
|
+
test('uses the inverse icon colour for the success variant', () => {
|
|
365
|
+
render(
|
|
366
|
+
<ThemeContextProvider>
|
|
367
|
+
<Button
|
|
368
|
+
variant='primary-success'
|
|
369
|
+
icon={<Icon.ChevronRight />}
|
|
370
|
+
>
|
|
371
|
+
Success
|
|
372
|
+
</Button>
|
|
373
|
+
</ThemeContextProvider>
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
expect(
|
|
377
|
+
getComputedStyle(screen.getByRole('button'))
|
|
378
|
+
.getPropertyValue('--ucl-uikit-button-icon-colour')
|
|
379
|
+
.trim()
|
|
380
|
+
).toBe(theme.colour.icon.inverse);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test.each([
|
|
384
|
+
['xsmall', '32px', '16px'],
|
|
385
|
+
['small', '40px', '20px'],
|
|
386
|
+
['medium', '48px', '24px'],
|
|
387
|
+
['large', '56px', '24px'],
|
|
388
|
+
] as const)(
|
|
389
|
+
'matches the Figma dimensions for the %s size',
|
|
390
|
+
(size, expectedHeight, expectedIconSize) => {
|
|
391
|
+
render(
|
|
392
|
+
<ThemeContextProvider>
|
|
393
|
+
<Button
|
|
394
|
+
icon={<Icon.ChevronRight />}
|
|
395
|
+
size={size}
|
|
396
|
+
>
|
|
397
|
+
Action
|
|
398
|
+
</Button>
|
|
399
|
+
</ThemeContextProvider>
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
expect(getComputedStyle(screen.getByRole('button')).height).toBe(
|
|
403
|
+
expectedHeight
|
|
404
|
+
);
|
|
405
|
+
expect(getComputedStyle(screen.getByTestId('ucl-uikit-icon')).width).toBe(
|
|
406
|
+
expectedIconSize
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
test('uses the larger extra-small icon when the button is icon-only', () => {
|
|
412
|
+
render(
|
|
413
|
+
<ThemeContextProvider>
|
|
414
|
+
<Button
|
|
415
|
+
aria-label='Next'
|
|
416
|
+
icon={<Icon.ChevronRight />}
|
|
417
|
+
size='xsmall'
|
|
418
|
+
/>
|
|
419
|
+
</ThemeContextProvider>
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
expect(getComputedStyle(screen.getByTestId('ucl-uikit-icon')).width).toBe(
|
|
423
|
+
'20px'
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test('styles a non-SVG icon through its className contract', () => {
|
|
428
|
+
render(
|
|
429
|
+
<ThemeContextProvider>
|
|
430
|
+
<Button
|
|
431
|
+
icon={
|
|
432
|
+
<span
|
|
433
|
+
className='custom-icon'
|
|
434
|
+
data-testid='custom-icon'
|
|
435
|
+
/>
|
|
436
|
+
}
|
|
437
|
+
size='xsmall'
|
|
438
|
+
>
|
|
439
|
+
Action
|
|
440
|
+
</Button>
|
|
441
|
+
</ThemeContextProvider>
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
const icon = screen.getByTestId('custom-icon');
|
|
445
|
+
expect(icon).toHaveClass('custom-icon');
|
|
446
|
+
expect(getComputedStyle(icon).width).toBe('16px');
|
|
447
|
+
expect(getComputedStyle(icon).height).toBe('16px');
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test.each([
|
|
451
|
+
'tertiary-no-padding',
|
|
452
|
+
'tertiary-destructive-no-padding',
|
|
453
|
+
] as const)('removes padding from the %s variant', (variant) => {
|
|
454
|
+
render(
|
|
455
|
+
<ThemeContextProvider>
|
|
456
|
+
<Button variant={variant}>Action</Button>
|
|
457
|
+
</ThemeContextProvider>
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
expect(getComputedStyle(screen.getByRole('button')).padding).toBe('0px');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('uses inverse secondary tokens on a dark background', () => {
|
|
464
|
+
render(
|
|
465
|
+
<ThemeContextProvider>
|
|
466
|
+
<Button
|
|
467
|
+
onLight={false}
|
|
468
|
+
variant='secondary'
|
|
469
|
+
>
|
|
470
|
+
Action
|
|
471
|
+
</Button>
|
|
472
|
+
</ThemeContextProvider>
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
const style = getComputedStyle(screen.getByRole('button'));
|
|
476
|
+
expect(style.color).toBe(hexToRgb(theme.colour.text.brandInverse));
|
|
477
|
+
expect(document.head.textContent?.replace(/\s/g, '')).toContain(
|
|
478
|
+
`outline:${theme.border.b2}solid${theme.colour.border.brandInverse}`
|
|
479
|
+
);
|
|
480
|
+
});
|
|
323
481
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
exports[`Button > maps legacy destructive prop to destructive variants 1`] = `
|
|
4
4
|
<button
|
|
5
5
|
aria-disabled="false"
|
|
6
|
-
class="ucl-uikit-button css-
|
|
6
|
+
class="ucl-uikit-button css-usvl64"
|
|
7
7
|
data-testid="ucl-uikit-button"
|
|
8
8
|
>
|
|
9
9
|
Delete
|
|
@@ -13,7 +13,7 @@ exports[`Button > maps legacy destructive prop to destructive variants 1`] = `
|
|
|
13
13
|
exports[`Button > maps legacy size default to medium 1`] = `
|
|
14
14
|
<button
|
|
15
15
|
aria-disabled="false"
|
|
16
|
-
class="ucl-uikit-button css-
|
|
16
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
17
17
|
data-testid="ucl-uikit-button"
|
|
18
18
|
>
|
|
19
19
|
Legacy default size
|
|
@@ -23,7 +23,7 @@ exports[`Button > maps legacy size default to medium 1`] = `
|
|
|
23
23
|
exports[`Button > snapshot: 'as' prop with 'a' 1`] = `
|
|
24
24
|
<a
|
|
25
25
|
aria-disabled="false"
|
|
26
|
-
class="ucl-uikit-button css-
|
|
26
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
27
27
|
data-testid="ucl-uikit-button"
|
|
28
28
|
href="https://ucl.ac.uk"
|
|
29
29
|
>
|
|
@@ -34,7 +34,7 @@ exports[`Button > snapshot: 'as' prop with 'a' 1`] = `
|
|
|
34
34
|
exports[`Button > snapshot: loading 1`] = `
|
|
35
35
|
<button
|
|
36
36
|
aria-disabled="false"
|
|
37
|
-
class="ucl-uikit-button css-
|
|
37
|
+
class="ucl-uikit-button css-gbx8ga"
|
|
38
38
|
data-testid="ucl-uikit-button"
|
|
39
39
|
disabled=""
|
|
40
40
|
>
|
|
@@ -67,7 +67,7 @@ exports[`Button > snapshot: loading 1`] = `
|
|
|
67
67
|
exports[`Button > snapshot: no props 1`] = `
|
|
68
68
|
<button
|
|
69
69
|
aria-disabled="false"
|
|
70
|
-
class="ucl-uikit-button css-
|
|
70
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
71
71
|
data-testid="ucl-uikit-button"
|
|
72
72
|
/>
|
|
73
73
|
`;
|
|
@@ -75,7 +75,7 @@ exports[`Button > snapshot: no props 1`] = `
|
|
|
75
75
|
exports[`Button > snapshot: testId prop 1`] = `
|
|
76
76
|
<button
|
|
77
77
|
aria-disabled="false"
|
|
78
|
-
class="ucl-uikit-button css-
|
|
78
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
79
79
|
data-testid="test123"
|
|
80
80
|
/>
|
|
81
81
|
`;
|
|
@@ -83,7 +83,7 @@ exports[`Button > snapshot: testId prop 1`] = `
|
|
|
83
83
|
exports[`Button > snapshot: variant prop 1`] = `
|
|
84
84
|
<button
|
|
85
85
|
aria-disabled="false"
|
|
86
|
-
class="ucl-uikit-button css-
|
|
86
|
+
class="ucl-uikit-button css-1wqhdg8"
|
|
87
87
|
data-testid="ucl-uikit-button"
|
|
88
88
|
/>
|
|
89
89
|
`;
|
|
@@ -91,11 +91,11 @@ exports[`Button > snapshot: variant prop 1`] = `
|
|
|
91
91
|
exports[`Button > snapshot: with icon 1`] = `
|
|
92
92
|
<button
|
|
93
93
|
aria-disabled="false"
|
|
94
|
-
class="ucl-uikit-button css-
|
|
94
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
95
95
|
data-testid="ucl-uikit-button"
|
|
96
96
|
>
|
|
97
97
|
<svg
|
|
98
|
-
class="ucl-uikit-icon css-
|
|
98
|
+
class="ucl-uikit-icon css-qo09cr"
|
|
99
99
|
data-testid="ucl-uikit-icon"
|
|
100
100
|
fill="none"
|
|
101
101
|
focusable="false"
|
|
@@ -119,12 +119,12 @@ exports[`Button > snapshot: with icon 1`] = `
|
|
|
119
119
|
exports[`Button > snapshot: with icon and iconPosition right 1`] = `
|
|
120
120
|
<button
|
|
121
121
|
aria-disabled="false"
|
|
122
|
-
class="ucl-uikit-button css-
|
|
122
|
+
class="ucl-uikit-button css-1wtmaoy"
|
|
123
123
|
data-testid="ucl-uikit-button"
|
|
124
124
|
>
|
|
125
125
|
Download
|
|
126
126
|
<svg
|
|
127
|
-
class="ucl-uikit-icon css-
|
|
127
|
+
class="ucl-uikit-icon css-qo09cr"
|
|
128
128
|
data-testid="ucl-uikit-icon"
|
|
129
129
|
fill="none"
|
|
130
130
|
focusable="false"
|
|
@@ -17,6 +17,7 @@ const buttonAccentStyle = (
|
|
|
17
17
|
const bgActiveColour = fill.brandPressed;
|
|
18
18
|
|
|
19
19
|
const baseStyle = css`
|
|
20
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.inverse};
|
|
20
21
|
background-color: ${bgColour};
|
|
21
22
|
color: ${theme.colour.text.inverse};
|
|
22
23
|
`;
|
|
@@ -38,6 +39,7 @@ const buttonAccentStyle = (
|
|
|
38
39
|
`;
|
|
39
40
|
|
|
40
41
|
const disabledStyle = css`
|
|
42
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.disabledOnBgFill};
|
|
41
43
|
background-color: ${theme.colour.fill.disabled};
|
|
42
44
|
color: ${theme.colour.text.onBgFillDisabled};
|
|
43
45
|
`;
|
|
@@ -18,6 +18,7 @@ const buttonPrimaryDestructiveStyle = (
|
|
|
18
18
|
const bgSelectedColour = fill.criticalHover;
|
|
19
19
|
|
|
20
20
|
const baseStyle = css`
|
|
21
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.inverse};
|
|
21
22
|
background-color: ${bgColour};
|
|
22
23
|
color: ${theme.colour.text.inverse};
|
|
23
24
|
`;
|
|
@@ -39,6 +40,7 @@ const buttonPrimaryDestructiveStyle = (
|
|
|
39
40
|
`;
|
|
40
41
|
|
|
41
42
|
const disabledStyle = css`
|
|
43
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.disabledOnBgFill};
|
|
42
44
|
border-color: ${theme.colour.fill.disabled};
|
|
43
45
|
background-color: ${theme.colour.fill.disabled};
|
|
44
46
|
color: ${theme.colour.text.onBgFillDisabled};
|
|
@@ -17,6 +17,7 @@ const buttonPrimaryStyle = (
|
|
|
17
17
|
const bgActiveColour = fill.brandPressed;
|
|
18
18
|
|
|
19
19
|
const baseStyle = css`
|
|
20
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.brandInverse};
|
|
20
21
|
background-color: ${bgColour};
|
|
21
22
|
color: ${theme.colour.text.brandInverse};
|
|
22
23
|
`;
|
|
@@ -38,6 +39,7 @@ const buttonPrimaryStyle = (
|
|
|
38
39
|
`;
|
|
39
40
|
|
|
40
41
|
const disabledStyle = css`
|
|
42
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.disabledOnBgFill};
|
|
41
43
|
background-color: ${theme.colour.fill.disabled};
|
|
42
44
|
color: ${theme.colour.text.onBgFillDisabled};
|
|
43
45
|
`;
|
|
@@ -6,14 +6,12 @@ const buttonPrimarySubtleStyle = (
|
|
|
6
6
|
theme: ThemeType,
|
|
7
7
|
selected: ButtonBaseProps['selected'],
|
|
8
8
|
disabled: ButtonBaseProps['disabled'],
|
|
9
|
-
loading: ButtonBaseProps['loading']
|
|
10
|
-
paddingPx: number
|
|
9
|
+
loading: ButtonBaseProps['loading']
|
|
11
10
|
) => {
|
|
12
11
|
const {
|
|
13
|
-
colour: { border, fill, text },
|
|
12
|
+
colour: { border, fill, icon, text },
|
|
14
13
|
} = theme;
|
|
15
14
|
|
|
16
|
-
const bgColour = fill.inverse;
|
|
17
15
|
const borderColour = border.subtle;
|
|
18
16
|
const bgHoverColour = fill.brandSubtleHover;
|
|
19
17
|
const bgActiveColour = fill.brandSubtleSelected;
|
|
@@ -21,18 +19,18 @@ const buttonPrimarySubtleStyle = (
|
|
|
21
19
|
const selectedBorderColour = border.brand;
|
|
22
20
|
const selectedTextColour = text.brandHover;
|
|
23
21
|
|
|
24
|
-
const adjustedPaddingPx = paddingPx + 1;
|
|
25
|
-
|
|
26
22
|
const baseStyle = css`
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
--ucl-uikit-button-icon-colour: ${icon.default};
|
|
24
|
+
background-color: transparent;
|
|
25
|
+
outline: ${theme.border.b1} solid ${borderColour};
|
|
26
|
+
outline-offset: -${theme.border.b1};
|
|
29
27
|
color: ${theme.colour.text.default};
|
|
30
|
-
padding: 0 ${adjustedPaddingPx}px;
|
|
31
28
|
`;
|
|
32
29
|
|
|
33
30
|
const selectedStyle = css`
|
|
31
|
+
--ucl-uikit-button-icon-colour: ${icon.brandSelectedOnBgFill};
|
|
34
32
|
background-color: ${selectedFillColour};
|
|
35
|
-
|
|
33
|
+
outline-color: ${selectedBorderColour};
|
|
36
34
|
color: ${selectedTextColour};
|
|
37
35
|
`;
|
|
38
36
|
|
|
@@ -49,7 +47,8 @@ const buttonPrimarySubtleStyle = (
|
|
|
49
47
|
`;
|
|
50
48
|
|
|
51
49
|
const disabledStyle = css`
|
|
52
|
-
|
|
50
|
+
--ucl-uikit-button-icon-colour: ${icon.disabled};
|
|
51
|
+
outline-color: ${border.disabled};
|
|
53
52
|
color: ${text.disabled};
|
|
54
53
|
`;
|
|
55
54
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { css, cx } from '@emotion/css';
|
|
2
|
+
import { ThemeType } from '../../../theme';
|
|
3
|
+
import { ButtonBaseProps } from '../Button';
|
|
4
|
+
|
|
5
|
+
const buttonPrimarySuccessStyle = (
|
|
6
|
+
theme: ThemeType,
|
|
7
|
+
selected: ButtonBaseProps['selected'],
|
|
8
|
+
disabled: ButtonBaseProps['disabled'],
|
|
9
|
+
loading: ButtonBaseProps['loading']
|
|
10
|
+
) => {
|
|
11
|
+
const baseStyle = css`
|
|
12
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.inverse};
|
|
13
|
+
background-color: ${theme.colour.fill.success};
|
|
14
|
+
color: ${theme.colour.text.inverse};
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const interactiveStyle = css`
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const selectedStyle = css`
|
|
22
|
+
background-color: ${theme.colour.fill.success};
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const disabledStyle = css`
|
|
26
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.disabledOnBgFill};
|
|
27
|
+
background-color: ${theme.colour.fill.disabled};
|
|
28
|
+
color: ${theme.colour.text.onBgFillDisabled};
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
return cx(
|
|
32
|
+
baseStyle,
|
|
33
|
+
selected && selectedStyle,
|
|
34
|
+
!disabled && !loading && interactiveStyle,
|
|
35
|
+
disabled && disabledStyle
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default buttonPrimarySuccessStyle;
|
|
@@ -19,6 +19,7 @@ const buttonPrimaryWarningStyle = (
|
|
|
19
19
|
const selectedBgColour = fill.cautionSelected;
|
|
20
20
|
|
|
21
21
|
const baseStyle = css`
|
|
22
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.caution};
|
|
22
23
|
background-color: ${bgColour};
|
|
23
24
|
color: ${textColour};
|
|
24
25
|
`;
|
|
@@ -40,6 +41,7 @@ const buttonPrimaryWarningStyle = (
|
|
|
40
41
|
`;
|
|
41
42
|
|
|
42
43
|
const disabledStyle = css`
|
|
44
|
+
--ucl-uikit-button-icon-colour: ${theme.colour.icon.disabledOnBgFill};
|
|
43
45
|
border-color: ${theme.colour.fill.disabled};
|
|
44
46
|
background-color: ${theme.colour.fill.disabled};
|
|
45
47
|
color: ${theme.colour.text.onBgFillDisabled};
|