088a6c1a05
- Backend: refactor nested ternaries, remove unused imports/any types - Frontend: fix exhaustive deps, a11y label associations, array index keys, empty CSS blocks, unused vars, type annotations - MedDetail modal: fix intake schedule bell icons not rendering (use unified intake source with fallback), place bell inline after person name - MedDetail modal: revert schedule rows from grid to flexbox layout Closes #264
58 lines
1.3 KiB
TypeScript
58 lines
1.3 KiB
TypeScript
// =============================================================================
|
||
// Lightbox Component - Full-screen image viewer
|
||
// =============================================================================
|
||
|
||
import type { MouseEvent } from "react";
|
||
import { useEffect } from "react";
|
||
|
||
export interface LightboxProps {
|
||
src: string;
|
||
alt: string;
|
||
onClose: () => void;
|
||
}
|
||
|
||
export function Lightbox({ src, alt, onClose }: LightboxProps) {
|
||
useEffect(() => {
|
||
const handleKeyDown = (event: KeyboardEvent) => {
|
||
if (event.key === "Escape") {
|
||
onClose();
|
||
}
|
||
};
|
||
|
||
document.addEventListener("keydown", handleKeyDown);
|
||
return () => document.removeEventListener("keydown", handleKeyDown);
|
||
}, [onClose]);
|
||
|
||
function handleOverlayClick(e: MouseEvent) {
|
||
e.stopPropagation();
|
||
if (e.target === e.currentTarget) {
|
||
onClose();
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div
|
||
className="lightbox-overlay"
|
||
onClick={handleOverlayClick}
|
||
onKeyDown={(e) => {
|
||
if (e.key === "Escape") {
|
||
onClose();
|
||
}
|
||
}}
|
||
>
|
||
<div className="lightbox-container">
|
||
<button className="lightbox-close" onClick={onClose}>
|
||
×
|
||
</button>
|
||
<img
|
||
src={src}
|
||
alt={alt}
|
||
className="lightbox-image"
|
||
onClick={(e) => e.stopPropagation()}
|
||
onKeyDown={(e) => e.stopPropagation()}
|
||
/>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|