Skip to main content

native_theme_gpui/
derive.rs

1//! Shade derivation helpers for hover/active states.
2//!
3//! Provides functions to derive interactive state colors (hover,
4//! active/pressed) from base colors. Uses the [`Colorize`] trait from
5//! gpui-component for lightness adjustments.
6
7use gpui::Hsla;
8use gpui_component::Colorize;
9
10/// Derive a hover state from a base color.
11///
12/// For light themes (is_dark=false): blends the background with base at 90% opacity.
13/// For dark themes (is_dark=true): blends the background with base at 90% opacity.
14///
15/// This matches gpui-component's internal `apply_config` hover derivation:
16/// `background.blend(base.opacity(0.9))`.
17pub fn hover_color(base: Hsla, bg: Hsla) -> Hsla {
18    bg.blend(base.opacity(0.9))
19}
20
21/// Derive an active/pressed state from a base color.
22///
23/// For light themes (is_dark=false): darkens by 10%.
24/// For dark themes (is_dark=true): darkens by 20%.
25///
26/// This matches gpui-component's internal `apply_config` active derivation.
27pub fn active_color(base: Hsla, is_dark: bool) -> Hsla {
28    let factor = if is_dark { 0.2 } else { 0.1 };
29    base.darken(factor)
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35    use gpui::hsla;
36
37    #[test]
38    fn hover_color_differs_from_base() {
39        let base = hsla(0.6, 0.7, 0.5, 1.0);
40        let bg = hsla(0.0, 0.0, 1.0, 1.0); // white background
41        let result = hover_color(base, bg);
42        // hover blends base at 0.9 opacity on bg -- should differ from base
43        assert_ne!(result, base, "hover should differ from base");
44    }
45
46    #[test]
47    fn active_color_light_theme_darkens() {
48        let base = hsla(0.6, 0.7, 0.5, 1.0);
49        let result = active_color(base, false);
50        assert!(
51            result.l < base.l,
52            "active (light) l={} should be < base l={}",
53            result.l,
54            base.l
55        );
56    }
57
58    #[test]
59    fn active_color_dark_theme_darkens_more() {
60        let base = hsla(0.6, 0.7, 0.5, 1.0);
61        let light_result = active_color(base, false);
62        let dark_result = active_color(base, true);
63        assert!(
64            dark_result.l < light_result.l,
65            "dark active l={} should darken more than light active l={}",
66            dark_result.l,
67            light_result.l
68        );
69    }
70}