refactor(ui): auto-detect dropdown position from last click
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user