_mixins.scss 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  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. @use "sass:math";
  23. @use "@material/animation/functions" as functions2;
  24. @use "@material/density/functions" as density-functions;
  25. @use "@material/feature-targeting/functions" as feature-targeting-functions;
  26. @use "@material/feature-targeting/mixins" as feature-targeting-mixins;
  27. @use "@material/ripple/mixins" as ripple-mixins;
  28. @use "@material/touch-target/mixins" as touch-target-mixins;
  29. @use "@material/theme/functions" as theme-functions;
  30. @use "./functions";
  31. @use "./keyframes";
  32. @use "./variables";
  33. @use "@material/theme/mixins" as theme-mixins;
  34. @use "@material/touch-target/variables" as touch-target-variables;
  35. //
  36. // Public
  37. //
  38. $ripple-target: ".mdc-checkbox__ripple";
  39. ///
  40. /// Checkbox core styles.
  41. ///
  42. @mixin core-styles($query: feature-targeting-functions.all()) {
  43. @include without-ripple($query);
  44. @include ripple($query);
  45. }
  46. // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
  47. // checkbox styles. It is recommended that most users use `mdc-checkbox-core-styles` instead.
  48. @mixin without-ripple($query: feature-targeting-functions.all()) {
  49. // postcss-bem-linter: define checkbox
  50. $feat-animation: feature-targeting-functions.create-target($query, animation);
  51. $feat-color: feature-targeting-functions.create-target($query, color);
  52. $feat-structure: feature-targeting-functions.create-target($query, structure);
  53. @include touch-target-mixins.wrapper($query); // COPYBARA_COMMENT_THIS_LINE
  54. @include feature-targeting-mixins.targets($feat-animation) {
  55. @include keyframes.mark-keyframes_;
  56. }
  57. .mdc-checkbox {
  58. @include feature-targeting-mixins.targets($feat-structure) {
  59. @include base_;
  60. }
  61. @include focus-indicator-color(variables.$baseline-theme-color, $query: $query);
  62. @include density(variables.$density-scale, $query: $query);
  63. }
  64. @include container-colors($query: $query);
  65. @include disabled-container-colors($query: $query);
  66. @include ink-color(variables.$mark-color, $query: $query);
  67. @include disabled-ink-color(variables.$mark-color, $query: $query);
  68. @media screen and (-ms-high-contrast: active) {
  69. @include disabled-container-colors(
  70. $unmarked-stroke-color: GrayText,
  71. $unmarked-fill-color: transparent,
  72. $marked-stroke-color: GrayText,
  73. $marked-fill-color: transparent,
  74. $query: $query
  75. );
  76. @include disabled-ink-color(GrayText, $query: $query);
  77. .mdc-checkbox__mixedmark {
  78. @include feature-targeting-mixins.targets($feat-structure) {
  79. margin: 0 1px; // Extra horizontal space around mixedmark symbol.
  80. }
  81. }
  82. }
  83. // Needed to disable hover effects on CSS-only (non-JS) checkboxes
  84. .mdc-checkbox--disabled {
  85. @include feature-targeting-mixins.targets($feat-structure) {
  86. @include disabled_;
  87. }
  88. }
  89. .mdc-checkbox__background {
  90. @include background_($query);
  91. }
  92. .mdc-checkbox__checkmark {
  93. @include checkmark_($query);
  94. }
  95. .mdc-checkbox__checkmark-path {
  96. @include checkmark-path_($query);
  97. }
  98. .mdc-checkbox__mixedmark {
  99. @include mixedmark_($query);
  100. }
  101. // JS checkbox
  102. .mdc-checkbox--upgraded {
  103. .mdc-checkbox__background,
  104. .mdc-checkbox__checkmark,
  105. .mdc-checkbox__checkmark-path,
  106. .mdc-checkbox__mixedmark {
  107. @include feature-targeting-mixins.targets($feat-animation) {
  108. @include child--upgraded_;
  109. }
  110. }
  111. }
  112. .mdc-checkbox--anim {
  113. @include feature-targeting-mixins.targets($feat-animation) {
  114. @include anim_;
  115. }
  116. }
  117. .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background,
  118. .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background {
  119. @include feature-targeting-mixins.targets($feat-animation) {
  120. @include background--marked_;
  121. }
  122. .mdc-checkbox__checkmark-path {
  123. @include feature-targeting-mixins.targets($feat-structure) {
  124. @include checkmark-path--marked_;
  125. }
  126. }
  127. }
  128. // The frame's ::before element is used as a focus indicator for the checkbox
  129. .mdc-checkbox__background::before {
  130. @include focus-indicator_($query);
  131. }
  132. .mdc-checkbox__native-control:focus ~ .mdc-checkbox__background::before {
  133. @include focus-indicator--focused_($query);
  134. }
  135. .mdc-checkbox__native-control {
  136. @include feature-targeting-mixins.targets($feat-structure) {
  137. @include native-control_;
  138. }
  139. &:disabled {
  140. @include feature-targeting-mixins.targets($feat-structure) {
  141. @include disabled_;
  142. }
  143. }
  144. }
  145. .mdc-checkbox--touch {
  146. @include touch-target-mixins.margin(
  147. $component-height: variables.$ripple-size,
  148. $component-width: variables.$ripple-size,
  149. $query: $query);
  150. @include touch-target(touch-target-variables.$height, $query: $query);
  151. }
  152. .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background {
  153. .mdc-checkbox__checkmark {
  154. @include checkmark--checked_($query);
  155. }
  156. .mdc-checkbox__mixedmark {
  157. @include feature-targeting-mixins.targets($feat-structure) {
  158. @include mixedmark--checked_;
  159. }
  160. }
  161. }
  162. .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background {
  163. .mdc-checkbox__checkmark {
  164. @include checkmark--indeterminate_($query);
  165. }
  166. .mdc-checkbox__mixedmark {
  167. @include feature-targeting-mixins.targets($feat-structure) {
  168. @include mixedmark--indeterminate_;
  169. }
  170. }
  171. }
  172. // postcss-bem-linter: end
  173. }
  174. // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
  175. // checkbox styles. It is recommended that most users use `mdc-checkbox-core-styles` instead.
  176. @mixin ripple($query: feature-targeting-functions.all()) {
  177. $feat-structure: feature-targeting-functions.create-target($query, structure);
  178. @include ripple-mixins.common($query); // COPYBARA_COMMENT_THIS_LINE
  179. .mdc-checkbox {
  180. @include ripple-mixins.surface($query: $query, $ripple-target: $ripple-target);
  181. @include ripple-mixins.states($color: on-surface, $query: $query, $ripple-target: $ripple-target);
  182. @include ripple-mixins.radius-unbounded($query: $query, $ripple-target: $ripple-target);
  183. }
  184. #{$ripple-target} {
  185. @include ripple-mixins.target-common($query: $query);
  186. }
  187. .mdc-ripple-upgraded--background-focused .mdc-checkbox__background::before {
  188. @include feature-targeting-mixins.targets($feat-structure) {
  189. content: none;
  190. }
  191. }
  192. }
  193. ///
  194. /// Sets density scale for checkbox.
  195. ///
  196. /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values
  197. /// `-3`, `-2`, `-1`, `0`.
  198. ///
  199. @mixin density($density-scale, $query: feature-targeting-functions.all()) {
  200. $size: density-functions.prop-value(
  201. $density-config: variables.$density-config,
  202. $density-scale: $density-scale,
  203. $property-name: size,
  204. );
  205. @include ripple-size($size, $query: $query);
  206. @if $density-scale != 0 {
  207. @include touch-target-reset_($query: $query);
  208. }
  209. }
  210. @mixin ripple-size($ripple-size, $query: feature-targeting-functions.all()) {
  211. $feat-structure: feature-targeting-functions.create-target($query, structure);
  212. $checkbox-padding: ($ripple-size - variables.$icon-size) / 2;
  213. @include feature-targeting-mixins.targets($feat-structure) {
  214. padding: $checkbox-padding;
  215. }
  216. .mdc-checkbox__background {
  217. @include feature-targeting-mixins.targets($feat-structure) {
  218. top: $checkbox-padding;
  219. left: $checkbox-padding;
  220. }
  221. }
  222. .mdc-checkbox__background::before {
  223. @include feature-targeting-mixins.targets($feat-structure) {
  224. top: -(variables.$border-width) - $checkbox-padding;
  225. left: -(variables.$border-width) - $checkbox-padding;
  226. width: $ripple-size;
  227. height: $ripple-size;
  228. }
  229. }
  230. @include touch-target($ripple-size, $ripple-size: $ripple-size, $query: $query);
  231. }
  232. ///
  233. /// Sets stroke & fill colors for both marked and unmarked state of enabled checkbox.
  234. /// Set $generate-keyframes to false to prevent the mixin from generating @keyframes
  235. /// @param {Color} $unmarked-stroke-color - The desired stroke color for the unmarked state
  236. /// @param {Color} $unmarked-fill-color - The desired fill color for the unmarked state
  237. /// @param {Color} $marked-stroke-color - The desired stroke color for the marked state
  238. /// @param {Color} $marked-fill-color - The desired fill color for the marked state
  239. /// @param {Boolean} $generate-keyframes [true] - Whether animation keyframes should be generated
  240. ///
  241. @mixin container-colors(
  242. $unmarked-stroke-color: variables.$border-color,
  243. $unmarked-fill-color: transparent,
  244. $marked-stroke-color: variables.$baseline-theme-color,
  245. $marked-fill-color: variables.$baseline-theme-color,
  246. $generate-keyframes: true,
  247. $query: feature-targeting-functions.all()
  248. ) {
  249. $feat-animation: feature-targeting-functions.create-target($query, animation);
  250. $feat-color: feature-targeting-functions.create-target($query, color);
  251. @include if-unmarked-enabled_ {
  252. @include container-colors_($unmarked-stroke-color, $unmarked-fill-color, $query: $query);
  253. }
  254. @include if-marked-enabled_ {
  255. @include container-colors_($marked-stroke-color, $marked-fill-color, $query: $query);
  256. }
  257. @if $generate-keyframes {
  258. $uid: theme-functions.color-hash($unmarked-stroke-color) +
  259. theme-functions.color-hash($marked-stroke-color) +
  260. theme-functions.color-hash($unmarked-fill-color) +
  261. theme-functions.color-hash($marked-fill-color);
  262. $anim-selector: if(&, "&.mdc-checkbox--anim", ".mdc-checkbox--anim");
  263. @include feature-targeting-mixins.targets($feat-animation, $feat-color) {
  264. @include keyframes.container-keyframes_(
  265. $from-stroke-color: $unmarked-stroke-color,
  266. $to-stroke-color: $marked-stroke-color,
  267. $from-fill-color: $unmarked-fill-color,
  268. $to-fill-color: $marked-fill-color,
  269. $uid: #{$uid}
  270. );
  271. }
  272. // stylelint-disable max-nesting-depth
  273. #{$anim-selector} {
  274. &-unchecked-checked,
  275. &-unchecked-indeterminate {
  276. .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
  277. @include feature-targeting-mixins.targets($feat-animation) {
  278. animation-name: mdc-checkbox-fade-in-background-#{$uid};
  279. }
  280. }
  281. }
  282. &-checked-unchecked,
  283. &-indeterminate-unchecked {
  284. .mdc-checkbox__native-control:enabled ~ .mdc-checkbox__background {
  285. @include feature-targeting-mixins.targets($feat-animation) {
  286. animation-name: mdc-checkbox-fade-out-background-#{$uid};
  287. }
  288. }
  289. }
  290. }
  291. // stylelint-enable max-nesting-depth
  292. }
  293. }
  294. ///
  295. /// Sets stroke & fill colors for both marked and unmarked state of disabled checkbox.
  296. /// @param {Color} $unmarked-stroke-color - The desired stroke color for the unmarked state
  297. /// @param {Color} $unmarked-fill-color - The desired fill color for the unmarked state
  298. /// @param {Color} $marked-stroke-color - The desired stroke color for the marked state
  299. /// @param {Color} $marked-fill-color - The desired fill color for the marked state
  300. ///
  301. @mixin disabled-container-colors(
  302. $unmarked-stroke-color: variables.$disabled-color,
  303. $unmarked-fill-color: transparent,
  304. $marked-stroke-color: transparent,
  305. $marked-fill-color: variables.$disabled-color,
  306. $query: feature-targeting-functions.all()
  307. ) {
  308. @include if-unmarked-disabled_ {
  309. @include container-colors_($unmarked-stroke-color, $unmarked-fill-color, $query: $query);
  310. }
  311. @include if-marked-disabled_ {
  312. @include container-colors_($marked-stroke-color, $marked-fill-color, $query: $query);
  313. }
  314. }
  315. ///
  316. /// Sets the ink color of the checked and indeterminate icons for an enabled checkbox
  317. /// @param {Color} $color - The desired ink color in enabled state
  318. ///
  319. @mixin ink-color($color, $query: feature-targeting-functions.all()) {
  320. @include if-enabled_ {
  321. @include ink-color_($color, $query: $query);
  322. }
  323. }
  324. ///
  325. /// Sets the ink color of the checked and indeterminate icons for a disabled checkbox
  326. /// @param {Color} $color - The desired ink color in disabled state
  327. ///
  328. @mixin disabled-ink-color($color, $query: feature-targeting-functions.all()) {
  329. $feat-color: feature-targeting-functions.create-target($query, color);
  330. @include if-disabled_ {
  331. @include ink-color_($color, $query: $query);
  332. }
  333. }
  334. @mixin focus-indicator-color($color, $query: feature-targeting-functions.all()) {
  335. $feat-color: feature-targeting-functions.create-target($query, color);
  336. .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background::before,
  337. .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background::before {
  338. @include feature-targeting-mixins.targets($feat-color) {
  339. @include theme-mixins.prop(background-color, $color);
  340. }
  341. }
  342. &.mdc-checkbox--selected {
  343. @include ripple-mixins.states($color: $color, $query: $query, $ripple-target: $ripple-target);
  344. }
  345. &.mdc-ripple-upgraded--background-focused.mdc-checkbox--selected {
  346. @include ripple-mixins.states-base-color($color: $color, $query: $query, $ripple-target: $ripple-target);
  347. }
  348. }
  349. ///
  350. /// Sets checkbox touch target size which can be more than the ripple size. Param `$ripple-size` is required for custom
  351. /// ripple size.
  352. ///
  353. /// @param {Number} $size Size of touch target (Native input) in `px`.
  354. /// @param {Number} $ripple-size Size of ripple in `px`. Required only for custom ripple size.
  355. ///
  356. @mixin touch-target(
  357. $size: variables.$ripple-size,
  358. $ripple-size: variables.$ripple-size,
  359. $query: feature-targeting-functions.all()) {
  360. $feat-structure: feature-targeting-functions.create-target($query, structure);
  361. $offset: ($ripple-size - $size) / 2;
  362. @include feature-targeting-mixins.targets($feat-structure) {
  363. .mdc-checkbox__native-control {
  364. top: $offset;
  365. right: $offset;
  366. left: $offset;
  367. width: $size;
  368. height: $size;
  369. }
  370. }
  371. }
  372. //
  373. // Private
  374. //
  375. @mixin base_ {
  376. display: inline-block;
  377. position: relative;
  378. flex: 0 0 variables.$icon-size;
  379. box-sizing: content-box;
  380. width: variables.$icon-size;
  381. height: variables.$icon-size;
  382. line-height: 0;
  383. white-space: nowrap;
  384. cursor: pointer;
  385. vertical-align: bottom;
  386. }
  387. @mixin disabled_ {
  388. cursor: default;
  389. pointer-events: none;
  390. }
  391. @mixin child--upgraded_ {
  392. // Due to the myriad of selector combos used to properly style a CSS-only checkbox, all of
  393. // which have varying selector precedence and make use of transitions, it is cleaner and more
  394. // efficient here to simply use !important, since the mdc-checkbox--anim-* classes will take
  395. // over from here.
  396. transition: none !important;
  397. }
  398. // Animation
  399. @mixin anim_ {
  400. $mdc-checkbox-indeterminate-change-duration_: 500ms;
  401. // stylelint-disable selector-max-type
  402. &-unchecked-checked,
  403. &-unchecked-indeterminate,
  404. &-checked-unchecked,
  405. &-indeterminate-unchecked {
  406. .mdc-checkbox__background {
  407. animation-duration: variables.$transition-duration * 2;
  408. animation-timing-function: linear;
  409. }
  410. }
  411. &-unchecked-checked {
  412. .mdc-checkbox__checkmark-path {
  413. // Instead of delaying the animation, we simply multiply its length by 2 and begin the
  414. // animation at 50% in order to prevent a flash of styles applied to a checked checkmark
  415. // as the background is fading in before the animation begins.
  416. animation: mdc-checkbox-unchecked-checked-checkmark-path variables.$transition-duration * 2 linear 0s;
  417. transition: none;
  418. }
  419. }
  420. &-unchecked-indeterminate {
  421. .mdc-checkbox__mixedmark {
  422. animation: mdc-checkbox-unchecked-indeterminate-mixedmark variables.$transition-duration linear 0s;
  423. transition: none;
  424. }
  425. }
  426. &-checked-unchecked {
  427. .mdc-checkbox__checkmark-path {
  428. animation: mdc-checkbox-checked-unchecked-checkmark-path variables.$transition-duration linear 0s;
  429. transition: none;
  430. }
  431. }
  432. &-checked-indeterminate {
  433. .mdc-checkbox__checkmark {
  434. animation: mdc-checkbox-checked-indeterminate-checkmark variables.$transition-duration linear 0s;
  435. transition: none;
  436. }
  437. .mdc-checkbox__mixedmark {
  438. animation: mdc-checkbox-checked-indeterminate-mixedmark variables.$transition-duration linear 0s;
  439. transition: none;
  440. }
  441. }
  442. &-indeterminate-checked {
  443. .mdc-checkbox__checkmark {
  444. animation: mdc-checkbox-indeterminate-checked-checkmark $mdc-checkbox-indeterminate-change-duration_ linear 0s;
  445. transition: none;
  446. }
  447. .mdc-checkbox__mixedmark {
  448. animation: mdc-checkbox-indeterminate-checked-mixedmark $mdc-checkbox-indeterminate-change-duration_ linear 0s;
  449. transition: none;
  450. }
  451. }
  452. &-indeterminate-unchecked {
  453. .mdc-checkbox__mixedmark {
  454. // stylelint-disable-next-line declaration-colon-space-after
  455. animation:
  456. mdc-checkbox-indeterminate-unchecked-mixedmark $mdc-checkbox-indeterminate-change-duration_ * .6 linear 0s;
  457. transition: none;
  458. }
  459. }
  460. // stylelint-enable selector-max-type
  461. }
  462. // Background
  463. ///
  464. /// Helps select the checkbox background only when its native control is in
  465. /// enabled state.
  466. /// @access private
  467. ///
  468. @mixin if-enabled_ {
  469. .mdc-checkbox__native-control:enabled ~ {
  470. @content;
  471. }
  472. }
  473. ///
  474. /// Helps select the checkbox background only when its native control is in
  475. /// disabled state.
  476. /// @access private
  477. ///
  478. @mixin if-disabled_ {
  479. .mdc-checkbox__native-control:disabled ~ {
  480. @content;
  481. }
  482. }
  483. ///
  484. /// Helps select the checkbox background only when its native control is in
  485. /// unmarked & enabled state.
  486. /// @access private
  487. ///
  488. @mixin if-unmarked-enabled_ {
  489. .mdc-checkbox__native-control:enabled:not(:checked):not(:indeterminate) ~ {
  490. @content;
  491. }
  492. }
  493. ///
  494. /// Helps select the checkbox background only when its native control is in
  495. /// unmarked & disabled state.
  496. /// @access private
  497. ///
  498. @mixin if-unmarked-disabled_ {
  499. // Note: we must use `[disabled]` instead of `:disabled` below because Edge does not always recalculate the style
  500. // property when the `:disabled` pseudo-class is followed by a sibling combinator. See:
  501. // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231/
  502. .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate) ~ {
  503. @content;
  504. }
  505. }
  506. ///
  507. /// Helps select the checkbox background only when its native control is in
  508. /// marked & enabled state.
  509. /// @access private
  510. ///
  511. @mixin if-marked-enabled_ {
  512. .mdc-checkbox__native-control:enabled:checked,
  513. .mdc-checkbox__native-control:enabled:indeterminate {
  514. ~ {
  515. @content;
  516. }
  517. }
  518. }
  519. ///
  520. /// Helps select the checkbox background only when its native control is in
  521. /// marked & disabled state.
  522. /// @access private
  523. ///
  524. @mixin if-marked-disabled_ {
  525. // Note: we must use `[disabled]` instead of `:disabled` below because Edge does not always recalculate the style
  526. // property when the `:disabled` pseudo-class is followed by a sibling combinator. See:
  527. // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231/
  528. .mdc-checkbox__native-control[disabled]:checked,
  529. .mdc-checkbox__native-control[disabled]:indeterminate {
  530. ~ {
  531. @content;
  532. }
  533. }
  534. }
  535. @mixin background_($query: feature-targeting-functions.all()) {
  536. $feat-animation: feature-targeting-functions.create-target($query, animation);
  537. $feat-structure: feature-targeting-functions.create-target($query, structure);
  538. $feat-color: feature-targeting-functions.create-target($query, color);
  539. @include feature-targeting-mixins.targets($feat-structure) {
  540. display: inline-flex;
  541. position: absolute;
  542. align-items: center;
  543. justify-content: center;
  544. box-sizing: border-box;
  545. width: variables.$icon-size;
  546. height: variables.$icon-size;
  547. // border-color is overridden by the mdc-checkbox-unmarked-stroke-color() mixin
  548. border: variables.$border-width solid currentColor;
  549. border-radius: 2px;
  550. background-color: transparent;
  551. pointer-events: none;
  552. will-change: background-color, border-color;
  553. }
  554. .mdc-checkbox__background::before {
  555. @include feature-targeting-mixins.targets($feat-color) {
  556. @include theme-mixins.prop(background-color, on-surface);
  557. }
  558. }
  559. @include feature-targeting-mixins.targets($feat-animation) {
  560. transition:
  561. functions.transition-exit(background-color),
  562. functions.transition-exit(border-color);
  563. }
  564. }
  565. @mixin background--marked_ {
  566. transition:
  567. functions.transition-enter(border-color),
  568. functions.transition-enter(background-color);
  569. }
  570. ///
  571. /// Sets the stroke & fill colors for the checkbox.
  572. /// This mixin should be wrapped in a mixin that qualifies state such as
  573. /// `mdc-checkbox-if-unmarked-enabled_`.
  574. /// @access private
  575. ///
  576. @mixin container-colors_($stroke-color, $fill-color, $query: feature-targeting-functions.all()) {
  577. $feat-color: feature-targeting-functions.create-target($query, color);
  578. .mdc-checkbox__background {
  579. @include feature-targeting-mixins.targets($feat-color) {
  580. @include theme-mixins.prop(border-color, $stroke-color);
  581. @include theme-mixins.prop(background-color, $fill-color);
  582. }
  583. }
  584. }
  585. // Focus indicator
  586. @mixin focus-indicator_($query: feature-targeting-functions.all()) {
  587. $feat-animation: feature-targeting-functions.create-target($query, animation);
  588. $feat-structure: feature-targeting-functions.create-target($query, structure);
  589. @include feature-targeting-mixins.targets($feat-structure) {
  590. position: absolute;
  591. transform: scale(0, 0);
  592. border-radius: 50%;
  593. opacity: 0;
  594. pointer-events: none;
  595. content: "";
  596. will-change: opacity, transform;
  597. }
  598. @include feature-targeting-mixins.targets($feat-animation) {
  599. transition:
  600. functions.transition-exit(opacity),
  601. functions.transition-exit(transform);
  602. }
  603. }
  604. @mixin focus-indicator--focused_($query: feature-targeting-functions.all()) {
  605. $feat-animation: feature-targeting-functions.create-target($query, animation);
  606. $feat-structure: feature-targeting-functions.create-target($query, structure);
  607. @include feature-targeting-mixins.targets($feat-structure) {
  608. transform: scale(1);
  609. opacity: variables.$focus-indicator-opacity;
  610. }
  611. @include feature-targeting-mixins.targets($feat-animation) {
  612. transition:
  613. functions.transition-enter(opacity, 0ms, 80ms),
  614. functions.transition-enter(transform, 0ms, 80ms);
  615. }
  616. }
  617. // Native input
  618. @mixin native-control_ {
  619. position: absolute;
  620. margin: 0;
  621. padding: 0;
  622. opacity: 0;
  623. cursor: inherit;
  624. }
  625. // Check mark
  626. @mixin checkmark_($query: feature-targeting-functions.all()) {
  627. $feat-animation: feature-targeting-functions.create-target($query, animation);
  628. $feat-structure: feature-targeting-functions.create-target($query, structure);
  629. @include feature-targeting-mixins.targets($feat-structure) {
  630. position: absolute;
  631. top: 0;
  632. right: 0;
  633. bottom: 0;
  634. left: 0;
  635. width: 100%;
  636. opacity: 0;
  637. }
  638. @include feature-targeting-mixins.targets($feat-animation) {
  639. transition: functions.transition-exit(opacity, 0ms, variables.$transition-duration * 2);
  640. }
  641. .mdc-checkbox--upgraded & {
  642. @include feature-targeting-mixins.targets($feat-structure) {
  643. opacity: 1;
  644. }
  645. }
  646. }
  647. @mixin checkmark--checked_($query: feature-targeting-functions.all()) {
  648. $feat-animation: feature-targeting-functions.create-target($query, animation);
  649. $feat-structure: feature-targeting-functions.create-target($query, structure);
  650. @include feature-targeting-mixins.targets($feat-animation) {
  651. transition:
  652. functions.transition-enter(opacity, 0ms, variables.$transition-duration * 2),
  653. functions.transition-enter(transform, 0ms, variables.$transition-duration * 2);
  654. }
  655. @include feature-targeting-mixins.targets($feat-structure) {
  656. opacity: 1;
  657. }
  658. }
  659. @mixin checkmark--indeterminate_($query: feature-targeting-functions.all()) {
  660. $feat-animation: feature-targeting-functions.create-target($query, animation);
  661. $feat-structure: feature-targeting-functions.create-target($query, structure);
  662. @include feature-targeting-mixins.targets($feat-structure) {
  663. transform: rotate(45deg);
  664. opacity: 0;
  665. }
  666. @include feature-targeting-mixins.targets($feat-animation) {
  667. transition:
  668. functions.transition-exit(opacity, 0ms, variables.$transition-duration),
  669. functions.transition-exit(transform, 0ms, variables.$transition-duration);
  670. }
  671. }
  672. ///
  673. /// Sets the ink color of the checked and indeterminate icons for a checkbox.
  674. /// This mixin should be wrapped in a mixin that qualifies state such as
  675. /// `mdc-checkbox-if-unmarked_`.
  676. /// @access private
  677. ///
  678. @mixin ink-color_($color, $query: feature-targeting-functions.all()) {
  679. $feat-color: feature-targeting-functions.create-target($query, color);
  680. .mdc-checkbox__background {
  681. .mdc-checkbox__checkmark {
  682. @include feature-targeting-mixins.targets($feat-color) {
  683. @include theme-mixins.prop(color, $color);
  684. }
  685. }
  686. .mdc-checkbox__mixedmark {
  687. @include feature-targeting-mixins.targets($feat-color) {
  688. @include theme-mixins.prop(border-color, $color);
  689. }
  690. }
  691. }
  692. }
  693. // Check mark path
  694. @mixin checkmark-path_($query: feature-targeting-functions.all()) {
  695. $feat-animation: feature-targeting-functions.create-target($query, animation);
  696. $feat-structure: feature-targeting-functions.create-target($query, structure);
  697. @include feature-targeting-mixins.targets($feat-animation) {
  698. transition: functions.transition-exit(stroke-dashoffset, 0ms, variables.$transition-duration * 2);
  699. }
  700. @include feature-targeting-mixins.targets($feat-structure) {
  701. stroke: currentColor;
  702. stroke-width: variables.$mark-stroke-size * 1.3;
  703. stroke-dashoffset: variables.$mark-path-length_;
  704. stroke-dasharray: variables.$mark-path-length_;
  705. }
  706. }
  707. @mixin checkmark-path--marked_ {
  708. stroke-dashoffset: 0;
  709. }
  710. // Mixed mark
  711. @mixin mixedmark_($query: feature-targeting-functions.all()) {
  712. $feat-animation: feature-targeting-functions.create-target($query, animation);
  713. $feat-structure: feature-targeting-functions.create-target($query, structure);
  714. @include feature-targeting-mixins.targets($feat-structure) {
  715. width: 100%;
  716. height: 0;
  717. transform: scaleX(0) rotate(0deg);
  718. border-width: math.floor(variables.$mark-stroke-size) / 2;
  719. border-style: solid;
  720. opacity: 0;
  721. }
  722. @include feature-targeting-mixins.targets($feat-animation) {
  723. transition:
  724. functions.transition-exit(opacity),
  725. functions.transition-exit(transform);
  726. }
  727. }
  728. @mixin mixedmark--checked_ {
  729. transform: scaleX(1) rotate(-45deg);
  730. }
  731. @mixin mixedmark--indeterminate_ {
  732. transform: scaleX(1) rotate(0deg);
  733. opacity: 1;
  734. }
  735. ///
  736. /// Resets touch target-related styles. This is called from the density mixin to
  737. /// automatically remove the increased touch target, since dense components
  738. /// don't have the same default a11y requirements.
  739. /// @access private
  740. ///
  741. @mixin touch-target-reset_($query: feature-targeting-functions.all()) {
  742. $feat-structure: feature-targeting-functions.create-target($query, structure);
  743. @include feature-targeting-mixins.targets($feat-structure) {
  744. margin: 0;
  745. }
  746. }