Skip to content

Commit

Permalink
Revert "refactor(material/form-field): tokenize density overrides (#2…
Browse files Browse the repository at this point in the history
…8249)" (#28269)

This reverts commit 087cf15.

(cherry picked from commit db17910)
  • Loading branch information
crisbeto committed Dec 12, 2023
1 parent fbcd237 commit 4cc4673
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 135 deletions.
51 changes: 1 addition & 50 deletions src/material/core/tokens/m2/mat/_form-field.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
@use 'sass:math';
@use 'sass:map';
@use '@material/textfield' as mdc-textfield;
@use '@material/density' as mdc-density;
@use '../../token-utils';
@use '../../../style/sass-utils';
@use '../../../theming/theming';
@use '../../../theming/inspection';
@use '../../../theming/palette';

Expand Down Expand Up @@ -90,52 +86,7 @@ $prefix: (mat, form-field);

// Tokens that can be configured through Angular Material's density theming API.
@function get-density-tokens($theme) {
$density-scale: theming.clamp-density(inspection.get-theme-density($theme), -4);
$height: mdc-density.prop-value(
$density-config: mdc-textfield.$density-config,
$density-scale: inspection.get-theme-density($theme),
$property-name: height,
);
$hide-label: $height < mdc-textfield.$minimum-height-for-filled-label;

// We computed the desired height of the form-field using the density configuration. The
// spec only describes vertical spacing/alignment in non-dense mode. This means that we
// cannot update the spacing to explicit numbers based on the density scale. Instead, we
// determine the height reduction and equally subtract it from the default `top` and `bottom`
// padding that is provided by the Material Design specification.
$vertical-deduction: math.div(mdc-textfield.$height - $height, 2);

// Note: these calculations are trivial enough that we could do them at runtime with `calc`
// and the value of the `height` token. The problem is that because we need to hide the label
// if the container becomes too short, we have to change the padding calculation. This is
// complicated further by the fact that filled form fields without labels have the same
// vertical padding as outlined ones. Alternatives:
// 1. Using container queries to hide the label and change the padding - this doesn't work
// because size container queries require setting the `container-type` property which breaks
// the form field layout. We could use style queries, but they're only supported in Chrome.
// 2. Monitoring the size of the label - we already have a `ResizeObserver` on the label so we
// could reuse it to also check when it becomes `display: none`. This would allows us to remove
// the three padding tokens. We don't do it, because it would require us to always set up
// the resize observer, as opposed to currently where it's only set up for outlined form fields.
// This may lead to performance regressions.
// 3. Conditionally adding `::before` and `::after` to the infix with positive and negative
// margin respectively - this works, but is likely to break a lot of overrides that are targeting
// a specific padding. It also runs the risk of overflowing the container.
// TODO: switch the padding tokens to style-based container queries
// when they become available in all the browsers we support.
$filled-with-label-padding-top: 24px - $vertical-deduction;
$filled-with-label-padding-bottom: 8px - $vertical-deduction;
$vertical-padding: 16px - $vertical-deduction;

@return (
container-height: $height,
filled-label-display: if($hide-label, none, block),
container-vertical-padding: $vertical-padding,
filled-with-label-container-padding-top:
if($hide-label, $vertical-padding, $filled-with-label-padding-top),
filled-with-label-container-padding-bottom:
if($hide-label, $vertical-padding, $filled-with-label-padding-bottom),
);
@return ();
}

