fix(color_picker): reveal scrollable palettes - #65
Merged
Conversation
The capped swatch grid gives no visible sign that more colors exist. Reuse the Moon scrollbar with always-visible overflow feedback, keeping its track clear of swatches inside the existing popup width and cap. Request a frame when measured scroll metrics change so opening the palette exposes its scrollbar without waiting for pointer interaction.
kirillDevPro
added a commit
to Moonbot-Tech/MoonTerminal
that referenced
this pull request
Sep 11, 2026
* feat(colors): share the custom HEX history across every picker A colour typed into a picker's HEX field was remembered only by the Badges settings tab, which kept its own reuse list inside the portable badges.json. Every other picker -- core colour, strategy colour fields, order lines, chart figures, labels, the arbitrage editor, News tags -- made the user retype the same shade from its code each time, so a personal colour scheme drifted apart across the surfaces it exists to tie together. The history now lives in its own cfg/custom_colors.json, owned by moon-core, and every picker seeds from and writes to one app-global entity. It stays most-recent-first, de-duped, and capped at 20 to match MoonUI's own MAX_CUSTOM_COLORS, above which a seeded list is silently trimmed. It is deliberately not an AppConfig field: remembering a colour is immediate app-local state, so pressing Cancel in Settings cannot roll it back and pressing Save is not required to keep it. An existing badges.json list is imported once, the first time the new file is absent, and is left in place afterwards so a downgrade still finds it. BadgesConfig::custom_colors therefore survives as migration-only data rather than a live reuse list. A corrupt badges.json imports as empty rather than failing, because the new file is never created on the error path and a hard error would leave the history unpersisted on every later launch too. Claude-Session: https://claude.ai/code/session_017mwXJTSXLJdEMfjXSvWpS4 * build(deps): bump MoonUI to 022d4c8 for the picker scrollbar Picks up Moonbot-Tech/MoonUI#65, which gives MoonColorPicker's swatch grid a visible scrollbar. The terminal hands that picker 65 swatches plus up to 20 remembered custom colours -- 17 rows against a budget of about five -- so without it the palette looked like only the rows that happened to fit. Only the MoonUI packages move; the MoonProtoBeta pin is unchanged. Claude-Session: https://claude.ai/code/session_017mwXJTSXLJdEMfjXSvWpS4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
MoonColorPicker's swatch grid is capped atGRID_MAX_HEIGHT_UI(~5 rows) and scrolls, butnothing on screen says so. Consumers that hand it a long palette are the ones that suffer:
MoonTerminal passes 65 swatches (13 rows) plus up to 20 remembered custom colours, so users
believe the palette is only the five rows they can see and never reach the rest.
The grid now carries an automatic vertical scrollbar built from the crate's existing
moon_scrollbar_overlay_with_palette/MOON_SCROLLBAR_TRACK/ScrollHandleprimitives. It ishonest: the overlay only builds a track when there is actually overflow, so a short palette (the
built-in 10-colour default) shows nothing.
Three details worth a reviewer's eye:
The arithmetic is exact —
4*6 = 24before,4*4 + 8 = 24after — so column width is unchangedat every UI scale. It is unconditional on purpose: a palette that gains the scrollbar the moment
a custom colour crosses the overflow threshold would otherwise visibly jump.
ScrollHandle's bounds andmax_offsetonly becomeavailable during prepaint, after the overlay has rendered, so a prepaint hook requests one
animation frame when they differ from what render saw. This is the same measure-then-refresh
idiom already used in
popover.rs, via the crate's ownElementExt::on_prepaint.custom_colors,set_custom_colors,customandMoonColorPickerEvent::CustomAddedall keep their signatures, and no caller needs a change.Raised by a MoonTerminal tester; the other half of that report (remembering typed HEX colours
app-wide) is a MoonTerminal-side change and needs nothing from this PR.
How to verify
cargo test -p moon-ui-components— 454 passing, including the existing colour-picker tests.cargo fmt --all -- --checkandcargo clippy -p moon-ui-components --all-targets --no-depsareclean for the edited file; the pre-existing warnings elsewhere in the crate are untouched.
Visually: open a
MoonColorPickerwith a palette longer than five rows and confirm the scrollbaris visible on open without interaction, and absent on the built-in default palette.
Not verified: a rendered pass across all three bundled themes and several UI scales, and
window-edge placements. The change uses only
tokens.ui(..)and palette colours, but no human haslooked at it on screen yet.
https://claude.ai/code/session_017mwXJTSXLJdEMfjXSvWpS4