Skip to content

Commit 98eef9e

Browse files
committed
CR changes
1 parent 6ac3c34 commit 98eef9e

6 files changed

Lines changed: 103 additions & 80 deletions

File tree

packages/design-system/src/components/ds-button-v3/__tests__/ds-button-v3.browser.test.tsx

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { createRef } from 'react';
22
import { describe, expect, it, vi } from 'vitest';
33
import { page } from 'vitest/browser';
44
import { DsButtonV3 } from '../index.ts';
5-
import styles from '../ds-button-v3.module.scss';
65

76
describe('DsButtonV3', () => {
87
it('calls onClick when clicked', async () => {
@@ -48,28 +47,28 @@ describe('DsButtonV3', () => {
4847
await expect.element(button).toHaveAttribute('data-color', 'negative');
4948
});
5049

51-
it('sets ondark color palette', async () => {
52-
await page.render(<DsButtonV3 color="ondark">Label</DsButtonV3>);
50+
it('applies iconOnly layout when startIcon is set without children', async () => {
51+
await page.render(<DsButtonV3 startIcon="check_circle" aria-label="Confirm" />);
5352

54-
const button = page.getByRole('button', { name: 'Label' });
53+
const button = page.getByRole('button', { name: 'Confirm' });
5554

56-
await expect.element(button).toHaveAttribute('data-color', 'ondark');
55+
await expect.element(button).toHaveAttribute('data-icon-only', 'true');
5756
});
5857

59-
it('applies iconOnly layout when icon is set without children', async () => {
60-
await page.render(<DsButtonV3 icon="check_circle" aria-label="Confirm" />);
58+
it('applies iconOnly layout when endIcon is set without children', async () => {
59+
await page.render(<DsButtonV3 endIcon="arrow_forward" aria-label="Next" />);
6160

62-
const button = page.getByRole('button', { name: 'Confirm' });
61+
const button = page.getByRole('button', { name: 'Next' });
6362

64-
await expect.element(button).toHaveClass(styles.iconOnly);
63+
await expect.element(button).toHaveAttribute('data-icon-only', 'true');
6564
});
6665

6766
it('does not apply iconOnly layout when icon is set with children', async () => {
68-
await page.render(<DsButtonV3 icon="check_circle">Save</DsButtonV3>);
67+
await page.render(<DsButtonV3 startIcon="check_circle">Save</DsButtonV3>);
6968

7069
const button = page.getByRole('button', { name: 'Save' });
7170

72-
await expect.element(button).not.toHaveClass(styles.iconOnly);
71+
await expect.element(button).not.toHaveAttribute('data-icon-only');
7372
});
7473

7574
it('renders native submit button type', async () => {
@@ -86,17 +85,17 @@ describe('DsButtonV3', () => {
8685
await expect.element(page.getByRole('button', { name: 'X' })).toHaveClass('extra');
8786
});
8887

89-
it('sets aria-busy and loading class when loading', async () => {
88+
it('sets aria-busy and data-loading when loading', async () => {
9089
await page.render(<DsButtonV3 loading>Save</DsButtonV3>);
9190

9291
const button = page.getByRole('button', { name: 'Save' });
9392

9493
await expect.element(button).toHaveAttribute('aria-busy', 'true');
95-
await expect.element(button).toHaveClass(styles.loading);
94+
await expect.element(button).toHaveAttribute('data-loading', '');
9695
});
9796

98-
it('renders spinner instead of icon when loading', async () => {
99-
await page.render(<DsButtonV3 loading icon="check_circle" aria-label="Saving" />);
97+
it('renders spinner instead of startIcon when loading', async () => {
98+
await page.render(<DsButtonV3 loading startIcon="check_circle" aria-label="Saving" />);
10099

101100
const button = page.getByRole('button', { name: 'Saving' });
102101

@@ -107,6 +106,34 @@ describe('DsButtonV3', () => {
107106
expect(el.querySelector('[aria-hidden]')).toBeNull();
108107
});
109108

109+
it('preserves endIcon when loading', async () => {
110+
await page.render(
111+
<DsButtonV3 loading startIcon="check_circle" endIcon="arrow_forward">
112+
Save
113+
</DsButtonV3>,
114+
);
115+
116+
const button = page.getByRole('button', { name: 'Save' });
117+
const el = button.element();
118+
const hiddenIcons = el.querySelectorAll('[aria-hidden]');
119+
120+
expect(el.querySelector('svg')).toBeTruthy();
121+
expect(hiddenIcons).toHaveLength(1);
122+
});
123+
124+
it('renders both startIcon and endIcon', async () => {
125+
await page.render(
126+
<DsButtonV3 startIcon="check_circle" endIcon="arrow_forward">
127+
Continue
128+
</DsButtonV3>,
129+
);
130+
131+
const button = page.getByRole('button', { name: 'Continue' });
132+
const hiddenIcons = button.element().querySelectorAll('[aria-hidden]');
133+
134+
expect(hiddenIcons).toHaveLength(2);
135+
});
136+
110137
it('does not call onClick when loading', async () => {
111138
const onClick = vi.fn();
112139

@@ -142,6 +169,7 @@ describe('DsButtonV3', () => {
142169

143170
await expect.element(button).toHaveAttribute('data-color', 'default');
144171
await expect.element(button).toHaveAttribute('data-variant', 'primary');
172+
await expect.element(button).toHaveAttribute('data-size', 'medium');
145173
});
146174

147175
it('forwards ref to the button element', async () => {
@@ -165,7 +193,7 @@ describe('DsButtonV3', () => {
165193
const button = page.getByRole('button', { name: 'Saving', disabled: true });
166194

167195
await expect.element(button).toBeDisabled();
168-
await expect.element(button).toHaveClass(styles.loading);
196+
await expect.element(button).toHaveAttribute('data-loading', '');
169197
await button.click({ force: true });
170198
expect(onClick).not.toHaveBeenCalled();
171199
});
@@ -180,7 +208,7 @@ describe('DsButtonV3', () => {
180208
const button = page.getByRole('button', { name: 'Saving', disabled: true });
181209

182210
await expect.element(button).toBeDisabled();
183-
await expect.element(button).not.toHaveClass(styles.loading);
211+
await expect.element(button).not.toHaveAttribute('data-loading');
184212
await expect.element(button).toHaveAttribute('aria-busy', 'true');
185213
});
186214

packages/design-system/src/components/ds-button-v3/ds-button-v3.module.scss

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ $transition-duration-quick: 0.15s;
3535
color $transition-duration-default,
3636
outline-color $transition-duration-quick;
3737

38-
&:disabled:not(.loading) {
38+
&:disabled:not([data-loading]) {
3939
cursor: not-allowed;
4040
}
4141

42-
&.loading {
42+
&[data-loading] {
4343
cursor: default;
4444
pointer-events: none;
4545
}
@@ -52,50 +52,50 @@ $transition-duration-quick: 0.15s;
5252
outline-style: solid;
5353
}
5454

55-
&.sizeLarge {
55+
&[data-size='large'] {
5656
padding: var(--3xs) var(--sm);
5757
min-height: $height-large;
5858
font-size: var(--font-size-md);
5959
line-height: var(--line-height-md);
6060
}
6161

62-
&.sizeMedium {
62+
&[data-size='medium'] {
6363
padding: var(--3xs) var(--sm);
6464
min-height: $height-medium;
6565
font-size: var(--font-size-sm);
6666
line-height: var(--line-height-sm);
6767
}
6868

69-
&.sizeSmall {
69+
&[data-size='small'] {
7070
padding: var(--3xs) var(--sm);
7171
min-height: $height-small;
7272
font-size: var(--font-size-xs);
7373
line-height: var(--line-height-xs);
7474
}
7575

76-
&.sizeTiny {
76+
&[data-size='tiny'] {
7777
min-height: var(--icon-width-tiny);
7878
padding: 0 var(--3xs);
7979
font-size: var(--font-size-xs);
8080
line-height: var(--line-height-xs);
8181
}
8282

83-
&.iconOnly.sizeLarge {
83+
&[data-icon-only][data-size='large'] {
8484
padding: var(--3xs);
8585
min-width: $height-large;
8686
}
8787

88-
&.iconOnly.sizeMedium {
88+
&[data-icon-only][data-size='medium'] {
8989
padding: var(--3xs);
9090
min-width: $height-medium;
9191
}
9292

93-
&.iconOnly.sizeSmall {
93+
&[data-icon-only][data-size='small'] {
9494
padding: var(--3xs);
9595
min-width: $height-small;
9696
}
9797

98-
&.iconOnly.sizeTiny {
98+
&[data-icon-only][data-size='tiny'] {
9999
padding: 0;
100100
min-width: var(--icon-width-tiny);
101101
}
@@ -125,7 +125,7 @@ $transition-duration-quick: 0.15s;
125125
background-color: var(--background-background-primary-selected);
126126
}
127127

128-
&:disabled:not(.loading) {
128+
&:disabled:not([data-loading]) {
129129
background-color: var(--background-background-disable);
130130
color: var(--font-font-on-action);
131131
}
@@ -162,7 +162,7 @@ $transition-duration-quick: 0.15s;
162162
border-color: var(--border-border-secondary-hover);
163163
}
164164

165-
&:disabled:not(.loading) {
165+
&:disabled:not([data-loading]) {
166166
background-color: var(--background-background-action-secondary);
167167
color: var(--font-font-disabled);
168168
border-color: var(--border-border);
@@ -197,7 +197,7 @@ $transition-duration-quick: 0.15s;
197197
color: var(--font-font-action-secondary);
198198
}
199199

200-
&:disabled:not(.loading) {
200+
&:disabled:not([data-loading]) {
201201
background-color: transparent;
202202
color: var(--font-font-disabled);
203203
}
@@ -227,7 +227,7 @@ $transition-duration-quick: 0.15s;
227227
background-color: var(--background-background-negative-selected);
228228
}
229229

230-
&:disabled:not(.loading) {
230+
&:disabled:not([data-loading]) {
231231
background-color: var(--background-background-disable);
232232
color: var(--font-font-on-action);
233233
}
@@ -260,7 +260,7 @@ $transition-duration-quick: 0.15s;
260260
border-color: var(--border-border-negative-hover);
261261
}
262262

263-
&:disabled:not(.loading) {
263+
&:disabled:not([data-loading]) {
264264
background-color: var(--background-background-action-secondary);
265265
color: var(--font-font-disabled);
266266
border-color: var(--border-border);
@@ -291,7 +291,7 @@ $transition-duration-quick: 0.15s;
291291
background-color: var(--background-background-negative-secondary-selected);
292292
}
293293

294-
&:disabled:not(.loading) {
294+
&:disabled:not([data-loading]) {
295295
background-color: transparent;
296296
color: var(--font-font-disabled);
297297
}
@@ -321,7 +321,7 @@ $transition-duration-quick: 0.15s;
321321
background-color: var(--background-background-ondark-primary-selected);
322322
}
323323

324-
&:disabled:not(.loading) {
324+
&:disabled:not([data-loading]) {
325325
background-color: var(--background-background-ondark-disabled);
326326
color: var(--font-font-disabled);
327327
}
@@ -354,7 +354,7 @@ $transition-duration-quick: 0.15s;
354354
background-color: var(--background-background-ondark-secondary-selected);
355355
}
356356

357-
&:disabled:not(.loading) {
357+
&:disabled:not([data-loading]) {
358358
background-color: transparent;
359359
color: var(--font-font-ondark-disabled);
360360
border-color: var(--background-background-ondark-disabled);
@@ -388,7 +388,7 @@ $transition-duration-quick: 0.15s;
388388
background-color: var(--background-background-ondark-secondary-selected);
389389
}
390390

391-
&:disabled:not(.loading) {
391+
&:disabled:not([data-loading]) {
392392
background-color: transparent;
393393
color: var(--font-font-ondark-disabled);
394394
}

packages/design-system/src/components/ds-button-v3/ds-button-v3.stories.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const Default: Story = {
3838
color: 'default',
3939
variant: 'primary',
4040
size: 'medium',
41-
icon: 'check_circle',
41+
startIcon: 'check_circle',
4242
children: 'Button',
4343
},
4444
};
@@ -49,23 +49,23 @@ const matrixRows = [
4949
];
5050

5151
const defaultIconMatrixRows = [
52-
{ label: 'check circle', icon: 'check_circle', variant: 'primary', color: 'default', loading: false },
53-
{ label: 'info', icon: 'info', variant: 'secondary', color: 'default', loading: false },
54-
{ label: 'delete', icon: 'delete', variant: 'tertiary', color: 'negative', loading: false },
55-
{ label: 'loading', icon: 'check_circle', variant: 'primary', color: 'default', loading: true },
52+
{ label: 'check circle', startIcon: 'check_circle', variant: 'primary', color: 'default', loading: false },
53+
{ label: 'info', startIcon: 'info', variant: 'secondary', color: 'default', loading: false },
54+
{ label: 'delete', startIcon: 'delete', variant: 'tertiary', color: 'negative', loading: false },
55+
{ label: 'loading', startIcon: 'check_circle', variant: 'primary', color: 'default', loading: true },
5656
] as const;
5757

5858
const onDarkIconMatrixRows = [
5959
{
6060
label: 'arrow down',
61-
icon: 'keyboard_arrow_down',
61+
startIcon: 'keyboard_arrow_down',
6262
variant: 'primary',
6363
color: 'ondark',
6464
loading: false,
6565
},
66-
{ label: 'home', icon: 'home', variant: 'secondary', color: 'ondark', loading: false },
67-
{ label: 'info', icon: 'info', variant: 'tertiary', color: 'ondark', loading: false },
68-
{ label: 'loading', icon: 'info', variant: 'primary', color: 'ondark', loading: true },
66+
{ label: 'home', startIcon: 'home', variant: 'secondary', color: 'ondark', loading: false },
67+
{ label: 'info', startIcon: 'info', variant: 'tertiary', color: 'ondark', loading: false },
68+
{ label: 'loading', startIcon: 'info', variant: 'primary', color: 'ondark', loading: true },
6969
] as const;
7070

7171
const MatrixGrid = ({ color }: { color?: ButtonV3Color }) => {
@@ -102,7 +102,7 @@ const MatrixGrid = ({ color }: { color?: ButtonV3Color }) => {
102102
color={color}
103103
variant={loading ? 'primary' : (label as (typeof buttonV3Variants)[number])}
104104
size={size}
105-
icon="check_circle"
105+
startIcon="check_circle"
106106
loading={loading}
107107
onClick={fn()}
108108
>
@@ -122,7 +122,7 @@ const IconMatrixGrid = ({
122122
}: {
123123
rows: ReadonlyArray<{
124124
label: string;
125-
icon: 'check_circle' | 'info' | 'delete' | 'keyboard_arrow_down' | 'home';
125+
startIcon: 'check_circle' | 'info' | 'delete' | 'keyboard_arrow_down' | 'home';
126126
variant: ButtonV3Variant;
127127
color: ButtonV3Color;
128128
loading: boolean;
@@ -143,7 +143,7 @@ const IconMatrixGrid = ({
143143
))}
144144
</div>
145145

146-
{rows.map(({ label, icon, loading, variant, color }) => (
146+
{rows.map(({ label, startIcon, loading, variant, color }) => (
147147
<div key={label} className={storyStyles.row}>
148148
<span
149149
className={classNames(storyStyles.rowLabel, {
@@ -162,7 +162,7 @@ const IconMatrixGrid = ({
162162
color={color}
163163
variant={variant}
164164
size={size}
165-
icon={icon}
165+
startIcon={startIcon}
166166
loading={loading}
167167
aria-label={ariaLabel}
168168
onClick={fn()}

0 commit comments

Comments
 (0)