Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material-experimental/mdc-form-field): fix outline notch width #23005

Merged
merged 2 commits into from Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/dev-app/mdc-input/mdc-input-demo.html
Expand Up @@ -731,6 +731,25 @@ <h3>&lt;textarea&gt; with bindable autosize </h3>
<mat-label>Label</mat-label>
<input matInput>
</mat-form-field>

<p>
Textarea alignment
</p>

<mat-form-field appearance="outline">
<mat-label>Textarea</mat-label>
<textarea matInput rows="1"></textarea>
</mat-form-field>

<mat-form-field appearance="outline">
<mat-label>Input</mat-label>
<input matInput>
</mat-form-field>

<mat-form-field appearance="outline">
<mat-label>Input</mat-label>
<input matInput>
</mat-form-field>
</mat-card-content>
</mat-card>

Expand Down
2 changes: 1 addition & 1 deletion src/material-experimental/mdc-chips/chip-input.spec.ts
Expand Up @@ -141,7 +141,7 @@ describe('MDC-based MatChipInput', () => {

it('should set input styling classes', () => {
expect(inputNativeElement.classList).toContain('mat-mdc-input-element');
expect(inputNativeElement.classList).toContain('mat-mdc-form-field-control');
expect(inputNativeElement.classList).toContain('mat-mdc-form-field-input-control');
expect(inputNativeElement.classList).toContain('mat-mdc-chip-input');
expect(inputNativeElement.classList).toContain('mdc-text-field__input');
});
Expand Down
2 changes: 1 addition & 1 deletion src/material-experimental/mdc-chips/chip-input.ts
Expand Up @@ -135,7 +135,7 @@ export class MatChipInput implements MatChipTextControl, AfterContentInit, OnCha
this.inputElement = this._elementRef.nativeElement as HTMLInputElement;

if (formField) {
this.inputElement.classList.add('mat-mdc-form-field-control');
this.inputElement.classList.add('mat-mdc-form-field-input-control');
}
}

Expand Down
Expand Up @@ -17,7 +17,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
// Remove the native select down arrow and ensure that the native appearance
// does not conflict with the form-field. e.g. Focus indication of the native
// select is undesired since we handle focus as part of the form-field.
select.mat-mdc-form-field-control {
select.mat-mdc-form-field-input-control {
-moz-appearance: none;
-webkit-appearance: none;
background-color: transparent;
Expand Down Expand Up @@ -58,7 +58,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt

// Add padding on the end of the native select so that the content does not
// overlap with the Material Design arrow.
.mat-mdc-form-field-control {
.mat-mdc-form-field-input-control {
padding-right: $mat-form-field-select-horizontal-end-padding;
[dir='rtl'] & {
padding-right: 0;
Expand All @@ -80,7 +80,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
$dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.54);
$disabled-dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.38);

select.mat-mdc-form-field-control {
select.mat-mdc-form-field-input-control {
// On dark themes we set the native `select` color to some shade of white,
// however the color propagates to all of the `option` elements, which are
// always on a white background inside the dropdown, causing them to blend in.
Expand Down
Expand Up @@ -38,7 +38,3 @@ $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;
@@ -1,6 +1,7 @@
@use '@material/textfield' as mdc-textfield;
@use '@material/theme/theme' as mdc-theme;
@use '@material/typography' as mdc-typography;
@use '@material/textfield/variables' as mdc-textfield-variables;
@use 'form-field-sizing';
@use '../mdc-helpers/mdc-helpers';
@use '../../material/core/theming/theming';
Expand All @@ -13,16 +14,13 @@
position: relative;
}

// The horizontal padding between the edge of the text box and the start of the subscript text.
$subscript-horizontal-padding: 16px;

.mat-mdc-form-field-hint-wrapper,
.mat-mdc-form-field-error-wrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 0 $subscript-horizontal-padding;
padding: 0 mdc-textfield-variables.$padding-horizontal;
}

.mat-mdc-form-field-bottom-align::before {
Expand All @@ -31,14 +29,8 @@
height: 16px;
}

// Scale down icons in the subscript to be the same size as the text.
.mat-mdc-form-field-subscript-wrapper,
.mat-mdc-form-field label {
.mat-icon {
width: 1em;
height: 1em;
font-size: inherit;
}
.mat-mdc-form-field-hint-end {
order: 1;
}

// Clears the floats on the hints. This is necessary for the hint animation to work.
Expand Down
30 changes: 23 additions & 7 deletions src/material-experimental/mdc-form-field/_form-field-theme.scss
Expand Up @@ -3,7 +3,7 @@
@use '@material/notched-outline' as mdc-notched-outline;
@use '@material/line-ripple' as mdc-line-ripple;
@use '@material/theme/theme-color' as mdc-theme-color;
@use '@material/typography' as mdc-typography;
@use '@material/typography/typography' as mdc-typography;
@use '../mdc-helpers/mdc-helpers';
@use '../../material/core/typography/typography';
@use 'form-field-density';
Expand Down Expand Up @@ -72,14 +72,30 @@
@include mdc-line-ripple.core-styles($query: mdc-helpers.$mat-typography-styles-query);
@include form-field-subscript.private-form-field-subscript-typography($config);

// MDC uses the `subtitle1` level for the input label and value, but the spec shows `body1` as
// the correct level.
.mat-mdc-form-field-control,
.mat-mdc-form-field label,
.mat-mdc-form-field-text-prefix,
.mat-mdc-form-field-text-suffix {
// MDC uses `subtitle1` for the input value, placeholder and floating label. The spec
// shows `body1` for text fields though, so we manually override the typography.
// Note: Form controls inherit the typography from the parent form field.
.mat-mdc-form-field,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think changing these selectors broke some of the typography. I'm seeing a few screenshots in g3 where the font changed. Can we change them back?

.mat-mdc-form-field .mdc-floating-label {
@include mdc-typography.typography(body1, $query: mdc-helpers.$mat-typography-styles-query);
}

// Above, we updated the floating label to use the `body1` typography level. The MDC notched
// outline overrides this accidentally (only when the label floats) to a `rem`-based value.
// This results in different label widths when floated/docked and ultimately breaks the notch
// width as it has been measured in the docked state (where `body1` is applied). We try to
// unset these styles set by the `mdc-notched-outline`:
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-notched-outline/_mixins.scss#L272-L292.
.mat-mdc-form-field .mdc-text-field--outlined {
// For the non-upgraded notch label (i.e. when rendered on the server), also
// use the correct `body1` typography level.
.mdc-floating-label--float-above {
font-size: mdc-typography.get-size(body1) * 0.75;
}
.mdc-notched-outline--upgraded .mdc-floating-label--float-above {
font-size: mdc-typography.get-size(body1);
}
}
}
}

Expand Down
@@ -1,20 +1,26 @@
@use 'form-field-sizing';
@use '@material/textfield/variables' as mdc-textfield-variables;

// Mixin that can be included to override the default MDC text-field
// styles to fit our needs. See individual comments for context on why
// certain MDC styles need to be modified.
@mixin private-text-field-structure-overrides() {
// Unset the border set by MDC. We move the border (which serves as the Material Design
// text-field bottom line) into its own element. This is necessary because we want the
// bottom-line to span across the whole form-field (including prefixes and suffixes).
.mat-mdc-form-field-control {
// bottom-line to span across the whole form-field (including prefixes and suffixes). Also
// we ensure that font styles are inherited for input elements. We do this because inputs by
// default have explicit font styles from the user agent, and we set the desired font styles
// in the parent `mat-form-field` element (for better custom form-field control support).
// Note: We increase specificity here because the MDC textfield seems to override this,
// depending on the CSS order, with an affix selector joint with the input.
.mat-mdc-form-field-input-control.mat-mdc-form-field-input-control {
font: inherit;
border: none;
}

// In order to ensure proper alignment of the floating label, we reset its line-height.
// The line-height is not important as the element is absolutely positioned and only has one line
// of text.
.mat-mdc-form-field .mdc-floating-label {
.mat-mdc-form-field .mdc-floating-label.mdc-floating-label {
line-height: normal;
}

Expand All @@ -24,15 +30,16 @@
// not work for us since we support arbitrary form field controls which don't necessarily
// use an `input` element. We organize the vertical spacing on the infix container.
.mdc-text-field--no-label:not(.mdc-text-field--textarea)
.mat-mdc-form-field-control.mdc-text-field__input,
.mat-mdc-text-field-wrapper .mat-mdc-form-field-control {
.mat-mdc-form-field-input-control.mdc-text-field__input,
.mat-mdc-text-field-wrapper .mat-mdc-form-field-input-control {
height: auto;
}

// Color inputs are a special case, because setting their height to
// `auto` will collapse them. The height value is an arbitrary number
// which was extracted from the user agent styles of Chrome and Firefox.
.mat-mdc-text-field-wrapper .mat-mdc-form-field-control.mdc-text-field__input[type='color'] {
.mat-mdc-text-field-wrapper
.mat-mdc-form-field-input-control.mdc-text-field__input[type='color'] {
height: 23px;
}

Expand All @@ -57,8 +64,8 @@
[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;
padding-left: mdc-textfield-variables.$padding-horizontal;
padding-right: mdc-textfield-variables.$padding-horizontal;
}
// ...and apply the correct padding resets for RTL languages.
.mat-mdc-form-field-has-icon-suffix .mat-mdc-text-field-wrapper {
Expand Down
Expand Up @@ -10,7 +10,15 @@
@mixin private-text-field-textarea-overrides() {
// Ensures that textarea elements inside of the form-field have proper vertical spacing
// to account for the floating label. Also ensures that there is no vertical text overflow.
.mat-mdc-textarea-input {
// **Note**: Before changing this selector, make sure the `cdk-textarea-autosize` class is
// still able to override the `resize` property to `none`.
.mat-mdc-form-field-textarea-control {
// Set the vertical alignment for textareas inside form fields to be the middle. This
// ensures that textareas do not stretch the infix container vertically without having
// multiple rows of text. See: https://github.com/angular/components/pull/22089.
vertical-align: middle;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this doesn't mess up prefix/suffix icon alignment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested with a text suffix/prefix and icons, looks good. Here is a screenshot for you to verify:
image

It looks like the icon aligns in the middle vertically if the textarea is resized to be larger; but that seems unrelated to this change, and I'm not sure what is expected here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it just me or are there some extra lines in that screenshot?
122447133-b815fe00-cfa3-11eb-8865-0c7dd87bd938

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to this PR (can be observed in Miles' form-field demo too; https://mmalerba-demo-1.web.app/mdc-input). I'll have a look at this in a separate PR; it's also observable on the MDC textfield itself but not as obvious.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I've noticed that extra line before too, it comes from the MDC styles. I remember having a similar issue back when I was writing our outline form field too.

// Textareas by default also allow users to resize the textarea horizontally. This
// causes the textarea to overflow the form-field. We only allow vertical resizing.
resize: vertical;
box-sizing: border-box;
height: auto;
Expand Down
18 changes: 11 additions & 7 deletions src/material-experimental/mdc-form-field/form-field.scss
Expand Up @@ -90,13 +90,21 @@
}
}

// Scale down icons in the subscript and floating label to be the same size
// as the text.
.mat-mdc-form-field-subscript-wrapper,
.mat-mdc-form-field label {
.mat-icon {
width: 1em;
height: 1em;
font-size: inherit;
}
}

// Infix that contains the projected content (usually an input or a textarea). We ensure
// that the projected form-field control and content can stretch as needed, but we also
// apply a default infix width to make the form-field's look natural.
.mat-mdc-form-field-infix {
// Prevent extra height from being added around the textarea, which throws off the overall
// height of the form-field
line-height: 0;
flex: auto;
min-width: 0;
width: form-field-sizing.$mat-form-field-default-infix-width;
Expand All @@ -105,10 +113,6 @@
box-sizing: border-box;
}

.mat-mdc-form-field-hint-end {
order: 1;
}

// In order to make it possible for developers to disable animations for form-fields,
// we only activate the animation styles if animations are not explicitly disabled.
.mat-mdc-form-field:not(.mat-form-field-no-animations) {
Expand Down
18 changes: 12 additions & 6 deletions src/material-experimental/mdc-form-field/form-field.ts
Expand Up @@ -93,6 +93,12 @@ const DEFAULT_FLOAT_LABEL: FloatLabelType = 'auto';
*/
const FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM = `translateY(-50%)`;

/**
* Horizontal padding in pixels used by the MDC for the wrapper containing infix.
* This value is extracted from MDC's Sass variables. See `$padding-horizontal`.
*/
const WRAPPER_HORIZONTAL_PADDING = 16;

/** Container for form controls that applies Material Design styling and behavior. */
@Component({
selector: 'mat-form-field',
Expand Down Expand Up @@ -691,16 +697,16 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
}
const iconPrefixContainer = this._iconPrefixContainer?.nativeElement;
const textPrefixContainer = this._textPrefixContainer?.nativeElement;
const iconPrefixContainerWidth = iconPrefixContainer?.getBoundingClientRect().width ?? 0;
const textPrefixContainerWidth = textPrefixContainer?.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 labelHorizontalOffset =
(this._dir.value === 'rtl' ? -1 : 1) * (
(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)
// If there's an icon prefix, we subtract the default horizontal padding as we
// reset the horizontal padding in CSS too.
(iconPrefixContainer ? iconPrefixContainerWidth - WRAPPER_HORIZONTAL_PADDING : 0) +
textPrefixContainerWidth
);

// Update the transform the floating label to account for the prefix container. Note
Expand Down
4 changes: 2 additions & 2 deletions src/material-experimental/mdc-input/input.spec.ts
Expand Up @@ -858,8 +858,8 @@ describe('MatMdcInput without forms', () => {
const inFormField = fixture.nativeElement.querySelector('.inside');
const outsideFormField = fixture.nativeElement.querySelector('.outside');

expect(inFormField.classList).toContain('mat-mdc-form-field-control');
expect(outsideFormField.classList).not.toContain('mat-mdc-form-field-control');
expect(inFormField.classList).toContain('mat-mdc-form-field-input-control');
expect(outsideFormField.classList).not.toContain('mat-mdc-form-field-input-control');
}));

});
Expand Down
4 changes: 2 additions & 2 deletions src/material-experimental/mdc-input/input.ts
Expand Up @@ -27,8 +27,8 @@ import {MatInput as BaseMatInput} from '@angular/material/input';
'[class.mat-input-element]': 'false',
'[class.mat-form-field-control]': 'false',
'[class.mat-input-server]': '_isServer',
'[class.mat-mdc-textarea-input]': '_isTextarea',
'[class.mat-mdc-form-field-control]': '_isInFormField',
'[class.mat-mdc-form-field-textarea-control]': '_isInFormField && _isTextarea',
'[class.mat-mdc-form-field-input-control]': '_isInFormField',
'[class.mdc-text-field__input]': '_isInFormField',
// Native input properties that are overwritten by Angular inputs need to be synced with
// the native input element. Otherwise property bindings for those don't work.
Expand Down
2 changes: 1 addition & 1 deletion src/material/datepicker/date-range-input.ts
Expand Up @@ -249,7 +249,7 @@ export class MatDateRangeInput<D> implements MatFormFieldControl<DateRange<D>>,
if (_formField?._elementRef.nativeElement.classList.contains('mat-mdc-form-field')) {
const classList = _elementRef.nativeElement.classList;
classList.add('mat-mdc-input-element');
classList.add('mat-mdc-form-field-control');
classList.add('mat-mdc-form-field-input-control');
}

// TODO(crisbeto): remove `as any` after #18206 lands.
Expand Down
Binary file removed src/material/form-field/.form-field.md.swp
Binary file not shown.