enhancement
major
minor
defect
critical
major
minor
major
#30147
React-Oberfläche: Menü "Weitere Aktionen" schließt nicht mit Escape, wenn alle Einträge deaktiviert sind
Fehlerbild
Ein Aufklappmenü der React-Oberfläche (z.B. das Überlaufmenü "Weitere Aktionen" einer Werkzeugleiste) schließt sich nicht mit Escape, wenn alle seine Einträge deaktiviert sind. Es schließt sich erst durch einen erneuten Klick auf den Menü-Knopf oder einen Klick außerhalb. Solange es offen ist, verdeckt es die darunterliegenden Elemente (z.B. Tabellenzeilen), Klicks dort treffen das Menü.
Schließt sich das Menü dagegen mit Escape, landet der Fokus nicht wieder auf dem Menü-Knopf, sondern auf einem anderen Knopf der Werkzeugleiste.
Nachstellen
tl-demo-react mit den BPE-Modulen, Administration -> Workflows: einen Workflow auswählen, "Weitere Aktionen" -> Löschen -> Ja. Danach ist nichts ausgewählt und alle Einträge des Menüs sind deaktiviert. "Weitere Aktionen" öffnen und Escape drücken: das Menü bleibt offen.
Ursache
useRovingMenu in com.top_logic.layout.react/react-src/bridge/menu.tsx behandelt die Tasten im onKeyDown des Menü-Elements. Der Fokus steht auch ohne aktivierten Eintrag im Menü (die Fokusfalle fokussiert dann das Menü-Element selbst), aber der Handler bricht ab, sobald es keinen aktivierten Eintrag gibt - noch bevor er Escape prüft.
Den Fokus gibt die Fokusfalle beim Schließen an das Element zurück, das ihn beim Öffnen hatte. Da der Menü-Knopf beim Öffnen mit der Maus den Fokus bewusst nicht übernimmt (der Fokus soll im Inhalt bleiben, auf dessen Auswahl die Befehle wirken), ist das ein beliebiges früher fokussiertes Element.
Lösung
- Escape schließt das Menü unabhängig davon, ob es aktivierte Einträge gibt. Das gilt für alle Menüs der React-Oberfläche (Überlaufmenü und Menügruppen der Werkzeugleiste, Kontextmenüs, Seitenleisten-Flyout, Menüs von Menu / TLMenu) und ebenso für das Menü im MUI-Theme (MuiMenuAdapter).
- Schließt Escape das Menü, geht der Fokus an den Knopf zurück, der es geöffnet hat (WAI-ARIA Menu Button). Wird ein Eintrag gewählt oder außerhalb geklickt, bleibt es dabei, dass der Fokus dorthin zurückgeht, wo er vor dem Öffnen stand. Ein Menü ohne Auslöser-Element (Kontextmenü an der Mausposition) behält dieses Verhalten auch bei Escape.
Technisch:
- Neuer Bridge-Hook useEscapeClose(open, onClose, trigger): schließt auf Escape, merkt sich das und liefert restoreTo, das nach einem Escape-Schließen den Auslöser nennt. useRovingMenu baut darauf auf und nimmt den Auslöser als optionalen Parameter.
- useFocusTrap hat die Option restoreTo, die beim Schließen das Element bestimmt, das den Fokus erhält (sonst das beim Öffnen fokussierte Element).
- Menu nimmt seinen Anker als Auslöser, wenn er ein Element ist; die Menügruppe der Werkzeugleiste ihren Menü-Knopf.
- Nebenbei: der Typfehler in MuiTabBarAdapter.test.tsx (fehlendes Pflichtfeld hidden der Reiter) ist behoben, tsc läuft für com.top_logic.layout.react.mui wieder fehlerfrei.