// Combines the tokens generated by the above functions into a single map with placeholder values.
Expand Down
3 changes: 2 additions & 1 deletion src/material/form-field/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ sass_binary(
sass_library(
name = "form_field_partials",
srcs = [
"_form-field-density.scss",
"_form-field-focus-overlay.scss",
"_form-field-high-contrast.scss",
"_form-field-native-select.scss",
"_form-field-sizing.scss",
"_form-field-subscript.scss",
"_mdc-text-field-density-overrides.scss",
"_mdc-text-field-structure-overrides.scss",
"_mdc-text-field-textarea-overrides.scss",
"_user-agent-overrides.scss",
Expand Down
118 changes: 118 additions & 0 deletions src/material/form-field/_form-field-density.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
@use 'sass:map';
@use 'sass:math';
@use '@material/density' as mdc-density;
@use '@material/textfield' as mdc-textfield;
@use '../core/theming/inspection';

@use './form-field-sizing';

// Mixin that sets the vertical spacing for the infix container of filled form fields.
// We need to apply spacing to the infix container because we removed the input padding
// provided by MDC in order to support arbitrary form-field controls.
@mixin _infix-vertical-spacing-filled($with-label-padding, $no-label-padding) {
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-form-field-infix {
padding-top: map.get($with-label-padding, top);
padding-bottom: map.get($with-label-padding, bottom);
}

.mdc-text-field--no-label:not(.mdc-text-field--outlined):not(.mdc-text-field--textarea)
.mat-mdc-form-field-infix {
padding-top: map.get($no-label-padding, top);
padding-bottom: map.get($no-label-padding, bottom);
}
}

// Mixin that sets the vertical spacing for the infix container of outlined form fields.
// We need to apply spacing to the infix container because we removed the input padding
// provided by MDC in order to support arbitrary form-field controls.
@mixin _infix-vertical-spacing-outlined($padding) {
.mat-mdc-text-field-wrapper.mdc-text-field--outlined .mat-mdc-form-field-infix {
padding-top: map.get($padding, top);
padding-bottom: map.get($padding, bottom);
}
}

// Mixin that includes the density styles for form fields. MDC provides their own density
// styles for MDC text-field which we cannot use. MDC relies on input elements to stretch
// vertically when the height is reduced as per density scale. This doesn't work for our
// form field since we support custom form field controls without a fixed height. Instead, we
// provide spacing that makes arbitrary controls align as specified in the Material Design
// specification. In order to support density, we need to adjust the vertical spacing to be
// based on the density scale.
@mixin private-form-field-density($theme) {
// Height of the form field that is based on the current density scale.
$height: mdc-density.prop-value(
$density-config: mdc-textfield.$density-config,
$density-scale: inspection.get-theme-density($theme),
$property-name: height,
);

// Whether floating labels for filled form fields should be hidden. MDC hides the label in
// their density styles when the height decreases too much. We match their density styles.
$hide-filled-floating-label: $height < mdc-textfield.$minimum-height-for-filled-label;
// We computed the desired height of the form-field using the density configuration. The
// spec only describes vertical spacing/alignment in non-dense mode. This means that we
// cannot update the spacing to explicit numbers based on the density scale. Instead, we
// determine the height reduction and equally subtract it from the default `top` and `bottom`
// padding that is provided by the Material Design specification.
$vertical-deduction: math.div(mdc-textfield.$height - $height, 2);
// Map that describes the padding for form-fields with label.
$with-label-padding: (
top: form-field-sizing.$mat-form-field-with-label-input-padding-top - $vertical-deduction,
bottom: form-field-sizing.$mat-form-field-with-label-input-padding-bottom - $vertical-deduction,
);
// Map that describes the padding for form-fields without label.
$no-label-padding: (
top: form-field-sizing.$mat-form-field-no-label-padding-top - $vertical-deduction,
bottom: form-field-sizing.$mat-form-field-no-label-padding-bottom - $vertical-deduction,
);

// We add a minimum height to the infix container in order to ensure that custom controls have
// the same default vertical space as text-field inputs (with respect to the vertical padding).
.mat-mdc-form-field-infix {
min-height: $height;
}

// By default, MDC aligns the label using percentage. This will be overwritten based
// on whether a textarea is used. This is not possible in our implementation of the
// form-field because we do not know what type of form-field control is set up. Hence
// we always use a fixed position for the label. This does not have any implications.
.mat-mdc-text-field-wrapper .mat-mdc-form-field-flex .mat-mdc-floating-label {
top: math.div($height, 2);
}

// For the outline appearance, we re-create the active floating label transform. This is
// necessary because the transform for docked floating labels can be updated to account for
// the width of prefix container.
.mat-mdc-text-field-wrapper.mdc-text-field--outlined .mdc-notched-outline--upgraded
.mdc-floating-label--float-above {
--mat-mdc-form-field-label-transform: translateY(
-#{mdc-textfield.get-outlined-label-position-y($height)})
scale(var(--mat-mdc-form-field-floating-label-scale, 0.75));
transform: var(--mat-mdc-form-field-label-transform);
}

// Add vertical spacing to the infix to ensure that outlined form fields have their controls
// aligned as if there is no label. This is done similarly in MDC and is specified in the
// Material Design specification. Outline form fields position the control as if there is no
// label. This is because the label overflows the form-field and doesn't need space at the top.
@include _infix-vertical-spacing-outlined($no-label-padding);

// MDC hides labels for filled form fields when the form field height decreases. We match
// this behavior in our custom density styles.
@if $hide-filled-floating-label {
// Update the spacing for filled form fields to account for the hidden floating label.
@include _infix-vertical-spacing-filled(
$no-label-padding, $no-label-padding);
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label {
display: none;
}
}
@else {
// By default, filled form fields align their controls differently based on whether there
// is a label or not. MDC does this too, but we cannot rely on their styles as we support
// arbitrary form field controls and MDC only applies their spacing to the `<input>` elements.
@include _infix-vertical-spacing-filled(
$with-label-padding, $no-label-padding);
}
}
40 changes: 40 additions & 0 deletions src/material/form-field/_form-field-sizing.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Top spacing of the form-field outline. MDC does not have a variable for this
// and just hard-codes it into their styles.
$mat-form-field-outline-top-spacing: 12px;

// Infix stretches to fit the container, but naturally wants to be this wide. We set
// this in order to have a consistent natural size for the various types of controls
// that can go in a form field.
$mat-form-field-default-infix-width: 180px !default;

// Minimum amount of space between start and end hints in the subscript. MDC does not
// have built-in support for hints.
$mat-form-field-hint-min-space: 1em !default;

// Vertical spacing of the text-field if there is no label. MDC hard-codes the spacing
// into their styles, but their spacing variables would not work for our form-field
// structure anyway. This is because MDC's input elements are larger than the text, and
// their padding variables are calculated with respect to the vertical empty space of the
// inputs. We take the explicit numbers provided by the Material Design specification.
// https://material.io/components/text-fields/#specs

// Vertical spacing of the text-field if there is a label. MDC hard-codes the spacing into
// their styles, but their spacing variables would not work for our form-field structure anyway.
// This is because MDC's alignment depends on the input element to expand to full infix height.
// We allow for arbitrary form controls and support dynamic height, so we manage the control
// infix alignment through padding on the infix that works for any control. We manually measure
// spacing as provided by the Material Design specification. The outlined dimensions in the
// spec section do not match with the text fields shown in the overview or the ones implemented
// by MDC. Note that we need to account for the input box offset. See above for more context.
$mat-form-field-with-label-input-padding-top: 24px;
$mat-form-field-with-label-input-padding-bottom: 8px;

// Vertical spacing of the text-field if there is no label. We manually measure the
// spacing in the specs. See comment above for padding for text fields with label. The
// 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;
3 changes: 2 additions & 1 deletion src/material/form-field/_form-field-subscript.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
@use '../core/tokens/token-utils';
@use './form-field-sizing';

@mixin private-form-field-subscript() {
// Wrapper for the hints and error messages.
Expand Down Expand Up @@ -49,7 +50,7 @@

// Spacer used to make sure start and end hints have enough space between them.
.mat-mdc-form-field-hint-spacer {
flex: 1 0 1em;
flex: 1 0 form-field-sizing.$mat-form-field-hint-min-space;
}

// Single error message displayed beneath the form field underline.
Expand Down
6 changes: 2 additions & 4 deletions src/material/form-field/_form-field-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@use '../core/typography/typography';
@use '../core/style/sass-utils';
@use '../core/tokens/token-utils';
@use './form-field-density';

@mixin base($theme) {
@if inspection.get-theme-version($theme) == 1 {
Expand Down Expand Up @@ -84,10 +85,7 @@
@include _theme-from-tokens(inspection.get-theme-tokens($theme, density));
}
@else {
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-form-field.$prefix,
tokens-mat-form-field.get-density-tokens($theme));
}
@include form-field-density.private-form-field-density($theme);
}
}

Expand Down
60 changes: 0 additions & 60 deletions src/material/form-field/_mdc-text-field-density-overrides.scss

This file was deleted.

18 changes: 4 additions & 14 deletions src/material/form-field/form-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
@use '../core/tokens/m2/mdc/filled-text-field' as tokens-mdc-filled-text-field;
@use '../core/tokens/m2/mdc/outlined-text-field' as tokens-mdc-outlined-text-field;
@use './form-field-sizing';
@use './form-field-subscript';
@use './form-field-focus-overlay';
@use './form-field-high-contrast';
@use './form-field-native-select';
@use './user-agent-overrides';
@use './mdc-text-field-textarea-overrides';
@use './mdc-text-field-structure-overrides';
@use './mdc-text-field-density-overrides';

// Includes the structural styles of the components that the form field is composed of.
@mixin _static-styles($query) {
Expand Down Expand Up @@ -57,7 +57,6 @@
// MDC text-field overwrites.
@include mdc-text-field-textarea-overrides.private-text-field-textarea-overrides();
@include mdc-text-field-structure-overrides.private-text-field-structure-overrides();
@include mdc-text-field-density-overrides.private-text-field-density-overrides();

// Include the subscript, focus-overlay, native select and high-contrast styles.
@include form-field-subscript.private-form-field-subscript();
Expand All @@ -66,10 +65,6 @@
@include form-field-high-contrast.private-form-field-high-contrast();
@include user-agent-overrides.private-form-field-user-agent-overrides();

// 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.
$_icon-prefix-infix-padding: 4px;

// Host element of the form-field. It contains the mdc-text-field wrapper
// and the subscript wrapper.
.mat-mdc-form-field {
Expand Down Expand Up @@ -149,11 +144,11 @@ $_icon-prefix-infix-padding: 4px;
// 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 $_icon-prefix-infix-padding 0 0;
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 $_icon-prefix-infix-padding;
padding: 0 0 0 form-field-sizing.$mat-form-field-icon-prefix-infix-padding;
}

.mat-mdc-form-field-icon-prefix,
Expand Down Expand Up @@ -183,12 +178,7 @@ $_icon-prefix-infix-padding: 4px;
.mat-mdc-form-field-infix {
flex: auto;
min-width: 0;

// Infix stretches to fit the container, but naturally wants to be this wide. We set
// this in order to have a consistent natural size for the various types of controls
// that can go in a form field.
width: 180px;

width: form-field-sizing.$mat-form-field-default-infix-width;
// Needed so that the floating label does not overlap with prefixes or suffixes.
position: relative;
box-sizing: border-box;
Expand Down
Loading

0 comments on commit 4cc4673

Please sign in to comment.