brackt/app/components/draft/AuthRecoveryOverlay.tsx
Claude e25cba09ac
Fix code review findings from WCAG compliance pass
- Add Arrow key navigation + roving tabindex to all role=radiogroup
  components (AutodraftSettings x2, TimerModeSelector,
  OvernightPauseSettings, ScoringPresetPicker) per ARIA radio pattern
- Extract shared focus-trap logic into useFocusTrap hook; update
  ConnectionOverlay and AuthRecoveryOverlay to use it
- Add tabIndex={-1} to ConnectionOverlay Card so focus can land in
  spinner-only state (no interactive children)
- Replace aria-live on loading dots container with sr-only span so
  status changes are announced by text content, not aria-label
- Remove contradictory aria-hidden+role=columnheader from
  AvailableParticipantsSection visual-only header row
- Remove invalid scope="col" from div[role=columnheader] in
  DraftSummaryView (scope is only valid on <th>)
- Remove redundant aria-label from ParticipantSelectionDialog sport
  select (htmlFor label is sufficient)
- Change WizardStepper connector <li> to role=presentation
- Revert muted-foreground from 62% to 55% (original already passes
  contrast; footer was fixed separately via text-muted-foreground)

https://claude.ai/code/session_01JXajpFxhqLf8aPCncP81k3
2026-05-17 23:46:57 +00:00

59 lines
1.9 KiB
TypeScript

import { useRef } from "react";
import { Button } from "~/components/ui/button";
import { Card } from "~/components/ui/card";
import { useFocusTrap } from "~/hooks/useFocusTrap";
interface AuthRecoveryOverlayProps {
isAuthDegraded: boolean;
}
export function AuthRecoveryOverlay({ isAuthDegraded }: AuthRecoveryOverlayProps) {
const dialogRef = useRef<HTMLDivElement>(null);
useFocusTrap(dialogRef, isAuthDegraded);
if (!isAuthDegraded) return null;
return (
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="auth-recovery-title"
className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[100]"
>
<Card className="w-full max-w-md mx-4 p-8 text-center">
<div className="flex flex-col items-center gap-6">
<div className="w-16 h-16 rounded-full bg-destructive/15 flex items-center justify-center">
<svg
aria-hidden="true"
className="w-8 h-8 text-destructive"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
</div>
<div>
<h2 id="auth-recovery-title" className="text-2xl font-bold mb-2">Session Expired</h2>
<p className="text-muted-foreground">
Your session has expired. Reload the page to reconnect to the draft.
</p>
</div>
<Button onClick={() => window.location.reload()} className="w-full" variant="default">
Reload Page
</Button>
</div>
</Card>
</div>
);
}