UNPKG

80.2 kBSCSSView Raw
1//
2// Copyright 2017 Google Inc.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
23// Selector '.mdc-*' should only be used in this project.
24// stylelint-disable selector-class-pattern --
25// TODO: document why this disable is neccessary
26
27@use 'sass:math';
28@use 'sass:list';
29@use 'sass:meta';
30@use '@material/animation/animation';
31@use '@material/density/functions' as density-functions;
32@use '@material/dom/dom';
33@use '@material/floating-label/mixins' as floating-label-mixins;
34@use '@material/floating-label/variables' as floating-label-variables;
35@use '@material/line-ripple/mixins' as line-ripple-mixins;
36@use '@material/notched-outline/mixins' as notched-outline-mixins;
37@use '@material/notched-outline/variables' as notched-outline-variables;
38@use '@material/ripple/ripple';
39@use '@material/ripple/ripple-theme';
40@use '@material/theme/custom-properties';
41@use '@material/theme/theme';
42@use '@material/shape/mixins' as shape-mixins;
43@use '@material/shape/functions' as shape-functions;
44@use '@material/feature-targeting/feature-targeting';
45@use '@material/typography/typography';
46@use 'helper-text/mixins' as helper-text-mixins;
47@use 'character-counter/mixins' as character-counter-mixins;
48@use 'icon/mixins' as icon-mixins;
49@use 'icon/variables' as icon-variables;
50@use './variables';
51@use '@material/rtl/rtl';
52
53@mixin core-styles($query: feature-targeting.all()) {
54 @include ripple($query);
55 @include without-ripple($query);
56 @include helper-text-mixins.helper-text-core-styles($query);
57 @include character-counter-mixins.character-counter-core-styles($query);
58 @include icon-mixins.icon-core-styles($query);
59}
60
61@mixin without-ripple($query: feature-targeting.all()) {
62 $feat-structure: feature-targeting.create-target($query, structure);
63
64 // Baseline
65 // postcss-bem-linter: define text-field
66 .mdc-text-field {
67 @include _base($query);
68 }
69
70 .mdc-text-field__input {
71 @include _input($query);
72
73 @include placeholder-selector_ {
74 @include _input-placeholder($query);
75 }
76
77 // Always show placeholder for text fields that has no
78 // label and show only on focused state when label is present.
79 .mdc-text-field--no-label &,
80 .mdc-text-field--focused & {
81 @include placeholder-selector_ {
82 @include _input-placeholder-visible($query);
83 }
84 }
85 }
86
87 .mdc-text-field__affix {
88 @include _affix($query: $query);
89
90 .mdc-text-field--label-floating &,
91 .mdc-text-field--no-label & {
92 @include _affix-visible($query: $query);
93 }
94
95 // Safari only
96 @supports (-webkit-hyphens: none) {
97 .mdc-text-field--outlined & {
98 @include _centered-affix-safari-support($query: $query);
99 }
100 }
101 }
102
103 .mdc-text-field__affix--prefix {
104 @include _prefix($query: $query);
105
106 .mdc-text-field--end-aligned & {
107 @include _prefix-end-aligned($query: $query);
108 }
109 }
110
111 .mdc-text-field__affix--suffix {
112 @include _suffix($query: $query);
113
114 .mdc-text-field--end-aligned & {
115 @include _suffix-end-aligned($query: $query);
116 }
117 }
118
119 // Variants
120
121 .mdc-text-field--filled {
122 @include _filled($query);
123
124 &.mdc-text-field--no-label {
125 @include _filled-no-label($query);
126 }
127 }
128
129 .mdc-text-field--outlined {
130 @include outlined_($query);
131
132 .mdc-notched-outline {
133 @include _outlined-notched-outline($query);
134 }
135 }
136
137 // Other Variations
138
139 .mdc-text-field--textarea {
140 @include textarea_($query);
141
142 .mdc-text-field__input {
143 @include _textarea-input($query);
144 }
145
146 &.mdc-text-field--filled {
147 @include _textarea-filled($query);
148
149 .mdc-text-field__input {
150 @include _textarea-filled-input($query);
151 }
152
153 &.mdc-text-field--no-label {
154 .mdc-text-field__input {
155 @include _textarea-filled-no-label-input($query);
156 }
157 }
158 }
159
160 &.mdc-text-field--outlined {
161 @include _textarea-outlined($query);
162
163 .mdc-text-field__input {
164 @include _textarea-outlined-input($query);
165 }
166
167 .mdc-floating-label {
168 @include _textarea-outlined-floating-label($query);
169 }
170 }
171
172 &.mdc-text-field--with-internal-counter {
173 .mdc-text-field__input {
174 @include _textarea-input-with-internal-counter($query);
175 }
176
177 .mdc-text-field-character-counter {
178 @include _textarea-internal-counter($query);
179 }
180 }
181 }
182
183 // Resizer element does not need to be under mdc-text-field--textarea, that
184 // just adds specificity
185 .mdc-text-field__resizer {
186 @include _textarea-resizer($query);
187
188 .mdc-text-field--filled & {
189 @include _textarea-filled-resizer($query);
190
191 .mdc-text-field__input,
192 .mdc-text-field-character-counter {
193 @include _textarea-filled-resizer-children($query);
194 }
195 }
196
197 .mdc-text-field--outlined & {
198 @include _textarea-outlined-resizer($query);
199
200 .mdc-text-field__input,
201 .mdc-text-field-character-counter {
202 @include _textarea-outlined-resizer-children($query);
203 }
204 }
205 }
206
207 .mdc-text-field--with-leading-icon {
208 @include _padding-horizontal-with-leading-icon($query);
209
210 &.mdc-text-field--filled {
211 @include with-leading-icon_($query);
212 }
213
214 &.mdc-text-field--outlined {
215 @include outlined-with-leading-icon_($query);
216 }
217 }
218
219 .mdc-text-field--with-trailing-icon {
220 @include _padding-horizontal-with-trailing-icon($query);
221
222 &.mdc-text-field--filled {
223 @include _with-trailing-icon($query);
224 }
225
226 &.mdc-text-field--outlined {
227 @include _outlined-with-trailing-icon($query);
228 }
229 }
230
231 .mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
232 @include _padding-horizontal-with-both-icons($query);
233
234 &.mdc-text-field--filled {
235 @include _with-leading-and-trailing-icon($query);
236 }
237 }
238
239 // postcss-bem-linter: define text-field-helper-text
240 // stylelint-disable plugin/selector-bem-pattern --
241 // TODO: document why this disable is neccessary
242 .mdc-text-field-helper-line {
243 @include feature-targeting.targets($feat-structure) {
244 display: flex;
245 justify-content: space-between;
246 box-sizing: border-box;
247 }
248
249 .mdc-text-field + & {
250 @include feature-targeting.targets($feat-structure) {
251 padding-right: variables.$helper-line-padding;
252 padding-left: variables.$helper-line-padding;
253 }
254 }
255 }
256 // stylelint-enable plugin/selector-bem-pattern
257 // postcss-bem-linter: end
258
259 // mdc-form-field tweaks to align text field label correctly
260 // stylelint-disable selector-max-type --
261 // TODO: document why this disable is neccessary
262 .mdc-form-field > .mdc-text-field + label {
263 @include feature-targeting.targets($feat-structure) {
264 align-self: flex-start;
265 }
266 }
267 // stylelint-enable selector-max-type
268
269 // States
270 .mdc-text-field--focused {
271 @include focused_($query);
272
273 &.mdc-text-field--outlined {
274 @include _focused-outlined($query);
275
276 &.mdc-text-field--textarea {
277 @include _focused-outlined-textarea($query);
278 }
279 }
280 }
281
282 .mdc-text-field--invalid {
283 @include invalid_($query);
284 }
285
286 .mdc-text-field--disabled {
287 @include disabled_($query);
288
289 &.mdc-text-field--filled {
290 @include _disabled-filled($query);
291 }
292
293 .mdc-text-field__input {
294 @include _disabled-input($query);
295 }
296 }
297
298 .mdc-text-field--end-aligned {
299 @include end-aligned_($query);
300 }
301
302 .mdc-text-field--ltr-text {
303 @include _ltr-text($query);
304
305 &.mdc-text-field--end-aligned {
306 @include _ltr-text-end-aligned($query);
307 }
308 }
309}
310
311// This API is intended for use by frameworks that may want to separate the ripple-related styles
312// from the other text field styles. It is recommended that most users use `mdc-text-field-core-styles` instead.
313@mixin ripple($query: feature-targeting.all()) {
314 @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE
315
316 .mdc-text-field--filled {
317 @include ripple.surface(
318 $query: $query,
319 $ripple-target: variables.$ripple-target
320 );
321 @include ripple.radius-bounded(
322 $query: $query,
323 $ripple-target: variables.$ripple-target
324 );
325 }
326
327 #{variables.$ripple-target} {
328 @include ripple.target-common($query: $query);
329 }
330}
331
332///
333/// Sets density scale for default text field variant.
334///
335/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
336/// `-3`, `-2`, `-1`, `0`. Default is `0`.
337/// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
338/// filled textfields at which to allow floating labels.
339///
340@mixin density(
341 $density-scale,
342 $minimum-height-for-filled-label: variables.$minimum-height-for-filled-label,
343 $query: feature-targeting.all()
344) {
345 $height: density-functions.prop-value(
346 $density-config: variables.$density-config,
347 $density-scale: $density-scale,
348 $property-name: height,
349 );
350
351 @include height(
352 $height,
353 $minimum-height-for-filled-label: $minimum-height-for-filled-label,
354 $query: $query
355 );
356 // TODO(b/151839219): resize icons and adjust label position
357 // @if $density-scale < 0 {
358 // @include icon-mixins.size(icon-variables.$dense-icon-size);
359 // }
360}
361
362///
363/// Sets density scale for outlined text field (Excluding outlined text field with leading icon).
364///
365/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
366/// `-3`, `-2`, `-1`, `0`. Default is `0`.
367///
368@mixin outlined-density($density-scale, $query: feature-targeting.all()) {
369 $height: density-functions.prop-value(
370 $density-config: variables.$density-config,
371 $density-scale: $density-scale,
372 $property-name: height,
373 );
374
375 @include outlined-height($height, $query: $query);
376 // TODO(b/151839219): resize icons and adjust label position
377 // @if $density-scale < 0 {
378 // @include icon-mixins.size(icon-variables.$dense-icon-size);
379 // }
380}
381
382///
383/// Sets density scale for outlined text field with leading icon.
384///
385/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
386/// `-3`, `-2`, `-1`, `0`. Default is `0`.
387///
388@mixin outlined-with-leading-icon-density(
389 $density-scale,
390 $query: feature-targeting.all()
391) {
392 $height: density-functions.prop-value(
393 $density-config: variables.$density-config,
394 $density-scale: $density-scale,
395 $property-name: height,
396 );
397
398 @include outlined-with-leading-icon-height($height, $query: $query);
399 // TODO(b/151839219): resize icons and adjust label position
400 // @if $density-scale < 0 {
401 // @include icon-mixins.size(icon-variables.$dense-icon-size);
402 // }
403}
404
405///
406/// Sets density scale for filled textarea.
407///
408/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
409/// `-3`, `-2`, `-1`, `0`. Default is `0`.
410///
411@mixin filled-textarea-density(
412 $density-scale,
413 $query: feature-targeting.all()
414) {
415 $feat-structure: feature-targeting.create-target($query, structure);
416 $textfield-height: density-functions.prop-value(
417 $density-config: variables.$density-config,
418 $density-scale: $density-scale,
419 $property-name: height,
420 );
421 $no-label-margin-top: density-functions.prop-value(
422 $density-config: variables.$textarea-filled-no-label-density-config,
423 $density-scale: math.div($density-scale, 2),
424 $property-name: margin-top,
425 );
426 $no-label-margin-bottom: density-functions.prop-value(
427 $density-config: variables.$textarea-filled-no-label-density-config,
428 $density-scale: math.div($density-scale, 2),
429 $property-name: margin-bottom,
430 );
431
432 // Textarea mixins require two modifier classes since two are used internally
433 // for styles (textarea and filled). An extra class is added for the public
434 // mixin so that only a single public class is needed for specificity.
435 &.mdc-text-field--filled {
436 .mdc-text-field__resizer {
437 @include feature-targeting.targets($feat-structure) {
438 min-height: $textfield-height;
439 }
440 }
441
442 @if $density-scale >= -1 {
443 $keyframe-suffix: text-field-filled-#{$density-scale};
444 $label-top: density-functions.prop-value(
445 $density-config: variables.$textarea-filled-label-density-config,
446 $density-scale: math.div($density-scale, 2),
447 $property-name: top,
448 );
449
450 // Adjust the floating position and animation/keyframes of the floating
451 // label by the new position of the resting label
452 $label-top-difference: variables.$textarea-outlined-label-top -
453 $label-top;
454
455 // Floating label position
456 @include floating-label-mixins.float-position(
457 variables.$textarea-filled-label-position-y - $label-top-difference,
458 $query: $query
459 );
460
461 // Floating label animation
462 @include floating-label-mixins.shake-animation(
463 $keyframe-suffix,
464 $query: $query
465 );
466 @at-root {
467 @include floating-label-mixins.shake-keyframes(
468 $keyframe-suffix,
469 variables.$textarea-filled-label-position-y - $label-top-difference,
470 0%,
471 $query: $query
472 );
473 }
474
475 // Resting label position
476 .mdc-floating-label {
477 @include feature-targeting.targets($feat-structure) {
478 top: $label-top;
479 }
480 }
481
482 $margin-bottom: density-functions.prop-value(
483 $density-config: variables.$textarea-filled-density-config,
484 $density-scale: $density-scale,
485 $property-name: margin-bottom,
486 );
487
488 .mdc-text-field__input {
489 @include feature-targeting.targets($feat-structure) {
490 margin-bottom: $margin-bottom;
491 }
492 }
493 } @else {
494 // The textarea is too dense to show a floating label
495 .mdc-floating-label {
496 @include feature-targeting.targets($feat-structure) {
497 display: none;
498 }
499 }
500
501 .mdc-text-field__input {
502 @include feature-targeting.targets($feat-structure) {
503 margin-top: $no-label-margin-top;
504 margin-bottom: $no-label-margin-bottom;
505 }
506 }
507 }
508
509 &.mdc-text-field--no-label {
510 .mdc-text-field__input {
511 @include feature-targeting.targets($feat-structure) {
512 margin-top: $no-label-margin-top;
513 margin-bottom: $no-label-margin-bottom;
514 }
515 }
516 }
517
518 &.mdc-text-field--with-internal-counter {
519 .mdc-text-field__input {
520 // Space between textarea and internal counter should not be affected
521 @include _textarea-input-with-internal-counter($query);
522 }
523 }
524 }
525}
526
527///
528/// Sets density scale for outlined textarea.
529///
530/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
531/// `-3`, `-2`, `-1`, `0`. Default is `0`.
532///
533@mixin outlined-textarea-density(
534 $density-scale,
535 $query: feature-targeting.all()
536) {
537 $feat-structure: feature-targeting.create-target($query, structure);
538 $keyframe-suffix: text-field-outlined-#{$density-scale};
539 $label-top: density-functions.prop-value(
540 $density-config: variables.$textarea-outlined-label-density-config,
541 $density-scale: math.div($density-scale, 2),
542 $property-name: top,
543 );
544 $textfield-height: density-functions.prop-value(
545 $density-config: variables.$density-config,
546 $density-scale: $density-scale,
547 $property-name: height,
548 );
549 $margin-top: density-functions.prop-value(
550 $density-config: variables.$textarea-outlined-density-config,
551 $density-scale: math.div($density-scale, 2),
552 $property-name: margin-top,
553 );
554 $margin-bottom: density-functions.prop-value(
555 $density-config: variables.$textarea-outlined-density-config,
556 $density-scale: math.div($density-scale, 2),
557 $property-name: margin-bottom,
558 );
559
560 // Textarea mixins require two modifier classes since two are used internally
561 // for styles (textarea and outlined). An extra class is added for the public
562 // mixin so that only a single public class is needed for specificity.
563 &.mdc-text-field--outlined {
564 // Adjust the floating position and animation/keyframes of the floating
565 // label by the new position of the resting label
566 $label-top-difference: variables.$textarea-outlined-label-top - $label-top;
567
568 // Floating label position
569 @include notched-outline-mixins.floating-label-float-position-absolute(
570 variables.$textarea-outlined-label-position-y - $label-top-difference,
571 $query: $query
572 );
573
574 // Floating label animation
575 @include floating-label-mixins.shake-animation(
576 $keyframe-suffix,
577 $query: $query
578 );
579 @at-root {
580 @include floating-label-mixins.shake-keyframes(
581 $keyframe-suffix,
582 variables.$textarea-outlined-label-position-y - $label-top-difference,
583 0%,
584 $query: $query
585 );
586 }
587
588 // Resting label position
589 .mdc-floating-label {
590 @include feature-targeting.targets($feat-structure) {
591 top: $label-top;
592 }
593 }
594
595 .mdc-text-field__resizer {
596 @include feature-targeting.targets($feat-structure) {
597 min-height: $textfield-height;
598 }
599 }
600
601 .mdc-text-field__input {
602 @include feature-targeting.targets($feat-structure) {
603 margin-top: $margin-top;
604 margin-bottom: $margin-bottom;
605 }
606 }
607
608 &.mdc-text-field--with-internal-counter {
609 .mdc-text-field__input {
610 // Space between textarea and internal counter should not be affected
611 @include _textarea-input-with-internal-counter($query);
612 }
613 }
614 }
615}
616
617///
618/// Sets the minimum number of rows for a textarea a textarea may be resized to.
619///
620/// For IE11 this mixin can be used instead of the rows attribute.
621///
622/// @param {Number} $rows - The minimum number of rows for a textarea.
623/// @param {Number} $line-height - The line-height of the textarea.
624///
625@mixin textarea-min-rows(
626 $rows,
627 $line-height: variables.$textarea-line-height,
628 $query: feature-targeting.all()
629) {
630 $feat-structure: feature-targeting.create-target($query, structure);
631
632 .mdc-text-field__input {
633 @include feature-targeting.targets($feat-structure) {
634 min-height: $rows * $line-height;
635 }
636 }
637}
638
639///
640/// Sets height of default text field variant.
641///
642/// @param {Number} $height
643/// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
644/// filled textfields at which to allow floating labels.
645/// @access public
646///
647@mixin height(
648 $height,
649 $minimum-height-for-filled-label: variables.$minimum-height-for-filled-label,
650 $query: feature-targeting.all()
651) {
652 $feat-structure: feature-targeting.create-target($query, structure);
653 @include feature-targeting.targets($feat-structure) {
654 height: $height;
655 }
656
657 @if $height < $minimum-height-for-filled-label {
658 @include _filled-no-label($query: $query);
659 }
660}
661
662///
663/// Sets height of outlined text field variant (Excluding outlined text field with leading icon).
664///
665/// @param {Number} $height
666/// @param {String} $keyframe-suffix - Optional suffix to use for generated
667/// floating label keyframes
668/// @access public
669///
670@mixin outlined-height(
671 $height,
672 $keyframe-suffix: text-field-outlined-#{$height},
673 $query: feature-targeting.all()
674) {
675 $feat-structure: feature-targeting.create-target($query, structure);
676 $positionY: variables.get-outlined-label-position-y($height);
677
678 // Floating label position
679 @include notched-outline-mixins.floating-label-float-position-absolute(
680 $positionY,
681 $query: $query
682 );
683
684 // Floating label animation
685 @include floating-label-mixins.shake-animation(
686 $keyframe-suffix,
687 $query: $query
688 );
689 @at-root {
690 @include floating-label-mixins.shake-keyframes(
691 $keyframe-suffix,
692 $positionY,
693 $query: $query
694 );
695 }
696
697 @include feature-targeting.targets($feat-structure) {
698 height: $height;
699 }
700}
701
702///
703/// Sets height of outlined text field with leading icon variant.
704///
705/// @param {Number} $height
706/// @param {String} $keyframe-suffix - Optional suffix to use for generated
707/// floating label keyframes
708/// @access public
709///
710@mixin outlined-with-leading-icon-height(
711 $height,
712 $keyframe-suffix: null,
713 $query: feature-targeting.all()
714) {
715 $feat-structure: feature-targeting.create-target($query, structure);
716
717 // This extra specificity is needed because textfield applies the below mixin
718 // already to two selectors (outlined + with-leading-icon). To override
719 // them with a new label position and animation, another selector is needed.
720 &.mdc-text-field--outlined {
721 @include _outlined-with-leading-icon-floating-label-position-animation(
722 $height,
723 $keyframe-suffix,
724 $query
725 );
726 }
727
728 @include feature-targeting.targets($feat-structure) {
729 height: $height;
730 }
731}
732
733// Mixin that sets the floating label position and animations for a given height.
734// This mixin is separate to allow outlined-with-leading-icon-height() to
735// provide greater specificity over the default mixin that adds styles for
736// outlined with leading icons.
737@mixin _outlined-with-leading-icon-floating-label-position-animation(
738 $height,
739 $keyframe-suffix: text-field-outlined-with-leading-icon-#{$height},
740 $query: feature-targeting.all()
741) {
742 $positionY: variables.get-outlined-label-position-y($height);
743
744 // Floating label position
745 @include notched-outline-mixins.floating-label-float-position-absolute(
746 $positionY,
747 variables.$outlined-with-leading-icon-label-position-x,
748 $query: $query
749 );
750
751 // Floating label animation
752 @include floating-label-mixins.shake-animation(
753 $keyframe-suffix,
754 $query: $query
755 );
756 @at-root {
757 @include floating-label-mixins.shake-keyframes(
758 $keyframe-suffix,
759 $positionY,
760 variables.$outlined-with-leading-icon-label-position-x,
761 $query: $query
762 );
763 }
764
765 $keyframe-suffix-rtl: #{$keyframe-suffix}-rtl;
766 @include rtl.rtl {
767 @include floating-label-mixins.shake-animation(
768 $keyframe-suffix,
769 $query: $query
770 );
771 }
772 @at-root {
773 @include floating-label-mixins.shake-keyframes(
774 $keyframe-suffix-rtl,
775 $positionY,
776 -(variables.$outlined-with-leading-icon-label-position-x),
777 $query: $query
778 );
779 }
780}
781
782///
783/// Sets shape radius of default text field variant.
784///
785/// @param {Number} $radius Shape radius value in `px` or in percentage.
786/// @param {Number} $text-field-height Height of default text field variant. Required only when `$radius` is in
787/// percentage unit and if text field has custom height. Defaults to `variables.$height`.
788/// @param {Boolean} $rtl-reflexive Set to true to flip shape radius in RTL context. Defaults to `false`.
789///
790@mixin shape-radius(
791 $radius,
792 $density-scale: variables.$density-scale,
793 $rtl-reflexive: false,
794 $query: feature-targeting.all()
795) {
796 @if meta.type-of($radius) == 'list' and list.length($radius) > 2 {
797 @error "mdc-textfield: Invalid radius #{$radius}. Only top-left and top-right corners may be customized.";
798 }
799
800 $height: density-functions.prop-value(
801 $density-config: variables.$density-config,
802 $density-scale: $density-scale,
803 $property-name: height,
804 );
805
806 $masked-radius: shape-functions.mask-radius($radius, 1 1 0 0);
807
808 @include shape-mixins.radius(
809 $masked-radius,
810 $rtl-reflexive,
811 $component-height: $height,
812 $query: $query
813 );
814}
815
816@mixin textarea-shape-radius(
817 $radius,
818 $rtl-reflexive: false,
819 $query: feature-targeting.all()
820) {
821 @include notched-outline-mixins.shape-radius(
822 $radius,
823 $rtl-reflexive,
824 $query: $query
825 );
826}
827
828///
829/// Customizes the color of the text entered into an enabled text field.
830/// @param {Color} $color - The desired input text color.
831///
832@mixin ink-color($color, $query: feature-targeting.all()) {
833 @include if-enabled_ {
834 @include ink-color_($color, $query: $query);
835 }
836}
837
838///
839/// Customizes the color of the entered text in a disabled text field.
840/// @param {Color} $color - The desired input text color.
841///
842@mixin disabled-ink-color($color, $query: feature-targeting.all()) {
843 @include if-disabled_ {
844 @include ink-color_($color, $query: $query);
845 }
846}
847
848///
849/// Customizes the color of the placeholder in an enabled text field.
850/// @param {Color} $color - The desired placeholder text color.
851///
852@mixin placeholder-color($color, $query: feature-targeting.all()) {
853 @include if-enabled_ {
854 @include placeholder-color_($color, $query: $query);
855 }
856}
857
858///
859/// Customizes the color of the placeholder in a disabled text field.
860/// @param {Color} $color - The desired placeholder text color.
861///
862@mixin disabled-placeholder-color($color, $query: feature-targeting.all()) {
863 @include if-disabled_ {
864 @include placeholder-color_($color, $query: $query);
865 }
866}
867
868///
869/// Customizes the background color of the text field or textarea when enabled.
870/// @param {Color} $color - The desired background color.
871///
872@mixin fill-color($color, $query: feature-targeting.all()) {
873 @include if-enabled_ {
874 @include fill-color_($color, $query: $query);
875 }
876}
877
878///
879/// Customizes the background color of the text field or textarea when disabled.
880/// @param {Color} $color - The desired background color.
881///
882@mixin disabled-fill-color($color, $query: feature-targeting.all()) {
883 @include if-disabled_ {
884 @include fill-color_($color, $query: $query);
885 }
886}
887
888///
889/// Customizes the text field bottom line color for the filled variant.
890/// @param {Color} $color - The desired bottom line color.
891///
892@mixin bottom-line-color($color, $query: feature-targeting.all()) {
893 @include if-enabled_ {
894 @include bottom-line-color_($color, $query: $query);
895 }
896}
897
898///
899/// Customizes the disabled text field bottom line color for the filled variant.
900/// @param {Color} $color - The desired bottom line color.
901///
902@mixin disabled-bottom-line-color($color, $query: feature-targeting.all()) {
903 @include if-disabled_ {
904 @include bottom-line-color_($color, $query: $query);
905 }
906}
907
908///
909/// Customizes the hover text field bottom line color for the filled variant.
910/// @param {Color} $color - The desired bottom line color.
911///
912@mixin hover-bottom-line-color($color, $query: feature-targeting.all()) {
913 @include if-enabled_ {
914 @include hover-bottom-line-color_($color, $query: $query);
915 }
916}
917
918///
919/// Customizes the color of the default line ripple of the text field.
920/// @param {Color} $color - The desired line ripple color.
921///
922@mixin line-ripple-color($color, $query: feature-targeting.all()) {
923 @include if-enabled_ {
924 @include line-ripple-color_($color, $query: $query);
925 }
926}
927
928///
929/// Customizes the text color of the label in an enabled text field.
930/// @param {Color} $color - The desired label text color.
931///
932@mixin label-color($color, $query: feature-targeting.all()) {
933 @include if-enabled_ {
934 @include label-ink-color_($color, $query: $query);
935 }
936}
937
938///
939/// Customizes the text color of the label in a disabled text field.
940/// @param {Color} $color - The desired label text color.
941///
942@mixin disabled-label-color($color, $query: feature-targeting.all()) {
943 @include if-disabled_ {
944 @include label-ink-color_($color, $query: $query);
945 }
946}
947
948///
949/// Customizes the border color of the outlined text field or textarea.
950/// @param {Color} $color - The desired outline border color.
951///
952@mixin outline-color($color, $query: feature-targeting.all()) {
953 @include if-enabled_ {
954 @include notched-outline-mixins.color($color, $query: $query);
955 }
956}
957
958///
959/// Customizes the outline border color when the text field or textarea is hovered.
960/// @param {Color} $color - The desired outline border color.
961///
962@mixin hover-outline-color($color, $query: feature-targeting.all()) {
963 @include if-enabled_ {
964 @include hover-outline-color_($color, $query: $query);
965 }
966}
967
968///
969/// Customizes the outline border color when the text field or textarea is focused.
970/// @param {Color} $color - The desired outline border color.
971///
972@mixin focused-outline-color($color, $query: feature-targeting.all()) {
973 @include if-enabled_ {
974 @include focused-outline-color_($color, $query: $query);
975 }
976}
977
978///
979/// Customizes the outline border color when the text field or textarea is disabled.
980/// @param {Color} $color - The desired outline border color.
981///
982@mixin disabled-outline-color($color, $query: feature-targeting.all()) {
983 @include if-disabled_ {
984 @include notched-outline-mixins.color($color, $query: $query);
985 }
986}
987
988///
989/// Customizes the caret color of the text field or textarea.
990/// @param {Color} $color - The desired caret color.
991///
992@mixin caret-color($color, $query: feature-targeting.all()) {
993 $feat-color: feature-targeting.create-target($query, color);
994
995 .mdc-text-field__input {
996 @include feature-targeting.targets($feat-color) {
997 @include theme.prop(caret-color, $color);
998 }
999 }
1000}
1001
1002///
1003/// Customizes the color of the prefix text for an enabled text field.
1004/// @param {Color} $color - The desired prefix text color.
1005///
1006@mixin prefix-color($color, $query: feature-targeting.all()) {
1007 @include if-enabled_ {
1008 @include _prefix-color($color, $query: $query);
1009 }
1010}
1011
1012///
1013/// Customizes the color of the prefix text for a disabled text field.
1014/// @param {Color} $color - The desired prefix text color.
1015///
1016@mixin disabled-prefix-color($color, $query: feature-targeting.all()) {
1017 @include if-disabled_ {
1018 @include _prefix-color($color, $query: $query);
1019 }
1020}
1021
1022///
1023/// Customizes the color of the suffix text for an enabled text field.
1024/// @param {Color} $color - The desired suffix text color.
1025///
1026@mixin suffix-color($color, $query: feature-targeting.all()) {
1027 @include if-enabled_ {
1028 @include _suffix-color($color, $query: $query);
1029 }
1030}
1031
1032///
1033/// Customizes the color of the suffix text for a disabled text field.
1034/// @param {Color} $color - The desired suffix text color.
1035///
1036@mixin disabled-suffix-color($color, $query: feature-targeting.all()) {
1037 @include if-disabled_ {
1038 @include _suffix-color($color, $query: $query);
1039 }
1040}
1041
1042///
1043/// Sets shape radius of outlined text field variant.
1044///
1045/// @param {Number} $radius Shape radius value in `px` or in percentage.
1046/// @param {Number} $text-field-height Height of outlined text field variant. Required only when `$radius` is in
1047/// percentage unit and if text field has custom height. Defaults to `variables.$height`.
1048/// @param {Boolean} $rtl-reflexive Set to true to flip shape radius in RTL context. Defaults to `false`.
1049///
1050@mixin outline-shape-radius(
1051 $radius,
1052 $density-scale: variables.$density-scale,
1053 $rtl-reflexive: false,
1054 $query: feature-targeting.all()
1055) {
1056 $feat-structure: feature-targeting.create-target($query, structure);
1057 $height: density-functions.prop-value(
1058 $density-config: variables.$density-config,
1059 $density-scale: $density-scale,
1060 $property-name: height,
1061 );
1062
1063 .mdc-notched-outline {
1064 @include notched-outline-mixins.shape-radius(
1065 $radius,
1066 $rtl-reflexive,
1067 $component-height: $height,
1068 $query: $query
1069 );
1070 }
1071
1072 $resolved-radius: shape-functions.resolve-radius(
1073 $radius,
1074 $component-height: $height
1075 );
1076 $unpacked-radius: shape-functions.unpack-radius($resolved-radius);
1077 $top-left-radius: list.nth($unpacked-radius, 1);
1078 $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius);
1079 $top-left-radius-px: $top-left-radius;
1080 @if ($top-left-is-custom-prop) {
1081 $top-left-radius-px: custom-properties.get-fallback($top-left-radius);
1082 }
1083 $top-right-radius: list.nth($unpacked-radius, 2);
1084 $top-right-is-custom-prop: custom-properties.is-custom-prop(
1085 $top-right-radius
1086 );
1087
1088 @if (
1089 $top-left-is-custom-prop or
1090 $top-right-is-custom-prop or
1091 $top-left-radius-px >
1092 notched-outline-variables.$leading-width
1093 ) {
1094 // The horizontal padding only needs to be overriden from the base padding
1095 // if the radius is a custom property, or if the top-left radius is a value
1096 // that is large than that default notched outline's leading width.
1097 @include _outline-shape-radius-horizontal-padding(
1098 $top-left-radius,
1099 $top-right-radius,
1100 $query: $query
1101 );
1102
1103 + .mdc-text-field-helper-line {
1104 @include _outline-shape-radius-horizontal-padding(
1105 $top-left-radius,
1106 $top-right-radius,
1107 $query: $query
1108 );
1109 }
1110
1111 // Ensure that leading/trailing icon padding is overriden. Even if the
1112 // top left/right isn't a custom property or the leading isn't larger, we
1113 // still need to override. The above left/right padding rules have more
1114 // specificty than the original leading/trailing icon rules, so we need to
1115 // re-apply them.
1116 // Additionally, if the top left/right radii _are_ custom properties, we
1117 // should use those instead.
1118
1119 &.mdc-text-field--with-leading-icon {
1120 @if ($top-right-is-custom-prop) {
1121 @include feature-targeting.targets($feat-structure) {
1122 @include rtl.ignore-next-line();
1123 padding-left: 0;
1124 }
1125 @include _apply-outline-shape-padding(
1126 padding-right,
1127 $top-right-radius,
1128 $query: $query
1129 );
1130
1131 @include rtl.rtl {
1132 @include _apply-outline-shape-padding(
1133 padding-left,
1134 $top-right-radius,
1135 $query: $query
1136 );
1137 @include feature-targeting.targets($feat-structure) {
1138 @include rtl.ignore-next-line();
1139 padding-right: 0;
1140 }
1141 }
1142 } @else {
1143 @include _padding-horizontal-with-leading-icon($query);
1144 }
1145 }
1146
1147 &.mdc-text-field--with-trailing-icon {
1148 @if (
1149 $top-left-is-custom-prop or
1150 $top-left-radius-px >
1151 notched-outline-variables.$leading-width
1152 ) {
1153 @include _apply-outline-shape-padding(
1154 padding-left,
1155 $top-left-radius,
1156 $add-label-padding: true,
1157 $query: $query
1158 );
1159 @include feature-targeting.targets($feat-structure) {
1160 @include rtl.ignore-next-line();
1161 padding-right: 0;
1162 }
1163
1164 @include rtl.rtl {
1165 @include feature-targeting.targets($feat-structure) {
1166 @include rtl.ignore-next-line();
1167 padding-left: 0;
1168 }
1169 @include _apply-outline-shape-padding(
1170 padding-right,
1171 $top-left-radius,
1172 $add-label-padding: true,
1173 $query: $query
1174 );
1175 }
1176 } @else {
1177 @include _padding-horizontal-with-trailing-icon($query);
1178 }
1179 }
1180
1181 &.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
1182 @include _padding-horizontal-with-both-icons($query);
1183 }
1184 }
1185}
1186
1187@mixin _outline-shape-radius-horizontal-padding(
1188 $top-left-radius,
1189 $top-right-radius,
1190 $query: feature-targeting.all()
1191) {
1192 @include _apply-outline-shape-padding(
1193 padding-left,
1194 $top-left-radius,
1195 $add-label-padding: true,
1196 $query: $query
1197 );
1198 @include _apply-outline-shape-padding(
1199 padding-right,
1200 $top-right-radius,
1201 $query: $query
1202 );
1203
1204 $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius);
1205 $top-left-radius-px: $top-left-radius;
1206 @if ($top-left-is-custom-prop) {
1207 $top-left-radius-px: custom-properties.get-fallback($top-left-radius);
1208 }
1209 $top-right-is-custom-prop: custom-properties.is-custom-prop(
1210 $top-right-radius
1211 );
1212 $top-right-radius-px: $top-right-radius;
1213 @if ($top-right-is-custom-prop) {
1214 $top-right-radius-px: custom-properties.get-fallback($top-right-radius);
1215 }
1216
1217 @if (
1218 (
1219 $top-left-is-custom-prop and
1220 $top-right-is-custom-prop and not
1221 custom-properties.are-equal($top-left-radius, $top-right-radius)
1222 ) or
1223 $top-left-radius-px !=
1224 $top-right-radius-px
1225 ) {
1226 // Normally base horizontal padding doesn't need RTL, but if the values
1227 // are different or they are two different custom properties, they need to
1228 // be reversed.
1229 @include rtl.rtl {
1230 @include _apply-outline-shape-padding(
1231 padding-right,
1232 $top-left-radius,
1233 $add-label-padding: true,
1234 $query: $query
1235 );
1236 @include _apply-outline-shape-padding(
1237 padding-left,
1238 $top-right-radius,
1239 $query: $query
1240 );
1241 }
1242 }
1243}
1244
1245@mixin _apply-outline-shape-padding(
1246 $property,
1247 $padding,
1248 $add-label-padding: false,
1249 $query: feature-targeting.all()
1250) {
1251 $feat-structure: feature-targeting.create-target($query, structure);
1252 $padding-is-custom-prop: custom-properties.is-custom-prop($padding);
1253 $padding-px: $padding;
1254 @if ($padding-is-custom-prop) {
1255 $padding-px: custom-properties.get-fallback($padding);
1256 }
1257
1258 @include feature-targeting.targets($feat-structure) {
1259 // The shape should only change the padding if the radius becomes greater
1260 // than the default padding. That means we need to add more padding.
1261 @if ($padding-px > variables.$padding-horizontal) {
1262 // Set a px value if it's greater. This is either the only value (if
1263 // we're given an exact value), or an IE11 fallback if we're given a
1264 // custom property and the fallback value is greater than the padding.
1265 $value: $padding-px;
1266 @if ($add-label-padding) {
1267 // If this is for the top-left leading, add the notched outline padding
1268 // to keep it aligned with the label
1269 $value: $padding-px + notched-outline-variables.$padding;
1270 }
1271
1272 @include rtl.ignore-next-line();
1273 #{$property}: $value;
1274 @if ($padding-is-custom-prop) {
1275 // Add an alternate GSS tag b/c this was an IE11 fallback and we're
1276 // going to add another property with the var() value
1277 /* @alternate */
1278 }
1279 }
1280 @if ($padding-is-custom-prop) {
1281 // If it's a custom property, always add it since the value may change
1282 // to be greater than the padding at runtime, even if the fallback is
1283 // not currently greater than the default padding.
1284 $value: custom-properties.create-var($padding);
1285 @if ($add-label-padding) {
1286 $value: calc(#{$value} + #{notched-outline-variables.$padding});
1287 }
1288
1289 // Interpolation is a workaround for sass/sass#3259.
1290 @supports (top: max(#{0%})) {
1291 // A max() function makes this runtime dynamic. The padding will be
1292 // whichever is greater: the default horizontal padding, or the calculated
1293 // custom property plus extra padding.
1294 @include rtl.ignore-next-line();
1295 #{$property}: max(#{variables.$padding-horizontal}, #{$value});
1296 }
1297 }
1298 }
1299}
1300
1301///
1302/// Sets the CSS transition for the floating label's 'float' animation.
1303///
1304/// @param {Number} $duration-ms - Duration (in ms) of the animation.
1305/// @param {String} $timing-function - Optionally overrides the default animation timing function.
1306///
1307@mixin floating-label-float-transition(
1308 $duration-ms,
1309 $timing-function: null,
1310 $query: feature-targeting.all()
1311) {
1312 .mdc-floating-label {
1313 @include floating-label-mixins.float-transition(
1314 $duration-ms,
1315 $timing-function,
1316 $query: $query
1317 );
1318 }
1319}
1320
1321///
1322/// Sets custom font size of the input.
1323///
1324/// @param {number} $font-size - Overrides the font size.
1325///
1326@mixin input-font-size($font-size, $query: feature-targeting.all()) {
1327 $feat-typography: feature-targeting.create-target($query, typography);
1328
1329 .mdc-text-field__input {
1330 @include feature-targeting.targets($feat-typography) {
1331 font-size: $font-size;
1332 }
1333 }
1334}
1335
1336///
1337/// Sets custom font family of the input.
1338///
1339/// @param {String} $font-family - Selected font family.
1340///
1341@mixin input-font-family($font-family, $query: feature-targeting.all()) {
1342 $feat-typography: feature-targeting.create-target($query, typography);
1343
1344 .mdc-text-field__input {
1345 @include feature-targeting.targets($feat-typography) {
1346 font-family: $font-family;
1347 }
1348 }
1349}
1350
1351// Private mixins
1352
1353// Base shared styles
1354@mixin _base($query: feature-targeting.all()) {
1355 $feat-structure: feature-targeting.create-target($query, structure);
1356
1357 // Shape
1358 @include shape-radius(variables.$shape-radius, $query: $query);
1359
1360 // Colors
1361 @include label-color(variables.$label, $query: $query);
1362 @include ink-color(variables.$ink-color, $query: $query);
1363 @include placeholder-color(variables.$placeholder-ink-color, $query: $query);
1364 @include caret-color(primary, $query: $query);
1365 @include helper-text-mixins.helper-text-color(
1366 variables.$helper-text-color,
1367 $query: $query
1368 );
1369 @include character-counter-mixins.character-counter-color(
1370 variables.$helper-text-color,
1371 $query: $query
1372 );
1373 @include icon-mixins.leading-icon-color(
1374 variables.$icon-color,
1375 $query: $query
1376 );
1377 @include icon-mixins.trailing-icon-color(
1378 variables.$icon-color,
1379 $query: $query
1380 );
1381 @include prefix-color(variables.$affix-color, $query: $query);
1382 @include suffix-color(variables.$affix-color, $query: $query);
1383
1384 // Floating Label
1385 @include floating-label_($query);
1386
1387 @include feature-targeting.targets($feat-structure) {
1388 // display and align-items are necessary to make the text field participate
1389 // in baseline alignment, even though some variants are 'centered'. Those
1390 // variants should use the _baseline-center-aligned() mixin
1391 display: inline-flex;
1392 align-items: baseline;
1393 padding: 0 variables.$padding-horizontal;
1394 position: relative;
1395 box-sizing: border-box;
1396 overflow: hidden;
1397 /* @alternate */
1398 will-change: opacity, transform, color;
1399 }
1400}
1401
1402// This mixin adds styles to visually center the text within the text field.
1403// Sibling text will align to the baseline and appear centered next to the
1404// text field.
1405@mixin _baseline-center-aligned($query: feature-targeting.all()) {
1406 $feat-structure: feature-targeting.create-target($query, structure);
1407
1408 @include feature-targeting.targets($feat-structure) {
1409 // In order for a flexbox container to participate in baseline alignment,
1410 // it follows these rules to determine where its baseline is:
1411 // https://www.w3.org/TR/css-flexbox-1/#flex-baselines
1412 //
1413 // In order to avoid leading icons 'controlling' the baseline (since they
1414 // are the first child), flexbox will generate a baseline from any child
1415 // flex items that participate in baseline alignment.
1416 //
1417 // Icons are set to "align-self: center", while all other children are
1418 // aligned to baseline. The next problem is deciding which child is
1419 // used to determine the baseline.
1420 //
1421 // According to spec, the item with the largest distance between its
1422 // baseline and the edge of the cross axis is placed flush with that edge,
1423 // making it the baseline of the container.
1424 // https://www.w3.org/TR/css-flexbox-1/#baseline-participation
1425 //
1426 // For the filled variant, the pseudo ::before strut is the 'largest'
1427 // child since the input has a height of 28px and the strut is 40px. We
1428 // can emulate center alignment and force the baseline to use the input
1429 // text by making the input the full height of the container and removing
1430 // the baseline strut.
1431
1432 // IE11 does not respect this, and makes the leading icon (if present) the
1433 // baseline. This is a gap with IE11 that we have accepted.
1434 .mdc-text-field__input {
1435 height: 100%;
1436 }
1437 }
1438}
1439
1440@mixin _padding-horizontal-with-leading-icon($query: feature-targeting.all()) {
1441 $feat-structure: feature-targeting.create-target($query, structure);
1442
1443 @include feature-targeting.targets($feat-structure) {
1444 @include rtl.reflexive-property(padding, 0, variables.$padding-horizontal);
1445 }
1446}
1447
1448@mixin _padding-horizontal-with-trailing-icon($query: feature-targeting.all()) {
1449 $feat-structure: feature-targeting.create-target($query, structure);
1450
1451 @include feature-targeting.targets($feat-structure) {
1452 @include rtl.reflexive-property(padding, variables.$padding-horizontal, 0);
1453 }
1454}
1455
1456@mixin _padding-horizontal-with-both-icons($query: feature-targeting.all()) {
1457 $feat-structure: feature-targeting.create-target($query, structure);
1458
1459 @include feature-targeting.targets($feat-structure) {
1460 @include rtl.ignore-next-line();
1461 padding-left: 0;
1462 @include rtl.ignore-next-line();
1463 padding-right: 0;
1464 }
1465}
1466
1467@mixin floating-label_($query: feature-targeting.all()) {
1468 $feat-structure: feature-targeting.create-target($query, structure);
1469
1470 .mdc-floating-label {
1471 @include feature-targeting.targets($feat-structure) {
1472 top: 50%;
1473 transform: translateY(-50%);
1474 pointer-events: none;
1475 }
1476 }
1477}
1478
1479// Filled
1480
1481@mixin _filled($query: feature-targeting.all()) {
1482 // Text Field intentionally omits press ripple, so each state needs to be specified individually.
1483 @include ripple-theme.states-base-color(
1484 variables.$ink-color,
1485 $query: $query,
1486 $ripple-target: variables.$ripple-target
1487 );
1488 @include ripple-theme.states-hover-opacity(
1489 ripple-theme.states-opacity(variables.$ink-color, hover),
1490 $query: $query,
1491 $ripple-target: variables.$ripple-target
1492 );
1493 @include ripple-theme.states-focus-opacity(
1494 ripple-theme.states-opacity(variables.$ink-color, focus),
1495 $query: $query,
1496 $ripple-target: variables.$ripple-target
1497 );
1498
1499 @include height(variables.$height, $query: $query);
1500 @include typography.baseline-top(
1501 variables.$filled-baseline-top,
1502 $query: $query
1503 );
1504 @include fill-color(variables.$background, $query: $query);
1505 @include bottom-line-color(variables.$bottom-line-idle, $query: $query);
1506 @include hover-bottom-line-color(
1507 variables.$bottom-line-hover,
1508 $query: $query
1509 );
1510 @include line-ripple-color_(primary, $query: $query);
1511 @include _filled-floating-label($query);
1512}
1513
1514@mixin _filled-floating-label($query: feature-targeting.all()) {
1515 $feat-structure: feature-targeting.create-target($query, structure);
1516
1517 .mdc-floating-label {
1518 @include feature-targeting.targets($feat-structure) {
1519 @include rtl.reflexive-position(left, variables.$label-offset);
1520 }
1521 }
1522
1523 @include floating-label-mixins.float-position(
1524 variables.$label-position-y,
1525 $query: $query
1526 );
1527}
1528
1529// Filled variant with no label. This variant centers the text elements and
1530// hides the label and is used with there is explicitly no label provided or
1531// when the height of the text field is too small for a label to be allowed.
1532@mixin _filled-no-label($query: feature-targeting.all()) {
1533 $feat-structure: feature-targeting.create-target($query, structure);
1534
1535 @include _baseline-center-aligned($query);
1536 @include feature-targeting.targets($feat-structure) {
1537 .mdc-floating-label {
1538 display: none;
1539 }
1540
1541 &::before {
1542 // Remove baseline-top strut
1543 display: none;
1544 }
1545 }
1546
1547 // Safari only
1548 @supports (-webkit-hyphens: none) {
1549 .mdc-text-field__affix {
1550 @include _centered-affix-safari-support($query: $query);
1551 }
1552 }
1553}
1554
1555// Outlined
1556
1557@mixin outlined_($query: feature-targeting.all()) {
1558 $feat-structure: feature-targeting.create-target($query, structure);
1559
1560 @include outlined-height(
1561 $height: variables.$height,
1562 $keyframe-suffix: text-field-outlined,
1563 $query: $query
1564 );
1565 @include _baseline-center-aligned($query: $query);
1566 @include outline-color(variables.$outlined-idle-border, $query: $query);
1567 @include hover-outline-color(
1568 variables.$outlined-hover-border,
1569 $query: $query
1570 );
1571 @include focused-outline-color(primary, $query: $query);
1572 @include outline-shape-radius(variables.$shape-radius, $query: $query);
1573 @include notched-outline-mixins.notch-offset(
1574 notched-outline-variables.$border-width,
1575 $query: $query
1576 );
1577 @include ripple-theme.states-base-color(
1578 transparent,
1579 $query: $query,
1580 $ripple-target: variables.$ripple-target
1581 );
1582 @include _outlined-floating-label($query);
1583
1584 @include feature-targeting.targets($feat-structure) {
1585 overflow: visible;
1586 }
1587
1588 .mdc-text-field__input {
1589 @include feature-targeting.targets($feat-structure) {
1590 // TODO(b/154349735): Investigate the neccessity of these styles
1591 display: flex;
1592 border: none !important; // FF adds unwanted border in HC mode on windows.
1593 background-color: transparent;
1594 }
1595 }
1596}
1597
1598@mixin _outlined-floating-label($query: feature-targeting.all()) {
1599 $feat-structure: feature-targeting.create-target($query, structure);
1600
1601 .mdc-floating-label {
1602 @include feature-targeting.targets($feat-structure) {
1603 @include rtl.reflexive-position(left, notched-outline-variables.$padding);
1604 }
1605 }
1606}
1607
1608@mixin _outlined-notched-outline($query: feature-targeting.all()) {
1609 $feat-structure: feature-targeting.create-target($query, structure);
1610
1611 @include feature-targeting.targets($feat-structure) {
1612 // Force the outline to appear "above" the textfield elements, even though
1613 // it is absolutely positioned and comes before the input in the DOM. This
1614 // is primarily for the textarea scrollbar and resize elements, which may
1615 // clip with with outline border.
1616 z-index: 1;
1617 }
1618}
1619
1620// States
1621
1622@mixin disabled_($query: feature-targeting.all()) {
1623 $feat-structure: feature-targeting.create-target($query, structure);
1624
1625 @include ink-color_(variables.$disabled-ink-color, $query: $query);
1626 @include placeholder-color_(
1627 variables.$disabled-placeholder-ink-color,
1628 $query: $query
1629 );
1630 @include label-ink-color_(variables.$disabled-label-color, $query: $query);
1631 @include helper-text-mixins.helper-text-color_(
1632 variables.$disabled-helper-text-color,
1633 $query: $query
1634 );
1635 @include character-counter-mixins.character-counter-color_(
1636 variables.$disabled-helper-text-color,
1637 $query: $query
1638 );
1639 @include icon-mixins.leading-icon-color_(
1640 variables.$disabled-icon,
1641 $query: $query
1642 );
1643 @include icon-mixins.trailing-icon-color_(
1644 variables.$disabled-icon,
1645 $query: $query
1646 );
1647 @include _prefix-color(variables.$disabled-affix-color, $query: $query);
1648 @include _suffix-color(variables.$disabled-affix-color, $query: $query);
1649
1650 // Mixins that are ok to include since they target variant-specific elements
1651 @include bottom-line-color_(variables.$disabled-border, $query: $query);
1652 @include notched-outline-mixins.color(
1653 variables.$outlined-disabled-border,
1654 $query: $query
1655 );
1656
1657 @include dom.forced-colors-mode {
1658 @include placeholder-color_(GrayText, $query: $query);
1659 @include label-ink-color_(GrayText, $query: $query);
1660 @include helper-text-mixins.helper-text-color_(GrayText, $query: $query);
1661 @include character-counter-mixins.character-counter-color_(
1662 GrayText,
1663 $query: $query
1664 );
1665 @include icon-mixins.leading-icon-color_(GrayText, $query: $query);
1666 @include icon-mixins.trailing-icon-color_(GrayText, $query: $query);
1667 @include _prefix-color(GrayText, $query: $query);
1668 @include _suffix-color(GrayText, $query: $query);
1669
1670 // Mixins that are ok to include since they target variant-specific elements
1671 @include bottom-line-color_(GrayText, $query: $query);
1672 @include notched-outline-mixins.color(GrayText, $query: $query);
1673 }
1674
1675 @include dom.forced-colors-mode($exclude-ie11: true) {
1676 .mdc-text-field__input {
1677 @include feature-targeting.targets($feat-structure) {
1678 background-color: Window;
1679 }
1680 }
1681
1682 .mdc-floating-label {
1683 @include feature-targeting.targets($feat-structure) {
1684 z-index: 1;
1685 }
1686 }
1687 }
1688
1689 @include feature-targeting.targets($feat-structure) {
1690 pointer-events: none;
1691 }
1692
1693 .mdc-floating-label {
1694 @include feature-targeting.targets($feat-structure) {
1695 cursor: default;
1696 }
1697 }
1698}
1699
1700@mixin _disabled-input($query: feature-targeting.all()) {
1701 $feat-structure: feature-targeting.create-target($query, structure);
1702
1703 @include feature-targeting.targets($feat-structure) {
1704 // disabled inputs should still allow users to interact with them to select
1705 // text and scroll for textareas
1706 pointer-events: auto;
1707 }
1708}
1709
1710@mixin _disabled-filled($query: feature-targeting.all()) {
1711 $feat-structure: feature-targeting.create-target($query, structure);
1712
1713 @include fill-color_(variables.$disabled-background, $query: $query);
1714
1715 #{variables.$ripple-target} {
1716 @include feature-targeting.targets($feat-structure) {
1717 // prevent ripple from displaying on hover when some interactible
1718 // elements like input and resize handles are hovered
1719 display: none;
1720 }
1721 }
1722}
1723
1724@mixin invalid_($query: feature-targeting.all()) {
1725 $feat-structure: feature-targeting.create-target($query, structure);
1726
1727 @include hover-bottom-line-color(variables.$error, $query: $query);
1728 @include line-ripple-color(variables.$error, $query: $query);
1729 @include label-color(variables.$error, $query: $query);
1730 @include helper-text-mixins.helper-text-validation-color(
1731 variables.$error,
1732 $query: $query
1733 );
1734 @include caret-color(variables.$error, $query: $query);
1735 @include icon-mixins.trailing-icon-color(variables.$error, $query: $query);
1736
1737 // Mixins that are ok to include since they target variant-specific elements
1738 @include bottom-line-color(variables.$error, $query: $query);
1739 @include outline-color(variables.$error, $query: $query);
1740 @include hover-outline-color(variables.$error, $query: $query);
1741 @include focused-outline-color(variables.$error, $query: $query);
1742
1743 + .mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg {
1744 @include feature-targeting.targets($feat-structure) {
1745 opacity: 1;
1746 }
1747 }
1748}
1749
1750@mixin focused_($query: feature-targeting.all()) {
1751 $feat-structure: feature-targeting.create-target($query, structure);
1752
1753 @include label-color(variables.$focused-label-color, $query: $query);
1754
1755 // Mixins that are ok to include since they target variant-specific elements
1756 @include notched-outline-mixins.stroke-width(
1757 variables.$outlined-stroke-width,
1758 $query: $query
1759 );
1760
1761 + .mdc-text-field-helper-line
1762 .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg) {
1763 @include feature-targeting.targets($feat-structure) {
1764 opacity: 1;
1765 }
1766 }
1767}
1768
1769@mixin _focused-outlined($query: feature-targeting.all()) {
1770 @include notched-outline-mixins.notch-offset(
1771 variables.$outlined-stroke-width,
1772 $query: $query
1773 );
1774}
1775
1776@mixin _focused-outlined-textarea($query: feature-targeting.all()) {
1777 @include notched-outline-mixins.notch-offset(0, $query: $query);
1778}
1779
1780// Icons
1781
1782@mixin with-leading-icon_($query: feature-targeting.all()) {
1783 $feat-structure: feature-targeting.create-target($query, structure);
1784
1785 $icon-padding: icon-variables.$leading-icon-padding-left +
1786 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1787
1788 .mdc-floating-label {
1789 @include _truncate-floating-label-max-width($icon-padding, $query: $query);
1790 @include feature-targeting.targets($feat-structure) {
1791 @include rtl.reflexive-position(left, $icon-padding);
1792 }
1793 }
1794
1795 $truncation: $icon-padding + variables.$padding-horizontal;
1796
1797 .mdc-floating-label--float-above {
1798 @include _truncate-floating-label-floated-max-width(
1799 $truncation,
1800 $query: $query
1801 );
1802 }
1803}
1804
1805@mixin _with-trailing-icon($query: feature-targeting.all()) {
1806 $truncation: icon-variables.$trailing-icon-padding-left +
1807 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right +
1808 variables.$label-offset;
1809
1810 .mdc-floating-label {
1811 @include _truncate-floating-label-max-width($truncation, $query: $query);
1812 }
1813
1814 .mdc-floating-label--float-above {
1815 @include _truncate-floating-label-floated-max-width(
1816 $truncation,
1817 $query: $query
1818 );
1819 }
1820}
1821
1822@mixin _with-leading-and-trailing-icon($query: feature-targeting.all()) {
1823 $leading-icon: icon-variables.$leading-icon-padding-left +
1824 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1825 $trailing-icon: icon-variables.$trailing-icon-padding-left +
1826 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
1827 $truncation: $leading-icon + $trailing-icon;
1828
1829 .mdc-floating-label {
1830 @include _truncate-floating-label-max-width($truncation, $query: $query);
1831 }
1832
1833 .mdc-floating-label--float-above {
1834 @include _truncate-floating-label-floated-max-width(
1835 $truncation,
1836 $query: $query
1837 );
1838 }
1839}
1840
1841@mixin outlined-with-leading-icon_($query: feature-targeting.all()) {
1842 $feat-structure: feature-targeting.create-target($query, structure);
1843
1844 // Resting label position
1845 $icon-padding: icon-variables.$leading-icon-padding-left +
1846 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1847 $left-spacing: $icon-padding - notched-outline-variables.$leading-width;
1848
1849 .mdc-floating-label {
1850 @include feature-targeting.targets($feat-structure) {
1851 @include rtl.reflexive-position(left, $left-spacing);
1852 }
1853 }
1854
1855 // Notch width
1856 $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;
1857 @include _truncate-notched-outline-max-width(
1858 $notch-truncation,
1859 $query: $query
1860 );
1861
1862 // Floating label position and animation
1863 @include _outlined-with-leading-icon-floating-label-position-animation(
1864 $height: variables.$height,
1865 $keyframe-suffix: text-field-outlined-leading-icon,
1866 $query: $query
1867 );
1868}
1869
1870///
1871/// Applied to the outlined text field with a trailing icon
1872///
1873@mixin _outlined-with-trailing-icon($query: feature-targeting.all()) {
1874 // Resting label position
1875 $icon-padding: icon-variables.$trailing-icon-padding-left +
1876 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
1877 // Notch width
1878 $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;
1879
1880 @include _truncate-notched-outline-max-width(
1881 $notch-truncation,
1882 $query: $query
1883 );
1884}
1885
1886///
1887/// Truncates the max-width of the notched outline by the given amount
1888///
1889/// @param {Number} $truncation - Amount to truncate the notched outline max-width
1890///
1891@mixin _truncate-notched-outline-max-width(
1892 $truncation,
1893 $query: feature-targeting.all()
1894) {
1895 @include notched-outline-mixins.notch-max-width(
1896 calc(100% - #{$truncation}),
1897 $query: $query
1898 );
1899}
1900
1901///
1902/// Truncates the max-width of the floating label by the given amount
1903///
1904/// @param {Number} $truncation - Amount to truncate the floating label max-width
1905///
1906@mixin _truncate-floating-label-max-width(
1907 $truncation,
1908 $query: feature-targeting.all()
1909) {
1910 @include floating-label-mixins.max-width(
1911 calc(100% - #{$truncation}),
1912 $query: $query
1913 );
1914}
1915
1916///
1917/// Truncates the max-width of the floating label by the given amount while scaling by the given scale value
1918///
1919/// @param {Number} $truncation - Amount to truncate the floating label max-width
1920///
1921@mixin _truncate-floating-label-floated-max-width(
1922 $truncation,
1923 $query: feature-targeting.all()
1924) {
1925 $scale: floating-label-variables.$float-scale;
1926 @include floating-label-mixins.max-width(
1927 calc(100% / #{$scale} - #{$truncation} / #{$scale}),
1928 $query: $query
1929 );
1930}
1931
1932// Textarea
1933
1934@mixin textarea_($query: feature-targeting.all()) {
1935 $feat-structure: feature-targeting.create-target($query, structure);
1936 $feat-animation: feature-targeting.create-target($query, animation);
1937
1938 @include _textarea-floating-label($query);
1939
1940 @include feature-targeting.targets($feat-structure) {
1941 flex-direction: column;
1942 align-items: center;
1943 width: auto;
1944 height: auto;
1945 padding: 0; // see below for explanation
1946 }
1947
1948 @include feature-targeting.targets($feat-animation) {
1949 transition: none;
1950 }
1951}
1952
1953@mixin _textarea-resizer($query: feature-targeting.all()) {
1954 $feat-structure: feature-targeting.create-target($query, structure);
1955
1956 @include feature-targeting.targets($feat-structure) {
1957 align-self: stretch;
1958 display: inline-flex;
1959 flex-direction: column;
1960 flex-grow: 1;
1961 max-height: 100%;
1962 max-width: 100%;
1963 min-height: variables.$height;
1964 // stylelint-disable declaration-block-no-duplicate-properties --
1965 // TODO: document why this disable is neccessary
1966
1967 // 'stretch' is the preferred rule here. It will allow the textarea to grow
1968 // to the min/max width of the container, but if an explicit width is set,
1969 // it cannot be resized horizontally.
1970 // Stretch is still a working draft. Chrome and Firefox have it implemented
1971 // with 'available' prefixes. fit-content is another good target for
1972 // Safari since it works in almost all use cases except when an explicit
1973 // width is set (the user can make the textarea smaller than the container).
1974 // None of this matters for IE11, which doesn't support resize.
1975 min-width: fit-content;
1976 /* @alternate */
1977 min-width: -moz-available;
1978 /* @alternate */
1979 min-width: -webkit-fill-available;
1980 // stylelint-enable declaration-block-no-duplicate-properties
1981 overflow: hidden;
1982 resize: both;
1983 }
1984}
1985
1986@mixin _textarea-filled-resizer($query: feature-targeting.all()) {
1987 $feat-structure: feature-targeting.create-target($query, structure);
1988 // Shift the resizer element up by a margin amount to make space for the
1989 // resize handle. For filled elements, the resize handle directly touches
1990 // the bottom line and is hard to see.
1991 // Using a margin affects the width and positioning of the overall component
1992 // and underlying textarea, which is why a transform is used instead.
1993 $y: -1 * variables.$textarea-input-handle-margin;
1994
1995 @include feature-targeting.targets($feat-structure) {
1996 transform: translateY($y);
1997 }
1998}
1999
2000@mixin _textarea-filled-resizer-children($query: feature-targeting.all()) {
2001 $feat-structure: feature-targeting.create-target($query, structure);
2002 // See above. After shifting the resize wrapper element, all of its children
2003 // should be shifted in the opposite direction (down) to compensate.
2004 $y: variables.$textarea-input-handle-margin;
2005
2006 @include feature-targeting.targets($feat-structure) {
2007 transform: translateY($y);
2008 }
2009}
2010
2011@mixin _textarea-outlined-resizer($query: feature-targeting.all()) {
2012 $feat-structure: feature-targeting.create-target($query, structure);
2013 // Shift the resizer element left/up by a margin amount to make space for the
2014 // resize handle. For outlined elements, the resize handle directly touches
2015 // the outline and is hard to see.
2016 // Using a margin affects the width and positioning of the overall component
2017 // and underlying textarea, which is why a transform is used instead.
2018 $x: -1 * variables.$textarea-input-handle-margin;
2019 $y: -1 * variables.$textarea-input-handle-margin;
2020
2021 @include feature-targeting.targets($feat-structure) {
2022 @include rtl.ignore-next-line();
2023 transform: translateX($x) translateY($y);
2024
2025 @include rtl.rtl {
2026 // Flip the horizontal shifting direction for RTL
2027 @include rtl.ignore-next-line();
2028 transform: translateX(-1 * $x) translateY($y);
2029 }
2030 }
2031}
2032
2033@mixin _textarea-outlined-resizer-children($query: feature-targeting.all()) {
2034 $feat-structure: feature-targeting.create-target($query, structure);
2035 // See above. After shifting the resize wrapper element, all of its children
2036 // should be shifted in the opposite direction (right and down) to compensate.
2037 $x: variables.$textarea-input-handle-margin;
2038 $y: variables.$textarea-input-handle-margin;
2039
2040 @include feature-targeting.targets($feat-structure) {
2041 @include rtl.ignore-next-line();
2042 transform: translateX($x) translateY($y);
2043
2044 @include rtl.rtl {
2045 // Flip the horizontal shifting direction for RTL
2046 @include rtl.ignore-next-line();
2047 transform: translateX(-1 * $x) translateY($y);
2048 }
2049 }
2050}
2051
2052@mixin _textarea-floating-label($query: feature-targeting.all()) {
2053 $feat-structure: feature-targeting.create-target($query, structure);
2054
2055 // Resting label position
2056 .mdc-floating-label {
2057 @include feature-targeting.targets($feat-structure) {
2058 top: variables.$textarea-label-top;
2059 }
2060
2061 // Resets center aligning the floating label.
2062 &:not(.mdc-floating-label--float-above) {
2063 @include feature-targeting.targets($feat-structure) {
2064 transform: none;
2065 }
2066 }
2067 }
2068}
2069
2070@mixin _textarea-input($query: feature-targeting.all()) {
2071 $feat-structure: feature-targeting.create-target($query, structure);
2072 $feat-typography: feature-targeting.create-target($query, typography);
2073
2074 @include feature-targeting.targets($feat-structure) {
2075 flex-grow: 1;
2076 height: auto;
2077 min-height: variables.$textarea-line-height;
2078 overflow-x: hidden; // https://bugzilla.mozilla.org/show_bug.cgi?id=33654
2079 overflow-y: auto;
2080 box-sizing: border-box;
2081 resize: none;
2082 // Textarea has horizontal padding instead of the container. This allows the
2083 // resize handle to extend to the edge of the container.
2084 padding: 0 variables.$padding-horizontal;
2085 }
2086
2087 @include feature-targeting.targets($feat-typography) {
2088 line-height: variables.$textarea-line-height;
2089 }
2090}
2091
2092@mixin _textarea-internal-counter($query: feature-targeting.all()) {
2093 $feat-structure: feature-targeting.create-target($query, structure);
2094
2095 @include typography.baseline-bottom(
2096 variables.$textarea-internal-counter-baseline-bottom,
2097 $query: $query
2098 );
2099 @include feature-targeting.targets($feat-structure) {
2100 align-self: flex-end;
2101 // Needed since padding is on the textarea and not the container
2102 padding: 0 variables.$padding-horizontal;
2103
2104 &::before {
2105 // Remove baseline-top
2106 display: none;
2107 }
2108 }
2109}
2110
2111@mixin _textarea-input-with-internal-counter($query: feature-targeting.all()) {
2112 $feat-structure: feature-targeting.create-target($query, structure);
2113
2114 @include feature-targeting.targets($feat-structure) {
2115 margin-bottom: variables.$textarea-internal-counter-input-margin-bottom;
2116 }
2117}
2118
2119@mixin _textarea-filled($query: feature-targeting.all()) {
2120 $feat-structure: feature-targeting.create-target($query, structure);
2121
2122 @include feature-targeting.targets($feat-structure) {
2123 &::before {
2124 // <textarea> does not align to baseline when it does not have a value,
2125 // unlike <input>, so we have to use padding to fake it instead
2126 display: none;
2127 }
2128 }
2129
2130 // Floating label position
2131 @include floating-label-mixins.float-position(
2132 variables.$textarea-filled-label-position-y,
2133 $query: $query
2134 );
2135
2136 // Floating label animation
2137 @include floating-label-mixins.shake-animation(
2138 textarea-filled,
2139 $query: $query
2140 );
2141 @at-root {
2142 @include floating-label-mixins.shake-keyframes(
2143 textarea-filled,
2144 variables.$textarea-filled-label-position-y,
2145 0%,
2146 $query: $query
2147 );
2148 }
2149}
2150
2151@mixin _textarea-filled-input($query: feature-targeting.all()) {
2152 $feat-structure: feature-targeting.create-target($query, structure);
2153
2154 @include feature-targeting.targets($feat-structure) {
2155 margin-top: variables.$textarea-filled-input-margin-top;
2156 margin-bottom: variables.$textarea-filled-input-margin-bottom;
2157 }
2158}
2159
2160@mixin _textarea-filled-no-label-input($query: feature-targeting.all()) {
2161 $feat-structure: feature-targeting.create-target($query, structure);
2162
2163 @include feature-targeting.targets($feat-structure) {
2164 margin-top: variables.$textarea-filled-no-label-input-margin-top;
2165 margin-bottom: variables.$textarea-filled-no-label-input-margin-bottom;
2166 }
2167}
2168
2169@mixin _textarea-outlined($query: feature-targeting.all()) {
2170 @include notched-outline-mixins.notch-offset(0, $query: $query);
2171
2172 // Floating label position
2173 @include notched-outline-mixins.floating-label-float-position-absolute(
2174 variables.$textarea-outlined-label-position-y,
2175 $query: $query
2176 );
2177
2178 // Floating label animation
2179 @include floating-label-mixins.shake-animation(
2180 textarea-outlined,
2181 $query: $query
2182 );
2183 @at-root {
2184 @include floating-label-mixins.shake-keyframes(
2185 textarea-outlined,
2186 variables.$textarea-outlined-label-position-y,
2187 0%,
2188 $query: $query
2189 );
2190 }
2191}
2192
2193@mixin _textarea-outlined-floating-label($query: feature-targeting.all()) {
2194 $feat-structure: feature-targeting.create-target($query, structure);
2195
2196 @include feature-targeting.targets($feat-structure) {
2197 top: variables.$textarea-outlined-label-top;
2198 }
2199}
2200
2201@mixin _textarea-outlined-input($query: feature-targeting.all()) {
2202 $feat-structure: feature-targeting.create-target($query, structure);
2203
2204 @include feature-targeting.targets($feat-structure) {
2205 margin-top: variables.$textarea-outlined-input-margin-top;
2206 margin-bottom: variables.$textarea-outlined-input-margin-bottom;
2207 }
2208}
2209
2210// Text, Prefix and Suffix
2211
2212// Common styles for the text of the text field, including the prefix, suffix,
2213// and input.
2214@mixin _text($query: feature-targeting.all()) {
2215 $feat-animation: feature-targeting.create-target($query, animation);
2216 $feat-structure: feature-targeting.create-target($query, structure);
2217
2218 // Exclude setting line-height to keep caret (text cursor) same height as the input text in iOS browser.
2219 @include typography.typography(
2220 subtitle1,
2221 $exclude-props: (line-height),
2222 $query: $query
2223 );
2224 @include feature-targeting.targets($feat-structure) {
2225 height: variables.$input-height;
2226 }
2227
2228 @include feature-targeting.targets($feat-animation) {
2229 transition: animation.standard(opacity, 150ms);
2230 }
2231}
2232
2233@mixin _input($query: feature-targeting.all()) {
2234 $feat-structure: feature-targeting.create-target($query, structure);
2235
2236 @include _text($query: $query);
2237 @include feature-targeting.targets($feat-structure) {
2238 width: 100%;
2239 min-width: 0; // Fixes flex issues on Firefox
2240 border: none;
2241 border-radius: 0;
2242 background: none;
2243 appearance: none;
2244 padding: 0;
2245
2246 // Remove built-in trailing clear icon on IE11. IE vendor prefixes cannot
2247 // be combined with other vendor prefixes like the webkit one below.
2248 &::-ms-clear {
2249 display: none;
2250 }
2251
2252 // Remove built-in datepicker icon on Chrome
2253 &::-webkit-calendar-picker-indicator {
2254 display: none;
2255 }
2256
2257 &:focus {
2258 outline: none;
2259 }
2260
2261 // Remove red outline on firefox
2262 &:invalid {
2263 box-shadow: none;
2264 }
2265 }
2266}
2267
2268@mixin _input-placeholder($query: feature-targeting.all()) {
2269 $feat-animation: feature-targeting.create-target($query, animation);
2270 $feat-structure: feature-targeting.create-target($query, structure);
2271
2272 @include feature-targeting.targets($feat-animation) {
2273 transition: animation.standard(opacity, 67ms);
2274 }
2275
2276 @include feature-targeting.targets($feat-structure) {
2277 opacity: 0;
2278 }
2279}
2280
2281@mixin _input-placeholder-visible($query: feature-targeting.all()) {
2282 $feat-animation: feature-targeting.create-target($query, animation);
2283 $feat-structure: feature-targeting.create-target($query, structure);
2284
2285 @include feature-targeting.targets($feat-animation) {
2286 transition-delay: 40ms;
2287 transition-duration: 110ms;
2288 }
2289
2290 @include feature-targeting.targets($feat-structure) {
2291 opacity: 1;
2292 }
2293}
2294
2295@mixin _affix($query: feature-targeting.all()) {
2296 $feat-structure: feature-targeting.create-target($query, structure);
2297
2298 @include _text($query: $query);
2299 @include feature-targeting.targets($feat-structure) {
2300 opacity: 0;
2301 white-space: nowrap;
2302 }
2303}
2304
2305// TODO(b/155467610): Remove when Safari supports baseline alignment
2306// https://github.com/material-components/material-components-web/issues/5879
2307@mixin _centered-affix-safari-support($query: feature-targeting.all()) {
2308 $feat-structure: feature-targeting.create-target($query, structure);
2309
2310 @include feature-targeting.targets($feat-structure) {
2311 align-items: center;
2312 align-self: center;
2313 display: inline-flex;
2314 height: 100%;
2315 }
2316}
2317
2318@mixin _affix-visible($query: feature-targeting.all()) {
2319 $feat-structure: feature-targeting.create-target($query, structure);
2320
2321 @include feature-targeting.targets($feat-structure) {
2322 opacity: 1;
2323 }
2324}
2325
2326@mixin _prefix($query: feature-targeting.all()) {
2327 $feat-structure: feature-targeting.create-target($query, structure);
2328
2329 @include feature-targeting.targets($feat-structure) {
2330 @include rtl.reflexive-box(padding, right, variables.$prefix-padding);
2331 }
2332}
2333
2334@mixin _prefix-end-aligned($query: feature-targeting.all()) {
2335 $feat-structure: feature-targeting.create-target($query, structure);
2336
2337 @include feature-targeting.targets($feat-structure) {
2338 @include rtl.reflexive-box(
2339 padding,
2340 right,
2341 variables.$prefix-end-aligned-padding
2342 );
2343 }
2344}
2345
2346@mixin _suffix($query: feature-targeting.all()) {
2347 $feat-structure: feature-targeting.create-target($query, structure);
2348
2349 @include feature-targeting.targets($feat-structure) {
2350 @include rtl.reflexive-box(padding, left, variables.$suffix-padding);
2351 }
2352}
2353
2354@mixin _suffix-end-aligned($query: feature-targeting.all()) {
2355 $feat-structure: feature-targeting.create-target($query, structure);
2356
2357 @include feature-targeting.targets($feat-structure) {
2358 @include rtl.reflexive-box(
2359 padding,
2360 left,
2361 variables.$suffix-end-aligned-padding
2362 );
2363 }
2364}
2365
2366// End aligned
2367@mixin end-aligned_($query: feature-targeting.all()) {
2368 $feat-structure: feature-targeting.create-target($query, structure);
2369
2370 .mdc-text-field__input {
2371 @include feature-targeting.targets($feat-structure) {
2372 // IE11 does not support text-align: end
2373 @include rtl.ignore-next-line();
2374 text-align: right;
2375 }
2376
2377 @include rtl.rtl {
2378 @include feature-targeting.targets($feat-structure) {
2379 @include rtl.ignore-next-line();
2380 text-align: left;
2381 }
2382 }
2383 }
2384}
2385
2386// Forces input, prefix, and suffix to be LTR when in an RTL environment. Other
2387// elements such as labels and icons will remain RTL.
2388@mixin _ltr-text($query: feature-targeting.all()) {
2389 $feat-structure: feature-targeting.create-target($query, structure);
2390
2391 @include feature-targeting.targets($feat-structure) {
2392 @include rtl.rtl {
2393 .mdc-text-field__input,
2394 .mdc-text-field__affix {
2395 @include rtl.ignore-next-line();
2396 direction: ltr;
2397 }
2398
2399 .mdc-text-field__affix--prefix {
2400 @include rtl.ignore-next-line();
2401 padding-left: 0;
2402 @include rtl.ignore-next-line();
2403 padding-right: variables.$prefix-padding;
2404 }
2405
2406 .mdc-text-field__affix--suffix {
2407 @include rtl.ignore-next-line();
2408 padding-left: variables.$suffix-padding;
2409 @include rtl.ignore-next-line();
2410 padding-right: 0;
2411 }
2412
2413 // Need to specify an order for all elements since icons maintain their
2414 // original positions. We can't just reverse the container.
2415 .mdc-text-field__icon--leading {
2416 order: 1;
2417 }
2418
2419 .mdc-text-field__affix--suffix {
2420 order: 2;
2421 }
2422
2423 .mdc-text-field__input {
2424 order: 3;
2425 }
2426
2427 .mdc-text-field__affix--prefix {
2428 order: 4;
2429 }
2430
2431 .mdc-text-field__icon--trailing {
2432 order: 5;
2433 }
2434 }
2435 }
2436}
2437
2438// Forces input, prefix, and suffix that are already forced to LTR to also be
2439// end-aligned. This mixin should be used alongside the styles provided in
2440// _ltr-text().
2441@mixin _ltr-text-end-aligned($query: feature-targeting.all()) {
2442 $feat-structure: feature-targeting.create-target($query, structure);
2443
2444 @include feature-targeting.targets($feat-structure) {
2445 @include rtl.rtl {
2446 .mdc-text-field__input {
2447 // IE11 does not support text-align: end, so we need to duplicate
2448 // the LTR end-aligned style here.
2449 @include rtl.ignore-next-line();
2450 text-align: right;
2451 }
2452
2453 .mdc-text-field__affix--prefix {
2454 // padding-left: 0 provided by _ltr-text mixin
2455 @include rtl.ignore-next-line();
2456 padding-right: variables.$prefix-end-aligned-padding;
2457 }
2458
2459 .mdc-text-field__affix--suffix {
2460 @include rtl.ignore-next-line();
2461 padding-left: variables.$suffix-end-aligned-padding;
2462 // padding-right: 0 provided by _ltr-text mixin
2463 }
2464 }
2465 }
2466}
2467
2468// Customization
2469
2470@mixin ink-color_($color, $query: feature-targeting.all()) {
2471 $feat-color: feature-targeting.create-target($query, color);
2472
2473 .mdc-text-field__input {
2474 @include feature-targeting.targets($feat-color) {
2475 @include theme.prop(color, $color);
2476 }
2477 }
2478}
2479
2480@mixin placeholder-color_($color, $query: feature-targeting.all()) {
2481 $feat-color: feature-targeting.create-target($query, color);
2482
2483 @include feature-targeting.targets($feat-color) {
2484 .mdc-text-field__input {
2485 @include placeholder-selector_ {
2486 @include theme.prop(color, $color);
2487 }
2488 }
2489 }
2490}
2491
2492@mixin fill-color_(
2493 $color,
2494 $query: feature-targeting.all(),
2495 $addAlternate: false
2496) {
2497 $feat-color: feature-targeting.create-target($query, color);
2498
2499 @include feature-targeting.targets($feat-color) {
2500 @if ($addAlternate) {
2501 /* @alternate */
2502 }
2503 @include theme.prop(background-color, $color);
2504 }
2505}
2506
2507@mixin bottom-line-color_($color, $query: feature-targeting.all()) {
2508 .mdc-line-ripple {
2509 @include line-ripple-mixins.inactive-color($color, $query: $query);
2510 }
2511}
2512
2513@mixin hover-bottom-line-color_($color, $query: feature-targeting.all()) {
2514 $feat-color: feature-targeting.create-target($query, color);
2515
2516 &:hover .mdc-line-ripple {
2517 @include line-ripple-mixins.inactive-color($color, $query: $query);
2518 }
2519}
2520
2521@mixin line-ripple-color_($color, $query: feature-targeting.all()) {
2522 .mdc-line-ripple {
2523 @include line-ripple-mixins.active-color($color, $query: $query);
2524 }
2525}
2526
2527@mixin hover-outline-color_($color, $query: feature-targeting.all()) {
2528 &:not(.mdc-text-field--focused):hover {
2529 .mdc-notched-outline {
2530 @include notched-outline-mixins.color($color, $query: $query);
2531 }
2532 }
2533}
2534
2535@mixin focused-outline-color_($color, $query: feature-targeting.all()) {
2536 &.mdc-text-field--focused {
2537 @include notched-outline-mixins.color($color, $query: $query);
2538 }
2539}
2540
2541@mixin label-ink-color_($color, $query: feature-targeting.all()) {
2542 .mdc-floating-label {
2543 @include floating-label-mixins.ink-color($color, $query: $query);
2544 }
2545}
2546
2547@mixin _prefix-color($color, $query: feature-targeting.all()) {
2548 $feat-color: feature-targeting.create-target($query, color);
2549
2550 @include feature-targeting.targets($feat-color) {
2551 .mdc-text-field__affix--prefix {
2552 @include theme.prop(color, $color);
2553 }
2554 }
2555}
2556
2557@mixin _suffix-color($color, $query: feature-targeting.all()) {
2558 $feat-color: feature-targeting.create-target($query, color);
2559
2560 @include feature-targeting.targets($feat-color) {
2561 .mdc-text-field__affix--suffix {
2562 @include theme.prop(color, $color);
2563 }
2564 }
2565}
2566
2567// Selectors
2568
2569@mixin placeholder-selector_ {
2570 // GSS will combine selectors with the same content, and some browsers have a
2571 // CSS quirk where it drops a rule if it does not recognize one of the
2572 // selectors.
2573 // To avoid GSS combining the ::placeholder and :-ms-input-placeholder
2574 // selectors, we wrap them in `@media all`.
2575 // TODO(b/142329051)
2576 @media all {
2577 // ::placeholder needs to be wrapped because IE11 will drop other selectors
2578 // with the same content
2579 &::placeholder {
2580 @content;
2581 }
2582 }
2583
2584 @media all {
2585 // :-ms-input-placeholder needs to be wrapped because Firefox will drop
2586 // other selectors with the same content
2587 &:-ms-input-placeholder {
2588 @content;
2589 }
2590 }
2591}
2592
2593// State qualifiers
2594
2595///
2596/// Helps style the text-field only when it's enabled.
2597/// @access private
2598///
2599@mixin if-enabled_ {
2600 &:not(.mdc-text-field--disabled) {
2601 @content;
2602 }
2603}
2604
2605///
2606/// Helps style the text-field only when it's disabled.
2607/// @access private
2608///
2609@mixin if-disabled_ {
2610 &.mdc-text-field--disabled {
2611 @content;
2612 }
2613}