From 6a2f7a787fd30890aca0d68fb44363302c9b1ed7 Mon Sep 17 00:00:00 2001 From: Maicon Godinho Date: Sun, 28 Jan 2024 13:16:02 -0300 Subject: [PATCH 1/9] feat: add password input --- src/icon/icon.module.ts | 4 + src/input/index.ts | 2 + src/input/input.module.ts | 10 +- src/input/label.component.ts | 34 ++- src/input/password-input-label.component.ts | 299 ++++++++++++++++++++ src/input/password.directive.ts | 51 ++++ src/input/password.stories.ts | 97 +++++++ 7 files changed, 489 insertions(+), 8 deletions(-) create mode 100644 src/input/password-input-label.component.ts create mode 100644 src/input/password.directive.ts create mode 100644 src/input/password.stories.ts diff --git a/src/icon/icon.module.ts b/src/icon/icon.module.ts index a43a68fb54..6a84183b22 100644 --- a/src/icon/icon.module.ts +++ b/src/icon/icon.module.ts @@ -57,6 +57,8 @@ import WarningFilled16 from "@carbon/icons/es/warning--filled/16"; import WarningFilled20 from "@carbon/icons/es/warning--filled/20"; import WarningAltFilled16 from "@carbon/icons/es/warning--alt--filled/16"; import WarningAltFilled20 from "@carbon/icons/es/warning--alt--filled/20"; +import View16 from "@carbon/icons/es/view/16"; +import ViewOff16 from "@carbon/icons/es/view--off/16"; // either provides a new instance of IconService, or returns the parent export function ICON_SERVICE_PROVIDER_FACTORY(parentService: IconService) { @@ -132,6 +134,8 @@ export class IconModule { SettingsAdjust16, Subtract16, TrashCan16, + View16, + ViewOff16, Warning16, WarningFilled16, WarningFilled20, diff --git a/src/input/index.ts b/src/input/index.ts index efb5886bc1..85019bb691 100644 --- a/src/input/index.ts +++ b/src/input/index.ts @@ -4,3 +4,5 @@ export * from "./label.component"; export * from "./text-area.directive"; export * from "./text-input-label.component"; export * from "./textarea-label.component"; +export * from "./password-input-label.component"; +export * from "./password.directive"; diff --git a/src/input/input.module.ts b/src/input/input.module.ts index adfd7f7a7a..9285dc8903 100644 --- a/src/input/input.module.ts +++ b/src/input/input.module.ts @@ -10,21 +10,27 @@ import { TextArea } from "./text-area.directive"; import { TextareaLabelComponent } from "./textarea-label.component"; import { TextInputLabelComponent } from "./text-input-label.component"; import { IconModule } from "carbon-components-angular/icon"; +import { PasswordInput } from "./password.directive"; +import { PasswordInputLabelComponent } from "./password-input-label.component"; @NgModule({ declarations: [ Label, TextInput, TextArea, + PasswordInput, TextareaLabelComponent, - TextInputLabelComponent + TextInputLabelComponent, + PasswordInputLabelComponent ], exports: [ Label, TextareaLabelComponent, TextInputLabelComponent, + PasswordInputLabelComponent, TextInput, - TextArea + TextArea, + PasswordInput ], imports: [ CommonModule, diff --git a/src/input/label.component.ts b/src/input/label.component.ts index eebed83cec..8dd7fc4074 100644 --- a/src/input/label.component.ts +++ b/src/input/label.component.ts @@ -13,6 +13,7 @@ import { import { TextArea } from "./text-area.directive"; import { TextInput } from "./input.directive"; +import { PasswordInput } from "./password.directive"; /** * Get started with importing the module: @@ -74,6 +75,22 @@ import { TextInput } from "./input.directive"; [textInputTemplate]="inputContentTemplate"> + + + + @@ -102,13 +119,13 @@ import { TextInput } from "./input.directive"; cdsIcon="warning--filled" size="16" class="cds--text-input__invalid-icon"> - + - +
+ * Label + * + * + * + * ``` + * + * [See demo](../../?path=/story/components-input--basic) + */ +@Component({ + selector: "cds-password-label, ibm-password-label", + template: ` + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ {{ helperText }} + +
+ +
+ {{ invalidText }} + +
+ +
+ {{ warnText }} + +
+ ` +}) +/** + * Represents the Password Input Label Component. + */ +export class PasswordInputLabelComponent implements AfterViewInit { + + /** + * Getter for generating classes for password visibility toggle. + */ + get passwordVisibilityToggleClasses(): string { + return [ + "cds--text-input--password__visibility__toggle", + "cds--btn", + "cds--btn--icon-only", + "cds--tooltip__trigger", + "cds--tooltip--a11y", + this.disabled ? "cds--btn--disabled" : "", + this.tooltipPosition ? `cds--tooltip--${this.tooltipPosition}` : "", + this.tooltipAlignment + ? `cds--tooltip--align-${this.tooltipAlignment}` + : "" + ].join(" "); + } + + /** + * Getter for checking if password is visible. + */ + get passwordIsVisible() { + return this.inputType === "text"; + } + + /** + * Counter for generating unique labelInputID. + */ + static labelCounter = 0; + /** + * Type for input field, either password or text. + */ + inputType: "password" | "text" = "password"; + + /** + * ID for the input item associated with the label. + */ + @Input() labelInputID = + "ibm-password-input-" + PasswordInputLabelComponent.labelCounter++; + + /** + * Flag for disabled label. + */ + @Input() disabled = false; + + /** + * Flag for loading (skeleton) label. + */ + @Input() skeleton = false; + + /** + * Template for label content. + */ + @Input() labelTemplate: TemplateRef; + + /** + * Template for password input. + */ + @Input() passwordInputTemplate: TemplateRef; + + /** + * Optional helper text under the label. + */ + @Input() helperText: string | TemplateRef; + + /** + * Sets the invalid text. + */ + @Input() invalidText: string | TemplateRef; + + /** + * Flag for an invalid label component. + */ + @Input() invalid = false; + + /** + * Flag for showing a warning. + */ + @Input() warn = false; + + /** + * Warning text. + */ + @Input() warnText: string | TemplateRef; + + /** + * Aria label for label. + */ + @Input() ariaLabel: string; + + /** + * Tooltip text for hiding password. + */ + @Input() hidePasswordLabel = "Hide password"; + + /** + * Tooltip text for showing password. + */ + @Input() showPasswordLabel = "Show password"; + + /** + * Alignment of the tooltip to the icon-only button. + */ + @Input() tooltipPosition: "top" | "right" | "bottom" | "left" = "bottom"; + + /** + * Direction of the tooltip for icon-only buttons. + */ + @Input() tooltipAlignment: "start" | "center" | "end" = "center"; + + /** + * Reference to the wrapper element. + * @ts-ignore + */ + @ViewChild("wrapper", { static: false }) + wrapper: ElementRef; + + /** + * Binding for applying class to host element. + */ + @HostBinding("class.cds--form-item") labelClass = true; + + /** + * Constructor for PasswordInputLabelComponent. + * @param changeDetectorRef - Reference to ChangeDetectorRef. + */ + constructor(protected changeDetectorRef: ChangeDetectorRef) { } + + /** + * Lifecycle hook called after the view has been initialized. + */ + ngAfterViewInit() { + if (this.wrapper) { + const inputElement = + this.wrapper.nativeElement.querySelector("input"); + if (inputElement) { + if (inputElement.id) { + this.labelInputID = inputElement.id; + this.changeDetectorRef.detectChanges(); + } + inputElement.setAttribute("id", this.labelInputID); + return; + } + + const divElement = this.wrapper.nativeElement.querySelector("div"); + if (divElement) { + if (divElement.id) { + this.labelInputID = divElement.id; + this.changeDetectorRef.detectChanges(); + } + divElement.setAttribute("id", this.labelInputID); + } + } + } + + /** + * Function to check if a value is a TemplateRef. + * @param value - Value to check. + * @returns Whether the value is a TemplateRef. + */ + public isTemplate(value) { + return value instanceof TemplateRef; + } + + /** + * Handler for toggling password visibility. + */ + public handleTogglePasswordVisibility() { + this.inputType = this.inputType === "password" ? "text" : "password"; + } +} diff --git a/src/input/password.directive.ts b/src/input/password.directive.ts new file mode 100644 index 0000000000..e5e9a5aa22 --- /dev/null +++ b/src/input/password.directive.ts @@ -0,0 +1,51 @@ +import { Directive, HostBinding, Input } from "@angular/core"; + +@Directive({ + selector: "[cdsPassword], [ibmPassword]" +}) +export class PasswordInput { + /** + * @deprecated since v5 - Use `cdsLayer` directive instead + * `light` or `dark` input theme + */ + @Input() theme: "light" | "dark" = "dark"; + + /** + * Input field render size + */ + @Input() size: "sm" | "md" | "lg" = "md"; + + @HostBinding("class.cds--text-input") inputClass = true; + @HostBinding("class.cds--password-input") passwordInputClass = true; + + /** + * @todo - remove `cds--text-input--${size}` classes in v12 + */ + @HostBinding("class.cds--text-input--sm") get isSizeSm() { + return this.size === "sm"; + } + @HostBinding("class.cds--text-input--md") get isSizeMd() { + return this.size === "md"; + } + @HostBinding("class.cds--text-input--lg") get isSizelg() { + return this.size === "lg"; + } + + // Size + @HostBinding("class.cds--layout--size-sm") get sizeSm() { + return this.size === "sm"; + } + @HostBinding("class.cds--layout--size-md") get sizeMd() { + return this.size === "md"; + } + @HostBinding("class.cds--layout--size-lg") get sizelg() { + return this.size === "lg"; + } + + @HostBinding("class.cds--text-input--invalid") @Input() invalid = false; + @HostBinding("class.cds--text-input__field-wrapper--warning") @Input() warn = false; + @HostBinding("class.cds--skeleton") @Input() skeleton = false; + @HostBinding("class.cds--text-input--light") get isLightTheme() { + return this.theme === "light"; + } +} diff --git a/src/input/password.stories.ts b/src/input/password.stories.ts new file mode 100644 index 0000000000..136c8e5759 --- /dev/null +++ b/src/input/password.stories.ts @@ -0,0 +1,97 @@ +/* tslint:disable variable-name */ + +import { moduleMetadata, Meta } from "@storybook/angular"; +import { InputModule, PasswordInputLabelComponent } from "."; +import { FormsModule } from "@angular/forms"; + +export default { + title: "Components/Input/Password", + decorators: [ + moduleMetadata({ + imports: [InputModule, FormsModule] + }) + ], + component: PasswordInputLabelComponent +} as Meta; + +const Template = (args) => ({ + props: args, + template: ` + + {{ label }} + + + + ` +}); +export const Basic = Template.bind({}); +Basic.args = { + disabled: false, + invalid: false, + invalidText: "Invalid entry", + warn: false, + warnText: "This is a warning!", + label: "Text input label", + helperText: "Optional helper text", + placeholder: "Placeholder", + autocomplete: "on", + theme: "dark", + size: "md", + value: "" +}; +Basic.argTypes = { + autocomplete: { + options: ["on", "off"], + control: "radio" + }, + theme: { + options: ["light", "dark"], + control: "radio" + }, + size: { + options: ["sm", "md", "lg"], + control: "select" + } +}; + +const SkeletonTemplate = (args) => ({ + props: args, + template: ` + + + + +
+ + ` +}); +export const Skeleton = SkeletonTemplate.bind({}); From 144f2846298b4a2fcf83e0600e55673e42a771db Mon Sep 17 00:00:00 2001 From: Akshat Patel Date: Tue, 21 May 2024 15:20:19 -0400 Subject: [PATCH 2/9] fix: bump styles peer dependency Signed-off-by: Akshat Patel --- package-lock.json | 16 ++++++++-------- package.json | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2529d94e47..d4b577d9c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@angular/platform-browser-dynamic": "14.3.0", "@angular/router": "14.3.0", "@babel/core": "7.9.6", - "@carbon/styles": "1.54.0", + "@carbon/styles": "1.56.0", "@carbon/themes": "11.24.0", "@commitlint/cli": "17.0.3", "@commitlint/config-conventional": "17.0.3", @@ -89,7 +89,7 @@ "@angular/common": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "@angular/core": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "@angular/forms": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", - "@carbon/styles": "^1.54.0", + "@carbon/styles": "^1.56.0", "rxjs": "^6.0.0 || ^7.0.0", "zone.js": "^0.11.0" } @@ -3820,9 +3820,9 @@ } }, "node_modules/@carbon/styles": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.54.0.tgz", - "integrity": "sha512-VXcx+o6q2ol2kcm3cfE8PaV2+EgbwVaSlZ9gH6VYorBN2MT4I9xypQAYzoyrNN0oV/Q92Xiyb3WejKuy74xFEg==", + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.56.0.tgz", + "integrity": "sha512-NE6A0YasZoHsGwdhzN3/8qsVl7pQHy6qMxjGyGH1MIfJV96ZwR5/3hQSVyWrom+bHsZBUPMgBemImZSX/cdqew==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -37790,9 +37790,9 @@ } }, "@carbon/styles": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.54.0.tgz", - "integrity": "sha512-VXcx+o6q2ol2kcm3cfE8PaV2+EgbwVaSlZ9gH6VYorBN2MT4I9xypQAYzoyrNN0oV/Q92Xiyb3WejKuy74xFEg==", + "version": "1.56.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.56.0.tgz", + "integrity": "sha512-NE6A0YasZoHsGwdhzN3/8qsVl7pQHy6qMxjGyGH1MIfJV96ZwR5/3hQSVyWrom+bHsZBUPMgBemImZSX/cdqew==", "dev": true, "requires": { "@carbon/colors": "^11.21.0", diff --git a/package.json b/package.json index 442be49461..a5aaab07fe 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@angular/common": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "@angular/core": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "@angular/forms": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", - "@carbon/styles": "^1.54.0", + "@carbon/styles": "^1.56.0", "rxjs": "^6.0.0 || ^7.0.0", "zone.js": "^0.11.0" }, @@ -85,7 +85,7 @@ "@angular/platform-browser-dynamic": "14.3.0", "@angular/router": "14.3.0", "@babel/core": "7.9.6", - "@carbon/styles": "1.54.0", + "@carbon/styles": "1.56.0", "@carbon/themes": "11.24.0", "@commitlint/cli": "17.0.3", "@commitlint/config-conventional": "17.0.3", From 6e5724dc01612df5323e98d96d9cbf5474bb5bf4 Mon Sep 17 00:00:00 2001 From: Akshat Patel Date: Tue, 21 May 2024 15:50:01 -0400 Subject: [PATCH 3/9] fix: simply content projection by toggling type attribute Signed-off-by: Akshat Patel --- src/input/input.module.ts | 6 +- src/input/password-input-label.component.ts | 248 ++++++++------------ src/input/password.directive.ts | 54 +++-- src/input/password.stories.ts | 69 ++---- 4 files changed, 172 insertions(+), 205 deletions(-) diff --git a/src/input/input.module.ts b/src/input/input.module.ts index 9285dc8903..141799fa45 100644 --- a/src/input/input.module.ts +++ b/src/input/input.module.ts @@ -12,6 +12,8 @@ import { TextInputLabelComponent } from "./text-input-label.component"; import { IconModule } from "carbon-components-angular/icon"; import { PasswordInput } from "./password.directive"; import { PasswordInputLabelComponent } from "./password-input-label.component"; +import { TooltipModule } from "carbon-components-angular/tooltip"; +import { ButtonModule } from "carbon-components-angular/button"; @NgModule({ declarations: [ @@ -35,7 +37,9 @@ import { PasswordInputLabelComponent } from "./password-input-label.component"; imports: [ CommonModule, FormsModule, - IconModule + IconModule, + ButtonModule, + TooltipModule ] }) export class InputModule { } diff --git a/src/input/password-input-label.component.ts b/src/input/password-input-label.component.ts index 761e3c0f7c..c56f7fd86e 100644 --- a/src/input/password-input-label.component.ts +++ b/src/input/password-input-label.component.ts @@ -6,8 +6,11 @@ import { HostBinding, TemplateRef, ViewChild, - ChangeDetectorRef + ChangeDetectorRef, + ContentChild } from "@angular/core"; +import { PasswordInput } from "./password.directive"; +import { BaseIconButton } from "../button"; /** * Get started with importing the module: @@ -19,8 +22,7 @@ import { * ```html * * Label - * - * + * * * ``` * @@ -29,142 +31,113 @@ import { @Component({ selector: "cds-password-label, ibm-password-label", template: ` - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- {{ helperText }} - -
- -
- {{ invalidText }} - -
- -
- {{ warnText }} - -
+ + +
+
+ + + + + + +
+ +
+
+
+
+ {{ helperText }} + +
+ +
+ {{ invalidText }} + +
+ +
+ {{ warnText }} + +
+
` }) /** * Represents the Password Input Label Component. */ -export class PasswordInputLabelComponent implements AfterViewInit { +export class PasswordInputLabelComponent extends BaseIconButton implements AfterViewInit { /** - * Getter for generating classes for password visibility toggle. + * Counter for generating unique labelInputID. */ - get passwordVisibilityToggleClasses(): string { - return [ - "cds--text-input--password__visibility__toggle", - "cds--btn", - "cds--btn--icon-only", - "cds--tooltip__trigger", - "cds--tooltip--a11y", - this.disabled ? "cds--btn--disabled" : "", - this.tooltipPosition ? `cds--tooltip--${this.tooltipPosition}` : "", - this.tooltipAlignment - ? `cds--tooltip--align-${this.tooltipAlignment}` - : "" - ].join(" "); - } + static labelCounter = 0; - /** - * Getter for checking if password is visible. - */ - get passwordIsVisible() { - return this.inputType === "text"; - } + @ContentChild(PasswordInput) textInput: PasswordInput; /** - * Counter for generating unique labelInputID. + * ID for the input item associated with the label. */ - static labelCounter = 0; + @Input() labelInputID = "cds-password-input-" + PasswordInputLabelComponent.labelCounter++; + /** * Type for input field, either password or text. */ inputType: "password" | "text" = "password"; /** - * ID for the input item associated with the label. - */ - @Input() labelInputID = - "ibm-password-input-" + PasswordInputLabelComponent.labelCounter++; + * Flag for checking if password is visible. + */ + passwordIsVisible = false; /** * Flag for disabled label. @@ -226,36 +199,28 @@ export class PasswordInputLabelComponent implements AfterViewInit { */ @Input() showPasswordLabel = "Show password"; - /** - * Alignment of the tooltip to the icon-only button. - */ - @Input() tooltipPosition: "top" | "right" | "bottom" | "left" = "bottom"; - - /** - * Direction of the tooltip for icon-only buttons. - */ - @Input() tooltipAlignment: "start" | "center" | "end" = "center"; - /** * Reference to the wrapper element. - * @ts-ignore */ - @ViewChild("wrapper", { static: false }) - wrapper: ElementRef; + @ViewChild("wrapper") wrapper: ElementRef; /** * Binding for applying class to host element. */ @HostBinding("class.cds--form-item") labelClass = true; + @HostBinding("class.cds--password-input-wrapper") passwordInputWrapper = true; + @HostBinding("class.cds--text-input-wrapper") textInputWrapper = true; /** * Constructor for PasswordInputLabelComponent. * @param changeDetectorRef - Reference to ChangeDetectorRef. */ - constructor(protected changeDetectorRef: ChangeDetectorRef) { } + constructor(protected changeDetectorRef: ChangeDetectorRef) { + super(); + } /** - * Lifecycle hook called after the view has been initialized. + * Lifecycle hook called after the view has been initialized to set the ID of the input element */ ngAfterViewInit() { if (this.wrapper) { @@ -269,15 +234,6 @@ export class PasswordInputLabelComponent implements AfterViewInit { inputElement.setAttribute("id", this.labelInputID); return; } - - const divElement = this.wrapper.nativeElement.querySelector("div"); - if (divElement) { - if (divElement.id) { - this.labelInputID = divElement.id; - this.changeDetectorRef.detectChanges(); - } - divElement.setAttribute("id", this.labelInputID); - } } } @@ -295,5 +251,7 @@ export class PasswordInputLabelComponent implements AfterViewInit { */ public handleTogglePasswordVisibility() { this.inputType = this.inputType === "password" ? "text" : "password"; + this.textInput.type = this.inputType; + this.passwordIsVisible = this.inputType === "text"; } } diff --git a/src/input/password.directive.ts b/src/input/password.directive.ts index e5e9a5aa22..b7305e2c8b 100644 --- a/src/input/password.directive.ts +++ b/src/input/password.directive.ts @@ -1,21 +1,25 @@ -import { Directive, HostBinding, Input } from "@angular/core"; +import { + Directive, + HostBinding, + Input, + Renderer2, + ElementRef, + AfterViewInit +} from "@angular/core"; @Directive({ selector: "[cdsPassword], [ibmPassword]" }) -export class PasswordInput { - /** - * @deprecated since v5 - Use `cdsLayer` directive instead - * `light` or `dark` input theme - */ - @Input() theme: "light" | "dark" = "dark"; - - /** - * Input field render size - */ - @Input() size: "sm" | "md" | "lg" = "md"; +export class PasswordInput implements AfterViewInit { - @HostBinding("class.cds--text-input") inputClass = true; + @Input() set type(type: string) { + if (type) { + this._type = type; + if (this.elementRef) { + this.renderer.setAttribute(this.elementRef.nativeElement, "type", this._type); + } + } + } @HostBinding("class.cds--password-input") passwordInputClass = true; /** @@ -41,11 +45,31 @@ export class PasswordInput { @HostBinding("class.cds--layout--size-lg") get sizelg() { return this.size === "lg"; } + @HostBinding("class.cds--text-input--light") get isLightTheme() { + return this.theme === "light"; + } + @HostBinding("class.cds--text-input") inputClass = true; @HostBinding("class.cds--text-input--invalid") @Input() invalid = false; @HostBinding("class.cds--text-input__field-wrapper--warning") @Input() warn = false; @HostBinding("class.cds--skeleton") @Input() skeleton = false; - @HostBinding("class.cds--text-input--light") get isLightTheme() { - return this.theme === "light"; + + /** + * @deprecated since v5 - Use `cdsLayer` directive instead + * `light` or `dark` input theme + */ + @Input() theme: "light" | "dark" = "dark"; + + /** + * Input field render size + */ + @Input() size: "sm" | "md" | "lg" = "md"; + + private _type = "password"; + + constructor(protected elementRef: ElementRef, protected renderer: Renderer2) { } + + ngAfterViewInit(): void { + this.renderer.setAttribute(this.elementRef.nativeElement, "type", this._type); } } diff --git a/src/input/password.stories.ts b/src/input/password.stories.ts index 136c8e5759..fe32995e88 100644 --- a/src/input/password.stories.ts +++ b/src/input/password.stories.ts @@ -17,41 +17,26 @@ export default { const Template = (args) => ({ props: args, template: ` - - {{ label }} - - - - ` + + {{ label }} + + + ` }); export const Basic = Template.bind({}); Basic.args = { @@ -65,8 +50,7 @@ Basic.args = { placeholder: "Placeholder", autocomplete: "on", theme: "dark", - size: "md", - value: "" + size: "md" }; Basic.argTypes = { autocomplete: { @@ -86,12 +70,9 @@ Basic.argTypes = { const SkeletonTemplate = (args) => ({ props: args, template: ` - - - - -
- - ` + + + + ` }); export const Skeleton = SkeletonTemplate.bind({}); From cf41d99b21d695a6043598fa18e34e5c20a43344 Mon Sep 17 00:00:00 2001 From: Akshat Patel Date: Tue, 21 May 2024 15:54:58 -0400 Subject: [PATCH 4/9] fix: import button from carbon-components-angular Signed-off-by: Akshat Patel --- src/input/password-input-label.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/password-input-label.component.ts b/src/input/password-input-label.component.ts index c56f7fd86e..4bf692aa93 100644 --- a/src/input/password-input-label.component.ts +++ b/src/input/password-input-label.component.ts @@ -10,7 +10,7 @@ import { ContentChild } from "@angular/core"; import { PasswordInput } from "./password.directive"; -import { BaseIconButton } from "../button"; +import { BaseIconButton } from "carbon-components-angular/button"; /** * Get started with importing the module: From e47d3296d09ba8eced429f769939756045b9fd6c Mon Sep 17 00:00:00 2001 From: Akshat Patel Date: Tue, 21 May 2024 16:46:18 -0400 Subject: [PATCH 5/9] chore: lint fix Signed-off-by: Akshat Patel --- src/input/label.component.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/input/label.component.ts b/src/input/label.component.ts index 6fb76a55e2..b5f74d327e 100644 --- a/src/input/label.component.ts +++ b/src/input/label.component.ts @@ -87,8 +87,7 @@ import { PasswordInput } from "./password.directive"; [warnText]="warnText" [ariaLabel]="ariaLabel" [labelTemplate]="labelContentTemplate" - [passwordInputTemplate]="inputContentTemplate" - > + [passwordInputTemplate]="inputContentTemplate"> @@ -119,13 +118,13 @@ import { PasswordInput } from "./password.directive"; cdsIcon="warning--filled" size="16" class="cds--text-input__invalid-icon"> - + - +
Date: Tue, 21 May 2024 19:35:11 -0400 Subject: [PATCH 6/9] test: add password input tests Signed-off-by: Akshat Patel --- src/input/password.spec.ts | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/input/password.spec.ts diff --git a/src/input/password.spec.ts b/src/input/password.spec.ts new file mode 100644 index 0000000000..7d55577fd4 --- /dev/null +++ b/src/input/password.spec.ts @@ -0,0 +1,57 @@ +import { TestBed, ComponentFixture } from "@angular/core/testing"; +import { Component, DebugElement } from "@angular/core"; +import { By } from "@angular/platform-browser"; + +import { PasswordInputLabelComponent, PasswordInput } from "./"; +import { Tooltip } from "../tooltip"; + +@Component({ + template: ` + + Password + + + ` +}) +class TestPasswordInputComponent {} + +fdescribe("Password", () => { + let fixture: ComponentFixture; + let component: TestPasswordInputComponent; + let passwordEl: DebugElement; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [PasswordInputLabelComponent, PasswordInput, Tooltip, TestPasswordInputComponent] + }); + fixture = TestBed.createComponent(TestPasswordInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + passwordEl = fixture.debugElement.query(By.css("cds-password-label")); + }); + + it("should create a password component", () => { + expect(component).toBeTruthy(); + expect(passwordEl).not.toBeNull(); + }); + + it("should assign wrapper classes to the host element", () => { + expect(passwordEl.nativeElement.classList.contains("cds--form-item")).toBeTruthy(); + expect(passwordEl.nativeElement.classList.contains("cds--password-input-wrapper")).toBeTruthy(); + expect(passwordEl.nativeElement.classList.contains("cds--text-input-wrapper")).toBeTruthy(); + }); + + it("should set initial input type to 'password'", () => { + expect(passwordEl.nativeElement.querySelector("input[type='password']")).not.toBeNull(); + }); + + it("should set input type to 'text' when toggle button is clicked", () => { + const visibilityToggleButton = passwordEl.nativeElement.querySelector("button.cds--text-input--password__visibility__toggle"); + visibilityToggleButton.click(); + fixture.detectChanges(); + expect(passwordEl.nativeElement.querySelector("input[type='password']")).toBeNull(); + expect(passwordEl.nativeElement.querySelector("input[type='text']")).not.toBeNull(); + }); +}); From 508cde48d57aac3efd0b09490e43b39fbd0693f5 Mon Sep 17 00:00:00 2001 From: Akshat Patel <38994122+Akshat55@users.noreply.github.com> Date: Thu, 23 May 2024 11:38:48 -0400 Subject: [PATCH 7/9] chore: lint template --- src/input/password-input-label.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/input/password-input-label.component.ts b/src/input/password-input-label.component.ts index 4bf692aa93..bbea32024d 100644 --- a/src/input/password-input-label.component.ts +++ b/src/input/password-input-label.component.ts @@ -38,8 +38,7 @@ import { BaseIconButton } from "carbon-components-angular/button"; [ngClass]="{ 'cds--label--disabled': disabled, 'cds--skeleton': skeleton - }" - > + }"> From f34747caa578ad104946d96089797ee9244489cc Mon Sep 17 00:00:00 2001 From: Akshat Patel <38994122+Akshat55@users.noreply.github.com> Date: Thu, 23 May 2024 11:38:55 -0400 Subject: [PATCH 8/9] chore: lint template --- src/input/password-input-label.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/input/password-input-label.component.ts b/src/input/password-input-label.component.ts index bbea32024d..6b86894665 100644 --- a/src/input/password-input-label.component.ts +++ b/src/input/password-input-label.component.ts @@ -115,7 +115,6 @@ import { BaseIconButton } from "carbon-components-angular/button"; * Represents the Password Input Label Component. */ export class PasswordInputLabelComponent extends BaseIconButton implements AfterViewInit { - /** * Counter for generating unique labelInputID. */ From 4e06becd7a91481720168f441104fbce4201f092 Mon Sep 17 00:00:00 2001 From: Zvonimir Fras Date: Thu, 23 May 2024 16:35:48 -0400 Subject: [PATCH 9/9] Lint a little --- src/input/password.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/input/password.spec.ts b/src/input/password.spec.ts index 7d55577fd4..f954b17317 100644 --- a/src/input/password.spec.ts +++ b/src/input/password.spec.ts @@ -9,9 +9,7 @@ import { Tooltip } from "../tooltip"; template: ` Password - + ` })