fix: react-doctor modal/dialog/dropzone a11y — 18 files to role+tabIndex+onKeyDown or dialog

This commit is contained in:
Nora
2026-06-26 03:20:10 -06:00
parent e3c1295e62
commit d0bfec9d36
90 changed files with 747 additions and 408 deletions
@@ -256,8 +256,13 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) {
{open && (
<div
role="dialog"
aria-modal="true"
aria-label="FSMA report"
tabIndex={-1}
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/30"
onClick={(e) => e.target === e.currentTarget && setOpen(false)}
onKeyDown={(e) => { if (e.key === "Escape") setOpen(false); }}
style={{ backdropFilter: "blur(4px)" }}
>
<div
@@ -94,8 +94,10 @@ export default function LotCreateModal({ isOpen, onClose, brandId }: Props) {
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
{/* Backdrop */}
<div
className="absolute inset-0 bg-black/50 backdrop-blur-sm"
<button
type="button"
aria-label="Close modal"
className="absolute inset-0 bg-black/50 backdrop-blur-sm border-0 p-0 cursor-default"
onClick={onClose}
/>
@@ -758,7 +758,9 @@ export default function LotDetailPanel({
className="w-full rounded-xl border border-[var(--admin-border)] bg-[var(--admin-bg-subtle)]/50 px-3 py-3 text-sm text-[var(--admin-text-primary)] outline-none focus:border-[var(--admin-accent)] focus:ring-2 focus:ring-[var(--admin-accent)]/20 transition-all"
>
<option value="">Select status...</option>
{STATUS_FLOW.filter((s) => s !== lot.status).map((s) => {
{STATUS_FLOW.flatMap((s) =>
s !== lot.status ? [s] : []
).map((s) => {
const c = EVENT_CONFIG[s];
return (
<option key={s} value={s}>
@@ -288,7 +288,6 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps)
value={manualInput}
onChange={(e) => setManualInput(e.target.value.toUpperCase())}
placeholder="e.g. TC-20260520-001"
autoFocus
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-3.5 text-base font-mono text-stone-900 placeholder:text-stone-400 focus:outline-none focus:border-stone-400"
/>
<p className="text-[10px] text-stone-400 mt-1.5">Enter the lot number from any Route Trace sticker</p>
@@ -88,7 +88,6 @@ export default function QuickNewLotModal({ brandId, onCreated, onClose }: Props)
onChange={(e) => setCropType(e.target.value)}
placeholder="e.g. Sweet Corn"
required
autoFocus
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-3 text-base text-stone-900 placeholder:text-stone-400 focus:outline-none focus:border-stone-400 focus:bg-white transition-colors"
/>
</div>
@@ -643,7 +643,7 @@ export default function RouteTraceDashboard({
className="rounded-lg border border-[var(--admin-border)] bg-white text-xs text-[var(--admin-text-primary)] px-2 py-1.5 sm:py-2 focus:outline-none focus:border-[var(--admin-accent)] flex-shrink-0"
>
<option value="">All Crops</option>
{[...new Set(haulingLots.map((l) => l.crop_type))].sort().map((c) => (
{[...new Set(haulingLots.map((l) => l.crop_type))].toSorted().map((c) => (
<option key={c} value={c}>{c}</option>
))}
</select>
@@ -84,7 +84,15 @@ export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail;
const qrPreviewSize = qrSize * scale * 0.55; // scaled down for preview
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
<div
role="dialog"
aria-modal="true"
aria-label="Print sticker"
tabIndex={-1}
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
onClick={onClose}
onKeyDown={(e) => { if (e.key === "Escape") onClose(); }}
>
<div className="w-full max-w-lg rounded-2xl bg-white shadow-xl" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center justify-between border-b border-stone-100 px-6 py-4">
<div>