Skip to content

Commit 6e5724d

Browse files
committed
fix: simply content projection by toggling type attribute
Signed-off-by: Akshat Patel <[email protected]>
1 parent 144f284 commit 6e5724d

File tree

4 files changed

+172
-205
lines changed

4 files changed

+172
-205
lines changed

src/input/input.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { TextInputLabelComponent } from "./text-input-label.component";
1212
import { IconModule } from "carbon-components-angular/icon";
1313
import { PasswordInput } from "./password.directive";
1414
import { PasswordInputLabelComponent } from "./password-input-label.component";
15+
import { TooltipModule } from "carbon-components-angular/tooltip";
16+
import { ButtonModule } from "carbon-components-angular/button";
1517

1618
@NgModule({
1719
declarations: [
@@ -35,7 +37,9 @@ import { PasswordInputLabelComponent } from "./password-input-label.component";
3537
imports: [
3638
CommonModule,
3739
FormsModule,
38-
IconModule
40+
IconModule,
41+
ButtonModule,
42+
TooltipModule
3943
]
4044
})
4145
export class InputModule { }

src/input/password-input-label.component.ts

Lines changed: 103 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import {
66
HostBinding,
77
TemplateRef,
88
ViewChild,
9-
ChangeDetectorRef
9+
ChangeDetectorRef,
10+
ContentChild
1011
} from "@angular/core";
12+
import { PasswordInput } from "./password.directive";
13+
import { BaseIconButton } from "../button";
1114

1215
/**
1316
* Get started with importing the module:
@@ -19,8 +22,7 @@ import {
1922
* ```html
2023
* <cds-password-label>
2124
* Label
22-
* <input cdsPassword type="text">
23-
* <input cdsPassword type="password">
25+
* <input cdsPassword>
2426
* </cds-password-label>
2527
* ```
2628
*
@@ -29,142 +31,113 @@ import {
2931
@Component({
3032
selector: "cds-password-label, ibm-password-label",
3133
template: `
32-
<label
33-
[for]="labelInputID"
34-
[attr.aria-label]="ariaLabel"
35-
class="cds--label"
36-
[ngClass]="{
37-
'cds--label--disabled': disabled,
38-
'cds--skeleton': skeleton
39-
}"
40-
>
41-
<ng-template *ngIf="labelTemplate; else labelContent" [ngTemplateOutlet]="labelTemplate"></ng-template>
42-
<ng-template #labelContent>
43-
<ng-content></ng-content>
44-
</ng-template>
45-
</label>
46-
47-
<div
48-
class="cds--text-input__field-wrapper"
49-
[ngClass]="{
50-
'cds--text-input__field-wrapper--warning': warn
51-
}"
52-
[attr.data-invalid]="invalid ? true : null"
53-
#wrapper
54-
>
55-
<svg *ngIf="!warn && invalid" cdsIcon="warning--filled" size="16" class="cds--text-input__invalid-icon"></svg>
56-
<svg
57-
*ngIf="!invalid && warn"
58-
cdsIcon="warning--alt--filled"
59-
size="16"
60-
class="cds--text-input__invalid-icon cds--text-input__invalid-icon--warning"
61-
></svg>
62-
63-
<ng-template *ngIf="passwordInputTemplate; else contentTemplate" [ngTemplateOutlet]="passwordInputTemplate"></ng-template>
64-
65-
<ng-template #passwordContent>
66-
<ng-content select="input[type=password]"></ng-content>
67-
</ng-template>
68-
69-
<ng-template #textContent>
70-
<ng-content select="input[type=text]"></ng-content>
71-
</ng-template>
72-
73-
<ng-template #contentTemplate>
74-
<ng-container
75-
*ngIf="inputType === 'password'; else textContent"
76-
>
77-
<ng-container
78-
*ngTemplateOutlet="passwordContent"
79-
></ng-container>
80-
</ng-container>
81-
</ng-template>
82-
83-
<button
84-
*ngIf="!skeleton"
85-
type="button"
86-
[ngClass]="passwordVisibilityToggleClasses"
87-
[disabled]="disabled"
88-
(click)="handleTogglePasswordVisibility()"
89-
>
90-
<ng-container *ngIf="!disabled">
91-
<span class="cds--assistive-text">
92-
{{
93-
passwordIsVisible
94-
? hidePasswordLabel
95-
: showPasswordLabel
96-
}}
97-
</span>
98-
</ng-container>
99-
<svg *ngIf="passwordIsVisible" cdsIcon="view--off" size="16"></svg>
100-
<svg *ngIf="!passwordIsVisible" cdsIcon="view" size="16"></svg>
101-
</button>
102-
</div>
103-
104-
<div
105-
*ngIf="!skeleton && helperText && !invalid && !warn"
106-
class="cds--form__helper-text"
107-
[ngClass]="{ 'cds--form__helper-text--disabled': disabled }"
108-
>
109-
<ng-container *ngIf="!isTemplate(helperText)">{{ helperText }}</ng-container>
110-
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
111-
</div>
112-
113-
<div *ngIf="!warn && invalid" class="cds--form-requirement">
114-
<ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container>
115-
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
116-
</div>
117-
118-
<div *ngIf="!invalid && warn" class="cds--form-requirement">
119-
<ng-container *ngIf="!isTemplate(warnText)">{{ warnText }}</ng-container>
120-
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
121-
</div>
34+
<label
35+
[for]="labelInputID"
36+
[attr.aria-label]="ariaLabel"
37+
class="cds--label"
38+
[ngClass]="{
39+
'cds--label--disabled': disabled,
40+
'cds--skeleton': skeleton
41+
}"
42+
>
43+
<ng-template *ngIf="labelTemplate; else labelContent" [ngTemplateOutlet]="labelTemplate"></ng-template>
44+
<ng-template #labelContent>
45+
<ng-content></ng-content>
46+
</ng-template>
47+
</label>
48+
49+
<div class="cds--text-input__field-outer-wrapper">
50+
<div
51+
class="cds--text-input__field-wrapper"
52+
[ngClass]="{
53+
'cds--text-input__field-wrapper--warning': warn
54+
}"
55+
[attr.data-invalid]="invalid ? true : null"
56+
#wrapper>
57+
<svg
58+
*ngIf="!warn && invalid"
59+
cdsIcon="warning--filled"
60+
size="16"
61+
class="cds--text-input__invalid-icon">
62+
</svg>
63+
<svg
64+
*ngIf="!invalid && warn"
65+
cdsIcon="warning--alt--filled"
66+
size="16"
67+
class="cds--text-input__invalid-icon cds--text-input__invalid-icon--warning">
68+
</svg>
69+
<ng-content select="[cdsPassword], [ibmPassword]"></ng-content>
70+
<cds-tooltip
71+
*ngIf="!skeleton"
72+
[description]="passwordIsVisible ? hidePasswordLabel : showPasswordLabel"
73+
[disabled]="disabled"
74+
[caret]="caret"
75+
[dropShadow]="dropShadow"
76+
[highContrast]="highContrast"
77+
[isOpen]="isOpen"
78+
[align]="align"
79+
[autoAlign]="autoAlign"
80+
[enterDelayMs]="enterDelayMs"
81+
[leaveDelayMs]="leaveDelayMs"
82+
class="cds--toggle-password-tooltip">
83+
<div class="cds--tooltip-trigger__wrapper">
84+
<button
85+
class="cds--text-input--password__visibility__toggle cds--btn cds--tooltip__trigger cds--tooltip--a11y"
86+
[disabled]="disabled"
87+
type="button"
88+
(click)="handleTogglePasswordVisibility($event)">
89+
<svg *ngIf="passwordIsVisible" cdsIcon="view--off" class="cds--icon-visibility-off" size="16"></svg>
90+
<svg *ngIf="!passwordIsVisible" cdsIcon="view" class="cds--icon-visibility-on" size="16"></svg>
91+
</button>
92+
</div>
93+
</cds-tooltip>
94+
</div>
95+
<div
96+
*ngIf="!skeleton && helperText && !invalid && !warn"
97+
class="cds--form__helper-text"
98+
[ngClass]="{ 'cds--form__helper-text--disabled': disabled }">
99+
<ng-container *ngIf="!isTemplate(helperText)">{{ helperText }}</ng-container>
100+
<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
101+
</div>
102+
103+
<div *ngIf="!warn && invalid" class="cds--form-requirement">
104+
<ng-container *ngIf="!isTemplate(invalidText)">{{ invalidText }}</ng-container>
105+
<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
106+
</div>
107+
108+
<div *ngIf="!invalid && warn" class="cds--form-requirement">
109+
<ng-container *ngIf="!isTemplate(warnText)">{{ warnText }}</ng-container>
110+
<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
111+
</div>
112+
</div>
122113
`
123114
})
124115
/**
125116
* Represents the Password Input Label Component.
126117
*/
127-
export class PasswordInputLabelComponent implements AfterViewInit {
118+
export class PasswordInputLabelComponent extends BaseIconButton implements AfterViewInit {
128119

129120
/**
130-
* Getter for generating classes for password visibility toggle.
121+
* Counter for generating unique labelInputID.
131122
*/
132-
get passwordVisibilityToggleClasses(): string {
133-
return [
134-
"cds--text-input--password__visibility__toggle",
135-
"cds--btn",
136-
"cds--btn--icon-only",
137-
"cds--tooltip__trigger",
138-
"cds--tooltip--a11y",
139-
this.disabled ? "cds--btn--disabled" : "",
140-
this.tooltipPosition ? `cds--tooltip--${this.tooltipPosition}` : "",
141-
this.tooltipAlignment
142-
? `cds--tooltip--align-${this.tooltipAlignment}`
143-
: ""
144-
].join(" ");
145-
}
123+
static labelCounter = 0;
146124

147-
/**
148-
* Getter for checking if password is visible.
149-
*/
150-
get passwordIsVisible() {
151-
return this.inputType === "text";
152-
}
125+
@ContentChild(PasswordInput) textInput: PasswordInput;
153126

154127
/**
155-
* Counter for generating unique labelInputID.
128+
* ID for the input item associated with the label.
156129
*/
157-
static labelCounter = 0;
130+
@Input() labelInputID = "cds-password-input-" + PasswordInputLabelComponent.labelCounter++;
131+
158132
/**
159133
* Type for input field, either password or text.
160134
*/
161135
inputType: "password" | "text" = "password";
162136

163137
/**
164-
* ID for the input item associated with the label.
165-
*/
166-
@Input() labelInputID =
167-
"ibm-password-input-" + PasswordInputLabelComponent.labelCounter++;
138+
* Flag for checking if password is visible.
139+
*/
140+
passwordIsVisible = false;
168141

169142
/**
170143
* Flag for disabled label.
@@ -226,36 +199,28 @@ export class PasswordInputLabelComponent implements AfterViewInit {
226199
*/
227200
@Input() showPasswordLabel = "Show password";
228201

229-
/**
230-
* Alignment of the tooltip to the icon-only button.
231-
*/
232-
@Input() tooltipPosition: "top" | "right" | "bottom" | "left" = "bottom";
233-
234-
/**
235-
* Direction of the tooltip for icon-only buttons.
236-
*/
237-
@Input() tooltipAlignment: "start" | "center" | "end" = "center";
238-
239202
/**
240203
* Reference to the wrapper element.
241-
* @ts-ignore
242204
*/
243-
@ViewChild("wrapper", { static: false })
244-
wrapper: ElementRef<HTMLDivElement>;
205+
@ViewChild("wrapper") wrapper: ElementRef<HTMLDivElement>;
245206

246207
/**
247208
* Binding for applying class to host element.
248209
*/
249210
@HostBinding("class.cds--form-item") labelClass = true;
211+
@HostBinding("class.cds--password-input-wrapper") passwordInputWrapper = true;
212+
@HostBinding("class.cds--text-input-wrapper") textInputWrapper = true;
250213

251214
/**
252215
* Constructor for PasswordInputLabelComponent.
253216
* @param changeDetectorRef - Reference to ChangeDetectorRef.
254217
*/
255-
constructor(protected changeDetectorRef: ChangeDetectorRef) { }
218+
constructor(protected changeDetectorRef: ChangeDetectorRef) {
219+
super();
220+
}
256221

257222
/**
258-
* Lifecycle hook called after the view has been initialized.
223+
* Lifecycle hook called after the view has been initialized to set the ID of the input element
259224
*/
260225
ngAfterViewInit() {
261226
if (this.wrapper) {
@@ -269,15 +234,6 @@ export class PasswordInputLabelComponent implements AfterViewInit {
269234
inputElement.setAttribute("id", this.labelInputID);
270235
return;
271236
}
272-
273-
const divElement = this.wrapper.nativeElement.querySelector("div");
274-
if (divElement) {
275-
if (divElement.id) {
276-
this.labelInputID = divElement.id;
277-
this.changeDetectorRef.detectChanges();
278-
}
279-
divElement.setAttribute("id", this.labelInputID);
280-
}
281237
}
282238
}
283239

@@ -295,5 +251,7 @@ export class PasswordInputLabelComponent implements AfterViewInit {
295251
*/
296252
public handleTogglePasswordVisibility() {
297253
this.inputType = this.inputType === "password" ? "text" : "password";
254+
this.textInput.type = this.inputType;
255+
this.passwordIsVisible = this.inputType === "text";
298256
}
299257
}

0 commit comments

Comments
 (0)