1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-13 06:43:35 +00:00

UIF - Prefer signal & change detection (#16940)

This commit is contained in:
Oscar Hinton
2025-10-21 18:52:40 +02:00
committed by GitHub
parent d3fc20f8b9
commit 65da23feaa
135 changed files with 503 additions and 51 deletions

View File

@@ -6,7 +6,7 @@ import { setA11yTitleAndAriaLabel } from "./set-a11y-title-and-aria-label";
selector: "[appA11yTitle]",
})
export class A11yTitleDirective {
title = input.required<string>({ alias: "appA11yTitle" });
readonly title = input.required<string>({ alias: "appA11yTitle" });
constructor(private el: ElementRef) {
const originalTitle = this.el.nativeElement.getAttribute("title");

View File

@@ -46,6 +46,8 @@ export interface AnonLayoutWrapperData {
hideBackgroundIllustration?: boolean;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
templateUrl: "anon-layout-wrapper.component.html",
imports: [AnonLayoutComponent, RouterModule],

View File

@@ -103,6 +103,8 @@ type Story = StoryObj<AnonLayoutWrapperComponent>;
// Default Example
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-default-primary-outlet-example-component",
template: "<p>Primary Outlet Example: <br> your primary component goes here</p>",
@@ -110,6 +112,8 @@ type Story = StoryObj<AnonLayoutWrapperComponent>;
})
export class DefaultPrimaryOutletExampleComponent {}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-default-secondary-outlet-example-component",
template: "<p>Secondary Outlet Example: <br> your secondary component goes here</p>",
@@ -117,6 +121,8 @@ export class DefaultPrimaryOutletExampleComponent {}
})
export class DefaultSecondaryOutletExampleComponent {}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-default-env-selector-outlet-example-component",
template: "<p>Env Selector Outlet Example: <br> your env selector component goes here</p>",
@@ -192,6 +198,8 @@ const changedData: AnonLayoutWrapperData = {
pageIcon: RegistrationCheckEmailIcon,
};
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-dynamic-content-example-component",
template: `

View File

@@ -27,6 +27,8 @@ import { TypographyModule } from "../typography";
export type AnonLayoutMaxWidth = "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "auth-anon-layout",
templateUrl: "./anon-layout.component.html",

View File

@@ -1,5 +1,7 @@
import { Component } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-root",
template: "",

View File

@@ -39,6 +39,8 @@ const template = `
<button class="tw-me-2" type="button" buttonType="muted" bitIconButton="bwi-star" label="Delete" bitFormButton [bitAction]="delete">Delete</button>
</form>`;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-promise-example",
template,
@@ -84,6 +86,8 @@ class PromiseExampleComponent {
};
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-observable-example",
template,

View File

@@ -20,6 +20,8 @@ const template = /*html*/ `
</button>
<button type="button" label="Delete" bitIconButton="bwi-trash" buttonType="danger" [bitAction]="action"></button>`;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template,
selector: "app-promise-example",
@@ -37,6 +39,8 @@ class PromiseExampleComponent {
};
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template,
selector: "app-action-resolves-quickly",
@@ -55,6 +59,8 @@ class ActionResolvesQuicklyComponent {
};
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template,
selector: "app-observable-example",
@@ -66,6 +72,8 @@ class ObservableExampleComponent {
};
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template,
selector: "app-rejected-promise-example",

View File

@@ -19,6 +19,8 @@ const SizeClasses: Record<SizeTypes, string[]> = {
* A variance in color across the avatar component is important as it is used in Account Switching as a
* visual indicator to recognize which of a personal or work account a user is logged into.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-avatar",
template: `

View File

