Skip to content

Commit d53f79e

Browse files
authoredMay 8, 2023
Update CL documentation (#5379)
1 parent f51ed10 commit d53f79e

14 files changed

+315
-220
lines changed
 

‎.prettierrc.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
{
2-
"printWidth": 100
2+
"printWidth": 100,
3+
"overrides": [
4+
{
5+
"files": "*.mdx",
6+
"options": {
7+
"proseWrap": "always"
8+
}
9+
}
10+
]
311
}

‎libs/components/src/async-actions/in-forms.stories.mdx

+28-21
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,32 @@ import { Meta } from "@storybook/addon-docs";
44

55
# Async Actions In Forms
66

7-
These directives should be used when building forms with buttons that trigger long running tasks in the background,
8-
eg. Submit or Delete buttons. For buttons that are not associated with a form see [Standalone Async Actions](?path=/story/component-library-async-actions-standalone-documentation--page).
7+
These directives should be used when building forms with buttons that trigger long running tasks in
8+
the background, eg. Submit or Delete buttons. For buttons that are not associated with a form see
9+
[Standalone Async Actions](?path=/story/component-library-async-actions-standalone-documentation--page).
910

10-
There are two separately supported use-cases: Submit buttons and standalone form buttons (eg. Delete buttons).
11+
There are two separately supported use-cases: Submit buttons and standalone form buttons (eg. Delete
12+
buttons).
1113

1214
## Usage: Submit buttons
1315

1416
Adding async actions to submit buttons requires the following 3 steps
1517

1618
### 1. Add a handler to your `Component`
1719

18-
A handler is a function that returns a promise or an observable. Functions that return `void` are also supported which is
19-
useful because `return;` can be used to abort an action.
20+
A handler is a function that returns a promise or an observable. Functions that return `void` are
21+
also supported which is useful because `return;` can be used to abort an action.
2022

21-
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler needs access to the parent
22-
component using the variable `this`.
23+
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler
24+
needs access to the parent component using the variable `this`.
2325

24-
**NOTE:** `formGroup.invalid` will always return `true` after the first `await` operation, event if the form is not actually
25-
invalid. This is due to the form getting disabled by the `bitSubmit` directive while waiting for the async action to complete.
26+
**NOTE:** `formGroup.invalid` will always return `true` after the first `await` operation, event if
27+
the form is not actually invalid. This is due to the form getting disabled by the `bitSubmit`
28+
directive while waiting for the async action to complete.
2629

27-
**NOTE:** Handlers do not need to check if any previous requests have finished because the directives have built in protection against
28-
users attempting to trigger new actions before the previous ones have finished.
30+
**NOTE:** Handlers do not need to check if any previous requests have finished because the
31+
directives have built in protection against users attempting to trigger new actions before the
32+
previous ones have finished.
2933

3034
```ts
3135
@Component({...})
@@ -51,8 +55,8 @@ class Component {
5155

5256
Add the `bitSubmit` directive and supply the handler defined in step 1.
5357

54-
**NOTE:** The `directive` is defined using the input syntax: `[input]="handler"`.
55-
This is different from how submit handlers are usually defined with the output syntax `(ngSubmit)="handler()"`.
58+
**NOTE:** The `directive` is defined using the input syntax: `[input]="handler"`. This is different
59+
from how submit handlers are usually defined with the output syntax `(ngSubmit)="handler()"`.
5660

5761
**NOTE:** `[bitSubmit]` is used instead of `(ngSubmit)`. Using both is not supported.
5862

@@ -76,14 +80,15 @@ Adding async actions to standalone form buttons requires the following 3 steps.
7680

7781
### 1. Add a handler to your `Component`
7882

79-
A handler is a function that returns a promise or an observable. Functions that return `void` are also supported which is
80-
useful for aborting an action.
83+
A handler is a function that returns a promise or an observable. Functions that return `void` are
84+
also supported which is useful for aborting an action.
8185

82-
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler needs access to the parent
83-
component using the variable `this`.
86+
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler
87+
needs access to the parent component using the variable `this`.
8488

85-
**NOTE:** Handlers do not need to check if any previous requests have finished because the directives have built in protection against
86-
users attempting to trigger new actions before the previous ones have finished.
89+
**NOTE:** Handlers do not need to check if any previous requests have finished because the
90+
directives have built in protection against users attempting to trigger new actions before the
91+
previous ones have finished.
8792

8893
```ts
8994
@Component({...})
@@ -113,7 +118,8 @@ The `bitSubmit` directive is required because of its coordinating role inside of
113118

114119
### 3. Add directives to the `button` element
115120

116-
Add `bitButton`, `bitFormButton`, `bitAction` directives to the button. Make sure to supply a handler.
121+
Add `bitButton`, `bitFormButton`, `bitAction` directives to the button. Make sure to supply a
122+
handler.
117123

118124
**NOTE:** A summary of what each directive does can be found inside the source code.
119125

@@ -124,7 +130,8 @@ Add `bitButton`, `bitFormButton`, `bitAction` directives to the button. Make sur
124130

125131
## `[bitSubmit]` Disabled Form Submit
126132

127-
If you need your form to be able to submit even when the form is disabled, then add `[allowDisabledFormSubmit]="true"` to your `<form>`
133+
If you need your form to be able to submit even when the form is disabled, then add
134+
`[allowDisabledFormSubmit]="true"` to your `<form>`
128135

129136
```html
130137
<form [formGroup]="formGroup" [bitSubmit]="submit" [allowDisabledFormSubmit]="true">...</form>

‎libs/components/src/async-actions/overview.stories.mdx

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { Meta } from "@storybook/addon-docs";
44

55
# Async Actions
66

7-
The directives in this module makes it easier for developers to reflect the progress of async actions in the UI when using
8-
buttons, while also providing robust and standardized error handling.
7+
The directives in this module makes it easier for developers to reflect the progress of async
8+
actions in the UI when using buttons, while also providing robust and standardized error handling.
99

10-
These buttons can either be standalone (such as Refresh buttons), submit buttons for forms or as standalone buttons
11-
that are part of a form (such as Delete buttons).
10+
These buttons can either be standalone (such as Refresh buttons), submit buttons for forms or as
11+
standalone buttons that are part of a form (such as Delete buttons).
1212

13-
These directives are meant to replace the older `appApiAction` directive, providing the option to use `observables` and reduce
14-
clutter inside our view `components`.
13+
These directives are meant to replace the older `appApiAction` directive, providing the option to
14+
use `observables` and reduce clutter inside our view `components`.
1515

1616
## When to use?
1717

‎libs/components/src/async-actions/standalone.stories.mdx

+12-10
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@ import { Meta } from "@storybook/addon-docs";
44

55
# Standalone Async Actions
66

7-
These directives should be used when building a standalone button that triggers a long running task in the background,
8-
eg. Refresh buttons. For non-submit buttons that are associated with forms see [Async Actions In Forms](?path=/story/component-library-async-actions-in-forms-documentation--page).
7+
These directives should be used when building a standalone button that triggers a long running task
8+
in the background, eg. Refresh buttons. For non-submit buttons that are associated with forms see
9+
[Async Actions In Forms](?path=/story/component-library-async-actions-in-forms-documentation--page).
910

1011
## Usage
1112

1213
Adding async actions to standalone buttons requires the following 2 steps
1314

1415
### 1. Add a handler to your `Component`
1516

16-
A handler is a function that returns a promise or an observable. Functions that return `void` are also supported which is
17-
useful because `return;` can be used to abort an action.
17+
A handler is a function that returns a promise or an observable. Functions that return `void` are
18+
also supported which is useful because `return;` can be used to abort an action.
1819

19-
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler needs access to the parent
20-
component using the variable `this`.
20+
**NOTE:** Defining the handlers as arrow-functions assigned to variables is mandatory if the handler
21+
needs access to the parent component using the variable `this`.
2122

22-
**NOTE:** Handlers do not need to check if any previous requests have finished because the directives have built in protection against
23-
users attempting to trigger new actions before the previous ones have finished.
23+
**NOTE:** Handlers do not need to check if any previous requests have finished because the
24+
directives have built in protection against users attempting to trigger new actions before the
25+
previous ones have finished.
2426

2527
#### Example using promises
2628

@@ -48,8 +50,8 @@ class Component {
4850

4951
Add the `bitAction` directive and supply the handler defined in step 1.
5052

51-
**NOTE:** The `directive` is defined using the input syntax: `[input]="handler"`.
52-
This is different from how click handlers are usually defined with the output syntax `(click)="handler()"`.
53+
**NOTE:** The `directive` is defined using the input syntax: `[input]="handler"`. This is different
54+
from how click handlers are usually defined with the output syntax `(click)="handler()"`.
5355

5456
**NOTE:** `[bitAction]` is used instead of `(click)`. Using both is not supported.
5557

‎libs/components/src/form-field/form-field.stories.ts

+3-9
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,12 @@ const Template: Story<BitFormFieldComponent> = (args: BitFormFieldComponent) =>
9595
...args,
9696
},
9797
template: `
98-
<form [formGroup]="formObj" (ngSubmit)="submit()">
98+
<form [formGroup]="formObj">
9999
<bit-form-field>
100-
<bit-label>Name</bit-label>
100+
<bit-label>Label</bit-label>
101101
<input bitInput formControlName="name" />
102+
<bit-hint>Optional Hint</bit-hint>
102103
</bit-form-field>
103-
104-
<bit-form-field>
105-
<bit-label>Email</bit-label>
106-
<input bitInput formControlName="email" />
107-
</bit-form-field>
108-
109-
<button type="submit" bitButton buttonType="primary">Submit</button>
110104
</form>
111105
`,
112106
});
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,18 @@
1-
import { Component, Input } from "@angular/core";
2-
import { FormsModule, ReactiveFormsModule, FormBuilder } from "@angular/forms";
1+
import { FormsModule, ReactiveFormsModule, FormControl, FormGroup } from "@angular/forms";
32
import { Meta, moduleMetadata, Story } from "@storybook/angular";
43

54
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
65

76
import { I18nMockService } from "../utils/i18n-mock.service";
87

98
import { RadioButtonModule } from "./radio-button.module";
10-
11-
const template = `
12-
<form [formGroup]="formObj">
13-
<bit-radio-group formControlName="radio" aria-label="Example radio group">
14-
<bit-label *ngIf="label">Group of radio buttons</bit-label>
15-
<bit-radio-button *ngFor="let option of TestValue | keyvalue" [ngClass]="{ 'tw-block': blockLayout }"
16-
[value]="option.value" id="radio-{{option.key}}" [disabled]="optionDisabled?.includes(option.value)">
17-
<bit-label>{{ option.key }}</bit-label>
18-
<bit-hint *ngIf="blockLayout">This is a hint for the {{option.key}} option</bit-hint>
19-
</bit-radio-button>
20-
</bit-radio-group>
21-
</form>`;
22-
23-
const TestValue = {
24-
First: 0,
25-
Second: 1,
26-
Third: 2,
27-
};
28-
29-
const reverseObject = (obj: Record<any, any>) =>
30-
Object.fromEntries(Object.entries(obj).map(([key, value]) => [value, key]));
31-
32-
@Component({
33-
selector: "app-example",
34-
template: template,
35-
})
36-
class ExampleComponent {
37-
protected TestValue = TestValue;
38-
39-
protected formObj = this.formBuilder.group({
40-
radio: TestValue.First,
41-
});
42-
43-
@Input() layout: "block" | "inline" = "inline";
44-
45-
@Input() label: boolean;
46-
47-
@Input() set selected(value: number) {
48-
this.formObj.patchValue({ radio: value });
49-
}
50-
51-
@Input() set groupDisabled(disable: boolean) {
52-
if (disable) {
53-
this.formObj.disable();
54-
} else {
55-
this.formObj.enable();
56-
}
57-
}
58-
59-
@Input() optionDisabled: number[] = [];
60-
61-
get blockLayout() {
62-
return this.layout === "block";
63-
}
64-
65-
constructor(private formBuilder: FormBuilder) {}
66-
}
9+
import { RadioGroupComponent } from "./radio-group.component";
6710

6811
export default {
6912
title: "Component Library/Form/Radio Button",
70-
component: ExampleComponent,
13+
component: RadioGroupComponent,
7114
decorators: [
7215
moduleMetadata({
73-
declarations: [ExampleComponent],
7416
imports: [FormsModule, ReactiveFormsModule, RadioButtonModule],
7517
providers: [
7618
{
@@ -92,56 +34,65 @@ export default {
9234
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=3930%3A16850&t=xXPx6GJYsJfuMQPE-4",
9335
},
9436
},
95-
args: {
96-
selected: TestValue.First,
97-
groupDisabled: false,
98-
optionDisabled: null,
99-
label: true,
100-
layout: "inline",
101-
},
102-
argTypes: {
103-
selected: {
104-
options: Object.values(TestValue),
105-
control: {
106-
type: "inline-radio",
107-
labels: reverseObject(TestValue),
108-
},
109-
},
110-
optionDisabled: {
111-
options: Object.values(TestValue),
112-
control: {
113-
type: "check",
114-
labels: reverseObject(TestValue),
115-
},
116-
},
117-
layout: {
118-
options: ["inline", "block"],
119-
control: {
120-
type: "inline-radio",
121-
labels: ["inline", "block"],
122-
},
123-
},
124-
},
12537
} as Meta;
12638

127-
const storyTemplate = `<app-example [selected]="selected" [groupDisabled]="groupDisabled" [optionDisabled]="optionDisabled" [label]="label" [layout]="layout"></app-example>`;
128-
129-
const InlineTemplate: Story<ExampleComponent> = (args: ExampleComponent) => ({
130-
props: args,
131-
template: storyTemplate,
39+
const InlineTemplate: Story<RadioGroupComponent> = (args: RadioGroupComponent) => ({
40+
props: {
41+
formObj: new FormGroup({
42+
radio: new FormControl(0),
43+
}),
44+
},
45+
template: `
46+
<form [formGroup]="formObj">
47+
<bit-radio-group formControlName="radio" aria-label="Example radio group">
48+
<bit-label>Group of radio buttons</bit-label>
49+
50+
<bit-radio-button id="radio-first" [value]="0">
51+
<bit-label>First</bit-label>
52+
</bit-radio-button>
53+
54+
<bit-radio-button id="radio-second" [value]="1">
55+
<bit-label>Second</bit-label>
56+
</bit-radio-button>
57+
58+
<bit-radio-button id="radio-third" [value]="2">
59+
<bit-label>Third</bit-label>
60+
</bit-radio-button>
61+
</bit-radio-group>
62+
</form>
63+
`,
13264
});
13365

13466
export const Inline = InlineTemplate.bind({});
135-
Inline.args = {
136-
layout: "inline",
137-
};
13867

139-
const BlockTemplate: Story<ExampleComponent> = (args: ExampleComponent) => ({
140-
props: args,
141-
template: storyTemplate,
68+
const BlockTemplate: Story<RadioGroupComponent> = (args: RadioGroupComponent) => ({
69+
props: {
70+
formObj: new FormGroup({
71+
radio: new FormControl(0),
72+
}),
73+
},
74+
template: `
75+
<form [formGroup]="formObj">
76+
<bit-radio-group formControlName="radio" aria-label="Example radio group">
77+
<bit-label>Group of radio buttons</bit-label>
78+
79+
<bit-radio-button id="radio-first" class="tw-block" [value]="0">
80+
<bit-label>First</bit-label>
81+
<bit-hint>This is a hint for the first option</bit-hint>
82+
</bit-radio-button>
83+
84+
<bit-radio-button id="radio-second" class="tw-block" [value]="1">
85+
<bit-label>Second</bit-label>
86+
<bit-hint>This is a hint for the second option</bit-hint>
87+
</bit-radio-button>
88+
89+
<bit-radio-button id="radio-third" class="tw-block" [value]="2">
90+
<bit-label>Third</bit-label>
91+
<bit-hint>This is a hint for the third option</bit-hint>
92+
</bit-radio-button>
93+
</bit-radio-group>
94+
</form>
95+
`,
14296
});
14397

14498
export const Block = BlockTemplate.bind({});
145-
Block.args = {
146-
layout: "block",
147-
};

‎libs/components/src/stories/Introduction.stories.mdx

+6-6
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ import { Meta } from "@storybook/addon-docs";
8181

8282
# Bitwarden Component Library
8383

84-
The Bitwarden Component Library is a collection of reusable low level components which empowers designers and
85-
developers to work more efficiently. The primary goal is to ensure a consistent design and behavior across the
86-
different clients and platforms. Currently the primary focus is the web based clients, namely _web_, _browser_ and
87-
_desktop_.
84+
The Bitwarden Component Library is a collection of reusable low level components which empowers
85+
designers and developers to work more efficiently. The primary goal is to ensure a consistent design
86+
and behavior across the different clients and platforms. Currently the primary focus is the web
87+
based clients, namely _web_, _browser_ and _desktop_.
8888

89-
**Roll out status:** we are currently in the process of transitioning the Web Vault to utilize the component library
90-
and the other clients will follow once this work is completed.
89+
**Roll out status:** we are currently in the process of transitioning the Web Vault to utilize the
90+
component library and the other clients will follow once this work is completed.
9191

9292
<div className="subheading">Configure</div>
9393

‎libs/components/src/stories/banner-docs.stories.mdx

+14-12
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@ import { Meta, Story } from "@storybook/addon-docs";
44

55
# Banner
66

7-
Banners are used for important communication with the user that needs to be seen right away, but has little effect on
8-
the experience. Banners appear at the top of the user's screen on page load and persist across all pages a user
9-
navigates to.
10-
11-
- They should always be dismissable and never use a timeout. If a user dismisses a banner, it should not reappear
12-
during that same active session.
13-
- Use banners sparingly, as they can feel intrusive to the user if they appear unexpectedly. Their effectiveness may
14-
decrease if too many are used.
7+
Banners are used for important communication with the user that needs to be seen right away, but has
8+
little effect on the experience. Banners appear at the top of the user's screen on page load and
9+
persist across all pages a user navigates to.
10+
11+
- They should always be dismissable and never use a timeout. If a user dismisses a banner, it should
12+
not reappear during that same active session.
13+
- Use banners sparingly, as they can feel intrusive to the user if they appear unexpectedly. Their
14+
effectiveness may decrease if too many are used.
1515
- Avoid stacking multiple banners.
16-
- Banners supports buttons and anchors using [bitLink](?path=/story/component-library-link--anchors).
16+
- Banners support a button link (text button).
1717

1818
## Types
1919

20-
Icons should remain consistent across these types. Do not change the icon without consulting designers.
20+
Icons should remain consistent across these types. Do not change the icon without consulting
21+
designers.
2122

2223
Use the following guidelines to help choose the correct type of banner.
2324

@@ -47,5 +48,6 @@ Rarely used, but may be used to alert users over critical messages or very outda
4748

4849
## Accessibility
4950

50-
Dialogs sets the `role="status"` and `aria-live="polite"` attributes to ensure screen readers announce the content
51-
prior to the test of the page. This behaviour can be disabled by setting `[useAlertRole]="false"`.
51+
Banners sets the `role="status"` and `aria-live="polite"` attributes to ensure screen readers
52+
announce the content prior to the test of the page. This behaviour can be disabled by setting
53+
`[useAlertRole]="false"`.

‎libs/components/src/stories/button-docs.stories.mdx

+45-26
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,53 @@ import { Meta, Story } from "@storybook/addon-docs";
44

55
# Button
66

7-
Use buttons for actions in forms, dialogs, and more with support for style, block, icon, and state.
7+
Buttons are interactive elements that can be triggered using a mouse, keyboard, or touch. They are
8+
used to indicate actions that can be performed by a user such as submitting a form.
89

9-
For pairings in the bottom left corner of a page or component, the `primary` call to action will go on the left side of a button group with the `secondary` call to action option on the left.
10+
## Guidelines
1011

11-
Pairings in the top right corner of a page, should have the `primary` call to action on the right.
12+
### Choosing the `<a>` or `<button>`
1213

13-
Groups of buttons should have 1rem of spacing between them.
14-
15-
## Choosing the `<a>` or `<button>`
16-
17-
Buttons can use either the `<a>` or `<button>` tags. Choose which based on the action the button takes:
14+
Buttons can use either the `<a>` or `<button>` tags. Choose which based on the action the button
15+
takes:
1816

1917
- If navigating to a new page, use `<a>`
2018
- If taking an action on the current page use `<button>`
2119
- If the button launches a dialog, use `<button>`
2220

23-
## Submit and async actions
21+
### Groups
2422

25-
Both submit and async action buttons use a loading button state while an action is taken.
23+
Groups of buttons should be seperated by a `0.5` rem gap. Usually acomplished by using the
24+
`tw-gap-2` class in the button group container.
2625

27-
<Story id="component-library-button--loading" />
26+
Groups within page content, dialog footers or forms should have the `primary` call to action placed
27+
to left. Groups in headers and navigational areas should have the `primary` call to action on the
28+
right.
29+
30+
## Accessibility
31+
32+
Please follow these guidelines to ensure that buttons are accessible to all users.
33+
34+
### Color contrast
35+
36+
All button styles are WCAG compliant when displayed on `background` and `background-alt` colors. To
37+
use a button on a different background, double check that the color contrast is sufficient in both
38+
the light and dark themes.
39+
40+
### Loading Buttons
41+
42+
Include an `aria-label` attribute that defaults to “loading” but can be configurable per
43+
implementation. On click, the screen reader should announce the `aria-label`. Once the action is
44+
compelted, use another messaging pattern to alert the user that the action is complete (example:
45+
success toast).
2846

29-
If your button is preforming a long running task in the background like a server API call, be sure to review the [Async Actions Directive](https://components.bitwarden.com/?path=/story/component-library-async-actions-overview--page).
47+
### Submit and async actions
48+
49+
Both submit and async action buttons use a loading button state while an action is taken. If your
50+
button is preforming a long running task in the background like a server API call, be sure to review
51+
the [Async Actions Directive](?path=/story/component-library-async-actions-overview--page).
52+
53+
<Story id="component-library-button--loading" />
3054

3155
## Styles
3256

@@ -36,13 +60,16 @@ There are 3 main styles for the button: Primary, Secondary, and Danger.
3660

3761
<Story id="component-library-button--primary" />
3862

39-
Use the primary button styling for all Primary call to actions. An action is "primary" if it relates to the main purpose of a page. There should never be 2 primary styled buttons next to each other.
63+
Use the primary button styling for all Primary call to actions. An action is "primary" if it relates
64+
to the main purpose of a page. There should never be 2 primary styled buttons next to each other.
4065

4166
### Secondary
4267

4368
<Story id="component-library-button--secondary" />
4469

45-
The secondary styling should be used for secondary calls to action. An action is "secondary" if it relates indirectly to the purpose of a page. There may be multiple secondary buttons next to each other; however, generally there should only be 1 or 2 calls to action per page.
70+
The secondary styling should be used for secondary calls to action. An action is "secondary" if it
71+
relates indirectly to the purpose of a page. There may be multiple secondary buttons next to each
72+
other; however, generally there should only be 1 or 2 calls to action per page.
4673

4774
### Danger
4875

@@ -52,22 +79,14 @@ Use the danger styling only in settings when the user may preform a permanent ac
5279

5380
## Disabled UI
5481

55-
Both the disabled and loading states use the default state’s color with a 60% opacity or `tw-opacity-60`.
82+
Both the disabled and loading states use the default state’s color with a 60% opacity or
83+
`tw-opacity-60`.
5684

5785
<Story id="component-library-button--disabled" />
5886

5987
## Block
6088

61-
Typically button widths expand with their text. In some causes though buttons may need to be block where the width is fixed and the text wraps to 2 lines if exceeding the button’s width.
89+
Typically button widths expand with their text. In some causes though buttons may need to be block
90+
where the width is fixed and the text wraps to 2 lines if exceeding the button’s width.
6291

6392
<Story id="component-library-button--block" />
64-
65-
## Accessibility
66-
67-
### Color contrast
68-
69-
All button styles are WCAG compliant when displayed on `background` and `background-alt` colors. To use a button on a different background, double check that the color contrast is sufficient in both the light and dark themes.
70-
71-
### Loading Buttons
72-
73-
Include an `aria-label` attribute that defaults to “loading” but can be configurable per implementation. On click, the screen reader should announce the `aria-label`. Once the action is compelted, use another messaging pattern to alert the user that the action is complete (example: success toast).

‎libs/components/src/stories/colors.stories.mdx

+11
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ th {
8989

9090
# Colors
9191

92+
Tailwind traditionally has a very large color palette. Bitwarden has their own more limited color
93+
palette instead.
94+
95+
This has a couple of advantages:
96+
97+
- Promotes consistency across the application.
98+
- Easier to maintain and make adjustments.
99+
- Allows us to support more than two themes light & dark, should it be needed.
100+
101+
Below are all the permited colors. Please consult design before considering adding a new color.
102+
92103
<div class="tw-flex tw-space-x-4">
93104
<Table />
94105
<Table class="theme_dark tw-bg-background" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Meta, Story, Source } from "@storybook/addon-docs";
2+
3+
<Meta title="Documentation/Forms" />
4+
5+
# Forms
6+
7+
Examples and usage guidelines for form control styles, layout options, and custom components for
8+
creating a wide variety of forms.
9+
10+
## Overview
11+
12+
Component Library forms should always be built using [Angular Reactive Forms][reactive]. Please read
13+
[ADR-0001][adr-0001] for a background to this decision. In practice this means that forms should
14+
always use the native `form` element and bind a `formGroup`.
15+
16+
Forms consists of one or multiple sections, and ends with one or multiple buttons.
17+
18+
### Form Field
19+
20+
A form field is the most common section in a form. It consists of a label, control and a optional
21+
hint.
22+
23+
<Story id="component-library-form-field--default" />
24+
25+
<Source id="component-library-form-field--default" />
26+
27+
### Radio group
28+
29+
A radio group is a form field that consists of a main label and multiple radio groups. Each group
30+
consists of a label and a radio input.
31+
32+
#### Block
33+
34+
<Story id="component-library-form-radio-button--block" />
35+
36+
<Source id="component-library-form-radio-button--block" />
37+
38+
#### Inline
39+
40+
<Story id="component-library-form-radio-button--inline" />
41+
42+
<Source id="component-library-form-radio-button--inline" />
43+
44+
## Full Example
45+
46+
<Story id="component-library-form--full-example" />
47+
48+
<Source id="component-library-form--full-example" />
49+
50+
[reactive]: https://angular.io/guide/reactive-forms
51+
[adr-0001]: https://contributing.bitwarden.com/architecture/adr/reactive-forms

‎libs/components/src/stories/icons.stories.mdx

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { Meta } from "@storybook/addon-docs/";
66

77
# Iconography
88

9-
Avoid using icons to convey information unless paired with meaningful, clear text. If an icon must be used and text cannot be displayed visually along with the icon, use an `aria-label` to provide the text to screen readers, and a `title` attribute to provide the text visually through a tool tip. Note: this pattern should only be followed for very common iconography such as, a settings cog icon or an options menu icon.
9+
Avoid using icons to convey information unless paired with meaningful, clear text. If an icon must
10+
be used and text cannot be displayed visually along with the icon, use an `aria-label` to provide
11+
the text to screen readers, and a `title` attribute to provide the text visually through a tool tip.
12+
Note: this pattern should only be followed for very common iconography such as, a settings cog icon
13+
or an options menu icon.
1014

1115
## Status Indicators
1216

‎libs/components/src/stories/input-docs.stories.mdx

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { Meta } from "@storybook/addon-docs";
44

55
# `bitInput`
66

7-
`bitInput` is an Angular directive to be used on `<input>`, `<select>`, and `<textarea>`
8-
tags in order to provide standardized TailwindCss styling, error handling, and more.
9-
It is meant to be used within a `<bit-form-field>` custom component.
7+
`bitInput` is an Angular directive to be used on `<input>`, `<select>`, and `<textarea>` tags in
8+
order to provide standardized TailwindCss styling, error handling, and more. It is meant to be used
9+
within a `<bit-form-field>` custom component.
1010

1111
## Basic Usage Example
1212

@@ -20,8 +20,8 @@ It is meant to be used within a `<bit-form-field>` custom component.
2020

2121
## Disabled `bitInput` and Error Handling
2222

23-
If you would like to be able to still show errors when an input is disabled for
24-
specific validation scenarios, then set `[showErrorsWhenDisabled]="true"`
23+
If you would like to be able to still show errors when an input is disabled for specific validation
24+
scenarios, then set `[showErrorsWhenDisabled]="true"`
2525

2626
```html
2727
<bit-form-field>
@@ -31,7 +31,8 @@ specific validation scenarios, then set `[showErrorsWhenDisabled]="true"`
3131
</bit-form-field>
3232
```
3333

34-
**NOTE:** Disabling a FormControl removes validation errors so you must manually set the errors after disabling:
34+
**NOTE:** Disabling a FormControl removes validation errors so you must manually set the errors
35+
after disabling:
3536

3637
```ts
3738
get exampleFormCtrl(): FormControl {

‎libs/components/src/stories/table-docs.stories.mdx

+62-17
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,37 @@ import { Meta, Story, Source } from "@storybook/addon-docs";
66

77
## Overview
88

9-
All tables should have a visible horizontal header and label for each column.
9+
The table component provides a comprehensive way to display, sort and filter data. It consists of
10+
two portions, a UI component called `bit-table` and the underlying data source `TableDataSource`.
11+
This documentation will initially focus on the UI portion before covering the data source.
12+
13+
## UI Component
14+
15+
The UI component consists of a couple of elements.
16+
17+
- `bit-table`: The main component that creates a native table element and applies the table styling.
18+
- `header`: A container for the table header.
19+
- `body`: A container for the table body.
20+
- `bitCell`: A cell within the table. Used for both headers and content.
21+
22+
### Guidelines
23+
24+
- Always include a row or column header with your table; this allows screen readers to better
25+
contextualize the data
26+
- Avoid spanning data across cells.
27+
- Be sure to make repeating actions unique by associating them with the object they relate to.
28+
Example: if there are multiple “Edit” buttons on a table, a screen reader should read “Edit,
29+
Netflix” for an edit option for a Netflix item.
30+
- Use [Virtual Scrolling](#virtual-scrolling) for large data sets.
31+
32+
### Example
1033

1134
<Story id="component-library-table--default" />
1235

13-
The below code is the absolute minimum required to create a table. However we strongly advise you to
14-
use the `dataSource` input to provide a data source for your table. This allows you to easily sort
15-
data.
36+
### Usage
37+
38+
The below code is the minimum required to create a table. However we strongly advise you to use the
39+
`dataSource` input to provide a data source for your table. This allows you to easily sort data.
1640

1741
```html
1842
<bit-table>
@@ -36,9 +60,8 @@ data.
3660
## Data Source
3761

3862
Bitwarden provides a data source for tables that can be used in place of a traditional data array.
39-
The `TableDataSource` implements sorting and will in the future also support filtering. This allows
40-
the `bitTable` component to focus on rendering while offloading the data management to the data
41-
source.
63+
The `TableDataSource` implements sorting and filtering capabilities. This allows the `bitTable`
64+
component to focus on rendering while offloading the data management to the data source.
4265

4366
```ts
4467
// External data source
@@ -51,14 +74,31 @@ dataSource.data = data;
5174
We use the `dataSource` as an input to the `bit-table` component, and access the rows to render
5275
within the `ng-template`which provides access to the rows using `let-rows$`.
5376

54-
<Source id="component-library-table--data-source" />
77+
```html
78+
<bit-table [dataSource]="dataSource">
79+
<ng-container header>
80+
<tr>
81+
<th bitCell bitSortable="id" default>Id</th>
82+
<th bitCell bitSortable="name">Name</th>
83+
<th bitCell bitSortable="other" [fn]="sortFn">Other</th>
84+
</tr>
85+
</ng-container>
86+
<ng-template body let-rows$>
87+
<tr bitRow *ngFor="let r of rows$ | async">
88+
<td bitCell>{{ r.id }}</td>
89+
<td bitCell>{{ r.name }}</td>
90+
<td bitCell>{{ r.other }}</td>
91+
</tr>
92+
</ng-template>
93+
</bit-table>
94+
```
5595

56-
### Sortable
96+
### Sorting
5797

5898
We provide a simple component for displaying sortable column headers. The `bitSortable` component
59-
wires up to the `TableDataSource` and will automatically sort the data when clicked and display
60-
an indicator for which column is currently sorted. The dafault sorting can be specified by setting
61-
the `default`.
99+
wires up to the `TableDataSource` and will automatically sort the data when clicked and display an
100+
indicator for which column is currently sorted. The dafault sorting can be specified by setting the
101+
`default`.
62102

63103
```html
64104
<th bitCell bitSortable="id" default>Id</th>
@@ -71,6 +111,16 @@ It's also possible to define a custom sorting function by setting the `fn` input
71111
const sortFn = (a: T, b: T) => (a.id > b.id ? 1 : -1);
72112
```
73113

114+
### Filtering
115+
116+
The `TableDataSource` supports a rudimentary filtering capability most commonly used to implement a
117+
search function. It works by converting each entry into a string of it's properties. The string is
118+
then compared against the filter value using a simple `indexOf`check.
119+
120+
```ts
121+
dataSource.filter = "search value";
122+
```
123+
74124
### Virtual Scrolling
75125

76126
It's heavily adviced to use virtual scrolling if you expect the table to have any significant amount
@@ -97,8 +147,3 @@ specify a `itemSize`, set `scrollWindow` to `true` and replace `*ngFor` with `*c
97147
</bit-table>
98148
</cdk-virtual-scroll-viewport>
99149
```
100-
101-
## Accessibility
102-
103-
- Always incude a row or column header with your table; this allows screen readers to better contextualize the data
104-
- Avoid spanning data across cells

0 commit comments

Comments
 (0)
Please sign in to comment.