UNPKG

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