Skip to content

Commit

Permalink
fix(material/form-field): Don't allow label to grow larger than input
Browse files Browse the repository at this point in the history
Fixes #26558
  • Loading branch information
mmalerba committed Aug 30, 2024
1 parent 3bf0e31 commit bc82412
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 71 deletions.
95 changes: 48 additions & 47 deletions src/material/form-field/_mdc-text-field-structure.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

// Includes the structural styles for the form field inherited from MDC.
@mixin private-text-field-structure {
$filled-slots: (tokens-mdc-filled-text-field.$prefix,
tokens-mdc-filled-text-field.get-token-slots());
$outlined-slots: (tokens-mdc-outlined-text-field.$prefix,
tokens-mdc-outlined-text-field.get-token-slots());
$filled-slots: (
tokens-mdc-filled-text-field.$prefix,
tokens-mdc-filled-text-field.get-token-slots()
);
$outlined-slots: (
tokens-mdc-outlined-text-field.$prefix,
tokens-mdc-outlined-text-field.get-token-slots()
);

.mdc-text-field {
display: inline-flex;
Expand Down Expand Up @@ -130,19 +134,15 @@
.mdc-text-field--outlined {
height: 56px;
overflow: visible;
padding-left: 16px;
padding-right: 16px;

@include _supports-max {
@include token-utils.use-tokens($outlined-slots...) {
$shape-var: token-utils.get-token-variable(container-shape);
padding-right: max(16px, #{$shape-var});
padding-left: max(16px, calc(#{$shape-var} + 4px));
@include token-utils.use-tokens($outlined-slots...) {
$shape-var: token-utils.get-token-variable(container-shape);
padding-right: max(16px, #{$shape-var});
padding-left: max(16px, calc(#{$shape-var} + 4px));

[dir='rtl'] & {
padding-right: max(16px, calc(#{$shape-var} + 4px));
padding-left: max(16px, #{$shape-var});
}
[dir='rtl'] & {
padding-right: max(16px, calc(#{$shape-var} + 4px));
padding-left: max(16px, #{$shape-var});
}
}
}
Expand Down Expand Up @@ -342,17 +342,14 @@
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
width: 12px;

@include token-utils.use-tokens($outlined-slots...) {
@include token-utils.create-token-slot(border-top-left-radius, container-shape);
@include token-utils.create-token-slot(border-bottom-left-radius, container-shape);

@include _supports-max {
.mdc-text-field--outlined .mdc-notched-outline & {
$shape-var: token-utils.get-token-variable(container-shape);
width: max(12px, #{$shape-var});
}
.mdc-text-field--outlined .mdc-notched-outline & {
$shape-var: token-utils.get-token-variable(container-shape);
width: max(12px, #{$shape-var});
}
}

Expand Down Expand Up @@ -397,14 +394,14 @@
.mdc-notched-outline__notch {
flex: 0 0 auto;
width: auto;
max-width: calc(100% - 24px);

@include token-utils.use-tokens($outlined-slots...) {
@include _supports-max {
.mdc-text-field--outlined .mdc-notched-outline & {
$shape-var: token-utils.get-token-variable(container-shape);
max-width: calc(100% - max(12px, #{$shape-var}) * 2);
}
.mdc-text-field--outlined .mdc-notched-outline & {
$shape-var: token-utils.get-token-variable(container-shape);
max-width: min(
var(--mat-form-field-notch-max-width, 100%),
calc(100% - max(12px, #{$shape-var}) * 2)
);
}
}

Expand Down Expand Up @@ -433,7 +430,8 @@
}

.mdc-line-ripple {
&::before, &::after {
&::before,
&::after {
position: absolute;
bottom: 0;
left: 0;
Expand All @@ -459,17 +457,21 @@
}

.mdc-text-field--filled.mdc-text-field--disabled & {
@include token-utils.create-token-slot(border-bottom-color,
disabled-active-indicator-color);
@include token-utils.create-token-slot(
border-bottom-color,
disabled-active-indicator-color
);
}

#{$enabled-field}.mdc-text-field--invalid & {
@include token-utils.create-token-slot(border-bottom-color, error-active-indicator-color);
}

#{$enabled-field}.mdc-text-field--invalid:not(.mdc-text-field--focused):hover & {
@include token-utils.create-token-slot(border-bottom-color,
error-hover-active-indicator-color);
@include token-utils.create-token-slot(
border-bottom-color,
error-hover-active-indicator-color
);
}
}
}
Expand All @@ -481,17 +483,21 @@

@include token-utils.use-tokens($filled-slots...) {
.mdc-text-field--filled & {
@include token-utils.create-token-slot(border-bottom-width,
focus-active-indicator-height);
@include token-utils.create-token-slot(
border-bottom-width,
focus-active-indicator-height
);
}

.mdc-text-field--filled:not(.mdc-text-field--disabled) & {
@include token-utils.create-token-slot(border-bottom-color, focus-active-indicator-color);
}

.mdc-text-field--filled.mdc-text-field--invalid:not(.mdc-text-field--disabled) & {
@include token-utils.create-token-slot(border-bottom-color,
error-focus-active-indicator-color);
@include token-utils.create-token-slot(
border-bottom-color,
error-focus-active-indicator-color
);
}
}
}
Expand Down Expand Up @@ -571,21 +577,14 @@
}
}

// Wraps the content in a `@supports` query targeting the `max` CSS function.
@mixin _supports-max {
// stylelint-disable material/no-prefixes
@supports (top: max(0%)) {
@content;
}
// stylelint-enable
}

// Includes the animation styles for the form field inherited from MDC.
@mixin private-text-field-animations {
$timing-curve: cubic-bezier(0.4, 0, 0.2, 1);

.mdc-floating-label {
transition: transform 150ms $timing-curve, color 150ms $timing-curve;
transition:
transform 150ms $timing-curve,
color 150ms $timing-curve;
}

.mdc-text-field__input {
Expand All @@ -611,6 +610,8 @@
}

.mdc-line-ripple::after {
transition: transform 180ms $timing-curve, opacity 180ms $timing-curve;
transition:
transform 180ms $timing-curve,
opacity 180ms $timing-curve;
}
}
57 changes: 33 additions & 24 deletions src/material/form-field/form-field.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,39 @@
simply link the label to the control using the label `for` attribute.
-->
@if (_hasFloatingLabel()) {
<label matFormFieldFloatingLabel
[floating]="_shouldLabelFloat()"
[monitorResize]="_hasOutline()"
[id]="_labelId"
[attr.for]="_control.disableAutomaticLabeling ? null : _control.id">
<label
matFormFieldFloatingLabel
[floating]="_shouldLabelFloat()"
[monitorResize]="_hasOutline()"
[id]="_labelId"
[attr.for]="_control.disableAutomaticLabeling ? null : _control.id"
>
<ng-content select="mat-label"></ng-content>
<!--
We set the required marker as a separate element, in order to make it easier to target if
apps want to override it and to be able to set `aria-hidden` so that screen readers don't
pick it up.
-->
@if (!hideRequiredMarker && _control.required) {
<span
aria-hidden="true"
class="mat-mdc-form-field-required-marker mdc-floating-label--required"></span>
}
@if (!hideRequiredMarker && _control.required) {
<span
aria-hidden="true"
class="mat-mdc-form-field-required-marker mdc-floating-label--required"
></span>
}
</label>
}
</ng-template>

<div class="mat-mdc-text-field-wrapper mdc-text-field" #textField
[class.mdc-text-field--filled]="!_hasOutline()"
[class.mdc-text-field--outlined]="_hasOutline()"
[class.mdc-text-field--no-label]="!_hasFloatingLabel()"
[class.mdc-text-field--disabled]="_control.disabled"
[class.mdc-text-field--invalid]="_control.errorState"
(click)="_control.onContainerClick($event)">
<div
class="mat-mdc-text-field-wrapper mdc-text-field"
#textField
[class.mdc-text-field--filled]="!_hasOutline()"
[class.mdc-text-field--outlined]="_hasOutline()"
[class.mdc-text-field--no-label]="!_hasFloatingLabel()"
[class.mdc-text-field--disabled]="_control.disabled"
[class.mdc-text-field--invalid]="_control.errorState"
(click)="_control.onContainerClick($event)"
>
@if (!_hasOutline() && !_control.disabled) {
<div class="mat-mdc-form-field-focus-overlay"></div>
}
Expand Down Expand Up @@ -72,13 +78,13 @@
</div>

@if (_hasTextSuffix) {
<div class="mat-mdc-form-field-text-suffix">
<div class="mat-mdc-form-field-text-suffix" #textSuffixContainer>
<ng-content select="[matTextSuffix]"></ng-content>
</div>
}

@if (_hasIconSuffix) {
<div class="mat-mdc-form-field-icon-suffix">
<div class="mat-mdc-form-field-icon-suffix" #iconSuffixContainer>
<ng-content select="[matSuffix], [matIconSuffix]"></ng-content>
</div>
}
Expand All @@ -89,13 +95,16 @@
}
</div>

<div class="mat-mdc-form-field-subscript-wrapper mat-mdc-form-field-bottom-align"
[class.mat-mdc-form-field-subscript-dynamic-size]="subscriptSizing === 'dynamic'">

<div
class="mat-mdc-form-field-subscript-wrapper mat-mdc-form-field-bottom-align"
[class.mat-mdc-form-field-subscript-dynamic-size]="subscriptSizing === 'dynamic'"
>
@switch (_getDisplayedMessages()) {
@case ('error') {
<div class="mat-mdc-form-field-error-wrapper"
[@transitionMessages]="_subscriptAnimationState">
<div
class="mat-mdc-form-field-error-wrapper"
[@transitionMessages]="_subscriptAnimationState"
>
<ng-content select="mat-error, [matError]"></ng-content>
</div>
}
Expand Down
16 changes: 16 additions & 0 deletions src/material/form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ export class MatFormField
@ViewChild('textField') _textField: ElementRef<HTMLElement>;
@ViewChild('iconPrefixContainer') _iconPrefixContainer: ElementRef<HTMLElement>;
@ViewChild('textPrefixContainer') _textPrefixContainer: ElementRef<HTMLElement>;
@ViewChild('iconSuffixContainer') _iconSuffixContainer: ElementRef<HTMLElement>;
@ViewChild('textSuffixContainer') _textSuffixContainer: ElementRef<HTMLElement>;
@ViewChild(MatFormFieldFloatingLabel) _floatingLabel: MatFormFieldFloatingLabel | undefined;
@ViewChild(MatFormFieldNotchedOutline) _notchedOutline: MatFormFieldNotchedOutline | undefined;
@ViewChild(MatFormFieldLineRipple) _lineRipple: MatFormFieldLineRipple | undefined;
Expand Down Expand Up @@ -708,8 +710,12 @@ export class MatFormField
}
const iconPrefixContainer = this._iconPrefixContainer?.nativeElement;
const textPrefixContainer = this._textPrefixContainer?.nativeElement;
const iconSuffixContainer = this._iconSuffixContainer?.nativeElement;
const textSuffixContainer = this._textSuffixContainer?.nativeElement;
const iconPrefixContainerWidth = iconPrefixContainer?.getBoundingClientRect().width ?? 0;
const textPrefixContainerWidth = textPrefixContainer?.getBoundingClientRect().width ?? 0;
const iconSuffixContainerWidth = iconSuffixContainer?.getBoundingClientRect().width ?? 0;
const textSuffixContainerWidth = textSuffixContainer?.getBoundingClientRect().width ?? 0;
// If the directionality is RTL, the x-axis transform needs to be inverted. This
// is because `transformX` does not change based on the page directionality.
const negate = this._dir.value === 'rtl' ? '-1' : '1';
Expand All @@ -724,6 +730,16 @@ export class MatFormField
--mat-mdc-form-field-label-transform,
${FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM} translateX(${labelHorizontalOffset})
)`;

const prefixAndSuffixWidth =
iconPrefixContainerWidth +
textPrefixContainerWidth +
iconSuffixContainerWidth +
textSuffixContainerWidth;
this._elementRef.nativeElement.style.setProperty(
'--mat-form-field-notch-max-width',
`calc(100% - ${prefixAndSuffixWidth}px)`,
);
}

/** Checks whether the form field is attached to the DOM. */
Expand Down

0 comments on commit bc82412

Please sign in to comment.