Skip to content

Commit f389864

Browse files
feat(text-field): add CR fixes #71
1 parent 5f03802 commit f389864

5 files changed

Lines changed: 82 additions & 54 deletions

File tree

tedi/components/form/form-field/form-field.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<ng-content select="label[tedi-label]"></ng-content>
22

3-
<div [ngClass]="classes()">
3+
<div [ngClass]="inputClasses()">
44
<ng-content select="input[tedi-text-field]"></ng-content>
55

66
@if (showClearButton()) {

tedi/components/form/form-field/form-field.component.scss

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,85 @@
11
.tedi-form-field {
2-
position: relative;
32
display: flex;
4-
gap: var(--form-field-inner-spacing);
5-
align-items: center;
6-
width: 100%;
7-
height: var(--form-field-height);
8-
background: var(--form-input-background-default);
9-
border: 1px solid var(--form-input-border-default);
10-
border-radius: var(--form-field-radius);
3+
flex-direction: column;
114

12-
&:not(
13-
.tedi-form-field--disabled,
14-
.tedi-form-field--valid,
15-
.tedi-form-field--invalid
16-
) {
17-
&:hover,
18-
&:has(input:hover) {
19-
border-color: var(--form-input-border-hover);
20-
}
5+
&__input {
6+
position: relative;
7+
display: flex;
8+
gap: var(--form-field-inner-spacing);
9+
align-items: center;
10+
width: 100%;
11+
height: var(--form-field-height);
12+
background: var(--form-input-background-default);
13+
border: 1px solid var(--form-input-border-default);
14+
border-radius: var(--form-field-radius);
15+
}
2116

22-
&:active,
23-
&:has(input:active) {
24-
border-color: var(--form-input-border-active);
25-
box-shadow: 0 0 0 1px var(--form-input-border-active);
17+
&--small {
18+
.tedi-label {
19+
font-size: var(--body-small-regular-size);
2620
}
2721

28-
&:focus-within,
29-
&:has(input:focus-visible) {
30-
border-color: var(--form-input-border-focus);
31-
box-shadow: 0 0 0 1px var(--form-input-border-focus);
22+
.tedi-form-field__input {
23+
height: var(--form-field-height-sm);
3224
}
3325
}
3426

35-
&.tedi-form-field--valid {
27+
&--large .tedi-form-field__input {
28+
height: var(--form-field-height-lg);
29+
}
30+
31+
&--valid .tedi-form-field__input {
3632
border-color: var(--form-general-feedback-success-border);
3733

3834
&:focus-within {
3935
box-shadow: 0 0 0 1px var(--form-general-feedback-success-border);
4036
}
4137
}
4238

43-
&.tedi-form-field--invalid {
39+
&--invalid .tedi-form-field__input {
4440
border-color: var(--form-general-feedback-error-border);
4541

4642
&:focus-within {
4743
box-shadow: 0 0 0 1px var(--form-general-feedback-error-border);
4844
}
4945
}
5046

51-
&.tedi-form-field--disabled {
47+
&--disabled .tedi-form-field__input {
5248
cursor: not-allowed;
5349
background: var(--form-input-background-disabled);
5450
border-color: var(--form-input-border-disabled);
5551
box-shadow: none;
5652
}
5753

58-
&--small {
59-
height: var(--form-field-height-sm);
54+
&--with-icon .tedi-form-field__input {
55+
padding-right: var(--form-field-padding-x-md-default);
6056
}
6157

62-
&--large {
63-
height: var(--form-field-height-lg);
58+
&--with-icon.tedi-form-field--large .tedi-form-field__input {
59+
padding-right: var(--form-field-padding-x-lg);
6460
}
6561

66-
&--with-icon {
67-
padding-right: var(--form-field-padding-x-md-default);
62+
&:not(
63+
.tedi-form-field--disabled,
64+
.tedi-form-field--valid,
65+
.tedi-form-field--invalid
66+
)
67+
.tedi-form-field__input {
68+
&:hover,
69+
&:has(input:hover) {
70+
border-color: var(--form-input-border-hover);
71+
}
6872

69-
&.tedi-form-field--large {
70-
padding-right: var(--form-field-padding-x-lg);
73+
&:active,
74+
&:has(input:active) {
75+
border-color: var(--form-input-border-active);
76+
box-shadow: 0 0 0 1px var(--form-input-border-active);
77+
}
78+
79+
&:focus-within,
80+
&:has(input:focus-visible) {
81+
border-color: var(--form-input-border-focus);
82+
box-shadow: 0 0 0 1px var(--form-input-border-focus);
7183
}
7284
}
7385

tedi/components/form/form-field/form-field.component.spec.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import {
99
TEDI_FORM_FIELD_CONTROL,
1010
FormFieldControl,
1111
} from "./form-field-control";
12-
import {
13-
FeedbackTextComponent,
14-
} from "../feedback-text/feedback-text.component";
12+
import { FeedbackTextComponent } from "../feedback-text/feedback-text.component";
1513

1614
@Component({
1715
selector: "mock-control",
@@ -47,7 +45,7 @@ export class MockFeedbackComponent extends FeedbackTextComponent {}
4745
[size]="size"
4846
[icon]="icon"
4947
[clearable]="clearable"
50-
[containerClass]="containerClass"
48+
[inputClass]="inputClass"
5149
>
5250
<mock-control #mockControl></mock-control>
5351
<tedi-feedback-text
@@ -67,7 +65,7 @@ class TestHostComponent {
6765
size: InputSize = "default";
6866
icon?: string | FormFieldIcon;
6967
clearable = false;
70-
containerClass?: string;
68+
inputClass?: string;
7169
feedbackType: "valid" | "error" | "default" = "default";
7270
}
7371

@@ -95,7 +93,7 @@ describe("FormFieldComponent", () => {
9593
it("should apply small size class", () => {
9694
host.size = "small";
9795
fixture.detectChanges();
98-
expect(formField.classes()["tedi-form-field--small"]).toBe(true);
96+
expect(formField.hostClasses()["tedi-form-field--small"]).toBe(true);
9997
});
10098

10199
it("should resolve string icon to config object", () => {
@@ -165,10 +163,10 @@ describe("FormFieldComponent", () => {
165163
});
166164

167165
it("should apply custom class", () => {
168-
host.containerClass = "custom-class";
166+
host.inputClass = "custom-class";
169167
fixture.detectChanges();
170168

171-
const classes = formField.classes() as Record<string, boolean>;
169+
const classes = formField.inputClasses() as Record<string, boolean>;
172170
expect(classes["custom-class"]).toBe(true);
173171
});
174172
});

tedi/components/form/form-field/form-field.component.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { Component, computed, ContentChild, input } from "@angular/core";
1+
import {
2+
ChangeDetectionStrategy,
3+
Component,
4+
computed,
5+
ContentChild,
6+
input,
7+
ViewEncapsulation,
8+
} from "@angular/core";
29
import { NgClass } from "@angular/common";
310
import {
411
FormFieldControl,
@@ -33,13 +40,18 @@ export interface FormFieldIcon {
3340
standalone: true,
3441
templateUrl: "./form-field.component.html",
3542
styleUrl: "./form-field.component.scss",
43+
encapsulation: ViewEncapsulation.None,
44+
changeDetection: ChangeDetectionStrategy.OnPush,
3645
imports: [
3746
NgClass,
3847
IconComponent,
3948
ClosingButtonComponent,
4049
SeparatorComponent,
4150
TediTranslationPipe,
4251
],
52+
host: {
53+
"[class]": "hostClasses()",
54+
},
4355
})
4456
export class FormFieldComponent {
4557
/**
@@ -57,9 +69,9 @@ export class FormFieldComponent {
5769
*/
5870
clearable = input<boolean>(false);
5971
/**
60-
* Custom CSS classes for the container.
72+
* Custom CSS classes for the input.
6173
*/
62-
containerClass = input<string | null>(null);
74+
inputClass = input<string | null>(null);
6375

6476
@ContentChild(TEDI_FORM_FIELD_CONTROL)
6577
control?: FormFieldControl;
@@ -91,12 +103,9 @@ export class FormFieldComponent {
91103

92104
readonly isDisabled = computed(() => this.control?.disabled() ?? false);
93105

94-
readonly classes = computed(() => {
95-
const customClass = this.containerClass();
96-
106+
readonly hostClasses = computed(() => {
97107
return {
98108
"tedi-form-field": true,
99-
...(customClass ? { [customClass]: true } : {}),
100109
"tedi-form-field--valid": this.validationState() === "valid",
101110
"tedi-form-field--invalid": this.validationState() === "invalid",
102111
"tedi-form-field--disabled": this.control?.disabled(),
@@ -106,6 +115,15 @@ export class FormFieldComponent {
106115
};
107116
});
108117

118+
readonly inputClasses = computed(() => {
119+
const customClass = this.inputClass();
120+
121+
return {
122+
"tedi-form-field__input": true,
123+
...(customClass ? { [customClass]: true } : {}),
124+
};
125+
});
126+
109127
clear() {
110128
this.control?.clearField?.();
111129
}

tedi/components/form/text-field/text-field.stories.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ export default {
7171
defaultValue: { summary: "false" },
7272
},
7373
},
74-
containerClass: {
74+
inputClass: {
7575
control: "text",
76-
description: "Custom CSS classes for the container.",
76+
description: "Custom CSS classes for the input.",
7777
table: {
7878
category: "Form Field inputs",
7979
type: { summary: "string" },

0 commit comments

Comments
 (0)