1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-19 15:57:42 +01:00

[CL-135] Migrate component library to standalone components (#12389)

* Migrate component library to standalone components

* Fix tests
This commit is contained in:
Oscar Hinton 2024-12-17 23:29:48 +01:00 committed by GitHub
parent ac13cf7ce6
commit 5a582dfc6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
101 changed files with 330 additions and 216 deletions

View File

@ -6,7 +6,7 @@ import { BehaviorSubject } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { BitIconButtonComponent } from "@bitwarden/components/src/icon-button/icon-button.component";
import { IconButtonModule, NavigationModule } from "@bitwarden/components";
import { NavItemComponent } from "@bitwarden/components/src/navigation/nav-item.component";
import { ProductSwitcherItem, ProductSwitcherService } from "../shared/product-switcher.service";
@ -45,13 +45,8 @@ describe("NavigationProductSwitcherComponent", () => {
mockProducts$.next({ bento: [], other: [] });
await TestBed.configureTestingModule({
imports: [RouterModule],
declarations: [
NavigationProductSwitcherComponent,
NavItemComponent,
BitIconButtonComponent,
I18nPipe,
],
imports: [RouterModule, NavigationModule, IconButtonModule],
declarations: [NavigationProductSwitcherComponent, I18nPipe],
providers: [
{ provide: ProductSwitcherService, useValue: productSwitcherService },
{

View File

@ -13,7 +13,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { TableModule } from "@bitwarden/components";
import { TableBodyDirective } from "@bitwarden/components/src/table/table.component";
import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared";
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
@ -27,7 +26,7 @@ describe("PasswordHealthComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PasswordHealthComponent, PipesModule, TableModule, LooseComponentsModule],
declarations: [TableBodyDirective],
declarations: [],
providers: [
{ provide: CipherService, useValue: mock<CipherService>() },
{ provide: I18nService, useValue: mock<I18nService>() },

View File

@ -1,14 +1,11 @@
import { NgModule } from "@angular/core";
import { SharedModule } from "../shared";
import { BitActionDirective } from "./bit-action.directive";
import { BitSubmitDirective } from "./bit-submit.directive";
import { BitFormButtonDirective } from "./form-button.directive";
@NgModule({
imports: [SharedModule],
declarations: [BitActionDirective, BitFormButtonDirective, BitSubmitDirective],
imports: [BitActionDirective, BitFormButtonDirective, BitSubmitDirective],
exports: [BitActionDirective, BitFormButtonDirective, BitSubmitDirective],
})
export class AsyncActionsModule {}

View File

@ -15,6 +15,7 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
*/
@Directive({
selector: "[bitAction]",
standalone: true,
})
export class BitActionDirective implements OnDestroy {
private destroy$ = new Subject<void>();

View File

@ -14,6 +14,7 @@ import { FunctionReturningAwaitable, functionToObservable } from "../utils/funct
*/
@Directive({
selector: "[formGroup][bitSubmit]",
standalone: true,
})
export class BitSubmitDirective implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();

View File

@ -25,6 +25,7 @@ import { BitSubmitDirective } from "./bit-submit.directive";
*/
@Directive({
selector: "button[bitFormButton]",
standalone: true,
})
export class BitFormButtonDirective implements OnDestroy {
private destroy$ = new Subject<void>();

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf, NgClass } from "@angular/common";
import { Component, Input, OnChanges } from "@angular/core";
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";
@ -18,6 +19,8 @@ const SizeClasses: Record<SizeTypes, string[]> = {
@Component({
selector: "bit-avatar",
template: `<img *ngIf="src" [src]="src" title="{{ title || text }}" [ngClass]="classList" />`,
standalone: true,
imports: [NgIf, NgClass],
})
export class AvatarComponent implements OnChanges {
@Input() border = false;

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { AvatarComponent } from "./avatar.component";
@NgModule({
imports: [CommonModule],
imports: [AvatarComponent],
exports: [AvatarComponent],
declarations: [AvatarComponent],
})
export class AvatarModule {}

View File

@ -1,12 +1,16 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, Input, OnChanges } from "@angular/core";
import { BadgeVariant } from "../badge";
import { BadgeModule, BadgeVariant } from "../badge";
import { I18nPipe } from "../shared/i18n.pipe";
@Component({
selector: "bit-badge-list",
templateUrl: "badge-list.component.html",
standalone: true,
imports: [CommonModule, BadgeModule, I18nPipe],
})
export class BadgeListComponent implements OnChanges {
private _maxItems: number;

View File

@ -1,13 +1,9 @@
import { NgModule } from "@angular/core";
import { BadgeModule } from "../badge";
import { SharedModule } from "../shared";
import { BadgeListComponent } from "./badge-list.component";
@NgModule({
imports: [SharedModule, BadgeModule],
imports: [BadgeListComponent],
exports: [BadgeListComponent],
declarations: [BadgeListComponent],
})
export class BadgeListModule {}

View File

@ -31,6 +31,7 @@ const hoverStyles: Record<BadgeVariant, string[]> = {
@Directive({
selector: "span[bitBadge], a[bitBadge], button[bitBadge]",
providers: [{ provide: FocusableElement, useExisting: BadgeDirective }],
standalone: true,
})
export class BadgeDirective implements FocusableElement {
@HostBinding("class") get classList() {

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BadgeDirective } from "./badge.directive";
@NgModule({
imports: [CommonModule],
imports: [BadgeDirective],
exports: [BadgeDirective],
declarations: [BadgeDirective],
})
export class BadgeModule {}

View File

@ -2,7 +2,6 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { SharedModule } from "../shared/shared.module";
import { I18nMockService } from "../utils/i18n-mock.service";
import { BannerComponent } from "./banner.component";
@ -13,8 +12,7 @@ describe("BannerComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SharedModule],
declarations: [BannerComponent],
imports: [BannerComponent],
providers: [
{
provide: I18nService,

View File

@ -1,7 +1,11 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, Input, OnInit, Output, EventEmitter } from "@angular/core";
import { IconButtonModule } from "../icon-button";
import { I18nPipe } from "../shared/i18n.pipe";
type BannerTypes = "premium" | "info" | "warning" | "danger";
const defaultIcon: Record<BannerTypes, string> = {
@ -14,6 +18,8 @@ const defaultIcon: Record<BannerTypes, string> = {
@Component({
selector: "bit-banner",
templateUrl: "./banner.component.html",
standalone: true,
imports: [CommonModule, IconButtonModule, I18nPipe],
})
export class BannerComponent implements OnInit {
@Input("bannerType") bannerType: BannerTypes = "info";

View File

@ -1,14 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IconButtonModule } from "../icon-button";
import { SharedModule } from "../shared/shared.module";
import { BannerComponent } from "./banner.component";
@NgModule({
imports: [CommonModule, SharedModule, IconButtonModule],
imports: [BannerComponent],
exports: [BannerComponent],
declarations: [BannerComponent],
})
export class BannerModule {}

View File

@ -1,11 +1,14 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf } from "@angular/common";
import { Component, EventEmitter, Input, Output, TemplateRef, ViewChild } from "@angular/core";
import { QueryParamsHandling } from "@angular/router";
@Component({
selector: "bit-breadcrumb",
templateUrl: "./breadcrumb.component.html",
standalone: true,
imports: [NgIf],
})
export class BreadcrumbComponent {
@Input()

View File

@ -1,10 +1,18 @@
import { CommonModule } from "@angular/common";
import { Component, ContentChildren, Input, QueryList } from "@angular/core";
import { RouterModule } from "@angular/router";
import { IconButtonModule } from "../icon-button";
import { LinkModule } from "../link";
import { MenuModule } from "../menu";
import { BreadcrumbComponent } from "./breadcrumb.component";
@Component({
selector: "bit-breadcrumbs",
templateUrl: "./breadcrumbs.component.html",
standalone: true,
imports: [CommonModule, LinkModule, RouterModule, IconButtonModule, MenuModule],
})
export class BreadcrumbsComponent {
@Input()

View File

@ -1,17 +1,10 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { IconButtonModule } from "../icon-button";
import { LinkModule } from "../link";
import { MenuModule } from "../menu";
import { BreadcrumbComponent } from "./breadcrumb.component";
import { BreadcrumbsComponent } from "./breadcrumbs.component";
@NgModule({
imports: [CommonModule, LinkModule, IconButtonModule, MenuModule, RouterModule],
declarations: [BreadcrumbsComponent, BreadcrumbComponent],
imports: [BreadcrumbsComponent, BreadcrumbComponent],
exports: [BreadcrumbsComponent, BreadcrumbComponent],
})
export class BreadcrumbsModule {}

View File

@ -1,6 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass } from "@angular/common";
import { Input, HostBinding, Component } from "@angular/core";
import { ButtonLikeAbstraction, ButtonType } from "../shared/button-like.abstraction";
@ -46,6 +47,8 @@ const buttonStyles: Record<ButtonType, string[]> = {
selector: "button[bitButton], a[bitButton]",
templateUrl: "button.component.html",
providers: [{ provide: ButtonLikeAbstraction, useExisting: ButtonComponent }],
standalone: true,
imports: [NgClass],
})
export class ButtonComponent implements ButtonLikeAbstraction {
@HostBinding("class") get classList() {

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { ButtonComponent } from "./button.component";
@NgModule({
imports: [CommonModule],
imports: [ButtonComponent],
exports: [ButtonComponent],
declarations: [ButtonComponent],
})
export class ButtonModule {}

View File

@ -9,6 +9,7 @@ import { BitFormControlAbstraction } from "../form-control";
selector: "input[type=checkbox][bitCheckbox]",
template: "",
providers: [{ provide: BitFormControlAbstraction, useExisting: CheckboxComponent }],
standalone: true,
})
export class CheckboxComponent implements BitFormControlAbstraction {
@HostBinding("class")

View File

@ -1,14 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormControlModule } from "../form-control";
import { SharedModule } from "../shared";
import { CheckboxComponent } from "./checkbox.component";
@NgModule({
imports: [SharedModule, CommonModule, FormControlModule],
declarations: [CheckboxComponent],
imports: [CheckboxComponent],
exports: [CheckboxComponent],
})
export class CheckboxModule {}

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgFor, NgIf } from "@angular/common";
import { Component, HostBinding, Input } from "@angular/core";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@ -23,6 +24,8 @@ enum CharacterType {
}}</span>
</span>`,
preserveWhitespaces: false,
standalone: true,
imports: [NgFor, NgIf],
})
export class ColorPasswordComponent {
@Input() password: string = null;

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { ColorPasswordComponent } from "./color-password.component";
@NgModule({
imports: [CommonModule],
imports: [ColorPasswordComponent],
exports: [ColorPasswordComponent],
declarations: [ColorPasswordComponent],
})
export class ColorPasswordModule {}

View File

@ -1,44 +1,25 @@
import { DialogModule as CdkDialogModule } from "@angular/cdk/dialog";
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";
import { AsyncActionsModule } from "../async-actions";
import { ButtonModule } from "../button";
import { IconButtonModule } from "../icon-button";
import { SharedModule } from "../shared";
import { TypographyModule } from "../typography";
import { DialogComponent } from "./dialog/dialog.component";
import { DialogService } from "./dialog.service";
import { DialogCloseDirective } from "./directives/dialog-close.directive";
import { DialogTitleContainerDirective } from "./directives/dialog-title-container.directive";
import { SimpleConfigurableDialogComponent } from "./simple-dialog/simple-configurable-dialog/simple-configurable-dialog.component";
import { IconDirective, SimpleDialogComponent } from "./simple-dialog/simple-dialog.component";
@NgModule({
imports: [
SharedModule,
AsyncActionsModule,
ButtonModule,
CdkDialogModule,
IconButtonModule,
ReactiveFormsModule,
TypographyModule,
],
declarations: [
DialogCloseDirective,
DialogTitleContainerDirective,
DialogComponent,
SimpleDialogComponent,
SimpleConfigurableDialogComponent,
IconDirective,
],
exports: [
CdkDialogModule,
DialogComponent,
SimpleDialogComponent,
DialogCloseDirective,
DialogComponent,
IconDirective,
SimpleDialogComponent,
],
providers: [DialogService],
})

View File

@ -1,14 +1,29 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { CommonModule } from "@angular/common";
import { Component, HostBinding, Input } from "@angular/core";
import { BitIconButtonComponent } from "../../icon-button/icon-button.component";
import { I18nPipe } from "../../shared/i18n.pipe";
import { TypographyDirective } from "../../typography/typography.directive";
import { fadeIn } from "../animations";
import { DialogCloseDirective } from "../directives/dialog-close.directive";
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
@Component({
selector: "bit-dialog",
templateUrl: "./dialog.component.html",
animations: [fadeIn],
standalone: true,
imports: [
CommonModule,
DialogTitleContainerDirective,
TypographyDirective,
BitIconButtonComponent,
DialogCloseDirective,
I18nPipe,
],
})
export class DialogComponent {
/** Background color */

View File

@ -3,6 +3,7 @@ import { Directive, HostBinding, HostListener, Input, Optional } from "@angular/
@Directive({
selector: "[bitDialogClose]",
standalone: true,
})
export class DialogCloseDirective {
@Input("bitDialogClose") dialogResult: any;

View File

@ -6,6 +6,7 @@ let nextId = 0;
@Directive({
selector: "[bitDialogTitleContainer]",
standalone: true,
})
export class DialogTitleContainerDirective implements OnInit {
@HostBinding("id") id = `bit-dialog-title-${nextId++}`;

View File

@ -1,12 +1,17 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
import { NgIf } from "@angular/common";
import { Component, Inject } from "@angular/core";
import { FormGroup } from "@angular/forms";
import { FormGroup, ReactiveFormsModule } from "@angular/forms";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { SimpleDialogOptions, SimpleDialogType, Translation } from "../..";
import { BitSubmitDirective } from "../../../async-actions/bit-submit.directive";
import { BitFormButtonDirective } from "../../../async-actions/form-button.directive";
import { ButtonComponent } from "../../../button/button.component";
import { SimpleDialogComponent, IconDirective } from "../simple-dialog.component";
const DEFAULT_ICON: Record<SimpleDialogType, string> = {
primary: "bwi-business",
@ -26,6 +31,16 @@ const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
@Component({
templateUrl: "./simple-configurable-dialog.component.html",
standalone: true,
imports: [
ReactiveFormsModule,
BitSubmitDirective,
SimpleDialogComponent,
IconDirective,
ButtonComponent,
BitFormButtonDirective,
NgIf,
],
})
export class SimpleConfigurableDialogComponent {
get iconClasses() {

View File

@ -1,14 +1,22 @@
import { NgIf } from "@angular/common";
import { Component, ContentChild, Directive } from "@angular/core";
import { TypographyDirective } from "../../typography/typography.directive";
import { fadeIn } from "../animations";
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
@Directive({ selector: "[bitDialogIcon]" })
@Directive({
selector: "[bitDialogIcon]",
standalone: true,
})
export class IconDirective {}
@Component({
selector: "bit-simple-dialog",
templateUrl: "./simple-dialog.component.html",
animations: [fadeIn],
standalone: true,
imports: [NgIf, DialogTitleContainerDirective, TypographyDirective],
})
export class SimpleDialogComponent {
@ContentChild(IconDirective) icon!: IconDirective;

View File

@ -1,15 +1,21 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass, NgIf } from "@angular/common";
import { Component, ContentChild, HostBinding, Input } from "@angular/core";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { I18nPipe } from "../shared/i18n.pipe";
import { TypographyDirective } from "../typography/typography.directive";
import { BitFormControlAbstraction } from "./form-control.abstraction";
@Component({
selector: "bit-form-control",
templateUrl: "form-control.component.html",
standalone: true,
imports: [NgClass, TypographyDirective, NgIf, I18nPipe],
})
export class FormControlComponent {
@Input() label: string;

View File

@ -1,15 +1,11 @@
import { NgModule } from "@angular/core";
import { SharedModule } from "../shared";
import { TypographyModule } from "../typography";
import { FormControlComponent } from "./form-control.component";
import { BitHintComponent } from "./hint.component";
import { BitLabel } from "./label.component";
@NgModule({
imports: [SharedModule, BitLabel, TypographyModule],
declarations: [FormControlComponent, BitHintComponent],
imports: [BitLabel, FormControlComponent, BitHintComponent],
exports: [FormControlComponent, BitLabel, BitHintComponent],
})
export class FormControlModule {}

View File

@ -8,6 +8,7 @@ let nextId = 0;
host: {
class: "tw-text-muted tw-font-normal tw-inline-block tw-mt-1 tw-text-xs",
},
standalone: true,
})
export class BitHintComponent {
@HostBinding() id = `bit-hint-${nextId++}`;

View File

@ -1,8 +1,11 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf } from "@angular/common";
import { Component, Input } from "@angular/core";
import { AbstractControl, UntypedFormGroup } from "@angular/forms";
import { I18nPipe } from "../shared/i18n.pipe";
@Component({
selector: "bit-error-summary",
template: ` <ng-container *ngIf="errorCount > 0">
@ -12,6 +15,8 @@ import { AbstractControl, UntypedFormGroup } from "@angular/forms";
class: "tw-block tw-text-danger tw-mt-2",
"aria-live": "assertive",
},
standalone: true,
imports: [NgIf, I18nPipe],
})
export class BitErrorSummary {
@Input()

View File

@ -14,6 +14,7 @@ let nextId = 0;
class: "tw-block tw-mt-1 tw-text-danger tw-text-xs",
"aria-live": "assertive",
},
standalone: true,
})
export class BitErrorComponent {
@HostBinding() id = `bit-error-${nextId++}`;

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import {
AfterContentChecked,
booleanAttribute,
@ -16,6 +17,7 @@ import {
import { BitHintComponent } from "../form-control/hint.component";
import { BitLabel } from "../form-control/label.component";
import { inputBorderClasses } from "../input/input.directive";
import { I18nPipe } from "../shared/i18n.pipe";
import { BitErrorComponent } from "./error.component";
import { BitFormFieldControl } from "./form-field-control";
@ -23,6 +25,8 @@ import { BitFormFieldControl } from "./form-field-control";
@Component({
selector: "bit-form-field",
templateUrl: "./form-field.component.html",
standalone: true,
imports: [CommonModule, BitErrorComponent, I18nPipe],
})
export class BitFormFieldComponent implements AfterContentChecked {
@ContentChild(BitFormFieldControl) input: BitFormFieldControl;

View File

@ -1,11 +1,8 @@
import { NgModule } from "@angular/core";
import { FormControlModule } from "../form-control";
import { BitInputDirective } from "../input/input.directive";
import { InputModule } from "../input/input.module";
import { MultiSelectComponent } from "../multi-select/multi-select.component";
import { MultiSelectModule } from "../multi-select/multi-select.module";
import { SharedModule } from "../shared";
import { BitErrorSummary } from "./error-summary.component";
import { BitErrorComponent } from "./error.component";
@ -15,8 +12,11 @@ import { BitPrefixDirective } from "./prefix.directive";
import { BitSuffixDirective } from "./suffix.directive";
@NgModule({
imports: [SharedModule, FormControlModule, InputModule, MultiSelectModule],
declarations: [
imports: [
FormControlModule,
InputModule,
MultiSelectModule,
BitErrorComponent,
BitErrorSummary,
BitFormFieldComponent,
@ -25,15 +25,16 @@ import { BitSuffixDirective } from "./suffix.directive";
BitSuffixDirective,
],
exports: [
FormControlModule,
InputModule,
MultiSelectModule,
BitErrorComponent,
BitErrorSummary,
BitFormFieldComponent,
BitInputDirective,
BitPasswordInputToggleDirective,
BitPrefixDirective,
BitSuffixDirective,
MultiSelectComponent,
FormControlModule,
],
})
export class FormFieldModule {}

View File

@ -18,6 +18,7 @@ import { BitFormFieldComponent } from "./form-field.component";
@Directive({
selector: "[bitPasswordInputToggle]",
standalone: true,
})
export class BitPasswordInputToggleDirective implements AfterContentInit, OnChanges {
/**

View File

@ -4,6 +4,7 @@ import { BitIconButtonComponent } from "../icon-button/icon-button.component";
@Directive({
selector: "[bitPrefix]",
standalone: true,
})
export class BitPrefixDirective implements OnInit {
@HostBinding("class") @Input() get classList() {

View File

@ -4,6 +4,7 @@ import { BitIconButtonComponent } from "../icon-button/icon-button.component";
@Directive({
selector: "[bitSuffix]",
standalone: true,
})
export class BitSuffixDirective implements OnInit {
@HostBinding("class") @Input() get classList() {

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgClass } from "@angular/common";
import { Component, ElementRef, HostBinding, Input } from "@angular/core";
import { ButtonLikeAbstraction, ButtonType } from "../shared/button-like.abstraction";
@ -134,6 +135,8 @@ const sizes: Record<IconButtonSize, string[]> = {
{ provide: ButtonLikeAbstraction, useExisting: BitIconButtonComponent },
{ provide: FocusableElement, useExisting: BitIconButtonComponent },
],
standalone: true,
imports: [NgClass],
})
export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableElement {
@Input("bitIconButton") icon: string;

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BitIconButtonComponent } from "./icon-button.component";
@NgModule({
imports: [CommonModule],
declarations: [BitIconButtonComponent],
imports: [BitIconButtonComponent],
exports: [BitIconButtonComponent],
})
export class IconButtonModule {}

View File

@ -8,6 +8,7 @@ import { Icon, isIcon } from "./icon";
@Component({
selector: "bit-icon",
template: ``,
standalone: true,
})
export class BitIconComponent {
@Input() set icon(icon: Icon) {

View File

@ -9,7 +9,7 @@ describe("IconComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [BitIconComponent],
imports: [BitIconComponent],
}).compileComponents();
fixture = TestBed.createComponent(BitIconComponent);

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BitIconComponent } from "./icon.component";
@NgModule({
imports: [CommonModule],
declarations: [BitIconComponent],
imports: [BitIconComponent],
exports: [BitIconComponent],
})
export class IconModule {}

View File

@ -30,6 +30,7 @@ export function inputBorderClasses(error: boolean) {
@Directive({
selector: "input[bitInput], select[bitInput], textarea[bitInput]",
providers: [{ provide: BitFormFieldControl, useExisting: BitInputDirective }],
standalone: true,
})
export class BitInputDirective implements BitFormFieldControl {
@HostBinding("class") @Input() get classList() {

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BitInputDirective } from "./input.directive";
@NgModule({
imports: [CommonModule],
declarations: [BitInputDirective],
imports: [BitInputDirective],
exports: [BitInputDirective],
})
export class InputModule {}

View File

@ -68,6 +68,7 @@ abstract class LinkDirective {
@Directive({
selector: "a[bitLink]",
standalone: true,
})
export class AnchorLinkDirective extends LinkDirective {
@HostBinding("class") get classList() {
@ -79,6 +80,7 @@ export class AnchorLinkDirective extends LinkDirective {
@Directive({
selector: "button[bitLink]",
standalone: true,
})
export class ButtonLinkDirective extends LinkDirective {
@HostBinding("class") get classList() {

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { AnchorLinkDirective, ButtonLinkDirective } from "./link.directive";
@NgModule({
imports: [CommonModule],
imports: [AnchorLinkDirective, ButtonLinkDirective],
exports: [AnchorLinkDirective, ButtonLinkDirective],
declarations: [AnchorLinkDirective, ButtonLinkDirective],
})
export class LinkModule {}

View File

@ -3,5 +3,6 @@ import { Component } from "@angular/core";
@Component({
selector: "bit-menu-divider",
templateUrl: "./menu-divider.component.html",
standalone: true,
})
export class MenuDividerComponent {}

View File

@ -1,10 +1,13 @@
import { FocusableOption } from "@angular/cdk/a11y";
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass } from "@angular/common";
import { Component, ElementRef, HostBinding, Input } from "@angular/core";
@Component({
selector: "[bitMenuItem]",
templateUrl: "menu-item.component.html",
standalone: true,
imports: [NgClass],
})
export class MenuItemDirective implements FocusableOption {
@HostBinding("class") classList = [

View File

@ -19,6 +19,7 @@ import { MenuComponent } from "./menu.component";
@Directive({
selector: "[bitMenuTriggerFor]",
exportAs: "menuTrigger",
standalone: true,
})
export class MenuTriggerForDirective implements OnDestroy {
@HostBinding("attr.aria-expanded") isOpen = false;

View File

@ -1,6 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { FocusKeyManager } from "@angular/cdk/a11y";
import { FocusKeyManager, CdkTrapFocus } from "@angular/cdk/a11y";
import {
Component,
Output,
@ -19,6 +19,8 @@ import { MenuItemDirective } from "./menu-item.directive";
selector: "bit-menu",
templateUrl: "./menu.component.html",
exportAs: "menuComponent",
standalone: true,
imports: [CdkTrapFocus],
})
export class MenuComponent implements AfterContentInit {
@ViewChild(TemplateRef) templateRef: TemplateRef<any>;

View File

@ -1,6 +1,3 @@
import { A11yModule } from "@angular/cdk/a11y";
import { OverlayModule } from "@angular/cdk/overlay";
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { MenuDividerComponent } from "./menu-divider.component";
@ -9,8 +6,7 @@ import { MenuTriggerForDirective } from "./menu-trigger-for.directive";
import { MenuComponent } from "./menu.component";
@NgModule({
imports: [A11yModule, CommonModule, OverlayModule],
declarations: [MenuComponent, MenuTriggerForDirective, MenuItemDirective, MenuDividerComponent],
imports: [MenuComponent, MenuTriggerForDirective, MenuItemDirective, MenuDividerComponent],
exports: [MenuComponent, MenuTriggerForDirective, MenuItemDirective, MenuDividerComponent],
})
export class MenuModule {}

View File

@ -3,23 +3,15 @@ import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
import { ButtonModule } from "../button/button.module";
import { MenuDividerComponent } from "./menu-divider.component";
import { MenuItemDirective } from "./menu-item.directive";
import { MenuTriggerForDirective } from "./menu-trigger-for.directive";
import { MenuComponent } from "./menu.component";
import { MenuModule } from "./menu.module";
export default {
title: "Component Library/Menu",
component: MenuTriggerForDirective,
decorators: [
moduleMetadata({
declarations: [
MenuTriggerForDirective,
MenuComponent,
MenuItemDirective,
MenuDividerComponent,
],
imports: [OverlayModule, ButtonModule],
imports: [MenuModule, OverlayModule, ButtonModule],
}),
],
parameters: {
@ -51,7 +43,7 @@ export const OpenMenu: Story = {
Disabled button
</button>
</bit-menu>
<div class="tw-h-40">
<div class="cdk-overlay-pane bit-menu-panel">
<ng-container *ngTemplateOutlet="myMenu.templateRef"></ng-container>
@ -67,7 +59,7 @@ export const ClosedMenu: Story = {
<div class="tw-h-40">
<button bitButton buttonType="secondary" [bitMenuTriggerFor]="myMenu">Open menu</button>
</div>
<bit-menu #myMenu>
<a href="#" bitMenuItem>Anchor link</a>
<a href="#" bitMenuItem>Another link</a>

View File

@ -2,6 +2,7 @@
// @ts-strict-ignore
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { hasModifierKey } from "@angular/cdk/keycodes";
import { NgIf } from "@angular/common";
import {
Component,
Input,
@ -13,12 +14,20 @@ import {
Optional,
Self,
} from "@angular/core";
import { ControlValueAccessor, NgControl, Validators } from "@angular/forms";
import { NgSelectComponent } from "@ng-select/ng-select";
import {
ControlValueAccessor,
NgControl,
Validators,
ReactiveFormsModule,
FormsModule,
} from "@angular/forms";
import { NgSelectComponent, NgSelectModule } from "@ng-select/ng-select";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { BadgeModule } from "../badge";
import { BitFormFieldControl } from "../form-field/form-field-control";
import { I18nPipe } from "../shared/i18n.pipe";
import { SelectItemView } from "./models/select-item-view";
@ -29,6 +38,8 @@ let nextId = 0;
selector: "bit-multi-select",
templateUrl: "./multi-select.component.html",
providers: [{ provide: BitFormFieldControl, useExisting: MultiSelectComponent }],
standalone: true,
imports: [NgSelectModule, ReactiveFormsModule, FormsModule, BadgeModule, NgIf, I18nPipe],
})
/**
* This component has been implemented to only support Multi-select list events

View File

@ -1,16 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { NgSelectModule } from "@ng-select/ng-select";
import { BadgeModule } from "../badge";
import { SharedModule } from "../shared";
import { MultiSelectComponent } from "./multi-select.component";
@NgModule({
imports: [CommonModule, FormsModule, NgSelectModule, BadgeModule, SharedModule],
imports: [MultiSelectComponent],
exports: [MultiSelectComponent],
declarations: [MultiSelectComponent],
})
export class MultiSelectModule {}

View File

@ -1,3 +1,4 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { SideNavService } from "./side-nav.service";
@ -5,6 +6,8 @@ import { SideNavService } from "./side-nav.service";
@Component({
selector: "bit-nav-divider",
templateUrl: "./nav-divider.component.html",
standalone: true,
imports: [CommonModule],
})
export class NavDividerComponent {
constructor(protected sideNavService: SideNavService) {}

View File

@ -1,3 +1,4 @@
import { CommonModule } from "@angular/common";
import {
AfterContentInit,
booleanAttribute,
@ -11,13 +12,22 @@ import {
SkipSelf,
} from "@angular/core";
import { IconButtonModule } from "../icon-button";
import { I18nPipe } from "../shared/i18n.pipe";
import { NavBaseComponent } from "./nav-base.component";
import { NavGroupAbstraction, NavItemComponent } from "./nav-item.component";
import { SideNavService } from "./side-nav.service";
@Component({
selector: "bit-nav-group",
templateUrl: "./nav-group.component.html",
providers: [{ provide: NavBaseComponent, useExisting: NavGroupComponent }],
providers: [
{ provide: NavBaseComponent, useExisting: NavGroupComponent },
{ provide: NavGroupAbstraction, useExisting: NavGroupComponent },
],
standalone: true,
imports: [CommonModule, NavItemComponent, IconButtonModule, I18nPipe],
})
export class NavGroupComponent extends NavBaseComponent implements AfterContentInit {
@ContentChildren(NavBaseComponent, {

View File

@ -1,14 +1,24 @@
import { CommonModule } from "@angular/common";
import { Component, HostListener, Input, Optional } from "@angular/core";
import { RouterModule } from "@angular/router";
import { BehaviorSubject, map } from "rxjs";
import { IconButtonModule } from "../icon-button";
import { NavBaseComponent } from "./nav-base.component";
import { NavGroupComponent } from "./nav-group.component";
import { SideNavService } from "./side-nav.service";
// Resolves a circular dependency between `NavItemComponent` and `NavItemGroup` when using standalone components.
export abstract class NavGroupAbstraction {
abstract setOpen(open: boolean): void;
}
@Component({
selector: "bit-nav-item",
templateUrl: "./nav-item.component.html",
providers: [{ provide: NavBaseComponent, useExisting: NavItemComponent }],
standalone: true,
imports: [CommonModule, IconButtonModule, RouterModule],
})
export class NavItemComponent extends NavBaseComponent {
/** Forces active styles to be shown, regardless of the `routerLinkActiveOptions` */
@ -52,7 +62,7 @@ export class NavItemComponent extends NavBaseComponent {
constructor(
protected sideNavService: SideNavService,
@Optional() private parentNavGroup: NavGroupComponent,
@Optional() private parentNavGroup: NavGroupAbstraction,
) {
super();
}

View File

@ -1,14 +1,20 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf } from "@angular/common";
import { Component, Input } from "@angular/core";
import { RouterLinkActive, RouterLink } from "@angular/router";
import { Icon } from "../icon";
import { BitIconComponent } from "../icon/icon.component";
import { NavItemComponent } from "./nav-item.component";
import { SideNavService } from "./side-nav.service";
@Component({
selector: "bit-nav-logo",
templateUrl: "./nav-logo.component.html",
standalone: true,
imports: [NgIf, RouterLinkActive, RouterLink, BitIconComponent, NavItemComponent],
})
export class NavLogoComponent {
/** Icon that is displayed when the side nav is closed */

View File

@ -1,13 +1,4 @@
import { A11yModule } from "@angular/cdk/a11y";
import { OverlayModule } from "@angular/cdk/overlay";
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { IconModule } from "../icon";
import { IconButtonModule } from "../icon-button/icon-button.module";
import { LinkModule } from "../link";
import { SharedModule } from "../shared/shared.module";
import { NavDividerComponent } from "./nav-divider.component";
import { NavGroupComponent } from "./nav-group.component";
@ -17,16 +8,6 @@ import { SideNavComponent } from "./side-nav.component";
@NgModule({
imports: [
CommonModule,
SharedModule,
IconButtonModule,
OverlayModule,
RouterModule,
IconModule,
A11yModule,
LinkModule,
],
declarations: [
NavDividerComponent,
NavGroupComponent,
NavItemComponent,

View File

@ -1,7 +1,13 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CdkTrapFocus } from "@angular/cdk/a11y";
import { CommonModule } from "@angular/common";
import { Component, ElementRef, Input, ViewChild } from "@angular/core";
import { BitIconButtonComponent } from "../icon-button/icon-button.component";
import { I18nPipe } from "../shared/i18n.pipe";
import { NavDividerComponent } from "./nav-divider.component";
import { SideNavService } from "./side-nav.service";
export type SideNavVariant = "primary" | "secondary";
@ -9,6 +15,8 @@ export type SideNavVariant = "primary" | "secondary";
@Component({
selector: "bit-side-nav",
templateUrl: "side-nav.component.html",
standalone: true,
imports: [CommonModule, CdkTrapFocus, NavDividerComponent, BitIconButtonComponent, I18nPipe],
})
export class SideNavComponent {
@Input() variant: SideNavVariant = "primary";

View File

@ -1,6 +1,7 @@
import { Component, Input } from "@angular/core";
import { Icons } from "..";
import { BitIconComponent } from "../icon/icon.component";
/**
* Component for displaying a message when there are no items to display. Expects title, description and button slots.
@ -8,6 +9,8 @@ import { Icons } from "..";
@Component({
selector: "bit-no-items",
templateUrl: "./no-items.component.html",
standalone: true,
imports: [BitIconComponent],
})
export class NoItemsComponent {
@Input() icon = Icons.Search;

View File

@ -1,13 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IconModule } from "../icon";
import { NoItemsComponent } from "./no-items.component";
@NgModule({
imports: [CommonModule, IconModule],
imports: [NoItemsComponent],
exports: [NoItemsComponent],
declarations: [NoItemsComponent],
})
export class NoItemsModule {}

View File

@ -1,3 +1,4 @@
import { CommonModule } from "@angular/common";
import { Component, Input } from "@angular/core";
type SizeTypes = "small" | "default" | "large";
@ -19,6 +20,8 @@ const BackgroundClasses: Record<BackgroundTypes, string[]> = {
@Component({
selector: "bit-progress",
templateUrl: "./progress.component.html",
standalone: true,
imports: [CommonModule],
})
export class ProgressComponent {
@Input() barWidth = 0;

View File

@ -1,11 +1,9 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { ProgressComponent } from "./progress.component";
@NgModule({
imports: [CommonModule],
imports: [ProgressComponent],
exports: [ProgressComponent],
declarations: [ProgressComponent],
})
export class ProgressModule {}

View File

@ -1,12 +1,17 @@
import { Component, HostBinding, Input } from "@angular/core";
import { FormControlModule } from "../form-control/form-control.module";
import { RadioGroupComponent } from "./radio-group.component";
import { RadioInputComponent } from "./radio-input.component";
let nextId = 0;
@Component({
selector: "bit-radio-button",
templateUrl: "radio-button.component.html",
standalone: true,
imports: [FormControlModule, RadioInputComponent],
})
export class RadioButtonComponent {
@HostBinding("attr.id") @Input() id = `bit-radio-button-${nextId++}`;

View File

@ -1,16 +1,13 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormControlModule } from "../form-control";
import { SharedModule } from "../shared";
import { RadioButtonComponent } from "./radio-button.component";
import { RadioGroupComponent } from "./radio-group.component";
import { RadioInputComponent } from "./radio-input.component";
@NgModule({
imports: [CommonModule, SharedModule, FormControlModule],
declarations: [RadioInputComponent, RadioButtonComponent, RadioGroupComponent],
imports: [FormControlModule, RadioInputComponent, RadioButtonComponent, RadioGroupComponent],
exports: [FormControlModule, RadioInputComponent, RadioButtonComponent, RadioGroupComponent],
})
export class RadioButtonModule {}

View File

@ -1,15 +1,19 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf, NgTemplateOutlet } from "@angular/common";
import { Component, ContentChild, HostBinding, Input, Optional, Self } from "@angular/core";
import { ControlValueAccessor, NgControl, Validators } from "@angular/forms";
import { BitLabel } from "../form-control/label.component";
import { I18nPipe } from "../shared/i18n.pipe";
let nextId = 0;
@Component({
selector: "bit-radio-group",
templateUrl: "radio-group.component.html",
standalone: true,
imports: [NgIf, NgTemplateOutlet, I18nPipe],
})
export class RadioGroupComponent implements ControlValueAccessor {
selected: unknown;

View File

@ -11,6 +11,7 @@ let nextId = 0;
selector: "input[type=radio][bitRadio]",
template: "",
providers: [{ provide: BitFormControlAbstraction, useExisting: RadioInputComponent }],
standalone: true,
})
export class RadioInputComponent implements BitFormControlAbstraction {
@HostBinding("attr.id") @Input() id = `bit-radio-input-${nextId++}`;

View File

@ -1,11 +1,18 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, ElementRef, Input, ViewChild } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
ReactiveFormsModule,
FormsModule,
} from "@angular/forms";
import { isBrowserSafariApi } from "@bitwarden/platform";
import { InputModule } from "../input/input.module";
import { FocusableElement } from "../shared/focusable-element";
import { I18nPipe } from "../shared/i18n.pipe";
let nextId = 0;
@ -23,6 +30,8 @@ let nextId = 0;
useExisting: SearchComponent,
},
],
standalone: true,
imports: [InputModule, ReactiveFormsModule, FormsModule, I18nPipe],
})
export class SearchComponent implements ControlValueAccessor, FocusableElement {
private notifyOnChange: (v: string) => void;

View File

@ -1,14 +1,9 @@
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { InputModule } from "../input/input.module";
import { SharedModule } from "../shared";
import { SearchComponent } from "./search.component";
@NgModule({
imports: [SharedModule, InputModule, FormsModule],
declarations: [SearchComponent],
imports: [SearchComponent],
exports: [SearchComponent],
})
export class SearchModule {}

View File

@ -7,6 +7,7 @@ import { Option } from "./option";
@Component({
selector: "bit-option",
template: `<ng-template><ng-content></ng-content></ng-template>`,
standalone: true,
})
export class OptionComponent<T = unknown> implements Option<T> {
@Input()

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgIf } from "@angular/common";
import {
Component,
ContentChildren,
@ -12,8 +13,14 @@ import {
Output,
EventEmitter,
} from "@angular/core";
import { ControlValueAccessor, NgControl, Validators } from "@angular/forms";
import { NgSelectComponent } from "@ng-select/ng-select";
import {
ControlValueAccessor,
NgControl,
Validators,
ReactiveFormsModule,
FormsModule,
} from "@angular/forms";
import { NgSelectComponent, NgSelectModule } from "@ng-select/ng-select";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -28,6 +35,8 @@ let nextId = 0;
selector: "bit-select",
templateUrl: "select.component.html",
providers: [{ provide: BitFormFieldControl, useExisting: SelectComponent }],
standalone: true,
imports: [NgSelectModule, ReactiveFormsModule, FormsModule, NgIf],
})
export class SelectComponent<T> implements BitFormFieldControl, ControlValueAccessor {
@ViewChild(NgSelectComponent) select: NgSelectComponent;

View File

@ -1,14 +1,10 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { NgSelectModule } from "@ng-select/ng-select";
import { OptionComponent } from "./option.component";
import { SelectComponent } from "./select.component";
@NgModule({
imports: [CommonModule, NgSelectModule, FormsModule],
declarations: [SelectComponent, OptionComponent],
imports: [SelectComponent, OptionComponent],
exports: [SelectComponent, OptionComponent],
})
export class SelectModule {}

View File

@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
*/
@Pipe({
name: "i18n",
standalone: true,
})
export class I18nPipe implements PipeTransform {
constructor(private i18nService: I18nService) {}

View File

@ -4,8 +4,7 @@ import { NgModule } from "@angular/core";
import { I18nPipe } from "./i18n.pipe";
@NgModule({
imports: [CommonModule],
declarations: [I18nPipe],
imports: [CommonModule, I18nPipe],
exports: [CommonModule, I18nPipe],
})
export class SharedModule {}

View File

@ -2,6 +2,7 @@ import { Directive, HostBinding } from "@angular/core";
@Directive({
selector: "th[bitCell], td[bitCell]",
standalone: true,
})
export class CellDirective {
@HostBinding("class") get classList() {

View File

@ -2,6 +2,7 @@ import { Directive, HostBinding, Input } from "@angular/core";
@Directive({
selector: "tr[bitRow]",
standalone: true,
})
export class RowDirective {
@Input() alignContent: "top" | "middle" | "bottom" | "baseline" = "middle";

View File

@ -1,6 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass } from "@angular/common";
import { Component, HostBinding, Input, OnInit } from "@angular/core";
import type { SortDirection, SortFn } from "./table-data-source";
@ -14,6 +15,8 @@ import { TableComponent } from "./table.component";
<i class="bwi tw-ml-2" [ngClass]="icon"></i>
</button>
`,
standalone: true,
imports: [NgClass],
})
export class SortableComponent implements OnInit {
/**

View File

@ -1,5 +1,12 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import {
CdkVirtualScrollViewport,
CdkVirtualScrollableWindow,
CdkFixedSizeVirtualScroll,
CdkVirtualForOf,
} from "@angular/cdk/scrolling";
import { CommonModule } from "@angular/common";
import {
AfterContentChecked,
Component,
@ -14,6 +21,7 @@ import {
TrackByFunction,
} from "@angular/core";
import { RowDirective } from "./row.directive";
import { TableComponent } from "./table.component";
/**
@ -42,6 +50,15 @@ export class BitRowDef {
selector: "bit-table-scroll",
templateUrl: "./table-scroll.component.html",
providers: [{ provide: TableComponent, useExisting: TableScrollComponent }],
standalone: true,
imports: [
CommonModule,
CdkVirtualScrollViewport,
CdkVirtualScrollableWindow,
CdkFixedSizeVirtualScroll,
CdkVirtualForOf,
RowDirective,
],
})
export class TableScrollComponent
extends TableComponent

View File

@ -1,6 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { isDataSource } from "@angular/cdk/collections";
import { CommonModule } from "@angular/common";
import {
AfterContentChecked,
Component,
@ -16,6 +17,7 @@ import { TableDataSource } from "./table-data-source";
@Directive({
selector: "ng-template[body]",
standalone: true,
})
export class TableBodyDirective {
// eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
@ -25,6 +27,8 @@ export class TableBodyDirective {
@Component({
selector: "bit-table",
templateUrl: "./table.component.html",
standalone: true,
imports: [CommonModule],
})
export class TableComponent implements OnDestroy, AfterContentChecked {
@Input() dataSource: TableDataSource<any>;

View File

@ -9,8 +9,10 @@ import { BitRowDef, TableScrollComponent } from "./table-scroll.component";
import { TableBodyDirective, TableComponent } from "./table.component";
@NgModule({
imports: [CommonModule, ScrollingModule, BitRowDef],
declarations: [
imports: [
CommonModule,
ScrollingModule,
BitRowDef,
CellDirective,
RowDirective,
SortableComponent,

View File

@ -10,5 +10,6 @@ import { Component } from "@angular/core";
"tw-h-16 tw-pl-4 tw-bg-background-alt tw-flex tw-items-end tw-border-0 tw-border-b tw-border-solid tw-border-secondary-300",
},
template: `<ng-content></ng-content>`,
standalone: true,
})
export class TabHeaderComponent {}

View File

@ -8,5 +8,6 @@ import { Directive } from "@angular/core";
host: {
class: "tw-inline-flex tw-flex-wrap tw-leading-5",
},
standalone: true,
})
export class TabListContainerDirective {}

View File

@ -7,7 +7,10 @@ import { Directive, ElementRef, HostBinding, Input } from "@angular/core";
* Directive used for styling tab header items for both nav links (anchor tags)
* and content tabs (button tags)
*/
@Directive({ selector: "[bitTabListItem]" })
@Directive({
selector: "[bitTabListItem]",
standalone: true,
})
export class TabListItemDirective implements FocusableOption {
@Input() active: boolean;
@Input() disabled: boolean;

View File

@ -1,11 +1,13 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { TemplatePortal } from "@angular/cdk/portal";
import { TemplatePortal, CdkPortalOutlet } from "@angular/cdk/portal";
import { Component, HostBinding, Input } from "@angular/core";
@Component({
selector: "bit-tab-body",
templateUrl: "tab-body.component.html",
standalone: true,
imports: [CdkPortalOutlet],
})
export class TabBodyComponent {
private _firstRender: boolean;

View File

@ -2,6 +2,7 @@
// @ts-strict-ignore
import { FocusKeyManager } from "@angular/cdk/a11y";
import { coerceNumberProperty } from "@angular/cdk/coercion";
import { CommonModule } from "@angular/common";
import {
AfterContentChecked,
AfterContentInit,
@ -17,8 +18,11 @@ import {
} from "@angular/core";
import { Subject, takeUntil } from "rxjs";
import { TabHeaderComponent } from "../shared/tab-header.component";
import { TabListContainerDirective } from "../shared/tab-list-container.directive";
import { TabListItemDirective } from "../shared/tab-list-item.directive";
import { TabBodyComponent } from "./tab-body.component";
import { TabComponent } from "./tab.component";
/** Used to generate unique ID's for each tab component */
@ -27,6 +31,14 @@ let nextId = 0;
@Component({
selector: "bit-tab-group",
templateUrl: "./tab-group.component.html",
standalone: true,
imports: [
CommonModule,
TabHeaderComponent,
TabListContainerDirective,
TabListItemDirective,
TabBodyComponent,
],
})
export class TabGroupComponent
implements AfterContentChecked, AfterContentInit, AfterViewInit, OnDestroy

View File

@ -16,6 +16,7 @@ import { Directive, TemplateRef } from "@angular/core";
*/
@Directive({
selector: "[bitTabLabel]",
standalone: true,
})
export class TabLabelDirective {
constructor(public templateRef: TemplateRef<unknown>) {}

View File

@ -19,6 +19,7 @@ import { TabLabelDirective } from "./tab-label.directive";
host: {
role: "tabpanel",
},
standalone: true,
})
export class TabComponent implements OnInit {
@Input() disabled = false;

View File

@ -2,7 +2,7 @@
// @ts-strict-ignore
import { FocusableOption } from "@angular/cdk/a11y";
import { AfterViewInit, Component, HostListener, Input, OnDestroy, ViewChild } from "@angular/core";
import { IsActiveMatchOptions, RouterLinkActive } from "@angular/router";
import { IsActiveMatchOptions, RouterLinkActive, RouterModule } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
import { TabListItemDirective } from "../shared/tab-list-item.directive";
@ -12,6 +12,8 @@ import { TabNavBarComponent } from "./tab-nav-bar.component";
@Component({
selector: "bit-tab-link",
templateUrl: "tab-link.component.html",
standalone: true,
imports: [TabListItemDirective, RouterModule],
})
export class TabLinkComponent implements FocusableOption, AfterViewInit, OnDestroy {
private destroy$ = new Subject<void>();

View File

@ -10,6 +10,9 @@ import {
QueryList,
} from "@angular/core";
import { TabHeaderComponent } from "../shared/tab-header.component";
import { TabListContainerDirective } from "../shared/tab-list-container.directive";
import { TabLinkComponent } from "./tab-link.component";
@Component({
@ -18,6 +21,8 @@ import { TabLinkComponent } from "./tab-link.component";
host: {
class: "tw-block",
},
standalone: true,
imports: [TabHeaderComponent, TabListContainerDirective],
})
export class TabNavBarComponent implements AfterContentInit {
@ContentChildren(forwardRef(() => TabLinkComponent)) tabLabels: QueryList<TabLinkComponent>;

View File

@ -1,11 +1,6 @@
import { PortalModule } from "@angular/cdk/portal";
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { TabHeaderComponent } from "./shared/tab-header.component";
import { TabListContainerDirective } from "./shared/tab-list-container.directive";
import { TabListItemDirective } from "./shared/tab-list-item.directive";
import { TabBodyComponent } from "./tab-group/tab-body.component";
import { TabGroupComponent } from "./tab-group/tab-group.component";
import { TabLabelDirective } from "./tab-group/tab-label.directive";
@ -14,7 +9,15 @@ import { TabLinkComponent } from "./tab-nav-bar/tab-link.component";
import { TabNavBarComponent } from "./tab-nav-bar/tab-nav-bar.component";
@NgModule({
imports: [CommonModule, RouterModule, PortalModule],
imports: [
CommonModule,
TabGroupComponent,
TabComponent,
TabLabelDirective,
TabNavBarComponent,
TabLinkComponent,
TabBodyComponent,
],
exports: [
TabGroupComponent,
TabComponent,
@ -22,16 +25,5 @@ import { TabNavBarComponent } from "./tab-nav-bar/tab-nav-bar.component";
TabNavBarComponent,
TabLinkComponent,
],
declarations: [
TabGroupComponent,
TabComponent,
TabLabelDirective,
TabListContainerDirective,
TabListItemDirective,
TabHeaderComponent,
TabNavBarComponent,
TabLinkComponent,
TabBodyComponent,
],
})
export class TabsModule {}

View File

@ -1,13 +1,10 @@
import { CommonModule } from "@angular/common";
import { ModuleWithProviders, NgModule } from "@angular/core";
import { DefaultNoComponentGlobalConfig, GlobalConfig, TOAST_CONFIG } from "ngx-toastr";
import { ToastComponent } from "./toast.component";
import { BitwardenToastrComponent } from "./toastr.component";
@NgModule({
imports: [CommonModule, ToastComponent],
declarations: [BitwardenToastrComponent],
imports: [BitwardenToastrComponent],
exports: [BitwardenToastrComponent],
})
export class ToastModule {

View File

@ -2,6 +2,8 @@ import { animate, state, style, transition, trigger } from "@angular/animations"
import { Component } from "@angular/core";
import { Toast as BaseToastrComponent } from "ngx-toastr";
import { ToastComponent } from "./toast.component";
@Component({
template: `
<bit-toast
@ -22,5 +24,7 @@ import { Toast as BaseToastrComponent } from "ngx-toastr";
]),
],
preserveWhitespaces: false,
standalone: true,
imports: [ToastComponent],
})
export class BitwardenToastrComponent extends BaseToastrComponent {}

View File

@ -13,6 +13,7 @@ let nextId = 0;
selector: "bit-toggle-group",
templateUrl: "./toggle-group.component.html",
preserveWhitespaces: false,
standalone: true,
})
export class ToggleGroupComponent<TValue = unknown> {
private id = nextId++;

View File

@ -1,14 +1,10 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { BadgeModule } from "../badge";
import { ToggleGroupComponent } from "./toggle-group.component";
import { ToggleComponent } from "./toggle.component";
@NgModule({
imports: [CommonModule, BadgeModule],
imports: [ToggleGroupComponent, ToggleComponent],
exports: [ToggleGroupComponent, ToggleComponent],
declarations: [ToggleGroupComponent, ToggleComponent],
})
export class ToggleGroupModule {}

View File

@ -1,5 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { NgClass } from "@angular/common";
import {
AfterContentChecked,
AfterViewInit,
@ -19,6 +20,8 @@ let nextId = 0;
selector: "bit-toggle",
templateUrl: "./toggle.component.html",
preserveWhitespaces: false,
standalone: true,
imports: [NgClass],
})
export class ToggleComponent<TValue> implements AfterContentChecked, AfterViewInit {
id = nextId++;

View File

@ -31,6 +31,7 @@ const margins: Record<TypographyType, string[]> = {
@Directive({
selector: "[bitTypography]",
standalone: true,
})
export class TypographyDirective {
@Input("bitTypography") bitTypography: TypographyType;

Some files were not shown because too many files have changed in this diff Show More