use dioxus::prelude::*;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum TooltipPlacement {
#[default]
Top,
Bottom,
Start,
End,
}
#[derive(Clone, PartialEq, Props)]
pub struct TooltipProps {
pub text: String,
#[props(default)]
pub placement: TooltipPlacement,
#[props(default)]
pub class: String,
pub children: Element,
}
#[component]
pub fn Tooltip(props: TooltipProps) -> Element {
let hovering = use_signal(|| false);
let is_hovering = *hovering.read();
let mut hover_signal = hovering;
let placement_class = match props.placement {
TooltipPlacement::Top => "bs-tooltip-top",
TooltipPlacement::Bottom => "bs-tooltip-bottom",
TooltipPlacement::Start => "bs-tooltip-start",
TooltipPlacement::End => "bs-tooltip-end",
};
let tooltip_class = if props.class.is_empty() {
format!("tooltip fade {placement_class} show")
} else {
format!("tooltip fade {placement_class} show {}", props.class)
};
let position_style = match props.placement {
TooltipPlacement::Top => {
"position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 0.4rem;"
}
TooltipPlacement::Bottom => {
"position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 0.4rem;"
}
TooltipPlacement::Start => {
"position: absolute; right: 100%; top: 50%; transform: translateY(-50%); margin-right: 0.4rem;"
}
TooltipPlacement::End => {
"position: absolute; left: 100%; top: 50%; transform: translateY(-50%); margin-left: 0.4rem;"
}
};
let arrow_placement = match props.placement {
TooltipPlacement::Top => "bottom: -6px; left: 50%; transform: translateX(-50%);",
TooltipPlacement::Bottom => "top: -6px; left: 50%; transform: translateX(-50%);",
TooltipPlacement::Start => "right: -6px; top: 50%; transform: translateY(-50%);",
TooltipPlacement::End => "left: -6px; top: 50%; transform: translateY(-50%);",
};
rsx! {
div {
style: "position: relative; display: inline-block;",
onmouseenter: move |_| hover_signal.set(true),
onmouseleave: move |_| hover_signal.set(false),
{props.children}
if is_hovering {
div {
class: "{tooltip_class}",
role: "tooltip",
style: "{position_style} z-index: 1080; pointer-events: none; white-space: nowrap;",
div { class: "tooltip-arrow", style: "position: absolute; {arrow_placement}" }
div { class: "tooltip-inner", "{props.text}" }
}
}
}
}
}