@@ -8,6 +8,8 @@ function transformMaxItems(value: number | undefined) {
return value == undefined ? undefined : Math.max(1, value);
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-badge-list",
templateUrl: "badge-list.component.html",

View File

@@ -55,6 +55,8 @@ const hoverStyles: Record<BadgeVariant, string[]> = {
* > `NOTE:` The `disabled` state only applies to buttons.
*
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "span[bitBadge], a[bitBadge], button[bitBadge]",
providers: [{ provide: FocusableElement, useExisting: BadgeComponent }],

View File

@@ -23,6 +23,8 @@ const defaultIcon: Record<BannerType, string> = {
* - Avoid stacking multiple banners.
* - Banners can contain a button or anchor that uses the `bitLink` directive with `linkType="secondary"`.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-banner",
templateUrl: "./banner.component.html",
@@ -40,6 +42,8 @@ export class BannerComponent implements OnInit {
readonly useAlertRole = input(true);
readonly showClose = input(true);
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() onClose = new EventEmitter<void>();
ngOnInit(): void {

View File

@@ -1,6 +1,8 @@
import { Component, EventEmitter, Output, TemplateRef, input, viewChild } from "@angular/core";
import { QueryParamsHandling } from "@angular/router";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-breadcrumb",
templateUrl: "./breadcrumb.component.html",
@@ -14,6 +16,8 @@ export class BreadcrumbComponent {
readonly queryParamsHandling = input<QueryParamsHandling>();
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output()
click = new EventEmitter();

View File

@@ -15,6 +15,8 @@ import { BreadcrumbComponent } from "./breadcrumb.component";
* Bitwarden uses this component to indicate the user's current location in a set of data organized in
* containers (Collections, Folders, or Projects).
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-breadcrumbs",
templateUrl: "./breadcrumbs.component.html",
@@ -25,6 +27,8 @@ export class BreadcrumbsComponent {
private breadcrumbs: BreadcrumbComponent[] = [];
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ContentChildren(BreadcrumbComponent)
protected set breadcrumbList(value: QueryList<BreadcrumbComponent>) {
this.breadcrumbs = value.toArray();

View File

@@ -18,6 +18,8 @@ interface Breadcrumb {
route: string;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: "",
})

View File

@@ -56,6 +56,8 @@ describe("Button", () => {
});
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-app",
template: `

View File

@@ -57,6 +57,8 @@ const buttonStyles: Record<ButtonType, string[]> = {
unstyled: [],
};
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "button[bitButton], a[bitButton]",
templateUrl: "button.component.html",
@@ -97,7 +99,7 @@ export class ButtonComponent implements ButtonLikeAbstraction {
.concat(buttonSizeStyles[this.size() || "default"]);
}
protected disabledAttr = computed(() => {
protected readonly disabledAttr = computed(() => {
const disabled = this.disabled() != null && this.disabled() !== false;
return disabled || this.loading();
});
@@ -110,7 +112,7 @@ export class ButtonComponent implements ButtonLikeAbstraction {
* We can't use `disabledAttr` for this, because it returns `true` when `loading` is `true`.
* We only want to show disabled styles during loading if `showLoadingStyles` is `true`.
*/
protected showDisabledStyles = computed(() => {
protected readonly showDisabledStyles = computed(() => {
return this.showLoadingStyle() || (this.disabledAttr() && this.loading() === false);
});
@@ -134,11 +136,11 @@ export class ButtonComponent implements ButtonLikeAbstraction {
* This pattern of converting a signal to an observable and back to a signal is not
* recommended. TODO -- find better way to use debounce with signals (CL-596)
*/
protected showLoadingStyle = toSignal(
protected readonly showLoadingStyle = toSignal(
toObservable(this.loading).pipe(debounce((isLoading) => interval(isLoading ? 75 : 0))),
);
disabled = model<boolean>(false);
readonly disabled = model<boolean>(false);
private el = inject(ElementRef<HTMLButtonElement>);
constructor() {

View File

@@ -28,6 +28,8 @@ let nextId = 0;
* sparingly, as they command a large amount of visual attention. Avoid using more than 1 callout in
* the same location.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-callout",
templateUrl: "callout.component.html",

View File

@@ -3,6 +3,8 @@ import { NgControl, Validators } from "@angular/forms";
import { BitFormControlAbstraction } from "../form-control";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "input[type=checkbox][bitCheckbox]",
template: "",

View File

@@ -28,6 +28,8 @@ const template = /*html*/ `
</form>
`;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "app-example",
template,
@@ -38,10 +40,14 @@ class ExampleComponent {
checkbox: [false, Validators.requiredTrue],
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() set checked(value: boolean) {
this.formObj.patchValue({ checkbox: value });
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() set disabled(disable: boolean) {
if (disable) {
this.formObj.disable();

View File

@@ -35,6 +35,8 @@ export type ChipSelectOption<T> = Option<T> & {
/**
* `<bit-chip-select>` is a select element that is commonly used to filter items in lists or tables.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-chip-select",
templateUrl: "chip-select.component.html",
@@ -49,6 +51,8 @@ export type ChipSelectOption<T> = Option<T> & {
})
export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, AfterViewInit {
readonly menu = viewChild(MenuComponent);
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChildren(MenuItemDirective) menuItems?: QueryList<MenuItemDirective>;
readonly chipSelectButton = viewChild<ElementRef<HTMLButtonElement>>("chipSelectButton");
@@ -63,6 +67,8 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
/** The select options to render */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ required: true })
get options(): ChipSelectOption<T>[] {
return this._options;
@@ -75,6 +81,8 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
/** Disables the entire chip */
// TODO: Skipped for signal migration because:
// Your application code writes to the input. This prevents migration.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute }) disabled = false;
/** Chip will stretch to full width of its container */
@@ -83,7 +91,7 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
/**
* We have `:focus-within` and `:focus-visible` but no `:focus-visible-within`
*/
protected focusVisibleWithin = signal(false);
protected readonly focusVisibleWithin = signal(false);
@HostListener("focusin", ["$event.target"])
onFocusIn(target: HTMLElement) {
this.focusVisibleWithin.set(target.matches("[data-fvw-target]:focus-visible"));

View File

@@ -9,6 +9,8 @@ type CharacterType = "letter" | "emoji" | "special" | "number";
* the logic for displaying letters as `text-main`, numbers as `primary`, and special symbols as
* `danger`.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-color-password",
template: `@for (character of passwordCharArray(); track $index; let i = $index) {
@@ -21,11 +23,11 @@ type CharacterType = "letter" | "emoji" | "special" | "number";
}`,
})
export class ColorPasswordComponent {
password = input<string>("");
showCount = input<boolean>(false);
readonly password = input<string>("");
readonly showCount = input<boolean>(false);
// Convert to an array to handle cases that strings have special characters, i.e.: emoji.
passwordCharArray = computed(() => {
readonly passwordCharArray = computed(() => {
return Array.from(this.password() ?? "");
});

View File

@@ -3,6 +3,8 @@ import { Component } from "@angular/core";
/**
* bit-container is a minimally styled component that limits the max width of its content to the tailwind theme variable '4xl'. '4xl' is equal to the value of 56rem
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-container",
templateUrl: "container.component.html",

View File

@@ -9,6 +9,8 @@ import { ToastService, CopyClickListener, COPY_CLICK_LISTENER } from "../";
import { CopyClickDirective } from "./copy-click.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<button type="button" appCopyClick="no toast shown" #noToast></button>
@@ -25,9 +27,17 @@ import { CopyClickDirective } from "./copy-click.directive";
imports: [CopyClickDirective],
})
class TestCopyClickComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChild("noToast") noToastButton!: ElementRef<HTMLButtonElement>;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChild("infoToast") infoToastButton!: ElementRef<HTMLButtonElement>;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChild("successToast") successToastButton!: ElementRef<HTMLButtonElement>;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChild("toastWithLabel") toastWithLabelButton!: ElementRef<HTMLButtonElement>;
}

View File

@@ -26,11 +26,11 @@ export const COPY_CLICK_LISTENER = new InjectionToken<CopyClickListener>("CopyCl
selector: "[appCopyClick]",
})
export class CopyClickDirective {
private _showToast = computed(() => {
private readonly _showToast = computed(() => {
return this.showToast() !== undefined;
});
private toastVariant = computed(() => {
private readonly toastVariant = computed(() => {
const showToast = this.showToast();
// When the `showToast` is set without a value, an empty string will be passed
if (showToast === "" || showToast === undefined) {
@@ -68,7 +68,7 @@ export class CopyClickDirective {
* <app-component [appCopyClick]="value to copy" showToast="info"/></app-component>
* ```
*/
showToast = input<ToastVariant | "">();
readonly showToast = input<ToastVariant | "">();
@HostListener("click") onClick() {
const valueToCopy = this.valueToCopy();

View File

@@ -21,6 +21,8 @@ interface Animal {
animal: string;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-layout>
@@ -62,6 +64,8 @@ class StoryDialogComponent {
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-dialog title="Dialog Title" dialogSize="large">
@@ -91,6 +95,8 @@ class StoryDialogContentComponent {
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-dialog

View File

@@ -26,6 +26,8 @@ import { DialogRef } from "../dialog.service";
import { DialogCloseDirective } from "../directives/dialog-close.directive";
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-dialog",
templateUrl: "./dialog.component.html",
@@ -47,8 +49,8 @@ import { DialogTitleContainerDirective } from "../directives/dialog-title-contai
})
export class DialogComponent {
private readonly destroyRef = inject(DestroyRef);
private scrollableBody = viewChild.required(CdkScrollable);
private scrollBottom = viewChild.required<ElementRef<HTMLDivElement>>("scrollBottom");
private readonly scrollableBody = viewChild.required(CdkScrollable);
private readonly scrollBottom = viewChild.required<ElementRef<HTMLDivElement>>("scrollBottom");
protected dialogRef = inject(DialogRef, { optional: true });
protected bodyHasScrolledFrom = hasScrolledFrom(this.scrollableBody);

View File

@@ -26,6 +26,8 @@ const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
danger: "tw-text-danger",
};
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
templateUrl: "./simple-configurable-dialog.component.html",
imports: [

View File

@@ -10,6 +10,8 @@ import { CalloutModule } from "../../../callout";
import { I18nMockService } from "../../../utils/i18n-mock.service";
import { DialogModule } from "../../dialog.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
@for (group of dialogs; track group) {

View File

@@ -9,6 +9,8 @@ import { DialogTitleContainerDirective } from "../directives/dialog-title-contai
})
export class IconDirective {}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-simple-dialog",
templateUrl: "./simple-dialog.component.html",
@@ -16,12 +18,14 @@ export class IconDirective {}
imports: [DialogTitleContainerDirective, TypographyDirective],
})
export class SimpleDialogComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ContentChild(IconDirective) icon!: IconDirective;
/**
* Optional flag to hide the dialog's center icon. Defaults to false.
*/
hideIcon = input(false, { transform: booleanAttribute });
readonly hideIcon = input(false, { transform: booleanAttribute });
get hasIcon() {
return this.icon != null;

View File

@@ -15,6 +15,8 @@ interface Animal {
animal: string;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<button type="button" bitButton (click)="openSimpleDialog()">Open Simple Dialog</button>
@@ -57,6 +59,8 @@ class StoryDialogComponent {
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-simple-dialog>
@@ -87,6 +91,8 @@ class SimpleDialogContent {
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-simple-dialog>
@@ -116,6 +122,8 @@ class NonDismissableWithPrimaryButtonContent {
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: `
<bit-simple-dialog>

View File

@@ -34,12 +34,16 @@ let nextId = 0;
* ```
*
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-disclosure",
template: `<ng-content></ng-content>`,
})
export class DisclosureComponent {
/** Emits the visibility of the disclosure content */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() openChange = new EventEmitter<boolean>();
private _open?: boolean;
@@ -48,6 +52,8 @@ export class DisclosureComponent {
*/
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute }) set open(isOpen: boolean) {
this._open = isOpen;
this.openChange.emit(isOpen);

View File

@@ -24,7 +24,7 @@ export class DrawerHeaderComponent {
/**
* The title to display
*/
title = input.required<string>();
readonly title = input.required<string>();
/** We don't want to set the HTML title attribute with `this.title` */
@HostBinding("attr.title")

View File

@@ -10,7 +10,7 @@ import { Directive, signal } from "@angular/core";
selector: "[bitDrawerHost]",
})
export class DrawerHostDirective {
private _portal = signal<Portal<unknown> | undefined>(undefined);
private readonly _portal = signal<Portal<unknown> | undefined>(undefined);
/** The portal to display */
portal = this._portal.asReadonly();

View File

@@ -25,7 +25,7 @@ import { DrawerService } from "./drawer.service";
})
export class DrawerComponent {
private drawerHost = inject(DrawerService);
private portal = viewChild.required(CdkPortal);
private readonly portal = viewChild.required(CdkPortal);
/**
* Whether or not the drawer is open.
@@ -33,7 +33,7 @@ export class DrawerComponent {
* Note: Does not support implicit boolean transform due to Angular limitation. Must be bound explicitly `[open]="true"` instead of just `open`.
* https://github.com/angular/angular/issues/55166#issuecomment-2032150999
**/
open = model<boolean>(false);
readonly open = model<boolean>(false);
/**
* The ARIA role of the drawer.
@@ -43,7 +43,7 @@ export class DrawerComponent {
* - [navigation](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/navigation_role)
* - For drawers that primary contain links to other content.
*/
role = input<"complementary" | "navigation">("complementary");
readonly role = input<"complementary" | "navigation">("complementary");
constructor() {
effect(

View File

@@ -3,7 +3,7 @@ import { Injectable, signal } from "@angular/core";
@Injectable({ providedIn: "root" })
export class DrawerService {
private _portal = signal<Portal<unknown> | undefined>(undefined);
private readonly _portal = signal<Portal<unknown> | undefined>(undefined);
/** The portal to display */
portal = this._portal.asReadonly();

View File

@@ -8,6 +8,8 @@ import { TypographyDirective } from "../typography/typography.directive";
import { BitFormControlAbstraction } from "./form-control.abstraction";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-form-control",
templateUrl: "form-control.component.html",

View File

@@ -6,6 +6,8 @@ import { FormControlComponent } from "./form-control.component";
// Increments for each instance of this component
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-label",
templateUrl: "label.component.html",

View File

@@ -3,6 +3,8 @@ import { AbstractControl, UntypedFormGroup } from "@angular/forms";
import { I18nPipe } from "@bitwarden/ui-common";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-error-summary",
template: ` @if (errorCount > 0) {

View File

@@ -5,6 +5,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
// Increments for each instance of this component
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-error",
template: `<i class="bwi bwi-error"></i> {{ displayError }}`,

View File

@@ -22,6 +22,8 @@ import { inputBorderClasses } from "../input/input.directive";
import { BitErrorComponent } from "./error.component";
import { BitFormFieldControl } from "./form-field-control";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-form-field",
templateUrl: "./form-field.component.html",
@@ -42,11 +44,13 @@ export class BitFormFieldComponent implements AfterContentChecked {
/** If `true`, remove the bottom border for `readonly` inputs */
// TODO: Skipped for signal migration because:
// Your application code writes to the input. This prevents migration.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute })
disableReadOnlyBorder = false;
protected prefixHasChildren = signal(false);
protected suffixHasChildren = signal(false);
protected readonly prefixHasChildren = signal(false);
protected readonly suffixHasChildren = signal(false);
get inputBorderClasses(): string {
const shouldFocusBorderAppear = this.defaultContentIsFocused();
@@ -87,7 +91,7 @@ export class BitFormFieldComponent implements AfterContentChecked {
* This is necessary because the `tw-group/bit-form-field` wraps the input and any prefix/suffix
* buttons
*/
protected defaultContentIsFocused = signal(false);
protected readonly defaultContentIsFocused = signal(false);
@HostListener("focusin", ["$event.target"])
onFocusIn(target: HTMLElement) {
this.defaultContentIsFocused.set(target.matches("[data-default-content] *:focus-visible"));

View File

@@ -27,6 +27,8 @@ export class BitPasswordInputToggleDirective implements AfterContentInit, OnChan
* Whether the input is toggled to show the password.
*/
readonly toggled = model(false);
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() toggledChange = new EventEmitter<boolean>();
@HostBinding("attr.title") title = this.i18nService.t("toggleVisibility");

View File

@@ -13,6 +13,8 @@ import { BitFormFieldComponent } from "./form-field.component";
import { FormFieldModule } from "./form-field.module";
import { BitPasswordInputToggleDirective } from "./password-input-toggle.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-form-field",
template: `

View File

@@ -81,6 +81,8 @@ const sizes: Record<IconButtonSize, string[]> = {
* Similar to the main button components, spacing between multiple icon buttons should be .5rem.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "button[bitIconButton]:not(button[bitButton])",
templateUrl: "icon-button.component.html",
@@ -143,7 +145,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
return [this.icon(), "!tw-m-0"];
}
protected disabledAttr = computed(() => {
protected readonly disabledAttr = computed(() => {
const disabled = this.disabled() != null && this.disabled() !== false;
return disabled || this.loading();
});
@@ -156,7 +158,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
* We can't use `disabledAttr` for this, because it returns `true` when `loading` is `true`.
* We only want to show disabled styles during loading if `showLoadingStyles` is `true`.
*/
protected showDisabledStyles = computed(() => {
protected readonly showDisabledStyles = computed(() => {
return this.showLoadingStyle() || (this.disabledAttr() && this.loading() === false);
});
@@ -174,7 +176,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
* This pattern of converting a signal to an observable and back to a signal is not
* recommended. TODO -- find better way to use debounce with signals (CL-596)
*/
protected showLoadingStyle = toSignal(
protected readonly showLoadingStyle = toSignal(
toObservable(this.loading).pipe(debounce((isLoading) => interval(isLoading ? 75 : 0))),
);

View File

@@ -56,6 +56,8 @@ const shapeStyles: Record<IconTileShape, Record<IconTileSize, string[]>> = {
* - Create visual hierarchy in lists or cards
* - Show app or service icons in a consistent format
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-icon-tile",
templateUrl: "icon-tile.component.html",

View File

@@ -3,6 +3,8 @@ import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
import { Icon, isIcon } from "@bitwarden/assets/svg";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-icon",
host: {

View File

@@ -74,6 +74,8 @@ export class BitInputDirective implements BitFormFieldControl {
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
@HostBinding()
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
get required() {
return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;

View File

@@ -1,5 +1,7 @@
import { Component } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-item-action",
imports: [],

View File

@@ -29,7 +29,7 @@ import { TypographyModule } from "../typography";
export class ItemContentComponent implements AfterContentChecked {
readonly endSlot = viewChild<ElementRef<HTMLDivElement>>("endSlot");
protected endSlotHasChildren = signal(false);
protected readonly endSlotHasChildren = signal(false);
/**
* Determines whether text will truncate or wrap.

View File

@@ -22,7 +22,7 @@ export class ItemComponent {
/**
* We have `:focus-within` and `:focus-visible` but no `:focus-visible-within`
*/
protected focusVisibleWithin = signal(false);
protected readonly focusVisibleWithin = signal(false);
@HostListener("focusin", ["$event.target"])
onFocusIn(target: HTMLElement) {
this.focusVisibleWithin.set(target.matches("[data-fvw-target]:focus-visible"));

View File

@@ -12,6 +12,8 @@ import { SharedModule } from "../shared";
import { ScrollLayoutHostDirective } from "./scroll-layout.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-layout",
templateUrl: "layout.component.html",
@@ -34,7 +36,7 @@ export class LayoutComponent {
protected sideNavService = inject(SideNavService);
protected drawerPortal = inject(DrawerService).portal;
private mainContent = viewChild.required<ElementRef<HTMLElement>>("main");
private readonly mainContent = viewChild.required<ElementRef<HTMLElement>>("main");
protected focusMainContent() {
this.mainContent().nativeElement.focus();
}
@@ -45,7 +47,7 @@ export class LayoutComponent {
*
* @see https://github.com/angular/components/issues/10247#issuecomment-384060265
**/
private skipLink = viewChild.required<ElementRef<HTMLElement>>("skipLink");
private readonly skipLink = viewChild.required<ElementRef<HTMLElement>>("skipLink");
handleKeydown(ev: KeyboardEvent) {
if (isNothingFocused()) {
ev.preventDefault();

View File

@@ -17,7 +17,7 @@ import { filter, fromEvent, Observable, switchMap } from "rxjs";
**/
@Injectable({ providedIn: "root" })
export class ScrollLayoutService {
scrollableRef = signal<ElementRef<HTMLElement> | null>(null);
readonly scrollableRef = signal<ElementRef<HTMLElement> | null>(null);
scrollableRef$ = toObservable(this.scrollableRef);
}

View File

@@ -99,7 +99,7 @@ export class AnchorLinkDirective extends LinkDirective {
export class ButtonLinkDirective extends LinkDirective {
private el = inject(ElementRef<HTMLButtonElement>);
disabled = input(false, { transform: booleanAttribute });
readonly disabled = input(false, { transform: booleanAttribute });
@HostBinding("class") get classList() {
return ["before:-tw-inset-y-[0.25rem]"]

View File

@@ -1,5 +1,7 @@
import { Component } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-menu-divider",
templateUrl: "./menu-divider.component.html",

View File

@@ -3,6 +3,8 @@ import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass } from "@angular/common";
import { Component, ElementRef, HostBinding, Input } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "[bitMenuItem]",
templateUrl: "menu-item.component.html",
@@ -42,6 +44,8 @@ export class MenuItemDirective implements FocusableOption {
// TODO: Skipped for signal migration because:
// This input overrides a field from a superclass, while the superclass field
// is not migrated.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: coerceBooleanProperty }) disabled?: boolean = false;
constructor(public elementRef: ElementRef<HTMLButtonElement>) {}

View File

@@ -68,6 +68,8 @@ describe("Menu", () => {
});
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-app",
template: `

View File

@@ -12,6 +12,8 @@ import {
import { MenuItemDirective } from "./menu-item.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-menu",
templateUrl: "./menu.component.html",
@@ -20,6 +22,8 @@ import { MenuItemDirective } from "./menu-item.directive";
})
export class MenuComponent implements AfterContentInit {
readonly templateRef = viewChild.required(TemplateRef);
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() closed = new EventEmitter<void>();
readonly menuItems = contentChildren(MenuItemDirective, { descendants: true });
keyManager?: FocusKeyManager<MenuItemDirective>;

View File

@@ -34,6 +34,8 @@ import { SelectItemView } from "./models/select-item-view";
// Increments for each instance of this component
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-multi-select",
templateUrl: "./multi-select.component.html",
@@ -64,6 +66,8 @@ export class MultiSelectComponent implements OnInit, BitFormFieldControl, Contro
readonly loading = input(false);
// TODO: Skipped for signal migration because:
// Your application code writes to the input. This prevents migration.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute }) disabled?: boolean;
// Internal tracking of selected items
@@ -79,6 +83,8 @@ export class MultiSelectComponent implements OnInit, BitFormFieldControl, Contro
/**Implemented as part of NG_VALUE_ACCESSOR */
private notifyOnTouched?: () => void;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() onItemsConfirmed = new EventEmitter<any[]>();
constructor(
@@ -208,6 +214,8 @@ export class MultiSelectComponent implements OnInit, BitFormFieldControl, Contro
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
@HostBinding("attr.required")
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
get required() {
return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;

View File

@@ -61,5 +61,7 @@ export abstract class NavBaseComponent {
/**
* Fires when main content is clicked
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() mainContentClicked: EventEmitter<MouseEvent> = new EventEmitter();
}

View File

@@ -3,6 +3,8 @@ import { Component } from "@angular/core";
import { SideNavService } from "./side-nav.service";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-nav-divider",
templateUrl: "./nav-divider.component.html",

View File

@@ -19,6 +19,8 @@ import { NavBaseComponent } from "./nav-base.component";
import { NavGroupAbstraction, NavItemComponent } from "./nav-item.component";
import { SideNavService } from "./side-nav.service";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-nav-group",
templateUrl: "./nav-group.component.html",
@@ -51,6 +53,8 @@ export class NavGroupComponent extends NavBaseComponent {
*/
readonly hideIfEmpty = input(false, { transform: booleanAttribute });
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output()
openChange = new EventEmitter<boolean>();

View File

@@ -12,6 +12,8 @@ import { I18nMockService } from "../utils/i18n-mock.service";
import { NavGroupComponent } from "./nav-group.component";
import { NavigationModule } from "./navigation.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
template: "",
})

View File

@@ -13,6 +13,8 @@ export abstract class NavGroupAbstraction {
abstract setOpen(open: boolean): void;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-nav-item",
templateUrl: "./nav-item.component.html",

View File

@@ -8,6 +8,8 @@ import { BitIconComponent } from "../icon/icon.component";
import { SideNavService } from "./side-nav.service";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-nav-logo",
templateUrl: "./nav-logo.component.html",

View File

@@ -11,6 +11,8 @@ import { SideNavService } from "./side-nav.service";
export type SideNavVariant = "primary" | "secondary";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-side-nav",
templateUrl: "side-nav.component.html",

View File

@@ -7,6 +7,8 @@ import { BitIconComponent } from "../icon/icon.component";
/**
* Component for displaying a message when there are no items to display. Expects title, description and button slots.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-no-items",
templateUrl: "./no-items.component.html",

View File

@@ -5,6 +5,8 @@ import { IconButtonModule } from "../icon-button/icon-button.module";
import { SharedModule } from "../shared/shared.module";
import { TypographyModule } from "../typography";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-popover",
imports: [A11yModule, IconButtonModule, SharedModule, TypographyModule],
@@ -14,5 +16,7 @@ import { TypographyModule } from "../typography";
export class PopoverComponent {
readonly templateRef = viewChild.required(TemplateRef);
readonly title = input("");
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() closed = new EventEmitter();
}

View File

@@ -20,6 +20,8 @@ const BackgroundClasses: Record<BackgroundType, string[]> = {
/**
* Progress indicators may be used to visually indicate progress or to visually measure some other value, such as a password strength indicator.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-progress",
templateUrl: "./progress.component.html",

View File

@@ -53,6 +53,8 @@ describe("RadioButton", () => {
});
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-component",
template: `

View File

@@ -7,6 +7,8 @@ import { RadioInputComponent } from "./radio-input.component";
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-radio-button",
templateUrl: "radio-button.component.html",

View File

@@ -63,6 +63,8 @@ describe("RadioGroupComponent", () => {
});
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-app",
template: `

View File

@@ -8,6 +8,8 @@ import { BitLabel } from "../form-control/label.component";
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-radio-group",
templateUrl: "radio-group.component.html",

View File

@@ -5,6 +5,8 @@ import { BitFormControlAbstraction } from "../form-control";
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "input[type=radio][bitRadio]",
template: "",

View File

@@ -13,6 +13,8 @@ export class ResizeObserverDirective implements OnDestroy {
}
});
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output()
resize = new EventEmitter();

View File

@@ -18,6 +18,8 @@ let nextId = 0;
/**
* Do not nest Search components inside another `<form>`, as they already contain their own standalone `<form>` element for searching.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-search",
templateUrl: "./search.component.html",
@@ -45,10 +47,12 @@ export class SearchComponent implements ControlValueAccessor, FocusableElement {
// Use `type="text"` for Safari to improve rendering performance
protected inputType = isBrowserSafariApi() ? ("text" as const) : ("search" as const);
protected isInputFocused = signal(false);
protected isFormHovered = signal(false);
protected readonly isInputFocused = signal(false);
protected readonly isFormHovered = signal(false);
protected showResetButton = computed(() => this.isInputFocused() || this.isFormHovered());
protected readonly showResetButton = computed(
() => this.isInputFocused() || this.isFormHovered(),
);
readonly disabled = model<boolean>();
readonly placeholder = input<string>();

View File

@@ -2,6 +2,8 @@ import { Component } from "@angular/core";
import { TypographyModule } from "../typography";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-section-header",
templateUrl: "./section-header.component.html",

View File

@@ -2,6 +2,8 @@ import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { CommonModule } from "@angular/common";
import { Component, input } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-section",
imports: [CommonModule],

View File

@@ -2,6 +2,8 @@ import { Component, booleanAttribute, input } from "@angular/core";
import { MappedOptionComponent } from "./option";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-option",
template: `<ng-template><ng-content></ng-content></ng-template>`,

View File

@@ -9,6 +9,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { SelectComponent } from "./select.component";
import { SelectModule } from "./select.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
imports: [SelectModule, ReactiveFormsModule],
template: `

View File

@@ -34,6 +34,8 @@ import { OptionComponent } from "./option.component";
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-select",
templateUrl: "select.component.html",
@@ -50,10 +52,12 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
readonly items = model<Option<T>[] | undefined>();
readonly placeholder = input(this.i18nService.t("selectPlaceholder"));
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() closed = new EventEmitter();
protected selectedValue = signal<T | undefined | null>(undefined);
selectedOption: Signal<Option<T> | null | undefined> = computed(() =>
protected readonly selectedValue = signal<T | undefined | null>(undefined);
readonly selectedOption: Signal<Option<T> | null | undefined> = computed(() =>
this.findSelectedOption(this.items(), this.selectedValue()),
);
protected searchInputId = `bit-select-search-input-${nextId++}`;
@@ -70,6 +74,8 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ContentChildren(OptionComponent)
protected set options(value: QueryList<OptionComponent<T>>) {
if (value == null || value.length == 0) {
@@ -94,6 +100,8 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
}
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
get disabled() {
return this._disabled ?? this.ngControl?.disabled ?? false;
@@ -166,6 +174,8 @@ export class SelectComponent<T> implements BitFormFieldControl, ControlValueAcce
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
@HostBinding("attr.required")
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
get required() {
return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;

View File

@@ -7,6 +7,8 @@ import { Component } from "@angular/core";
* Pass skeleton loaders into the start, default, and end content slots. The content within each slot
* is fully customizable.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-skeleton-group",
templateUrl: "./skeleton-group.component.html",

View File

@@ -10,6 +10,8 @@ import { SkeletonComponent } from "./skeleton.component";
* Customize the number of lines represented with the `lines` input. Customize the width
* by applying a class to the `bit-skeleton-text` element (i.e. `tw-w-1/2`).
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-skeleton-text",
templateUrl: "./skeleton-text.component.html",
@@ -27,5 +29,5 @@ export class SkeletonTextComponent {
/**
* Array-transformed version of the `lines` to loop over
*/
protected linesArray = computed(() => [...Array(this.lines()).keys()]);
protected readonly linesArray = computed(() => [...Array(this.lines()).keys()]);
}

View File

@@ -10,6 +10,8 @@ import { Component, input } from "@angular/core";
*
* If you're looking to represent lines of text, use the `bit-skeleton-text` helper component.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-skeleton",
templateUrl: "./skeleton.component.html",

View File

@@ -3,6 +3,8 @@ import { Component, HostBinding, Input, booleanAttribute } from "@angular/core";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-spinner",
templateUrl: "spinner.component.html",
@@ -13,21 +15,29 @@ export class SpinnerComponent {
/**
* The size of the spinner. Defaults to `large`.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() size: "fill" | "small" | "large" = "large";
/**
* Disable the default color of the spinner, inherits the text color.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute }) noColor = false;
/**
* Accessibility title. Defaults to `Loading`.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() title = this.i18nService.t("loading");
/**
* Display text for screen readers.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input({ transform: booleanAttribute }) sr = true;
@HostBinding("class") get classList() {

View File

@@ -1,6 +1,8 @@
import { CdkStep, CdkStepper } from "@angular/cdk/stepper";
import { Component, input } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-step",
templateUrl: "step.component.html",
@@ -8,7 +10,7 @@ import { Component, input } from "@angular/core";
standalone: true,
})
export class StepComponent extends CdkStep {
subLabel = input();
readonly subLabel = input();
constructor(stepper: CdkStepper) {
super(stepper);

View File

@@ -12,6 +12,8 @@ import { StepComponent } from "./step.component";
* The `<bit-stepper>` component extends the
* [Angular CdkStepper](https://material.angular.io/cdk/stepper/api#CdkStepper) component
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-stepper",
templateUrl: "stepper.component.html",
@@ -44,6 +46,8 @@ export class StepperComponent extends CdkStepper {
// overriding CdkStepper orientation input so we can default to vertical
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
override get orientation() {
return this.internalOrientation || "vertical";

View File

@@ -7,6 +7,8 @@ import { ScrollLayoutDirective } from "../../../layout";
import { SectionComponent } from "../../../section";
import { TableDataSource, TableModule } from "../../../table";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "dialog-virtual-scroll-block",
standalone: true,

View File

@@ -7,6 +7,8 @@ import { DialogService } from "../../../dialog";
import { I18nMockService } from "../../../utils/i18n-mock.service";
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-kitchen-sink-form",
imports: [KitchenSinkSharedModule],

View File

@@ -8,6 +8,8 @@ import { KitchenSinkForm } from "./kitchen-sink-form.component";
import { KitchenSinkTable } from "./kitchen-sink-table.component";
import { KitchenSinkToggleList } from "./kitchen-sink-toggle-list.component";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
imports: [KitchenSinkSharedModule],
template: `
@@ -85,6 +87,8 @@ class KitchenSinkDialog {
constructor(public dialogRef: DialogRef) {}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-tab-main",
imports: [KitchenSinkSharedModule, KitchenSinkTable, KitchenSinkToggleList, KitchenSinkForm],
@@ -175,7 +179,7 @@ class KitchenSinkDialog {
export class KitchenSinkMainComponent {
constructor(public dialogService: DialogService) {}
protected drawerOpen = signal(false);
protected readonly drawerOpen = signal(false);
openDialog() {
this.dialogService.open(KitchenSinkDialog);

View File

@@ -2,6 +2,8 @@ import { Component } from "@angular/core";
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-kitchen-sink-table",
imports: [KitchenSinkSharedModule],

View File

@@ -2,6 +2,8 @@ import { Component } from "@angular/core";
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-kitchen-sink-toggle-list",
imports: [KitchenSinkSharedModule],

View File

@@ -13,6 +13,8 @@ describe("SwitchComponent", () => {
let switchComponent: SwitchComponent;
let inputEl: HTMLInputElement;
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-host",
imports: [FormsModule, BitLabel, ReactiveFormsModule, SwitchModule],
@@ -70,6 +72,8 @@ describe("SwitchComponent", () => {
});
it("should update checked when selected input changes outside of a form", async () => {
// TODO: Fix this the next time the file is edited.
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "test-selected-host",
template: `<bit-switch [selected]="checked"><bit-label>Element</bit-label></bit-switch>`,

View File

@@ -21,6 +21,8 @@ let nextId = 0;
/**
* Switch component for toggling between two states. Switch actions are meant to take place immediately and are not to be used in a form where saving/submiting actions are required.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-switch",
providers: [
@@ -46,19 +48,19 @@ export class SwitchComponent implements ControlValueAccessor, AfterViewInit {
/**
* Model signal for selected state binding when used outside of a form
*/
protected selected = model(false);
protected readonly selected = model(false);
/**
* Model signal for disabled binding when used outside of a form
*/
protected disabled = model(false);
protected disabledReasonText = input<string | null>(null);
protected readonly disabled = model(false);
protected readonly disabledReasonText = input<string | null>(null);
private hintComponent = contentChild<BitHintComponent>(BitHintComponent);
private readonly hintComponent = contentChild<BitHintComponent>(BitHintComponent);
private disabledReasonTextId = `bit-switch-disabled-text-${nextId++}`;
private describedByIds = computed(() => {
private readonly describedByIds = computed(() => {
const ids: string[] = [];
if (this.disabledReasonText() && this.disabled()) {

View File

@@ -5,6 +5,8 @@ import { Component, HostBinding, OnInit, input } from "@angular/core";
import type { SortDirection, SortFn } from "./table-data-source";
import { TableComponent } from "./table.component";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "th[bitSortable]",
template: `

View File

@@ -44,6 +44,8 @@ export class BitRowDef {
*
* Utilizes virtual scrolling to render large datasets.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-table-scroll",
templateUrl: "./table-scroll.component.html",

View File

@@ -21,6 +21,8 @@ export class TableBodyDirective {
constructor(public readonly template: TemplateRef<any>) {}
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-table",
templateUrl: "./table.component.html",

View File

@@ -3,6 +3,8 @@ import { Component } from "@angular/core";
/**
* Component used for styling the tab header/background for both content and navigation tabs
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-tab-header",
host: {

View File

@@ -13,6 +13,8 @@ export class TabListItemDirective implements FocusableOption {
// TODO: Skipped for signal migration because:
// This input overrides a field from a superclass, while the superclass field
// is not migrated.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() disabled = false;
@HostBinding("attr.disabled")

View File

@@ -1,6 +1,8 @@
import { TemplatePortal, CdkPortalOutlet } from "@angular/cdk/portal";
import { Component, effect, HostBinding, input } from "@angular/core";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-tab-body",
templateUrl: "tab-body.component.html",

View File

@@ -27,6 +27,8 @@ import { TabComponent } from "./tab.component";
/** Used to generate unique ID's for each tab component */
let nextId = 0;
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-tab-group",
templateUrl: "./tab-group.component.html",
@@ -57,14 +59,16 @@ export class TabGroupComponent implements AfterContentChecked, AfterViewInit {
readonly preserveContent = input(false);
/** Error if no `TabComponent` is supplied. (`contentChildren`, used to query for all the tabs, doesn't support `required`) */
private _tab = contentChild.required(TabComponent);
private readonly _tab = contentChild.required(TabComponent);
protected tabs = contentChildren(TabComponent);
protected readonly tabs = contentChildren(TabComponent);
readonly tabLabels = viewChildren(TabListItemDirective);
/** The index of the active tab. */
// TODO: Skipped for signal migration because:
// Accessor inputs cannot be migrated as they are too complex.
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input()
get selectedIndex(): number | null {
return this._selectedIndex;
@@ -75,9 +79,13 @@ export class TabGroupComponent implements AfterContentChecked, AfterViewInit {
private _selectedIndex: number | null = null;
/** Output to enable support for two-way binding on `[(selectedIndex)]` */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() readonly selectedIndexChange: EventEmitter<number> = new EventEmitter<number>();
/** Event emitted when the tab selection has changed. */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() readonly selectedTabChange: EventEmitter<BitTabChangeEvent> =
new EventEmitter<BitTabChangeEvent>();

View File

@@ -11,6 +11,8 @@ import {
import { TabLabelDirective } from "./tab-label.directive";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "bit-tab",
templateUrl: "./tab.component.html",
@@ -33,6 +35,8 @@ export class TabComponent implements OnInit {
readonly contentTabIndex = input<number | undefined>();
readonly implicitContent = viewChild.required(TemplateRef);
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ContentChild(TabLabelDirective) templateLabel?: TabLabelDirective;
private _contentPortal: TemplatePortal | null = null;

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