UNPKG

79.4 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 @supports (top: max(0%)) {
1290 // A max() function makes this runtime dynamic. The padding will be
1291 // whichever is greater: the default horizontal padding, or the calculated
1292 // custom property plus extra padding.
1293 @include rtl.ignore-next-line();
1294 #{$property}: max(#{variables.$padding-horizontal}, #{$value});
1295 }
1296 }
1297 }
1298}
1299
1300///
1301/// Sets the CSS transition for the floating label's 'float' animation.
1302///
1303/// @param {Number} $duration-ms - Duration (in ms) of the animation.
1304/// @param {String} $timing-function - Optionally overrides the default animation timing function.
1305///
1306@mixin floating-label-float-transition(
1307 $duration-ms,
1308 $timing-function: null,
1309 $query: feature-targeting.all()
1310) {
1311 .mdc-floating-label {
1312 @include floating-label-mixins.float-transition(
1313 $duration-ms,
1314 $timing-function,
1315 $query: $query
1316 );
1317 }
1318}
1319
1320// Private mixins
1321
1322// Base shared styles
1323@mixin _base($query: feature-targeting.all()) {
1324 $feat-structure: feature-targeting.create-target($query, structure);
1325
1326 // Shape
1327 @include shape-radius(variables.$shape-radius, $query: $query);
1328
1329 // Colors
1330 @include label-color(variables.$label, $query: $query);
1331 @include ink-color(variables.$ink-color, $query: $query);
1332 @include placeholder-color(variables.$placeholder-ink-color, $query: $query);
1333 @include caret-color(primary, $query: $query);
1334 @include helper-text-mixins.helper-text-color(
1335 variables.$helper-text-color,
1336 $query: $query
1337 );
1338 @include character-counter-mixins.character-counter-color(
1339 variables.$helper-text-color,
1340 $query: $query
1341 );
1342 @include icon-mixins.leading-icon-color(
1343 variables.$icon-color,
1344 $query: $query
1345 );
1346 @include icon-mixins.trailing-icon-color(
1347 variables.$icon-color,
1348 $query: $query
1349 );
1350 @include prefix-color(variables.$affix-color, $query: $query);
1351 @include suffix-color(variables.$affix-color, $query: $query);
1352
1353 // Floating Label
1354 @include floating-label_($query);
1355
1356 @include feature-targeting.targets($feat-structure) {
1357 // display and align-items are necessary to make the text field participate
1358 // in baseline alignment, even though some variants are 'centered'. Those
1359 // variants should use the _baseline-center-aligned() mixin
1360 display: inline-flex;
1361 align-items: baseline;
1362 padding: 0 variables.$padding-horizontal;
1363 position: relative;
1364 box-sizing: border-box;
1365 overflow: hidden;
1366 /* @alternate */
1367 will-change: opacity, transform, color;
1368 }
1369}
1370
1371// This mixin adds styles to visually center the text within the text field.
1372// Sibling text will align to the baseline and appear centered next to the
1373// text field.
1374@mixin _baseline-center-aligned($query: feature-targeting.all()) {
1375 $feat-structure: feature-targeting.create-target($query, structure);
1376
1377 @include feature-targeting.targets($feat-structure) {
1378 // In order for a flexbox container to participate in baseline alignment,
1379 // it follows these rules to determine where its baseline is:
1380 // https://www.w3.org/TR/css-flexbox-1/#flex-baselines
1381 //
1382 // In order to avoid leading icons 'controlling' the baseline (since they
1383 // are the first child), flexbox will generate a baseline from any child
1384 // flex items that participate in baseline alignment.
1385 //
1386 // Icons are set to "align-self: center", while all other children are
1387 // aligned to baseline. The next problem is deciding which child is
1388 // used to determine the baseline.
1389 //
1390 // According to spec, the item with the largest distance between its
1391 // baseline and the edge of the cross axis is placed flush with that edge,
1392 // making it the baseline of the container.
1393 // https://www.w3.org/TR/css-flexbox-1/#baseline-participation
1394 //
1395 // For the filled variant, the pseudo ::before strut is the 'largest'
1396 // child since the input has a height of 28px and the strut is 40px. We
1397 // can emulate center alignment and force the baseline to use the input
1398 // text by making the input the full height of the container and removing
1399 // the baseline strut.
1400
1401 // IE11 does not respect this, and makes the leading icon (if present) the
1402 // baseline. This is a gap with IE11 that we have accepted.
1403 .mdc-text-field__input {
1404 height: 100%;
1405 }
1406 }
1407}
1408
1409@mixin _padding-horizontal-with-leading-icon($query: feature-targeting.all()) {
1410 $feat-structure: feature-targeting.create-target($query, structure);
1411
1412 @include feature-targeting.targets($feat-structure) {
1413 @include rtl.reflexive-property(padding, 0, variables.$padding-horizontal);
1414 }
1415}
1416
1417@mixin _padding-horizontal-with-trailing-icon($query: feature-targeting.all()) {
1418 $feat-structure: feature-targeting.create-target($query, structure);
1419
1420 @include feature-targeting.targets($feat-structure) {
1421 @include rtl.reflexive-property(padding, variables.$padding-horizontal, 0);
1422 }
1423}
1424
1425@mixin _padding-horizontal-with-both-icons($query: feature-targeting.all()) {
1426 $feat-structure: feature-targeting.create-target($query, structure);
1427
1428 @include feature-targeting.targets($feat-structure) {
1429 @include rtl.ignore-next-line();
1430 padding-left: 0;
1431 @include rtl.ignore-next-line();
1432 padding-right: 0;
1433 }
1434}
1435
1436@mixin floating-label_($query: feature-targeting.all()) {
1437 $feat-structure: feature-targeting.create-target($query, structure);
1438
1439 .mdc-floating-label {
1440 @include feature-targeting.targets($feat-structure) {
1441 top: 50%;
1442 transform: translateY(-50%);
1443 pointer-events: none;
1444 }
1445 }
1446}
1447
1448// Filled
1449
1450@mixin _filled($query: feature-targeting.all()) {
1451 // Text Field intentionally omits press ripple, so each state needs to be specified individually.
1452 @include ripple-theme.states-base-color(
1453 variables.$ink-color,
1454 $query: $query,
1455 $ripple-target: variables.$ripple-target
1456 );
1457 @include ripple-theme.states-hover-opacity(
1458 ripple-theme.states-opacity(variables.$ink-color, hover),
1459 $query: $query,
1460 $ripple-target: variables.$ripple-target
1461 );
1462 @include ripple-theme.states-focus-opacity(
1463 ripple-theme.states-opacity(variables.$ink-color, focus),
1464 $query: $query,
1465 $ripple-target: variables.$ripple-target
1466 );
1467
1468 @include height(variables.$height, $query: $query);
1469 @include typography.baseline-top(
1470 variables.$filled-baseline-top,
1471 $query: $query
1472 );
1473 @include fill-color(variables.$background, $query: $query);
1474 @include bottom-line-color(variables.$bottom-line-idle, $query: $query);
1475 @include hover-bottom-line-color(
1476 variables.$bottom-line-hover,
1477 $query: $query
1478 );
1479 @include line-ripple-color_(primary, $query: $query);
1480 @include _filled-floating-label($query);
1481}
1482
1483@mixin _filled-floating-label($query: feature-targeting.all()) {
1484 $feat-structure: feature-targeting.create-target($query, structure);
1485
1486 .mdc-floating-label {
1487 @include feature-targeting.targets($feat-structure) {
1488 @include rtl.reflexive-position(left, variables.$label-offset);
1489 }
1490 }
1491
1492 @include floating-label-mixins.float-position(
1493 variables.$label-position-y,
1494 $query: $query
1495 );
1496}
1497
1498// Filled variant with no label. This variant centers the text elements and
1499// hides the label and is used with there is explicitly no label provided or
1500// when the height of the text field is too small for a label to be allowed.
1501@mixin _filled-no-label($query: feature-targeting.all()) {
1502 $feat-structure: feature-targeting.create-target($query, structure);
1503
1504 @include _baseline-center-aligned($query);
1505 @include feature-targeting.targets($feat-structure) {
1506 .mdc-floating-label {
1507 display: none;
1508 }
1509
1510 &::before {
1511 // Remove baseline-top strut
1512 display: none;
1513 }
1514 }
1515
1516 // Safari only
1517 @supports (-webkit-hyphens: none) {
1518 .mdc-text-field__affix {
1519 @include _centered-affix-safari-support($query: $query);
1520 }
1521 }
1522}
1523
1524// Outlined
1525
1526@mixin outlined_($query: feature-targeting.all()) {
1527 $feat-structure: feature-targeting.create-target($query, structure);
1528
1529 @include outlined-height(
1530 $height: variables.$height,
1531 $keyframe-suffix: text-field-outlined,
1532 $query: $query
1533 );
1534 @include _baseline-center-aligned($query: $query);
1535 @include outline-color(variables.$outlined-idle-border, $query: $query);
1536 @include hover-outline-color(
1537 variables.$outlined-hover-border,
1538 $query: $query
1539 );
1540 @include focused-outline-color(primary, $query: $query);
1541 @include outline-shape-radius(variables.$shape-radius, $query: $query);
1542 @include notched-outline-mixins.notch-offset(
1543 notched-outline-variables.$border-width,
1544 $query: $query
1545 );
1546 @include ripple-theme.states-base-color(
1547 transparent,
1548 $query: $query,
1549 $ripple-target: variables.$ripple-target
1550 );
1551 @include _outlined-floating-label($query);
1552
1553 @include feature-targeting.targets($feat-structure) {
1554 overflow: visible;
1555 }
1556
1557 .mdc-text-field__input {
1558 @include feature-targeting.targets($feat-structure) {
1559 // TODO(b/154349735): Investigate the neccessity of these styles
1560 display: flex;
1561 border: none !important; // FF adds unwanted border in HC mode on windows.
1562 background-color: transparent;
1563 }
1564 }
1565}
1566
1567@mixin _outlined-floating-label($query: feature-targeting.all()) {
1568 $feat-structure: feature-targeting.create-target($query, structure);
1569
1570 .mdc-floating-label {
1571 @include feature-targeting.targets($feat-structure) {
1572 @include rtl.reflexive-position(left, notched-outline-variables.$padding);
1573 }
1574 }
1575}
1576
1577@mixin _outlined-notched-outline($query: feature-targeting.all()) {
1578 $feat-structure: feature-targeting.create-target($query, structure);
1579
1580 @include feature-targeting.targets($feat-structure) {
1581 // Force the outline to appear "above" the textfield elements, even though
1582 // it is absolutely positioned and comes before the input in the DOM. This
1583 // is primarily for the textarea scrollbar and resize elements, which may
1584 // clip with with outline border.
1585 z-index: 1;
1586 }
1587}
1588
1589// States
1590
1591@mixin disabled_($query: feature-targeting.all()) {
1592 $feat-structure: feature-targeting.create-target($query, structure);
1593
1594 @include ink-color_(variables.$disabled-ink-color, $query: $query);
1595 @include placeholder-color_(
1596 variables.$disabled-placeholder-ink-color,
1597 $query: $query
1598 );
1599 @include label-ink-color_(variables.$disabled-label-color, $query: $query);
1600 @include helper-text-mixins.helper-text-color_(
1601 variables.$disabled-helper-text-color,
1602 $query: $query
1603 );
1604 @include character-counter-mixins.character-counter-color_(
1605 variables.$disabled-helper-text-color,
1606 $query: $query
1607 );
1608 @include icon-mixins.leading-icon-color_(
1609 variables.$disabled-icon,
1610 $query: $query
1611 );
1612 @include icon-mixins.trailing-icon-color_(
1613 variables.$disabled-icon,
1614 $query: $query
1615 );
1616 @include _prefix-color(variables.$disabled-affix-color, $query: $query);
1617 @include _suffix-color(variables.$disabled-affix-color, $query: $query);
1618
1619 // Mixins that are ok to include since they target variant-specific elements
1620 @include bottom-line-color_(variables.$disabled-border, $query: $query);
1621 @include notched-outline-mixins.color(
1622 variables.$outlined-disabled-border,
1623 $query: $query
1624 );
1625
1626 @include dom.forced-colors-mode {
1627 @include placeholder-color_(GrayText, $query: $query);
1628 @include label-ink-color_(GrayText, $query: $query);
1629 @include helper-text-mixins.helper-text-color_(GrayText, $query: $query);
1630 @include character-counter-mixins.character-counter-color_(
1631 GrayText,
1632 $query: $query
1633 );
1634 @include icon-mixins.leading-icon-color_(GrayText, $query: $query);
1635 @include icon-mixins.trailing-icon-color_(GrayText, $query: $query);
1636 @include _prefix-color(GrayText, $query: $query);
1637 @include _suffix-color(GrayText, $query: $query);
1638
1639 // Mixins that are ok to include since they target variant-specific elements
1640 @include bottom-line-color_(GrayText, $query: $query);
1641 @include notched-outline-mixins.color(GrayText, $query: $query);
1642 }
1643
1644 @include dom.forced-colors-mode($exclude-ie11: true) {
1645 .mdc-text-field__input {
1646 @include feature-targeting.targets($feat-structure) {
1647 background-color: Window;
1648 }
1649 }
1650
1651 .mdc-floating-label {
1652 @include feature-targeting.targets($feat-structure) {
1653 z-index: 1;
1654 }
1655 }
1656 }
1657
1658 @include feature-targeting.targets($feat-structure) {
1659 pointer-events: none;
1660 }
1661
1662 .mdc-floating-label {
1663 @include feature-targeting.targets($feat-structure) {
1664 cursor: default;
1665 }
1666 }
1667}
1668
1669@mixin _disabled-input($query: feature-targeting.all()) {
1670 $feat-structure: feature-targeting.create-target($query, structure);
1671
1672 @include feature-targeting.targets($feat-structure) {
1673 // disabled inputs should still allow users to interact with them to select
1674 // text and scroll for textareas
1675 pointer-events: auto;
1676 }
1677}
1678
1679@mixin _disabled-filled($query: feature-targeting.all()) {
1680 $feat-structure: feature-targeting.create-target($query, structure);
1681
1682 @include fill-color_(variables.$disabled-background, $query: $query);
1683
1684 #{variables.$ripple-target} {
1685 @include feature-targeting.targets($feat-structure) {
1686 // prevent ripple from displaying on hover when some interactible
1687 // elements like input and resize handles are hovered
1688 display: none;
1689 }
1690 }
1691}
1692
1693@mixin invalid_($query: feature-targeting.all()) {
1694 $feat-structure: feature-targeting.create-target($query, structure);
1695
1696 @include hover-bottom-line-color(variables.$error, $query: $query);
1697 @include line-ripple-color(variables.$error, $query: $query);
1698 @include label-color(variables.$error, $query: $query);
1699 @include helper-text-mixins.helper-text-validation-color(
1700 variables.$error,
1701 $query: $query
1702 );
1703 @include caret-color(variables.$error, $query: $query);
1704 @include icon-mixins.trailing-icon-color(variables.$error, $query: $query);
1705
1706 // Mixins that are ok to include since they target variant-specific elements
1707 @include bottom-line-color(variables.$error, $query: $query);
1708 @include outline-color(variables.$error, $query: $query);
1709 @include hover-outline-color(variables.$error, $query: $query);
1710 @include focused-outline-color(variables.$error, $query: $query);
1711
1712 + .mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg {
1713 @include feature-targeting.targets($feat-structure) {
1714 opacity: 1;
1715 }
1716 }
1717}
1718
1719@mixin focused_($query: feature-targeting.all()) {
1720 $feat-structure: feature-targeting.create-target($query, structure);
1721
1722 @include label-color(variables.$focused-label-color, $query: $query);
1723
1724 // Mixins that are ok to include since they target variant-specific elements
1725 @include notched-outline-mixins.stroke-width(
1726 variables.$outlined-stroke-width,
1727 $query: $query
1728 );
1729
1730 + .mdc-text-field-helper-line
1731 .mdc-text-field-helper-text:not(.mdc-text-field-helper-text--validation-msg) {
1732 @include feature-targeting.targets($feat-structure) {
1733 opacity: 1;
1734 }
1735 }
1736}
1737
1738@mixin _focused-outlined($query: feature-targeting.all()) {
1739 @include notched-outline-mixins.notch-offset(
1740 variables.$outlined-stroke-width,
1741 $query: $query
1742 );
1743}
1744
1745@mixin _focused-outlined-textarea($query: feature-targeting.all()) {
1746 @include notched-outline-mixins.notch-offset(0, $query: $query);
1747}
1748
1749// Icons
1750
1751@mixin with-leading-icon_($query: feature-targeting.all()) {
1752 $feat-structure: feature-targeting.create-target($query, structure);
1753
1754 $icon-padding: icon-variables.$leading-icon-padding-left +
1755 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1756
1757 .mdc-floating-label {
1758 @include _truncate-floating-label-max-width($icon-padding, $query: $query);
1759 @include feature-targeting.targets($feat-structure) {
1760 @include rtl.reflexive-position(left, $icon-padding);
1761 }
1762 }
1763
1764 $truncation: $icon-padding + variables.$padding-horizontal;
1765
1766 .mdc-floating-label--float-above {
1767 @include _truncate-floating-label-floated-max-width(
1768 $truncation,
1769 $query: $query
1770 );
1771 }
1772}
1773
1774@mixin _with-trailing-icon($query: feature-targeting.all()) {
1775 $truncation: icon-variables.$trailing-icon-padding-left +
1776 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right +
1777 variables.$label-offset;
1778
1779 .mdc-floating-label {
1780 @include _truncate-floating-label-max-width($truncation, $query: $query);
1781 }
1782
1783 .mdc-floating-label--float-above {
1784 @include _truncate-floating-label-floated-max-width(
1785 $truncation,
1786 $query: $query
1787 );
1788 }
1789}
1790
1791@mixin _with-leading-and-trailing-icon($query: feature-targeting.all()) {
1792 $leading-icon: icon-variables.$leading-icon-padding-left +
1793 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1794 $trailing-icon: icon-variables.$trailing-icon-padding-left +
1795 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
1796 $truncation: $leading-icon + $trailing-icon;
1797
1798 .mdc-floating-label {
1799 @include _truncate-floating-label-max-width($truncation, $query: $query);
1800 }
1801
1802 .mdc-floating-label--float-above {
1803 @include _truncate-floating-label-floated-max-width(
1804 $truncation,
1805 $query: $query
1806 );
1807 }
1808}
1809
1810@mixin outlined-with-leading-icon_($query: feature-targeting.all()) {
1811 $feat-structure: feature-targeting.create-target($query, structure);
1812
1813 // Resting label position
1814 $icon-padding: icon-variables.$leading-icon-padding-left +
1815 icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
1816 $left-spacing: $icon-padding - notched-outline-variables.$leading-width;
1817
1818 .mdc-floating-label {
1819 @include feature-targeting.targets($feat-structure) {
1820 @include rtl.reflexive-position(left, $left-spacing);
1821 }
1822 }
1823
1824 // Notch width
1825 $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;
1826 @include _truncate-notched-outline-max-width(
1827 $notch-truncation,
1828 $query: $query
1829 );
1830
1831 // Floating label position and animation
1832 @include _outlined-with-leading-icon-floating-label-position-animation(
1833 $height: variables.$height,
1834 $keyframe-suffix: text-field-outlined-leading-icon,
1835 $query: $query
1836 );
1837}
1838
1839///
1840/// Applied to the outlined text field with a trailing icon
1841///
1842@mixin _outlined-with-trailing-icon($query: feature-targeting.all()) {
1843 // Resting label position
1844 $icon-padding: icon-variables.$trailing-icon-padding-left +
1845 icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
1846 // Notch width
1847 $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;
1848
1849 @include _truncate-notched-outline-max-width(
1850 $notch-truncation,
1851 $query: $query
1852 );
1853}
1854
1855///
1856/// Truncates the max-width of the notched outline by the given amount
1857///
1858/// @param {Number} $truncation - Amount to truncate the notched outline max-width
1859///
1860@mixin _truncate-notched-outline-max-width(
1861 $truncation,
1862 $query: feature-targeting.all()
1863) {
1864 @include notched-outline-mixins.notch-max-width(
1865 calc(100% - #{$truncation}),
1866 $query: $query
1867 );
1868}
1869
1870///
1871/// Truncates the max-width of the floating label by the given amount
1872///
1873/// @param {Number} $truncation - Amount to truncate the floating label max-width
1874///
1875@mixin _truncate-floating-label-max-width(
1876 $truncation,
1877 $query: feature-targeting.all()
1878) {
1879 @include floating-label-mixins.max-width(
1880 calc(100% - #{$truncation}),
1881 $query: $query
1882 );
1883}
1884
1885///
1886/// Truncates the max-width of the floating label by the given amount while scaling by the given scale value
1887///
1888/// @param {Number} $truncation - Amount to truncate the floating label max-width
1889///
1890@mixin _truncate-floating-label-floated-max-width(
1891 $truncation,
1892 $query: feature-targeting.all()
1893) {
1894 $scale: floating-label-variables.$float-scale;
1895 @include floating-label-mixins.max-width(
1896 calc(100% / #{$scale} - #{$truncation} / #{$scale}),
1897 $query: $query
1898 );
1899}
1900
1901// Textarea
1902
1903@mixin textarea_($query: feature-targeting.all()) {
1904 $feat-structure: feature-targeting.create-target($query, structure);
1905 $feat-animation: feature-targeting.create-target($query, animation);
1906
1907 @include _textarea-floating-label($query);
1908
1909 @include feature-targeting.targets($feat-structure) {
1910 flex-direction: column;
1911 align-items: center;
1912 width: auto;
1913 height: auto;
1914 padding: 0; // see below for explanation
1915 }
1916
1917 @include feature-targeting.targets($feat-animation) {
1918 transition: none;
1919 }
1920}
1921
1922@mixin _textarea-resizer($query: feature-targeting.all()) {
1923 $feat-structure: feature-targeting.create-target($query, structure);
1924
1925 @include feature-targeting.targets($feat-structure) {
1926 align-self: stretch;
1927 display: inline-flex;
1928 flex-direction: column;
1929 flex-grow: 1;
1930 max-height: 100%;
1931 max-width: 100%;
1932 min-height: variables.$height;
1933 // stylelint-disable declaration-block-no-duplicate-properties --
1934 // TODO: document why this disable is neccessary
1935
1936 // 'stretch' is the preferred rule here. It will allow the textarea to grow
1937 // to the min/max width of the container, but if an explicit width is set,
1938 // it cannot be resized horizontally.
1939 // Stretch is still a working draft. Chrome and Firefox have it implemented
1940 // with 'available' prefixes. fit-content is another good target for
1941 // Safari since it works in almost all use cases except when an explicit
1942 // width is set (the user can make the textarea smaller than the container).
1943 // None of this matters for IE11, which doesn't support resize.
1944 min-width: fit-content;
1945 /* @alternate */
1946 min-width: -moz-available;
1947 /* @alternate */
1948 min-width: -webkit-fill-available;
1949 // stylelint-enable declaration-block-no-duplicate-properties
1950 overflow: hidden;
1951 resize: both;
1952 }
1953}
1954
1955@mixin _textarea-filled-resizer($query: feature-targeting.all()) {
1956 $feat-structure: feature-targeting.create-target($query, structure);
1957 // Shift the resizer element up by a margin amount to make space for the
1958 // resize handle. For filled elements, the resize handle directly touches
1959 // the bottom line and is hard to see.
1960 // Using a margin affects the width and positioning of the overall component
1961 // and underlying textarea, which is why a transform is used instead.
1962 $y: -1 * variables.$textarea-input-handle-margin;
1963
1964 @include feature-targeting.targets($feat-structure) {
1965 transform: translateY($y);
1966 }
1967}
1968
1969@mixin _textarea-filled-resizer-children($query: feature-targeting.all()) {
1970 $feat-structure: feature-targeting.create-target($query, structure);
1971 // See above. After shifting the resize wrapper element, all of its children
1972 // should be shifted in the opposite direction (down) to compensate.
1973 $y: variables.$textarea-input-handle-margin;
1974
1975 @include feature-targeting.targets($feat-structure) {
1976 transform: translateY($y);
1977 }
1978}
1979
1980@mixin _textarea-outlined-resizer($query: feature-targeting.all()) {
1981 $feat-structure: feature-targeting.create-target($query, structure);
1982 // Shift the resizer element left/up by a margin amount to make space for the
1983 // resize handle. For outlined elements, the resize handle directly touches
1984 // the outline and is hard to see.
1985 // Using a margin affects the width and positioning of the overall component
1986 // and underlying textarea, which is why a transform is used instead.
1987 $x: -1 * variables.$textarea-input-handle-margin;
1988 $y: -1 * variables.$textarea-input-handle-margin;
1989
1990 @include feature-targeting.targets($feat-structure) {
1991 @include rtl.ignore-next-line();
1992 transform: translateX($x) translateY($y);
1993
1994 @include rtl.rtl {
1995 // Flip the horizontal shifting direction for RTL
1996 @include rtl.ignore-next-line();
1997 transform: translateX(-1 * $x) translateY($y);
1998 }
1999 }
2000}
2001
2002@mixin _textarea-outlined-resizer-children($query: feature-targeting.all()) {
2003 $feat-structure: feature-targeting.create-target($query, structure);
2004 // See above. After shifting the resize wrapper element, all of its children
2005 // should be shifted in the opposite direction (right and down) to compensate.
2006 $x: variables.$textarea-input-handle-margin;
2007 $y: variables.$textarea-input-handle-margin;
2008
2009 @include feature-targeting.targets($feat-structure) {
2010 @include rtl.ignore-next-line();
2011 transform: translateX($x) translateY($y);
2012
2013 @include rtl.rtl {
2014 // Flip the horizontal shifting direction for RTL
2015 @include rtl.ignore-next-line();
2016 transform: translateX(-1 * $x) translateY($y);
2017 }
2018 }
2019}
2020
2021@mixin _textarea-floating-label($query: feature-targeting.all()) {
2022 $feat-structure: feature-targeting.create-target($query, structure);
2023
2024 // Resting label position
2025 .mdc-floating-label {
2026 @include feature-targeting.targets($feat-structure) {
2027 top: variables.$textarea-label-top;
2028 }
2029
2030 // Resets center aligning the floating label.
2031 &:not(.mdc-floating-label--float-above) {
2032 @include feature-targeting.targets($feat-structure) {
2033 transform: none;
2034 }
2035 }
2036 }
2037}
2038
2039@mixin _textarea-input($query: feature-targeting.all()) {
2040 $feat-structure: feature-targeting.create-target($query, structure);
2041 $feat-typography: feature-targeting.create-target($query, typography);
2042
2043 @include feature-targeting.targets($feat-structure) {
2044 flex-grow: 1;
2045 height: auto;
2046 min-height: variables.$textarea-line-height;
2047 overflow-x: hidden; // https://bugzilla.mozilla.org/show_bug.cgi?id=33654
2048 overflow-y: auto;
2049 box-sizing: border-box;
2050 resize: none;
2051 // Textarea has horizontal padding instead of the container. This allows the
2052 // resize handle to extend to the edge of the container.
2053 padding: 0 variables.$padding-horizontal;
2054 }
2055
2056 @include feature-targeting.targets($feat-typography) {
2057 line-height: variables.$textarea-line-height;
2058 }
2059}
2060
2061@mixin _textarea-internal-counter($query: feature-targeting.all()) {
2062 $feat-structure: feature-targeting.create-target($query, structure);
2063
2064 @include typography.baseline-bottom(
2065 variables.$textarea-internal-counter-baseline-bottom,
2066 $query: $query
2067 );
2068 @include feature-targeting.targets($feat-structure) {
2069 align-self: flex-end;
2070 // Needed since padding is on the textarea and not the container
2071 padding: 0 variables.$padding-horizontal;
2072
2073 &::before {
2074 // Remove baseline-top
2075 display: none;
2076 }
2077 }
2078}
2079
2080@mixin _textarea-input-with-internal-counter($query: feature-targeting.all()) {
2081 $feat-structure: feature-targeting.create-target($query, structure);
2082
2083 @include feature-targeting.targets($feat-structure) {
2084 margin-bottom: variables.$textarea-internal-counter-input-margin-bottom;
2085 }
2086}
2087
2088@mixin _textarea-filled($query: feature-targeting.all()) {
2089 $feat-structure: feature-targeting.create-target($query, structure);
2090
2091 @include feature-targeting.targets($feat-structure) {
2092 &::before {
2093 // <textarea> does not align to baseline when it does not have a value,
2094 // unlike <input>, so we have to use padding to fake it instead
2095 display: none;
2096 }
2097 }
2098
2099 // Floating label position
2100 @include floating-label-mixins.float-position(
2101 variables.$textarea-filled-label-position-y,
2102 $query: $query
2103 );
2104
2105 // Floating label animation
2106 @include floating-label-mixins.shake-animation(
2107 textarea-filled,
2108 $query: $query
2109 );
2110 @at-root {
2111 @include floating-label-mixins.shake-keyframes(
2112 textarea-filled,
2113 variables.$textarea-filled-label-position-y,
2114 0%,
2115 $query: $query
2116 );
2117 }
2118}
2119
2120@mixin _textarea-filled-input($query: feature-targeting.all()) {
2121 $feat-structure: feature-targeting.create-target($query, structure);
2122
2123 @include feature-targeting.targets($feat-structure) {
2124 margin-top: variables.$textarea-filled-input-margin-top;
2125 margin-bottom: variables.$textarea-filled-input-margin-bottom;
2126 }
2127}
2128
2129@mixin _textarea-filled-no-label-input($query: feature-targeting.all()) {
2130 $feat-structure: feature-targeting.create-target($query, structure);
2131
2132 @include feature-targeting.targets($feat-structure) {
2133 margin-top: variables.$textarea-filled-no-label-input-margin-top;
2134 margin-bottom: variables.$textarea-filled-no-label-input-margin-bottom;
2135 }
2136}
2137
2138@mixin _textarea-outlined($query: feature-targeting.all()) {
2139 @include notched-outline-mixins.notch-offset(0, $query: $query);
2140
2141 // Floating label position
2142 @include notched-outline-mixins.floating-label-float-position-absolute(
2143 variables.$textarea-outlined-label-position-y,
2144 $query: $query
2145 );
2146
2147 // Floating label animation
2148 @include floating-label-mixins.shake-animation(
2149 textarea-outlined,
2150 $query: $query
2151 );
2152 @at-root {
2153 @include floating-label-mixins.shake-keyframes(
2154 textarea-outlined,
2155 variables.$textarea-outlined-label-position-y,
2156 0%,
2157 $query: $query
2158 );
2159 }
2160}
2161
2162@mixin _textarea-outlined-floating-label($query: feature-targeting.all()) {
2163 $feat-structure: feature-targeting.create-target($query, structure);
2164
2165 @include feature-targeting.targets($feat-structure) {
2166 top: variables.$textarea-outlined-label-top;
2167 }
2168}
2169
2170@mixin _textarea-outlined-input($query: feature-targeting.all()) {
2171 $feat-structure: feature-targeting.create-target($query, structure);
2172
2173 @include feature-targeting.targets($feat-structure) {
2174 margin-top: variables.$textarea-outlined-input-margin-top;
2175 margin-bottom: variables.$textarea-outlined-input-margin-bottom;
2176 }
2177}
2178
2179// Text, Prefix and Suffix
2180
2181// Common styles for the text of the text field, including the prefix, suffix,
2182// and input.
2183@mixin _text($query: feature-targeting.all()) {
2184 $feat-animation: feature-targeting.create-target($query, animation);
2185 $feat-structure: feature-targeting.create-target($query, structure);
2186
2187 // Exclude setting line-height to keep caret (text cursor) same height as the input text in iOS browser.
2188 @include typography.typography(
2189 subtitle1,
2190 $exclude-props: (line-height),
2191 $query: $query
2192 );
2193 @include feature-targeting.targets($feat-structure) {
2194 height: variables.$input-height;
2195 }
2196
2197 @include feature-targeting.targets($feat-animation) {
2198 transition: animation.standard(opacity, 150ms);
2199 }
2200}
2201
2202@mixin _input($query: feature-targeting.all()) {
2203 $feat-structure: feature-targeting.create-target($query, structure);
2204
2205 @include _text($query: $query);
2206 @include feature-targeting.targets($feat-structure) {
2207 width: 100%;
2208 min-width: 0; // Fixes flex issues on Firefox
2209 border: none;
2210 border-radius: 0;
2211 background: none;
2212 appearance: none;
2213 padding: 0;
2214
2215 // Remove built-in trailing clear icon on IE11. IE vendor prefixes cannot
2216 // be combined with other vendor prefixes like the webkit one below.
2217 &::-ms-clear {
2218 display: none;
2219 }
2220
2221 // Remove built-in datepicker icon on Chrome
2222 &::-webkit-calendar-picker-indicator {
2223 display: none;
2224 }
2225
2226 &:focus {
2227 outline: none;
2228 }
2229
2230 // Remove red outline on firefox
2231 &:invalid {
2232 box-shadow: none;
2233 }
2234 }
2235}
2236
2237@mixin _input-placeholder($query: feature-targeting.all()) {
2238 $feat-animation: feature-targeting.create-target($query, animation);
2239 $feat-structure: feature-targeting.create-target($query, structure);
2240
2241 @include feature-targeting.targets($feat-animation) {
2242 transition: animation.standard(opacity, 67ms);
2243 }
2244
2245 @include feature-targeting.targets($feat-structure) {
2246 opacity: 0;
2247 }
2248}
2249
2250@mixin _input-placeholder-visible($query: feature-targeting.all()) {
2251 $feat-animation: feature-targeting.create-target($query, animation);
2252 $feat-structure: feature-targeting.create-target($query, structure);
2253
2254 @include feature-targeting.targets($feat-animation) {
2255 transition-delay: 40ms;
2256 transition-duration: 110ms;
2257 }
2258
2259 @include feature-targeting.targets($feat-structure) {
2260 opacity: 1;
2261 }
2262}
2263
2264@mixin _affix($query: feature-targeting.all()) {
2265 $feat-structure: feature-targeting.create-target($query, structure);
2266
2267 @include _text($query: $query);
2268 @include feature-targeting.targets($feat-structure) {
2269 opacity: 0;
2270 white-space: nowrap;
2271 }
2272}
2273
2274// TODO(b/155467610): Remove when Safari supports baseline alignment
2275// https://github.com/material-components/material-components-web/issues/5879
2276@mixin _centered-affix-safari-support($query: feature-targeting.all()) {
2277 $feat-structure: feature-targeting.create-target($query, structure);
2278
2279 @include feature-targeting.targets($feat-structure) {
2280 align-items: center;
2281 align-self: center;
2282 display: inline-flex;
2283 height: 100%;
2284 }
2285}
2286
2287@mixin _affix-visible($query: feature-targeting.all()) {
2288 $feat-structure: feature-targeting.create-target($query, structure);
2289
2290 @include feature-targeting.targets($feat-structure) {
2291 opacity: 1;
2292 }
2293}
2294
2295@mixin _prefix($query: feature-targeting.all()) {
2296 $feat-structure: feature-targeting.create-target($query, structure);
2297
2298 @include feature-targeting.targets($feat-structure) {
2299 @include rtl.reflexive-box(padding, right, variables.$prefix-padding);
2300 }
2301}
2302
2303@mixin _prefix-end-aligned($query: feature-targeting.all()) {
2304 $feat-structure: feature-targeting.create-target($query, structure);
2305
2306 @include feature-targeting.targets($feat-structure) {
2307 @include rtl.reflexive-box(
2308 padding,
2309 right,
2310 variables.$prefix-end-aligned-padding
2311 );
2312 }
2313}
2314
2315@mixin _suffix($query: feature-targeting.all()) {
2316 $feat-structure: feature-targeting.create-target($query, structure);
2317
2318 @include feature-targeting.targets($feat-structure) {
2319 @include rtl.reflexive-box(padding, left, variables.$suffix-padding);
2320 }
2321}
2322
2323@mixin _suffix-end-aligned($query: feature-targeting.all()) {
2324 $feat-structure: feature-targeting.create-target($query, structure);
2325
2326 @include feature-targeting.targets($feat-structure) {
2327 @include rtl.reflexive-box(
2328 padding,
2329 left,
2330 variables.$suffix-end-aligned-padding
2331 );
2332 }
2333}
2334
2335// End aligned
2336@mixin end-aligned_($query: feature-targeting.all()) {
2337 $feat-structure: feature-targeting.create-target($query, structure);
2338
2339 .mdc-text-field__input {
2340 @include feature-targeting.targets($feat-structure) {
2341 // IE11 does not support text-align: end
2342 @include rtl.ignore-next-line();
2343 text-align: right;
2344 }
2345
2346 @include rtl.rtl {
2347 @include feature-targeting.targets($feat-structure) {
2348 @include rtl.ignore-next-line();
2349 text-align: left;
2350 }
2351 }
2352 }
2353}
2354
2355// Forces input, prefix, and suffix to be LTR when in an RTL environment. Other
2356// elements such as labels and icons will remain RTL.
2357@mixin _ltr-text($query: feature-targeting.all()) {
2358 $feat-structure: feature-targeting.create-target($query, structure);
2359
2360 @include feature-targeting.targets($feat-structure) {
2361 @include rtl.rtl {
2362 .mdc-text-field__input,
2363 .mdc-text-field__affix {
2364 @include rtl.ignore-next-line();
2365 direction: ltr;
2366 }
2367
2368 .mdc-text-field__affix--prefix {
2369 @include rtl.ignore-next-line();
2370 padding-left: 0;
2371 @include rtl.ignore-next-line();
2372 padding-right: variables.$prefix-padding;
2373 }
2374
2375 .mdc-text-field__affix--suffix {
2376 @include rtl.ignore-next-line();
2377 padding-left: variables.$suffix-padding;
2378 @include rtl.ignore-next-line();
2379 padding-right: 0;
2380 }
2381
2382 // Need to specify an order for all elements since icons maintain their
2383 // original positions. We can't just reverse the container.
2384 .mdc-text-field__icon--leading {
2385 order: 1;
2386 }
2387
2388 .mdc-text-field__affix--suffix {
2389 order: 2;
2390 }
2391
2392 .mdc-text-field__input {
2393 order: 3;
2394 }
2395
2396 .mdc-text-field__affix--prefix {
2397 order: 4;
2398 }
2399
2400 .mdc-text-field__icon--trailing {
2401 order: 5;
2402 }
2403 }
2404 }
2405}
2406
2407// Forces input, prefix, and suffix that are already forced to LTR to also be
2408// end-aligned. This mixin should be used alongside the styles provided in
2409// _ltr-text().
2410@mixin _ltr-text-end-aligned($query: feature-targeting.all()) {
2411 $feat-structure: feature-targeting.create-target($query, structure);
2412
2413 @include feature-targeting.targets($feat-structure) {
2414 @include rtl.rtl {
2415 .mdc-text-field__input {
2416 // IE11 does not support text-align: end, so we need to duplicate
2417 // the LTR end-aligned style here.
2418 @include rtl.ignore-next-line();
2419 text-align: right;
2420 }
2421
2422 .mdc-text-field__affix--prefix {
2423 // padding-left: 0 provided by _ltr-text mixin
2424 @include rtl.ignore-next-line();
2425 padding-right: variables.$prefix-end-aligned-padding;
2426 }
2427
2428 .mdc-text-field__affix--suffix {
2429 @include rtl.ignore-next-line();
2430 padding-left: variables.$suffix-end-aligned-padding;
2431 // padding-right: 0 provided by _ltr-text mixin
2432 }
2433 }
2434 }
2435}
2436
2437// Customization
2438
2439@mixin ink-color_($color, $query: feature-targeting.all()) {
2440 $feat-color: feature-targeting.create-target($query, color);
2441
2442 .mdc-text-field__input {
2443 @include feature-targeting.targets($feat-color) {
2444 @include theme.prop(color, $color);
2445 }
2446 }
2447}
2448
2449@mixin placeholder-color_($color, $query: feature-targeting.all()) {
2450 $feat-color: feature-targeting.create-target($query, color);
2451
2452 @include feature-targeting.targets($feat-color) {
2453 .mdc-text-field__input {
2454 @include placeholder-selector_ {
2455 @include theme.prop(color, $color);
2456 }
2457 }
2458 }
2459}
2460
2461@mixin fill-color_(
2462 $color,
2463 $query: feature-targeting.all(),
2464 $addAlternate: false
2465) {
2466 $feat-color: feature-targeting.create-target($query, color);
2467
2468 @include feature-targeting.targets($feat-color) {
2469 @if ($addAlternate) {
2470 /* @alternate */
2471 }
2472 @include theme.prop(background-color, $color);
2473 }
2474}
2475
2476@mixin bottom-line-color_($color, $query: feature-targeting.all()) {
2477 .mdc-line-ripple {
2478 @include line-ripple-mixins.inactive-color($color, $query: $query);
2479 }
2480}
2481
2482@mixin hover-bottom-line-color_($color, $query: feature-targeting.all()) {
2483 $feat-color: feature-targeting.create-target($query, color);
2484
2485 &:hover .mdc-line-ripple {
2486 @include line-ripple-mixins.inactive-color($color, $query: $query);
2487 }
2488}
2489
2490@mixin line-ripple-color_($color, $query: feature-targeting.all()) {
2491 .mdc-line-ripple {
2492 @include line-ripple-mixins.active-color($color, $query: $query);
2493 }
2494}
2495
2496@mixin hover-outline-color_($color, $query: feature-targeting.all()) {
2497 &:not(.mdc-text-field--focused):hover {
2498 .mdc-notched-outline {
2499 @include notched-outline-mixins.color($color, $query: $query);
2500 }
2501 }
2502}
2503
2504@mixin focused-outline-color_($color, $query: feature-targeting.all()) {
2505 &.mdc-text-field--focused {
2506 @include notched-outline-mixins.color($color, $query: $query);
2507 }
2508}
2509
2510@mixin label-ink-color_($color, $query: feature-targeting.all()) {
2511 .mdc-floating-label {
2512 @include floating-label-mixins.ink-color($color, $query: $query);
2513 }
2514}
2515
2516@mixin _prefix-color($color, $query: feature-targeting.all()) {
2517 $feat-color: feature-targeting.create-target($query, color);
2518
2519 @include feature-targeting.targets($feat-color) {
2520 .mdc-text-field__affix--prefix {
2521 @include theme.prop(color, $color);
2522 }
2523 }
2524}
2525
2526@mixin _suffix-color($color, $query: feature-targeting.all()) {
2527 $feat-color: feature-targeting.create-target($query, color);
2528
2529 @include feature-targeting.targets($feat-color) {
2530 .mdc-text-field__affix--suffix {
2531 @include theme.prop(color, $color);
2532 }
2533 }
2534}
2535
2536// Selectors
2537
2538@mixin placeholder-selector_ {
2539 // GSS will combine selectors with the same content, and some browsers have a
2540 // CSS quirk where it drops a rule if it does not recognize one of the
2541 // selectors.
2542 // To avoid GSS combining the ::placeholder and :-ms-input-placeholder
2543 // selectors, we wrap them in `@media all`.
2544 // TODO(b/142329051)
2545 @media all {
2546 // ::placeholder needs to be wrapped because IE11 will drop other selectors
2547 // with the same content
2548 &::placeholder {
2549 @content;
2550 }
2551 }
2552
2553 @media all {
2554 // :-ms-input-placeholder needs to be wrapped because Firefox will drop
2555 // other selectors with the same content
2556 &:-ms-input-placeholder {
2557 @content;
2558 }
2559 }
2560}
2561
2562// State qualifiers
2563
2564///
2565/// Helps style the text-field only when it's enabled.
2566/// @access private
2567///
2568@mixin if-enabled_ {
2569 &:not(.mdc-text-field--disabled) {
2570 @content;
2571 }
2572}
2573
2574///
2575/// Helps style the text-field only when it's disabled.
2576/// @access private
2577///
2578@mixin if-disabled_ {
2579 &.mdc-text-field--disabled {
2580 @content;
2581 }
2582}