1
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-08-09 15:16:51 +02:00

Add shift-tab keyboard support for dialogs (modal & Offcanvas components) (#33865)

* consolidate dialog focus trap logic

* add shift-tab support to focustrap

* remove redundant null check of trap element

Co-authored-by: GeoSot <geo.sotis@gmail.com>

* remove area support forom focusableChildren

* fix no expectations warning in focustrap tests

Co-authored-by: GeoSot <geo.sotis@gmail.com>
Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
Ryan Berliner
2021-07-27 01:01:04 -04:00
committed by GitHub
parent 8536474583
commit 7646f6bd33
9 changed files with 499 additions and 71 deletions

View File

@@ -18,6 +18,7 @@ import BaseComponent from './base-component'
import SelectorEngine from './dom/selector-engine'
import Manipulator from './dom/manipulator'
import Backdrop from './util/backdrop'
import FocusTrap from './util/focustrap'
/**
* ------------------------------------------------------------------------
@@ -52,7 +53,6 @@ const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
@@ -73,6 +73,7 @@ class Offcanvas extends BaseComponent {
this._config = this._getConfig(config)
this._isShown = false
this._backdrop = this._initializeBackDrop()
this._focustrap = this._initializeFocusTrap()
this._addEventListeners()
}
@@ -110,7 +111,6 @@ class Offcanvas extends BaseComponent {
if (!this._config.scroll) {
new ScrollBarHelper().hide()
this._enforceFocusOnElement(this._element)
}
this._element.removeAttribute('aria-hidden')
@@ -119,6 +119,10 @@ class Offcanvas extends BaseComponent {
this._element.classList.add(CLASS_NAME_SHOW)
const completeCallBack = () => {
if (!this._config.scroll) {
this._focustrap.activate()
}
EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })
}
@@ -136,7 +140,7 @@ class Offcanvas extends BaseComponent {
return
}
EventHandler.off(document, EVENT_FOCUSIN)
this._focustrap.deactivate()
this._element.blur()
this._isShown = false
this._element.classList.remove(CLASS_NAME_SHOW)
@@ -160,8 +164,8 @@ class Offcanvas extends BaseComponent {
dispose() {
this._backdrop.dispose()
this._focustrap.deactivate()
super.dispose()
EventHandler.off(document, EVENT_FOCUSIN)
}
// Private
@@ -186,16 +190,10 @@ class Offcanvas extends BaseComponent {
})
}
_enforceFocusOnElement(element) {
EventHandler.off(document, EVENT_FOCUSIN) // guard against infinite focus loop
EventHandler.on(document, EVENT_FOCUSIN, event => {
if (document !== event.target &&
element !== event.target &&
!element.contains(event.target)) {
element.focus()
}
_initializeFocusTrap() {
return new FocusTrap({
trapElement: this._element
})
element.focus()
}
_addEventListeners() {