refactor context menu and keyboard navigation handling for improved clarity and maintainability

This commit is contained in:
Ross
2025-08-11 10:58:22 +01:00
parent c6f8b271a9
commit de9cf60adc
+134 -129
View File
@@ -1174,17 +1174,17 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
}; };
}, []); }, []);
useEffect(() => { useEffect(() => {
const el = appRootRef.current; const el = appRootRef.current;
if (!el) return; if (!el) return;
const handleContextMenu = (e: MouseEvent) => { const handleContextMenu = (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
}; };
el.addEventListener("contextmenu", handleContextMenu); el.addEventListener("contextmenu", handleContextMenu);
return () => { return () => {
el.removeEventListener("contextmenu", handleContextMenu); el.removeEventListener("contextmenu", handleContextMenu);
}; };
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!referenceLinesEnabled) return; if (!referenceLinesEnabled) return;
@@ -1926,6 +1926,8 @@ useEffect(() => {
useEffect(() => { useEffect(() => {
const el = appRootRef.current;
if (!el) return;
function handleArrowKeyNavigation(e: KeyboardEvent) { function handleArrowKeyNavigation(e: KeyboardEvent) {
console.log("Handling arrow key navigation", e.key); console.log("Handling arrow key navigation", e.key);
console.log("activeViewport", activeViewport); console.log("activeViewport", activeViewport);
@@ -1975,8 +1977,11 @@ useEffect(() => {
} }
} }
window.addEventListener("keydown", handleArrowKeyNavigation); el.addEventListener("keydown", handleArrowKeyNavigation);
return () => window.removeEventListener("keydown", handleArrowKeyNavigation);
return () => {
el.removeEventListener("keydown", handleArrowKeyNavigation);
};
}, [activeViewport, viewportModes, viewportImageIds, updateOverlay]); }, [activeViewport, viewportModes, viewportImageIds, updateOverlay]);
@@ -2401,98 +2406,98 @@ useEffect(() => {
</div> </div>
{/* Preset menu (bottom right of viewport) */} {/* Preset menu (bottom right of viewport) */}
<div <div
style={{ style={{
position: "absolute", position: "absolute",
right: 8, right: 8,
bottom: 8, bottom: 8,
zIndex: 10, zIndex: 10,
pointerEvents: "auto", // <-- ensure pointer events are enabled pointerEvents: "auto", // <-- ensure pointer events are enabled
}} }}
> >
<div <div
className="preset-menu" className="preset-menu"
style={{
background: "rgba(0,0,0,0.7)",
color: "#fff",
borderRadius: "4px",
fontSize: "14px",
minWidth: "120px",
overflow: "hidden",
cursor: "pointer",
position: "relative",
boxShadow: presetsOpenArr[i] ? "0 2px 8px rgba(0,0,0,0.3)" : undefined,
pointerEvents: "auto", // <-- ensure pointer events are enabled
}}
onClick={e => e.stopPropagation()} // <-- prevent bubbling to viewport
>
<div
style={{
padding: "6px 12px",
fontWeight: "bold",
userSelect: "none",
}}
onClick={e => {
e.stopPropagation(); // <-- prevent bubbling to viewport
setPresetsOpenArr(prev => {
const next = [...prev];
next[i] = !next[i];
return next;
});
}}
>
Presets
<span style={{ float: "right", fontWeight: "normal" }}>
{presetsOpenArr[i] ? "▲" : "▼"}
</span>
</div>
{presetsOpenArr[i] && (
<div
className="preset-menu-content"
style={{
background: "rgba(0,0,0,0.95)",
borderRadius: "0 0 4px 4px",
padding: "6px 0 6px 0",
display: "flex",
flexDirection: "column",
zIndex: 11,
pointerEvents: "auto", // <-- ensure pointer events are enabled
}}
onClick={e => e.stopPropagation()} // <-- prevent bubbling to viewport
>
{WINDOW_LEVEL_PRESETS.map((preset) => (
<button
key={preset.name}
style={{ style={{
display: "block", background: "rgba(0,0,0,0.7)",
width: "100%",
margin: "2px 0",
background: "#333",
color: "#fff", color: "#fff",
border: "none", borderRadius: "4px",
borderRadius: "3px", fontSize: "14px",
minWidth: "120px",
overflow: "hidden",
cursor: "pointer", cursor: "pointer",
padding: "4px 0", position: "relative",
fontSize: "13px", boxShadow: presetsOpenArr[i] ? "0 2px 8px rgba(0,0,0,0.3)" : undefined,
opacity: 0.9, pointerEvents: "auto", // <-- ensure pointer events are enabled
}}
onClick={e => {
e.stopPropagation(); // <-- prevent bubbling to viewport
handleApplyPreset(i, preset.center, preset.width);
setPresetsOpenArr(prev => {
const next = [...prev];
next[i] = false;
return next;
});
}} }}
onClick={e => e.stopPropagation()} // <-- prevent bubbling to viewport
> >
{preset.name} <div
</button> style={{
))} padding: "6px 12px",
</div> fontWeight: "bold",
)} userSelect: "none",
</div> }}
</div> onClick={e => {
e.stopPropagation(); // <-- prevent bubbling to viewport
setPresetsOpenArr(prev => {
const next = [...prev];
next[i] = !next[i];
return next;
});
}}
>
Presets
<span style={{ float: "right", fontWeight: "normal" }}>
{presetsOpenArr[i] ? "▲" : "▼"}
</span>
</div>
{presetsOpenArr[i] && (
<div
className="preset-menu-content"
style={{
background: "rgba(0,0,0,0.95)",
borderRadius: "0 0 4px 4px",
padding: "6px 0 6px 0",
display: "flex",
flexDirection: "column",
zIndex: 11,
pointerEvents: "auto", // <-- ensure pointer events are enabled
}}
onClick={e => e.stopPropagation()} // <-- prevent bubbling to viewport
>
{WINDOW_LEVEL_PRESETS.map((preset) => (
<button
key={preset.name}
style={{
display: "block",
width: "100%",
margin: "2px 0",
background: "#333",
color: "#fff",
border: "none",
borderRadius: "3px",
cursor: "pointer",
padding: "4px 0",
fontSize: "13px",
opacity: 0.9,
}}
onClick={e => {
e.stopPropagation(); // <-- prevent bubbling to viewport
handleApplyPreset(i, preset.center, preset.width);
setPresetsOpenArr(prev => {
const next = [...prev];
next[i] = false;
return next;
});
}}
>
{preset.name}
</button>
))}
</div>
)}
</div>
</div>
{/* Position bar inside each viewport */} {/* Position bar inside each viewport */}
{viewportModes[i] === "stack" && viewportImageIds[i] && ( {viewportModes[i] === "stack" && viewportImageIds[i] && (
<div <div
@@ -2856,18 +2861,18 @@ useEffect(() => {
return ( return (
// App root // App root
<div <div
ref={appRootRef} ref={appRootRef}
style={{ style={{
position: "relative", position: "relative",
inset: 0, inset: 0,
width: "100%", width: "100%",
height: "100%", height: "100%",
boxSizing: "border-box", boxSizing: "border-box",
background: "#222", background: "#222",
padding: "12px", padding: "12px",
overflow: "hidden", overflow: "hidden",
}}> }}>
{/* Loading overlay */} {/* Loading overlay */}
{loadingState && ( {loadingState && (
<div <div
@@ -3086,23 +3091,23 @@ useEffect(() => {
? "Disable Alt Key for Reference Cursors" ? "Disable Alt Key for Reference Cursors"
: "Enable Alt Key for Reference Cursors"} : "Enable Alt Key for Reference Cursors"}
</button> </button>
<button <button
style={{ style={{
padding: "10px 18px", padding: "10px 18px",
background: annotationNavEnabled ? "#1976d2" : "#333", background: annotationNavEnabled ? "#1976d2" : "#333",
color: "#fff", color: "#fff",
border: "none", border: "none",
borderRadius: "4px", borderRadius: "4px",
fontWeight: "bold", fontWeight: "bold",
cursor: "pointer", cursor: "pointer",
fontSize: "15px", fontSize: "15px",
marginBottom: "18px", marginBottom: "18px",
width: "100%", width: "100%",
}} }}
onClick={() => setAnnotationNavEnabled((prev) => !prev)} onClick={() => setAnnotationNavEnabled((prev) => !prev)}
> >
{annotationNavEnabled ? "Hide" : "Show"} Annotation Navigation {annotationNavEnabled ? "Hide" : "Show"} Annotation Navigation
</button> </button>
{/* Add more menu items here if needed */} {/* Add more menu items here if needed */}
</div> </div>