Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Full-Screen size to Modal and Responsive variations for breakpoints #28683

Merged
merged 4 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 2 additions & 4 deletions js/src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`
const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`

const CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable'
const CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure'
const CLASS_NAME_BACKDROP = 'modal-backdrop'
const CLASS_NAME_OPEN = 'modal-open'
Expand Down Expand Up @@ -249,11 +248,10 @@ class Modal {
this._element.style.display = 'block'
this._element.removeAttribute('aria-hidden')
this._element.setAttribute('aria-modal', true)
this._element.scrollTop = 0

if (this._dialog.classList.contains(CLASS_NAME_SCROLLABLE) && modalBody) {
if (modalBody) {
modalBody.scrollTop = 0
} else {
this._element.scrollTop = 0
}

if (transition) {
Expand Down
16 changes: 8 additions & 8 deletions js/tests/unit/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,40 +382,40 @@ describe('Modal', () => {
modal.show()
})

it('should set modal body scroll top to 0 if .modal-dialog-scrollable', done => {
it('should set .modal\'s scroll top to 0', done => {
fixtureEl.innerHTML = [
'<div class="modal fade">',
' <div class="modal-dialog modal-dialog-scrollable">',
' <div class="modal-body"></div>',
' <div class="modal-dialog">',
' </div>',
'</div>'
].join('')

const modalEl = fixtureEl.querySelector('.modal')
const modalBody = modalEl.querySelector('.modal-body')
const modal = new Modal(modalEl)

modalEl.addEventListener('shown.bs.modal', () => {
expect(modalBody.scrollTop).toEqual(0)
expect(modalEl.scrollTop).toEqual(0)
done()
})

modal.show()
})

it('should set .modal\'s scroll top to 0 if .modal-dialog-scrollable and modal body do not exists', done => {
it('should set modal body scroll top to 0 if modal body do not exists', done => {
fixtureEl.innerHTML = [
'<div class="modal fade">',
' <div class="modal-dialog modal-dialog-scrollable">',
' <div class="modal-dialog">',
' <div class="modal-body"></div>',
' </div>',
'</div>'
].join('')

const modalEl = fixtureEl.querySelector('.modal')
const modalBody = modalEl.querySelector('.modal-body')
const modal = new Modal(modalEl)

modalEl.addEventListener('shown.bs.modal', () => {
expect(modalEl.scrollTop).toEqual(0)
expect(modalBody.scrollTop).toEqual(0)
done()
})

Expand Down
39 changes: 34 additions & 5 deletions scss/_modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@
overflow: hidden;
}

.modal-header,
.modal-footer {
flex-shrink: 0;
}

.modal-body {
overflow-y: auto;
}
Expand Down Expand Up @@ -115,6 +110,7 @@
// Top section of the modal w/ title and dismiss
.modal-header {
display: flex;
flex-shrink: 0;
align-items: flex-start; // so the close btn always stays on the upper right corner
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
padding: $modal-header-padding;
Expand Down Expand Up @@ -148,6 +144,7 @@
.modal-footer {
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
align-items: center; // vertically center
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
padding: $modal-inner-padding - $modal-footer-margin-between / 2;
Expand Down Expand Up @@ -204,3 +201,35 @@
@include media-breakpoint-up(xl) {
.modal-xl { max-width: $modal-xl; }
}

@each $breakpoint in map-keys($grid-breakpoints) {
$next-breakpoint: breakpoint-next($breakpoint);
$postfix: if(breakpoint-max($breakpoint, $grid-breakpoints) == null, "", "-#{$next-breakpoint}-down");

@include media-breakpoint-down($breakpoint) {
.modal-fullscreen#{$postfix} {
width: 100vw;
max-width: none;
height: 100%;
margin: 0;

.modal-content {
height: 100%;
GeoSot marked this conversation as resolved.
Show resolved Hide resolved
border: 0;
@include border-radius(0);
}

.modal-header {
@include border-radius(0);
}

.modal-body {
overflow-y: auto;
GeoSot marked this conversation as resolved.
Show resolved Hide resolved
}

.modal-footer {
@include border-radius(0);
}
}
}
}
162 changes: 162 additions & 0 deletions site/content/docs/4.3/components/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,168 @@ Our default modal without modifier class constitutes the "medium" size modal.
</div>
</div>

## Fullscreen Modal

Another override is the option to pop up a modal that covers the user viewport, available via modifier classes that are placed on a `.modal-dialog`.

<table class="table">
<thead>
<tr>
<th>Class</th>
<th>Availability</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>.modal-fullscreen</code></td>
<td>Always</td>
</tr>
<tr>
<td><code>.modal-fullscreen-sm-down</code></td>
<td><code>Below 576px</code></td>
</tr>
<tr>
<td><code>.modal-fullscreen-md-down</code></td>
<td><code>Below 768px</code></td>
</tr>
<tr>
<td><code>.modal-fullscreen-lg-down</code></td>
<td><code>Below 992px</code></td>
</tr>
<tr>
<td><code>.modal-fullscreen-xl-down</code></td>
<td><code>Below 1200px</code></td>
</tr>
</tbody>
</table>

<div class="bd-example">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalFullscreen">Full screen</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalFullscreenSm">Full screen below sm</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalFullscreenMd">Full screen below md</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalFullscreenLg">Full screen below lg</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalFullscreenXl">Full screen below xl</button>
</div>

{{< highlight html >}}
<!-- Full screen modal -->
<div class="modal-dialog modal-fullscreen-sm-down">
...
</div>
{{< /highlight >}}

<div class="modal fade" id="exampleModalFullscreen" tabindex="-1" role="dialog" aria-labelledby="exampleModalFullscreenLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h4" id="exampleModalFullscreenLabel">Full screen modal</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

<div class="modal fade" id="exampleModalFullscreenSm" tabindex="-1" role="dialog" aria-labelledby="exampleModalFullscreenSmLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-sm-down" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h4" id="exampleModalFullscreenSmLabel">Full screen below sm</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

<div class="modal fade" id="exampleModalFullscreenMd" tabindex="-1" role="dialog" aria-labelledby="exampleModalFullscreenMdLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-md-down" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h4" id="exampleModalFullscreenMdLabel">Full screen below md</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

<div class="modal fade" id="exampleModalFullscreenLg" tabindex="-1" role="dialog" aria-labelledby="exampleModalFullscreenLgLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-lg-down" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h4" id="exampleModalFullscreenLgLabel">Full screen below lg</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

<div class="modal fade" id="exampleModalFullscreenXl" tabindex="-1" role="dialog" aria-labelledby="exampleModalFullscreenXlLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-xl-down" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h4" id="exampleModalFullscreenXlLabel">Full screen below xl</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

## Usage

The modal plugin toggles your hidden content on demand, via data attributes or JavaScript. It also adds `.modal-open` to the `<body>` to override default scrolling behavior and generates a `.modal-backdrop` to provide a click area for dismissing shown modals when clicking outside the modal.
Expand Down