perspective_viewer/components/
modal.rs1use std::cell::Cell;
14use std::marker::PhantomData;
15use std::rc::Rc;
16
17use derivative::Derivative;
18use yew::html::*;
19use yew::prelude::*;
20use yew::virtual_dom::VChild;
21
22use crate::utils::WeakScope;
23
24#[derive(Properties, Derivative)]
25#[derivative(PartialEq(bound = ""))]
26pub struct ModalProps<T>
27where
28 T: Component,
29 T::Properties: ModalLink<T>,
30{
31 pub child: Option<VChild<T>>,
32}
33
34#[derive(Debug)]
35pub enum ModalMsg<T>
36where
37 T: Component,
38{
39 SetPos {
40 top: f64,
41 left: f64,
42 visible: bool,
43 rev_vert: bool,
44 },
45 SubMsg(T::Message),
46}
47
48#[derive(Default)]
49pub struct Modal<T> {
50 css: String,
51 rev_vert: ModalOrientation,
52 _comp: PhantomData<T>,
53}
54
55impl<T> Component for Modal<T>
56where
57 T: Component,
58 T::Properties: ModalLink<T>,
59{
60 type Message = ModalMsg<T>;
61 type Properties = ModalProps<T>;
62
63 fn create(_ctx: &Context<Self>) -> Self {
64 Self {
65 css: ":host{{top:0px;left:0px;opacity:0}}".to_owned(),
66 rev_vert: Default::default(),
67 _comp: PhantomData,
68 }
69 }
70
71 fn update(&mut self, ctx: &Context<Self>, msg: ModalMsg<T>) -> bool {
72 match msg {
73 ModalMsg::SetPos {
74 top,
75 left,
76 visible,
77 rev_vert,
78 } => {
79 let opacity = if visible { "" } else { ";opacity:0" };
80 self.css = format!(":host{{top:{top}px;left:{left}px{opacity}}}");
81 self.rev_vert.0.set(rev_vert);
82 true
83 },
84 ModalMsg::SubMsg(msg) => {
85 if let Some(child) = &ctx.props().child {
86 if let Some(link) = child.props.weak_link().borrow().as_ref() {
87 link.send_message(msg);
88 }
89 }
90
91 false
92 },
93 }
94 }
95
96 fn view(&self, ctx: &Context<Self>) -> Html {
97 let child = ctx
98 .props()
99 .child
100 .clone()
101 .map(Html::from)
102 .unwrap_or_default();
103
104 html! {
105 <>
106 <style>{ self.css.to_owned() }</style>
107 <ContextProvider<ModalOrientation> context={&self.rev_vert}>
108 <NoRender>{ child }</NoRender>
109 </ContextProvider<ModalOrientation>>
110 </>
111 }
112 }
113}
114
115#[derive(Clone, Default, Eq, PartialEq)]
116pub struct ModalOrientation(Rc<Cell<bool>>);
117
118impl ImplicitClone for ModalOrientation {}
119
120impl From<ModalOrientation> for bool {
121 fn from(x: ModalOrientation) -> Self {
122 x.0.get()
123 }
124}
125
126pub trait ModalLink<T>
127where
128 T: Component,
129{
130 fn weak_link(&self) -> &'_ WeakScope<T>;
131}
132
133pub trait SetModalLink {
134 fn set_modal_link(&self);
135}
136
137impl<T> SetModalLink for &Context<T>
138where
139 T: Component,
140 T::Properties: ModalLink<T>,
141{
142 fn set_modal_link(&self) {
143 *self.props().weak_link().borrow_mut() = Some(self.link().clone());
144 }
145}
146
147#[derive(Properties, Clone)]
148struct NoRenderProps {
149 pub children: Children,
150}
151
152impl PartialEq for NoRenderProps {
153 fn eq(&self, _other: &Self) -> bool {
154 true
155 }
156}
157
158struct NoRender {}
159
160impl Component for NoRender {
161 type Message = ();
162 type Properties = NoRenderProps;
163
164 fn create(_ctx: &Context<Self>) -> Self {
165 Self {}
166 }
167
168 fn view(&self, ctx: &Context<Self>) -> Html {
169 html! { { ctx.props().children.iter().collect::<Html>() } }
170 }
171}