Skip to content

Add chartDivergingColors theming config option#13581

Merged
sfc-gh-mbarnes merged 10 commits intodevelopfrom
diverging-colors-2
Jan 15, 2026
Merged

Add chartDivergingColors theming config option#13581
sfc-gh-mbarnes merged 10 commits intodevelopfrom
diverging-colors-2

Conversation

@mayagbarnes
Copy link
Copy Markdown
Collaborator

Describe your changes

Adding a config option chartDivergingColors for [theme] that controls the diverging colors passed to ArrowVegaLightChart & PlotlyChart components.

These impact our built-in chart commands (st.line_chart, st.area_chart, st.bar_chart, & st.scatter_chart) as well as st.vega_lite_chart, st.altair_chart, and st.plotly_chart

Note: In order to support diverging color config consistent with other chart color configs, the plotly diverging template was updated from 11 placeholders to 10. This does not change existing behavior since we were only providing 10 colors to slot into the 11 placeholders in our default diverging colors array.

Testing Plan

  • Unit Tests (JS & Python): ✅ Added
  • E2E Tests: ✅ Added
  • Manual Testing: ✅

@mayagbarnes mayagbarnes added security-assessment-completed change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users labels Jan 14, 2026
@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Jan 14, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 14, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13581/streamlit-1.53.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13581.streamlit.app (☁️ Deploy here if not accessible)

@mayagbarnes mayagbarnes marked this pull request as ready for review January 14, 2026 09:46
@mayagbarnes mayagbarnes requested a review from a team as a code owner January 14, 2026 09:46
Copilot AI review requested due to automatic review settings January 14, 2026 09:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds a new chartDivergingColors theming configuration option that allows users to customize the diverging color scale used in Streamlit charts. The feature applies to built-in chart commands (st.line_chart, st.area_chart, st.bar_chart, st.scatter_chart) as well as st.vega_lite_chart, st.altair_chart, and st.plotly_chart. The PR also updates the Plotly diverging template from 11 to 10 color placeholders to maintain consistency with other color configurations.

Changes:

  • Added chartDivergingColors configuration option to theme settings (protobuf, Python config, frontend theme)
  • Refactored chart color parsing logic in Python backend to eliminate code duplication
  • Updated Plotly and Vega-Lite chart components to use the new diverging colors
  • Added comprehensive test coverage (Python unit tests, TypeScript unit tests, and E2E tests)

Reviewed changes

Copilot reviewed 18 out of 24 changed files in this pull request and generated no comments.

Show a summary per file
File Description
proto/streamlit/proto/NewSession.proto Added chart_diverging_colors field to CustomThemeConfig message
lib/streamlit/config.py Added chartDivergingColors theme configuration option with documentation
lib/streamlit/runtime/app_session.py Refactored chart color parsing into reusable function and added diverging colors support
lib/streamlit/elements/lib/streamlit_plotly_theme.py Updated Plotly template from 11 to 10 diverging color placeholders
frontend/lib/src/theme/utils.ts Added validation and handling for chartDivergingColors in theme creation
frontend/lib/src/theme/getColors.ts Added default diverging colors array to theme colors
frontend/lib/src/components/elements/PlotlyChart/CustomTheme.tsx Updated to use theme's chartDivergingColors and removed unused function
frontend/lib/src/components/elements/ArrowVegaLiteChart/CustomTheme.tsx Updated to use theme's chartDivergingColors from theme object
frontend/component-v2-lib/src/theme.ts Added chartDivergingColors to StreamlitTheme interface
e2e_playwright/theming/theme_chart_colors_test.py Added E2E test configuration for diverging colors
e2e_playwright/theming/theme_chart_colors_app.py Added test scenarios for Altair and Plotly diverging color charts
Test files Comprehensive unit and E2E test coverage for the new feature

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 14, 2026

📈 Python coverage change detected

The Python unit test coverage has increased by 0.0237%

  • Current PR: 92.4269% (22778 statements, 1725 missed)
  • Latest develop: 92.4032% (22786 statements, 1731 missed)

✅ Coverage change is within normal range.

