gpui_ui_kit/
tooltip.rs

1//! Tooltip component
2//!
3//! Contextual information displayed on hover.
4
5use gpui::prelude::*;
6use gpui::*;
7
8/// Tooltip placement
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum TooltipPlacement {
11    /// Above the target
12    #[default]
13    Top,
14    /// Below the target
15    Bottom,
16    /// Left of the target
17    Left,
18    /// Right of the target
19    Right,
20}
21
22/// A tooltip component
23/// Note: Actual hover behavior requires state management in the parent
24pub struct Tooltip {
25    content: SharedString,
26    placement: TooltipPlacement,
27    delay_ms: u32,
28}
29
30impl Tooltip {
31    /// Create a new tooltip
32    pub fn new(content: impl Into<SharedString>) -> Self {
33        Self {
34            content: content.into(),
35            placement: TooltipPlacement::default(),
36            delay_ms: 200,
37        }
38    }
39
40    /// Set placement
41    pub fn placement(mut self, placement: TooltipPlacement) -> Self {
42        self.placement = placement;
43        self
44    }
45
46    /// Set delay in milliseconds
47    pub fn delay(mut self, delay_ms: u32) -> Self {
48        self.delay_ms = delay_ms;
49        self
50    }
51
52    /// Build the tooltip element (to be positioned by parent)
53    pub fn build(self) -> Div {
54        let mut tooltip = div()
55            .absolute()
56            .px_2()
57            .py_1()
58            .bg(rgb(0x1a1a1a))
59            .border_1()
60            .border_color(rgb(0x3a3a3a))
61            .rounded(px(4.0))
62            .shadow_lg()
63            .text_xs()
64            .text_color(rgb(0xffffff))
65            .whitespace_nowrap();
66
67        // Position based on placement
68        match self.placement {
69            TooltipPlacement::Top => {
70                tooltip = tooltip.bottom_full().left_0().mb_1();
71            }
72            TooltipPlacement::Bottom => {
73                tooltip = tooltip.top_full().left_0().mt_1();
74            }
75            TooltipPlacement::Left => {
76                tooltip = tooltip.right_full().top_0().mr_1();
77            }
78            TooltipPlacement::Right => {
79                tooltip = tooltip.left_full().top_0().ml_1();
80            }
81        }
82
83        tooltip.child(self.content)
84    }
85}
86
87impl IntoElement for Tooltip {
88    type Element = Div;
89
90    fn into_element(self) -> Self::Element {
91        self.build()
92    }
93}
94
95/// A wrapper that shows tooltip on hover
96/// Note: Requires state management for hover tracking
97pub struct WithTooltip {
98    child: AnyElement,
99    tooltip: SharedString,
100    placement: TooltipPlacement,
101    show_tooltip: bool,
102}
103
104impl WithTooltip {
105    /// Create a new tooltip wrapper
106    pub fn new(child: impl IntoElement, tooltip: impl Into<SharedString>) -> Self {
107        Self {
108            child: child.into_any_element(),
109            tooltip: tooltip.into(),
110            placement: TooltipPlacement::default(),
111            show_tooltip: false,
112        }
113    }
114
115    /// Set placement
116    pub fn placement(mut self, placement: TooltipPlacement) -> Self {
117        self.placement = placement;
118        self
119    }
120
121    /// Set whether tooltip is visible (controlled mode)
122    pub fn show(mut self, show: bool) -> Self {
123        self.show_tooltip = show;
124        self
125    }
126
127    /// Build into element
128    pub fn build(self) -> Div {
129        let mut container = div().relative().child(self.child);
130
131        if self.show_tooltip {
132            container =
133                container.child(Tooltip::new(self.tooltip).placement(self.placement).build());
134        }
135
136        container
137    }
138}
139
140impl IntoElement for WithTooltip {
141    type Element = Div;
142
143    fn into_element(self) -> Self::Element {
144        self.build()
145    }
146}