Skip to content

Commit

Permalink
fix(material-experimental/mdc-form-field): fix prefix/suffix padding
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalerba committed Mar 5, 2021
1 parent 7006b48 commit b80bb42
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,11 @@ $mat-form-field-with-label-input-padding-bottom: 8px;
// same reasoning applies to the padding for text fields without label.
$mat-form-field-no-label-padding-bottom: 16px;
$mat-form-field-no-label-padding-top: 16px;

// The amount of padding between the icon prefix/suffix and the infix.
// This assumes that the icon will be a 24px square with 12px padding.
$mat-form-field-icon-prefix-infix-padding: 4px;

// The amount of padding between the end of the form-field and the infix for a form-field with no
// icons.
$mat-form-field-end-padding: 16px;
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@
flex: auto;
}

// The icon prefix/suffix is closer to the edge of the form-field than the infix is in a
// form-field with no prefix/suffix. Therefore the standard padding has to be removed when showing
// an icon prefix or suffix. We can't rely on MDC's styles for this because we use a different
// structure for our form-field in order to support arbitrary height input elements.
.mat-mdc-form-field-has-icon-prefix .mat-mdc-text-field-wrapper {
padding-left: 0;
}
.mat-mdc-form-field-has-icon-suffix .mat-mdc-text-field-wrapper {
padding-right: 0;
}
[dir='rtl'] {
// Undo the above padding removals which only apply in LTR languages.
.mat-mdc-text-field-wrapper {
padding-left: form-field-sizing.$mat-form-field-end-padding;
padding-right: form-field-sizing.$mat-form-field-end-padding;
}
// ...and apply the correct padding resets for RTL languages.
.mat-mdc-form-field-has-icon-suffix .mat-mdc-text-field-wrapper {
padding-left: 0;
}
.mat-mdc-form-field-has-icon-prefix .mat-mdc-text-field-wrapper {
padding-right: 0;
}
}

// The default MDC text-field implementation does not support labels which always float.
// MDC only renders the placeholder if the input is focused. We extend this to show the
// placeholder if the form-field label is set to always float.
Expand Down
10 changes: 8 additions & 2 deletions src/material-experimental/mdc-form-field/directives/prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Directive, InjectionToken} from '@angular/core';
import {Directive, ElementRef, InjectionToken} from '@angular/core';