Coverage by files
Name Stmts Miss Cover
streamlit/__init__.py 137 0 100%
streamlit/__main__.py 3 3 0%
streamlit/auth_util.py 201 35 83%
streamlit/cli_util.py 39 6 85%
streamlit/column_config.py 3 0 100%
streamlit/commands/__init__.py 0 0 100%
streamlit/commands/echo.py 54 11 80%
streamlit/commands/execution_control.py 70 10 86%
streamlit/commands/logo.py 41 6 85%
streamlit/commands/navigation.py 106 2 98%
streamlit/commands/page_config.py 106 4 96%
streamlit/components/__init__.py 0 0 100%
streamlit/components/lib/__init__.py 0 0 100%
streamlit/components/lib/local_component_registry.py 35 2 94%
streamlit/components/types/__init__.py 0 0 100%
streamlit/components/types/base_component_registry.py 14 0 100%
streamlit/components/types/base_custom_component.py 49 6 88%
streamlit/components/v1/__init__.py 5 0 100%
streamlit/components/v1/component_arrow.py 33 8 76%
streamlit/components/v1/component_registry.py 41 3 93%
streamlit/components/v1/components.py 4 4 0%
streamlit/components/v1/custom_component.py 85 7 92%
streamlit/components/v2/__init__.py 27 0 100%
streamlit/components/v2/bidi_component/__init__.py 4 0 100%
streamlit/components/v2/bidi_component/constants.py 5 0 100%
streamlit/components/v2/bidi_component/main.py 148 17 89%
streamlit/components/v2/bidi_component/serialization.py 81 2 98%
streamlit/components/v2/bidi_component/state.py 13 0 100%
streamlit/components/v2/component_definition_resolver.py 30 0 100%
streamlit/components/v2/component_file_watcher.py 117 9 92%
streamlit/components/v2/component_manager.py 97 13 87%
streamlit/components/v2/component_manifest_handler.py 24 0 100%
streamlit/components/v2/component_path_utils.py 68 5 93%
streamlit/components/v2/component_registry.py 121 8 93%
streamlit/components/v2/get_bidi_component_manager.py 8 1 88%
streamlit/components/v2/manifest_scanner.py 224 25 89%
streamlit/components/v2/presentation.py 84 19 77%
streamlit/components/v2/types.py 8 8 0%
streamlit/config.py 415 12 97%
streamlit/config_option.py 79 3 96%
streamlit/config_util.py 288 7 98%
streamlit/connections/__init__.py 6 0 100%
streamlit/connections/base_connection.py 49 0 100%
streamlit/connections/snowflake_connection.py 97 18 81%
streamlit/connections/snowpark_connection.py 44 3 93%
streamlit/connections/sql_connection.py 56 6 89%
streamlit/connections/util.py 33 0 100%
streamlit/cursor.py 130 1 99%
streamlit/dataframe_util.py 506 51 90%
streamlit/delta_generator.py 250 7 97%
streamlit/delta_generator_singletons.py 74 7 91%
streamlit/deprecation_util.py 59 4 93%
streamlit/development.py 1 0 100%
streamlit/elements/__init__.py 0 0 100%
streamlit/elements/alert.py 60 0 100%
streamlit/elements/arrow.py 201 15 93%
streamlit/elements/balloons.py 10 0 100%
streamlit/elements/bokeh_chart.py 9 0 100%
streamlit/elements/code.py 20 1 95%
streamlit/elements/deck_gl_json_chart.py 104 10 90%
streamlit/elements/dialog_decorator.py 38 0 100%
streamlit/elements/doc_string.py 227 9 96%
streamlit/elements/empty.py 16 4 75%
streamlit/elements/exception.py 101 10 90%
streamlit/elements/form.py 56 2 96%
streamlit/elements/graphviz_chart.py 36 1 97%
streamlit/elements/heading.py 56 0 100%
streamlit/elements/html.py 49 0 100%
streamlit/elements/iframe.py 29 0 100%
streamlit/elements/image.py 32 0 100%
streamlit/elements/json.py 48 6 88%
streamlit/elements/layouts.py 140 3 98%
streamlit/elements/lib/__init__.py 0 0 100%
streamlit/elements/lib/built_in_chart_utils.py 391 26 93%
streamlit/elements/lib/color_util.py 100 4 96%
streamlit/elements/lib/column_config_utils.py 169 1 99%
streamlit/elements/lib/column_types.py 190 4 98%
streamlit/elements/lib/dialog.py 69 1 99%
streamlit/elements/lib/dicttools.py 39 2 95%
streamlit/elements/lib/file_uploader_utils.py 30 0 100%
streamlit/elements/lib/form_utils.py 26 0 100%
streamlit/elements/lib/image_utils.py 176 21 88%
streamlit/elements/lib/js_number.py 28 3 89%
streamlit/elements/lib/layout_utils.py 121 1 99%
streamlit/elements/lib/mutable_status_container.py 73 4 95%
streamlit/elements/lib/options_selector_utils.py 119 0 100%
streamlit/elements/lib/pandas_styler_utils.py 80 2 98%
streamlit/elements/lib/policies.py 56 1 98%
streamlit/elements/lib/shortcut_utils.py 42 2 95%
streamlit/elements/lib/streamlit_plotly_theme.py 48 0 100%
streamlit/elements/lib/subtitle_utils.py 76 13 83%
streamlit/elements/lib/utils.py 76 5 93%
streamlit/elements/map.py 110 1 99%
streamlit/elements/markdown.py 65 2 97%
streamlit/elements/media.py 181 8 96%
streamlit/elements/metric.py 104 0 100%
streamlit/elements/pdf.py 49 2 96%
streamlit/elements/plotly_chart.py 129 6 95%
streamlit/elements/progress.py 36 0 100%
streamlit/elements/pyplot.py 39 2 95%
streamlit/elements/snow.py 10 0 100%
streamlit/elements/space.py 12 0 100%
streamlit/elements/spinner.py 44 3 93%
streamlit/elements/text.py 16 0 100%
streamlit/elements/toast.py 26 0 100%
streamlit/elements/vega_charts.py 238 3 99%
streamlit/elements/widgets/__init__.py 0 0 100%
streamlit/elements/widgets/audio_input.py 68 10 85%
streamlit/elements/widgets/button.py 245 6 98%
streamlit/elements/widgets/button_group.py 171 1 99%
streamlit/elements/widgets/camera_input.py 62 10 84%
streamlit/elements/widgets/chat.py 237 58 76%
streamlit/elements/widgets/checkbox.py 52 0 100%
streamlit/elements/widgets/color_picker.py 59 2 97%
streamlit/elements/widgets/data_editor.py 254 14 94%
streamlit/elements/widgets/file_uploader.py 108 18 83%
streamlit/elements/widgets/multiselect.py 109 2 98%
streamlit/elements/widgets/number_input.py 146 4 97%
streamlit/elements/widgets/radio.py 83 5 94%
streamlit/elements/widgets/select_slider.py 97 0 100%
streamlit/elements/widgets/selectbox.py 95 1 99%
streamlit/elements/widgets/slider.py 241 8 97%
streamlit/elements/widgets/text_widgets.py 130 6 95%
streamlit/elements/widgets/time_widgets.py 390 19 95%
streamlit/elements/write.py 166 32 81%
streamlit/emojis.py 4 0 100%
streamlit/env_util.py 21 3 86%
streamlit/error_util.py 33 2 94%
streamlit/errors.py 191 25 87%
streamlit/external/__init__.py 0 0 100%
streamlit/external/langchain/__init__.py 2 0 100%
streamlit/external/langchain/streamlit_callback_handler.py 141 82 42%
streamlit/file_util.py 84 8 90%
streamlit/git_util.py 100 5 95%
streamlit/logger.py 54 0 100%
streamlit/material_icon_names.py 1 0 100%
streamlit/navigation/__init__.py 0 0 100%
streamlit/navigation/page.py 78 2 97%
streamlit/net_util.py 55 3 95%
streamlit/platform.py 10 1 90%
streamlit/runtime/__init__.py 8 0 100%
streamlit/runtime/app_session.py 457 86 81%
streamlit/runtime/caching/__init__.py 21 0 100%
streamlit/runtime/caching/cache_data_api.py 191 3 98%
streamlit/runtime/caching/cache_errors.py 45 4 91%
streamlit/runtime/caching/cache_resource_api.py 165 1 99%
streamlit/runtime/caching/cache_type.py 11 1 91%
streamlit/runtime/caching/cache_utils.py 176 9 95%
streamlit/runtime/caching/cached_message_replay.py 108 1 99%
streamlit/runtime/caching/hashing.py 311 25 92%
streamlit/runtime/caching/legacy_cache_api.py 14 0 100%
streamlit/runtime/caching/storage/__init__.py 2 0 100%
streamlit/runtime/caching/storage/cache_storage_protocol.py 31 2 94%
streamlit/runtime/caching/storage/dummy_cache_storage.py 21 0 100%
streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py 67 1 99%
streamlit/runtime/caching/storage/local_disk_cache_storage.py 86 4 95%
streamlit/runtime/caching/ttl_cleanup_cache.py 28 0 100%
streamlit/runtime/connection_factory.py 96 11 89%
streamlit/runtime/context.py 137 0 100%
streamlit/runtime/context_util.py 18 0 100%
streamlit/runtime/credentials.py 139 4 97%
streamlit/runtime/download_data_util.py 27 0 100%
streamlit/runtime/forward_msg_cache.py 23 2 91%
streamlit/runtime/forward_msg_queue.py 63 4 94%
streamlit/runtime/fragment.py 112 2 98%
streamlit/runtime/media_file_manager.py 110 7 94%
streamlit/runtime/media_file_storage.py 15 0 100%
streamlit/runtime/memory_media_file_storage.py 73 0 100%
streamlit/runtime/memory_session_storage.py 15 0 100%
streamlit/runtime/memory_uploaded_file_manager.py 46 1 98%
streamlit/runtime/metrics_util.py 195 13 93%
streamlit/runtime/pages_manager.py 59 2 97%
streamlit/runtime/runtime.py 253 16 94%
streamlit/runtime/runtime_util.py 30 1 97%
streamlit/runtime/script_data.py 16 0 100%
streamlit/runtime/scriptrunner/__init__.py 5 0 100%
streamlit/runtime/scriptrunner/exec_code.py 49 5 90%
streamlit/runtime/scriptrunner/magic.py 83 1 99%
streamlit/runtime/scriptrunner/magic_funcs.py 10 1 90%
streamlit/runtime/scriptrunner/script_cache.py 27 0 100%
streamlit/runtime/scriptrunner/script_runner.py 230 27 88%
streamlit/runtime/scriptrunner_utils/__init__.py 0 0 100%
streamlit/runtime/scriptrunner_utils/exceptions.py 11 1 91%
streamlit/runtime/scriptrunner_utils/script_requests.py 106 5 95%
streamlit/runtime/scriptrunner_utils/script_run_context.py 123 2 98%
streamlit/runtime/secrets.py 242 26 89%
streamlit/runtime/session_manager.py 71 2 97%
streamlit/runtime/state/__init__.py 7 0 100%
streamlit/runtime/state/common.py 52 2 96%
streamlit/runtime/state/presentation.py 19 4 79%
streamlit/runtime/state/query_params.py 117 4 97%
streamlit/runtime/state/query_params_proxy.py 71 0 100%
streamlit/runtime/state/safe_session_state.py 77 9 88%
streamlit/runtime/state/session_state.py 440 33 92%
streamlit/runtime/state/session_state_proxy.py 62 8 87%
streamlit/runtime/state/widgets.py 15 1 93%
streamlit/runtime/stats.py 139 11 92%
streamlit/runtime/theme_util.py 46 1 98%
streamlit/runtime/uploaded_file_manager.py 39 3 92%
streamlit/runtime/websocket_session_manager.py 116 0 100%
streamlit/source_util.py 36 1 97%
streamlit/starlette.py 2 0 100%
streamlit/string_util.py 93 9 90%
streamlit/temporary_directory.py 18 1 94%
streamlit/testing/__init__.py 0 0 100%
streamlit/testing/v1/__init__.py 2 0 100%
streamlit/testing/v1/app_test.py 242 6 98%
streamlit/testing/v1/element_tree.py 1371 87 94%
streamlit/testing/v1/local_script_runner.py 71 2 97%
streamlit/testing/v1/util.py 17 0 100%
streamlit/time_util.py 28 1 96%
streamlit/type_util.py 148 16 89%
streamlit/url_util.py 39 4 90%
streamlit/user_info.py 118 10 92%
streamlit/util.py 38 1 97%
streamlit/version.py 3 0 100%
streamlit/watcher/__init__.py 3 0 100%
streamlit/watcher/event_based_path_watcher.py 181 24 87%
streamlit/watcher/folder_black_list.py 14 1 93%
streamlit/watcher/local_sources_watcher.py 127 9 93%
streamlit/watcher/path_watcher.py 42 3 93%
streamlit/watcher/polling_path_watcher.py 55 2 96%
streamlit/watcher/util.py 49 1 98%
streamlit/web/__init__.py 0 0 100%
streamlit/web/bootstrap.py 175 21 88%
streamlit/web/cache_storage_manager_config.py 5 0 100%
streamlit/web/cli.py 191 17 91%
streamlit/web/server/__init__.py 5 0 100%
streamlit/web/server/app_discovery.py 103 5 95%
streamlit/web/server/app_static_file_handler.py 29 3 90%
streamlit/web/server/authlib_tornado_integration.py 42 5 88%
streamlit/web/server/bidi_component_request_handler.py 65 8 88%
streamlit/web/server/browser_websocket_handler.py 147 36 76%
streamlit/web/server/component_file_utils.py 24 0 100%
streamlit/web/server/component_request_handler.py 55 4 93%
streamlit/web/server/media_file_handler.py 65 9 86%
streamlit/web/server/oauth_authlib_routes.py 184 38 79%
streamlit/web/server/oidc_mixin.py 46 0 100%
streamlit/web/server/routes.py 90 7 92%
streamlit/web/server/server.py 195 13 93%
streamlit/web/server/server_util.py 68 5 93%
streamlit/web/server/starlette/__init__.py 3 0 100%
streamlit/web/server/starlette/starlette_app.py 146 4 97%
streamlit/web/server/starlette/starlette_app_utils.py 101 7 93%
streamlit/web/server/starlette/starlette_auth_routes.py 201 45 78%
streamlit/web/server/starlette/starlette_gzip_middleware.py 30 0 100%
streamlit/web/server/starlette/starlette_routes.py 342 83 76%
streamlit/web/server/starlette/starlette_server.py 167 7 96%
streamlit/web/server/starlette/starlette_server_config.py 13 0 100%
streamlit/web/server/starlette/starlette_static_routes.py 64 3 95%
streamlit/web/server/starlette/starlette_websocket.py 203 23 89%
streamlit/web/server/stats_request_handler.py 59 5 92%
streamlit/web/server/upload_file_request_handler.py 59 14 76%
streamlit/web/server/websocket_headers.py 19 1 95%
TOTAL 22778 1725 92%

