UNPKG

26.3 kBSCSSView Raw
1//
2// Copyright 2016 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// stylelint-disable selector-class-pattern --
24// Selector '.mdc-*' should only be used in this project.
25
26@use 'sass:map';
27@use 'sass:math';
28@use '@material/animation/functions' as functions2;
29@use '@material/density/functions' as density-functions;
30@use '@material/density/variables' as density-variables;
31@use '@material/feature-targeting/feature-targeting';
32@use '@material/ripple/ripple';
33@use '@material/ripple/ripple-theme';
34@use '@material/theme/color-custom-properties';
35@use '@material/theme/custom-properties';
36@use '@material/theme/keys';
37@use '@material/theme/theme';
38@use '@material/theme/theme-color';
39@use '@material/theme/shadow-dom';
40@use '@material/touch-target/touch-target';
41@use './checkbox-custom-properties';
42
43$baseline-theme-color: secondary !default;
44$mark-color: theme-color.prop-value(on-secondary) !default;
45$border-color: rgba(theme-color.prop-value(on-surface), 0.54) !default;
46$disabled-color: rgba(theme-color.prop-value(on-surface), 0.38) !default;
47
48$ripple-size: 40px !default;
49$icon-size: 18px !default;
50$mark-stroke-size: math.div(2, 15) * $icon-size !default;
51$border-width: 2px !default;
52$transition-duration: 90ms !default;
53$item-spacing: 4px !default;
54$focus-indicator-opacity: map.get(
55 ripple-theme.$dark-ink-opacities,
56 focus
57) !default;
58
59$minimum-size: 28px !default;
60$maximum-size: $ripple-size !default;
61$density-scale: density-variables.$default-scale !default;
62$density-config: (
63 size: (
64 minimum: $minimum-size,
65 default: $ripple-size,
66 maximum: $maximum-size,
67 ),
68) !default;
69
70$ripple-target: '.mdc-checkbox__ripple';
71$custom-property-prefix: 'checkbox';
72
73// TODO(b/188417756): State layer (ripple) size token is missing including
74// `state-layer-size`.
75// TODO(b/188529841): `selected-checkmark-color` and `disabled-selected-checkmark-color` does not exist in tokens.
76$light-theme: (
77 disabled-selected-checkmark-color: $mark-color,
78 disabled-selected-icon-color: $disabled-color,
79 disabled-selected-icon-opacity: null,
80 disabled-unselected-icon-color: $disabled-color,
81 disabled-unselected-icon-opacity: null,
82 selected-checkmark-color: $mark-color,
83 selected-focus-icon-color: $baseline-theme-color,
84 selected-focus-state-layer-color: theme-color.$on-surface,
85 selected-focus-state-layer-opacity: 0.12,
86 selected-hover-icon-color: $baseline-theme-color,
87 selected-hover-state-layer-color: $baseline-theme-color,
88 selected-hover-state-layer-opacity:
89 map.get(ripple-theme.$dark-ink-opacities, hover),
90 selected-icon-color: $baseline-theme-color,
91 selected-pressed-icon-color: $baseline-theme-color,
92 selected-pressed-state-layer-color: theme-color.$on-surface,
93 selected-pressed-state-layer-opacity:
94 map.get(ripple-theme.$dark-ink-opacities, pressed),
95 state-layer-size: $ripple-size,
96 unselected-focus-icon-color: $baseline-theme-color,
97 unselected-focus-state-layer-color: theme-color.$on-surface,
98 unselected-focus-state-layer-opacity:
99 map.get(ripple-theme.$dark-ink-opacities, focus),
100 unselected-hover-icon-color: $baseline-theme-color,
101 unselected-hover-state-layer-color: theme-color.$on-surface,
102 unselected-hover-state-layer-opacity:
103 map.get(ripple-theme.$dark-ink-opacities, hover),
104 unselected-icon-color: $border-color,
105 unselected-pressed-icon-color: $border-color,
106 unselected-pressed-state-layer-color: theme-color.$on-surface,
107 unselected-pressed-state-layer-opacity:
108 map.get(ripple-theme.$dark-ink-opacities, pressed),
109);
110
111$forced-colors-theme: (
112 disabled-selected-checkmark-color: ButtonFace,
113 disabled-selected-icon-color: GrayText,
114 disabled-selected-icon-opacity: 1,
115 disabled-unselected-icon-color: GrayText,
116 disabled-unselected-icon-opacity: 1,
117 selected-checkmark-color: ButtonText,
118);
119
120@mixin theme($theme) {
121 @include theme.validate-theme-keys($light-theme, $theme);
122 @include keys.declare-custom-properties(
123 $theme,
124 $prefix: $custom-property-prefix
125 );
126}
127
128@mixin theme-styles($theme) {
129 @include theme.validate-theme-keys($light-theme, $theme);
130 $theme: keys.create-theme-properties(
131 $theme,
132 $prefix: $custom-property-prefix
133 );
134
135 @include disabled-container-colors(
136 $unmarked-stroke-color: map.get($theme, disabled-unselected-icon-color),
137 $marked-fill-color: map.get($theme, disabled-selected-icon-color)
138 );
139
140 @include ink-color(map.get($theme, selected-checkmark-color));
141 @include disabled-ink-color(
142 map.get($theme, disabled-selected-checkmark-color)
143 );
144
145 @include _icon-color(
146 map.get($theme, unselected-icon-color),
147 map.get($theme, selected-icon-color)
148 );
149
150 &:hover {
151 @include _icon-color(
152 map.get($theme, unselected-hover-icon-color),
153 map.get($theme, selected-hover-icon-color)
154 );
155 }
156
157 @include ripple-theme.focus() {
158 @include _icon-color(
159 map.get($theme, unselected-focus-icon-color),
160 map.get($theme, selected-focus-icon-color)
161 );
162 }
163
164 @include ripple-theme.active() {
165 @include _icon-color(
166 map.get($theme, unselected-pressed-icon-color),
167 map.get($theme, selected-pressed-icon-color)
168 );
169 }
170
171 @include ripple-color(
172 $color: map.get($theme, unselected-hover-state-layer-color),
173 $opacity-map: (
174 hover: map.get($theme, unselected-hover-state-layer-opacity),
175 focus: map.get($theme, unselected-focus-state-layer-opacity),
176 press: map.get($theme, unselected-pressed-state-layer-opacity),
177 )
178 );
179
180 @include focus-indicator-color(
181 $color: map.get($theme, selected-hover-state-layer-color),
182 $opacity-map: (
183 hover: map.get($theme, selected-hover-state-layer-opacity),
184 focus: map.get($theme, selected-focus-state-layer-opacity),
185 press: map.get($theme, selected-pressed-state-layer-opacity),
186 )
187 );
188
189 @include ripple-size(map.get($theme, state-layer-size));
190 // Set touch target to ripple size.
191 @include touch-target(
192 map.get($theme, state-layer-size),
193 map.get($theme, state-layer-size)
194 );
195}
196
197$light-theme-deprecated: (
198 density-scale: 0,
199 checkmark-color: $mark-color,
200 container-checked-color: $baseline-theme-color,
201 container-checked-hover-color: null,
202 container-disabled-color: $disabled-color,
203 outline-color: $border-color,
204 outline-hover-color: null,
205 ripple-color: theme-color.$on-surface,
206 ripple-opacity: ripple-theme.$dark-ink-opacities,
207 ripple-checked-color: $baseline-theme-color,
208 ripple-checked-opacity: ripple-theme.$dark-ink-opacities,
209);
210
211/// Sets theme to checkbox based on provided theme configuration.
212/// Only emits theme related styles.
213/// @param {Map} $theme - Theme configuration to use for theming checkbox.
214@mixin theme-deprecated($theme, $query: feature-targeting.all()) {
215 @include theme.validate-theme($light-theme-deprecated, $theme);
216
217 $ripple-color: map.get($theme, ripple-color);
218 $ripple-opacity: map.get($theme, ripple-opacity);
219 @if $ripple-opacity == null {
220 $ripple-opacity: ();
221 }
222 @if $ripple-color {
223 @include ripple-color(
224 $color: $ripple-color,
225 $opacity-map: $ripple-opacity,
226 $query: $query
227 );
228 }
229
230 $ripple-checked-color: map.get($theme, ripple-checked-color);
231 $ripple-checked-opacity: map.get($theme, ripple-checked-opacity);
232 @if $ripple-checked-opacity == null {
233 $ripple-checked-opacity: ();
234 }
235 @if $ripple-checked-color {
236 @include focus-indicator-color(
237 $color: $ripple-checked-color,
238 $opacity-map: $ripple-checked-opacity,
239 $query: $query
240 );
241 }
242
243 $density-scale: map.get($theme, density-scale);
244 @if $density-scale != null {
245 @include density($density-scale: $density-scale, $query: $query);
246 }
247
248 $outline-color: map.get($theme, outline-color);
249 $container-checked-color: map.get($theme, container-checked-color);
250 @if (
251 ($outline-color and not $container-checked-color) or
252 (not $outline-color and $container-checked-color)
253 ) {
254 @error 'Both `outline-color` and `container-checked-color` keys should be provided.';
255 }
256 @if ($outline-color and $container-checked-color) {
257 @include container-colors(
258 $unmarked-stroke-color: $outline-color,
259 $marked-stroke-color: $container-checked-color,
260 $marked-fill-color: $container-checked-color,
261 $query: $query
262 );
263 }
264
265 $outline-hover-color: map.get($theme, outline-hover-color);
266 $container-checked-hover-color: map.get(
267 $theme,
268 container-checked-hover-color
269 );
270 @if (
271 ($outline-hover-color and not $container-checked-hover-color) or
272 (not $outline-hover-color and $container-checked-hover-color)
273 ) {
274 @error 'Both `outline-hover-color` and `container-checked-hover-color` keys should be provided.';
275 }
276 @if ($outline-hover-color and $container-checked-hover-color) {
277 @include ripple-theme.states-selector() {
278 @include container-colors(
279 $unmarked-stroke-color: $outline-hover-color,
280 $marked-stroke-color: $container-checked-hover-color,
281 $marked-fill-color: $container-checked-hover-color,
282 $query: $query
283 );
284 }
285 }
286
287 $container-disabled-color: map.get($theme, container-disabled-color);
288 @if $container-disabled-color {
289 @include disabled-container-colors(
290 $unmarked-stroke-color: $container-disabled-color,
291 $marked-fill-color: $container-disabled-color,
292 $query: $query
293 );
294 }
295
296 $checkmark-color: map.get($theme, checkmark-color);
297 @if $checkmark-color {
298 @include ink-color($checkmark-color, $query: $query);
299 @include disabled-ink-color($checkmark-color, $query: $query);
300 }
301}
302
303///
304/// @param {Number | String} $density-scale - Density scale value for component.
305/// Supported density scale values `-3`, `-2`, `-1`, `0`.
306/// @return Returns ripple size of checkbox for given density scale.
307///
308@function get-ripple-size($density-scale) {
309 @return density-functions.prop-value(
310 $density-config: $density-config,
311 $density-scale: $density-scale,
312 $property-name: size
313 );
314}
315
316///
317/// Sets density scale for checkbox.
318///
319/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values
320/// `-3`, `-2`, `-1`, `0`.
321///
322@mixin density($density-scale, $query: feature-targeting.all()) {
323 $size: get-ripple-size($density-scale);
324
325 @include ripple-size($size, $query: $query);
326 @include touch-target($size, $ripple-size: $size, $query: $query);
327}
328
329/// Sets ripple size of checkbox and optionally set touch target size which can
330/// be more than the size of ripple.
331/// @param {Number} $ripple-size - Visual ripple size of checkbox.
332@mixin ripple-size($ripple-size, $query: feature-targeting.all()) {
333 $feat-structure: feature-targeting.create-target($query, structure);
334
335 @if $ripple-size and not custom-properties.is-custom-prop($ripple-size) {
336 $ripple-size: custom-properties.create(
337 checkbox-custom-properties.$ripple-size,
338 $ripple-size
339 );
340 }
341 $checkbox-padding: 'calc((_ripple-size - _icon-size) / 2)';
342 $replace: (
343 _ripple-size: $ripple-size,
344 _icon-size: $icon-size,
345 );
346
347 @include feature-targeting.targets($feat-structure) {
348 @include theme.property(padding, $checkbox-padding, $replace: $replace);
349 }
350
351 .mdc-checkbox__background {
352 @include feature-targeting.targets($feat-structure) {
353 @include theme.property(top, $checkbox-padding, $replace: $replace);
354 @include theme.property(left, $checkbox-padding, $replace: $replace);
355 }
356 }
357}
358
359/// Sets the touch target size and appropriate margin to accommodate the
360/// touch target.
361/// @param {Number} $touch-target-size Size of touch target (Native input) in `px`.
362/// @param {Number} $ripple-size Size of ripple in `px`.
363@mixin touch-target(
364 $touch-target-size,
365 $ripple-size,
366 $query: feature-targeting.all()
367) {
368 $feat-structure: feature-targeting.create-target($query, structure);
369
370 @if $touch-target-size {
371 @if not custom-properties.is-custom-prop($touch-target-size) {
372 $touch-target-size: custom-properties.create(
373 checkbox-custom-properties.$touch-target-size,
374 $touch-target-size
375 );
376 }
377
378 $margin: 'calc((_touch-target-size - _ripple-size) / 2)';
379 $replace: (
380 _touch-target-size: $touch-target-size,
381 _ripple-size: $ripple-size,
382 );
383
384 @include feature-targeting.targets($feat-structure) {
385 @include theme.property(margin, $margin, $replace: $replace);
386 }
387
388 $offset: 'calc((_ripple-size - _touch-target-size) / 2)';
389
390 @include feature-targeting.targets($feat-structure) {
391 .mdc-checkbox__native-control {
392 @include theme.property(top, $offset, $replace: $replace);
393 @include theme.property(right, $offset, $replace: $replace);
394 @include theme.property(left, $offset, $replace: $replace);
395 @include theme.property(width, $touch-target-size);
396 @include theme.property(height, $touch-target-size);
397 }
398 }
399 }
400}
401
402@mixin _icon-color($unselected-color, $selected-color) {
403 @if $unselected-color and $selected-color {
404 @include container-colors(
405 $unmarked-stroke-color: $unselected-color,
406 $marked-stroke-color: $selected-color,
407 $marked-fill-color: $selected-color
408 );
409 } @else if $unselected-color or $selected-color {
410 @error 'Both unselected and selected icon colors should be provided.';
411 }
412}
413
414///
415/// Sets stroke & fill colors for both marked and unmarked state of enabled checkbox.
416/// Set $generate-keyframes to false to prevent the mixin from generating @keyframes
417/// @param {Color} $unmarked-stroke-color - The desired stroke color for the unmarked state
418/// @param {Color} $unmarked-fill-color - The desired fill color for the unmarked state
419/// @param {Color} $marked-stroke-color - The desired stroke color for the marked state
420/// @param {Color} $marked-fill-color - The desired fill color for the marked state
421/// @param {Boolean} $generate-keyframes [true] - Whether animation keyframes should be generated
422///
423@mixin container-colors(
424 $unmarked-stroke-color: $border-color,
425 $unmarked-fill-color: transparent,
426 $marked-stroke-color: $baseline-theme-color,
427 $marked-fill-color: $baseline-theme-color,
428 $generate-keyframes: true,
429 $query: feature-targeting.all()
430) {
431 $feat-animation: feature-targeting.create-target($query, animation);
432 $feat-color: feature-targeting.create-target($query, color);
433
434 // Unchecked colors
435 @if (
436 $unmarked-stroke-color and not
437 custom-properties.is-custom-prop($unmarked-stroke-color)
438 ) {
439 $unmarked-stroke-color: custom-properties.create(
440 checkbox-custom-properties.$unchecked-color,
441 theme-color.prop-value($unmarked-stroke-color)
442 );
443 }
444
445 @include if-unmarked-enabled_ {
446 @include container-colors_(
447 $unmarked-stroke-color,
448 $unmarked-fill-color,
449 $query: $query
450 );
451 }
452
453 // Checked colors
454 @if (
455 $marked-stroke-color and not
456 custom-properties.is-custom-prop($marked-stroke-color)
457 ) {
458 $marked-stroke-color: custom-properties.create(
459 checkbox-custom-properties.$checked-color,
460 custom-properties.create(
461 color-custom-properties.$secondary,
462 theme-color.prop-value($marked-stroke-color)
463 )
464 );
465 }
466 @if (
467 $marked-fill-color and not
468 custom-properties.is-custom-prop($marked-fill-color)
469 ) {
470 $marked-fill-color: custom-properties.create(
471 checkbox-custom-properties.$checked-color,
472 custom-properties.create(
473 color-custom-properties.$secondary,
474 theme-color.prop-value($marked-fill-color)
475 )
476 );
477 }
478
479 @include if-marked-enabled_ {
480 @include container-colors_(
481 $marked-stroke-color,
482 $marked-fill-color,
483 $query: $query
484 );
485 }
486
487 @if $generate-keyframes and
488 $unmarked-stroke-color and
489 $marked-stroke-color and
490 $unmarked-fill-color and
491 $marked-fill-color
492 {
493 $uid: theme-color.color-hash($unmarked-stroke-color) +
494 theme-color.color-hash($marked-stroke-color) +
495 theme-color.color-hash($unmarked-fill-color) +
496 theme-color.color-hash($marked-fill-color);
497
498 $anim-selector: if(&, '&.mdc-checkbox--anim', '.mdc-checkbox--anim');
499
500 @include feature-targeting.targets($feat-animation, $feat-color) {
501 @include container-keyframes_(
502 $from-stroke-color: $unmarked-stroke-color,
503 $to-stroke-color: $marked-stroke-color,
504 $from-fill-color: $unmarked-fill-color,
505 $to-fill-color: $marked-fill-color,
506 $uid: #{$uid}
507 );
508 }
509
510 #{$anim-selector} {
511 &-unchecked-checked,
512 &-unchecked-indeterminate {
513 .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
514 @include feature-targeting.targets($feat-animation) {
515 animation-name: mdc-checkbox-fade-in-background-#{$uid};
516 }
517 }
518 }
519
520 &-checked-unchecked,
521 &-indeterminate-unchecked {
522 .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
523 @include feature-targeting.targets($feat-animation) {
524 animation-name: mdc-checkbox-fade-out-background-#{$uid};
525 }
526 }
527 }
528 }
529 }
530}
531
532///
533/// Sets stroke & fill colors for both marked and unmarked state of disabled checkbox.
534/// @param {Color} $unmarked-stroke-color - The desired stroke color for the unmarked state
535/// @param {Color} $unmarked-fill-color - The desired fill color for the unmarked state
536/// @param {Color} $marked-stroke-color - The desired stroke color for the marked state
537/// @param {Color} $marked-fill-color - The desired fill color for the marked state
538///
539@mixin disabled-container-colors(
540 $unmarked-stroke-color: $disabled-color,
541 $unmarked-fill-color: transparent,
542 $marked-stroke-color: transparent,
543 $marked-fill-color: $disabled-color,
544 $query: feature-targeting.all()
545) {
546 @if (
547 $unmarked-stroke-color and not
548 custom-properties.is-custom-prop($unmarked-stroke-color)
549 ) {
550 $unmarked-stroke-color: custom-properties.create(
551 checkbox-custom-properties.$disabled-color,
552 theme-color.prop-value($unmarked-stroke-color)
553 );
554 }
555
556 @if $unmarked-stroke-color == null {
557 $unmarked-fill-color: null;
558 }
559
560 @include if-unmarked-disabled_ {
561 @include container-colors_(
562 $unmarked-stroke-color,
563 $unmarked-fill-color,
564 $query: $query
565 );
566 }
567
568 @if (
569 $marked-fill-color and not
570 custom-properties.is-custom-prop($marked-fill-color)
571 ) {
572 $marked-fill-color: custom-properties.create(
573 checkbox-custom-properties.$disabled-color,
574 theme-color.prop-value($marked-fill-color)
575 );
576 }
577
578 @if $marked-fill-color and
579 custom-properties.get-fallback($marked-fill-color) ==
580 GrayText
581 {
582 // Transparent appears white in HCM
583 $marked-stroke-color: GrayText;
584 }
585
586 @if $marked-fill-color == null {
587 $marked-stroke-color: null;
588 }
589
590 @include if-marked-disabled_ {
591 @include container-colors_(
592 $marked-stroke-color,
593 $marked-fill-color,
594 $query: $query
595 );
596 }
597}
598
599///
600/// Sets the ink color of the checked and indeterminate icons for an enabled checkbox
601/// @param {Color} $color - The desired ink color in enabled state
602///
603@mixin ink-color($color, $query: feature-targeting.all()) {
604 @if ($color and not custom-properties.is-custom-prop($color)) {
605 $color: custom-properties.create(
606 checkbox-custom-properties.$ink-color,
607 $color
608 );
609 }
610
611 @include if-enabled_ {
612 @include ink-color_($color, $query: $query);
613 }
614}
615
616///
617/// Sets the ink color of the checked and indeterminate icons for a disabled checkbox
618/// @param {Color} $color - The desired ink color in disabled state
619///
620@mixin disabled-ink-color($color, $query: feature-targeting.all()) {
621 @if ($color and not custom-properties.is-custom-prop($color)) {
622 $color: custom-properties.create(
623 checkbox-custom-properties.$ink-color,
624 $color
625 );
626 }
627
628 @include if-disabled_ {
629 @include ink-color_($color, $query: $query);
630 }
631}
632
633/// Sets ripple color when checkbox is not in checked state.
634@mixin ripple-color(
635 $color,
636 $opacity-map: null,
637 $query: feature-targeting.all()
638) {
639 @include ripple-theme.states(
640 $color: $color,
641 $opacity-map: $opacity-map,
642 $query: $query,
643 $ripple-target: $ripple-target
644 );
645}
646
647/// Sets focus indicator color when checkbox is in checked state.
648@mixin focus-indicator-color(
649 $color,
650 $opacity-map: null,
651 $query: feature-targeting.all()
652) {
653 $feat-color: feature-targeting.create-target($query, color);
654
655 &.mdc-checkbox--selected {
656 @include ripple-theme.states(
657 $color: $color,
658 $opacity-map: $opacity-map,
659 $query: $query,
660 $ripple-target: $ripple-target
661 );
662 }
663
664 &.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected {
665 @include ripple-theme.states-base-color(
666 $color: $color,
667 $query: $query,
668 $ripple-target: $ripple-target
669 );
670 }
671}
672
673//
674// Private
675//
676
677///
678/// Helps select the checkbox background only when its native control is in
679/// enabled state.
680/// @access private
681///
682@mixin if-enabled_ {
683 .mdc-checkbox__native-control:enabled ~ {
684 @content;
685 }
686}
687
688///
689/// Helps select the checkbox background only when its native control is in
690/// disabled state.
691/// @access private
692///
693@mixin if-disabled_ {
694 .mdc-checkbox__native-control:disabled ~ {
695 @content;
696 }
697}
698
699///
700/// Helps select the checkbox background only when its native control is in
701/// unmarked & enabled state.
702/// @access private
703///
704@mixin if-unmarked-enabled_ {
705 .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate):not([data-indeterminate='true'])
706 ~ {
707 @content;
708 }
709}
710
711///
712/// Helps select the checkbox background only when its native control is in
713/// unmarked & disabled state.
714/// @access private
715///
716@mixin if-unmarked-disabled_ {
717 // Note: we must use `[disabled]` instead of `:disabled` below because Edge does not always recalculate the style
718 // property when the `:disabled` pseudo-class is followed by a sibling combinator. See:
719 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231/
720 .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate='true'])
721 ~ {
722 @content;
723 }
724}
725
726///
727/// Helps select the checkbox background only when its native control is in
728/// marked & enabled state.
729/// @access private
730///
731@mixin if-marked-enabled_ {
732 .mdc-checkbox__native-control:enabled:checked,
733 .mdc-checkbox__native-control:enabled:indeterminate,
734 .mdc-checkbox__native-control[data-indeterminate='true']:enabled {
735 ~ {
736 @content;
737 }
738 }
739}
740
741///
742/// Helps select the checkbox background only when its native control is in
743/// marked & disabled state.
744/// @access private
745///
746@mixin if-marked-disabled_ {
747 // Note: we must use `[disabled]` instead of `:disabled` below because Edge does not always recalculate the style
748 // property when the `:disabled` pseudo-class is followed by a sibling combinator. See:
749 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231/
750 .mdc-checkbox__native-control[disabled]:checked,
751 .mdc-checkbox__native-control[disabled]:indeterminate,
752 .mdc-checkbox__native-control[data-indeterminate='true'][disabled] {
753 ~ {
754 @content;
755 }
756 }
757}
758
759///
760/// Sets the stroke & fill colors for the checkbox.
761/// This mixin should be wrapped in a mixin that qualifies state such as
762/// `mdc-checkbox-if-unmarked-enabled_`.
763/// @access private
764///
765@mixin container-colors_(
766 $stroke-color,
767 $fill-color,
768 $query: feature-targeting.all()
769) {
770 $feat-color: feature-targeting.create-target($query, color);
771
772 .mdc-checkbox__background {
773 @include feature-targeting.targets($feat-color) {
774 @include theme.property(border-color, $stroke-color);
775 @include theme.property(background-color, $fill-color);
776 }
777 }
778}
779
780///
781/// Sets the ink color of the checked and indeterminate icons for a checkbox.
782/// This mixin should be wrapped in a mixin that qualifies state such as
783/// `mdc-checkbox-if-unmarked_`.
784/// @access private
785///
786@mixin ink-color_($color, $query: feature-targeting.all()) {
787 $feat-color: feature-targeting.create-target($query, color);
788
789 .mdc-checkbox__background {
790 .mdc-checkbox__checkmark {
791 @include feature-targeting.targets($feat-color) {
792 @include theme.property(color, $color);
793 }
794 }
795
796 .mdc-checkbox__mixedmark {
797 @include feature-targeting.targets($feat-color) {
798 @include theme.property(border-color, $color);
799 }
800 }
801 }
802}
803
804@mixin container-keyframes_(
805 $from-stroke-color,
806 $to-stroke-color,
807 $from-fill-color,
808 $to-fill-color,
809 $uid
810) {
811 @keyframes mdc-checkbox-fade-in-background-#{$uid} {
812 0% {
813 @include theme.property(border-color, $from-stroke-color);
814 @include theme.property(background-color, $from-fill-color);
815 }
816
817 50% {
818 @include theme.property(border-color, $to-stroke-color);
819 @include theme.property(background-color, $to-fill-color);
820 }
821 }
822
823 @keyframes mdc-checkbox-fade-out-background-#{$uid} {
824 0%,
825 80% {
826 @include theme.property(border-color, $to-stroke-color);
827 @include theme.property(background-color, $to-fill-color);
828 }
829
830 100% {
831 @include theme.property(border-color, $from-stroke-color);
832 @include theme.property(background-color, $from-fill-color);
833 }
834 }
835}