yew_bs/components/
popovers.rs1use yew::prelude::*;
2use web_sys::Element;
3use wasm_bindgen::JsValue;
4use crate::interop::BsPopover;
5#[derive(Clone, Copy, PartialEq, Debug)]
6pub enum PopoverPlacement {
7 Auto,
8 Top,
9 Bottom,
10 Left,
11 Right,
12}
13impl PopoverPlacement {
14 pub fn as_str(&self) -> &'static str {
15 match self {
16 PopoverPlacement::Auto => "auto",
17 PopoverPlacement::Top => "top",
18 PopoverPlacement::Bottom => "bottom",
19 PopoverPlacement::Left => "left",
20 PopoverPlacement::Right => "right",
21 }
22 }
23}
24#[derive(Clone, Copy, PartialEq, Debug)]
26pub enum PopoverTrigger {
27 Click,
28 Hover,
29 Focus,
30 Manual,
31}
32impl PopoverTrigger {
33 pub fn as_str(&self) -> &'static str {
34 match self {
35 PopoverTrigger::Click => "click",
36 PopoverTrigger::Hover => "hover",
37 PopoverTrigger::Focus => "focus",
38 PopoverTrigger::Manual => "manual",
39 }
40 }
41}
42#[derive(Properties, PartialEq)]
43pub struct PopoverProps {
44 #[prop_or_default]
45 pub children: Children,
46 #[prop_or_default]
47 pub title: Option<AttrValue>,
48 #[prop_or_default]
49 pub content: Option<AttrValue>,
50 #[prop_or(PopoverPlacement::Top)]
51 pub placement: PopoverPlacement,
52 #[prop_or(PopoverTrigger::Click)]
53 pub trigger: PopoverTrigger,
54 #[prop_or_default]
55 pub show: bool,
56 #[prop_or_default]
57 pub allow_html: bool,
58 #[prop_or_default]
59 pub template: Option<AttrValue>,
60 #[prop_or(true)]
61 pub animation: bool,
62 #[prop_or_default]
63 pub delay: Option<u32>,
64 #[prop_or_default]
65 pub class: Option<AttrValue>,
66 #[prop_or_default]
67 pub node_ref: NodeRef,
68}
69#[function_component(Popover)]
70pub fn popover(props: &PopoverProps) -> Html {
71 let node_ref = props.node_ref.clone();
72 {
73 let node_ref = node_ref.clone();
74 let title = props.title.clone();
75 let content = props.content.clone();
76 let placement = props.placement;
77 let trigger = props.trigger;
78 let show = props.show;
79 let allow_html = props.allow_html;
80 let template = props.template.clone();
81 let animation = props.animation;
82 let delay = props.delay;
83 use_effect_with(
84 (),
85 move |_| {
86 if let Some(element) = node_ref.cast::<Element>() {
87 let options = js_sys::Object::new();
88 if let Some(title) = &title {
89 js_sys::Reflect::set(
90 &options,
91 &"title".into(),
92 &title.as_str().into(),
93 )
94 .unwrap();
95 }
96 if let Some(content) = &content {
97 js_sys::Reflect::set(
98 &options,
99 &"content".into(),
100 &content.as_str().into(),
101 )
102 .unwrap();
103 }
104 js_sys::Reflect::set(
105 &options,
106 &"placement".into(),
107 &placement.as_str().into(),
108 )
109 .unwrap();
110 js_sys::Reflect::set(
111 &options,
112 &"trigger".into(),
113 &trigger.as_str().into(),
114 )
115 .unwrap();
116 js_sys::Reflect::set(&options, &"html".into(), &allow_html.into())
117 .unwrap();
118 js_sys::Reflect::set(
119 &options,
120 &"animation".into(),
121 &animation.into(),
122 )
123 .unwrap();
124 if let Some(delay) = delay {
125 js_sys::Reflect::set(&options, &"delay".into(), &delay.into())
126 .unwrap();
127 }
128 if let Some(template) = &template {
129 js_sys::Reflect::set(
130 &options,
131 &"template".into(),
132 &template.as_str().into(),
133 )
134 .unwrap();
135 }
136 let bs_popover = BsPopover::new(
137 &element,
138 Some(&JsValue::from(options)),
139 );
140 if show {
141 bs_popover.show();
142 }
143 }
144 || ()
145 },
146 );
147 }
148 html! {
149 < span ref = { node_ref } class = { props.class.clone() } > { for props.children
150 .iter() } </ span >
151 }
152}
153#[derive(Properties, PartialEq)]
154pub struct PopoverHeaderProps {
155 #[prop_or_default]
156 pub children: Children,
157 #[prop_or_default]
158 pub class: Option<AttrValue>,
159}
160#[function_component(PopoverHeader)]
161pub fn popover_header(props: &PopoverHeaderProps) -> Html {
162 let mut classes = "popover-header".to_string();
163 if let Some(class) = &props.class {
164 classes.push(' ');
165 classes.push_str(class.as_str());
166 }
167 html! {
168 < div class = { classes } > { for props.children.iter() } </ div >
169 }
170}
171#[derive(Properties, PartialEq)]
172pub struct PopoverBodyProps {
173 #[prop_or_default]
174 pub children: Children,
175 #[prop_or_default]
176 pub class: Option<AttrValue>,
177}
178#[function_component(PopoverBody)]
179pub fn popover_body(props: &PopoverBodyProps) -> Html {
180 let mut classes = "popover-body".to_string();
181 if let Some(class) = &props.class {
182 classes.push(' ');
183 classes.push_str(class.as_str());
184 }
185 html! {
186 < div class = { classes } > { for props.children.iter() } </ div >
187 }
188}