Skip to content

Commit 8d504de

Browse files
authored
feat(modal): add full size modifier (#5175)
1 parent b58fefc commit 8d504de

File tree

3 files changed

+106
-114
lines changed

3 files changed

+106
-114
lines changed

ui/components/modals/RELEASENOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
<!-- ## [Unreleased] -->
66

7+
## 2.22.0
8+
### Changed
9+
- Optimized full size option and refactored to use CSS grid.
10+
711
## 2.21.0
812
### Fixed
913
- Fixed `aria-labelledby` to meet accessibility requirements specifically for screen readers.

ui/components/modals/base/_index.scss

Lines changed: 100 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -284,129 +284,123 @@
284284
}
285285
}
286286

287+
/**
288+
* @summary Makes the modal full screen in small viewports
289+
* @name full
290+
* @selector .slds-modal_full
291+
* @restrict .slds-modal
292+
* @modifier
293+
* @group size
294+
*/
287295
.slds-modal_full {
288296

289-
.slds-modal__header {
290-
border-top-left-radius: 0;
291-
border-top-right-radius: 0;
292-
293-
@include mq-medium-min {
294-
border-top-right-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
295-
border-top-left-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
296-
}
297-
}
298-
/**
299-
* Headless modal styling
300-
*/
301-
.slds-modal__content_headless,
302-
.slds-modal__header_empty + .slds-modal__content {
303-
@include mq-medium-min {
304-
border-top-right-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
305-
border-top-left-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
306-
}
307-
}
308-
297+
// Behaves like large size when not in a small viewport
309298
.slds-modal__container {
310-
width: 100%;
299+
width: 90%;
311300
max-width: none;
312-
min-width: 0;
313-
margin: 0;
314-
padding: $spacing-medium 0 0 0;
315-
justify-content: flex-start;
316-
background-color: var(--slds-c-modal-header-color-background, var(--slds-c-modal-color-background, var(--slds-g-color-neutral-base-100, #{$color-background-alt})));
317-
border-radius: 0;
318-
319-
@include mq-medium-min {
320-
width: 90%;
321-
max-width: none;
322-
min-width: 40rem; // TODO: Tokenize
323-
justify-content: center;
324-
border-radius: $border-radius-medium;
325-
margin: 0 auto;
326-
padding: $square-icon-large-boundary 0 $square-icon-large-boundary-alt 0;
327-
background: transparent;
328-
}
301+
min-width: 40rem;
329302
}
330303

331-
/**
332-
* Footless modal styling
333-
*/
334-
.slds-modal__content_footless,
335-
.slds-modal__container > .slds-modal__content:last-child,
336-
.slds-modal__content_has-hidden-footer {
337-
border-bottom-right-radius: unset;
338-
border-bottom-left-radius: unset;
339-
box-shadow: unset;
340-
341-
@include mq-medium-min {
342-
border-bottom-right-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
343-
border-bottom-left-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
344-
box-shadow: var(--slds-c-modal-shadow, var(--sds-c-modal-shadow, $shadow-drop-down));
304+
// We use mq-medium-max since modal was originally designed as desktop first;
305+
// This saves us from having to duplicate code for the full modifier.
306+
@include mq-medium-max {
307+
// Account for iOS safe areas so our modal doesn't load underneath iOS elements.
308+
top: env(safe-area-inset-top, 0);
309+
// Override slds-modal's bottom: 0 so we can make the height dynamic.
310+
bottom: auto;
311+
// Viewport may be dynamic, e.g., iOS Safari toolbar hiding behavior, so we use dvh. Safe areas may not be required here.
312+
height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
313+
314+
.slds-modal__header {
315+
grid-area: header;
316+
border-top-left-radius: 0;
317+
border-top-right-radius: 0;
345318
}
346-
}
347319

348-
/* Close button style for modal size="full" in mobile */
349-
.slds-modal_full-close-button {
350-
border: none;
320+
.slds-modal__container {
321+
width: 100%;
322+
max-width: none;
323+
min-width: 0;
324+
margin: 0;
325+
padding: $spacing-medium 0 0 0;
326+
// Only __content used to get background color, we want entire modal to get it since we're fullscreen
327+
background-color: var(--slds-c-modal-header-color-background, var(--slds-c-modal-color-background, var(--slds-g-color-neutral-base-100, #{$color-background-alt})));
328+
border-radius: 0;
329+
/* Establishes the main layout of the modal. Grid is defined by grid-template-areas
330+
which explicitly defines the grid and allows optional elements to be omitted like
331+
the header or footer. */
332+
display: grid;
333+
height: 100dvh;
334+
grid-template-rows: min-content min-content 1fr min-content;
335+
grid-template-areas:
336+
"close"
337+
"header"
338+
"content"
339+
"footer";
340+
}
351341

352-
@include mq-medium-min {
353-
/* Revert back to non-mobile sizing style.
354-
All variants' closing button should look the same once out of mobile sizing. */
355-
background-color: transparent;
356-
}
357-
}
342+
/**
343+
* Footless modal styling
344+
*/
345+
.slds-modal__content_footless,
346+
.slds-modal__container > .slds-modal__content:last-child,
347+
.slds-modal__content_has-hidden-footer {
348+
border-bottom-right-radius: 0;
349+
border-bottom-left-radius: 0;
350+
box-shadow: none;
351+
}
358352

359-
.slds-modal__close {
360-
right: $spacing-medium;
353+
.slds-modal__close {
354+
grid-area: close;
355+
right: $spacing-medium;
356+
357+
// A few things going on here:
358+
// - We want to avoid a markup change for a single modifier so we reassign/override.
359+
// - Button icon doesn't have component level hooks (yet), so we don't include them here
360+
// and we have to override the CSS property instead of reassign.
361+
// - States on button have a bug, they override instead of reassign hooks
362+
// so the values of empty hooks default to initial values. In the case
363+
// of background colors, the background will disappear (initial = transparent).
364+
--slds-c-button-color-background: var(--slds-g-color-neutral-base-100, #{$button-color-background-primary});
365+
--slds-c-button-color-background-active: var(--slds-g-color-neutral-base-100, #{$button-color-background-primary});
366+
color: var(--slds-g-color-neutral-base-50, #{$color-text-icon-default});
367+
}
361368

362-
@include mq-medium-min {
363-
right: ($spacing-x-small * -1);
364-
color: var(--slds-g-color-neutral-base-100, #{$color-text-link-inverse});
365-
366-
&[disabled],
367-
&:disabled {
368-
background-color: transparent;
369-
border-color: var(--slds-g-color-neutral-100-opacity-10, #{$color-border-button-inverse-disabled});
370-
}
371-
372-
&:hover,
373-
&:focus {
374-
color: var(--slds-g-color-neutral-100-opacity-75, #{$color-text-link-inverse-hover});
375-
}
376-
377-
&:focus {
378-
@include focus-inverse;
379-
}
380-
381-
&:active {
382-
color: var(--slds-g-color-neutral-100-opacity-50, #{$color-text-link-inverse-active});
383-
}
384-
385-
&[disabled],
386-
&:disabled {
387-
color: var(--slds-g-color-neutral-100-opacity-10, #{$color-text-link-inverse-disabled});
388-
}
369+
.slds-modal__close:hover,
370+
.slds-modal__:focus {
371+
color: $brand-accessible-active;
389372
}
390-
}
391373

392-
.slds-modal__footer {
393-
border-bottom-right-radius: unset;
394-
border-bottom-left-radius: unset;
395-
box-shadow: unset;
374+
.slds-modal__content {
375+
grid-area: content;
376+
}
396377

397-
@include mq-medium-min {
398-
border-bottom-right-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
399-
border-bottom-left-radius: var(--slds-c-modal-radius-border, var(--sds-c-modal-radius-border, $border-radius-medium));
400-
box-shadow: var(--slds-c-modal-shadow, var(--sds-c-modal-shadow, $shadow-drop-down));
378+
.slds-modal__footer {
379+
grid-area: footer;
380+
border-bottom-right-radius: 0;
381+
border-bottom-left-radius: 0;
382+
box-shadow: none;
401383
}
402384
}
403-
}
404-
405-
.slds-modal_full-content {
406-
flex: 1;
407385

408-
@include mq-medium-min {
409-
flex: unset;
386+
/**
387+
* INTERNAL USE ONLY - SUBJECT TO CHANGE AND REMOVAL
388+
*
389+
* SLDS Blueprint <> LBC Parity Patch
390+
*
391+
* SLDS blueprints and LBC implementation are not 1:1. This patch is needed to
392+
* account for the differences introduced in the LBC implementation. Location
393+
* of this code would ideally live within the LBC component CSS module but
394+
* synthetic shadow and how LBC deconstructs the modal into individual components
395+
* makes this not feasible. Not ideal, but this is the best solution for now.
396+
* Selectors are scoped to lightning-* to avoid any potential outside conflicts.
397+
*/
398+
lightning-button-icon + div,
399+
lightning-modal,
400+
lightning-modal-header,
401+
lightning-modal-body,
402+
lightning-modal-footer {
403+
display: contents;
410404
}
411405
}
412406

ui/components/modals/base/example.jsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,7 @@ export let Modal = (props) => (
5858
{
5959
props.closeButton !== false ? (
6060
<ButtonIcon
61-
className={classNames('slds-modal__close',
62-
{'slds-button_icon-inverse': !props.isFullSize,
63-
'slds-button_icon-border-filled slds-modal_full-close-button': props.isFullSize }
64-
)}
61+
className="slds-modal__close slds-button_icon-inverse"
6562
iconClassName="slds-button__icon_large"
6663
symbol="close"
6764
assistiveText="Cancel and close"
@@ -195,10 +192,7 @@ export let ModalSizes = (props) => (
195192
Modal header
196193
</h1>
197194
</ModalHeader>
198-
<ModalContent className={classNames(
199-
props.size === 'full' && 'slds-modal_full-content slds-p-around_medium'
200-
)}
201-
>
195+
<ModalContent className='slds-p-around_medium'>
202196
<PlaceholderParagraphs />
203197
<br />
204198
<PlaceholderParagraphs />

0 commit comments

Comments
 (0)