_select.scss 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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. // NOTE: this is the implementation of the aforementioned classes.
  25. @use 'sass:math';
  26. @use '@material/dom/mixins' as dom-mixins;
  27. @use '@material/feature-targeting/feature-targeting';
  28. @use '@material/floating-label/mixins' as floating-label-mixins;
  29. @use '@material/floating-label/variables' as floating-label-variables;
  30. @use '@material/list/mixins' as list-mixins;
  31. @use '@material/list/evolution-mixins' as list-evolution-mixins;
  32. @use '@material/notched-outline/mixins' as notched-outline-mixins;
  33. @use '@material/notched-outline/variables' as notched-outline-variables;
  34. @use '@material/rtl/rtl';
  35. @use '@material/typography/mixins' as typography-mixins;
  36. @use './select-helper-text-theme';
  37. @use './select-icon-theme';
  38. @use './select-theme';
  39. @use './select-filled';
  40. @use './select-outlined';
  41. @use './select-ripple';
  42. @use './select-helper-text';
  43. @use './select-icon';
  44. @mixin static-styles($query: feature-targeting.all()) {
  45. @include _static-styles-base($query);
  46. @include select-filled.static-styles($query);
  47. @include select-outlined.static-styles($query);
  48. }
  49. @mixin _static-styles-base($query) {
  50. $feat-structure: feature-targeting.create-target($query, structure);
  51. .mdc-select {
  52. // Floating label private mixin
  53. @include _floating-label($query: $query);
  54. @include _option-side-padding(16px, $query: $query);
  55. @include _option-graphic-trailing-margin(12px, $query: $query);
  56. @include feature-targeting.targets($feat-structure) {
  57. display: inline-flex;
  58. position: relative; // Menu is absolutely positioned relative to this.
  59. &[hidden] {
  60. display: none;
  61. }
  62. }
  63. &__dropdown-icon {
  64. @include _dropdown-icon-base($query: $query);
  65. @include _dropdown-icon-inactive($query: $query);
  66. @include feature-targeting.targets($feat-structure) {
  67. display: inline-flex;
  68. position: relative;
  69. align-self: center;
  70. align-items: center;
  71. justify-content: center;
  72. flex-shrink: 0;
  73. pointer-events: none;
  74. }
  75. .mdc-select--activated & {
  76. @include _dropdown-icon-active($query: $query);
  77. }
  78. }
  79. }
  80. .mdc-select__anchor {
  81. @include feature-targeting.targets($feat-structure) {
  82. min-width: 0;
  83. flex: 1 1 auto;
  84. position: relative;
  85. box-sizing: border-box;
  86. overflow: hidden;
  87. outline: none;
  88. cursor: pointer;
  89. }
  90. }
  91. @include _text($query: $query);
  92. .mdc-select--disabled {
  93. @include _disabled($query: $query);
  94. }
  95. .mdc-select--with-leading-icon {
  96. @include _option-side-padding(12px, $query: $query);
  97. }
  98. @include _list($query: $query);
  99. @include select-filled.core-styles($query: $query);
  100. @include select-outlined.core-styles($query: $query);
  101. @include select-ripple.core-styles($query: $query);
  102. @include select-helper-text.helper-text-core-styles($query: $query);
  103. @include select-icon.icon-core-styles($query: $query);
  104. }
  105. @mixin core-styles($query: feature-targeting.all()) {
  106. @include _static-styles-base($query);
  107. $feat-animation: feature-targeting.create-target($query, animation);
  108. $feat-color: feature-targeting.create-target($query, color);
  109. $feat-structure: feature-targeting.create-target($query, structure);
  110. .mdc-select {
  111. @include select-theme.ink-color(
  112. (
  113. default: select-theme.$ink-color,
  114. disabled: select-theme.$disabled-ink-color,
  115. ),
  116. $query: $query
  117. );
  118. @include select-theme.label-color(
  119. (
  120. default: select-theme.$label-color,
  121. focus: select-theme.$focused-label-color,
  122. disabled: select-theme.$disabled-label-color,
  123. ),
  124. $query: $query
  125. );
  126. @include select-theme.dropdown-icon-color(
  127. (
  128. default: select-theme.$dropdown-icon-color,
  129. focus: primary,
  130. disabled: select-theme.$disabled-dropdown-icon-color,
  131. ),
  132. $query: $query
  133. );
  134. @include select-helper-text-theme.helper-text-color(
  135. (
  136. default: select-helper-text-theme.$helper-text-color,
  137. disabled: select-helper-text-theme.$disabled-helper-text-color,
  138. ),
  139. $query: $query
  140. );
  141. @include select-icon-theme.icon-color(
  142. (
  143. default: select-icon-theme.$icon-color,
  144. disabled: select-icon-theme.$disabled-icon-color,
  145. ),
  146. $query: $query
  147. );
  148. // High-contrast mode support
  149. @include dom-mixins.forced-colors-mode() {
  150. $gray-text: (
  151. disabled: GrayText,
  152. );
  153. @include select-theme.ink-color($gray-text, $query: $query);
  154. @include select-theme.dropdown-icon-color(
  155. (
  156. disabled: red,
  157. ),
  158. $query: $query
  159. );
  160. @include select-theme.label-color($gray-text, $query: $query);
  161. @include select-theme.bottom-line-color($gray-text, $query: $query);
  162. @include select-theme.outline-color($gray-text, $query: $query);
  163. @include select-icon-theme.icon-color($gray-text, $query: $query);
  164. @include select-helper-text-theme.helper-text-color(
  165. $gray-text,
  166. $query: $query
  167. );
  168. }
  169. @include _padding-horizontal(
  170. $left: select-theme.$anchor-padding-left,
  171. $left-with-leading-icon:
  172. select-theme.$anchor-padding-left-with-leading-icon,
  173. $right: select-theme.$anchor-padding-right,
  174. $query: $query
  175. );
  176. @include select-icon-theme.size(
  177. select-icon-theme.$icon-size,
  178. $query: $query
  179. );
  180. @include select-theme.dropdown-icon-size(
  181. select-icon-theme.$icon-size,
  182. $query: $query
  183. );
  184. &__dropdown-icon {
  185. @include feature-targeting.targets($feat-structure) {
  186. @include rtl.reflexive-property(
  187. margin,
  188. select-icon-theme.$icon-horizontal-margin,
  189. select-icon-theme.$icon-horizontal-margin
  190. );
  191. }
  192. }
  193. }
  194. .mdc-select__anchor {
  195. @include floating-label-mixins.float-position(
  196. select-theme.$label-position-y,
  197. $query: $query
  198. );
  199. @include feature-targeting.targets($feat-structure) {
  200. width: select-theme.$default-width;
  201. }
  202. }
  203. .mdc-select--invalid {
  204. @include select-theme.label-color(
  205. (
  206. default: select-theme.$error-color,
  207. focus: select-theme.$error-color,
  208. ),
  209. $query: $query
  210. );
  211. @include select-helper-text-theme.helper-text-validation-color(
  212. select-theme.$error-color,
  213. $query: $query
  214. );
  215. @include select-theme.dropdown-icon-color(
  216. (
  217. default: select-theme.$error-color,
  218. focus: select-theme.$error-color,
  219. ),
  220. $query: $query
  221. );
  222. }
  223. @include _text-container-height($query: $query);
  224. }
  225. @mixin _list($query) {
  226. $feat-structure: feature-targeting.create-target($query, structure);
  227. @include dom-mixins.forced-colors-mode() {
  228. .mdc-select__menu::before {
  229. @include dom-mixins.transparent-border($query: $query);
  230. }
  231. }
  232. .mdc-select__menu .mdc-deprecated-list,
  233. .mdc-select__menu .mdc-list {
  234. @include select-icon-theme.icon-horizontal-margins(0, 0, $query: $query);
  235. @include list-mixins.deprecated-item-selected-text-color(
  236. on-surface,
  237. $query: $query
  238. );
  239. }
  240. .mdc-select__menu .mdc-list-item__start {
  241. @include feature-targeting.targets($feat-structure) {
  242. display: inline-flex;
  243. align-items: center;
  244. }
  245. }
  246. .mdc-select__option {
  247. @include list-evolution-mixins.item-spacing(16px, $query: $query);
  248. }
  249. .mdc-select__one-line-option {
  250. @include list-evolution-mixins.one-line-item-height(48px, $query: $query);
  251. }
  252. .mdc-select__two-line-option {
  253. @include list-evolution-mixins.two-line-item-height(64px, $query: $query);
  254. &.mdc-list-item--with-two-lines {
  255. .mdc-list-item__start {
  256. @include feature-targeting.targets($feat-structure) {
  257. margin-top: 20px;
  258. }
  259. }
  260. .mdc-list-item__primary-text {
  261. @include typography-mixins.text-baseline(
  262. $top: 28px,
  263. $bottom: 20px,
  264. $query: $query
  265. );
  266. }
  267. &.mdc-list-item--with-trailing-meta .mdc-list-item__end {
  268. @include typography-mixins.text-baseline($top: 36px, $query: $query);
  269. }
  270. }
  271. }
  272. .mdc-select__option-with-leading-content {
  273. @include list-evolution-mixins.item-start-spacing(12px, 0, $query: $query);
  274. @include list-evolution-mixins.item-start-size(36px, 24px, $query: $query);
  275. @include list-evolution-mixins.item-spacing(0, 12px, $query: $query);
  276. }
  277. .mdc-select__option-with-meta {
  278. @include list-evolution-mixins.item-end-spacing(12px, $query: $query);
  279. }
  280. }
  281. ///
  282. /// Sets base dropdown icon styles.
  283. /// @access private
  284. ///
  285. @mixin _dropdown-icon-base($query: feature-targeting.all()) {
  286. $feat-structure: feature-targeting.create-target($query, structure);
  287. .mdc-select__dropdown-icon-active,
  288. .mdc-select__dropdown-icon-inactive {
  289. @include feature-targeting.targets($feat-structure) {
  290. position: absolute;
  291. top: 0;
  292. left: 0;
  293. }
  294. }
  295. .mdc-select__dropdown-icon-graphic {
  296. $svg-natural-width: 10px;
  297. $svg-natural-height: 5px;
  298. @include feature-targeting.targets($feat-structure) {
  299. width: math.div($svg-natural-width, select-icon-theme.$icon-size) * 100%;
  300. height: math.div($svg-natural-height, select-icon-theme.$icon-size) * 100%;
  301. }
  302. }
  303. }
  304. ///
  305. /// Sets styles for transitioning the dropdown icon to inactive state.
  306. /// @access private
  307. ///
  308. @mixin _dropdown-icon-inactive($query: feature-targeting.all()) {
  309. $feat-structure: feature-targeting.create-target($query, structure);
  310. $feat-animation: feature-targeting.create-target($query, animation);
  311. .mdc-select__dropdown-icon-inactive {
  312. @include feature-targeting.targets($feat-structure) {
  313. opacity: 1;
  314. }
  315. @include feature-targeting.targets($feat-animation) {
  316. transition: opacity select-theme.$icon-inactive-fade-in-duration linear
  317. select-theme.$icon-inactive-fade-out-duration;
  318. }
  319. }
  320. .mdc-select__dropdown-icon-active {
  321. @include feature-targeting.targets($feat-structure) {
  322. opacity: 0;
  323. }
  324. @include feature-targeting.targets($feat-animation) {
  325. transition: opacity select-theme.$icon-inactive-fade-out-duration linear;
  326. }
  327. }
  328. }
  329. ///
  330. /// Sets styles for transitioning the dropdown icon to activated state.
  331. /// @access private
  332. ///
  333. @mixin _dropdown-icon-active($query: feature-targeting.all()) {
  334. $feat-structure: feature-targeting.create-target($query, structure);
  335. $feat-animation: feature-targeting.create-target($query, animation);
  336. .mdc-select__dropdown-icon-inactive {
  337. @include feature-targeting.targets($feat-structure) {
  338. opacity: 0;
  339. }
  340. @include feature-targeting.targets($feat-animation) {
  341. transition: opacity select-theme.$icon-active-fade-out-duration linear;
  342. }
  343. }
  344. .mdc-select__dropdown-icon-active {
  345. @include feature-targeting.targets($feat-structure) {
  346. opacity: 1;
  347. }
  348. @include feature-targeting.targets($feat-animation) {
  349. transition: opacity select-theme.$icon-active-fade-in-duration linear
  350. select-theme.$icon-active-fade-out-duration;
  351. }
  352. }
  353. }
  354. ///
  355. /// Sets the side padding for option text.
  356. /// @access private
  357. ///
  358. @mixin _option-side-padding($side-padding, $query: feature-targeting.all()) {
  359. $feat-structure: feature-targeting.create-target($query, structure);
  360. .mdc-select__menu .mdc-deprecated-list-item {
  361. @include feature-targeting.targets($feat-structure) {
  362. @include rtl.reflexive-property(padding, $side-padding, $side-padding);
  363. }
  364. }
  365. }
  366. ///
  367. /// Sets the traliing margin for an option's leading graphic.
  368. /// @access private
  369. ///
  370. @mixin _option-graphic-trailing-margin(
  371. $margin-right,
  372. $query: feature-targeting.all()
  373. ) {
  374. $feat-structure: feature-targeting.create-target($query, structure);
  375. .mdc-select__menu .mdc-deprecated-list-item__graphic {
  376. @include feature-targeting.targets($feat-structure) {
  377. @include rtl.reflexive-box(margin, right, $margin-right);
  378. }
  379. }
  380. }
  381. @mixin _floating-label($query: feature-targeting.all()) {
  382. $feat-structure: feature-targeting.create-target($query, structure);
  383. .mdc-floating-label {
  384. @include feature-targeting.targets($feat-structure) {
  385. top: 50%;
  386. transform: translateY(-50%);
  387. pointer-events: none;
  388. }
  389. }
  390. }
  391. @mixin _text-container-height($query: feature-targeting.all()) {
  392. $feat-structure: feature-targeting.create-target($query, structure);
  393. .mdc-select__selected-text-container {
  394. @include feature-targeting.targets($feat-structure) {
  395. height: select-theme.$selected-text-height;
  396. }
  397. }
  398. }
  399. @mixin _text($query: feature-targeting.all()) {
  400. $feat-structure: feature-targeting.create-target($query, structure);
  401. $feat-color: feature-targeting.create-target($query, color);
  402. .mdc-select__selected-text-container {
  403. @include feature-targeting.targets($feat-structure) {
  404. display: flex;
  405. appearance: none;
  406. pointer-events: none;
  407. box-sizing: border-box;
  408. width: auto;
  409. min-width: 0;
  410. flex-grow: 1;
  411. border: none;
  412. outline: none;
  413. padding: 0;
  414. }
  415. @include feature-targeting.targets($feat-color) {
  416. background-color: transparent;
  417. color: inherit; // Override default user agent stylesheet
  418. }
  419. }
  420. .mdc-select__selected-text {
  421. @include typography-mixins.typography(subtitle1, $query: $query);
  422. @include typography-mixins.overflow-ellipsis($query: $query);
  423. @include feature-targeting.targets($feat-structure) {
  424. display: block;
  425. width: 100%;
  426. @include rtl.ignore-next-line();
  427. text-align: left;
  428. @include rtl.rtl {
  429. @include rtl.ignore-next-line();
  430. text-align: right;
  431. }
  432. }
  433. }
  434. }
  435. @mixin _disabled($query: feature-targeting.all()) {
  436. $feat-structure: feature-targeting.create-target($query, structure);
  437. @include feature-targeting.targets($feat-structure) {
  438. cursor: default;
  439. pointer-events: none;
  440. }
  441. }
  442. /// Adds horizontal padding to the selected text
  443. ///
  444. /// @param {Number} $left - left side padding
  445. /// @param {Number} $left-with-leading-icon - left-side padding when a leading
  446. /// icon is present
  447. /// @param {Number} $right - right-side padding; note that a trailing icon is
  448. /// always present.
  449. @mixin _padding-horizontal(
  450. $left,
  451. $left-with-leading-icon,
  452. $right,
  453. $query: feature-targeting.all()
  454. ) {
  455. $feat-structure: feature-targeting.create-target($query, structure);
  456. .mdc-select__anchor {
  457. @include feature-targeting.targets($feat-structure) {
  458. @include rtl.reflexive-property(padding, $left, $right);
  459. }
  460. }
  461. &.mdc-select--with-leading-icon .mdc-select__anchor {
  462. @include feature-targeting.targets($feat-structure) {
  463. @include rtl.reflexive-property(padding, $left-with-leading-icon, $right);
  464. }
  465. }
  466. }