Skip to content

fix(color_picker): reveal scrollable palettes - #65

Merged
kirillDevPro merged 2 commits into
masterfrom
kirillDevPro/wt-488-picker-scroll
Sep 11, 2026
Merged

fix(color_picker): reveal scrollable palettes#65
kirillDevPro merged 2 commits into
masterfrom
kirillDevPro/wt-488-picker-scroll

Conversation

@kirillDevPro

Copy link
Copy Markdown
Collaborator

What & why

MoonColorPicker's swatch grid is capped at GRID_MAX_HEIGHT_UI (~5 rows) and scrolls, but
nothing 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 / ScrollHandle primitives. It is
honest: 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 track gutter is reserved unconditionally, and the grid gap drops 6 -> 4 to pay for it.
    The arithmetic is exact — 4*6 = 24 before, 4*4 + 8 = 24 after — so column width is unchanged
    at 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.
  • Layout metrics are read one frame late. ScrollHandle's bounds and max_offset only become
    available 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 own ElementExt::on_prepaint.
  • The public API is untouchedcustom_colors, set_custom_colors, custom and
    MoonColorPickerEvent::CustomAdded all 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 -- --check and cargo clippy -p moon-ui-components --all-targets --no-deps are
clean for the edited file; the pre-existing warnings elsewhere in the crate are untouched.

Visually: open a MoonColorPicker with a palette longer than five rows and confirm the scrollbar
is 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 has
looked at it on screen yet.

https://claude.ai/code/session_017mwXJTSXLJdEMfjXSvWpS4

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
kirillDevPro merged commit 022d4c8 into master Sep 11, 2026
2 checks passed
@kirillDevPro
kirillDevPro deleted the kirillDevPro/wt-488-picker-scroll branch September 11, 2026 14:51
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
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.

1 participant