feat(widgets): Add controlled mode and state callbacks#9973
feat(widgets): Add controlled mode and state callbacks#9973chrisgervang wants to merge 5 commits intomasterfrom
Conversation
Implement controlled/uncontrolled component pattern for 12 widgets (ThemeWidget, FullscreenWidget, TimelineWidget, ZoomWidget, CompassWidget, GimbalWidget, GeocoderWidget, ResetViewWidget, ViewSelectorWidget, SplitterWidget, StatsWidget, LoadingWidget). Add state props, getter methods, and callbacks. Update widget overview documentation with controlled/uncontrolled mode explanation. Closes #9964 Co-Authored-By: Claude (global.anthropic.claude-haiku-4-5-20251001-v1:0) <noreply@anthropic.com>
Resolve conflict in stats-widget.tsx: keep _collapsed naming for controlled mode internal state, use _getStats() method from master. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove redundant _playing assignments in timeline-widget start()/stop() - Remove redundant updateHTML() calls after super.setProps() in multiple widgets - Fix IconMenu to support controlled mode via selectedItem prop Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve conflicts in: - docs/api-reference/widgets/stats-widget.md: Merged documentation formats, added controlled mode props - modules/widgets/src/reset-view-widget.tsx: Combined multi-view loop with onReset callback - modules/widgets/src/stats-widget.tsx: Used dropdown button with corrected variable name Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| */ | ||
| getCollapsed(): boolean { | ||
| return this.props.collapsed ?? this._collapsed; | ||
| } |
There was a problem hiding this comment.
Constructor sets wrong property name for collapsed state
High Severity
The internal state property was renamed from collapsed to _collapsed (line 85), but the constructor assignment on line 100 still writes to this.collapsed instead of this._collapsed. This creates a stray dynamic property on the instance that nothing reads, while _collapsed retains its default value of true. As a result, getCollapsed() always returns true in uncontrolled mode, completely breaking the defaultIsExpanded prop — the widget will always start collapsed regardless of the setting.
Additional Locations (1)
| } else if (!props.playing && this._playing) { | ||
| this._stopTimer(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Initial controlled playing: true never starts the timer
Medium Severity
When a TimelineWidget is created with playing: true in controlled mode, the playback timer never starts. In setProps, the change detection compares props.playing against prevPlaying captured from this.props — but since the constructor already merged props via super(props), both values are true, so the condition props.playing !== prevPlaying is always false on initial setup. Additionally, onAdd unconditionally resets _playing to false. The UI correctly shows "Pause" (via getPlaying()), but time never advances because _startTimer() is never called.


Summary
Implements controlled/uncontrolled component pattern for 12 deck.gl widgets, enabling applications to drive widget state from external state management. Adds state props, getter methods, and event callbacks.
Change List
Closes #9964
Note
High Risk
Touches state/interaction logic across many widgets (fullscreen, theming, timeline playback, view selection/splitting, navigation), so regressions in UI behavior and state sync are plausible. The
StatsWidgetrefactor appears to leave athis.collapsedassignment despite removing the field, which may be a TypeScript/build break if not corrected.Overview
Widgets can now run in controlled mode: several widgets accept new state props (e.g.
themeMode,fullscreen,collapsed,time/playing,viewMode,split) and expose getters so apps can drive widget UI from external state.Adds new event hooks for user-driven changes such as
onFullscreenChange,onThemeModeChange,onCollapsedChange,onPlayingChange, and action callbacks likeonZoom,onCompassReset,onGimbalReset,onGeocode,onReset, andonLoadingChange.Docs are updated across widget API pages plus an
overview.mdsection explaining controlled vs uncontrolled patterns.Written by Cursor Bugbot for commit 66d4315. This will update automatically on new commits. Configure here.