📊 View detailed coverage comparison

Comment on lines 323 to 325
const DIVERGING_7 = "#000028"
const DIVERGING_8 = "#000029"
const DIVERGING_9 = "#000030"
Copy link
Copy Markdown
Collaborator Author

@mayagbarnes mayagbarnes Jan 15, 2026

Choose a reason for hiding this comment

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

In order to support diverging color config consistent with other chart color configs, the plotly diverging template was updated from 11 placeholders to 10.
This does not change existing behavior since we were only providing 10 colors to slot into the 11 placeholders in our default diverging colors array anyway.
Rebalanced the default scale to account for 10 colors

@lukasmasuch lukasmasuch added the ai-review If applied to PR or issue will run AI review workflow label Jan 15, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Jan 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Summary

This PR adds a new theming config option chartDivergingColors that allows users to customize the diverging color scale used in charts (Altair, VegaLite, and Plotly). The implementation follows the existing patterns established for chartCategoricalColors and chartSequentialColors.

Key changes include:

  • New proto field chart_diverging_colors (ID 62) in CustomThemeConfig
  • Python config option theme.chartDivergingColors with validation for exactly 10 colors
  • Backend refactoring of chart color parsing into a reusable _parse_and_populate_chart_colors helper
  • Frontend theme types and validation for the new color array
  • Updated Plotly diverging template from 11 to 10 placeholders (aligning with the actual color count)
  • Comprehensive test coverage across Python unit tests, frontend tests, and E2E tests

