Skip to content

fix(layout): keep confirmation dialogs above map-control panels (#451)#461

Merged
giswqs merged 2 commits into
mainfrom
fix/dialog-above-map-control-panels
Jun 18, 2026
Merged

fix(layout): keep confirmation dialogs above map-control panels (#451)#461
giswqs merged 2 commits into
mainfrom
fix/dialog-above-map-control-panels

Conversation

@giswqs

@giswqs giswqs commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #451. When a map-control panel is open (the reporter hit it with the basemap control), the layer-removal confirmation dialog renders behind the panel, leaving part of the text unreadable.

Root cause

Map-control packages (e.g. maplibre-gl-basemap-control) append their panel to the map containermap.getContainer().appendChild(panel) — with position: absolute; z-index: 1000. The map area <main> was only position: relative (not an isolating stacking context), so that z-index: 1000 escaped to the root stacking context and beat the body-portaled shadcn Dialog (z-50). The .maplibregl-control-container (z-index: 2) does not help here because the panel is appended to the map container directly, not the control container.

Fix

Add isolation: isolate to <main> so it becomes its own stacking context. Every map-control panel appended to the map container is then contained below the modal layer. This fixes the whole class of map-panel-over-dialog conflicts without touching the shadcn z-index scale (so Radix popovers/selects nested inside dialogs keep working). <main> already has overflow-hidden, so nothing relied on panels escaping it.

Verification

Drove the real running app with Playwright and ran a causal stacking test against the actual .maplibregl-map container (the node the basemap control appends to) and the real <main>:

Condition Topmost element at the overlap point
With fix (main isolated) dialog (z-50) ✅
Pre-fix simulated (main.style.isolation='auto') panel (z-1000) — reproduces the bug

Confirmed <main> is now the only stacking context between the map container and <body>. Pre-commit (eslint + full build) passes; app renders with no layout regression.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where map control panels could overlap with and obscure dialog elements (for example, confirmation dialogs), ensuring dialogs remain properly visible and interactive.

Map-control panels (e.g. maplibre-gl-basemap-control) append their panel
to the map container with `position: absolute; z-index: 1000`. The map
area `<main>` was only `position: relative`, so that z-index escaped to
the root stacking context and rendered above body-portaled modal dialogs
(z-50) such as the layer-removal confirmation, leaving part of the dialog
unreadable behind the panel.

Make `<main>` an isolating stacking context (`isolation: isolate`) so all
map-control panels appended to the map container stay contained below the
modal layer. This fixes the reported basemap case and the whole class of
map-panel-over-dialog conflicts without touching the shadcn z-index scale
(so Radix popovers/selects nested inside dialogs keep working).
@netlify

netlify Bot commented Jun 18, 2026

Copy link
Copy Markdown

Deploy Preview for geolibre-app ready!

Name Link
🔨 Latest commit c4a872b
🔍 Latest deploy log https://app.netlify.com/projects/geolibre-app/deploys/6a3359288372e3000811faf6
😎 Deploy Preview https://deploy-preview-461--geolibre-app.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 50812691-6f4a-4fd6-a9ec-983c46e09ab8

📥 Commits

Reviewing files that changed from the base of the PR and between 0f2b676 and c4a872b.

📒 Files selected for processing (1)
  • apps/geolibre-desktop/src/components/layout/DesktopShell.tsx

📝 Walkthrough

Walkthrough

Adds the isolate CSS utility class to the <main> map container element in DesktopShell, creating an explicit stacking context for the map area. An explanatory comment is also added. This prevents map-control panels appended to the map container from escaping to the root stacking context and rendering above body-portaled dialogs.

Changes

Map Container Stacking Context Fix

Layer / File(s) Summary
Add isolate to map container className
apps/geolibre-desktop/src/components/layout/DesktopShell.tsx
Adds the isolate Tailwind utility and an inline comment to the <main> element, establishing a dedicated stacking context so map-control panels remain below body-portaled dialogs such as the layer-deletion confirmation.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

🐇 A single word, isolate, tucked in with care,
The map controls stay put — they don't float in the air.
Dialogs pop up front, as they always should,
No more hiding behind layers — now everything's good!
Hop hop hooray, the z-index stacks right! 🗺️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and clearly summarizes the main fix: adding CSS isolation to resolve stacking context issues with confirmation dialogs appearing behind map control panels.
Linked Issues check ✅ Passed The code changes directly address issue #451 by implementing the fix to establish a proper stacking context, ensuring confirmation dialogs render above map-control panels as required.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the stacking context issue in DesktopShell; no unrelated modifications are present in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dialog-above-map-control-panels

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread apps/geolibre-desktop/src/components/layout/DesktopShell.tsx Outdated
// layer. Without it those z-indexes escape to the root stacking
// context and cover body-portaled dialogs like the layer-removal
// confirmation (z-50). See issue #451.
className={`relative isolate min-w-0 flex-1 overflow-hidden ${

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Potential mobile regression for position: fixed control-panel dropdowns (medium confidence).

basemap-style.ts, swipe-style.ts, lidar-style.ts, and geoagent-style.ts all render a position: fixed; z-index: 10000 dropdown menu that is appended directly to map.getContainer() — i.e. inside <main>.

Before this fix those fixed dropdowns had z-10000 in the root stacking context. On mobile, LayerPanel and StylePanel have max-md:z-30 on their root elements, so they were stacking contexts at z-30 in the root — below the dropdowns.

After this fix <main> is an isolated stacking context with z-index: auto in the parent context. The position: fixed elements (layout unchanged — they still position relative to the viewport) now have their z-index evaluated within <main>. When the browser resolves the paint order it compares <main> (z-auto) against LayerPanel/StylePanel (z-30), making those panels paint on top of everything inside <main>, including those fixed dropdowns.

In practice this is low-risk because on mobile those panels cover the whole map area and a user is unlikely to have both a map-control dropdown and a mobile overlay panel open simultaneously. But it is a change in z-order that wasn't called out in the PR description and wasn't covered by the Playwright causal test, so it is worth confirming with a manual smoke-test on a mobile viewport.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks - this is an accepted, intentional consequence of the containment fix rather than a regression to patch. The whole point of isolate on <main> is to keep the map-control dropdowns (z-index: 10000, appended to the map container) contained below body-portaled dialogs; a side effect is that on a mobile viewport those dropdowns no longer escape above the full-screen LayerPanel/StylePanel (max-md:z-30). Since those panels cover the entire map area on mobile, having both a map-control dropdown and a panel open at once is not a realistic state, which matches your low-risk assessment. Leaving this thread open so a maintainer can confirm with the manual mobile-viewport smoke-test you suggested before resolving.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

This is a small, well-reasoned CSS fix. The core mechanism is correct: isolation: isolate creates a new stacking context for <main> without affecting position: fixed layout (no transform/perspective/filter side-effects), so all map-control panels appended to the map container are contained within <main>'s z-order and can no longer beat body-portaled dialogs.


Bugs

Finding Confidence
Wrong z-index value in comment — line 1195 says z-index:1000; basemap-style.ts:67, swipe-style.ts:71, lidar-style.ts:119, and geoagent-style.ts:67 all use z-index: 10000. The fix works either way, but the doc is misleading. High
Mobile z-order regression for fixed-position dropdownsLayerPanel and StylePanel both carry max-md:z-30 on their root elements, making them stacking contexts at z-30 on mobile. Before the fix, position: fixed; z-index: 10000 control-panel dropdowns (basemap, swipe, lidar, geoagent) were in the root context and beat those panels. After the fix they're inside <main> (z-auto), so the mobile panels now paint above them. Unlikely to surface in practice (panels cover the map area on mobile), but the scenario was not covered by the Playwright causal test. Medium

Security

Nothing to flag.

Performance

Nothing to flag. isolation: isolate is a very lightweight stacking-context hint; no compositing-layer penalty worth noting here.

Quality

Finding Confidence
Incidental behavior change: StoryMap presenterStoryMapPresenter portals into map.getContainer() and uses z-[70]/z-[72] on its overlays. Before the fix those were in the root context (above dialogs at z-50); after the fix they're inside <main> (z-auto), so body-portaled dialogs now render above the presentation overlay. This is actually the more correct behavior (dialogs should cover content), but it is an undocumented change. Low

CLAUDE.md

Finding Confidence
Multi-line comment blockCLAUDE.md says "Never write multi-paragraph docstrings or multi-line comment blocks — one short line max." The added comment is 6 lines. The workaround is genuinely non-obvious and deserves a comment, but the format should be condensed to one line (see inline suggestion). High

Overall: The fix is mechanically correct and solves the reported issue cleanly. The two actionable items are fixing the z-index: 1000 → 10000 value in the comment and condensing it to one line; the mobile dropdown z-order change is low-risk but worth a manual smoke-test before merge.

- Condense the `<main>` isolate comment to a single line and correct the
  cited map-panel z-index from 1000 to 10000 (the four control-panel
  style sheets all use z-index: 10000).
) : null}
<main
className={`relative min-w-0 flex-1 overflow-hidden ${
// `isolate` creates a stacking context so map-panel z-indexes (up to 10000) stay below body-portaled dialogs. See #451.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor nit: the comment says "up to 10000" but the PR description (and the basemap control's actual CSS) cites z-index: 1000. The order of magnitude difference could mislead a future reader. Consider using the documented value or a loose upper-bound phrasing:

Suggested change
// `isolate` creates a stacking context so map-panel z-indexes (up to 10000) stay below body-portaled dialogs. See #451.
// `isolate` creates a stacking context so map-panel z-indexes (≤ 1000) stay below body-portaled dialogs. See #451.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

The fix is correct and well-reasoned. isolation: isolate is exactly the right CSS primitive here — it creates a new stacking context on \

`without altering layout, flex behaviour, overflow clipping, or any other box properties. Radix UI dialogs/popovers/selects all portal todocument.body(outside``), so they remain in the root stacking context and are unaffected. MapLibre markers, popups, and control panels are DOM children of the map container inside ``, so they are correctly contained by the new stacking context. The sibling LayerPanelandStylePanelelements also sit outside``` in the DOM, so they are unaffected.

Findings

Quality

  • Comment z-index value mismatch (low confidence, nit): The inline comment reads "up to 10000" while the PR description and the basemap control's CSS use z-index: 1000. The order-of-magnitude difference could mislead a future reader. Suggestion posted inline.

  • No regression test committed (medium confidence): The PR description says the fix was verified with a Playwright causal stacking test, but that test was not added to the e2e/ suite. A test like document.elementFromPoint at the overlap co-ordinates (or CSS getComputedStyle on \isolation`) would guard against the stacking context being accidentally removed. Since the verification was already written, committing it as a dedicated spec (e.g. e2e/stacking.spec.ts`) would be low-effort and prevent the bug from silently regressing.

Bugs / Security / Performance / CLAUDE.md

Nothing to flag. The one-line change is minimal-blast-radius, the Tailwind isolate utility maps directly to isolation: isolate, and no existing CSS rules in index.css or node_modules override it. The CLAUDE.md guideline for MapLibre control styling ("add scoped overrides in src/index.css, never edit node_modules") is not relevant here since the fix is layout-level, not control-level.

@giswqs giswqs merged commit f8d6277 into main Jun 18, 2026
20 of 21 checks passed
@giswqs giswqs deleted the fix/dialog-above-map-control-panels branch June 18, 2026 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue: Dialogue box for layer deletion confirmation is not displayed as the topmost dialogue box.

1 participant