patternfly_yew/components/
tooltip.rs

1//! Tooltip
2use crate::prelude::{ExtendClasses, Orientation};
3use popper_rs::{prelude::*, yew::component::PortalPopper};
4use yew::prelude::*;
5
6/// Properties for [`Tooltip`]
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct TooltipProperties {
9    pub children: Html,
10    pub text: String,
11}
12
13/// Tooltip component
14///
15/// > A **tooltip** is in-app messaging used to identify elements on a page with short, clarifying text.
16///
17/// See: <https://www.patternfly.org/components/tooltip>
18///
19/// ## Properties
20///
21/// Defined by [`TooltipProperties`].
22#[function_component(Tooltip)]
23pub fn tooltip(props: &TooltipProperties) -> Html {
24    let active = use_state_eq(|| false);
25    let state = use_state_eq(State::default);
26
27    let onmouseenter = use_callback(active.clone(), |_, active| active.set(true));
28    let onmouseleave = use_callback(active.clone(), |_, active| active.set(false));
29
30    let content_ref = use_node_ref();
31    let target_ref = use_node_ref();
32
33    let onstatechange = use_callback(state.clone(), |new_state, state| state.set(new_state));
34
35    html! (
36        <>
37            <span {onmouseenter} {onmouseleave} ref={target_ref.clone()}>
38                { props.children.clone() }
39            </span>
40            <PortalPopper
41                visible={*active}
42                content={content_ref.clone()}
43                target={target_ref}
44                {onstatechange}
45                placement={Placement::Right}
46                modifiers={vec![
47                    Modifier::Offset(Offset {
48                        skidding: 0,
49                        distance: 11,
50                    }),
51                    Modifier::PreventOverflow(PreventOverflow { padding: 0 }),
52                ]}
53            >
54                <TooltipPopupContent
55                    state={(*state).clone()}
56                    text={props.text.clone()}
57                    r#ref={content_ref}
58                />
59            </PortalPopper>
60        </>
61    )
62}
63
64#[derive(PartialEq, Properties)]
65struct TooltipPopupContentProperties {
66    text: String,
67    state: State,
68    r#ref: NodeRef,
69}
70
71#[function_component(TooltipPopupContent)]
72fn tooltip_popup_content(props: &TooltipPopupContentProperties) -> Html {
73    let orientation = Orientation::from_popper_data(&props.state.attributes.popper);
74
75    html! {
76        <TooltipPopup
77            r#ref={props.r#ref.clone()}
78            style={&props.state.styles.popper.extend_with("z-index", "1000")}
79            {orientation}
80            text={props.text.clone()}
81        />
82    }
83}
84
85/// Properties for [`TooltipPopup`]
86#[derive(Clone, PartialEq, Properties)]
87pub struct TooltipPopupProperties {
88    pub text: String,
89    pub orientation: Orientation,
90    #[prop_or_default]
91    pub style: AttrValue,
92    #[prop_or_default]
93    pub r#ref: NodeRef,
94}
95
96/// The content shown when the tooltip pops up.
97///
98/// ## Properties
99///
100/// Defined by [`TooltipPopupProperties`].
101#[function_component(TooltipPopup)]
102pub fn tooltip_popup(props: &TooltipPopupProperties) -> Html {
103    let mut class = Classes::from("pf-v5-c-tooltip");
104
105    class.extend_from(&props.orientation);
106
107    html! {
108        <div ref={&props.r#ref} style={&props.style} {class} role="tooltip">
109            <div class="pf-v5-c-tooltip__arrow"></div>
110            <div class="pf-v5-c-tooltip__content">
111                { &props.text }
112            </div>
113        </div>
114    }
115}