From 58a2904ceea4133b1d5fb153534f991a00d5bdde Mon Sep 17 00:00:00 2001 From: Vicki League Date: Tue, 24 Jun 2025 13:27:17 -0400 Subject: [PATCH] finish migrating input module --- .../src/form-field/form-field-control.ts | 9 ++++--- .../src/input/autofocus.directive.ts | 20 ++++++++------ libs/components/src/input/input.directive.ts | 27 ++++++++----------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/libs/components/src/form-field/form-field-control.ts b/libs/components/src/form-field/form-field-control.ts index cd7c36b4cea..8fc1c5395dc 100644 --- a/libs/components/src/form-field/form-field-control.ts +++ b/libs/components/src/form-field/form-field-control.ts @@ -1,4 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line + +import { Signal } from "@angular/core"; + // @ts-strict-ignore export type InputTypes = | "text" @@ -14,13 +17,13 @@ export type InputTypes = export abstract class BitFormFieldControl { ariaDescribedBy: string; - id: string; + id: Signal; labelForId: string; required: boolean; hasError: boolean; error: [string, any]; - type?: InputTypes; - spellcheck?: boolean; + type?: Signal; + spellcheck?: Signal; readOnly?: boolean; focus?: () => void; } diff --git a/libs/components/src/input/autofocus.directive.ts b/libs/components/src/input/autofocus.directive.ts index d85350bc22d..2e3f99c91c0 100644 --- a/libs/components/src/input/autofocus.directive.ts +++ b/libs/components/src/input/autofocus.directive.ts @@ -1,6 +1,14 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { AfterContentChecked, Directive, ElementRef, Input, NgZone, Optional } from "@angular/core"; +import { + AfterContentChecked, + computed, + Directive, + ElementRef, + input, + NgZone, + Optional, +} from "@angular/core"; import { take } from "rxjs/operators"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -21,13 +29,9 @@ import { FocusableElement } from "../shared/focusable-element"; selector: "[appAutofocus], [bitAutofocus]", }) export class AutofocusDirective implements AfterContentChecked { - // TODO: Skipped for migration because: - // Accessor inputs cannot be migrated as they are too complex. - @Input() set appAutofocus(condition: boolean | string) { - this.autofocus = condition === "" || condition === true; - } + appAutofocus = input(); - private autofocus: boolean; + private autofocus = computed(() => this.appAutofocus() === "" || this.appAutofocus() === true); // Track if we have already focused the element. private focused = false; @@ -48,7 +52,7 @@ export class AutofocusDirective implements AfterContentChecked { */ ngAfterContentChecked() { // We only want to focus the element on initial render and it's not a mobile browser - if (this.focused || !this.autofocus || Utils.isMobileBrowser) { + if (this.focused || !this.autofocus() || Utils.isMobileBrowser) { return; } diff --git a/libs/components/src/input/input.directive.ts b/libs/components/src/input/input.directive.ts index 53f0ca542eb..1266559c7c6 100644 --- a/libs/components/src/input/input.directive.ts +++ b/libs/components/src/input/input.directive.ts @@ -31,11 +31,15 @@ export function inputBorderClasses(error: boolean) { @Directive({ selector: "input[bitInput], select[bitInput], textarea[bitInput]", providers: [{ provide: BitFormFieldControl, useExisting: BitInputDirective }], + host: { + "[attr.class]": "getClassList()", + "[id]": "id()", + "[attr.type]": "type()", + "[attr.spellcheck]": "spellcheck()", + }, }) export class BitInputDirective implements BitFormFieldControl { - // TODO: Skipped for migration because: - // Accessor inputs cannot be migrated as they are too complex. - @HostBinding("class") @Input() get classList() { + classList() { const classes = [ "tw-block", "tw-w-full", @@ -55,10 +59,7 @@ export class BitInputDirective implements BitFormFieldControl { return classes.filter((s) => s != ""); } - // TODO: Skipped for migration because: - // This input is used in combination with `@HostBinding` and migrating would - // break. - @HostBinding() @Input() id = `bit-input-${nextId++}`; + readonly id = input(`bit-input-${nextId++}`); @HostBinding("attr.aria-describedby") ariaDescribedBy: string; @@ -66,15 +67,9 @@ export class BitInputDirective implements BitFormFieldControl { return this.hasError ? true : undefined; } - // TODO: Skipped for migration because: - // This input is used in combination with `@HostBinding` and migrating would - // break. - @HostBinding("attr.type") @Input() type?: InputTypes; + readonly type = input(); - // TODO: Skipped for migration because: - // This input is used in combination with `@HostBinding` and migrating would - // break. - @HostBinding("attr.spellcheck") @Input() spellcheck?: boolean; + readonly spellcheck = input(); // TODO: Skipped for migration because: // Accessor inputs cannot be migrated as they are too complex. @@ -94,7 +89,7 @@ export class BitInputDirective implements BitFormFieldControl { readonly showErrorsWhenDisabled = input(false); get labelForId(): string { - return this.id; + return this.id(); } @HostListener("input")