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.
remove-alert-role
James Teh 2022-11-24 02:21:42 +10:00 zatwierdzone przez GitHub
rodzic a447b9535e
commit 8792d912bc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 20 dodań i 4 usunięć

Wyświetl plik

@ -117,7 +117,15 @@
firstTime = false
const { autoFocus } = this.get()
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 }))
}
}
}
})

Wyświetl plik

@ -108,7 +108,7 @@ A11yDialog.prototype.show = function (event) {
// it later, then set the focus to the first focusable child of the dialog
// element
focusedBeforeDialog = document.activeElement
setFocusToFirstItem(this.node)
setInitialFocus(this.node)
// 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
@ -281,7 +281,7 @@ A11yDialog.prototype._maintainFocus = function (event) {
// If the dialog is shown and the focus is not within the dialog element,
// move it back to its first focusable child
if (this.shown && !this.node.contains(event.target)) {
setFocusToFirstItem(this.node)
setInitialFocus(this.node)
}
}
@ -333,9 +333,17 @@ function collect (target) {
*
* @param {Element} node
*/
function setFocusToFirstItem (node) {
function setInitialFocus (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) {
focusableChildren[0].focus()
}