refactor(ui): auto-detect dropdown position from last click

This commit is contained in:
Joan
2026-02-07 23:01:34 +01:00
parent 6f1e8c56f2
commit 2e9a833a1a
2 changed files with 18 additions and 14 deletions

View File

@@ -5,12 +5,22 @@ import './GameDropdown.css';
interface GameDropdownProps { interface GameDropdownProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
position: { x: number; y: number }; position?: { x: number; y: number }; // Made optional
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
width?: string; width?: string;
} }
// Track last click position globally to avoid passing it every time
let lastClickPos = { x: 0, y: 0 };
if (typeof window !== 'undefined') {
// Capture usage of mouse down to update position before component renders
window.addEventListener('mousedown', (e) => {
lastClickPos = { x: e.clientX, y: e.clientY };
}, { capture: true });
}
/** /**
* GameDropdown * GameDropdown
* *
@@ -56,10 +66,13 @@ export const GameDropdown: React.FC<GameDropdownProps> = ({
if (!isOpen) return null; if (!isOpen) return null;
// Adjust position to keep within viewport // Use passed position or fallback to last click position
// Default offset of -10 to center mouse over menu // Default offset of -10 to center mouse over menu
let x = position.x - 10; const targetX = position ? position.x : lastClickPos.x;
let y = position.y - 10; const targetY = position ? position.y : lastClickPos.y;
let x = targetX - 10;
let y = targetY - 10;
let flipUp = false; let flipUp = false;
// Simple adjustment logic (can be improved with measuring ref) // Simple adjustment logic (can be improved with measuring ref)

View File

@@ -94,7 +94,6 @@ function LocationView({
// Dropdown State // Dropdown State
const [activeDropdown, setActiveDropdown] = useState<string | null>(null) const [activeDropdown, setActiveDropdown] = useState<string | null>(null)
const [dropdownPos, setDropdownPos] = useState({ x: 0, y: 0 })
// Handle dropdown toggle // Handle dropdown toggle
const handleDropdownClick = (e: React.MouseEvent, id: string) => { const handleDropdownClick = (e: React.MouseEvent, id: string) => {
@@ -102,11 +101,7 @@ function LocationView({
if (activeDropdown === id) { if (activeDropdown === id) {
setActiveDropdown(null) setActiveDropdown(null)
} else { } else {
// Use mouse position for grid-like dropdown behavior // GameDropdown now auto-detects mouse position if we don't pass it
setDropdownPos({
x: e.clientX,
y: e.clientY
})
setActiveDropdown(id) setActiveDropdown(id)
} }
} }
@@ -244,7 +239,6 @@ function LocationView({
<GameDropdown <GameDropdown
isOpen={true} isOpen={true}
onClose={() => setActiveDropdown(null)} onClose={() => setActiveDropdown(null)}
position={dropdownPos}
width="160px" width="160px"
> >
<div className="game-dropdown-header">{getTranslatedText(enemy.name)}</div> <div className="game-dropdown-header">{getTranslatedText(enemy.name)}</div>
@@ -295,7 +289,6 @@ function LocationView({
<GameDropdown <GameDropdown
isOpen={true} isOpen={true}
onClose={() => setActiveDropdown(null)} onClose={() => setActiveDropdown(null)}
position={dropdownPos}
width="160px" width="160px"
> >
<div className="game-dropdown-header">{getTranslatedText(corpse.name)}</div> <div className="game-dropdown-header">{getTranslatedText(corpse.name)}</div>
@@ -345,7 +338,6 @@ function LocationView({
<GameDropdown <GameDropdown
isOpen={true} isOpen={true}
onClose={() => setActiveDropdown(null)} onClose={() => setActiveDropdown(null)}
position={dropdownPos}
> >
<div className="game-dropdown-header">{getTranslatedText(npc.name)}</div> <div className="game-dropdown-header">{getTranslatedText(npc.name)}</div>
<GameButton variant="primary" size="sm" style={{ width: '100%', justifyContent: 'flex-start' }}> <GameButton variant="primary" size="sm" style={{ width: '100%', justifyContent: 'flex-start' }}>
@@ -439,7 +431,6 @@ function LocationView({
<GameDropdown <GameDropdown
isOpen={true} isOpen={true}
onClose={() => setActiveDropdown(null)} onClose={() => setActiveDropdown(null)}
position={dropdownPos}
width="160px" width="160px"
> >
<div className="game-dropdown-header">{getTranslatedText(item.name)}</div> <div className="game-dropdown-header">{getTranslatedText(item.name)}</div>