feat(mapbox): Add widget support to MapboxOverlay via IControl adapter#9963
feat(mapbox): Add widget support to MapboxOverlay via IControl adapter#9963chrisgervang wants to merge 7 commits intomasterfrom
Conversation
40d85b9 to
9426c8c
Compare
| for (const widget of mapboxWidgets) { | ||
| const existingControl = existingControlsById.get(widget.id); | ||
|
|
||
| if (existingControl && existingControl.widget.placement === widget.placement) { |
There was a problem hiding this comment.
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.
79355a6 to
287b467
Compare
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>
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>
287b467 to
e793c90
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| this._widget.props._container = null; | ||
| } | ||
| this._container?.remove(); | ||
| this._container = null; |
There was a problem hiding this comment.
onRemove clears _container on wrong widget instance
Low Severity
After successive setProps calls with new widget instances of the same id, DeckWidgetControl._widget references the latest new instance (via setWidget), while WidgetManager tracks the original old instance (via oldWidget.setProps(widget.props)). When DeckWidgetControl.onRemove runs, it clears _container on the control's widget (the wrong instance), leaving a stale _container reference pointing to a detached DOM element on the widget that WidgetManager actually manages.


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_containerprop.Change List
DeckWidgetControlclass that wraps deck widgets as Mapbox IControlsviewId: 'mapbox'in MapboxOverlay, automatically wrapping them as IControlswidget.props._containerto Mapbox-positioned element so WidgetManager appends thereNote
Medium Risk
Introduces new widget lifecycle/control-management inside
MapboxOverlay, including DOM container reassignment via the internalwidget.props._container, which could affect widget rendering/cleanup if edge cases aren’t covered. Scope is limited to widgets withviewId: 'mapbox'and is backed by new unit tests.Overview
Adds Mapbox/MapLibre control-container support for deck.gl widgets. Widgets with
viewId: 'mapbox'are now wrapped in a newDeckWidgetControlIControl adapter so they render in the map’s native control positions instead of overlapping the overlay.MapboxOverlaynow processeswidgetsononAdd(before Deck creation) and onsetProps, creating/reusing/removing widget controls by widgetidandplacementand cleaning them up ononRemove.Tests are expanded with a mock
addControl(control, position)/hasControlimplementation and new widget-focused specs (including container reuse and interleaved mode); test GL setup is also tweaked to use an isolated device and remove unused imports.Written by Cursor Bugbot for commit e793c90. This will update automatically on new commits. Configure here.