Layers panel: a hidden component row uses the faded colour, keeping the 3:1 floor (#1911 issue)

The tint at half alpha composited to about 2.4:1 (dark) and 2.2:1 (light) on the panel, under the 3:1 floor for dim text. Hidden rows now use the faded colour; shown rows keep the tint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Trevor BrownandClaude Fable 5.1 committed 2026-11-06 21:48:31 -05:00
1 parent e9098d0df3
commit 11d808833c
3 files changed
+44 -9

No files matched your search

@@ -91,3 +91,37 @@ fn rows_inside_a_selected_component_take_a_tone_of_its_row() {
assert!(!rect_under(&shapes, t.selected_row_child, label), "not the plain selection's child tone (dark {dark})");
}
}
/// The Layers panel with the component "Button" hidden and nothing selected.
fn drawn_hidden(dark: bool) -> (Vec<Shape>, Tokens) {
let mut s = Session::new();
let f = id(s.execute("frame.create", &json!({"x": 0, "y": 0, "width": 100, "height": 40, "props": {"name": "Button"}})).unwrap());
let c = id(s.execute("component.create", &json!({"ids": [f]})).unwrap());
s.execute(if dark { "view.themeDark" } else { "view.themeLight" }, &json!({})).unwrap();
s.execute("node.set", &json!({"id": c, "props": {"visible": false}})).unwrap();
s.execute("select.set", &json!({"ids": []})).unwrap();
let mut u = Ui::new(s);
u.frame(vec![]);
let shapes = crate::live_tests::flat(&u.frame_output(vec![]).shapes);
(shapes, Tokens::get(&u.ctx))
}
/// `fg` (premultiplied, as egui paints it) composited over the opaque `bg`.
fn over(fg: Color32, bg: Color32) -> Color32 {
let k = 1.0 - f32::from(fg.a()) / 255.0;
let mix = |f: u8, b: u8| (f32::from(f) + f32::from(b) * k).round().min(255.0) as u8;
Color32::from_rgb(mix(fg.r(), bg.r()), mix(fg.g(), bg.g()), mix(fg.b(), bg.b()))
}
#[test]
fn a_hidden_component_name_keeps_the_dim_text_floor_of_3_to_1() {
for dark in [false, true] {
let (shapes, t) = drawn_hidden(dark);
assert_eq!(t.dark, dark);
let col = name_colour(&shapes, "Button");
for (what, bg) in [("the panel", t.panel), ("a hovered row", t.hover)] {
let ratio = color(over(col, bg)).contrast(color(bg));
assert!(ratio >= 3.0, "hidden component name {col:?} is {ratio:.2}:1 on {what} (dark {dark})");
}
}
}
+9 -8
View File
@@ -746,16 +746,17 @@ fn is_component(kind: &NodeKind) -> bool {
matches!(kind, NodeKind::Component { .. } | NodeKind::ComponentSet { .. } | NodeKind::Instance { .. })
}
/// A row's icon or name colour: the theme's component tint (faded when hidden; it reads at AA on
/// the panel and on the selected row, where the canvas purple doesn't, #1903), else `normal` or
/// `faded`.
/// A row's icon or name colour: the theme's component tint when shown (it reads at AA on the
/// panel and on the selected row, where the canvas purple doesn't, #1903), else `normal` or, when
/// hidden, `faded` (halving the tint's alpha would drop it to about 2.2:1, under the 3:1 floor
/// for dim text).
fn row_color(t: &Tokens, component: bool, shown: bool, normal: Color32, faded: Color32) -> Color32 {
if component {
t.component.gamma_multiply(if shown { 1.0 } else { 0.5 })
} else if shown {
normal
} else {
if !shown {
faded
} else if component {
t.component
} else {
normal
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ interaction feel not yet compared.
| Item | Status | Notes |
|---|---|---|
| UI3 layout: tab strip as title bar, icon rail, file header, pages + layers, floating bottom toolbar with flyouts, Design / Prototype / Inspect panels | done | frameless window on Windows/Linux with drawn buttons; on a Wayland compositor that offers no server-side decorations (GNOME) the window gets winit's Adwaita controls instead (#592; checked by its author on GNOME, KDE not run) |
| Light and dark themes | done | colours from `theme::Tokens`; component, variant and instance rows in the Layers panel take the theme's component tint, at AA on the panel and on their selected row, and the rows inside a selected component a tone of its row (`layers_component_rows_tests`, #1903); a file or a page made while the dark theme shows gets a `#1E1E1E` page (`#F5F5F5` in the light theme), its own from then on: changing the theme repaints no page and opened files keep theirs; the file the app opens with takes the theme once it is known; the CLI, MCP and exports have no theme and keep `#F5F5F5`; text drawn with the Text tool is white on a dark page and black on a light one (so is text a command makes in the app without naming a fill; headless sessions keep black) (`theme_pages_tests`, `dark_page_text_tests`) |
| Light and dark themes | done | colours from `theme::Tokens`; component, variant and instance rows in the Layers panel take the theme's component tint, at AA on the panel and on their selected row (hidden ones in the faded text colour, at least 3:1), and the rows inside a selected component a tone of its row (`layers_component_rows_tests`, #1903); a file or a page made while the dark theme shows gets a `#1E1E1E` page (`#F5F5F5` in the light theme), its own from then on: changing the theme repaints no page and opened files keep theirs; the file the app opens with takes the theme once it is known; the CLI, MCP and exports have no theme and keep `#F5F5F5`; text drawn with the Text tool is white on a dark page and black on a light one (so is text a command makes in the app without naming a fill; headless sessions keep black) (`theme_pages_tests`, `dark_page_text_tests`) |
| UI3 layout: tab strip as title bar, icon rail, file header, pages + layers, floating bottom toolbar with flyouts, Design / Prototype / Inspect panels | done | frameless window on Windows/Linux with drawn buttons; tabs reorder by dragging along the strip, and closing one whose file has unsaved changes asks Don't Save / Cancel / Save (Alt+close drops the changes at once, #2032); on a Wayland compositor that offers no server-side decorations (GNOME) the window gets winit's Adwaita controls instead (#592; checked by its author on GNOME, KDE not run) |
| Light and dark themes | done | colours from `theme::Tokens`; a file or a page made while the dark theme shows gets a `#1E1E1E` page (`#F5F5F5` in the light theme), its own from then on: changing the theme repaints no page and opened files keep theirs; the file the app opens with takes the theme once it is known; the CLI, MCP and exports have no theme and keep `#F5F5F5`; text drawn with the Text tool is white on a dark page and black on a light one (so is text a command makes in the app without naming a fill; headless sessions keep black) (`theme_pages_tests`, `dark_page_text_tests`) |
| Minimize UI (Shift+Cmd/Ctrl+\\, the Minimize button by the file name) and Show/Hide UI (Cmd/Ctrl+\\) | done | Minimize collapses the navigation bar and both sidebars and keeps the toolbar and the panel widths; "If you select an object while the panels are minimized, the left sidebar remains minimized while the right sidebar expands [...] Once all objects are deselected, the right panel minimizes again" (Explore the navigation bar and left sidebar); a small Expand button at the top left of the canvas puts them back (FigCraft's own, the article names no control for it). Hide UI takes the toolbar too (`panel_width_tests`, `shortcuts_tests`; #1835) |