dioxus_ui_system/molecules/
tooltip.rs1use dioxus::prelude::*;
6use crate::theme::{use_theme, use_style};
7use crate::styles::Style;
8
9#[derive(Props, Clone, PartialEq)]
11pub struct TooltipProps {
12 pub children: Element,
14 pub content: String,
16 #[props(default)]
18 pub placement: TooltipPlacement,
19 #[props(default = 200)]
21 pub delay: u64,
22 #[props(default)]
24 pub style: Option<String>,
25}
26
27#[derive(Default, Clone, PartialEq)]
29pub enum TooltipPlacement {
30 #[default]
32 Top,
33 TopStart,
35 TopEnd,
37 Right,
39 RightStart,
41 RightEnd,
43 Bottom,
45 BottomStart,
47 BottomEnd,
49 Left,
51 LeftStart,
53 LeftEnd,
55}
56
57#[component]
59pub fn Tooltip(props: TooltipProps) -> Element {
60 let _theme = use_theme();
61 let mut is_visible = use_signal(|| false);
62 let show_timeout = use_signal(|| None::<i32>);
63
64 let position_style = match props.placement {
65 TooltipPlacement::Top => "bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);",
66 TooltipPlacement::TopStart => "bottom: calc(100% + 6px); left: 0;",
67 TooltipPlacement::TopEnd => "bottom: calc(100% + 6px); right: 0;",
68 TooltipPlacement::Right => "left: calc(100% + 6px); top: 50%; transform: translateY(-50%);",
69 TooltipPlacement::RightStart => "left: calc(100% + 6px); top: 0;",
70 TooltipPlacement::RightEnd => "left: calc(100% + 6px); bottom: 0;",
71 TooltipPlacement::Bottom => "top: calc(100% + 6px); left: 50%; transform: translateX(-50%);",
72 TooltipPlacement::BottomStart => "top: calc(100% + 6px); left: 0;",
73 TooltipPlacement::BottomEnd => "top: calc(100% + 6px); right: 0;",
74 TooltipPlacement::Left => "right: calc(100% + 6px); top: 50%; transform: translateY(-50%);",
75 TooltipPlacement::LeftStart => "right: calc(100% + 6px); top: 0;",
76 TooltipPlacement::LeftEnd => "right: calc(100% + 6px); bottom: 0;",
77 };
78
79 let tooltip_style = use_style(|t| {
80 Style::new()
81 .absolute()
82 .px(&t.spacing, "sm")
83 .py(&t.spacing, "xs")
84 .rounded(&t.radius, "md")
85 .bg(&t.colors.foreground)
86 .text_color(&t.colors.background)
87 .font_size(12)
88 .font_weight(500)
89 .whitespace_nowrap()
90 .z_index(100)
91 .build()
92 });
93
94 let mut show_tooltip = move || {
95 is_visible.set(true);
99 };
100
101 let mut hide_tooltip = move || {
102 if let Some(timeout) = show_timeout() {
103 let _ = timeout;
105 }
106 is_visible.set(false);
107 };
108
109 rsx! {
110 span {
111 style: "position: relative; display: inline-block;",
112 onmouseenter: move |_| show_tooltip(),
113 onmouseleave: move |_| hide_tooltip(),
114 onfocus: move |_| show_tooltip(),
115 onblur: move |_| hide_tooltip(),
116
117 {props.children}
118
119 if is_visible() {
120 div {
121 role: "tooltip",
122 style: "{tooltip_style} {position_style} {props.style.clone().unwrap_or_default()}",
123 "{props.content}"
124 }
125 }
126 }
127 }
128}
129
130#[derive(Props, Clone, PartialEq)]
132pub struct SimpleTooltipProps {
133 pub children: Element,
135 pub text: String,
137 #[props(default)]
139 pub placement: TooltipPlacement,
140}
141
142#[component]
144pub fn SimpleTooltip(props: SimpleTooltipProps) -> Element {
145 rsx! {
146 Tooltip {
147 content: props.text,
148 placement: props.placement,
149 {props.children}
150 }
151 }
152}