"use client"; // Dialog-Basis-Komponente — SHL-01. WCAG 2.1 AA: Fokus-Falle, ESC schließt, Tastaturbedienung vollständig. import { useEffect, useRef } from "react"; import type { ReactNode } from "react"; import { useI18n } from "../i18n/i18n"; const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; export interface DialogProps { open: boolean; onClose: () => void; titleId: string; title: string; children: ReactNode; } export function Dialog({ open, onClose, titleId, title, children }: DialogProps) { const { t } = useI18n(); const dialogRef = useRef(null); const previouslyFocused = useRef(null); useEffect(() => { if (!open) return; previouslyFocused.current = document.activeElement as HTMLElement | null; const node = dialogRef.current; const focusables = node?.querySelectorAll(FOCUSABLE_SELECTOR); focusables?.[0]?.focus(); function handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") { onClose(); return; } if (event.key !== "Tab" || !node) return; const items = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR)); if (items.length === 0) return; const first = items[0]; const last = items[items.length - 1]; if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); } else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } } document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("keydown", handleKeyDown); previouslyFocused.current?.focus(); }; }, [open, onClose]); if (!open) return null; return (
{ if (event.target === event.currentTarget) onClose(); }} >

{title}

{children}
); }