Skip to content

Commit bcf0810

Browse files
authored
Style toggle button (#72)
* Style toggle button * Add new snapshots
1 parent 3efa9f4 commit bcf0810

File tree

8 files changed

+121
-11
lines changed

8 files changed

+121
-11
lines changed

packages/components/.storybook/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import remarkGfm from 'remark-gfm';
33
module.exports = {
44
stories: [
55
'../docs/**/*.mdx',
6+
'../src/**/*.mdx',
67
'../src/**/*.stories.mdx',
78
'../src/**/*.stories.ts'
89
],
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Canvas, Meta, Primary, Controls, Story } from '@storybook/blocks';
2+
import * as ButtonStories from './button.stories';
3+
4+
<Meta of={ButtonStories} />
5+
6+
# Button
7+
8+
<Primary />
9+
10+
## Props
11+
12+
<Controls />
13+
14+
## Stories
15+
16+
### Default
17+
18+
<Canvas>
19+
<Story of={ButtonStories.Neutral} />
20+
</Canvas>
21+
22+
### Error
23+
24+
<Canvas>
25+
<Story of={ButtonStories.Error} />
26+
</Canvas>
27+
28+
### Accent
29+
30+
<Canvas>
31+
<Story of={ButtonStories.Accent} />
32+
</Canvas>
33+
34+
### Lightweight
35+
36+
<Canvas>
37+
<Story of={ButtonStories.Lightweight} />
38+
</Canvas>
39+
40+
### With autofocus
41+
42+
<Canvas>
43+
<Story of={ButtonStories.WithAutofocus} />
44+
</Canvas>
45+
46+
### With disabled
47+
48+
<Canvas>
49+
<Story of={ButtonStories.WithDisabled} />
50+
</Canvas>
51+
52+
### With start icon
53+
54+
<Canvas>
55+
<Story of={ButtonStories.WithStartIcon} />
56+
</Canvas>
57+
58+
### Icon only
59+
60+
<Canvas>
61+
<Story of={ButtonStories.IconOnly} />
62+
</Canvas>
63+
64+
### Toggle button
65+
66+
To define a toggle button, you must set the `aria-pressed` attribute
67+
to `false` or `true` depending on the state of the button.
68+
69+
> Reference used: https://joshcollinsworth.com/blog/accessible-toggle-buttons
70+
71+
<Canvas>
72+
<Story of={ButtonStories.Toggle} />
73+
</Canvas>

packages/components/src/button/button.stories.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export default {
2828
table: {
2929
disable: true
3030
}
31+
},
32+
ariaPressed: {
33+
control: 'select',
34+
options: ['none', 'true', 'false']
3135
}
3236
}
3337
} as Meta;
@@ -46,6 +50,7 @@ const Template: StoryFn = (args, context): HTMLElement => {
4650
${args.isDisabled ? 'disabled' : ''}
4751
${args.isAutoFocused ? 'autofocus' : ''}
4852
${args.isMinimal ? 'minimal' : ''}
53+
${args.ariaPressed !== 'none' ? `aria-pressed=${args.ariaPressed}` : ''}
4954
>${args.startIcon ? getFaIcon('plus', args.label ? 'start' : null) : ''}${
5055
args.label ?? ''
5156
}</jp-button
@@ -58,56 +63,64 @@ const Template: StoryFn = (args, context): HTMLElement => {
5863
return container.firstChild as HTMLElement;
5964
};
6065

61-
export const Default: StoryObj = { render: Template.bind({}) };
62-
Default.args = {
66+
export const Accent: StoryObj = { render: Template.bind({}) };
67+
Accent.args = {
6368
label: 'Button Text',
6469
appearance: 'Accent',
6570
isDisabled: false,
6671
isAutoFocused: false,
6772
isMinimal: false,
6873
startIcon: false,
74+
ariaPressed: 'none',
6975
onClick: action('button-clicked')
7076
};
7177

7278
export const Error: StoryObj = { render: Template.bind({}) };
7379
Error.args = {
74-
...Default.args,
80+
...Accent.args,
7581
appearance: 'Error'
7682
};
7783

7884
export const Neutral: StoryObj = { render: Template.bind({}) };
7985
Neutral.args = {
80-
...Default.args,
86+
...Accent.args,
8187
appearance: 'Neutral'
8288
};
8389

8490
export const Lightweight: StoryObj = { render: Template.bind({}) };
8591
Lightweight.args = {
86-
...Default.args,
92+
...Accent.args,
8793
appearance: 'Lightweight'
8894
};
8995

9096
export const WithAutofocus: StoryObj = { render: Template.bind({}) };
9197
WithAutofocus.args = {
92-
...Default.args,
98+
...Accent.args,
9399
isAutoFocused: true
94100
};
95101

96102
export const WithDisabled: StoryObj = { render: Template.bind({}) };
97103
WithDisabled.args = {
98-
...Default.args,
104+
...Accent.args,
99105
isDisabled: true
100106
};
101107

102108
export const WithStartIcon: StoryObj = { render: Template.bind({}) };
103109
WithStartIcon.args = {
104-
...Default.args,
110+
...Accent.args,
105111
startIcon: true
106112
};
107113

108114
export const IconOnly: StoryObj = { render: Template.bind({}) };
109115
IconOnly.args = {
110-
...Default.args,
116+
...Accent.args,
111117
label: null,
112118
startIcon: true
113119
};
120+
121+
export const Toggle: StoryObj = { render: Template.bind({}) };
122+
Toggle.storyName = 'Toggle button';
123+
Toggle.args = {
124+
...Accent.args,
125+
ariaPressed: 'true'
126+
};

packages/components/src/button/button.styles.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) Microsoft Corporation.
33
// Distributed under the terms of the Modified BSD License.
44

5+
import { neutralFillStrongActive } from '@microsoft/fast-components';
56
import { css, ElementStyles } from '@microsoft/fast-element';
67
import {
78
ButtonOptions,
@@ -30,6 +31,7 @@ import {
3031
errorFillFocus,
3132
errorFillHover,
3233
errorFillRest,
34+
errorForegroundActive,
3335
focusStrokeWidth,
3436
foregroundOnAccentActive,
3537
foregroundOnAccentHover,
@@ -113,6 +115,11 @@ const BaseButtonStyles = css`
113115
background-color: ${neutralFillActive};
114116
}
115117
118+
:host([aria-pressed='true']) {
119+
box-shadow: inset 0px 0px 5px 5px ${neutralFillStrongActive};
120+
scale: 0.95;
121+
}
122+
116123
:host([minimal]) {
117124
--density: -4;
118125
}
@@ -216,6 +223,10 @@ const AccentButtonStyles = css`
216223
color: ${foregroundOnAccentHover};
217224
}
218225
226+
:host([appearance='accent'][aria-pressed='true']) {
227+
box-shadow: inset 0px 0px 5px 5px ${accentForegroundActive};
228+
}
229+
219230
:host([appearance='accent']:active) .control:active {
220231
background: ${accentFillActive};
221232
color: ${foregroundOnAccentActive};
@@ -276,6 +287,10 @@ const ErrorButtonStyles = css`
276287
color: ${foregroundOnAccentHover};
277288
}
278289
290+
:host([appearance='error'][aria-pressed='true']) {
291+
box-shadow: inset 0px 0px 5px 5px ${errorForegroundActive};
292+
}
293+
279294
:host([appearance='error']:active) .control:active {
280295
background: ${errorFillActive};
281296
color: ${foregroundOnAccentActive};

packages/components/src/button/button.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
import { test, expect } from '@playwright/test';
55

6-
test('Default', async ({ page }) => {
7-
await page.goto('/iframe.html?id=components-button--default');
6+
test('Accent', async ({ page }) => {
7+
await page.goto('/iframe.html?id=components-button--accent');
88

99
expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
1010
'button-default.png'
@@ -66,3 +66,11 @@ test('Icon Only', async ({ page }) => {
6666
'button-icon-only.png'
6767
);
6868
});
69+
70+
test('Toggled', async ({ page }) => {
71+
await page.goto('/iframe.html?id=components-button--toggle');
72+
73+
expect(await page.locator('jp-button').screenshot()).toMatchSnapshot(
74+
'button-toggle.png'
75+
);
76+
});
2.09 KB
Loading
2.09 KB
Loading
4.75 KB
Loading

0 commit comments

Comments
 (0)