1
1
mirror of https://github.com/primer/css.git synced 2024-12-23 06:01:54 +03:00

OverlayBase ongoing stylesheets

This commit is contained in:
Vinicius Depizzol 2022-06-28 21:49:56 -07:00
parent 0cca3c1e33
commit 74a4d200c3
4 changed files with 522 additions and 729 deletions

View File

@ -1,620 +0,0 @@
import clsx from 'clsx'
import React from 'react'
import ConditionalWrapper from '../../helpers/ConditionalWrapper'
import {PatternFullBleed} from '../ActionList/ActionListFeatures.stories.jsx'
const variant = {}
export default {
title: 'UI Patterns/Overlay',
parameters: {
layout: 'padded'
},
excludeStories: ['OverlayTemplate'],
argTypes: {
// Header
title: {
name: 'title',
type: {name: 'string', required: true},
description: 'The heading element of the overlay',
defaultValue: 'Title',
table: {
category: 'Header'
}
},
description: {
name: 'description',
type: 'string',
description: 'The sub-heading element of the overlay',
defaultValue: '',
table: {
category: 'Header'
}
},
headerVariant: {
options: ['medium', 'large', 'custom'],
defaultValue: 'medium',
control: {
type: 'inline-radio',
},
description: 'medium title (default), large title, or custom header',
table: {
category: 'Header'
}
},
toggleOverlay: {
control: {type: 'boolean'},
description: 'show/hide overlay',
defaultValue: false,
table: {
category: 'Demo'
}
},
showCloseButton: {
control: {type: 'boolean'},
description: 'show/hide close button',
defaultValue: false,
table: {
category: 'Demo'
}
},
showFooterButton: {
control: {type: 'boolean'},
description: 'show/hide footer button',
defaultValue: false,
table: {
category: 'Demo'
}
},
// Properties
width: {
options: ['auto', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge'],
control: {
type: 'inline-radio',
},
description: 'Width options: xsmall: 192px, small: 256px, medium: 320px, large: 480px, xlarge: 640px, xxlarge: 960px',
table: {
category: 'Properties'
}
},
height: {
options: ['auto', 'xsmall', 'small', 'medium', 'large', 'xlarge'],
control: {
type: 'inline-radio',
},
description: 'Height options: auto: adjusts to content, xsmall: 192px, small: 256px, medium: 320px, large: 432px, xlarge: 600px',
table: {
category: 'Properties'
}
},
bodyPaddingVariant: {
options: [0, 1, 2], // iterator
mapping: ['', 'Overlay-body--paddingCondensed', 'Overlay-body--paddingNone'], // values
control: {
type: 'inline-radio',
labels: ['normal (default)', 'condensed', 'none']
},
description: 'body spacing',
table: {
category: 'CSS'
}
},
// Variant
variant: {
options: ['center', 'anchor', 'side', 'full'],
type: {
name: 'select',
required: true,
},
description: '',
table: {
category: 'Variant'
}
},
variantWhenNarrow: {
options: ['inherit', 'center', 'anchor', 'side', 'full'],
defaultValue: 'inherit',
type: {
name: 'select',
required: false,
},
description: '',
table: {
category: 'Variant'
}
},
placementNarrow: {
options: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
mapping: [
'Overlay-backdrop--placement-top-whenNarrow',
'',
'',
'',
'Overlay-backdrop--placement-bottom-whenNarrow',
'',
'',
'',
'Overlay-backdrop--placement-right-whenNarrow',
'',
'',
'',
'Overlay-backdrop--placement-left-whenNarrow',
'',
'',
'',
''
],
control: {
type: 'inline-radio',
labels: [
'top',
'top-start',
'top-center',
'top-end',
'bottom',
'bottom-start',
'bottom-center',
'bottom-end',
'right',
'right-start',
'right-center',
'right-end',
'left',
'left-start',
'left-center',
'left-end',
'reset'
]
},
description: 'Positions overlay for narrow viewport range',
table: {
category: 'Placement'
}
},
placementRegular: {
options: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
mapping: [
'Overlay-backdrop--placement-top',
'',
'',
'',
'Overlay-backdrop--placement-bottom',
'',
'',
'',
'Overlay-backdrop--placement-right',
'',
'',
'',
'Overlay-backdrop--placement-left',
'',
'',
'',
''
],
control: {
type: 'inline-radio',
labels: [
'top',
'top-start',
'top-center',
'top-end',
'bottom',
'bottom-start',
'bottom-center',
'bottom-end',
'right',
'right-start',
'right-center',
'right-end',
'left',
'left-start',
'left-center',
'left-end',
'reset'
]
},
description: 'Positions overlay for regular viewport range',
table: {
category: 'Placement'
}
},
hasHeader: {
control: {type: 'boolean'},
description:
'A header region may be used to provide context to the user by displaying a title, description, and offering an easy-to-escape route with a Close button. Headers may also provide ways for the user to interact with the content, such as with search and tabs.',
defaultValue: true,
table: {
category: 'Header'
}
},
hasFooter: {
control: {type: 'boolean'},
description:
'The footer region may be used to show confirmation actions, navigation links, or other important elements that should appear outside of the content scrolling region.',
defaultValue: true,
table: {
category: 'Footer'
}
},
showFooterDivider: {
control: {type: 'boolean'},
defaultValue: false,
description: 'Show dividers above footer',
table: {
category: 'CSS'
}
},
showHeaderDivider: {
control: {type: 'boolean'},
defaultValue: false,
description: 'Show dividers below header',
table: {
category: 'Header'
}
},
headerSlot: {
description: 'Slot for custom header content. Only shown if header variant is set to `custom`.',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
subHeaderSlot: {
description: 'Slot for sub header content, present below the header and before the body.',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
actionContentSlot: {
description: 'Slot for additional header action',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
motion: {
options: ['auto', 'none', 'scaleFade', 'slide', 'slideFade'],
control: {
type: 'inline-radio',
},
description: 'Animation options for show/hide overlay',
table: {
category: 'Properties'
}
},
footerContentAlign: {
options: [0, 1, 2], // iterator
mapping: ['Overlay-footer--alignStart', 'Overlay-footer--alignCenter', 'Overlay-footer--alignEnd'], // values
control: {
type: 'inline-radio',
labels: ['start', 'center', 'end']
},
description: 'Align footer contents',
table: {
category: 'Footer'
}
},
role: {
description: 'Semantic role',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
ariaLabelledy: {
description: 'aria-labelledby',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
ariaDescribedby: {
description: 'aria-describedby',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
dataFocusTrap: {
description: 'data-focus-trap',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
titleId: {
description: 'title id',
control: {type: 'string'},
table: {
category: 'HTML'
}
},
descriptionId: {
description: 'description id',
control: {type: 'string'},
table: {
category: 'HTML'
}
}
}
}
const focusMethod = function getFocus() {
const dialog = document.getElementById('overlay-backdrop')[0]
dialog.focus()
}
const toggleDialog = () => {
const dialog = document.getElementById('overlay-backdrop')
dialog.classList.toggle('Overlay--hidden')
focusMethod()
}
export const OverlayTemplate = ({
title,
description,
toggleOverlay,
variantWhenNarrow,
variant,
width,
height,
showFooterDivider,
showHeaderDivider,
hasHeader,
hasFooter,
headerSlot,
subHeaderSlot,
motion,
footerContentAlign,
showCloseButton,
showFooterButton,
actionContentSlot,
headerVariant,
bodyPaddingVariant,
role,
ariaLabelledby,
ariaDescribedby,
dataFocusTrap,
bodySlot,
titleId,
descriptionId,
placementNarrow,
placementRegular
}) => {
// Default values
width = width ?? 'auto';
height = height ?? 'auto';
motion = motion ?? 'auto';
variant = variant ?? 'center';
variantWhenNarrow = variantWhenNarrow ?? 'inherit';
headerVariant = headerVariant ?? 'medium';
// Inherit values
variantWhenNarrow = variantWhenNarrow === 'inherit' ? variant : variantWhenNarrow;
// Leave `null` values for states that don't require a modifier class
headerVariant = headerVariant === 'medium' ? null : headerVariant;
return (
<>
<button class="btn" onClick={toggleDialog}>
<span>Open overlay</span>
</button>
<div
id="overlay-backdrop"
className={clsx(
toggleOverlay && 'Overlay--hidden',
variant && `Overlay-backdrop--${variant}`,
variantWhenNarrow && `Overlay-backdrop--${variantWhenNarrow}-whenNarrow`,
placementRegular && `${placementRegular}`,
placementNarrow && `${placementNarrow}`,
)}
>
<div
className={clsx(
'Overlay',
width && `Overlay--width-${width}`,
height && `Overlay--height-${height}`,
motion && `Overlay--motion-${motion}`,
)}
data-focus-trap={dataFocusTrap}
role={role}
aria-labelledby={ariaLabelledby}
aria-describedby={ariaDescribedby}
open
>
{hasHeader && (
<header
className={clsx(
'Overlay-header',
showHeaderDivider && 'Overlay-header--divided',
headerVariant && `Overlay-header--${headerVariant}`
)}
aria-role="none"
>
<div className="Overlay-headerContentWrap">
<div className="Overlay-titleWrap">
{title && (
<h1 id={titleId} className="Overlay-title">
{title}
</h1>
)}
{description && (
<h2 id={descriptionId} className="Overlay-description">
{description}
</h2>
)}
{headerVariant == 'custom' && headerSlot && (
<div className="Overlay-customHeader">
{headerSlot}
</div>
)}
</div>
{showCloseButton && (
<div className="Overlay-actionWrap">
{actionContentSlot && <div dangerouslySetInnerHTML={{__html: actionContentSlot}} />}
<button className="Overlay-closeButton" aria-label="Close" onClick={toggleDialog}>
<svg aria-hidden="true" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
<path
fill-rule="evenodd"
d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"
></path>
</svg>
</button>
</div>
)}
</div>
{subHeaderSlot && (
<div className="Overlay-subHeader">
{subHeaderSlot}
</div>
)}
</header>
)}
<div className={clsx('Overlay-body', bodyPaddingVariant && `${bodyPaddingVariant}`)}>{bodySlot}</div>
{hasFooter && (
<footer
className={clsx(
'Overlay-footer',
showFooterDivider && 'Overlay-footer--divided',
footerContentAlign && `${footerContentAlign}`
)}
>
{showFooterButton && (
<button class="btn" onClick={toggleDialog}>
<span>Continue</span>
</button>
)}
</footer>
)}
</div>
</div>
</>
);
};
export const Playground = OverlayTemplate.bind();
Playground.storyName = 'Playground';
Playground.args = {
title: 'This is the title of the dialog',
description: 'This is the subtitle of the dialog',
motion: 1,
footerContentAlign: 2,
showCloseButton: true,
showFooterButton: false,
headerSlot: '',
actionContentSlot: '',
headerVariant: 'medium',
bodyPaddingVariant: 0,
width: 'small',
height: 'small',
hasHeader: true,
hasFooter: true,
showFooterDivider: false,
showHeaderDivider: false,
role: '',
ariaDescribedby: '',
dataFocusTrap: '',
bodySlot: (
<>
<p>This is the body of the dialog</p>
</>
)
};
export const Dialog = OverlayTemplate.bind();
Dialog.storyName = 'Dialog';
Dialog.args = {
variant: 'center',
// Header
hasHeader: true,
title: 'Dialog title',
description: 'This is the subtitle of the dialog',
// Properties
width: 'medium',
height: 'small',
motion: 'auto',
footerContentAlign: 2,
showCloseButton: true,
showFooterButton: false,
headerSlot: '',
actionContentSlot: '',
headerVariant: 'large',
bodyPaddingVariant: 0,
hasFooter: false,
showFooterDivider: false,
showHeaderDivider: false,
role: '',
ariaDescribedby: '',
dataFocusTrap: '',
bodySlot: (
<>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
</>
)
};
export const CustomHeader = OverlayTemplate.bind();
CustomHeader.storyName = 'Custom header';
CustomHeader.args = {
variant: 'center',
// Header
hasHeader: true,
title: 'Dialog title',
description: 'This is the subtitle of the dialog',
// Properties
width: 'medium',
height: 'small',
motion: 'auto',
// Header
headerVariant: 'custom',
headerSlot: (
<><div style={{background: 'pink', height: '32px', width: '100%'}}>Custom header</div></>
),
subHeaderSlot: (
<>UnderlineNav</>
),
footerContentAlign: 2,
showCloseButton: true,
showFooterButton: false,
actionContentSlot: '',
bodyPaddingVariant: 0,
hasFooter: false,
showFooterDivider: false,
showHeaderDivider: false,
role: '',
ariaDescribedby: '',
dataFocusTrap: '',
bodySlot: (
<>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
<div>Lorem ipsum dolor sit amet.</div>
</>
)
};

View File

@ -0,0 +1,275 @@
import clsx from 'clsx'
import React from 'react'
import ConditionalWrapper from '../../helpers/ConditionalWrapper'
import {PatternFullBleed} from '../ActionList/ActionListFeatures.stories.jsx'
export default {
title: 'UI Patterns/Overlay base',
parameters: {
layout: 'padded'
},
excludeStories: ['OverlayBaseTemplate'],
argTypes: {
// # backdrop
// # - visible
// # - transparent
// # - none
// # motion
// # - auto
// # - none
// # placement
// # - viewport
// # - top, left, right, bottom, full, center
// # - anchored
// # - [directions]
// # open/dismiss behavior
// # - open: boolean
// # - API client-side:
// # - open
// # - dismiss
// # sizing
// # - width: auto, xsmall, small, medium, large, xlarge, xxlarge
// # - height: auto, xsmall, small, medium, large, xlarge
// backdrop
backdrop: {
options: ['visible', 'transparent', 'none'],
control: {
type: 'inline-radio',
}
},
placement: {
// Todo: fix placement options
options: ['top', 'left', 'right', 'bottom', 'full', 'center', 'anchor'],
control: {
type: 'inline-radio',
}
},
motion: {
options: ['auto', 'none'],
control: {
type: 'inline-radio',
}
},
width: {
options: ['auto', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge'],
control: {
type: 'select',
}
},
height: {
options: ['auto', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xlarge'],
control: {
type: 'select',
}
},
open: {
control: {
type: 'boolean',
}
},
// content
contentSlot: {
description: 'Slot for the overlay contents.',
control: {type: 'string'},
}
}
}
const focusOverlay = function getFocus() {
const overlay = document.querySelector('.Overlay');
overlay.focus()
}
const toggleOverlay = () => {
const overlay = document.querySelector('.Overlay');
overlay.classList.toggle('Overlay--open');
focusOverlay();
}
export const OverlayBaseTemplate = ({
placement,
backdrop,
motion,
width,
height,
open,
contentSlot
}) => {
// Default values
backdrop = backdrop ?? 'visible';
placement = placement ?? 'center';
width = width ?? 'auto';
height = height ?? 'auto';
motion = motion ?? 'auto';
// Inherit values
// variantWhenNarrow = variantWhenNarrow === 'inherit' ? variant : variantWhenNarrow;
// Leave `null` values for states that don't require a modifier class
// headerVariant = headerVariant === 'medium' ? null : headerVariant;
return (
<>
<button class="btn" onClick={toggleOverlay}>
<span>Open overlay</span>
</button>
<div
className={clsx(
'Overlay',
open && 'Overlay--open',
placement && `Overlay--${placement}`,
)}
>
<div
className={clsx(
'Overlay-wrapper',
)}
// data-focus-trap={dataFocusTrap}
// role={role}
// aria-labelledby={ariaLabelledby}
// aria-describedby={ariaDescribedby}
// open
>
<div className={clsx(
'Overlay-content',
width && `Overlay-content--width-${width}`,
height && `Overlay-content--height-${height}`,
motion && `Overlay-content--motion-${motion}`,
)}>
{contentSlot}
</div>
</div>
{backdrop !== 'none' && (
<div className={clsx(
'Overlay-backdrop',
backdrop && `Overlay-backdrop--${backdrop}`,
)}></div>
)}
</div>
</>
);
};
export const Playground = OverlayBaseTemplate.bind();
Playground.storyName = 'Playground';
Playground.args = {
placement: 'viewport-top',
width: 'small',
height: 'small',
open: true,
// title: 'This is the title of the dialog',
// description: 'This is the subtitle of the dialog',
// motion: 1,
// footerContentAlign: 2,
// showCloseButton: true,
// showFooterButton: false,
// headerSlot: '',
// actionContentSlot: '',
// headerVariant: 'medium',
// bodyPaddingVariant: 0,
// hasHeader: true,
// hasFooter: true,
// showFooterDivider: false,
// showHeaderDivider: false,
// role: '',
// ariaDescribedby: '',
// dataFocusTrap: '',
contentSlot: (
<>
<p>This is the body of the dialog</p>
</>
)
};
// export const Dialog = OverlayBaseTemplate.bind();
// Dialog.storyName = 'Dialog';
// Dialog.args = {
// /*
// variant: 'center',
// // Header
// hasHeader: true,
// title: 'Dialog title',
// description: 'This is the subtitle of the dialog',
// // Properties
// width: 'medium',
// height: 'small',
// motion: 'auto',
// footerContentAlign: 2,
// showCloseButton: true,
// showFooterButton: false,
// headerSlot: '',
// actionContentSlot: '',
// headerVariant: 'large',
// bodyPaddingVariant: 0,
// hasFooter: false,
// showFooterDivider: false,
// showHeaderDivider: false,
// role: '',
// ariaDescribedby: '',
// dataFocusTrap: '',
// */
// contentSlot: (
// <>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// </>
// )
// };
// export const CustomHeader = OverlayBaseTemplate.bind();
// CustomHeader.storyName = 'Custom header';
// CustomHeader.args = {
// variant: 'center',
// // Header
// hasHeader: true,
// title: 'Dialog title',
// description: 'This is the subtitle of the dialog',
// // Properties
// width: 'medium',
// height: 'small',
// motion: 'auto',
// // Header
// headerVariant: 'custom',
// headerSlot: (
// <><div style={{background: 'pink', height: '32px', width: '100%'}}>Custom header</div></>
// ),
// subHeaderSlot: (
// <>UnderlineNav</>
// ),
// footerContentAlign: 2,
// showCloseButton: true,
// showFooterButton: false,
// actionContentSlot: '',
// bodyPaddingVariant: 0,
// hasFooter: false,
// showFooterDivider: false,
// showHeaderDivider: false,
// role: '',
// ariaDescribedby: '',
// dataFocusTrap: '',
// bodySlot: (
// <>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// <div>Lorem ipsum dolor sit amet.</div>
// </>
// )
// };

View File

@ -1,2 +1,2 @@
@import '../support/index.scss'; @import '../support/index.scss';
@import './overlay.scss'; @import './overlay-base.scss';

View File

@ -23,40 +23,171 @@ $Overlay-height: (
xlarge: 600px xlarge: 600px
) !default; ) !default;
// Helpers
@mixin Overlay--fullViewportHeight() {
height: 100vh;
height: -webkit-fill-available;
max-height: 100vh;
@supports(height: 100dvh) {
height: 100dvh;
max-height: 100dvh;
}
}
// Overlay structure // Overlay structure
// ================= // =================
// //
// .Overlay-backdrop // .Overlay
// .Overlay // .Overlay-wrapper
// .Overlay-header // .Overlay-content
// .Overlay-headerContentWrap // .Overlay-backdrop
// .Overlay-titleWrap
// .Overlay-title
// .Overlay-description
// .Overlay-actionWrap
// .Overlay-closeButton
// .Overlay-body
// .Overlay-footer
//
// Todo:
// - Overlay-form?
// - Deprecate Overlay-closeButton in favor of redesigned iconButton
// Visibility
// Todo: these are applied to `Overlay-backdrop`, not to `Overlay`
.Overlay--hidden {
display: none !important;
}
.Overlay--visibilityHidden {
height: 0;
overflow: hidden;
visibility: hidden;
opacity: 0;
}
.Overlay { .Overlay {
isolation: isolate;
position: absolute;
visibility: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
@include Overlay--fullViewportHeight;
}
.Overlay--open {
visibility: visible;
display: flex;
}
// Overlay-wrapper
.Overlay-wrapper {
display: flex;
position: relative;
z-index: 2;
}
.Overlay--anchor {
// Todo: anchored position
outline: 10px solid pink;
}
.Overlay--center {
align-items: center;
justify-content: center;
}
.Overlay--full {
.Overlay-wrapper {
width: 100%;
}
.Overlay-content {
flex-grow: 1;
border-radius: unset;
width: 100%;
max-width: 100vw;
@include Overlay--fullViewportHeight;
}
}
.Overlay--top {
align-items: start;
justify-content: center;
.Overlay-content {
@media (prefers-reduced-motion: no-preference) {
animation: $primer-duration-slow $primer-easing-out Overlay--motion-slideInDown;
}
border-radius: $primer-borderRadius-large;
border-top-right-radius: 0;
border-top-left-radius: 0;
}
}
.Overlay--left {
align-items: center;
justify-content: left;
.Overlay-content {
border-radius: $primer-borderRadius-large;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
@include Overlay--fullViewportHeight;
@media (prefers-reduced-motion: no-preference) {
animation: $primer-duration-slow $primer-easing-out Overlay--motion-slideInRight;
}
}
}
.Overlay--bottom {
align-items: end;
justify-content: center;
.Overlay-content {
border-radius: $primer-borderRadius-large;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
@media (prefers-reduced-motion: no-preference) {
animation: $primer-duration-slow $primer-easing-out Overlay--motion-slideInUp;
}
}
}
.Overlay--right {
align-items: center;
justify-content: right;
.Overlay-content {
border-radius: $primer-borderRadius-large;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
@include Overlay--fullViewportHeight;
@media (prefers-reduced-motion: no-preference) {
animation: $primer-duration-slow $primer-easing-out Overlay--motion-slideInLeft;
}
}
}
// Overlay-backdrop
.Overlay-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1;
background-color: var(--color-neutral-muted);
@include Overlay--fullViewportHeight;
}
.Overlay-backdrop--transparent {
background-color: transparent;
}
// .Overlay--hidden {
// display: none !important;
// }
// Question: what's visibilityHidden used for?
// .Overlay--visibilityHidden {
// height: 0;
// overflow: hidden;
// visibility: hidden;
// opacity: 0;
// }
// Overlay-content
.Overlay-content {
position: relative; position: relative;
display: flex; display: flex;
min-width: #{map-get($Overlay-width, 'xsmall')}; min-width: #{map-get($Overlay-width, 'xsmall')};
@ -70,88 +201,95 @@ $Overlay-height: (
@supports (height: 100dvh) { @supports (height: 100dvh) {
max-height: 100dvh; max-height: 100dvh;
} }
// Dimensions
// Todo: auto-generate based on Scss variables?
&.Overlay--height-auto {
height: auto;
}
&.Overlay--height-xsmall {
height: min(#{map-get($Overlay-height, 'xsmall')}, 100vh - 2rem);
}
&.Overlay--height-small {
height: min(#{map-get($Overlay-height, 'small')}, 100vh - 2rem);
}
&.Overlay--height-medium {
height: min(#{map-get($Overlay-height, 'medium')}, 100vh - 2rem);
}
&.Overlay--height-large {
height: min(#{map-get($Overlay-height, 'large')}, 100vh - 2rem);
}
&.Overlay--height-xlarge {
height: min(#{map-get($Overlay-height, 'xlarge')}, 100vh - 2rem);
}
&.Overlay--width-auto {
width: auto;
}
&.Overlay--width-xsmall {
width: min(#{map-get($Overlay-width, 'xsmall')}, 100vw - 2rem);
}
&.Overlay--width-small {
width: min(#{map-get($Overlay-width, 'small')}, 100vw - 2rem);
}
&.Overlay--width-medium {
width: min(#{map-get($Overlay-width, 'medium')}, 100vw - 2rem);
}
&.Overlay--width-large {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'large')}, 100vw - 2rem);
}
&.Overlay--width-xlarge {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'xlarge')}, 100vw - 2rem);
}
&.Overlay--width-xxlarge {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'xxlarge')}, 100vw - 2rem);
}
// Motion
&.Overlay--motion-scaleFade {
@media (prefers-reduced-motion: no-preference) {
// Todo: replace with primer-duration-slow token
animation: $primer-duration-slow $primer-easing-out Overlay--motion-scaleFade;
}
}
// &.Overlay--motion-slide {
// @media (prefers-reduced-motion: no-preference) {
// animation: $primer-duration-slow $primer-easing-out Overlay--motion-slide;
// }
// }
} }
// Dimensions
.Overlay-content--height-auto {
height: auto;
}
.Overlay-content--height-xsmall {
height: min(#{map-get($Overlay-height, 'xsmall')}, 100vh - 2rem);
}
.Overlay-content--height-small {
height: min(#{map-get($Overlay-height, 'small')}, 100vh - 2rem);
}
.Overlay-content--height-medium {
height: min(#{map-get($Overlay-height, 'medium')}, 100vh - 2rem);
}
.Overlay-content--height-large {
height: min(#{map-get($Overlay-height, 'large')}, 100vh - 2rem);
}
.Overlay-content--height-xlarge {
height: min(#{map-get($Overlay-height, 'xlarge')}, 100vh - 2rem);
}
.Overlay-content--width-auto {
width: auto;
}
.Overlay-content--width-xsmall {
width: min(#{map-get($Overlay-width, 'xsmall')}, 100vw - 2rem);
}
.Overlay-content--width-small {
width: min(#{map-get($Overlay-width, 'small')}, 100vw - 2rem);
}
.Overlay-content--width-medium {
width: min(#{map-get($Overlay-width, 'medium')}, 100vw - 2rem);
}
.Overlay-content--width-large {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'large')}, 100vw - 2rem);
}
.Overlay-content--width-xlarge {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'xlarge')}, 100vw - 2rem);
}
.Overlay-content--width-xxlarge {
// stylelint-disable-next-line primer/responsive-widths
width: min(#{map-get($Overlay-width, 'xxlarge')}, 100vw - 2rem);
}
// Motion
.Overlay--motion-auto {
// Todo: Apply animation to Overlay-wrapper?
@media (prefers-reduced-motion: no-preference) {
// Todo: replace with primer-duration-slow token
animation: $primer-duration-slow $primer-easing-out Overlay--motion-scaleFade;
}
}
.Overlay--motion-none {
animation: none;
}
// &.Overlay--motion-slide {
// @media (prefers-reduced-motion: no-preference) {
// animation: $primer-duration-slow $primer-easing-out Overlay--motion-slide;
// }
// }
// for <form> element that wraps entire contents of overlay // for <form> element that wraps entire contents of overlay
.Overlay-form { // .Overlay-form {
display: flex; // display: flex;
overflow: auto; // overflow: auto;
flex-direction: column; // flex-direction: column;
flex-grow: 1; // flex-grow: 1;
} // }
// Move overlay header to specialized dialog component?
.Overlay-header { .Overlay-header {
z-index: 1; z-index: 1;