fix: open the keyboard shortcuts at the top instead of scrolled down to the tour link

This commit is contained in:
Linus Rath
2026-10-28 02:05:50 +01:00
parent 22629c0c6c
commit b08bb61a96
2 changed files with 17 additions and 20 deletions
+9 -14
View File
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useId, useRef, type ReactNode, type RefObject, type FormEvent } from "react";
import { useId, useRef, type ReactNode, type RefObject, type FormEvent } from "react";
import { createPortal } from "react-dom";
import { useTranslations } from "next-intl";
import { useFocusTrap } from "@/hooks/use-focus-trap";
@@ -91,23 +91,18 @@ export function Dialog({
const id = useId();
const titleId = `${id}-title`;
const descriptionId = `${id}-description`;
const panelRef = useFocusTrap({ isActive: isOpen, onEscape: onClose, restoreFocus: true });
// The focus starts on an explicit target, else the first field, else
// the first control.
const panelRef = useFocusTrap({
isActive: isOpen,
onEscape: onClose,
restoreFocus: true,
initialFocus: () => initialFocus?.current ?? panelRef.current?.querySelector<HTMLElement>(FIELD_SELECTOR),
});
// A press that started on the backdrop, so a text selection dragged out of
// a field and released outside doesn't count as an outside click.
const pressedOnBackdrop = useRef(false);
// The focus trap has put the focus on the first control; a field or an
// explicit target is the better start.
useEffect(() => {
if (!isOpen) return;
const panel = panelRef.current;
if (!panel) return;
const target = initialFocus?.current ?? panel.querySelector<HTMLElement>(FIELD_SELECTOR);
target?.focus();
// Only on open: a later render must not pull the focus back.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
if (!isOpen || typeof document === "undefined") return null;
const blockOutside = preventOutsideClose || dirty;
+8 -6
View File
@@ -8,12 +8,15 @@ interface UseFocusTrapOptions {
isActive: boolean;
onEscape?: () => void;
restoreFocus?: boolean;
/** Where the focus goes on open, instead of the first focusable element. */
initialFocus?: () => HTMLElement | null | undefined;
}
export function useFocusTrap({
isActive,
onEscape,
restoreFocus = true,
initialFocus,
}: UseFocusTrapOptions) {
const containerRef = useRef<HTMLDivElement>(null);
const previousActiveElement = useRef<HTMLElement | null>(null);
@@ -22,8 +25,10 @@ export function useFocusTrap({
// focus back to the opener and then to the first element, out of the field
// the user was typing in whenever the page behind rendered again.
const onEscapeRef = useRef(onEscape);
const initialFocusRef = useRef(initialFocus);
useEffect(() => {
onEscapeRef.current = onEscape;
initialFocusRef.current = initialFocus;
});
useEffect(() => {
@@ -57,12 +62,9 @@ export function useFocusTrap({
};
container.addEventListener('focusin', handleFocusIn);
// Focus first element
const focusableElements = getFocusableElements();
const firstElement = focusableElements[0];
if (firstElement) {
firstElement.focus();
}
// Focus the requested element, else the first one
const target = initialFocusRef.current?.() ?? getFocusableElements()[0];
target?.focus();
// Handle Tab key to trap focus
const handleKeyDown = (e: KeyboardEvent) => {