fix: focus the textarea in the Compose dialog (#2227)
ComposeBox already specified autoFocus for the ComposeInput. However, this didn't work because the dialog was disabled when the ComposeInput code tried to focus the textarea. To fix this, tweak A11yDialog to look for the autofocus attribute when determining what to focus. This is consistent with the behavior for native HTML dialogs. Then, have ComposeInput set this attribute if it's in a dialog. Fixes #1839.
This commit is contained in:
parent
a447b9535e
commit
8792d912bc
|
@ -117,7 +117,15 @@
|
||||||
firstTime = false
|
firstTime = false
|
||||||
const { autoFocus } = this.get()
|
const { autoFocus } = this.get()
|
||||||
if (autoFocus) {
|
if (autoFocus) {
|
||||||
requestAnimationFrame(() => textarea.focus({ preventScroll: true }))
|
const { realm } = this.get()
|
||||||
|
if (realm === 'dialog') {
|
||||||
|
// If we're in a dialog, the dialog will be hidden at this
|
||||||
|
// point. Also, the dialog has its own initial focus behavior.
|
||||||
|
// Tell the dialog to focus the textarea.
|
||||||
|
textarea.setAttribute('autofocus', true)
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(() => textarea.focus({ preventScroll: true }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -108,7 +108,7 @@ A11yDialog.prototype.show = function (event) {
|
||||||
// it later, then set the focus to the first focusable child of the dialog
|
// it later, then set the focus to the first focusable child of the dialog
|
||||||
// element
|
// element
|
||||||
focusedBeforeDialog = document.activeElement
|
focusedBeforeDialog = document.activeElement
|
||||||
setFocusToFirstItem(this.node)
|
setInitialFocus(this.node)
|
||||||
|
|
||||||
// Bind a focus event listener to the body element to make sure the focus
|
// Bind a focus event listener to the body element to make sure the focus
|
||||||
// stays trapped inside the dialog while open, and start listening for some
|
// stays trapped inside the dialog while open, and start listening for some
|
||||||
|
@ -281,7 +281,7 @@ A11yDialog.prototype._maintainFocus = function (event) {
|
||||||
// If the dialog is shown and the focus is not within the dialog element,
|
// If the dialog is shown and the focus is not within the dialog element,
|
||||||
// move it back to its first focusable child
|
// move it back to its first focusable child
|
||||||
if (this.shown && !this.node.contains(event.target)) {
|
if (this.shown && !this.node.contains(event.target)) {
|
||||||
setFocusToFirstItem(this.node)
|
setInitialFocus(this.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +333,17 @@ function collect (target) {
|
||||||
*
|
*
|
||||||
* @param {Element} node
|
* @param {Element} node
|
||||||
*/
|
*/
|
||||||
function setFocusToFirstItem (node) {
|
function setInitialFocus (node) {
|
||||||
const focusableChildren = getFocusableChildren(node)
|
const focusableChildren = getFocusableChildren(node)
|
||||||
|
|
||||||
|
// If there's an element with an autofocus attribute, focus that.
|
||||||
|
for (const child of focusableChildren) {
|
||||||
|
if (child.getAttribute('autofocus')) {
|
||||||
|
child.focus()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise, focus the first focusable element.
|
||||||
if (focusableChildren.length) {
|
if (focusableChildren.length) {
|
||||||
focusableChildren[0].focus()
|
focusableChildren[0].focus()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue