fix: Focus the textarea in the Compose dialog instead of the Close button.

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.
composeFocusText
James Teh 2022-11-23 12:40:24 +10:00
rodzic 6b1533c947
commit cbfa48e965
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()
}