mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
[CL-707] Migrate CL codebase to signals (#15340)
This commit is contained in:
@@ -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,
|
||||
booleanAttribute,
|
||||
Directive,
|
||||
ElementRef,
|
||||
input,
|
||||
NgZone,
|
||||
Optional,
|
||||
} from "@angular/core";
|
||||
import { take } from "rxjs/operators";
|
||||
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@@ -21,11 +29,7 @@ import { FocusableElement } from "../shared/focusable-element";
|
||||
selector: "[appAutofocus], [bitAutofocus]",
|
||||
})
|
||||
export class AutofocusDirective implements AfterContentChecked {
|
||||
@Input() set appAutofocus(condition: boolean | string) {
|
||||
this.autofocus = condition === "" || condition === true;
|
||||
}
|
||||
|
||||
private autofocus: boolean;
|
||||
readonly appAutofocus = input(undefined, { transform: booleanAttribute });
|
||||
|
||||
// Track if we have already focused the element.
|
||||
private focused = false;
|
||||
@@ -46,7 +50,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.appAutofocus() || Utils.isMobileBrowser) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
21
libs/components/src/input/autofocus.mdx
Normal file
21
libs/components/src/input/autofocus.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Meta, Canvas, Primary, Controls, Title, Description } from "@storybook/addon-docs";
|
||||
|
||||
import * as stories from "./autofocus.stories";
|
||||
|
||||
<Meta of={stories} />
|
||||
|
||||
```ts
|
||||
import { AutofocusDirective } from "@bitwarden/components";
|
||||
```
|
||||
|
||||
<Title />
|
||||
<Description />
|
||||
|
||||
<Primary />
|
||||
<Controls />
|
||||
|
||||
## Accessibility
|
||||
|
||||
The autofocus directive has accessibility implications, because it will steal focus from wherever it
|
||||
would naturally be placed on page load. Please consider whether or not the user truly needs the
|
||||
element truly needs to be manually focused on their behalf.
|
||||
26
libs/components/src/input/autofocus.stories.ts
Normal file
26
libs/components/src/input/autofocus.stories.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Meta, moduleMetadata, StoryObj } from "@storybook/angular";
|
||||
|
||||
import { FormFieldModule } from "../form-field";
|
||||
|
||||
import { AutofocusDirective } from "./autofocus.directive";
|
||||
|
||||
export default {
|
||||
title: "Component Library/Form/Autofocus Directive",
|
||||
component: AutofocusDirective,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [AutofocusDirective, FormFieldModule],
|
||||
}),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
export const AutofocusField: StoryObj = {
|
||||
render: (args) => ({
|
||||
template: /*html*/ `
|
||||
<bit-form-field>
|
||||
<bit-label>Email</bit-label>
|
||||
<input bitInput formControlName="email" appAutofocus />
|
||||
</bit-form-field>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
NgZone,
|
||||
Optional,
|
||||
Self,
|
||||
input,
|
||||
model,
|
||||
} from "@angular/core";
|
||||
import { NgControl, Validators } from "@angular/forms";
|
||||
|
||||
@@ -30,9 +32,15 @@ export function inputBorderClasses(error: boolean) {
|
||||
@Directive({
|
||||
selector: "input[bitInput], select[bitInput], textarea[bitInput]",
|
||||
providers: [{ provide: BitFormFieldControl, useExisting: BitInputDirective }],
|
||||
host: {
|
||||
"[class]": "classList()",
|
||||
"[id]": "id()",
|
||||
"[attr.type]": "type()",
|
||||
"[attr.spellcheck]": "spellcheck()",
|
||||
},
|
||||
})
|
||||
export class BitInputDirective implements BitFormFieldControl {
|
||||
@HostBinding("class") @Input() get classList() {
|
||||
classList() {
|
||||
const classes = [
|
||||
"tw-block",
|
||||
"tw-w-full",
|
||||
@@ -52,7 +60,7 @@ export class BitInputDirective implements BitFormFieldControl {
|
||||
return classes.filter((s) => s != "");
|
||||
}
|
||||
|
||||
@HostBinding() @Input() id = `bit-input-${nextId++}`;
|
||||
readonly id = input(`bit-input-${nextId++}`);
|
||||
|
||||
@HostBinding("attr.aria-describedby") ariaDescribedBy: string;
|
||||
|
||||
@@ -60,10 +68,12 @@ export class BitInputDirective implements BitFormFieldControl {
|
||||
return this.hasError ? true : undefined;
|
||||
}
|
||||
|
||||
@HostBinding("attr.type") @Input() type?: InputTypes;
|
||||
readonly type = model<InputTypes>();
|
||||
|
||||
@HostBinding("attr.spellcheck") @Input() spellcheck?: boolean;
|
||||
readonly spellcheck = model<boolean>();
|
||||
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Accessor inputs cannot be migrated as they are too complex.
|
||||
@HostBinding()
|
||||
@Input()
|
||||
get required() {
|
||||
@@ -74,13 +84,13 @@ export class BitInputDirective implements BitFormFieldControl {
|
||||
}
|
||||
private _required: boolean;
|
||||
|
||||
@Input() hasPrefix = false;
|
||||
@Input() hasSuffix = false;
|
||||
readonly hasPrefix = input(false);
|
||||
readonly hasSuffix = input(false);
|
||||
|
||||
@Input() showErrorsWhenDisabled? = false;
|
||||
readonly showErrorsWhenDisabled = input<boolean>(false);
|
||||
|
||||
get labelForId(): string {
|
||||
return this.id;
|
||||
return this.id();
|
||||
}
|
||||
|
||||
@HostListener("input")
|
||||
@@ -89,7 +99,7 @@ export class BitInputDirective implements BitFormFieldControl {
|
||||
}
|
||||
|
||||
get hasError() {
|
||||
if (this.showErrorsWhenDisabled) {
|
||||
if (this.showErrorsWhenDisabled()) {
|
||||
return (
|
||||
(this.ngControl?.status === "INVALID" || this.ngControl?.status === "DISABLED") &&
|
||||
this.ngControl?.touched &&
|
||||
|
||||
Reference in New Issue
Block a user