_radio.scss 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. // stylelint-disable selector-class-pattern --
  23. // Selector '.mdc-*' should only be used in this project.
  24. @use 'sass:map';
  25. @use '@material/animation/animation';
  26. @use '@material/dom/dom';
  27. @use '@material/feature-targeting/feature-targeting';
  28. @use '@material/ripple/ripple';
  29. @use '@material/ripple/ripple-theme';
  30. @use '@material/touch-target/mixins' as touch-target-mixins;
  31. @use '@material/touch-target/variables' as touch-target-variables;
  32. @use './radio-theme';
  33. @use '@material/focus-ring/focus-ring';
  34. $ripple-target: radio-theme.$ripple-target;
  35. ///
  36. /// Radio core styles.
  37. ///
  38. @mixin core-styles($query: feature-targeting.all()) {
  39. @include without-ripple($query);
  40. @include ripple($query);
  41. }
  42. @mixin static-styles($query: feature-targeting.all()) {
  43. $feat-animation: feature-targeting.create-target($query, animation);
  44. $feat-color: feature-targeting.create-target($query, color);
  45. $feat-structure: feature-targeting.create-target($query, structure);
  46. .mdc-radio {
  47. @include feature-targeting.targets($feat-structure) {
  48. display: inline-block;
  49. position: relative;
  50. flex: 0 0 auto;
  51. box-sizing: content-box;
  52. width: radio-theme.$icon-size;
  53. height: radio-theme.$icon-size;
  54. cursor: pointer;
  55. /* @alternate */
  56. will-change: opacity, transform, border-color, color;
  57. &[hidden] {
  58. display: none;
  59. }
  60. }
  61. // Container for radio circles and ripple.
  62. &__background {
  63. @include feature-targeting.targets($feat-structure) {
  64. display: inline-block;
  65. position: relative;
  66. box-sizing: border-box;
  67. width: radio-theme.$icon-size;
  68. height: radio-theme.$icon-size;
  69. }
  70. &::before {
  71. @include feature-targeting.targets($feat-structure) {
  72. position: absolute;
  73. transform: scale(0, 0);
  74. border-radius: 50%;
  75. opacity: 0;
  76. pointer-events: none;
  77. content: '';
  78. }
  79. @include feature-targeting.targets($feat-animation) {
  80. transition: exit(opacity), exit(transform);
  81. }
  82. }
  83. }
  84. &__outer-circle {
  85. @include feature-targeting.targets($feat-structure) {
  86. position: absolute;
  87. top: 0;
  88. left: 0;
  89. box-sizing: border-box;
  90. width: 100%;
  91. height: 100%;
  92. border-width: 2px;
  93. border-style: solid;
  94. border-radius: 50%;
  95. }
  96. @include feature-targeting.targets($feat-animation) {
  97. transition: exit(border-color);
  98. }
  99. }
  100. &__inner-circle {
  101. @include feature-targeting.targets($feat-structure) {
  102. position: absolute;
  103. top: 0;
  104. left: 0;
  105. box-sizing: border-box;
  106. width: 100%;
  107. height: 100%;
  108. transform: scale(0, 0);
  109. border-width: 10px;
  110. border-style: solid;
  111. border-radius: 50%;
  112. }
  113. @include feature-targeting.targets($feat-animation) {
  114. transition: exit(transform), exit(border-color);
  115. }
  116. }
  117. &__native-control {
  118. @include feature-targeting.targets($feat-structure) {
  119. position: absolute;
  120. margin: 0;
  121. padding: 0;
  122. opacity: 0;
  123. cursor: inherit;
  124. z-index: 1;
  125. }
  126. }
  127. &--touch {
  128. @include touch-target-mixins.margin(
  129. $component-height: radio-theme.$ripple-size,
  130. $component-width: radio-theme.$ripple-size,
  131. $query: $query
  132. );
  133. @include radio-theme.touch-target(
  134. $size: touch-target-variables.$height,
  135. $query: $query
  136. );
  137. }
  138. @include ripple-theme.focus {
  139. .mdc-radio__focus-ring {
  140. @include focus-ring.focus-ring(
  141. $container-outer-padding-vertical: 0,
  142. $container-outer-padding-horizontal: 0,
  143. $query: $query
  144. );
  145. }
  146. }
  147. }
  148. .mdc-radio__native-control:checked,
  149. .mdc-radio__native-control:disabled {
  150. + .mdc-radio__background {
  151. @include feature-targeting.targets($feat-animation) {
  152. transition: enter(opacity), enter(transform);
  153. }
  154. .mdc-radio__outer-circle {
  155. @include feature-targeting.targets($feat-animation) {
  156. transition: enter(border-color);
  157. }
  158. }
  159. .mdc-radio__inner-circle {
  160. @include feature-targeting.targets($feat-animation) {
  161. transition: enter(transform), enter(border-color);
  162. }
  163. }
  164. }
  165. }
  166. .mdc-radio--disabled {
  167. @include feature-targeting.targets($feat-structure) {
  168. cursor: default;
  169. pointer-events: none;
  170. }
  171. }
  172. .mdc-radio__native-control:checked {
  173. + .mdc-radio__background {
  174. .mdc-radio__inner-circle {
  175. @include feature-targeting.targets($feat-structure) {
  176. transform: scale(0.5);
  177. }
  178. @include feature-targeting.targets($feat-animation) {
  179. transition: enter(transform), enter(border-color);
  180. }
  181. }
  182. }
  183. }
  184. .mdc-radio__native-control:disabled,
  185. [aria-disabled='true'] .mdc-radio__native-control {
  186. + .mdc-radio__background {
  187. @include feature-targeting.targets($feat-structure) {
  188. cursor: default;
  189. }
  190. }
  191. }
  192. .mdc-radio__native-control:focus {
  193. + .mdc-radio__background::before {
  194. @include feature-targeting.targets($feat-structure) {
  195. transform: scale(1);
  196. opacity: map.get(ripple-theme.$dark-ink-opacities, focus);
  197. }
  198. @include feature-targeting.targets($feat-animation) {
  199. transition: enter(opacity), enter(transform);
  200. }
  201. }
  202. }
  203. }
  204. // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
  205. // radio styles. It is recommended that most users use `mdc-radio-core-styles` instead.
  206. @mixin without-ripple($query: feature-targeting.all()) {
  207. // postcss-bem-linter: define radio
  208. @include touch-target-mixins.wrapper($query); // COPYBARA_COMMENT_THIS_LINE
  209. .mdc-radio {
  210. @include radio-theme.unchecked-stroke-color(
  211. radio-theme.$unchecked-color,
  212. $query: $query
  213. );
  214. @include radio-theme.checked-stroke-color(
  215. radio-theme.$baseline-theme-color,
  216. $query: $query
  217. );
  218. @include radio-theme.ink-color(
  219. radio-theme.$baseline-theme-color,
  220. $query: $query
  221. );
  222. @include radio-theme.disabled-unchecked-stroke-color(
  223. radio-theme.$disabled-circle-color,
  224. $query: $query
  225. );
  226. @include radio-theme.disabled-checked-stroke-color(
  227. radio-theme.$disabled-circle-color,
  228. $query: $query
  229. );
  230. @include radio-theme.disabled-ink-color(
  231. radio-theme.$disabled-circle-color,
  232. $query: $query
  233. );
  234. @include radio-theme.focus-indicator-color(
  235. radio-theme.$baseline-theme-color,
  236. $query: $query
  237. );
  238. @include radio-theme.density(radio-theme.$density-scale, $query: $query);
  239. @include dom.forced-colors-mode {
  240. &.mdc-radio--disabled {
  241. @include radio-theme.disabled-unchecked-stroke-color(
  242. GrayText,
  243. $query: $query
  244. );
  245. @include radio-theme.disabled-checked-stroke-color(
  246. GrayText,
  247. $query: $query
  248. );
  249. @include radio-theme.disabled-ink-color(GrayText, $query: $query);
  250. }
  251. }
  252. }
  253. @include static-styles($query: $query);
  254. // postcss-bem-linter: end
  255. }
  256. // This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
  257. // radio styles. It is recommended that most users use `mdc-radio-core-styles` instead.
  258. @mixin ripple($query: feature-targeting.all()) {
  259. $feat-structure: feature-targeting.create-target($query, structure);
  260. @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE
  261. .mdc-radio {
  262. @include ripple.surface($query: $query, $ripple-target: $ripple-target);
  263. @include ripple.radius-unbounded(
  264. $query: $query,
  265. $ripple-target: $ripple-target
  266. );
  267. @include ripple-theme.states(
  268. $color: radio-theme.$baseline-theme-color,
  269. $query: $query,
  270. $ripple-target: $ripple-target
  271. );
  272. &.mdc-ripple-upgraded,
  273. &.mdc-ripple-upgraded--background-focused {
  274. .mdc-radio__background::before {
  275. @include feature-targeting.targets($feat-structure) {
  276. content: none;
  277. }
  278. }
  279. }
  280. }
  281. #{$ripple-target} {
  282. @include ripple.target-common($query: $query);
  283. }
  284. }
  285. @function enter($name) {
  286. @return animation.enter($name, radio-theme.$transition-duration);
  287. }
  288. @function exit($name) {
  289. @return animation.exit-temporary($name, radio-theme.$transition-duration);
  290. }