/**
* Injection token that can be used to reference instances of `MatPrefix`. It serves as
Expand All @@ -20,4 +20,10 @@ export const MAT_PREFIX = new InjectionToken<MatPrefix>('MatPrefix');
selector: '[matPrefix], [matIconPrefix], [matTextPrefix]',
providers: [{provide: MAT_PREFIX, useExisting: MatPrefix}],
})
export class MatPrefix {}
export class MatPrefix {
_isText = false;

constructor(elementRef: ElementRef) {
this._isText = elementRef.nativeElement.hasAttribute('matTextPrefix');
}
}
10 changes: 8 additions & 2 deletions src/material-experimental/mdc-form-field/directives/suffix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Directive, InjectionToken} from '@angular/core';
import {Directive, ElementRef, InjectionToken} from '@angular/core';

/**
* Injection token that can be used to reference instances of `MatSuffix`. It serves as
Expand All @@ -20,4 +20,10 @@ export const MAT_SUFFIX = new InjectionToken<MatSuffix>('MatSuffix');
selector: '[matSuffix], [matIconSuffix], [matTextSuffix]',
providers: [{provide: MAT_SUFFIX, useExisting: MatSuffix}],
})
export class MatSuffix {}
export class MatSuffix {
_isText = false;

constructor(elementRef: ElementRef) {
this._isText = elementRef.nativeElement.hasAttribute('matTextSuffix');
}
}
8 changes: 4 additions & 4 deletions src/material-experimental/mdc-form-field/form-field.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
</ng-template>
</div>

<div class="mat-mdc-form-field-icon-prefix" *ngIf="_prefixChildren.length" #iconPrefixContainer>
<div class="mat-mdc-form-field-icon-prefix" *ngIf="_hasIconPrefix" #iconPrefixContainer>
<ng-content select="[matPrefix], [matIconPrefix]"></ng-content>
</div>
<div class="mat-mdc-form-field-text-prefix" *ngIf="_prefixChildren.length" #textPrefixContainer>
<div class="mat-mdc-form-field-text-prefix" *ngIf="_hasTextPrefix" #textPrefixContainer>
<ng-content select="[matTextPrefix]"></ng-content>
</div>

Expand All @@ -59,10 +59,10 @@
<ng-content></ng-content>
</div>

<div class="mat-mdc-form-field-text-suffix" *ngIf="_suffixChildren.length">
<div class="mat-mdc-form-field-text-suffix" *ngIf="_hasTextSuffix">
<ng-content select="[matTextSuffix]"></ng-content>
</div>
<div class="mat-mdc-form-field-icon-suffix" *ngIf="_suffixChildren.length">
<div class="mat-mdc-form-field-icon-suffix" *ngIf="_hasIconSuffix">
<ng-content select="[matSuffix], [matIconSuffix]"></ng-content>
</div>
</div>
Expand Down
24 changes: 23 additions & 1 deletion src/material-experimental/mdc-form-field/form-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
@use '../mdc-helpers/mdc-helpers';
@import '@material/textfield/mixins.import';


// Base styles for MDC text-field, notched-outline, floating label and line-ripple.
@include mdc-text-field-without-ripple(
$query: mdc-helpers.$mat-base-styles-without-animation-query);
Expand Down Expand Up @@ -52,9 +51,32 @@
width: 100%;
}

// Vertically center icons.
.mat-mdc-form-field-icon-prefix,
.mat-mdc-form-field-icon-suffix {
align-self: center;
// The line-height can cause the prefix/suffix container to be taller than the actual icons,
// breaking the vertical centering. To prevent this we set the line-height to 0.
line-height: 0;
}

// The prefix/suffix needs a little extra padding between the icon and the infix. Because we need to
// support arbitrary height input elements, we use a different DOM structure for prefix and suffix
// icons, and therefore can't rely on MDC for these styles.
.mat-mdc-form-field-icon-prefix,
[dir='rtl'] .mat-mdc-form-field-icon-suffix {
padding: 0 form-field-sizing.$mat-form-field-icon-prefix-infix-padding 0 0;
}
.mat-mdc-form-field-icon-suffix,
[dir='rtl'] .mat-mdc-form-field-icon-prefix {
padding: 0 0 0 form-field-sizing.$mat-form-field-icon-prefix-infix-padding;
}

.mat-mdc-form-field-icon-prefix,
.mat-mdc-form-field-icon-suffix {
& > .mat-icon {
padding: 12px;
}
}

// Infix that contains the projected content (usually an input or a textarea). We ensure
Expand Down
34 changes: 28 additions & 6 deletions src/material-experimental/mdc-form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ const FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM = `translateY(-50%)`;
host: {
'class': 'mat-mdc-form-field',
'[class.mat-mdc-form-field-label-always-float]': '_shouldAlwaysFloat()',
'[class.mat-mdc-form-field-has-icon-prefix]': '_hasIconPrefix',
'[class.mat-mdc-form-field-has-icon-suffix]': '_hasIconSuffix',

// Note that these classes reuse the same names as the non-MDC version, because they can be
// considered a public API since custom form controls may use them to style themselves.
Expand Down Expand Up @@ -197,6 +199,11 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
}
private _hintLabel = '';

_hasIconPrefix = false;
_hasTextPrefix = false;
_hasIconSuffix = false;
_hasTextSuffix = false;

// Unique id for the internal form field label.
readonly _labelId = `mat-mdc-form-field-label-${nextUniqueId++}`;

Expand Down Expand Up @@ -438,13 +445,24 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
}
}

private _checkPrefixAndSuffixTypes() {
this._hasIconPrefix = !!this._prefixChildren.find(p => !p._isText);
this._hasTextPrefix = !!this._prefixChildren.find(p => p._isText);
this._hasIconSuffix = !!this._suffixChildren.find(s => !s._isText);
this._hasTextSuffix = !!this._suffixChildren.find(s => s._isText);
}

/** Initializes the prefix and suffix containers. */
private _initializePrefixAndSuffix() {
this._checkPrefixAndSuffixTypes();
// Mark the form-field as dirty whenever the prefix or suffix children change. This
// is necessary because we conditionally display the prefix/suffix containers based
// on whether there is projected content.
merge(this._prefixChildren.changes, this._suffixChildren.changes)
.subscribe(() => this._changeDetectorRef.markForCheck());
.subscribe(() => {
this._checkPrefixAndSuffixTypes();
this._changeDetectorRef.markForCheck();
});
}

/**
Expand Down Expand Up @@ -667,15 +685,19 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
this._needsOutlineLabelOffsetUpdateOnStable = true;
return;
}
const iconPrefixContainer = this._iconPrefixContainer.nativeElement as HTMLElement;
const textPrefixContainer = this._textPrefixContainer.nativeElement as HTMLElement;
const iconPrefixContainer = this._iconPrefixContainer?.nativeElement;
const textPrefixContainer = this._textPrefixContainer?.nativeElement;
// 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 labelHorizontalOffset =
(this._dir.value === 'rtl' ? -1 : 1) * (
iconPrefixContainer.getBoundingClientRect().width +
textPrefixContainer.getBoundingClientRect().width
);
(iconPrefixContainer ?
// If there's an icon prefix, we disable the default 16px padding,
// so make sure to account for that.
(iconPrefixContainer?.getBoundingClientRect().width ?? 0) - 16 : 0
) +
(textPrefixContainer?.getBoundingClientRect().width ?? 0)
);

// Update the transform the floating label to account for the prefix container. Note
// that we do not want to overwrite the default transform for docked floating labels.
Expand Down

0 comments on commit b80bb42

Please sign in to comment.