Skip to content

fix: Prevent toolbar from overlapping the right-click context menu#11881

Open
mykh-hailo wants to merge 3 commits intoopenstreetmap:developfrom
mykh-hailo:fix/toolbar-overlaps-right-click-menu
Open

fix: Prevent toolbar from overlapping the right-click context menu#11881
mykh-hailo wants to merge 3 commits intoopenstreetmap:developfrom
mykh-hailo:fix/toolbar-overlaps-right-click-menu

Conversation

@mykh-hailo
Copy link

@mykh-hailo mykh-hailo commented Feb 17, 2026

What is this PR

This branch fixes popover placement when using left/right placements inside scrollable containers. The update adjusts the popover's vertical position to prevent overflow beyond the scroll container, clamps the arrow position so it remains visually aligned and within the popover bounds, and includes a short-lived debug log used during verification

Closes: #11017

Root Cause

  • Symptom: Popovers placed at "left" or "right" could overflow the vertical bounds of their container(over-map) and the arrow could be mis-positioned or clipped, especially when the anchor or container was scrolled or the popover size changed dynamically.
  • Root cause: coordinate-space mismatch and inconsistent measurement sources during positioning updates for left/right placements.

What changed

  • Adjusted popover/context menu positioning logic to account for the toolbar's width and safe area on the right side of the viewport.
  • Added a small offset and collision-detection fallback so the context menu will open to the left when there's insufficient space on the right.
  • Minor CSS tweaks to ensure z-index and pointer-events are correct so the context menu is interactable and visually above the toolbar.
  • Small defensive updates to ensure behavior is stable across different viewport sizes and when the toolbar is collapsed/expanded.
@mykh-hailo mykh-hailo changed the title fix: Prevent toolbar from overlapping the right-click context menu # Feb 18, 2026
@tyrasd tyrasd added the usability An issue with ease-of-use or design label Feb 18, 2026
Copy link
Member

@tyrasd tyrasd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, thanks!

Just a few code linting remarks (see below) that should be easy to address.

PS: I was wondering why the top/bottom branch can get away with using the slightly simpler implementation using offsetWidth / w properties of the popover/scroll nodes, while for left/right we have to use getBoundingClientRects to calculate the clamped positions. I'd assume the getBoundingClientRect approach would also work for the top/bottom case, and it should be more robust in case we want to use it in the future for a situation where the simple calculation might not work. Also, maybe the code could be simplified slightly when the two branches use the same calculation (only x/y need to be flipped for each)… What do you think?

if (scrollNode) {

var initialPosX = position.x;
if ((placement === 'top' || placement === 'bottom')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double parentheses are not necessary here:

Suggested change
if ((placement === 'top' || placement === 'bottom')) {
if (placement === 'top' || placement === 'bottom') {
position.y += (scrollNodeRect.top + 10) - popoverRect.top;
}

var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this var arrow is already defined above in the if (placement === 'top' || placement === 'bottom') branch. Maybe change both to const.

const arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow');

(And since we're touching this part of the code anyway: can you also upgrade the other remaining variable definitions in the two if branches here to consts?)

// keep the arrow centered on the button, or as close as possible
var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
arrow.style('left', ~~arrowPosX + 'px');
} else if (placement === "left" || placement === "right") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for strings, please use single brackets '.

Suggested change
} else if (placement === "left" || placement === "right") {
} else if (placement === 'left' || placement === 'right') {
var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
arrow.style('left', ~~arrowPosX + 'px');
var popoverRect = popoverSelection.node().getBoundingClientRect();
var scrollNodeRect = scrollNode.getBoundingClientRect()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing ; 😉

Suggested change
var scrollNodeRect = scrollNode.getBoundingClientRect()
var scrollNodeRect = scrollNode.getBoundingClientRect();
@mykh-hailo
Copy link
Author

@tyrasd I made some updates on your comments on my PR.
Please check and leave your comments if any.
Thank you.

@mykh-hailo mykh-hailo requested a review from tyrasd February 25, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

usability An issue with ease-of-use or design

2 participants