_banner-theme.scss 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. //
  2. // Copyright 2020 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. // Selector '.mdc-*' should only be used in this project.
  23. // stylelint-disable selector-class-pattern --
  24. // Internal styling for Tooltip MDC component.
  25. @use 'sass:map';
  26. @use 'sass:meta';
  27. @use '@material/elevation/elevation-theme';
  28. @use '@material/feature-targeting/feature-targeting';
  29. @use '@material/rtl/rtl';
  30. @use '@material/shape/mixins' as shape-mixins;
  31. @use '@material/button/button-text-theme';
  32. @use '@material/theme/theme';
  33. @use '@material/theme/theme-color';
  34. @use '@material/theme/keys';
  35. @use '@material/typography/typography';
  36. @use '@material/tokens/resolvers';
  37. $fill-color: surface;
  38. $text-color: on-surface;
  39. $divider-color: rgba(theme-color.prop-value(on-surface), 0.12);
  40. $graphic-background-color: primary;
  41. $graphic-color: surface;
  42. $graphic-shape-radius: 50%;
  43. $primary-action-text-color: primary;
  44. $secondary-action-text-color: primary;
  45. $mobile-breakpoint: 480px;
  46. $z-index: 1;
  47. $custom-property-prefix: 'banner';
  48. $light-theme: (
  49. action-focus-state-layer-color: theme-color.$primary,
  50. action-focus-state-layer-opacity: 0.12,
  51. action-focus-label-text-color: null,
  52. action-hover-state-layer-color: theme-color.$primary,
  53. action-hover-state-layer-opacity: 0.04,
  54. action-hover-label-text-color: null,
  55. action-label-text-color: theme-color.$primary,
  56. // TODO(b/197004146): Support action label typography.
  57. action-label-text-font: null,
  58. action-label-text-size: null,
  59. action-label-text-tracking: null,
  60. action-label-text-weight: null,
  61. action-pressed-state-layer-color: theme-color.$primary,
  62. action-pressed-state-layer-opacity: 0.1,
  63. action-pressed-label-text-color: null,
  64. container-color: theme-color.$surface,
  65. container-elevation: null,
  66. container-shadow-color: null,
  67. container-shape: 0,
  68. divider-color: $divider-color,
  69. divider-height: 1px,
  70. supporting-text-color: theme-color.$on-surface,
  71. supporting-text-font: typography.get-font(body2),
  72. supporting-text-line-height: typography.get-line-height(body2),
  73. supporting-text-size: typography.get-size(body2),
  74. supporting-text-tracking: typography.get-tracking(body2),
  75. supporting-text-weight: typography.get-weight(body2),
  76. with-image-image-shape: $graphic-shape-radius,
  77. with-image-image-size: 40px,
  78. );
  79. @mixin theme($theme, $resolvers: resolvers.$material) {
  80. // TODO(b/251881053): Replace with `validate-theme`.
  81. @include theme.validate-theme-styles($light-theme, $theme);
  82. $theme: _resolve-theme($theme, $resolvers);
  83. @include keys.declare-custom-properties(
  84. $theme,
  85. $prefix: $custom-property-prefix
  86. );
  87. }
  88. @function _resolve-theme($theme, $resolvers) {
  89. @return map.merge(
  90. $theme,
  91. _resolve-theme-elevation(
  92. $theme,
  93. map.get($resolvers, elevation),
  94. container-elevation
  95. )
  96. );
  97. }
  98. @function _resolve-theme-elevation($theme, $resolver, $keys...) {
  99. @if $resolver == null {
  100. @return $theme;
  101. }
  102. @each $key in $keys {
  103. // Resolve the value for each state key.
  104. $resolved-value: meta.call(
  105. $resolver,
  106. $elevation: map.get($theme, $key),
  107. $shadow-color: map.get($theme, container-shadow-color)
  108. );
  109. // Update the theme with the resolved value.
  110. $theme: map.set($theme, $key, $resolved-value);
  111. }
  112. @return $theme;
  113. }
  114. @mixin theme-styles(
  115. $theme,
  116. $resolver: resolvers.$material,
  117. $query: feature-targeting.all()
  118. ) {
  119. @include theme.validate-theme-styles($light-theme, $theme);
  120. $theme: keys.create-theme-properties(
  121. $theme,
  122. $prefix: $custom-property-prefix
  123. );
  124. @include text-color(map.get($theme, supporting-text-color), $query: $query);
  125. @include _supporting-text-typography(
  126. (
  127. font: map.get($theme, supporting-text-font),
  128. size: map.get($theme, supporting-text-size),
  129. tracking: map.get($theme, supporting-text-tracking),
  130. weight: map.get($theme, supporting-text-weight),
  131. line-height: map.get($theme, supporting-text-line-height),
  132. ),
  133. $query: $query
  134. );
  135. @include graphic-shape-radius(
  136. map.get($theme, with-image-image-shape),
  137. $query: $query
  138. );
  139. @include _graphic-size(
  140. map.get($theme, with-image-image-size),
  141. $query: $query
  142. );
  143. @include fill-color(map.get($theme, container-color), $query: $query);
  144. @include divider-color(map.get($theme, divider-color), $query: $query);
  145. @include _divider-height(map.get($theme, divider-height), $query: $query);
  146. @include _banner-shape(map.get($theme, container-shape), $query: $query);
  147. @include _banner-elevation(
  148. $resolver,
  149. map.get($theme, container-elevation),
  150. map.get($theme, container-shadow-color),
  151. $query
  152. );
  153. .mdc-button {
  154. @include button-text-theme.theme-styles(
  155. (
  156. focus-label-text-color: map.get($theme, action-focus-label-text-color),
  157. focus-state-layer-color: map.get($theme, action-focus-state-layer-color),
  158. focus-state-layer-opacity:
  159. map.get($theme, action-focus-state-layer-opacity),
  160. hover-label-text-color: map.get($theme, action-hover-label-text-color),
  161. hover-state-layer-color: map.get($theme, action-hover-state-layer-color),
  162. hover-state-layer-opacity:
  163. map.get($theme, action-hover-state-layer-opacity),
  164. label-text-color: map.get($theme, action-label-text-color),
  165. label-text-font: map.get($theme, action-label-text-font),
  166. label-text-size: map.get($theme, action-label-text-size),
  167. label-text-tracking: map.get($theme, action-label-text-tracking),
  168. label-text-weight: map.get($theme, action-label-text-weight),
  169. pressed-label-text-color:
  170. map.get($theme, action-pressed-label-text-color),
  171. pressed-state-layer-color:
  172. map.get($theme, action-pressed-state-layer-color),
  173. pressed-state-layer-opacity:
  174. map.get($theme, action-pressed-state-layer-opacity),
  175. ),
  176. $query: $query
  177. );
  178. }
  179. }
  180. ///
  181. /// Customizes fill color.
  182. /// @param {Color | String} $color Either a valid color value or a key from
  183. /// `$theme-theme-color.property-values`.
  184. ///
  185. @mixin fill-color($color, $query: feature-targeting.all()) {
  186. $feat-color: feature-targeting.create-target($query, color);
  187. @include feature-targeting.targets($feat-color) {
  188. @include theme.property(background-color, $color);
  189. }
  190. .mdc-banner__fixed {
  191. @include feature-targeting.targets($feat-color) {
  192. @include theme.property(background-color, $color);
  193. }
  194. }
  195. }
  196. ///
  197. /// Customizes text color.
  198. /// @param {Color | String} $color Either a valid color value or a key from
  199. /// `$theme-theme-color.property-values`.
  200. ///
  201. @mixin text-color($color, $query: feature-targeting.all()) {
  202. $feat-color: feature-targeting.create-target($query, color);
  203. .mdc-banner__text {
  204. @include feature-targeting.targets($feat-color) {
  205. @include theme.property(color, $color);
  206. }
  207. }
  208. }
  209. ///
  210. /// Customizes divider color.
  211. /// @param {Color | String} $color Either a valid color value or a key from
  212. /// `$theme-theme-color.property-values`.
  213. ///
  214. @mixin divider-color($color, $query: feature-targeting.all()) {
  215. $feat-color: feature-targeting.create-target($query, color);
  216. @include feature-targeting.targets($feat-color) {
  217. @include theme.property(border-bottom-color, $color);
  218. }
  219. .mdc-banner__fixed {
  220. @include feature-targeting.targets($feat-color) {
  221. @include theme.property(border-bottom-color, $color);
  222. }
  223. }
  224. }
  225. @mixin _divider-height($height, $query: feature-targeting.all()) {
  226. $feat-structure: feature-targeting.create-target($query, structure);
  227. @include feature-targeting.targets($feat-structure) {
  228. @include theme.property(border-bottom-width, $height);
  229. }
  230. .mdc-banner__fixed {
  231. @include feature-targeting.targets($feat-structure) {
  232. @include theme.property(border-bottom-width, $height);
  233. }
  234. }
  235. }
  236. ///
  237. /// Customizes the graphic color.
  238. /// @param {Color | String} $color Either a valid color value or a key from
  239. /// `$theme-theme-color.property-values`.
  240. ///
  241. @mixin graphic-color($color, $query: feature-targeting.all()) {
  242. $feat-color: feature-targeting.create-target($query, color);
  243. .mdc-banner__graphic {
  244. @include feature-targeting.targets($feat-color) {
  245. @include theme.property(color, $color);
  246. }
  247. }
  248. }
  249. ///
  250. /// Customizes the graphic background color.
  251. /// @param {Color | String} $color Either a valid color value or a key from
  252. /// `$theme-theme-color.property-values`.
  253. ///
  254. @mixin graphic-background-color($color, $query: feature-targeting.all()) {
  255. $feat-color: feature-targeting.create-target($query, color);
  256. .mdc-banner__graphic {
  257. @include feature-targeting.targets($feat-color) {
  258. @include theme.property(background-color, $color);
  259. }
  260. }
  261. }
  262. ///
  263. /// Customizes the graphic shape radius.
  264. /// @param {Number} $shape-radius Shape radius in length or percentage.
  265. ///
  266. @mixin graphic-shape-radius($shape-radius, $query: feature-targeting.all()) {
  267. .mdc-banner__graphic {
  268. @include shape-mixins.radius($shape-radius, $query: $query);
  269. }
  270. }
  271. ///
  272. /// Sets the min-width for the banner content.
  273. /// @param {Number} $min-width Minimum width value in `px`.
  274. /// @param {Number} $mobile-breakpoint Mobile breakpoint value in `px`.
  275. ///
  276. @mixin min-width(
  277. $min-width,
  278. $mobile-breakpoint: $mobile-breakpoint,
  279. $query: feature-targeting.all()
  280. ) {
  281. $feat-structure: feature-targeting.create-target($query, structure);
  282. .mdc-banner__content,
  283. .mdc-banner__fixed {
  284. @include feature-targeting.targets($feat-structure) {
  285. min-width: $min-width;
  286. // The first media query ensures that banners are always 100% width on
  287. // mobile devices, as required by the spec. The second media query
  288. // prevents banners from being wider than the viewport for large min-width
  289. // values.
  290. @media (max-width: $mobile-breakpoint), (max-width: $min-width) {
  291. min-width: 100%;
  292. }
  293. }
  294. }
  295. }
  296. ///
  297. /// Sets the max-width for the banner content.
  298. /// @param {Number} $max-width Maximum width value in `px`.
  299. ///
  300. @mixin max-width($max-width, $query: feature-targeting.all()) {
  301. $feat-structure: feature-targeting.create-target($query, structure);
  302. .mdc-banner__content {
  303. @include feature-targeting.targets($feat-structure) {
  304. max-width: $max-width;
  305. }
  306. }
  307. }
  308. ///
  309. /// Sets the banner content to centered instead of leading.
  310. ///
  311. @mixin position-centered($query: feature-targeting.all()) {
  312. $feat-structure: feature-targeting.create-target($query, structure);
  313. .mdc-banner__content {
  314. @include feature-targeting.targets($feat-structure) {
  315. left: 0;
  316. margin-left: auto;
  317. margin-right: auto;
  318. right: 0;
  319. }
  320. }
  321. }
  322. ///
  323. /// Sets the banner content to stacked layout.
  324. ///
  325. @mixin layout-stacked($query: feature-targeting.all()) {
  326. $feat-structure: feature-targeting.create-target($query, structure);
  327. @include feature-targeting.targets($feat-structure) {
  328. .mdc-banner__content {
  329. flex-wrap: wrap;
  330. }
  331. .mdc-banner__graphic {
  332. margin-bottom: 12px;
  333. }
  334. .mdc-banner__text {
  335. @include rtl.reflexive-property(margin, 16px, 8px);
  336. padding-bottom: 4px;
  337. }
  338. .mdc-banner__actions {
  339. margin-left: auto;
  340. }
  341. }
  342. }
  343. // Sets the z-index of the banner.
  344. // @param {Number} $z-index
  345. @mixin z-index($z-index, $query: feature-targeting.all()) {
  346. $feat-structure: feature-targeting.create-target($query, structure);
  347. @include feature-targeting.targets($feat-structure) {
  348. z-index: $z-index;
  349. }
  350. }
  351. // Sets the width of the banner fixed element. Use to adjust the width of the
  352. // fixed banner in cases where width is not the same as the viewport.
  353. // @param {Number} $width Width value in `px`.
  354. @mixin fixed-width($width, $query: feature-targeting.all()) {
  355. $feat-structure: feature-targeting.create-target($query, structure);
  356. .mdc-banner__fixed {
  357. @include feature-targeting.targets($feat-structure) {
  358. width: $width;
  359. }
  360. }
  361. }
  362. @mixin _supporting-text-typography(
  363. $typography-map,
  364. $query: feature-targeting.all()
  365. ) {
  366. $feat-typography: feature-targeting.create-target($query, typography);
  367. $font: map.get($typography-map, font);
  368. $size: map.get($typography-map, size);
  369. $tracking: map.get($typography-map, tracking);
  370. $weight: map.get($typography-map, weight);
  371. $line-height: map.get($typography-map, line-height);
  372. .mdc-banner__text {
  373. @include feature-targeting.targets($feat-typography) {
  374. @include theme.property(letter-spacing, $tracking);
  375. @include theme.property(font-size, $size);
  376. @include theme.property(font-family, $font);
  377. @include theme.property(font-weight, $weight);
  378. @include theme.property(line-height, $line-height);
  379. }
  380. }
  381. }
  382. @mixin _banner-shape($shape, $query: feature-targeting.all()) {
  383. @include shape-mixins.radius($shape, $query: $query);
  384. }
  385. @mixin _banner-elevation(
  386. $resolver,
  387. $elevation,
  388. $shadow-color,
  389. $query: feature-targeting.all()
  390. ) {
  391. $elevation-resolver: map.get($resolver, elevation);
  392. @include elevation-theme.with-resolver(
  393. $elevation-resolver,
  394. $elevation: $elevation,
  395. $shadow-color: $shadow-color,
  396. $query: $query
  397. );
  398. }
  399. @mixin _graphic-size($size, $query: feature-targeting.all()) {
  400. $feat-structure: feature-targeting.create-target($query, structure);
  401. .mdc-banner__graphic {
  402. @include feature-targeting.targets($feat-structure) {
  403. @include theme.property(height, $size);
  404. @include theme.property(width, $size);
  405. }
  406. }
  407. }