picocss/scss/components/_modal.scss
Yohn 6bc6d79caf Fixes header and footer in modal when form is direct child of the article, and if the form would be between the header and footer tags.
Modals with the size classes on the dialog were not sizing correctly when form was a child of the modal, and this has been corrected.
2025-01-18 19:31:23 -05:00

261 lines
5.9 KiB
SCSS

@use "sass:map";
@use "../settings" as *;
@if map.get($modules, "components/modal") {
/**
* Modal (<dialog>)
*/
:root,
:host {
#{$css-var-prefix}scrollbar-width: 0px;
}
#{$parent-selector} dialog:not(.modal-fs, .modal-xlg, .modal-lg, .modal-md, .modal-sm) {
> article:not(:has(> form:first-child)),
> article > form:first-child {
width: 100%;
@if map.get($breakpoints, "sm") {
@media (min-width: map.get(map.get($breakpoints, "sm"), "breakpoint")) {
max-width: map.get(map.get($breakpoints, "sm"), "viewport");
}
}
@if map.get($breakpoints, "md") {
@media (min-width: map.get(map.get($breakpoints, "md"), "breakpoint")) {
max-width: map.get(map.get($breakpoints, "md"), "viewport");
}
}
}
}
#{$parent-selector} dialog {
display: grid;
z-index: 999;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
align-items: center;
justify-content: center;
width: inherit;
min-width: 100%;
height: inherit;
min-height: 100%;
padding: var(#{$css-var-prefix}spacing);
border: 0;
backdrop-filter: var(#{$css-var-prefix}modal-overlay-backdrop-filter);
background-color: var(#{$css-var-prefix}modal-overlay-background-color);
color: var(#{$css-var-prefix}color);
@if $enable-transitions {
transform: scale(1);
transition: transform var(#{$css-var-prefix}transition);
}
// Content
> article:not(:has(> form:first-child)),
> article > form:first-child {
$close-selector: if(
$enable-classes,
".close, :is(a, button)[rel=prev]",
":is(a, button)[rel=prev]"
);
> header {
> * {
margin-bottom: 0;
}
#{$close-selector} {
margin: 0;
margin-left: var(#{$css-var-prefix}spacing);
padding: 0;
float: right;
}
}
> footer {
text-align: right;
button,
[role="button"] {
margin-bottom: 0;
&:not(:first-of-type) {
margin-left: calc(var(#{$css-var-prefix}spacing) * 0.5);
}
}
}
// Close icon
#{$close-selector} {
display: block;
width: 1rem;
height: 1rem;
margin-top: calc(var(#{$css-var-prefix}spacing) * -1);
margin-bottom: var(#{$css-var-prefix}spacing);
margin-left: auto;
border: none;
background-image: var(#{$css-var-prefix}icon-close);
background-position: center;
background-size: auto 1rem;
background-repeat: no-repeat;
background-color: transparent;
opacity: 0.5;
@if $enable-transitions {
transition: opacity var(#{$css-var-prefix}transition);
}
&:is([aria-current]:not([aria-current="false"]), :hover, :active, :focus) {
opacity: 1;
}
}
}
// Closed state
&:not([open]),
&[open="false"] {
visibility: hidden;
opacity: 0;
& article {
transform: scale(0.7);
}
}
}
// Utilities
@if $enable-classes {
.modal-is-open {
padding-right: var(#{$css-var-prefix}scrollbar-width, 0px);
overflow: hidden;
pointer-events: none;
touch-action: none;
dialog {
pointer-events: auto;
touch-action: auto;
}
}
dialog {
// Small modal
&.modal-sm {
> article {
width: 90vw;
max-width: 400px;
}
}
// Medium modal (default)
&.modal-md {
> article {
width: 90vw;
max-width: 600px;
}
}
// Large modal
&.modal-lg {
> article {
width: 90vw;
max-width: 800px;
}
}
// Extra large modal
&.modal-xlg {
> article {
width: 95vw;
max-width: 1000px;
}
}
// Fullscreen modal
&.modal-fs {
padding: 0;
> article {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100vw;
max-width: 100vw;
height: 100vh;
max-height: 100vh;
//border-radius: 0;
margin: 0;
//padding: var(--spacing);
overflow-y: auto;
> footer {
display: flex;
justify-content: flex-end;
margin-top: auto;
}
}
}
// Handle mobile responsiveness
@media (max-width: 576px) {
&:not(.modal-fs) {
> article {
width: 95vw;
}
}
}
}
}
// Prevent scrolling body when modal is open
body:has(dialog[open]) {
overflow: hidden;
}
// Animations
@if $enable-classes and $enable-transitions {
$animation-duration: 0.2s;
:where(.modal-is-opening, .modal-is-closing) {
dialog,
dialog > article {
animation-duration: $animation-duration;
animation-timing-function: ease-in-out;
animation-fill-mode: both;
}
dialog {
animation-duration: ($animation-duration * 4);
animation-name: modal-overlay;
> article {
animation-delay: $animation-duration;
animation-name: modal;
}
}
}
.modal-is-closing {
dialog,
dialog > article {
animation-delay: 0s;
animation-direction: reverse;
}
}
@keyframes modal-overlay {
from {
backdrop-filter: none;
background-color: transparent;
}
}
@keyframes modal {
from {
transform: translateY(-100%);
opacity: 0;
}
}
}
}