Code Quality

Strengths:

  1. Clean refactoring: The _parse_and_populate_chart_colors helper in app_session.py (lines 1021-1071) nicely consolidates previously duplicated code for parsing categorical and sequential colors. This improves maintainability.

  2. Consistent patterns: The implementation closely follows the existing patterns for chartCategoricalColors and chartSequentialColors, making the codebase consistent and predictable.

  3. Proper validation: Both backend (Python) and frontend (TypeScript) validate that exactly 10 colors are provided, with appropriate error/warning logging when invalid.

  4. Good documentation: The config option in config.py (lines 2283-2309) includes a clear description with default color values.

Minor observations:

  1. The frontend validation in utils.ts (lines 880-899) follows the same pattern as sequential colors validation, which is good for consistency.

  2. The default diverging colors in getColors.ts (lines 265-278) use a red-to-blue scale, which is a standard choice for diverging data.

Test Coverage

Python Unit Tests:

  • config_test.py: Updated to include chartDivergingColors in theme config options
  • proto_compatibility_test.py: Added new proto field check
  • app_session_test.py: Comprehensive test data for all theme scenarios including the new diverging colors

Frontend Unit Tests:

  • theme.test.ts: Updated BidiComponent theme extraction test
  • utils.test.ts: The existing chart color validation tests cover the new diverging colors pattern

