_select-theme.scss 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788
  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 'sass:color';
  27. @use 'sass:list';
  28. @use 'sass:map';
  29. @use 'sass:meta';
  30. @use '@material/tokens/resolvers';
  31. @use '@material/density/functions' as density-functions;
  32. @use '@material/density/variables' as density-variables;
  33. @use '@material/elevation/elevation-theme';
  34. @use '@material/feature-targeting/feature-targeting';
  35. @use '@material/floating-label/mixins' as floating-label-mixins;
  36. @use '@material/floating-label/variables' as floating-label-variables;
  37. @use '@material/line-ripple/mixins' as line-ripple-mixins;
  38. @use '@material/list/mixins' as list-mixins;
  39. @use '@material/list/evolution-mixins' as list-evolution-mixins;
  40. @use '@material/menu-surface/mixins' as menu-surface-mixins;
  41. @use '@material/notched-outline/mixins' as notched-outline-mixins;
  42. @use '@material/notched-outline/variables' as notched-outline-variables;
  43. @use '@material/ripple/ripple-theme';
  44. @use '@material/rtl/rtl';
  45. @use '@material/shape/functions' as shape-functions;
  46. @use '@material/shape/mixins' as shape-mixins;
  47. @use '@material/theme/css';
  48. @use '@material/theme/custom-properties';
  49. @use '@material/theme/gss';
  50. @use '@material/theme/keys';
  51. @use '@material/theme/state';
  52. @use '@material/theme/theme';
  53. @use '@material/theme/variables' as theme-variables;
  54. @use '@material/typography/mixins' as typography-mixins;
  55. @use '@material/typography/typography';
  56. @use './select-helper-text-theme';
  57. @use './select-icon-theme';
  58. @use './select-shared-theme';
  59. $ripple-target: '.mdc-select__ripple';
  60. @function get-outlined-label-position-y($select-anchor-height) {
  61. @if custom-properties.is-custom-prop($select-anchor-height) {
  62. $value: custom-properties.get-declaration-value($select-anchor-height);
  63. @return calc(
  64. calc($value / 2) +
  65. math.div(notched-outline-variables.$label-box-height, 2)
  66. );
  67. } @else {
  68. @return math.div($select-anchor-height, 2) +
  69. math.div(notched-outline-variables.$label-box-height, 2);
  70. }
  71. }
  72. $arrow-padding: 52px !default;
  73. $label-padding: 16px !default;
  74. $height: 56px !default;
  75. $minimum-height-for-filled-label: 52px !default;
  76. $filled-baseline-top: 40px !default;
  77. $selected-text-height: 28px !default;
  78. $anchor-padding-left: 16px !default;
  79. $anchor-padding-left-with-leading-icon: 0 !default;
  80. $anchor-padding-right: 0 !default;
  81. $outlined-stroke-width: 2px !default;
  82. $default-width: 200px !default;
  83. $shape-radius: small !default;
  84. $minimum-height: 40px !default;
  85. $minimum-height-for-filled-label: 52px !default;
  86. $maximum-height: $height !default;
  87. $density-scale: density-variables.$default-scale !default;
  88. $density-config: (
  89. height: (
  90. default: $height,
  91. maximum: $maximum-height,
  92. minimum: $minimum-height,
  93. ),
  94. ) !default;
  95. $ink-color: rgba(theme-variables.prop-value(on-surface), 0.87) !default;
  96. $dropdown-icon-color: rgba(
  97. theme-variables.prop-value(on-surface),
  98. 0.54
  99. ) !default;
  100. $label-color: rgba(theme-variables.prop-value(on-surface), 0.6) !default;
  101. $focused-label-color: rgba(theme-variables.prop-value(primary), 0.87) !default;
  102. $bottom-line-idle-color: rgba(
  103. theme-variables.prop-value(on-surface),
  104. 0.42
  105. ) !default;
  106. $bottom-line-hover-color: rgba(
  107. theme-variables.prop-value(on-surface),
  108. 0.87
  109. ) !default;
  110. $fill-color: color.mix(
  111. theme-variables.prop-value(on-surface),
  112. theme-variables.prop-value(surface),
  113. 4%
  114. ) !default;
  115. // Disabled Styles
  116. $disabled-label-color: rgba(
  117. theme-variables.prop-value(on-surface),
  118. 0.38
  119. ) !default;
  120. $disabled-ink-color: rgba(
  121. theme-variables.prop-value(on-surface),
  122. 0.38
  123. ) !default;
  124. $disabled-fill-color: color.mix(
  125. theme-variables.prop-value(on-surface),
  126. theme-variables.prop-value(surface),
  127. 2%
  128. ) !default;
  129. $disabled-fill-border: rgba(
  130. theme-variables.prop-value(on-surface),
  131. 0.06
  132. ) !default;
  133. $disabled-bottom-line-color: rgba(
  134. theme-variables.prop-value(on-surface),
  135. 0.06
  136. ) !default;
  137. $disabled-dropdown-icon-color: rgba(
  138. theme-variables.prop-value(on-surface),
  139. 0.38
  140. ) !default;
  141. $disabled-outline-color: rgba(
  142. theme-variables.prop-value(on-surface),
  143. 0.06
  144. ) !default;
  145. $outlined-idle-border: rgba(
  146. theme-variables.prop-value(on-surface),
  147. 0.38
  148. ) !default;
  149. $outlined-hover-border: rgba(
  150. theme-variables.prop-value(on-surface),
  151. 0.87
  152. ) !default;
  153. $label-position-y: 106% !default;
  154. $outline-label-offset: 16px !default;
  155. $outlined-label-position-y: get-outlined-label-position-y($height) !default;
  156. $outlined-with-leading-icon-label-position-x: 32px !default;
  157. $dropdown-transition-duration: 150ms !default;
  158. // Transition durartions to active state
  159. $icon-active-fade-out-duration: 0.33 * $dropdown-transition-duration !default;
  160. $icon-active-fade-in-duration: 0.67 * $dropdown-transition-duration !default;
  161. // Transition durartions to inactive state
  162. $icon-inactive-fade-out-duration: 0.5 * $dropdown-transition-duration !default;
  163. $icon-inactive-fade-in-duration: 0.5 * $dropdown-transition-duration !default;
  164. // Error colors
  165. $error-color: error !default;
  166. @mixin theme-styles($theme, $resolvers: resolvers.$material) {
  167. @include container-fill-color(
  168. (
  169. default: map.get($theme, text-field-container-color),
  170. disabled: map.get($theme, text-field-disabled-container-color),
  171. )
  172. );
  173. @include outline-color(
  174. (
  175. default: map.get($theme, text-field-outline-color),
  176. hover: map.get($theme, text-field-hover-outline-color),
  177. focus: map.get($theme, text-field-focus-outline-color),
  178. disabled: map.get($theme, text-field-disabled-outline-color),
  179. )
  180. );
  181. @include _error-outline-color(
  182. (
  183. default: map.get($theme, text-field-error-outline-color),
  184. hover: map.get($theme, text-field-error-hover-outline-color),
  185. focus: map.get($theme, text-field-error-focus-outline-color),
  186. )
  187. );
  188. @include outline-width(
  189. (
  190. default: map.get($theme, text-field-outline-width),
  191. hover: map.get($theme, text-field-hover-outline-width),
  192. focus: map.get($theme, text-field-focus-outline-width),
  193. )
  194. );
  195. @include _menu-container-color(map.get($theme, menu-container-color));
  196. @include _menu-container-elevation(map.get($theme, menu-container-elevation));
  197. @include _menu-container-shape(map.get($theme, menu-container-shape));
  198. @include _menu-container-surface-tint-layer-color(
  199. map.get($theme, menu-container-surface-tint-layer-color)
  200. );
  201. @include _menu-divider-color(map.get($theme, menu-divider-color));
  202. @include _menu-divider-height(map.get($theme, menu-divider-height));
  203. @include _menu-list-item-container-height(
  204. map.get($theme, menu-list-item-container-height)
  205. );
  206. @include _menu-list-item-label-text-color(
  207. map.get($theme, menu-list-item-label-text-color)
  208. );
  209. @include _menu-list-item-label-text-typography(
  210. (
  211. font: map.get($theme, menu-list-item-label-text-font),
  212. line-height: map.get($theme, menu-list-item-label-text-line-height),
  213. size: map.get($theme, menu-list-item-label-text-size),
  214. tracking: map.get($theme, menu-list-item-label-text-tracking),
  215. weight: map.get($theme, menu-list-item-label-text-weight),
  216. )
  217. );
  218. @include _menu-list-item-state-layer(
  219. (
  220. focus-state-layer-color:
  221. map.get($theme, menu-list-item-focus-state-layer-color),
  222. focus-state-layer-opacity:
  223. map.get($theme, menu-list-item-focus-state-layer-opacity),
  224. hover-state-layer-color:
  225. map.get($theme, menu-list-item-hover-state-layer-color),
  226. hover-state-layer-opacity:
  227. map.get($theme, menu-list-item-hover-state-layer-opacity),
  228. pressed-state-layer-color:
  229. map.get($theme, menu-list-item-pressed-state-layer-color),
  230. pressed-state-layer-opacity:
  231. map.get($theme, menu-list-item-pressed-state-layer-opacity),
  232. )
  233. );
  234. @include _menu-list-item-selected-container-color(
  235. map.get($theme, menu-list-item-selected-container-color)
  236. );
  237. @include _menu-list-item-with-leading-icon-leading-icon-color(
  238. map.get($theme, menu-list-item-with-leading-icon-leading-icon-color)
  239. );
  240. @include _menu-list-item-with-leading-icon-leading-icon-size(
  241. map.get($theme, menu-list-item-with-leading-icon-leading-icon-size)
  242. );
  243. // TODO: Create new mixin for trailing icon theming when select supports it.
  244. @include _menu-list-item-with-leading-icon-leading-icon-color(
  245. map.get($theme, menu-list-item-with-trailing-icon-trailing-icon-color)
  246. );
  247. @include _menu-list-item-with-leading-icon-leading-icon-size(
  248. map.get($theme, menu-list-item-with-trailing-icon-trailing-icon-size)
  249. );
  250. @include bottom-line-color(
  251. (
  252. default: map.get($theme, text-field-active-indicator-color),
  253. hover: map.get($theme, text-field-hover-active-indicator-color),
  254. focus: map.get($theme, text-field-focus-active-indicator-color),
  255. disabled: map.get($theme, text-field-disabled-active-indicator-color),
  256. )
  257. );
  258. @include dropdown-icon-size(map.get($theme, text-field-trailing-icon-size));
  259. @include select-icon-theme.size(
  260. map.get($theme, text-field-leading-icon-size)
  261. );
  262. @include _text-field-error-active-indicator-color(
  263. (
  264. default: map.get($theme, text-field-error-active-indicator-color),
  265. hover: map.get($theme, text-field-error-hover-active-indicator-color),
  266. focus: map.get($theme, text-field-error-focus-active-indicator-color),
  267. )
  268. );
  269. @include _text-field-active-indicator-height(
  270. (
  271. default: map.get($theme, text-field-active-indicator-height),
  272. focus: map.get($theme, text-field-focus-active-indicator-height),
  273. )
  274. );
  275. // TODO(b/259951357): Cleanup branch after fix and tokens upgrade.
  276. @if map.has-key($theme, text-field-caret-color) or
  277. map.has-key($theme, text-field-error-caret-color)
  278. {
  279. @include _text-field-trailing-icon-color(
  280. (
  281. default: map.get($theme, text-field-caret-color),
  282. hover: map.get($theme, text-field-hover-caret-color),
  283. focus: map.get($theme, text-field-focus-caret-color),
  284. )
  285. );
  286. @include _text-field-error-trailing-icon-color(
  287. (
  288. default: map.get($theme, text-field-error-caret-color),
  289. hover: map.get($theme, text-field-error-hover-caret-color),
  290. focus: map.get($theme, text-field-error-focus-caret-color),
  291. )
  292. );
  293. } @else {
  294. @include _text-field-trailing-icon-color(
  295. (
  296. default: map.get($theme, text-field-trailing-icon-color),
  297. hover: map.get($theme, text-field-hover-trailing-icon-color),
  298. focus: map.get($theme, text-field-focus-trailing-icon-color),
  299. disabled: map.get($theme, text-field-disabled-trailing-icon-color),
  300. )
  301. );
  302. @include _text-field-error-trailing-icon-color(
  303. (
  304. default: map.get($theme, text-field-error-trailing-icon-color),
  305. hover: map.get($theme, text-field-error-hover-trailing-icon-color),
  306. focus: map.get($theme, text-field-error-focus-trailing-icon-color),
  307. )
  308. );
  309. }
  310. @include ink-color(
  311. (
  312. default: map.get($theme, text-field-input-text-color),
  313. hover: map.get($theme, text-field-hover-input-text-color),
  314. focus: map.get($theme, text-field-focus-input-text-color),
  315. disabled: map.get($theme, text-field-disabled-input-text-color),
  316. )
  317. );
  318. @include _error-input-text-color(
  319. (
  320. default: map.get($theme, text-field-error-input-text-color),
  321. hover: map.get($theme, text-field-error-hover-input-text-color),
  322. focus: map.get($theme, text-field-error-focus-input-text-color),
  323. )
  324. );
  325. @include label-color(
  326. (
  327. default: map.get($theme, text-field-label-text-color),
  328. hover: map.get($theme, text-field-hover-label-text-color),
  329. focus: map.get($theme, text-field-focus-label-text-color),
  330. disabled: map.get($theme, text-field-disabled-label-text-color),
  331. )
  332. );
  333. @include label-floating-color(
  334. (
  335. default: map.get($theme, text-field-label-text-color),
  336. hover: map.get($theme, text-field-hover-label-text-color),
  337. focus: map.get($theme, text-field-focus-label-text-color),
  338. disabled: map.get($theme, text-field-disabled-label-text-color),
  339. )
  340. );
  341. @include _error-label-text-color(
  342. (
  343. default: map.get($theme, text-field-error-label-text-color),
  344. hover: map.get($theme, text-field-error-hover-label-text-color),
  345. focus: map.get($theme, text-field-error-focus-label-text-color),
  346. )
  347. );
  348. @include _text-field-leading-icon-color(
  349. (
  350. default: map.get($theme, text-field-leading-icon-color),
  351. hover: map.get($theme, text-field-hover-leading-icon-color),
  352. focus: map.get($theme, text-field-focus-leading-icon-color),
  353. disabled: map.get($theme, text-field-disabled-leading-icon-color),
  354. )
  355. );
  356. @include _error-text-field-leading-icon-color(
  357. (
  358. default: map.get($theme, text-field-error-leading-icon-color),
  359. hover: map.get($theme, text-field-error-hover-leading-icon-color),
  360. focus: map.get($theme, text-field-error-focus-leading-icon-color),
  361. )
  362. );
  363. @include select-helper-text-theme.helper-text-color(
  364. (
  365. default: map.get($theme, text-field-supporting-text-color),
  366. disabled: map.get($theme, text-field-disabled-supporting-text-color),
  367. hover: map.get($theme, text-field-hover-supporting-text-color),
  368. focus: map.get($theme, text-field-focus-supporting-text-color),
  369. )
  370. );
  371. @include select-helper-text-theme.helper-text-validation-color(
  372. (
  373. default: map.get($theme, text-field-error-supporting-text-color),
  374. hover: map.get($theme, text-field-error-hover-supporting-text-color),
  375. focus: map.get($theme, text-field-error-focus-supporting-text-color),
  376. )
  377. );
  378. @include _text-field-input-text-typography(
  379. (
  380. font: map.get($theme, text-field-input-text-font),
  381. line-height: map.get($theme, text-field-input-text-line-height),
  382. size: map.get($theme, text-field-input-text-size),
  383. tracking: map.get($theme, text-field-input-text-tracking),
  384. weight: map.get($theme, text-field-input-text-weight),
  385. )
  386. );
  387. @include _text-field-label-text-typography(
  388. (
  389. font: map.get($theme, text-field-label-text-font),
  390. line-height: map.get($theme, text-field-label-text-line-height),
  391. size: map.get($theme, text-field-label-text-size),
  392. tracking: map.get($theme, text-field-label-text-tracking),
  393. weight: map.get($theme, text-field-label-text-weight),
  394. )
  395. );
  396. @include _text-field-label-text-populated-typography(
  397. (
  398. line-height: map.get($theme, text-field-label-text-populated-line-height),
  399. size: map.get($theme, text-field-label-text-populated-size),
  400. )
  401. );
  402. @include _text-field-supporting-text-typography(
  403. (
  404. font: map.get($theme, text-field-supporting-text-font),
  405. line-height: map.get($theme, text-field-supporting-text-line-height),
  406. size: map.get($theme, text-field-supporting-text-size),
  407. tracking: map.get($theme, text-field-supporting-text-tracking),
  408. weight: map.get($theme, text-field-supporting-text-weight),
  409. )
  410. );
  411. }
  412. @mixin _text-field-supporting-text-typography($typography-theme) {
  413. & + .mdc-select-helper-text {
  414. @include typography.theme-styles($typography-theme);
  415. }
  416. }
  417. @mixin _text-field-input-text-typography($typography-theme) {
  418. .mdc-select__selected-text {
  419. @include typography.theme-styles($typography-theme);
  420. }
  421. }
  422. @mixin _text-field-label-text-populated-typography($typography-theme) {
  423. .mdc-floating-label--float-above,
  424. // Used for CSS specificity to match with selector used in `outlined-height()`.
  425. &.mdc-select--with-leading-icon .mdc-select__anchor .mdc-notched-outline .mdc-floating-label.mdc-floating-label--float-above {
  426. @include typography.theme-styles($typography-theme);
  427. }
  428. }
  429. @mixin _text-field-label-text-typography($typography-theme) {
  430. .mdc-floating-label {
  431. @include typography.theme-styles($typography-theme);
  432. }
  433. }
  434. @mixin _error-outline-color($color) {
  435. &.mdc-select--invalid {
  436. @include outline-color($color);
  437. }
  438. }
  439. @mixin _error-text-field-leading-icon-color($color) {
  440. &.mdc-select--invalid {
  441. @include _text-field-leading-icon-color($color);
  442. }
  443. }
  444. @mixin _text-field-leading-icon-color($color) {
  445. @include _if-enabled {
  446. @include _set-text-field-leading-icon-color(
  447. state.get-default-state($color)
  448. );
  449. &:not(.mdc-select--focused):hover {
  450. @include _set-text-field-leading-icon-color(
  451. state.get-hover-state($color)
  452. );
  453. }
  454. @include _if-focused {
  455. @include _set-text-field-leading-icon-color(
  456. state.get-focus-state($color)
  457. );
  458. }
  459. }
  460. @include _if-disabled {
  461. @include _set-text-field-leading-icon-color(
  462. state.get-disabled-state($color)
  463. );
  464. }
  465. }
  466. @mixin _set-text-field-leading-icon-color($color) {
  467. .mdc-select__anchor .mdc-select__icon {
  468. @include theme.property(color, $color);
  469. }
  470. }
  471. @mixin _error-label-text-color($color) {
  472. &.mdc-select--invalid {
  473. @include label-color($color);
  474. }
  475. }
  476. @mixin _error-input-text-color($color) {
  477. &.mdc-select--invalid {
  478. @include ink-color($color);
  479. }
  480. }
  481. @mixin _text-field-trailing-icon-color($color) {
  482. @include dropdown-icon-color($color);
  483. }
  484. @mixin _text-field-error-trailing-icon-color($color) {
  485. &.mdc-select--invalid {
  486. @include dropdown-icon-color($color);
  487. }
  488. }
  489. @mixin _text-field-error-active-indicator-color($color) {
  490. &.mdc-select--invalid {
  491. @include bottom-line-color($color);
  492. }
  493. }
  494. @mixin _text-field-active-indicator-height($height) {
  495. .mdc-line-ripple {
  496. @include line-ripple-mixins.height(state.get-default-state($height));
  497. @include line-ripple-mixins.active-height(state.get-focus-state($height));
  498. }
  499. }
  500. @mixin _menu-list-item-with-leading-icon-leading-icon-color($color) {
  501. &:not(.mdc-select--disabled) .mdc-select__option .mdc-select__icon {
  502. @include theme.property(color, $color);
  503. }
  504. }
  505. @mixin _menu-list-item-with-leading-icon-leading-icon-size($size) {
  506. &:not(.mdc-select--disabled) .mdc-select__option .mdc-select__icon {
  507. @include theme.property(font-size, $size);
  508. }
  509. }
  510. @mixin _menu-list-item-selected-container-color($color) {
  511. .mdc-select__option {
  512. @include list-evolution-mixins.list-item-selected-container-color($color);
  513. }
  514. }
  515. @mixin _menu-list-item-label-text-typography($typography-theme) {
  516. .mdc-select__option {
  517. @include list-evolution-mixins.list-primary-text-typography(
  518. $typography-theme
  519. );
  520. }
  521. }
  522. @mixin _menu-list-item-label-text-color($color) {
  523. .mdc-select__option {
  524. @include list-evolution-mixins.list-primary-text-ink-color($color);
  525. }
  526. }
  527. @mixin _menu-list-item-container-height($height) {
  528. .mdc-select__option {
  529. @include list-evolution-mixins.list-item-height($height);
  530. }
  531. }
  532. @mixin _menu-list-item-state-layer($ripple-theme) {
  533. .mdc-list-item:not(.mdc-list-item--disabled) {
  534. @include ripple-theme.theme-styles(
  535. $ripple-theme,
  536. $ripple-target: list-evolution-mixins.$ripple-target
  537. );
  538. }
  539. }
  540. @mixin _menu-divider-color($color) {
  541. .mdc-select__list {
  542. @include list-evolution-mixins.divider-color($color);
  543. }
  544. }
  545. @mixin _menu-divider-height($height) {
  546. .mdc-select__list {
  547. @include list-evolution-mixins.divider-height($height);
  548. }
  549. }
  550. @mixin _menu-container-color($color) {
  551. .mdc-select__menu {
  552. @include menu-surface-mixins.fill-color($color);
  553. }
  554. }
  555. @mixin _menu-container-elevation($elevation) {
  556. @if $elevation {
  557. .mdc-select__menu {
  558. @include elevation-theme.shadow(map.get($elevation, shadow));
  559. @include elevation-theme.overlay-opacity(
  560. map.get($elevation, overlay-opacity)
  561. );
  562. }
  563. }
  564. }
  565. @mixin _menu-container-shape($shape) {
  566. .mdc-select__menu {
  567. @include menu-surface-mixins.shape-radius($shape);
  568. }
  569. }
  570. @mixin _menu-container-surface-tint-layer-color($color) {
  571. .mdc-select__menu {
  572. @include elevation-theme.overlay-container-color($color);
  573. }
  574. }
  575. @mixin menu-list-item-secondary-label-text-color($color) {
  576. .mdc-select__list {
  577. @include list-evolution-mixins.list-secondary-text-ink-color($color);
  578. }
  579. }
  580. @mixin menu-list-item-secondary-label-text-typography($typography-theme) {
  581. .mdc-select__list {
  582. @include list-evolution-mixins.list-secondary-text-typography(
  583. $typography-theme
  584. );
  585. }
  586. }
  587. /// Sets the min-width of the select.
  588. /// @param {Number} $min-width - The desired min-width.
  589. /// @deprecated using this mixin is no longer required, and clients may set
  590. /// the attribute directly
  591. @mixin min-width($min-width, $query: feature-targeting.all()) {
  592. $feat-structure: feature-targeting.create-target($query, structure);
  593. @include feature-targeting.targets($feat-structure) {
  594. min-width: $min-width;
  595. }
  596. }
  597. /// Sets the select behavior to change width dynamically based on content.
  598. /// @param {Number} $min-width - The min-width of the select, which should be
  599. /// large enough to allow the label (if exists) to display in full.
  600. @mixin variable-width($min-width, $query: feature-targeting.all()) {
  601. $feat-structure: feature-targeting.create-target($query, structure);
  602. .mdc-select__anchor {
  603. @include feature-targeting.targets($feat-structure) {
  604. width: 100%;
  605. min-width: $min-width;
  606. }
  607. }
  608. }
  609. @mixin ink-color($color-or-map, $query: feature-targeting.all()) {
  610. @include _if-enabled {
  611. @include _ink-color(state.get-default-state($color-or-map), $query: $query);
  612. }
  613. @include _if-disabled {
  614. @include _ink-color(
  615. state.get-disabled-state($color-or-map),
  616. $query: $query
  617. );
  618. }
  619. }
  620. @mixin container-fill-color($color-or-map, $query: feature-targeting.all()) {
  621. @include _if-enabled {
  622. @include _container-fill-color(
  623. state.get-default-state($color-or-map),
  624. $query: $query
  625. );
  626. }
  627. @include _if-disabled {
  628. @include _container-fill-color(
  629. state.get-disabled-state($color-or-map),
  630. $query: $query
  631. );
  632. }
  633. }
  634. @mixin dropdown-icon-color($color-or-map, $query: feature-targeting.all()) {
  635. @include _if-enabled {
  636. @include _dropdown-icon-color(
  637. state.get-default-state($color-or-map),
  638. $query: $query
  639. );
  640. &:not(.mdc-select--focused):hover {
  641. @include _dropdown-icon-color(
  642. state.get-hover-state($color-or-map),
  643. $query: $query
  644. );
  645. }
  646. @include _if-focused {
  647. @include _dropdown-icon-color(
  648. state.get-focus-state($color-or-map),
  649. $query: $query
  650. );
  651. }
  652. }
  653. @include _if-disabled {
  654. @include _dropdown-icon-color(
  655. state.get-disabled-state($color-or-map),
  656. $query: $query
  657. );
  658. }
  659. }
  660. @mixin label-floating-color($color-or-map, $query: feature-targeting.all()) {
  661. @include _if-enabled {
  662. @include _label-floating-color(
  663. state.get-default-state($color-or-map),
  664. $query: $query
  665. );
  666. &:not(.mdc-select--focused):hover {
  667. @include _label-floating-color(
  668. state.get-hover-state($color-or-map),
  669. $query: $query
  670. );
  671. }
  672. }
  673. }
  674. @mixin bottom-line-color($color-or-map, $query: feature-targeting.all()) {
  675. @include _if-enabled {
  676. @include _bottom-line-color(
  677. state.get-default-state($color-or-map),
  678. $query: $query
  679. );
  680. // bottom line inactive/active are on different elements, does not need
  681. // to check for :not() focused
  682. &:hover {
  683. @include _bottom-line-color(
  684. state.get-hover-state($color-or-map),
  685. $query: $query
  686. );
  687. }
  688. @include _focused-line-ripple-color(
  689. state.get-focus-state($color-or-map),
  690. $query: $query
  691. );
  692. }
  693. @include _if-disabled {
  694. @include _bottom-line-color(
  695. state.get-disabled-state($color-or-map),
  696. $query: $query
  697. );
  698. }
  699. }
  700. @mixin label-color($color-or-map, $query: feature-targeting.all()) {
  701. @include _if-enabled {
  702. @include _label-color(
  703. state.get-default-state($color-or-map),
  704. $query: $query
  705. );
  706. @include _if-focused {
  707. @include _label-color(
  708. state.get-focus-state($color-or-map),
  709. $query: $query
  710. );
  711. }
  712. &:not(.mdc-select--focused):hover {
  713. @include _label-color(
  714. state.get-hover-state($color-or-map),
  715. $query: $query
  716. );
  717. }
  718. }
  719. @include _if-disabled {
  720. @include _label-color(
  721. state.get-disabled-state($color-or-map),
  722. $query: $query
  723. );
  724. }
  725. }
  726. @mixin outline-color($color-or-map, $query: feature-targeting.all()) {
  727. @include _if-enabled {
  728. @include _outline-color(
  729. state.get-default-state($color-or-map),
  730. $query: $query
  731. );
  732. &:not(.mdc-select--focused) .mdc-select__anchor:hover {
  733. @include _hover-outline-color(
  734. state.get-hover-state($color-or-map),
  735. $query: $query
  736. );
  737. }
  738. @include _if-focused {
  739. @include _focused-outline-color(
  740. state.get-focus-state($color-or-map),
  741. $query: $query
  742. );
  743. }
  744. }
  745. @include _if-disabled {
  746. @include _outline-color(
  747. state.get-disabled-state($color-or-map),
  748. $query: $query
  749. );
  750. }
  751. }
  752. @mixin outline-width($width, $query: feature-targeting.all()) {
  753. @include _if-enabled {
  754. @include _outline-width(state.get-default-state($width), $query: $query);
  755. &:not(.mdc-select--focused) .mdc-select__anchor:hover {
  756. @include _outline-width(state.get-hover-state($width), $query: $query);
  757. }
  758. @include _if-focused {
  759. .mdc-notched-outline {
  760. @include _outline-width(state.get-focus-state($width), $query: $query);
  761. }
  762. }
  763. }
  764. }
  765. @mixin _outline-width($width, $query: feature-targeting.all()) {
  766. @if $width {
  767. @include notched-outline-mixins.stroke-width($width, $query: $query);
  768. }
  769. }
  770. ///
  771. /// Sets the dropdown icon to the specified size.
  772. ///
  773. @mixin dropdown-icon-size($size, $query: feature-targeting.all()) {
  774. $feat-structure: feature-targeting.create-target($query, structure);
  775. .mdc-select__dropdown-icon {
  776. @include feature-targeting.targets($feat-structure) {
  777. @include theme.property(width, $size);
  778. @include theme.property(height, $size);
  779. }
  780. }
  781. }
  782. @mixin filled-shape-radius(
  783. $radius,
  784. $density-scale: $density-scale,
  785. $rtl-reflexive: false,
  786. $query: feature-targeting.all()
  787. ) {
  788. @if (meta.type-of($radius) == 'list') and
  789. (list.length($radius) > 2) and
  790. (
  791. (list.nth($radius, 3) != 0 and list.nth($radius, 3) != 0px) or
  792. (list.nth($radius, 4) != 0 and list.nth($radius, 4) != 0px)
  793. )
  794. {
  795. @error "mdc-select: Invalid radius #{$radius}. Only top-left and top-right corners may be customized.";
  796. }
  797. $height: density-functions.prop-value(
  798. $density-config: $density-config,
  799. $density-scale: $density-scale,
  800. $property-name: height,
  801. );
  802. $masked-radius: shape-functions.mask-radius($radius, 1 1 0 0);
  803. $fallback: if(
  804. custom-properties.is-custom-prop($radius),
  805. custom-properties.get-fallback($radius),
  806. null
  807. );
  808. @if meta.type-of($fallback) == 'list' {
  809. $fallback: css.unpack-value($fallback);
  810. $first: list.nth($masked-radius, 1);
  811. $second: list.nth($masked-radius, 2);
  812. $third: list.nth($masked-radius, 3);
  813. $fourth: list.nth($masked-radius, 4);
  814. $masked-radius: (
  815. if(
  816. custom-properties.is-custom-prop($first),
  817. custom-properties.set-fallback($first, list.nth($fallback, 1)),
  818. $first
  819. ),
  820. if(
  821. custom-properties.is-custom-prop($second),
  822. custom-properties.set-fallback($second, list.nth($fallback, 2)),
  823. $second
  824. ),
  825. if(
  826. custom-properties.is-custom-prop($third),
  827. custom-properties.set-fallback($third, list.nth($fallback, 3)),
  828. $third
  829. ),
  830. if(
  831. custom-properties.is-custom-prop($fourth),
  832. custom-properties.set-fallback($fourth, list.nth($fallback, 4)),
  833. $fourth
  834. )
  835. );
  836. }
  837. .mdc-select__anchor {
  838. @include shape-mixins.radius(
  839. $masked-radius,
  840. $rtl-reflexive,
  841. $component-height: $height,
  842. $query: $query
  843. );
  844. }
  845. }
  846. @mixin outline-shape-radius(
  847. $radius,
  848. $density-scale: $density-scale,
  849. $rtl-reflexive: false,
  850. $query: feature-targeting.all(),
  851. $height: null
  852. ) {
  853. $feat-structure: feature-targeting.create-target($query, structure);
  854. @if not $height {
  855. $height: density-functions.prop-value(
  856. $density-config: $density-config,
  857. $density-scale: $density-scale,
  858. $property-name: height,
  859. );
  860. }
  861. .mdc-notched-outline {
  862. @include notched-outline-mixins.shape-radius(
  863. $radius,
  864. $rtl-reflexive,
  865. $component-height: $height,
  866. $query: $query
  867. );
  868. }
  869. $resolved-radius: shape-functions.resolve-radius(
  870. $radius,
  871. $component-height: $height
  872. );
  873. $unpacked-radius: shape-functions.unpack-radius($resolved-radius);
  874. $top-left-radius: list.nth($unpacked-radius, 1);
  875. $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius);
  876. $top-left-radius-px: $top-left-radius;
  877. @if ($top-left-is-custom-prop) {
  878. $top-left-radius-px: custom-properties.get-fallback($top-left-radius);
  879. }
  880. @if (
  881. $top-left-is-custom-prop or
  882. $top-left-radius-px >
  883. notched-outline-variables.$leading-width
  884. ) {
  885. .mdc-select__anchor {
  886. @include _apply-outline-shape-padding(
  887. padding-left,
  888. $top-left-radius,
  889. $add-label-padding: true,
  890. $query: $query
  891. );
  892. @include rtl.rtl {
  893. @include feature-targeting.targets($feat-structure) {
  894. @include rtl.ignore-next-line();
  895. padding-left: 0;
  896. }
  897. @include _apply-outline-shape-padding(
  898. padding-right,
  899. $top-left-radius,
  900. $add-label-padding: true,
  901. $query: $query
  902. );
  903. }
  904. }
  905. + .mdc-select-helper-text {
  906. @include _apply-outline-shape-padding(
  907. margin-left,
  908. $top-left-radius,
  909. $add-label-padding: true,
  910. $query: $query
  911. );
  912. @include rtl.rtl {
  913. @include feature-targeting.targets($feat-structure) {
  914. @include rtl.ignore-next-line();
  915. margin-left: 0;
  916. }
  917. @include _apply-outline-shape-padding(
  918. margin-right,
  919. $top-left-radius,
  920. $add-label-padding: true,
  921. $query: $query
  922. );
  923. }
  924. }
  925. // Unlike textfield, select does not need to re-apply leading icon padding.
  926. // This is because select only has one potential leading class, not two
  927. // extra classes like textfield (leading + trailing). Textfield's two extra
  928. // classes can cause specificity conflicts, requiring everything to be
  929. // re-applied.
  930. }
  931. }
  932. ///
  933. /// Sets density scale for filled select variant.
  934. ///
  935. /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
  936. /// `-3`, `-2`, `-1`, `0`. Default is `0`.
  937. /// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
  938. /// filled selects at which to allow floating labels.
  939. ///
  940. @mixin filled-density(
  941. $density-scale,
  942. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  943. $query: feature-targeting.all()
  944. ) {
  945. $height: density-functions.prop-value(
  946. $density-config: $density-config,
  947. $density-scale: $density-scale,
  948. $property-name: height,
  949. );
  950. @include filled-height(
  951. $height,
  952. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  953. $query: $query
  954. );
  955. @include _list-density($density-scale, $query: $query);
  956. }
  957. ///
  958. /// Sets density scale for filled select variant with leading icon.
  959. ///
  960. /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
  961. /// `-3`, `-2`, `-1`, `0`. Default is `0`.
  962. /// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
  963. /// filled selects at which to allow floating labels.
  964. ///
  965. @mixin filled-with-leading-icon-density(
  966. $density-scale,
  967. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  968. $query: feature-targeting.all()
  969. ) {
  970. $height: density-functions.prop-value(
  971. $density-config: $density-config,
  972. $density-scale: $density-scale,
  973. $property-name: height,
  974. );
  975. @include filled-with-leading-icon-height(
  976. $height,
  977. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  978. $query: $query
  979. );
  980. @include _list-density($density-scale, $query: $query);
  981. }
  982. ///
  983. /// Sets density scale for outlined select (Excluding outlined select with leading icon).
  984. ///
  985. /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
  986. /// `-3`, `-2`, `-1`, `0`. Default is `0`.
  987. ///
  988. @mixin outlined-density($density-scale, $query: feature-targeting.all()) {
  989. $height: density-functions.prop-value(
  990. $density-config: $density-config,
  991. $density-scale: $density-scale,
  992. $property-name: height,
  993. );
  994. @include outlined-height($height, $query: $query);
  995. @include _list-density($density-scale, $query: $query);
  996. }
  997. ///
  998. /// Sets density scale for outlined select with leading icon.
  999. ///
  1000. /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
  1001. /// `-3`, `-2`, `-1`, `0`. Default is `0`.
  1002. ///
  1003. @mixin outlined-with-leading-icon-density(
  1004. $density-scale,
  1005. $query: feature-targeting.all()
  1006. ) {
  1007. $height: density-functions.prop-value(
  1008. $density-config: $density-config,
  1009. $density-scale: $density-scale,
  1010. $property-name: height,
  1011. );
  1012. @include outlined-with-leading-icon-height($height, $query: $query);
  1013. @include _list-density($density-scale, $query: $query);
  1014. }
  1015. @mixin _list-density($density-scale, $query) {
  1016. @include list-mixins.deprecated-single-line-density(
  1017. $density-scale,
  1018. $query: $query
  1019. );
  1020. .mdc-select__one-line-option {
  1021. @include list-evolution-mixins.one-line-item-density(
  1022. $density-scale,
  1023. $exclude-variants: true,
  1024. $query: $query
  1025. );
  1026. }
  1027. .mdc-select__two-line-option {
  1028. @include list-evolution-mixins.two-line-item-density(
  1029. $density-scale,
  1030. $query: $query
  1031. );
  1032. }
  1033. }
  1034. ///
  1035. /// Sets height of default select variant.
  1036. ///
  1037. /// @param {Number} $new-height
  1038. /// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
  1039. /// filled selects at which to allow floating labels.
  1040. /// @param {Number} $filled-baseline-top The baseline from the top of the anchor
  1041. /// that the input should be aligned to for a filled variant with a label
  1042. /// @access public
  1043. ///
  1044. @mixin filled-height(
  1045. $new-height,
  1046. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  1047. $filled-baseline-top: $filled-baseline-top,
  1048. $query: feature-targeting.all()
  1049. ) {
  1050. $feat-structure: feature-targeting.create-target($query, structure);
  1051. .mdc-select__anchor {
  1052. @include feature-targeting.targets($feat-structure) {
  1053. @include theme.property(height, $new-height);
  1054. }
  1055. // Filled variant is aligned to baseline...
  1056. @include typography-mixins.baseline(
  1057. $top: $filled-baseline-top,
  1058. $display: flex,
  1059. $query: $query
  1060. );
  1061. // ...unless it is too small to display a label
  1062. // TODO(b/283457421): Account for dynamic height
  1063. @if _is-less-than($new-height, $minimum-height-for-filled-label) {
  1064. @include center-aligned($query: $query);
  1065. @include feature-targeting.targets($feat-structure) {
  1066. .mdc-floating-label {
  1067. display: none;
  1068. }
  1069. }
  1070. }
  1071. }
  1072. // No-label variants are always centered
  1073. &.mdc-select--no-label .mdc-select__anchor {
  1074. @include center-aligned($query: $query);
  1075. }
  1076. // TODO(b/283457421): Account for dynamic height
  1077. @if _is-less-than($new-height, $height) {
  1078. @include dropdown-icon-size(
  1079. select-icon-theme.$dense-icon-size,
  1080. $query: $query
  1081. );
  1082. &.mdc-select--filled {
  1083. @include truncate-floating-label-max-width(
  1084. $leading-icon-size: 0,
  1085. $dropdown-icon-size: select-icon-theme.$dense-icon-size,
  1086. $query: $query
  1087. );
  1088. }
  1089. }
  1090. }
  1091. ///
  1092. /// Sets height of filled select variant with leading icon.
  1093. ///
  1094. /// @param {Number} $height
  1095. /// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
  1096. /// filled selects at which to allow floating labels.
  1097. /// @param {Number} $filled-baseline-top The baseline from the top of the anchor
  1098. /// that the input should be aligned to for a filled variant with a label
  1099. /// @access public
  1100. ///
  1101. @mixin filled-with-leading-icon-height(
  1102. $new-height,
  1103. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  1104. $filled-baseline-top: $filled-baseline-top,
  1105. $query: feature-targeting.all()
  1106. ) {
  1107. $feat-structure: feature-targeting.create-target($query, structure);
  1108. @include filled-height(
  1109. $new-height,
  1110. $minimum-height-for-filled-label: $minimum-height-for-filled-label,
  1111. $filled-baseline-top: $filled-baseline-top,
  1112. $query: $query
  1113. );
  1114. // TODO(b/283457421): Account for dynamic height
  1115. @if _is-less-than($new-height, $height) {
  1116. @include select-icon-theme.size(
  1117. select-icon-theme.$dense-icon-size,
  1118. $query: $query
  1119. );
  1120. &.mdc-select--filled {
  1121. @include truncate-floating-label-max-width(
  1122. $leading-icon-size: select-icon-theme.$dense-icon-size,
  1123. $dropdown-icon-size: select-icon-theme.$dense-icon-size,
  1124. $query: $query
  1125. );
  1126. }
  1127. .mdc-deprecated-list-item__graphic {
  1128. width: select-icon-theme.$dense-icon-size;
  1129. height: select-icon-theme.$dense-icon-size;
  1130. }
  1131. @include list-evolution-mixins.item-start-size(
  1132. $width: select-icon-theme.$dense-icon-size + 12px,
  1133. $height: select-icon-theme.$dense-icon-size,
  1134. $query: $query
  1135. );
  1136. .mdc-select__anchor {
  1137. @include leading-icon-floating-label-position(
  1138. select-icon-theme.$dense-icon-size,
  1139. $query: $query
  1140. );
  1141. }
  1142. }
  1143. }
  1144. ///
  1145. /// Sets height of outlined select variant (Excluding outlined select with leading icon).
  1146. ///
  1147. /// @param {Number} $new-height
  1148. /// @param {String} $keyframe-suffix - Optional suffix to use for generated
  1149. /// floating label keyframes
  1150. ///
  1151. @mixin outlined-height(
  1152. $new-height,
  1153. $keyframe-suffix: null,
  1154. $query: feature-targeting.all()
  1155. ) {
  1156. $feat-structure: feature-targeting.create-target($query, structure);
  1157. $positionY: get-outlined-label-position-y($new-height);
  1158. @if $keyframe-suffix == null {
  1159. $modifier: $new-height;
  1160. @if custom-properties.is-custom-prop($modifier) {
  1161. $modifier: custom-properties.get-fallback($modifier);
  1162. }
  1163. $keyframe-suffix: select-outlined-#{$modifier};
  1164. }
  1165. .mdc-select__anchor {
  1166. // Floating label position
  1167. @include notched-outline-mixins.floating-label-float-position-absolute(
  1168. $positionY,
  1169. $query: $query
  1170. );
  1171. // Floating label animation
  1172. @include floating-label-mixins.shake-animation(
  1173. $keyframe-suffix,
  1174. $query: $query
  1175. );
  1176. @at-root {
  1177. @include floating-label-mixins.shake-keyframes(
  1178. $keyframe-suffix,
  1179. $positionY,
  1180. $query: $query
  1181. );
  1182. }
  1183. @include feature-targeting.targets($feat-structure) {
  1184. @include theme.property(height, $new-height);
  1185. }
  1186. }
  1187. // TODO(b/283457421): Account for dynamic height
  1188. @if _is-less-than($new-height, $height) {
  1189. @include dropdown-icon-size(
  1190. select-icon-theme.$dense-icon-size,
  1191. $query: $query
  1192. );
  1193. &.mdc-select--outlined {
  1194. @include truncate-notched-outline-max-width(
  1195. $leading-icon-size: 0,
  1196. $dropdown-icon-size: select-icon-theme.$dense-icon-size,
  1197. $query: $query
  1198. );
  1199. }
  1200. }
  1201. }
  1202. ///
  1203. /// Sets height of outlined select with leading icon variant.
  1204. ///
  1205. /// @param {Number} $new-height
  1206. /// @param {String} $keyframe-suffix - Optional suffix to use for generated
  1207. /// floating label keyframes
  1208. ///
  1209. @mixin outlined-with-leading-icon-height(
  1210. $new-height,
  1211. $keyframe-suffix: null,
  1212. $query: feature-targeting.all()
  1213. ) {
  1214. $feat-structure: feature-targeting.create-target($query, structure);
  1215. .mdc-select__anchor {
  1216. // TODO(b/283457421): Account for dynamic height
  1217. @if _is-less-than($new-height, $height) {
  1218. @include dropdown-icon-size(
  1219. select-icon-theme.$dense-icon-size,
  1220. $query: $query
  1221. );
  1222. @include outlined-with-leading-icon-floating-label-position-animation(
  1223. $new-height,
  1224. select-icon-theme.$dense-icon-size,
  1225. $keyframe-suffix,
  1226. $query: $query
  1227. );
  1228. } @else {
  1229. @include outlined-with-leading-icon-floating-label-position-animation(
  1230. $new-height,
  1231. select-icon-theme.$icon-size,
  1232. $keyframe-suffix,
  1233. $query: $query
  1234. );
  1235. }
  1236. @include feature-targeting.targets($feat-structure) {
  1237. @include theme.property(height, $new-height);
  1238. }
  1239. }
  1240. // TODO(b/283457421): Account for dynamic height
  1241. @if _is-less-than($new-height, $height) {
  1242. .mdc-deprecated-list-item__graphic {
  1243. width: select-icon-theme.$dense-icon-size;
  1244. height: select-icon-theme.$dense-icon-size;
  1245. }
  1246. @include list-evolution-mixins.item-start-size(
  1247. $width: select-icon-theme.$dense-icon-size + 12px,
  1248. $height: select-icon-theme.$dense-icon-size,
  1249. $query: $query
  1250. );
  1251. @include select-icon-theme.size(
  1252. select-icon-theme.$dense-icon-size,
  1253. $query: $query
  1254. );
  1255. &.mdc-select--outlined {
  1256. @include truncate-notched-outline-max-width(
  1257. $leading-icon-size: select-icon-theme.$dense-icon-size,
  1258. $dropdown-icon-size: select-icon-theme.$dense-icon-size,
  1259. $query: $query
  1260. );
  1261. }
  1262. }
  1263. }
  1264. // $add-label-padding is copied from textfield's mixin, even though select
  1265. // always sets it to true. This is to try and keep things aligned between select
  1266. // and textfield for when these styles are refactored into shared styles.
  1267. @mixin _apply-outline-shape-padding(
  1268. $property,
  1269. $padding,
  1270. $add-label-padding: false,
  1271. $query: feature-targeting.all()
  1272. ) {
  1273. $feat-structure: feature-targeting.create-target($query, structure);
  1274. $padding-is-custom-prop: custom-properties.is-custom-prop($padding);
  1275. $padding-px: $padding;
  1276. @if ($padding-is-custom-prop) {
  1277. $padding-px: custom-properties.get-fallback($padding);
  1278. }
  1279. @include feature-targeting.targets($feat-structure) {
  1280. // The shape should only change the padding if the radius becomes greater
  1281. // than the default padding. That means we need to add more padding.
  1282. @if ($padding-px > notched-outline-variables.$leading-width) {
  1283. // Set a px value if it's greater. This is either the only value (if
  1284. // we're given an exact value), or an IE11 fallback if we're given a
  1285. // custom property and the fallback value is greater than the padding.
  1286. $value: $padding-px;
  1287. @if ($add-label-padding) {
  1288. // If this is for the top-left leading, add the notched outline padding
  1289. // to keep it aligned with the label
  1290. $value: $padding-px + notched-outline-variables.$padding;
  1291. }
  1292. @include rtl.ignore-next-line();
  1293. #{$property}: $value;
  1294. @include gss.annotate(
  1295. (
  1296. alternate: $padding-is-custom-prop,
  1297. )
  1298. );
  1299. }
  1300. @if ($padding-is-custom-prop) {
  1301. // If it's a custom property, always add it since the value may change
  1302. // to be greater than the padding at runtime, even if the fallback is
  1303. // not currently greater than the default padding.
  1304. $value: custom-properties.create-var($padding);
  1305. @if ($add-label-padding) {
  1306. $value: calc(#{$value} + #{notched-outline-variables.$padding});
  1307. }
  1308. // Interpolation is a workaround for sass/sass#3259.
  1309. @supports (top: max(#{0%})) {
  1310. // A max() function makes this runtime dynamic. The padding will be
  1311. // whichever is greater: the default horizontal padding, or the
  1312. // calculated custom property plus extra padding.
  1313. @include rtl.ignore-next-line();
  1314. #{$property}: max(#{$anchor-padding-left}, #{$value});
  1315. }
  1316. }
  1317. }
  1318. }
  1319. // Removes filled baseline alignment
  1320. @mixin center-aligned($query: feature-targeting.all()) {
  1321. $feat-structure: feature-targeting.create-target($query, structure);
  1322. .mdc-select__selected-text {
  1323. @include typography-mixins.zero-width-prefix($query: $query);
  1324. }
  1325. @include feature-targeting.targets($feat-structure) {
  1326. // In order for a flexbox container to participate in baseline alignment,
  1327. // it follows these rules to determine where its baseline is:
  1328. // https://www.w3.org/TR/css-flexbox-1/#flex-baselines
  1329. //
  1330. // In order to avoid leading icons "controlling" the baseline (since they
  1331. // are the first child), flexbox will generate a baseline from any child
  1332. // flex items that participate in baseline alignment.
  1333. //
  1334. // Icons are set to "align-self: center", while all other children are
  1335. // aligned to baseline. The next problem is deciding which child is
  1336. // used to determine the baseline.
  1337. //
  1338. // According to spec, the item with the largest distance between its
  1339. // baseline and the edge of the cross axis is placed flush with that edge,
  1340. // making it the baseline of the container.
  1341. // https://www.w3.org/TR/css-flexbox-1/#baseline-participation
  1342. //
  1343. // For the filled variant, the pseudo ::before strut is the "largest"
  1344. // child since the input has a height of 28px and the strut is 40px. We
  1345. // can emulate center alignment and force the baseline to use the input
  1346. // text by making the input the full height of the container and removing
  1347. // the baseline strut.
  1348. //
  1349. // IE11 does not respect this, and makes the leading icon (if present)
  1350. // the baseline.
  1351. .mdc-select__selected-text-container {
  1352. height: 100%;
  1353. display: inline-flex;
  1354. align-items: center;
  1355. }
  1356. &::before {
  1357. display: none;
  1358. }
  1359. }
  1360. }
  1361. ///
  1362. /// Sets the position of the floating label for a select with leading icon.
  1363. /// @param {number} $icon-size - The size of the leading icon.
  1364. ///
  1365. @mixin leading-icon-floating-label-position(
  1366. $icon-size: select-icon-theme.$icon-size,
  1367. $query: feature-targeting.all()
  1368. ) {
  1369. $feat-structure: feature-targeting.create-target($query, structure);
  1370. $icon-total-width: $icon-size + 2 * select-icon-theme.$icon-horizontal-margin;
  1371. .mdc-floating-label {
  1372. @include feature-targeting.targets($feat-structure) {
  1373. @include rtl.reflexive-position(left, $icon-total-width);
  1374. }
  1375. }
  1376. }
  1377. ///
  1378. /// Sets the floating label position and animations for a given height for an
  1379. /// outlined select with leaing icon.
  1380. /// @param {number} $icon-size - The size of the leading icon.
  1381. /// @param {string} $keyframe-suffix - The suffix for the newly generated keyframes.
  1382. ///
  1383. @mixin outlined-with-leading-icon-floating-label-position-animation(
  1384. $height,
  1385. $icon-size,
  1386. $keyframe-suffix: select-outlined-leading-icon-#{$height},
  1387. $query: feature-targeting.all()
  1388. ) {
  1389. $feat-structure: feature-targeting.create-target($query, structure);
  1390. $icon-total-width: $icon-size + 2 * select-icon-theme.$icon-horizontal-margin;
  1391. $resting-position-x: $icon-total-width -
  1392. select-icon-theme.$icon-horizontal-margin;
  1393. $float-position-y: get-outlined-label-position-y($height);
  1394. $float-position-x: $icon-size + select-icon-theme.$icon-horizontal-margin -
  1395. notched-outline-variables.$notch-gutter-size;
  1396. // Resting label position
  1397. .mdc-floating-label {
  1398. @include feature-targeting.targets($feat-structure) {
  1399. @include rtl.reflexive-position(left, $resting-position-x);
  1400. }
  1401. }
  1402. // Floating label position
  1403. @include notched-outline-mixins.floating-label-float-position-absolute(
  1404. $float-position-y,
  1405. $float-position-x,
  1406. $query: $query
  1407. );
  1408. // Floating label animation
  1409. @include floating-label-mixins.shake-animation(
  1410. $keyframe-suffix,
  1411. $query: $query
  1412. );
  1413. @at-root {
  1414. @include floating-label-mixins.shake-keyframes(
  1415. $keyframe-suffix,
  1416. $float-position-y,
  1417. $float-position-x,
  1418. $query: $query
  1419. );
  1420. }
  1421. $keyframe-suffix-rtl: #{$keyframe-suffix}-rtl;
  1422. @include rtl.rtl {
  1423. @include floating-label-mixins.shake-animation(
  1424. $keyframe-suffix,
  1425. $query: $query
  1426. );
  1427. }
  1428. @at-root {
  1429. @include floating-label-mixins.shake-keyframes(
  1430. $keyframe-suffix-rtl,
  1431. $float-position-y,
  1432. -($float-position-x),
  1433. $query: $query
  1434. );
  1435. }
  1436. }
  1437. ///
  1438. /// Truncates the max-width of the floating label according to sizes of the
  1439. /// leading icon and dropdown icon.
  1440. ///
  1441. /// @param {Number} $leading-icon-size - Size of leading icon.
  1442. /// @param {Number} $dropdown-icon-size - Size of dropdown icon.
  1443. ///
  1444. @mixin truncate-floating-label-max-width(
  1445. $leading-icon-size,
  1446. $dropdown-icon-size,
  1447. $query: feature-targeting.all()
  1448. ) {
  1449. $truncation: select-icon-theme.$icon-horizontal-margin * 2 +
  1450. $dropdown-icon-size;
  1451. @if $leading-icon-size > 0 {
  1452. $truncation: $truncation +
  1453. select-icon-theme.$icon-horizontal-margin *
  1454. 2 +
  1455. $leading-icon-size;
  1456. } @else {
  1457. $truncation: $truncation + $outline-label-offset;
  1458. }
  1459. .mdc-floating-label {
  1460. @include floating-label-mixins.max-width(
  1461. calc(100% - #{$truncation}),
  1462. $query: $query
  1463. );
  1464. }
  1465. .mdc-floating-label--float-above {
  1466. $scale: floating-label-variables.$float-scale;
  1467. @include floating-label-mixins.max-width(
  1468. calc(100% / #{$scale} - #{$truncation} / #{$scale}),
  1469. $query: $query
  1470. );
  1471. }
  1472. }
  1473. ///
  1474. /// Truncates the max-width of the notched outline according to the sizes of
  1475. /// the leading icon and dropdown icon.
  1476. ///
  1477. /// @param {Number} $leading-icon-size - Size of leading icon.
  1478. /// @param {Number} $dropdown-icon-size - Size of dropdown icon.
  1479. ///
  1480. @mixin truncate-notched-outline-max-width(
  1481. $leading-icon-size,
  1482. $dropdown-icon-size,
  1483. $query: feature-targeting.all()
  1484. ) {
  1485. $truncation: select-icon-theme.$icon-horizontal-margin * 2 +
  1486. $dropdown-icon-size + notched-outline-variables.$leading-width;
  1487. @if $leading-icon-size > 0 {
  1488. $truncation: $truncation +
  1489. select-icon-theme.$icon-horizontal-margin +
  1490. $leading-icon-size;
  1491. }
  1492. .mdc-select__anchor {
  1493. @include notched-outline-mixins.notch-max-width(
  1494. calc(100% - #{$truncation}),
  1495. $query: $query
  1496. );
  1497. }
  1498. }
  1499. /// Selector for focused state
  1500. /// @access private
  1501. @mixin _if-focused {
  1502. &.mdc-select--focused {
  1503. @content;
  1504. }
  1505. }
  1506. /// Selector for enabled state
  1507. /// @access private
  1508. @mixin _if-enabled {
  1509. &:not(.mdc-select--disabled) {
  1510. @content;
  1511. }
  1512. }
  1513. /// Selector for disabled state
  1514. /// @access private
  1515. @mixin _if-disabled {
  1516. &.mdc-select--disabled {
  1517. @content;
  1518. }
  1519. }
  1520. @mixin _ink-color($color, $query: feature-targeting.all()) {
  1521. $feat-color: feature-targeting.create-target($query, color);
  1522. @if $color {
  1523. .mdc-select__selected-text {
  1524. @include feature-targeting.targets($feat-color) {
  1525. @include theme.property(color, $color);
  1526. }
  1527. }
  1528. }
  1529. }
  1530. @mixin _container-fill-color($color, $query: feature-targeting.all()) {
  1531. $feat-color: feature-targeting.create-target($query, color);
  1532. @if $color {
  1533. .mdc-select__anchor {
  1534. @include feature-targeting.targets($feat-color) {
  1535. @include theme.property(background-color, $color);
  1536. }
  1537. }
  1538. }
  1539. }
  1540. @mixin _bottom-line-color($color, $query: feature-targeting.all()) {
  1541. @if $color {
  1542. .mdc-line-ripple {
  1543. @include line-ripple-mixins.inactive-color($color, $query: $query);
  1544. }
  1545. }
  1546. }
  1547. @mixin _focused-line-ripple-color($color, $query: feature-targeting.all()) {
  1548. @if $color {
  1549. .mdc-line-ripple {
  1550. @include line-ripple-mixins.active-color($color, $query: $query);
  1551. }
  1552. }
  1553. }
  1554. @mixin _outline-color($color, $query: feature-targeting.all()) {
  1555. @if $color {
  1556. @include notched-outline-mixins.color($color, $query: $query);
  1557. }
  1558. }
  1559. @mixin _hover-outline-color($color, $query: feature-targeting.all()) {
  1560. @if $color {
  1561. .mdc-notched-outline {
  1562. @include notched-outline-mixins.color($color, $query: $query);
  1563. }
  1564. }
  1565. }
  1566. @mixin _focused-outline-color($color, $query: feature-targeting.all()) {
  1567. @if $color {
  1568. .mdc-notched-outline {
  1569. @include notched-outline-mixins.color($color, $query: $query);
  1570. }
  1571. }
  1572. }
  1573. @mixin _label-color($color, $query: feature-targeting.all()) {
  1574. @if $color {
  1575. .mdc-floating-label {
  1576. @include floating-label-mixins.ink-color($color, $query: $query);
  1577. }
  1578. }
  1579. }
  1580. @mixin _label-floating-color($color, $query: feature-targeting.all()) {
  1581. @if $color {
  1582. .mdc-floating-label--float-above {
  1583. @include floating-label-mixins.ink-color($color, $query: $query);
  1584. }
  1585. }
  1586. }
  1587. ///
  1588. /// Sets the dropdown icon to the specified color.
  1589. /// @access private
  1590. ///
  1591. @mixin _dropdown-icon-color($color, $query: feature-targeting.all()) {
  1592. $feat-color: feature-targeting.create-target($query, color);
  1593. @if $color {
  1594. @include feature-targeting.targets($feat-color) {
  1595. .mdc-select__dropdown-icon {
  1596. @include theme.property(fill, $color);
  1597. }
  1598. }
  1599. }
  1600. }
  1601. ///
  1602. /// Compare the two inputs even if they're custom-prop objects.
  1603. /// @access private
  1604. ///
  1605. @function _is-less-than($subject, $object) {
  1606. $fallback-subject: if(
  1607. custom-properties.is-custom-prop($subject),
  1608. custom-properties.get-fallback($subject),
  1609. $subject
  1610. );
  1611. $fallback-object: if(
  1612. custom-properties.is-custom-prop($object),
  1613. custom-properties.get-fallback($object),
  1614. $object
  1615. );
  1616. @return $fallback-subject < $fallback-object;
  1617. }