Skip to content

feat(material-experimental/mdc-form-field): Add option for dynamic su… #24241

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

Merged
merged 1 commit into from
Jan 24, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/dev-app/mdc-input/mdc-input-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,81 @@ <h4>Textarea</h4>
</mat-card-content>
</mat-card>

<mat-card class="demo-card demo-basic">
<mat-toolbar color="primary">Dynamic Subscript Sizing</mat-toolbar>
<mat-card-content>
<p>
One validation
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput [(ngModel)]="fillAppearance" required>
<mat-error>This field is required</mat-error>
</mat-form-field>
</p>

<p>
One very long validation that wraps
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic"
style="width: 212px">
<mat-label>Fill appearance</mat-label>
<input matInput [(ngModel)]="fillAppearance" required>
<mat-error>This field is extremely, very much, absolutely positively required so do not forget it!</mat-error>
</mat-form-field>
</p>

<p>
One hint and one validation
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput [(ngModel)]="fillAppearance" required>
<mat-error>This field is required</mat-error>
<mat-hint>Please type something here</mat-hint>
</mat-form-field>
</p>

<p>
Multiple errors
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput [(ngModel)]="fillAppearance" required>
<mat-error>AAA</mat-error>
<mat-error>BBB</mat-error>
<mat-error>CCC</mat-error>
</mat-form-field>
</p>

<p>
Multiple hints
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput>
<mat-hint>aaa</mat-hint>
<mat-hint>bbb</mat-hint>
<mat-hint>ccc</mat-hint>
</mat-form-field>
</p>

<p>
Multiple hints with differing alignment
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput>
<mat-hint>aaa</mat-hint>
<mat-hint align="end">bbb</mat-hint>
<mat-hint align="end">ccc</mat-hint>
</mat-form-field>
</p>

<p>
No hints or errors
<mat-form-field appearance="fill" [color]="color" subscriptSizing="dynamic">
<mat-label>Fill appearance</mat-label>
<input matInput>
</mat-form-field>
</p>
</mat-card-content>
</mat-card>

<mat-card class="demo-card demo-basic">
<mat-toolbar color="primary">Number Inputs</mat-toolbar>
<mat-card-content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,23 @@
padding: 0 mdc-textfield-variables.$padding-horizontal;
}

.mat-mdc-form-field-subscript-dynamic-size {
.mat-mdc-form-field-hint-wrapper,
.mat-mdc-form-field-error-wrapper {
position: static;
}
}

.mat-mdc-form-field-bottom-align::before {
content: '';
display: inline-block;
height: 16px;
}

.mat-mdc-form-field-bottom-align.mat-mdc-form-field-subscript-dynamic-size::before {
content: unset;
}

.mat-mdc-form-field-hint-end {
order: 1;
}
Expand Down
1 change: 1 addition & 0 deletions src/material-experimental/mdc-form-field/form-field.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
</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'"
[ngSwitch]="_getDisplayedMessages()">
<div class="mat-mdc-form-field-error-wrapper" *ngSwitchCase="'error'"
[@transitionMessages]="_subscriptAnimationState">
Expand Down
21 changes: 21 additions & 0 deletions src/material-experimental/mdc-form-field/form-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export type FloatLabelType = 'always' | 'auto';
/** Possible appearance styles for the form field. */
export type MatFormFieldAppearance = 'fill' | 'outline';

/** Behaviors for how the subscript height is set. */
export type SubscriptSizing = 'fixed' | 'dynamic';

/**
* Represents the default options for the form field that can be configured
* using the `MAT_FORM_FIELD_DEFAULT_OPTIONS` injection token.
Expand All @@ -69,6 +72,7 @@ export interface MatFormFieldDefaultOptions {
appearance?: MatFormFieldAppearance;
hideRequiredMarker?: boolean;
floatLabel?: FloatLabelType;
subscriptSizing?: SubscriptSizing;
}

/**
Expand All @@ -87,6 +91,9 @@ const DEFAULT_APPEARANCE: MatFormFieldAppearance = 'fill';
/** Default appearance used by the form-field. */
const DEFAULT_FLOAT_LABEL: FloatLabelType = 'auto';

