2023-11-20 02:10:17 +01:00
|
|
|
import { Meta } from "@storybook/addon-docs";
|
|
|
|
|
|
|
|
<Meta title="Documentation/Migration" />
|
|
|
|
|
|
|
|
# Migrating to the Component Library
|
|
|
|
|
|
|
|
You have been tasked with migrating a component to use the CL. What does that entail?
|
|
|
|
|
|
|
|
## Getting Started
|
|
|
|
|
|
|
|
Before progressing here, please ensure that...
|
|
|
|
|
|
|
|
- You have fully setup your dev environment as described in the
|
|
|
|
[contributing docs](https://contributing.bitwarden.com/).
|
|
|
|
- You are familiar with [Angular reactive forms](https://angular.io/guide/reactive-forms).
|
|
|
|
- You are familiar with [Tailwind](https://tailwindcss.com/docs/utility-first).
|
|
|
|
|
|
|
|
## Background
|
|
|
|
|
|
|
|
The design of Bitwarden is in flux. At the time of writing, the frontend codebase uses a mix of
|
|
|
|
multiple UI frameworks: Bootstrap, custom "box" styles, and this component library, which is built
|
|
|
|
on top of Tailwind. In short, the "CL migration" is a move to only use the CL and remove everything
|
|
|
|
else.
|
|
|
|
|
|
|
|
This is very important work. Centralizing around a shared design system will:
|
|
|
|
|
|
|
|
- improve user experience by utilizing consistent patterns
|
|
|
|
- improve developer experience by reducing custom complex UI code
|
|
|
|
- improve dev & design velocity by having a central location to make UI/UX changes that impact the
|
|
|
|
entire project
|
|
|
|
|
|
|
|
## Success Criteria
|
|
|
|
|
|
|
|
Follow these steps to fully migrate a component.
|
|
|
|
|
|
|
|
### Use Storybook
|
|
|
|
|
|
|
|
Don't recreate the wheel.
|
|
|
|
|
|
|
|
After reviewing a design, consult this Storybook to determine if there is a component built for your
|
|
|
|
usecase. Don't waste effort styling a button or building a popover menu from scratch--we already
|
2023-12-08 17:37:03 +01:00
|
|
|
have those. If a component isn't flexible enough or doesn't exist for your usecase, contact the
|
|
|
|
Component Library team.
|
2023-11-20 02:10:17 +01:00
|
|
|
|
|
|
|
### Use Tailwind
|
|
|
|
|
|
|
|
Only use Tailwind for styling. No Bootstrap or other custom CSS is allowed.
|
|
|
|
|
|
|
|
This is easy to verify. Bitwarden prefixes all Tailwind classes with `tw-`. If you see a class
|
|
|
|
without this prefix, it probably shouldn't be there.
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-danger-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
<span class="tw-font-bold tw-text-danger">Bad (Bootstrap)</span>
|
|
|
|
```html
|
|
|
|
<div class="mb-2"></div>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
<span class="tw-font-bold tw-text-success">Good (Tailwind)</span>
|
|
|
|
```html
|
|
|
|
<div class="tw-mb-2"></div>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
|
|
**Exception:** Icon font classes, prefixed with `bwi`, are allowed.
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
<span class="tw-font-bold tw-text-success">Good (Icons)</span>
|
|
|
|
```html
|
|
|
|
<i class="bwi bwi-spinner bwi-lg bwi-spin" aria-hidden="true"></i>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
|
|
### Use Reactive Forms
|
|
|
|
|
|
|
|
The CL has form components that integrate with Angular's reactive forms: `bit-form-field`,
|
|
|
|
`bitSubmit`, `bit-form-control`, etc. All forms should be migrated from template-drive forms to
|
|
|
|
reactive forms to make use of these components. Review the
|
|
|
|
[form component docs](?path=/docs/component-library-form--docs).
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-danger-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
<span class="tw-text-danger tw-font-bold">Bad</span>
|
|
|
|
```html
|
|
|
|
<form #form (ngSubmit)="submit()">
|
|
|
|
...
|
|
|
|
</form>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
<span class="tw-text-success tw-font-bold">Good</span>
|
|
|
|
```html
|
|
|
|
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
|
|
|
...
|
|
|
|
</form>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
|
|
### Dialogs
|
|
|
|
|
|
|
|
Legacy Bootstrap modals use the `ModalService`. These should be converted to use the `DialogService`
|
|
|
|
and it's [related CL components](?path=/docs/component-library-dialogs--docs). Components that are
|
|
|
|
fully migrated should have no reference to the `ModalService`.
|
|
|
|
|
|
|
|
1. Update the template to use CL components:
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-danger-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
```html
|
|
|
|
<!-- FooDialogComponent -->
|
|
|
|
<div class="modal fade" role="dialog" aria-modal="true">...</div>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
```html
|
|
|
|
<!-- FooDialogComponent -->
|
|
|
|
<bit-dialog>...</bit-dialog>
|
|
|
|
```
|
|
|
|
</div>
|
|
|
|
|
|
|
|
2. Create a static `open` method on the component, that calls `DialogService.open`:
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
```ts
|
|
|
|
export class FooDialogComponent {
|
|
|
|
//...
|
|
|
|
|
|
|
|
static open(dialogService: DialogService) {
|
|
|
|
return dialogService.open(DeleteAccountComponent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
3. If you need to pass data into the dialog, pass it to `open` as a parameter and inject
|
|
|
|
`DIALOG_DATA` into the component's constructor.
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">
|
2023-11-20 02:10:17 +01:00
|
|
|
```ts
|
|
|
|
export type FooDialogParams = {
|
|
|
|
bar: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class FooDialogComponent {
|
|
|
|
constructor(@Inject(DIALOG_DATA) protected params: FooDialogParams) {}
|
|
|
|
|
|
|
|
static open(dialogService: DialogService, data: FooDialogParams) {
|
|
|
|
return dialogService.open(DeleteAccountComponent, { data });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
4. Replace calls to `ModalService.open` or `ModalService.openViewRef` with the newly created static
|
|
|
|
`open` method:
|
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-danger-600/10 tw-p-4">`this.modalService.open(FooDialogComponent);`</div>
|
2023-11-20 02:10:17 +01:00
|
|
|
|
2024-04-05 16:58:32 +02:00
|
|
|
<div class="tw-bg-success-600/10 tw-p-4">`FooDialogComponent.open(this.dialogService);`</div>
|
2023-11-20 02:10:17 +01:00
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
|
The following examples come from accross the Bitwarden codebase.
|
|
|
|
|
|
|
|
### 1.) AboutComponent
|
|
|
|
|
|
|
|
Codeowner: Platform
|
|
|
|
|
|
|
|
https://github.com/bitwarden/clients/pull/6301/files
|
|
|
|
|
|
|
|
This migration updates a `ModalService` component to the `DialogService`.
|
|
|
|
|
|
|
|
**Note:** Most of the internal markup of this component was unchanged, aside from the removal of
|
|
|
|
defunct Bootstrap classes.
|
|
|
|
|
|
|
|
### 2.) Auth
|
|
|
|
|
|
|
|
Codeowner: Auth
|
|
|
|
|
|
|
|
https://github.com/bitwarden/clients/pull/5377
|
|
|
|
|
|
|
|
This PR also does some general refactoring, the main relevant change can be seen here:
|
|
|
|
|
|
|
|
[Old template](https://github.com/bitwarden/clients/pull/5377/files#diff-4fcab9ffa4ed26904c53da3bd130e346986576f2372e90b0f66188c809f9284d)
|
|
|
|
-->
|
|
|
|
[New template](https://github.com/bitwarden/clients/pull/5377/files#diff-cb93c74c828b9b49dc7869cc0324f5f7d6609da6f72e38ac6baba6d5b6384327)
|
|
|
|
|
|
|
|
Updates a dialog, similar to example 1, but also adds CL form components and Angular Reactive Forms.
|
|
|
|
|
|
|
|
### 3.) AC
|
|
|
|
|
|
|
|
Codeowner: Admin Console
|
|
|
|
|
|
|
|
https://github.com/bitwarden/clients/pull/5417
|
|
|
|
|
|
|
|
Migrates dialog, form, buttons, and a table.
|
|
|
|
|
|
|
|
### 4.) Vault
|
|
|
|
|
|
|
|
Codeowner: Vault
|
|
|
|
|
|
|
|
https://github.com/bitwarden/clients/pull/5648
|
|
|
|
|
|
|
|
Some of our components are shared between multiple clients (web, desktop, and the browser extension)
|
|
|
|
through the use of inheritance. This PR updates the _web_ template of a cross-client component to
|
|
|
|
use Tailwind and the CL, and updates the base component implementation to use reactive forms,
|
|
|
|
without updating the desktop or browser templates.
|
|
|
|
|
|
|
|
## Questions
|
|
|
|
|
2023-12-08 17:37:03 +01:00
|
|
|
Please direct any development questions to the Component Library team. Thank you!
|