Added animation when modal backdrop is static (#29516)

This commit is contained in:
Higor Araújo dos Anjos 2019-10-25 15:12:09 -03:00 committed by XhmikosR
parent 9ee9b8a1e8
commit 46912797b2
5 changed files with 121 additions and 9 deletions

View File

@ -50,6 +50,7 @@ const DefaultType = {
const Event = { const Event = {
HIDE: `hide${EVENT_KEY}`, HIDE: `hide${EVENT_KEY}`,
HIDE_PREVENTED: `hidePrevented${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`, HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`, SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`, SHOWN: `shown${EVENT_KEY}`,
@ -68,7 +69,8 @@ const ClassName = {
BACKDROP: 'modal-backdrop', BACKDROP: 'modal-backdrop',
OPEN: 'modal-open', OPEN: 'modal-open',
FADE: 'fade', FADE: 'fade',
SHOW: 'show' SHOW: 'show',
STATIC: 'modal-static'
} }
const Selector = { const Selector = {
@ -307,8 +309,7 @@ class Modal {
if (this._isShown && this._config.keyboard) { if (this._isShown && this._config.keyboard) {
EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => { EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => {
if (event.which === ESCAPE_KEYCODE) { if (event.which === ESCAPE_KEYCODE) {
event.preventDefault() this._triggerBackdropTransition()
this.hide()
} }
}) })
} else { } else {
@ -367,11 +368,7 @@ class Modal {
return return
} }
if (this._config.backdrop === 'static') { this._triggerBackdropTransition()
this._element.focus()
} else {
this.hide()
}
}) })
if (animate) { if (animate) {
@ -409,6 +406,25 @@ class Modal {
} }
} }
_triggerBackdropTransition() {
if (this._config.backdrop === 'static') {
const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
if (hideEvent.defaultPrevented) {
return
}
this._element.classList.add(ClassName.STATIC)
const modalTransitionDuration = getTransitionDurationFromElement(this._element)
EventHandler.one(this._element, TRANSITION_END, () => {
this._element.classList.remove(ClassName.STATIC)
})
emulateTransitionEnd(this._element, modalTransitionDuration)
this._element.focus()
} else {
this.hide()
}
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// the following methods are used to handle overflowing modals // the following methods are used to handle overflowing modals
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@ -540,6 +540,33 @@ describe('Modal', () => {
modal.show() modal.show()
}) })
it('should not close modal when clicking outside of modal-content if backdrop = static', done => {
fixtureEl.innerHTML = '<div class="modal" data-backdrop="static" ><div class="modal-dialog" /></div>'
const modalEl = fixtureEl.querySelector('.modal')
const modal = new Modal(modalEl, {
backdrop: 'static'
})
const shownCallback = () => {
setTimeout(() => {
expect(modal._isShown).toEqual(true)
done()
}, 10)
}
modalEl.addEventListener('shown.bs.modal', () => {
modalEl.click()
shownCallback()
})
modalEl.addEventListener('hidden.bs.modal', () => {
throw new Error('Should not hide a modal')
})
modal.show()
})
it('should not adjust the inline body padding when it does not overflow', done => { it('should not adjust the inline body padding when it does not overflow', done => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>' fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'

View File

@ -48,6 +48,11 @@
.modal.show & { .modal.show & {
transform: $modal-show-transform; transform: $modal-show-transform;
} }
// When trying to close, animate focus to scale
.modal.modal-static & {
transform: $modal-scale-transform;
}
} }
.modal-dialog-scrollable { .modal-dialog-scrollable {

View File

@ -1073,6 +1073,7 @@ $modal-sm: 300px !default;
$modal-fade-transform: translate(0, -50px) !default; $modal-fade-transform: translate(0, -50px) !default;
$modal-show-transform: none !default; $modal-show-transform: none !default;
$modal-transition: transform .3s ease-out !default; $modal-transition: transform .3s ease-out !default;
$modal-scale-transform: scale(1.02) !default;
// Alerts // Alerts

View File

@ -140,6 +140,65 @@ Toggle a working modal demo by clicking the button below. It will slide down and
</div> </div>
{{< /highlight >}} {{< /highlight >}}
### Static backdrop
When backdrop is set to static, the modal will not close when clicking outside it. Click the button below to try it.
<div id="staticBackdropLive" class="modal fade" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLiveLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLiveLabel">Modal title</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>I will not close if you click outside me. Don't even try to press escape key.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Understood</button>
</div>
</div>
</div>
</div>
<div class="bd-example">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdropLive">
Launch static backdrop modal
</button>
</div>
{{< highlight html >}}
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
Launch static backdrop modal
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Modal title</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>
<button type="button" class="btn btn-primary">Understood</button>
</div>
</div>
</div>
</div>
{{< /highlight >}}
### Scrolling long content ### Scrolling long content
When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean. When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean.
@ -753,7 +812,7 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
<td>backdrop</td> <td>backdrop</td>
<td>boolean or the string <code>'static'</code></td> <td>boolean or the string <code>'static'</code></td>
<td>true</td> <td>true</td>
<td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click.</td> <td>Includes a modal-backdrop element. Alternatively, specify <code>static</code> for a backdrop which doesn't close the modal on click or on escape key press.</td>
</tr> </tr>
<tr> <tr>
<td>keyboard</td> <td>keyboard</td>
@ -859,6 +918,10 @@ Bootstrap's modal class exposes a few events for hooking into modal functionalit
<td>hidden.bs.modal</td> <td>hidden.bs.modal</td>
<td>This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).</td> <td>This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).</td>
</tr> </tr>
<tr>
<td>hidePrevented.bs.modal</td>
<td>This event is fired when the modal is shown, its backdrop is <code>static</code> and a click outside the modal or a scape key press is performed.</td>
</tr>
</tbody> </tbody>
</table> </table>