|
284 | 284 | }
|
285 | 285 | }
|
286 | 286 |
|
| 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 | + */ |
287 | 295 | .slds-modal_full {
|
288 | 296 |
|
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 |
309 | 298 | .slds-modal__container {
|
310 |
| - width: 100%; |
| 299 | + width: 90%; |
311 | 300 | 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; |
329 | 302 | }
|
330 | 303 |
|
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; |
345 | 318 | }
|
346 |
| - } |
347 | 319 |
|
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 | + } |
351 | 341 |
|
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 | + } |
358 | 352 |
|
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 | + } |
361 | 368 |
|
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; |
389 | 372 | }
|
390 |
| - } |
391 | 373 |
|
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 | + } |
396 | 377 |
|
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; |
401 | 383 | }
|
402 | 384 | }
|
403 |
| -} |
404 |
| - |
405 |
| -.slds-modal_full-content { |
406 |
| - flex: 1; |
407 | 385 |
|
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; |
410 | 404 | }
|
411 | 405 | }
|
412 | 406 |
|
|
0 commit comments