_fab.scss 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2016 Google Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. // stylelint-disable selector-class-pattern --
  21. // Selector '.mdc-*' should only be used in this project.
  22. @use '@material/animation/functions' as animation-functions;
  23. @use '@material/elevation/elevation-theme';
  24. @use '@material/elevation/elevation';
  25. @use '@material/feature-targeting/feature-targeting';
  26. @use '@material/focus-ring/focus-ring';
  27. @use '@material/dom/mixins' as dom-mixins;
  28. @use '@material/ripple/ripple';
  29. @use '@material/ripple/ripple-theme';
  30. @use '@material/shape/mixins' as shape-mixins;
  31. @use '@material/shape/functions' as shape-functions;
  32. @use '@material/theme/css';
  33. @use '@material/theme/custom-properties';
  34. @use '@material/theme/replace';
  35. @use '@material/theme/state';
  36. @use '@material/theme/theme-color';
  37. @use '@material/theme/theme';
  38. @use '@material/touch-target/mixins' as touch-target-mixins;
  39. @use '@material/typography/typography';
  40. @use './fab-custom-properties';
  41. @use './extended-fab-theme';
  42. @use './fab-theme';
  43. @use 'sass:math';
  44. @use 'sass:list';
  45. @mixin core-styles($query: feature-targeting.all()) {
  46. @include without-ripple($query);
  47. @include ripple($query);
  48. }
  49. @mixin static-styles($query: feature-targeting.all()) {
  50. // postcss-bem-linter: define fab
  51. @include touch-target-mixins.wrapper($query); // COPYBARA_COMMENT_THIS_LINE
  52. // prettier-ignore
  53. @include elevation.overlay-common($query); // COPYBARA_COMMENT_THIS_LINE
  54. .mdc-fab {
  55. @include base_($query: $query);
  56. }
  57. .mdc-fab--mini {
  58. @include mini_($query: $query);
  59. }
  60. .mdc-fab--extended {
  61. @include extended_($query: $query);
  62. }
  63. .mdc-fab--touch {
  64. @include touch-target-mixins.margin(
  65. $component-height: fab-theme.$mini-height,
  66. $component-width: fab-theme.$mini-height,
  67. $query: $query
  68. );
  69. .mdc-fab__touch {
  70. @include touch-target-mixins.touch-target(
  71. $set-width: true,
  72. $query: $query
  73. );
  74. }
  75. }
  76. .mdc-fab::before {
  77. @include dom-mixins.transparent-border($query: $query);
  78. }
  79. .mdc-fab__label {
  80. @include label_($query: $query);
  81. }
  82. .mdc-fab__icon {
  83. @include icon_($query: $query);
  84. }
  85. // Increase specificity for FAB icon styles that need to override styles defined for .material-icons
  86. // (which is loaded separately so the order of CSS definitions is not guaranteed)
  87. .mdc-fab .mdc-fab__icon {
  88. @include icon-overrides_($query: $query);
  89. }
  90. .mdc-fab--exited {
  91. @include exited_($query: $query);
  92. }
  93. // postcss-bem-linter: end
  94. }
  95. @mixin without-ripple($query: feature-targeting.all()) {
  96. @include static-styles($query: $query);
  97. .mdc-fab {
  98. @include fab-theme.container-color(secondary, $query: $query);
  99. @include fab-theme.icon-size(24px, $query: $query);
  100. @include fab-theme.ink-color(on-secondary, $query: $query);
  101. @include fab-theme.shape-radius(fab-theme.$shape-radius, $query: $query);
  102. @include elevation-theme.elevation(6, $query: $query);
  103. }
  104. }
  105. @mixin ripple($query: feature-targeting.all()) {
  106. $feat-structure: feature-targeting.create-target($query, structure);
  107. @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE
  108. .mdc-fab {
  109. @include ripple.surface(
  110. $query: $query,
  111. $ripple-target: fab-theme.$ripple-target
  112. );
  113. @include ripple.radius-bounded(
  114. $query: $query,
  115. $ripple-target: fab-theme.$ripple-target
  116. );
  117. // Set `$opacity-map` to null to apply default opacity-map.
  118. @include fab-theme.ripple-color(
  119. on-secondary,
  120. $opacity-map: null,
  121. $query: $query
  122. );
  123. #{fab-theme.$ripple-target} {
  124. @include ripple.target-common($query: $query);
  125. @include feature-targeting.targets($feat-structure) {
  126. overflow: hidden;
  127. }
  128. }
  129. @include ripple-theme.behind-content(
  130. fab-theme.$ripple-target,
  131. $query: $query
  132. );
  133. }
  134. }
  135. $icon-enter-delay_: 90ms;
  136. $icon-enter-duration_: 180ms;
  137. @mixin base_($query: feature-targeting.all()) {
  138. @include elevation-theme.overlay-surface-position($query: $query);
  139. @include elevation-theme.overlay-dimensions(100%, $query: $query);
  140. $feat-animation: feature-targeting.create-target($query, animation);
  141. $feat-structure: feature-targeting.create-target($query, structure);
  142. @include feature-targeting.targets($feat-structure) {
  143. display: inline-flex;
  144. position: relative;
  145. align-items: center;
  146. justify-content: center;
  147. box-sizing: border-box;
  148. width: fab-theme.$height;
  149. height: fab-theme.$height;
  150. padding: 0;
  151. border: none;
  152. fill: currentColor;
  153. text-decoration: none;
  154. cursor: pointer;
  155. user-select: none;
  156. -moz-appearance: none;
  157. -webkit-appearance: none;
  158. // Even though `visible` is the default, IE 11 computes the property as
  159. // `hidden` in some cases, unless it's explicitly defined here.
  160. overflow: visible;
  161. &[hidden] {
  162. display: none;
  163. }
  164. }
  165. @include feature-targeting.targets($feat-animation) {
  166. transition: box-shadow elevation-theme.$transition-duration
  167. elevation-theme.$transition-timing-function,
  168. opacity 15ms linear 30ms,
  169. animation-functions.enter(
  170. transform,
  171. $icon-enter-duration_ + $icon-enter-delay_
  172. );
  173. }
  174. &::-moz-focus-inner {
  175. @include feature-targeting.targets($feat-structure) {
  176. padding: 0;
  177. border: 0;
  178. }
  179. }
  180. &:hover {
  181. @include elevation-theme.elevation(8, $query: $query);
  182. }
  183. @include ripple-theme.focus() {
  184. @include elevation-theme.elevation(8, $query: $query);
  185. }
  186. .mdc-fab__focus-ring {
  187. @include feature-targeting.targets($feat-structure) {
  188. position: absolute;
  189. }
  190. }
  191. @include ripple-theme.focus() {
  192. .mdc-fab__focus-ring {
  193. @include focus-ring.focus-ring($query: $query);
  194. }
  195. }
  196. // Increase active state specificity due to ripple-theme.focus().
  197. &:active,
  198. &:focus:active {
  199. @include elevation-theme.elevation(12, $query: $query);
  200. }
  201. &:active,
  202. &:focus {
  203. // TODO(acdvorak): Should this be paired with states and/or ripple? We don't want to disable outline
  204. // (an accessibility/usability feature) unless we're confident that there is also a visual indication that the
  205. // element has focus. If the client has customized the DOM in some unexpected way, and is certain that another
  206. // element will receive focus instead, they can always override this property manually in their CSS.
  207. @include feature-targeting.targets($feat-structure) {
  208. outline: none;
  209. }
  210. }
  211. &:hover {
  212. @include feature-targeting.targets($feat-structure) {
  213. cursor: pointer;
  214. }
  215. }
  216. // stylelint-disable selector-max-type --
  217. // This allows for using SVGs within them to align properly in all browsers.
  218. // Can remove once: https://bugzilla.mozilla.org/show_bug.cgi?id=1294515 is resolved.
  219. // postcss-bem-linter: ignore
  220. > svg {
  221. @include feature-targeting.targets($feat-structure) {
  222. width: 100%;
  223. }
  224. }
  225. // stylelint-enable selector-max-type
  226. }
  227. @mixin mini_($query: feature-targeting.all()) {
  228. $feat-structure: feature-targeting.create-target($query, structure);
  229. @include feature-targeting.targets($feat-structure) {
  230. width: fab-theme.$mini-height;
  231. height: fab-theme.$mini-height;
  232. }
  233. }
  234. @mixin extended_($query: feature-targeting.all()) {
  235. @include typography.typography(button, $query: $query);
  236. @include extended-fab-theme.extended-shape-radius(
  237. fab-theme.$shape-radius,
  238. $query: $query
  239. );
  240. $extended-icon-padding: custom-properties.create(
  241. fab-custom-properties.$extended-icon-padding,
  242. extended-fab-theme.$extended-icon-padding
  243. );
  244. $extended-label-padding: custom-properties.create(
  245. fab-custom-properties.$extended-label-padding,
  246. extended-fab-theme.$extended-label-padding
  247. );
  248. @include extended-fab-theme.extended-padding(
  249. extended-fab-theme.$extended-icon-padding,
  250. extended-fab-theme.$extended-label-padding,
  251. $query: $query
  252. );
  253. $feat-structure: feature-targeting.create-target($query, structure);
  254. @include feature-targeting.targets($feat-structure) {
  255. width: auto;
  256. max-width: 100%;
  257. height: extended-fab-theme.$extended-height;
  258. // This allows the text within the extended fab to be centered for varying font sizes.
  259. /* @alternate */
  260. line-height: normal;
  261. }
  262. }
  263. @mixin icon_($query: feature-targeting.all()) {
  264. $feat-animation: feature-targeting.create-target($query, animation);
  265. $feat-structure: feature-targeting.create-target($query, structure);
  266. @include feature-targeting.targets($feat-animation) {
  267. transition: animation-functions.enter(
  268. transform,
  269. $icon-enter-duration_,
  270. $icon-enter-delay_
  271. );
  272. }
  273. @include feature-targeting.targets($feat-structure) {
  274. fill: currentColor;
  275. will-change: transform;
  276. }
  277. }
  278. @mixin label_($query: feature-targeting.all()) {
  279. $feat-structure: feature-targeting.create-target($query, structure);
  280. @include feature-targeting.targets($feat-structure) {
  281. justify-content: flex-start;
  282. text-overflow: ellipsis;
  283. white-space: nowrap;
  284. overflow-x: hidden;
  285. overflow-y: visible;
  286. }
  287. }
  288. @mixin icon-overrides_($query: feature-targeting.all()) {
  289. $feat-structure: feature-targeting.create-target($query, structure);
  290. @include feature-targeting.targets($feat-structure) {
  291. display: inline-flex;
  292. align-items: center;
  293. justify-content: center;
  294. }
  295. }
  296. @mixin exited_($query: feature-targeting.all()) {
  297. $feat-animation: feature-targeting.create-target($query, animation);
  298. $feat-structure: feature-targeting.create-target($query, structure);
  299. @include feature-targeting.targets($feat-structure) {
  300. transform: scale(0);
  301. opacity: 0;
  302. }
  303. @include feature-targeting.targets($feat-animation) {
  304. transition: opacity 15ms linear 150ms,
  305. animation-functions.exit-permanent(transform, 180ms);
  306. }
  307. .mdc-fab__icon {
  308. @include feature-targeting.targets($feat-structure) {
  309. transform: scale(0);
  310. }
  311. @include feature-targeting.targets($feat-animation) {
  312. transition: animation-functions.exit-permanent(transform, 135ms);
  313. }
  314. }
  315. }