/** Default way that the suffix element height is set. */
const DEFAULT_SUBSCRIPT_SIZING: SubscriptSizing = 'fixed';

/**
* Default transform for docked floating labels in a MDC text-field. This value has been
* extracted from the MDC text-field styles because we programmatically modify the docked
Expand Down Expand Up @@ -206,6 +213,20 @@ export class MatFormField
}
private _appearance: MatFormFieldAppearance = DEFAULT_APPEARANCE;

/**
* Whether the form field should reserve space for one line of hint/error text (default)
* or to have the spacing grow from 0px as needed based on the size of the hint/error content.
* Note that when using dynamic sizing, layout shifts will occur when hint/error text changes.
*/
@Input()
get subscriptSizing(): SubscriptSizing {
return this._subscriptSizing || this._defaults?.subscriptSizing || DEFAULT_SUBSCRIPT_SIZING;
}
set subscriptSizing(value: SubscriptSizing) {
this._subscriptSizing = value || this._defaults?.subscriptSizing || DEFAULT_SUBSCRIPT_SIZING;
}
private _subscriptSizing: SubscriptSizing = DEFAULT_SUBSCRIPT_SIZING;

/** Text for the form field hint. */
@Input()
get hintLabel(): string {
Expand Down
55 changes: 55 additions & 0 deletions src/material-experimental/mdc-input/input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
MatFormField,
MatFormFieldAppearance,
MatFormFieldModule,
SubscriptSizing,
} from '@angular/material-experimental/mdc-form-field';
import {MatIconModule} from '@angular/material/icon';
import {By} from '@angular/platform-browser';
Expand Down Expand Up @@ -1406,6 +1407,47 @@ describe('MatFormField default options', () => {
expect(fixture.componentInstance.formField.hideRequiredMarker).toBe(true);
expect(fixture.componentInstance.formField.appearance).toBe('outline');
});

it('defaults subscriptSizing to false', () => {
const fixture = createComponent(MatInputWithSubscriptSizing);
fixture.detectChanges();

const subscriptElement = fixture.nativeElement.querySelector(
'.mat-mdc-form-field-subscript-wrapper',
);

expect(fixture.componentInstance.formField.subscriptSizing).toBe('fixed');
expect(subscriptElement.classList.contains('mat-mdc-form-field-subscript-dynamic-size')).toBe(
false,
);

fixture.componentInstance.sizing = 'dynamic';
fixture.detectChanges();

expect(fixture.componentInstance.formField.subscriptSizing).toBe('dynamic');
expect(subscriptElement.classList.contains('mat-mdc-form-field-subscript-dynamic-size')).toBe(
true,
);
});

it('changes the default value of subscriptSizing', () => {
const fixture = createComponent(MatInputWithSubscriptSizing, [
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: {
subscriptSizing: 'dynamic',
},
},
]);

fixture.detectChanges();
expect(fixture.componentInstance.formField.subscriptSizing).toBe('dynamic');
expect(
fixture.nativeElement
.querySelector('.mat-mdc-form-field-subscript-wrapper')
.classList.contains('mat-mdc-form-field-subscript-dynamic-size'),
).toBe(true);
});
});

function configureTestingModule(
Expand Down Expand Up @@ -1815,6 +1857,19 @@ class MatInputWithAppearance {
appearance: MatFormFieldAppearance;
}

@Component({
template: `
<mat-form-field [subscriptSizing]="sizing">
<mat-label>My Label</mat-label>
<input matInput placeholder="Placeholder" required>
</mat-form-field>
`,
})
class MatInputWithSubscriptSizing {
@ViewChild(MatFormField) formField: MatFormField;
sizing: SubscriptSizing;
}

@Component({
template: `
<mat-form-field>
Expand Down