E2E Tests:

  • theme_chart_colors_app.py: Added diverging color test charts for both Altair and Plotly
  • theme_chart_colors_test.py: Updated fixture with custom diverging colors (10 colors from red to purple)
  • Updated snapshots for all browsers (chromium, firefox, webkit)

The test coverage is comprehensive and follows the best practices documented in the project guidelines.

Backwards Compatibility

Proto Changes (Safe):

  • Adding a new optional repeated field (chart_diverging_colors = 62) is backwards compatible
  • The Next ID comment was properly updated to 63

Plotly Template Change (Low Risk):

  • The Plotly diverging template changed from 11 placeholders to 10
  • The PR notes this doesn't change existing behavior since only 10 colors were ever provided
  • This is correct - the old code defined DIVERGING_10 = "#000031" but never populated it with a real color

Frontend API:

  • The new chartDivergingColors property in StreamlitTheme (component-v2-lib) is additive
  • Custom components that don't use this field will be unaffected

No breaking changes identified.

Security & Risk

No security concerns identified. The changes:

  • Only add new optional configuration fields
  • Follow existing input validation patterns
  • Don't expose any new attack surfaces

Regression risk is low because:

  • The feature is opt-in (users must explicitly configure chartDivergingColors)
  • Default behavior uses the computed default colors from the theme
  • Existing chart color functionality (chartCategoricalColors, chartSequentialColors) is unchanged

