rustyle_css/components/
tooltip.rs

1//! Tooltip component styles
2//!
3//! Provides type-safe tooltip styling with variants and positions.
4
5use super::{ComponentStyle, Variant};
6use crate::css::{Color, Radius, Spacing};
7use crate::tokens::{BorderTokens, ColorTokens, SpacingTokens};
8
9/// Tooltip position
10#[derive(Clone, Debug)]
11pub enum TooltipPosition {
12    Top,
13    Bottom,
14    Left,
15    Right,
16}
17
18/// Tooltip style configuration
19#[derive(Clone, Debug)]
20pub struct TooltipStyle {
21    pub variant: Variant,
22    pub position: TooltipPosition,
23    pub tokens: Option<TooltipTokens>,
24}
25
26/// Tooltip design tokens
27#[derive(Clone, Debug)]
28pub struct TooltipTokens {
29    pub colors: ColorTokens,
30    pub spacing: SpacingTokens,
31    pub borders: BorderTokens,
32}
33
34impl TooltipStyle {
35    /// Create a new tooltip style
36    pub fn new(variant: Variant, position: TooltipPosition) -> Self {
37        Self {
38            variant,
39            position,
40            tokens: None,
41        }
42    }
43
44    /// Set custom tokens
45    pub fn tokens(mut self, tokens: TooltipTokens) -> Self {
46        self.tokens = Some(tokens);
47        self
48    }
49
50    fn background_color(&self) -> Color {
51        let default_colors = ColorTokens::default();
52        let colors = self
53            .tokens
54            .as_ref()
55            .map(|t| &t.colors)
56            .unwrap_or(&default_colors);
57
58        match &self.variant {
59            Variant::Primary => colors.primary.c600.clone(),
60            Variant::Secondary => colors.secondary.c600.clone(),
61            Variant::Success => colors.semantic.success.clone(),
62            Variant::Error => colors.semantic.error.clone(),
63            Variant::Warning => colors.semantic.warning.clone(),
64            Variant::Info => colors.semantic.info.clone(),
65        }
66    }
67
68    fn text_color(&self) -> Color {
69        Color::named("white")
70    }
71
72    fn padding(&self) -> Spacing {
73        let default_spacing = SpacingTokens::default();
74        let spacing = self
75            .tokens
76            .as_ref()
77            .map(|t| &t.spacing)
78            .unwrap_or(&default_spacing);
79
80        Spacing::vh(spacing.xs.clone(), spacing.sm.clone())
81    }
82
83    fn border_radius(&self) -> Radius {
84        let default_borders = BorderTokens::default();
85        let borders = self
86            .tokens
87            .as_ref()
88            .map(|t| &t.borders)
89            .unwrap_or(&default_borders);
90
91        Radius::all(borders.radius.sm.clone())
92    }
93}
94
95impl ComponentStyle for TooltipStyle {
96    fn to_css(&self) -> String {
97        let mut css = String::new();
98
99        css.push_str(&format!(
100            "background-color: {}; ",
101            self.background_color().to_css()
102        ));
103        css.push_str(&format!("color: {}; ", self.text_color().to_css()));
104        css.push_str(&format!("padding: {}; ", self.padding().to_css()));
105        css.push_str(&format!(
106            "border-radius: {}; ",
107            self.border_radius().to_css()
108        ));
109        css.push_str("position: absolute; ");
110        css.push_str("z-index: 1000; ");
111        css.push_str("pointer-events: none; ");
112        css.push_str("white-space: nowrap; ");
113        css.push_str(
114            "box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); ",
115        );
116
117        // Position-specific styles
118        match &self.position {
119            TooltipPosition::Top => {
120                css.push_str("bottom: 100%; ");
121                css.push_str("left: 50%; ");
122                css.push_str("transform: translateX(-50%); ");
123                css.push_str("margin-bottom: 5px; ");
124            }
125            TooltipPosition::Bottom => {
126                css.push_str("top: 100%; ");
127                css.push_str("left: 50%; ");
128                css.push_str("transform: translateX(-50%); ");
129                css.push_str("margin-top: 5px; ");
130            }
131            TooltipPosition::Left => {
132                css.push_str("right: 100%; ");
133                css.push_str("top: 50%; ");
134                css.push_str("transform: translateY(-50%); ");
135                css.push_str("margin-right: 5px; ");
136            }
137            TooltipPosition::Right => {
138                css.push_str("left: 100%; ");
139                css.push_str("top: 50%; ");
140                css.push_str("transform: translateY(-50%); ");
141                css.push_str("margin-left: 5px; ");
142            }
143        }
144
145        css
146    }
147
148    fn class_name(&self) -> &str {
149        "rustyle-tooltip"
150    }
151}
152
153impl Default for TooltipStyle {
154    fn default() -> Self {
155        Self::new(Variant::Primary, TooltipPosition::Top)
156    }
157}