_mixins.scss 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. //
  2. // Copyright 2018 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. // stylelint-disable selector-class-pattern --
  23. // Selector '.mdc-*' should only be used in this project.
  24. // Internal styling for Dialog MDC component.
  25. @use 'sass:map';
  26. @use 'sass:math';
  27. @use '@material/animation/functions' as animation-functions;
  28. @use '@material/button/button-theme';
  29. @use '@material/dom/dom';
  30. @use '@material/elevation/mixins' as elevation-mixins;
  31. @use '@material/feature-targeting/feature-targeting';
  32. @use '@material/rtl/rtl';
  33. @use '@material/shape/mixins' as shape-mixins;
  34. @use '@material/theme/custom-properties';
  35. @use '@material/theme/theme';
  36. @use '@material/theme/theme-color';
  37. @use '@material/touch-target/variables' as touch-target-variables;
  38. @use '@material/typography/typography';
  39. @use './dialog-custom-properties';
  40. @use '@material/icon-button/icon-button-theme';
  41. @use './variables';
  42. @mixin static-styles($query: feature-targeting.all()) {
  43. $feat-animation: feature-targeting.create-target($query, animation);
  44. $feat-structure: feature-targeting.create-target($query, structure);
  45. // prettier-ignore
  46. @include elevation-mixins.overlay-common($query); // COPYBARA_COMMENT_THIS_LINE
  47. // postcss-bem-linter: define dialog
  48. .mdc-dialog,
  49. .mdc-dialog__scrim {
  50. @include feature-targeting.targets($feat-structure) {
  51. position: fixed;
  52. top: 0;
  53. left: 0;
  54. align-items: center;
  55. justify-content: center;
  56. box-sizing: border-box;
  57. width: 100%;
  58. height: 100%;
  59. }
  60. }
  61. .mdc-dialog {
  62. // Note: the top padding is only 20px for dialogs without titles; see below for override.
  63. @include content-padding(20px, 24px, 20px, 24px, $query: $query);
  64. @include min-width(variables.$min-width, $query: $query);
  65. @include max-width(variables.$max-width, variables.$margin, $query: $query);
  66. @include max-height(null, variables.$margin, $query: $query);
  67. @include feature-targeting.targets($feat-structure) {
  68. // Use `display: none` instead of `visibility: hidden` to avoid recalculating layout when the dialog is closed.
  69. display: none;
  70. $z-index: custom-properties.create(
  71. dialog-custom-properties.$z-index,
  72. variables.$z-index
  73. );
  74. @include theme.property(z-index, $z-index);
  75. }
  76. &.mdc-dialog--fullscreen {
  77. @include _fullscreen-dialog-size($query: $query);
  78. }
  79. &.mdc-dialog__scrim--hidden {
  80. .mdc-dialog__scrim {
  81. @include feature-targeting.targets($feat-structure) {
  82. opacity: 0;
  83. }
  84. }
  85. }
  86. }
  87. .mdc-dialog__scrim {
  88. @include feature-targeting.targets($feat-structure) {
  89. opacity: 0;
  90. z-index: -1;
  91. }
  92. }
  93. // This wrapper element is needed to make max-height work in IE 11.
  94. // See https://github.com/philipwalton/flexbugs/issues/216
  95. .mdc-dialog__container {
  96. @include feature-targeting.targets($feat-structure) {
  97. display: flex;
  98. flex-direction: row; // IE 11
  99. align-items: center;
  100. justify-content: space-around; // Ensure Safari centers the dialog (because it treats the container's width oddly)
  101. box-sizing: border-box;
  102. height: 100%;
  103. transform: scale(0.8);
  104. opacity: 0;
  105. // This element is necessary for IE 11 and needs to have `height: 100%`.
  106. // Let clicks on element fall through to scrim element underneath.
  107. pointer-events: none;
  108. }
  109. }
  110. .mdc-dialog__surface {
  111. @include elevation-mixins.overlay-surface-position($query: $query);
  112. @include elevation-mixins.overlay-dimensions(100%, $query: $query);
  113. @include feature-targeting.targets($feat-structure) {
  114. display: flex;
  115. flex-direction: column;
  116. flex-grow: 0; // IE 11
  117. flex-shrink: 0; // IE 11
  118. box-sizing: border-box;
  119. max-width: 100%; // IE 11
  120. max-height: 100%; // IE 11
  121. pointer-events: auto; // Override from `.mdc-dialog__container`.
  122. // IE 11: Otherwise, scrolling content in `mdc-dialog__content` overflows.
  123. overflow-y: auto;
  124. outline: 0;
  125. @include rtl.rtl {
  126. @include rtl.ignore-next-line();
  127. text-align: right;
  128. }
  129. @include dom.forced-colors-mode {
  130. // Colored outline is used for HCM instead of transparent border
  131. // below to prevent scrolling content overflow.
  132. outline: 2px solid windowText;
  133. }
  134. }
  135. &::before {
  136. @include dom.transparent-border($border-width: 2px, $query: $query);
  137. @include feature-targeting.targets($feat-structure) {
  138. // Prevent IE11 from rendering this element, because it causes scrolling
  139. // content to overflow.
  140. @media screen and (-ms-high-contrast: active),
  141. screen and (-ms-high-contrast: none) {
  142. content: none;
  143. }
  144. }
  145. }
  146. }
  147. .mdc-dialog__title {
  148. @include typography.text-baseline(
  149. $top: 40px,
  150. $display: block,
  151. $lineHeight: null,
  152. $query: $query
  153. );
  154. @include feature-targeting.targets($feat-structure) {
  155. position: relative;
  156. flex-shrink: 0;
  157. box-sizing: border-box;
  158. margin: 0 0 1px;
  159. padding: 0 24px variables.$title-bottom-padding;
  160. @include rtl.rtl {
  161. @include rtl.ignore-next-line();
  162. text-align: right;
  163. }
  164. }
  165. }
  166. .mdc-dialog--scrollable .mdc-dialog__title {
  167. @include feature-targeting.targets($feat-structure) {
  168. margin-bottom: 1px;
  169. // Adjust bottom padding to make title height align to spec when divider is present.
  170. // (Titles for alert dialogs w/o dividers align based on text baseline. All spec values are divisible by 4.)
  171. padding-bottom: variables.$title-bottom-padding + 6px;
  172. }
  173. }
  174. .mdc-dialog--fullscreen {
  175. .mdc-dialog__header {
  176. @include feature-targeting.targets($feat-structure) {
  177. align-items: baseline;
  178. border-bottom: 1px solid transparent;
  179. display: inline-flex;
  180. justify-content: space-between;
  181. padding: 0 variables.$header-side-padding
  182. variables.$title-bottom-padding;
  183. z-index: 1;
  184. @include dom.forced-colors-mode($exclude-ie11: true) {
  185. border-bottom-color: CanvasText;
  186. }
  187. @include _modal-header(
  188. $close-icon-padding: variables.$close-icon-padding
  189. );
  190. }
  191. }
  192. .mdc-dialog__title {
  193. @include feature-targeting.targets($feat-structure) {
  194. margin-bottom: 0;
  195. padding: 0;
  196. border-bottom: 0;
  197. }
  198. }
  199. &.mdc-dialog--scrollable .mdc-dialog__title {
  200. @include feature-targeting.targets($feat-structure) {
  201. border-bottom: 0;
  202. margin-bottom: 0;
  203. }
  204. }
  205. .mdc-dialog__close {
  206. @include feature-targeting.targets($feat-structure) {
  207. top: 5px;
  208. }
  209. }
  210. &.mdc-dialog--scrollable .mdc-dialog__actions {
  211. // If full-screen dialog is scrollable, the scroll divider over the action
  212. // buttons (i.e. the "footer") should only be visible when the content is
  213. // "cut off" by the footer. To toggle this divider, we override the
  214. // styling set by the mdc-dialog--scrollable class, and instead rely on
  215. // the mdc-dialog-scroll-divider-footer class to determine when the
  216. // border-top should be visible.
  217. @include feature-targeting.targets($feat-structure) {
  218. border-top: 1px solid transparent;
  219. @include dom.forced-colors-mode($exclude-ie11: true) {
  220. border-top-color: CanvasText;
  221. }
  222. }
  223. }
  224. }
  225. // Needed so that close affordance is aligned as if there was a title.
  226. .mdc-dialog--fullscreen--titleless {
  227. .mdc-dialog__close {
  228. @include feature-targeting.targets($feat-structure) {
  229. margin-top: 4px;
  230. }
  231. }
  232. &.mdc-dialog--scrollable .mdc-dialog__close {
  233. @include feature-targeting.targets($feat-structure) {
  234. margin-top: 0;
  235. }
  236. }
  237. }
  238. .mdc-dialog__content {
  239. @include feature-targeting.targets($feat-structure) {
  240. flex-grow: 1;
  241. box-sizing: border-box;
  242. margin: 0;
  243. overflow: auto;
  244. }
  245. // The content element already has top/bottom padding, so we need to suppress margins on its first/last children.
  246. > :first-child {
  247. @include feature-targeting.targets($feat-structure) {
  248. margin-top: 0;
  249. }
  250. }
  251. // The content element already has top/bottom padding, so we need to suppress margins on its first/last children.
  252. > :last-child {
  253. @include feature-targeting.targets($feat-structure) {
  254. margin-bottom: 0;
  255. }
  256. }
  257. }
  258. .mdc-dialog__title + .mdc-dialog__content,
  259. .mdc-dialog__header + .mdc-dialog__content {
  260. @include feature-targeting.targets($feat-structure) {
  261. // Eliminate padding to bring as close to spec as possible, relying on title padding.
  262. // (Spec seems inconsistent RE title/body spacing on alert vs. simple variants.)
  263. padding-top: 0;
  264. }
  265. }
  266. .mdc-dialog--scrollable .mdc-dialog__title + .mdc-dialog__content {
  267. @include feature-targeting.targets($feat-structure) {
  268. // Reduce and equalize vertical paddings when scrollable dividers are present
  269. // (Note: this is intentionally after title + content to take precedence)
  270. padding-top: 8px;
  271. padding-bottom: 8px;
  272. }
  273. }
  274. .mdc-dialog__content .mdc-deprecated-list:first-child:last-child {
  275. @include feature-targeting.targets($feat-structure) {
  276. // Override default .mdc-deprecated-list padding for content consisting exclusively of a MDC List
  277. padding: 6px 0 0; // Top padding balances with title height
  278. }
  279. }
  280. .mdc-dialog--scrollable
  281. .mdc-dialog__content
  282. .mdc-deprecated-list:first-child:last-child {
  283. @include feature-targeting.targets($feat-structure) {
  284. // Override default .mdc-deprecated-list padding for content consisting exclusively of a MDC List
  285. padding: 0;
  286. }
  287. }
  288. .mdc-dialog__actions {
  289. @include feature-targeting.targets($feat-structure) {
  290. display: flex;
  291. position: relative;
  292. flex-shrink: 0;
  293. flex-wrap: wrap;
  294. align-items: center;
  295. justify-content: flex-end;
  296. box-sizing: border-box;
  297. min-height: 52px;
  298. margin: 0;
  299. padding: variables.$actions-padding;
  300. border-top: 1px solid transparent;
  301. @include dom.forced-colors-mode($exclude-ie11: true) {
  302. border-top-color: CanvasText;
  303. }
  304. }
  305. .mdc-dialog--stacked & {
  306. @include feature-targeting.targets($feat-structure) {
  307. flex-direction: column;
  308. align-items: flex-end;
  309. }
  310. }
  311. }
  312. .mdc-dialog__button {
  313. @include feature-targeting.targets($feat-structure) {
  314. @include rtl.reflexive-box(margin, left, 8px);
  315. }
  316. &:first-child {
  317. @include feature-targeting.targets($feat-structure) {
  318. @include rtl.reflexive-box(margin, left, 0);
  319. }
  320. }
  321. @include feature-targeting.targets($feat-structure) {
  322. max-width: 100%; // Prevent long text from overflowing parent element in IE 11
  323. @include rtl.ignore-next-line();
  324. text-align: right;
  325. @include rtl.rtl {
  326. @include rtl.ignore-next-line();
  327. text-align: left;
  328. }
  329. }
  330. .mdc-dialog--stacked &:not(:first-child) {
  331. @include feature-targeting.targets($feat-structure) {
  332. margin-top: 12px;
  333. }
  334. }
  335. }
  336. .mdc-dialog--open,
  337. .mdc-dialog--opening,
  338. .mdc-dialog--closing {
  339. @include feature-targeting.targets($feat-structure) {
  340. display: flex;
  341. }
  342. }
  343. .mdc-dialog--opening {
  344. .mdc-dialog__scrim {
  345. @include feature-targeting.targets($feat-animation) {
  346. transition: opacity 150ms linear;
  347. }
  348. }
  349. .mdc-dialog__container {
  350. @include feature-targeting.targets($feat-animation) {
  351. transition: opacity 75ms linear,
  352. animation-functions.enter(transform, 150ms);
  353. }
  354. }
  355. }
  356. .mdc-dialog--closing {
  357. .mdc-dialog__scrim,
  358. .mdc-dialog__container {
  359. @include feature-targeting.targets($feat-animation) {
  360. transition: opacity 75ms linear;
  361. }
  362. }
  363. .mdc-dialog__container {
  364. @include feature-targeting.targets($feat-structure) {
  365. // Dialog container scales up while opening, but should remain scaled up while closing
  366. transform: none;
  367. }
  368. }
  369. }
  370. .mdc-dialog--open {
  371. .mdc-dialog__scrim {
  372. @include feature-targeting.targets($feat-structure) {
  373. opacity: 1;
  374. }
  375. }
  376. .mdc-dialog__container {
  377. @include feature-targeting.targets($feat-structure) {
  378. transform: none;
  379. opacity: 1;
  380. }
  381. }
  382. &.mdc-dialog__surface-scrim--shown {
  383. .mdc-dialog__surface-scrim {
  384. @include feature-targeting.targets($feat-structure) {
  385. opacity: 1;
  386. }
  387. }
  388. }
  389. &.mdc-dialog__surface-scrim--hiding {
  390. .mdc-dialog__surface-scrim {
  391. @include feature-targeting.targets($feat-animation) {
  392. transition: opacity 75ms linear;
  393. }
  394. }
  395. }
  396. &.mdc-dialog__surface-scrim--showing {
  397. .mdc-dialog__surface-scrim {
  398. @include feature-targeting.targets($feat-animation) {
  399. transition: opacity 150ms linear;
  400. }
  401. }
  402. }
  403. }
  404. .mdc-dialog__surface-scrim {
  405. @include feature-targeting.targets($feat-structure) {
  406. display: none;
  407. opacity: 0;
  408. position: absolute;
  409. width: 100%;
  410. height: 100%;
  411. z-index: 1;
  412. }
  413. .mdc-dialog__surface-scrim--shown &,
  414. .mdc-dialog__surface-scrim--showing &,
  415. .mdc-dialog__surface-scrim--hiding & {
  416. @include feature-targeting.targets($feat-structure) {
  417. display: block;
  418. }
  419. }
  420. }
  421. // postcss-bem-linter: end
  422. // Class applied to body while dialog is open, to prevent scrolling behind the dialog
  423. .mdc-dialog-scroll-lock {
  424. @include feature-targeting.targets($feat-structure) {
  425. overflow: hidden;
  426. }
  427. }
  428. .mdc-dialog--no-content-padding {
  429. .mdc-dialog__content {
  430. @include feature-targeting.targets($feat-structure) {
  431. padding: 0;
  432. }
  433. }
  434. }
  435. .mdc-dialog--sheet {
  436. .mdc-dialog__container .mdc-dialog__close {
  437. @include feature-targeting.targets($feat-structure) {
  438. right: variables.$sheet-close-icon-right;
  439. top: variables.$sheet-close-icon-top;
  440. position: absolute;
  441. // Customers can create their stacking context in dialog content using
  442. // any way of createing stacking context. For example with
  443. // position: relative;
  444. // z-index: 0;
  445. z-index: 1;
  446. }
  447. }
  448. }
  449. .mdc-dialog__scrim--removed {
  450. @include feature-targeting.targets($feat-structure) {
  451. pointer-events: none;
  452. }
  453. .mdc-dialog__scrim,
  454. .mdc-dialog__surface-scrim {
  455. @include feature-targeting.targets($feat-structure) {
  456. display: none;
  457. }
  458. }
  459. }
  460. }
  461. @mixin core-styles($query: feature-targeting.all()) {
  462. $feat-structure: feature-targeting.create-target($query, structure);
  463. .mdc-dialog {
  464. @include container-fill-color(surface, $query: $query);
  465. @include scrim-color(variables.$scrim-color, $query: $query);
  466. @include title-ink-color(variables.$title-ink-color, $query: $query);
  467. @include content-ink-color(variables.$content-ink-color, $query: $query);
  468. @include scroll-divider-color(
  469. variables.$scroll-divider-color,
  470. $query: $query
  471. );
  472. @include shape-radius(variables.$shape-radius, $query: $query);
  473. }
  474. .mdc-dialog__surface {
  475. @include elevation-mixins.elevation(24, $query: $query);
  476. }
  477. .mdc-dialog__title {
  478. @include typography.typography(headline6, $query: $query);
  479. }
  480. .mdc-dialog__content {
  481. @include typography.typography(body1, $query: $query);
  482. }
  483. // For go/soy-checks/rewrite-css
  484. .mdc-dialog__title-icon {
  485. @include feature-targeting.targets($feat-structure) {
  486. /** Hook for theming API. */
  487. }
  488. }
  489. @include static-styles($query: $query);
  490. }
  491. @mixin container-fill-color($color, $query: feature-targeting.all()) {
  492. $feat-color: feature-targeting.create-target($query, color);
  493. .mdc-dialog__surface {
  494. @include feature-targeting.targets($feat-color) {
  495. @include theme.property(background-color, $color);
  496. }
  497. }
  498. }
  499. @mixin scrim-color(
  500. $color,
  501. $opacity: variables.$scrim-opacity,
  502. $query: feature-targeting.all()
  503. ) {
  504. $feat-color: feature-targeting.create-target($query, color);
  505. .mdc-dialog__scrim {
  506. @include feature-targeting.targets($feat-color) {
  507. background-color: rgba(theme-color.prop-value($color), $opacity);
  508. }
  509. }
  510. .mdc-dialog__surface-scrim {
  511. @include feature-targeting.targets($feat-color) {
  512. background-color: rgba(theme-color.prop-value($color), $opacity);
  513. }
  514. }
  515. }
  516. @mixin title-ink-color(
  517. $color,
  518. $opacity: variables.$title-ink-opacity,
  519. $query: feature-targeting.all()
  520. ) {
  521. $feat-color: feature-targeting.create-target($query, color);
  522. .mdc-dialog__title {
  523. @include feature-targeting.targets($feat-color) {
  524. color: rgba(theme-color.prop-value($color), $opacity);
  525. }
  526. }
  527. }
  528. @mixin content-ink-color(
  529. $color,
  530. $opacity: variables.$content-ink-opacity,
  531. $query: feature-targeting.all()
  532. ) {
  533. $feat-color: feature-targeting.create-target($query, color);
  534. .mdc-dialog__content {
  535. @include feature-targeting.targets($feat-color) {
  536. color: rgba(theme-color.prop-value($color), $opacity);
  537. }
  538. }
  539. .mdc-dialog__close {
  540. @include icon-button-theme.ink_color($color: $color, $query: $query);
  541. }
  542. }
  543. /// Defines the `display` property of the content element using a given query.
  544. /// This is useful if the content of the dialog needs to use a custom layout,
  545. /// for example one that consists of a fixed header and a fixed footer, with a
  546. /// scrollable list area in-between, which is sized to fill available space
  547. /// (see b/231813016).
  548. /// @param {string} $display - The `display` type to set.
  549. /// @param {string} $query Query.
  550. @mixin content-display($display, $query: feature-targeting.all()) {
  551. $feat-structure: feature-targeting.create-target($query, structure);
  552. .mdc-dialog__content {
  553. @include feature-targeting.targets($feat-structure) {
  554. display: $display;
  555. }
  556. }
  557. }
  558. @mixin content-padding(
  559. $padding-top,
  560. $padding-right,
  561. $padding-bottom,
  562. $padding-left,
  563. $query: feature-targeting.all()
  564. ) {
  565. $feat-structure: feature-targeting.create-target($query, structure);
  566. .mdc-dialog__content {
  567. @include feature-targeting.targets($feat-structure) {
  568. padding: $padding-top $padding-right $padding-bottom $padding-left;
  569. }
  570. }
  571. }
  572. @mixin scroll-divider-color(
  573. $color,
  574. $opacity: variables.$scroll-divider-opacity,
  575. $query: feature-targeting.all()
  576. ) {
  577. $feat-color: feature-targeting.create-target($query, color);
  578. &.mdc-dialog--scrollable .mdc-dialog__title,
  579. &.mdc-dialog--scrollable .mdc-dialog__actions,
  580. &.mdc-dialog--scrollable.mdc-dialog-scroll-divider-footer
  581. .mdc-dialog__actions {
  582. @include feature-targeting.targets($feat-color) {
  583. border-color: rgba(theme-color.prop-value($color), $opacity);
  584. }
  585. }
  586. &.mdc-dialog--scrollable .mdc-dialog__title {
  587. @include feature-targeting.targets($feat-color) {
  588. border-bottom: 1px solid rgba(theme-color.prop-value($color), $opacity);
  589. margin-bottom: 0;
  590. }
  591. }
  592. &.mdc-dialog-scroll-divider-header.mdc-dialog--fullscreen
  593. .mdc-dialog__header {
  594. @include elevation-mixins.elevation(2, $query: $query);
  595. }
  596. }
  597. @mixin shape-radius(
  598. $radius,
  599. $rtl-reflexive: false,
  600. $query: feature-targeting.all()
  601. ) {
  602. $feat-structure: feature-targeting.create-target($query, structure);
  603. .mdc-dialog__surface {
  604. @include shape-mixins.radius($radius, $rtl-reflexive, $query: $query);
  605. }
  606. }
  607. @mixin min-width($min-width, $query: feature-targeting.all()) {
  608. $feat-structure: feature-targeting.create-target($query, structure);
  609. .mdc-dialog__surface {
  610. @include feature-targeting.targets($feat-structure) {
  611. min-width: $min-width;
  612. }
  613. }
  614. }
  615. @mixin min-height($min-height, $query: feature-targeting.all()) {
  616. $feat-structure: feature-targeting.create-target($query, structure);
  617. .mdc-dialog__surface {
  618. @include feature-targeting.targets($feat-structure) {
  619. min-height: $min-height;
  620. }
  621. }
  622. }
  623. @mixin max-width-with-breakpoint(
  624. $above-breakpoint-max-width,
  625. $below-breakpoint-max-width,
  626. $max-width-breakpoint,
  627. $query: feature-targeting.all()
  628. ) {
  629. $feat-structure: feature-targeting.create-target($query, structure);
  630. .mdc-dialog__surface {
  631. @include feature-targeting.targets($feat-structure) {
  632. @media (max-width: $max-width-breakpoint) {
  633. max-width: $below-breakpoint-max-width;
  634. }
  635. @media (min-width: $max-width-breakpoint) {
  636. max-width: $above-breakpoint-max-width;
  637. }
  638. }
  639. }
  640. }
  641. @mixin max-width($max-width, $margin, $query: feature-targeting.all()) {
  642. $feat-structure: feature-targeting.create-target($query, structure);
  643. $max-width-breakpoint: $max-width + ($margin * 2);
  644. // Fit snugly within the viewport at smaller screen sizes.
  645. $below-breakpoint-max-width: calc(100vw - #{$margin * 2});
  646. @if $max-width {
  647. @include max-width-with-breakpoint(
  648. $max-width,
  649. $below-breakpoint-max-width,
  650. $max-width-breakpoint,
  651. $query
  652. );
  653. } @else {
  654. .mdc-dialog__surface {
  655. @include feature-targeting.targets($feat-structure) {
  656. max-width: $below-breakpoint-max-width;
  657. }
  658. }
  659. }
  660. }
  661. @mixin max-height($max-height, $margin, $query: feature-targeting.all()) {
  662. $feat-structure: feature-targeting.create-target($query, structure);
  663. $max-size-calc-expr: calc(100% - #{$margin * 2});
  664. .mdc-dialog__surface {
  665. @include feature-targeting.targets($feat-structure) {
  666. @if $max-height {
  667. $max-height-breakpoint: $max-height + ($margin * 2);
  668. // Fit snugly within the viewport at smaller screen sizes.
  669. @media (max-height: $max-height-breakpoint) {
  670. max-height: $max-size-calc-expr;
  671. }
  672. // Once the screen gets big enough, apply a fixed maximum height.
  673. @media (min-height: $max-height-breakpoint) {
  674. max-height: $max-height;
  675. }
  676. } @else {
  677. max-height: $max-size-calc-expr;
  678. }
  679. }
  680. }
  681. // Target IE 11.
  682. @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
  683. // On IE 11, if surface height is fixed and container height is 100%,
  684. // scrolling content overflows. So, reset height if surface height
  685. // is fixed.
  686. .mdc-dialog__container {
  687. @include feature-targeting.targets($feat-structure) {
  688. @if $max-height {
  689. $max-height-breakpoint: $max-height + ($margin * 2);
  690. @media (min-height: $max-height-breakpoint) {
  691. align-items: stretch;
  692. height: auto;
  693. }
  694. }
  695. }
  696. }
  697. }
  698. }
  699. // Applied to dialogs that have buttons with an increased touch target.
  700. @mixin with-touch-target($query: feature-targeting.all()) {
  701. $feat-structure: feature-targeting.create-target($query, structure);
  702. $touch-target-margin: math.div(
  703. touch-target-variables.$height - button-theme.$height,
  704. 2
  705. );
  706. $vertical-padding: math.max(
  707. 0,
  708. variables.$actions-padding - $touch-target-margin
  709. );
  710. // Buttons with an increased touch target have added vertical margin, so
  711. // decrease the actions element padding to compensate.
  712. .mdc-dialog__actions {
  713. @include feature-targeting.targets($feat-structure) {
  714. padding-top: $vertical-padding;
  715. padding-bottom: $vertical-padding;
  716. // The below styles override the default button touch target values,
  717. // which otherwise cause `mdc-dialog__surface` to scroll unnnecessarily
  718. // in IE 11.
  719. .mdc-button__touch {
  720. top: -$touch-target-margin; // IE 11
  721. transform: none; // IE 11
  722. }
  723. }
  724. }
  725. }
  726. /// Defines dialog position on the screen.
  727. /// Dialog position can be customised across both vertical and horizontal axis.
  728. /// If only one axis is specified dialog is centered across the second one.
  729. /// Only one value can be specified for each axis at the time. For example
  730. /// dialog can not have both $top and $bottom specified because it will conflict
  731. /// with size related mixins. Use `min-width`, `max-width` and `max-height`
  732. /// to control the dialog size.
  733. /// @param {Map} $position-map - Dialog position specified as map with keys
  734. /// {top, bottom, left, right}
  735. @mixin position($position-map, $query: feature-targeting.all()) {
  736. $feat-structure: feature-targeting.create-target($query, structure);
  737. $top: map.get($position-map, top);
  738. $right: map.get($position-map, right);
  739. $bottom: map.get($position-map, bottom);
  740. $left: map.get($position-map, left);
  741. @if ($top != null and $bottom != null) {
  742. @error "Top and Botton properties can not be used simultaneously. Use " +
  743. "`min-width`, `max-width` and `max-height` to control dialog size.";
  744. }
  745. @if ($right != null and $left != null) {
  746. @error "Right and Left properties can not be used simultaneously. Use " +
  747. "`min-width`, `max-width` and `max-height` to control dialog size.";
  748. }
  749. @include feature-targeting.targets($feat-structure) {
  750. @if ($top != null) {
  751. .mdc-dialog__container {
  752. align-items: flex-start;
  753. padding-top: $top;
  754. }
  755. }
  756. @if ($bottom != null) {
  757. .mdc-dialog__container {
  758. align-items: flex-end;
  759. padding-bottom: $bottom;
  760. }
  761. }
  762. @if ($right != null) {
  763. &.mdc-dialog {
  764. justify-content: flex-end;
  765. padding-right: $right;
  766. }
  767. }
  768. @if ($left != null) {
  769. &.mdc-dialog {
  770. justify-content: flex-start;
  771. padding-left: $left;
  772. }
  773. }
  774. }
  775. }
  776. /// Defines dialog base z-index.
  777. /// This mixin can be used to specify dialog base z-index to make it compatible
  778. /// with other frameworks used on the same page.
  779. /// @param {Number} $z-index - Dialog z-index value.
  780. @mixin z-index($z-index, $query: feature-targeting.all()) {
  781. $feat-structure: feature-targeting.create-target($query, structure);
  782. @include feature-targeting.targets($feat-structure) {
  783. &.mdc-dialog {
  784. z-index: $z-index;
  785. }
  786. }
  787. }
  788. /// This mixin can be used to hide the fullscreen dialog header when the dialog
  789. /// is a standard modal and not yet fullscreen in X-small sizes.
  790. @mixin fullscreen-dialog-hide-modal-header($query: feature-targeting.all()) {
  791. $feat-structure: feature-targeting.create-target($query, structure);
  792. // Non-fullscreen-dialog sizes
  793. @media (min-width: 600px) {
  794. &.mdc-dialog--fullscreen {
  795. .mdc-dialog__header {
  796. @include feature-targeting.targets($feat-structure) {
  797. display: none;
  798. }
  799. }
  800. .mdc-dialog__content {
  801. @include feature-targeting.targets($feat-structure) {
  802. padding-top: 24px;
  803. }
  804. }
  805. }
  806. }
  807. }
  808. @mixin _fullscreen-dialog-size($query: feature-targeting.all()) {
  809. $feat-structure: feature-targeting.create-target($query, structure);
  810. .mdc-dialog__surface {
  811. @include feature-targeting.targets($feat-structure) {
  812. // Reset the max-width so the default dialog sizing doesn't interfere with
  813. // the full-screen dialog sizing.
  814. max-width: none;
  815. }
  816. // Medium screens
  817. @media (max-width: 960px) {
  818. @include feature-targeting.targets($feat-structure) {
  819. max-height: 560px;
  820. width: 560px;
  821. @include _modal-header(
  822. $close-icon-padding: variables.$close-icon-padding
  823. );
  824. }
  825. }
  826. // Small screens
  827. @media (max-width: 720px) {
  828. @include feature-targeting.targets($feat-structure) {
  829. $max-small-height: 560px;
  830. $max-small-width: 560px;
  831. $min-horizontal-small-margin: 56px;
  832. $min-vertical-small-margin: 80px;
  833. @include _fluid-size-calc(
  834. $vertical-margin: $min-vertical-small-margin,
  835. $max-height: $max-small-height,
  836. $horizontal-margin: $min-horizontal-small-margin,
  837. $max-width: $max-small-width
  838. );
  839. @include _modal-header(
  840. $close-icon-padding: variables.$close-icon-padding
  841. );
  842. }
  843. }
  844. // X-Small Screens
  845. @media (max-width: 720px) and (max-height: 400px),
  846. (max-width: 600px),
  847. (min-width: 720px) and (max-height: 400px) {
  848. @include feature-targeting.targets($feat-structure) {
  849. // Use 100% instead of vw/vh so the url bar is taken into account on
  850. // mobile.
  851. height: 100%;
  852. max-height: 100vh;
  853. max-width: 100vw;
  854. width: 100vw;
  855. @include _fullscreen-header(
  856. $close-icon-padding: variables.$close-icon-padding,
  857. $title-side-padding: variables.$title-side-padding
  858. );
  859. }
  860. @include shape-mixins.radius(0, $query: $query);
  861. }
  862. // Large to X-Large screens
  863. @media (min-width: 960px) {
  864. @include feature-targeting.targets($feat-structure) {
  865. $min-horizontal-margin: 200px;
  866. width: calc(100vw - #{$min-horizontal-margin * 2});
  867. @include _modal-header(
  868. $close-icon-padding: variables.$close-icon-padding
  869. );
  870. }
  871. }
  872. }
  873. }
  874. /// Defines styling to specify a fluid dialog size while maintaining a specific
  875. /// vertical and horizontal margin.
  876. /// @param {Number} $vertical-margin
  877. /// @param {Number} $max-height
  878. /// @param {Number} $horizontal-margin
  879. /// @param {Number} $max-width
  880. @mixin _fluid-size-calc(
  881. $vertical-margin,
  882. $max-height,
  883. $horizontal-margin,
  884. $max-width
  885. ) {
  886. $max-width-calc-expr: calc(100vw - #{$horizontal-margin * 2});
  887. $max-width-breakpoint: $max-width + ($horizontal-margin * 2);
  888. @media (max-width: $max-width-breakpoint) {
  889. width: $max-width-calc-expr;
  890. }
  891. @media (min-width: $max-width-breakpoint) {
  892. width: $max-width;
  893. }
  894. $max-height-calc-expr: calc(100vh - #{$vertical-margin * 2});
  895. $max-height-breakpoint: $max-height + ($vertical-margin * 2);
  896. @media (max-height: $max-height-breakpoint) {
  897. max-height: $max-height-calc-expr;
  898. }
  899. @media (min-height: $max-height-breakpoint) {
  900. max-height: $max-height;
  901. }
  902. }
  903. /// Defines styles for the header bar when a dialog takes up the full screen.
  904. /// @param {Number} $close-icon-padding - Padding on close icon button.
  905. /// @param {Number} $title-side-padding - Space between the edge of the close
  906. /// icon button and edge of the title.
  907. @mixin _fullscreen-header($close-icon-padding, $title-side-padding) {
  908. .mdc-dialog__close {
  909. order: -1;
  910. @include theme.property(left, -#{$close-icon-padding});
  911. }
  912. .mdc-dialog__header {
  913. padding: 0 variables.$fullscreen-header-side-padding
  914. variables.$title-bottom-padding;
  915. justify-content: flex-start;
  916. }
  917. .mdc-dialog__title {
  918. @include theme.property(
  919. margin-left,
  920. 'calc(title - 2 * close)',
  921. $replace: (title: $title-side-padding, close: $close-icon-padding)
  922. );
  923. }
  924. }
  925. /// Defines styles for the header bar when a dialog is modal.
  926. /// @param {Number} $close-icon-padding - Padding on close icon button.
  927. @mixin _modal-header($close-icon-padding) {
  928. .mdc-dialog__close {
  929. @include theme.property(right, -#{$close-icon-padding});
  930. }
  931. }