Recommendations

No blocking issues found. The PR is well-implemented and follows the established patterns.

Optional suggestions for future consideration:

  1. Consider adding a unit test specifically for the _parse_and_populate_chart_colors helper function to verify edge cases (malformed JSON, wrong length arrays, etc.), though the existing integration tests do cover these scenarios indirectly.

  2. The E2E test uses np.random.normal and np.random.uniform for generating test data in the Plotly diverging chart. For fully deterministic tests, consider adding np.random.seed() or using fixed data. However, since this is a visual snapshot test focused on colors rather than data positions, this is acceptable.

Verdict

APPROVED: This PR adds a well-implemented, backwards-compatible theming feature with comprehensive test coverage. The code follows existing patterns, includes proper validation, and poses no security or regression risks.


This is an automated AI review. Please verify the feedback and use your judgment.

Copy link
Copy Markdown

@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.

✅ Bugbot reviewed your changes and found no bugs!

Copy link
Copy Markdown
Collaborator

@lukasmasuch lukasmasuch left a comment

Choose a reason for hiding this comment

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

LGTM 👍

Copy link
Copy Markdown
Contributor

@sfc-gh-mbarnes sfc-gh-mbarnes left a comment

Choose a reason for hiding this comment

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

Echoing approval above

@sfc-gh-mbarnes sfc-gh-mbarnes merged commit d74b865 into develop Jan 15, 2026
44 checks passed
@sfc-gh-mbarnes sfc-gh-mbarnes deleted the diverging-colors-2 branch January 15, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants