_radio-common.scss 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. @use '../core/tokens/m2/mdc/radio' as tokens-mdc-radio;
  2. @use '../core/tokens/token-utils';
  3. $_icon-size: 20px;
  4. @function _enter-transition($name) {
  5. @return $name 90ms cubic-bezier(0, 0, 0.2, 1);
  6. }
  7. @function _exit-transition($name) {
  8. @return $name 90ms cubic-bezier(0.4, 0, 0.6, 1);
  9. }
  10. // Structural styles for a radio button. Shared with the selection list.
  11. @mixin radio-structure($is-interactive) {
  12. $tokens: tokens-mdc-radio.$prefix, tokens-mdc-radio.get-token-slots();
  13. .mdc-radio {
  14. display: inline-block;
  15. position: relative;
  16. flex: 0 0 auto;
  17. box-sizing: content-box;
  18. width: $_icon-size;
  19. height: $_icon-size;
  20. cursor: pointer;
  21. // This is something we inherited from MDC, but it shouldn't be necessary.
  22. // Removing it will likely lead to screenshot diffs.
  23. will-change: opacity, transform, border-color, color;
  24. @include token-utils.use-tokens($tokens...) {
  25. $size-token: token-utils.get-token-variable(state-layer-size);
  26. padding: calc((#{$size-token} - #{$_icon-size}) / 2);
  27. }
  28. @if ($is-interactive) {
  29. // MDC's hover indication comes from their ripple which we don't use.
  30. &:hover > .mdc-radio__native-control:not([disabled]):not(:focus) {
  31. & ~ .mdc-radio__background::before {
  32. opacity: 0.04;
  33. transform: scale(1);
  34. }
  35. }
  36. &:hover > .mdc-radio__native-control:not([disabled]) ~ .mdc-radio__background {
  37. > .mdc-radio__outer-circle {
  38. @include token-utils.use-tokens($tokens...) {
  39. @include token-utils.create-token-slot(border-color, unselected-hover-icon-color);
  40. }
  41. }
  42. }
  43. &:hover > .mdc-radio__native-control:enabled:checked + .mdc-radio__background {
  44. > .mdc-radio__outer-circle,
  45. > .mdc-radio__inner-circle {
  46. @include token-utils.use-tokens($tokens...) {
  47. @include token-utils.create-token-slot(border-color, selected-hover-icon-color);
  48. }
  49. }
  50. }
  51. &:active > .mdc-radio__native-control:enabled:not(:checked) + .mdc-radio__background {
  52. > .mdc-radio__outer-circle {
  53. @include token-utils.use-tokens($tokens...) {
  54. @include token-utils.create-token-slot(border-color, unselected-pressed-icon-color);
  55. }
  56. }
  57. }
  58. &:active > .mdc-radio__native-control:enabled:checked + .mdc-radio__background {
  59. > .mdc-radio__outer-circle,
  60. > .mdc-radio__inner-circle {
  61. @include token-utils.use-tokens($tokens...) {
  62. @include token-utils.create-token-slot(border-color, selected-pressed-icon-color);
  63. }
  64. }
  65. }
  66. }
  67. }
  68. .mdc-radio__background {
  69. display: inline-block;
  70. position: relative;
  71. box-sizing: border-box;
  72. width: $_icon-size;
  73. height: $_icon-size;
  74. &::before {
  75. position: absolute;
  76. transform: scale(0, 0);
  77. border-radius: 50%;
  78. opacity: 0;
  79. pointer-events: none;
  80. content: '';
  81. transition: _exit-transition(opacity), _exit-transition(transform);
  82. @include token-utils.use-tokens($tokens...) {
  83. $size: token-utils.get-token-variable(state-layer-size);
  84. $offset: calc(-1 * (#{$size} - #{$_icon-size}) / 2);
  85. width: $size;
  86. height: $size;
  87. top: $offset;
  88. left: $offset;
  89. }
  90. }
  91. }
  92. .mdc-radio__outer-circle {
  93. position: absolute;
  94. top: 0;
  95. left: 0;
  96. box-sizing: border-box;
  97. width: 100%;
  98. height: 100%;
  99. border-width: 2px;
  100. border-style: solid;
  101. border-radius: 50%;
  102. transition: _exit-transition(border-color);
  103. }
  104. .mdc-radio__inner-circle {
  105. position: absolute;
  106. top: 0;
  107. left: 0;
  108. box-sizing: border-box;
  109. width: 100%;
  110. height: 100%;
  111. transform: scale(0, 0);
  112. border-width: 10px;
  113. border-style: solid;
  114. border-radius: 50%;
  115. transition: _exit-transition(transform), _exit-transition(border-color);
  116. }
  117. .mdc-radio__native-control {
  118. position: absolute;
  119. margin: 0;
  120. padding: 0;
  121. opacity: 0;
  122. top: 0;
  123. right: 0;
  124. left: 0;
  125. cursor: inherit;
  126. z-index: 1;
  127. @include token-utils.use-tokens($tokens...) {
  128. @include token-utils.create-token-slot(width, state-layer-size);
  129. @include token-utils.create-token-slot(height, state-layer-size);
  130. }
  131. &:checked, &:disabled {
  132. + .mdc-radio__background {
  133. transition: _enter-transition(opacity), _enter-transition(transform);
  134. > .mdc-radio__outer-circle {
  135. transition: _enter-transition(border-color);
  136. }
  137. > .mdc-radio__inner-circle {
  138. transition: _enter-transition(transform), _enter-transition(border-color);
  139. }
  140. }
  141. }
  142. @if ($is-interactive) {
  143. &:focus + .mdc-radio__background::before {
  144. transform: scale(1);
  145. opacity: 0.12;
  146. transition: _enter-transition(opacity), _enter-transition(transform);
  147. }
  148. }
  149. &:disabled {
  150. @include token-utils.use-tokens($tokens...) {
  151. &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle {
  152. @include token-utils.create-token-slot(border-color, disabled-unselected-icon-color);
  153. @include token-utils.create-token-slot(opacity, disabled-unselected-icon-opacity);
  154. }
  155. + .mdc-radio__background {
  156. cursor: default;
  157. > .mdc-radio__inner-circle,
  158. > .mdc-radio__outer-circle {
  159. @include token-utils.create-token-slot(border-color, disabled-selected-icon-color);
  160. @include token-utils.create-token-slot(opacity, disabled-selected-icon-opacity);
  161. }
  162. }
  163. }
  164. }
  165. &:enabled {
  166. @include token-utils.use-tokens($tokens...) {
  167. &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle {
  168. @include token-utils.create-token-slot(border-color, unselected-icon-color);
  169. }
  170. &:checked + .mdc-radio__background {
  171. > .mdc-radio__outer-circle,
  172. > .mdc-radio__inner-circle {
  173. @include token-utils.create-token-slot(border-color, selected-icon-color);
  174. }
  175. }
  176. @if ($is-interactive) {
  177. &:focus:checked + .mdc-radio__background {
  178. > .mdc-radio__inner-circle,
  179. > .mdc-radio__outer-circle {
  180. @include token-utils.create-token-slot(border-color, selected-focus-icon-color);
  181. }
  182. }
  183. }
  184. }
  185. }
  186. &:checked + .mdc-radio__background > .mdc-radio__inner-circle {
  187. transform: scale(0.5);
  188. transition: _enter-transition(transform), _enter-transition(border-color);
  189. }
  190. }
  191. @if ($is-interactive) {
  192. &.mat-mdc-radio-disabled-interactive .mdc-radio--disabled {
  193. pointer-events: auto;
  194. @include token-utils.use-tokens($tokens...) {
  195. // stylelint-disable selector-combinator-space-before
  196. .mdc-radio__native-control:not(:checked) + .mdc-radio__background
  197. > .mdc-radio__outer-circle {
  198. @include token-utils.create-token-slot(border-color, disabled-unselected-icon-color);
  199. @include token-utils.create-token-slot(opacity, disabled-unselected-icon-opacity);
  200. }
  201. // stylelint-enable selector-combinator-space-before
  202. &:hover .mdc-radio__native-control:checked + .mdc-radio__background,
  203. .mdc-radio__native-control:checked:focus + .mdc-radio__background,
  204. .mdc-radio__native-control + .mdc-radio__background {
  205. > .mdc-radio__inner-circle,
  206. > .mdc-radio__outer-circle {
  207. @include token-utils.create-token-slot(border-color, disabled-selected-icon-color);
  208. @include token-utils.create-token-slot(opacity, disabled-selected-icon-opacity);
  209. }
  210. }
  211. }
  212. }
  213. }
  214. }
  215. // Conditionally disables the animations of the radio button.
  216. @mixin radio-noop-animations() {
  217. &._mat-animation-noopable {
  218. .mdc-radio__background::before,
  219. .mdc-radio__outer-circle,
  220. .mdc-radio__inner-circle {
  221. // Needs to be `!important`, because MDC's selectors are really specific.
  222. transition: none !important;
  223. }
  224. }
  225. }