Skip to content

Comments

feat(mapbox): Add widget support to MapboxOverlay via IControl adapter#9963

Open
chrisgervang wants to merge 7 commits intomasterfrom
chr/mapbox-widget-support
Open

feat(mapbox): Add widget support to MapboxOverlay via IControl adapter#9963
chrisgervang wants to merge 7 commits intomasterfrom
chr/mapbox-widget-support

Conversation

@chrisgervang
Copy link
Collaborator

@chrisgervang chrisgervang commented Jan 25, 2026

Closes #9962

Background

Enable deck widgets to coexist with native Mapbox/MapLibre controls without DOM overlap by rendering widgets with viewId: 'mapbox' into the map's control container system via the new _container prop.

Change List

  • Add DeckWidgetControl class that wraps deck widgets as Mapbox IControls
  • Process widgets with viewId: 'mapbox' in MapboxOverlay, automatically wrapping them as IControls
  • Set widget.props._container to Mapbox-positioned element so WidgetManager appends there
  • Widgets stack correctly with native controls in the same DOM container, preventing overlap

Note

Medium Risk
Changes overlay lifecycle behavior by mutating widget _container and dynamically adding/removing Mapbox controls, which could impact widget rendering/cleanup and control ordering across setProps and mode switches.

Overview
Adds Mapbox/MapLibre control integration for deck.gl widgets: widgets with viewId: 'mapbox' are now wrapped as IControls so they render inside the map’s native control containers (avoiding DOM overlap with built-in controls).

MapboxOverlay now creates/updates/removes these widget-controls on onAdd, setProps, and onRemove, reusing controls by widget id (and only recreating on placement change) while still passing widgets through to Deck for event handling. Tests and mocks are extended to cover widget behavior and control positioning, and overlaid-mode tests use an isolated WebGL device to avoid shared context issues.

Written by Cursor Bugbot for commit 79355a6. This will update automatically on new commits. Configure here.

Cursor Bugbot found 1 potential issue for commit 79355a6

@coveralls
Copy link

coveralls commented Jan 25, 2026

Coverage Status

coverage: 91.108% (+0.02%) from 91.091%
when pulling 79355a6 on chr/mapbox-widget-support
into 1510545 on master.

@chrisgervang chrisgervang mentioned this pull request Jan 25, 2026
62 tasks
@chrisgervang chrisgervang added this to the v9.3 milestone Feb 2, 2026
chrisgervang and others added 4 commits February 4, 2026 15:24
Enable deck widgets to coexist with native Mapbox/MapLibre controls without
DOM overlap by rendering widgets with viewId: 'mapbox' into the map's control
container system.

- Add DeckWidgetControl class that wraps deck widgets as IControls
- Process widgets with viewId: 'mapbox' in MapboxOverlay
- Set widget._container to Mapbox-positioned element via IControl
- Widgets stack correctly with native controls in same container

Closes #9962

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add TestWidget class for testing widget integration
- Test regular widgets render in deck container
- Test widgets with viewId: 'mapbox' are wrapped as IControl
- Test mixed widgets (regular + mapbox)
- Test setProps updates widget controls
- Test interleaved mode widget support
- Update mock map to support control positions and hasControl

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Overlaid mode tests create their own Deck instances which can cause GL
context corruption when sharing contexts across tests. Using an isolated
WebGLDevice for these tests prevents hangs in the test suite.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
…d rootElement

When setProps was called with widgets, _processWidgets would destroy and
recreate all DeckWidgetControls. This removed the container from the DOM,
orphaning the widget's rootElement since WidgetManager wouldn't re-attach
it (same widget id means no change detected).

Now matches widgets by id (like WidgetManager) and only recreates controls
when the widget is new or placement changes. For existing widgets with same
id and placement, the container is preserved and copied to the new widget
instance to support React patterns where widgets are recreated on render.

Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
@chrisgervang chrisgervang force-pushed the chr/mapbox-widget-support branch from 40d85b9 to 9426c8c Compare February 4, 2026 23:24
chrisgervang and others added 3 commits February 4, 2026 15:58
Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
When _processWidgets reuses a DeckWidgetControl for a new widget instance
with the same id and placement, the control's internal _widget reference
must be updated. Otherwise the control references the old widget, causing
incorrect behavior in onRemove() and potential memory leaks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

for (const widget of mapboxWidgets) {
const existingControl = existingControlsById.get(widget.id);

if (existingControl && existingControl.widget.placement === widget.placement) {
Copy link

Choose a reason for hiding this comment

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

Placement change undetected for mutated widget objects

Low Severity

The placement comparison existingControl.widget.placement === widget.placement fails to detect placement changes when the same widget object is passed with a mutated placement property. After setWidget(widget) is called in a previous iteration, existingControl.widget becomes the same reference as the current widget. When both sides of the comparison reference the same object, the comparison is trivially true regardless of whether placement was actually changed. The control remains in its original map position even though the widget's placement changed.

Fix in Cursor Fix in Web

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.

feat(mapbox): Add widget support to MapboxOverlay via IControl adapter

2 participants