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.set(rev_vert);
82 true
83 },
84 ModalMsg::SubMsg(msg) => {
85 if let Some(child) = &ctx.props().child
86 && let Some(link) = child.props.weak_link().borrow().as_ref()
87 {
88 link.send_message(msg);
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 ModalOrientation {
121 pub fn set(&self, value: bool) {
122 self.0.set(value);
123 }
124}
125
126impl From<ModalOrientation> for bool {
127 fn from(x: ModalOrientation) -> Self {
128 x.0.get()
129 }
130}
131
132pub trait ModalLink<T>
133where
134 T: Component,
135{
136 fn weak_link(&self) -> &'_ WeakScope<T>;
137}
138
139pub trait SetModalLink {
140 fn set_modal_link(&self);
141}
142
143impl<T> SetModalLink for &Context<T>
144where
145 T: Component,
146 T::Properties: ModalLink<T>,
147{
148 fn set_modal_link(&self) {
149 *self.props().weak_link().borrow_mut() = Some(self.link().clone());
150 }
151}
152
153#[derive(Properties, Clone)]
154struct NoRenderProps {
155 pub children: Children,
156}
157
158impl PartialEq for NoRenderProps {
159 fn eq(&self, _other: &Self) -> bool {
160 true
161 }
162}
163
164struct NoRender {}
165
166impl Component for NoRender {
167 type Message = ();
168 type Properties = NoRenderProps;
169
170 fn create(_ctx: &Context<Self>) -> Self {
171 Self {}
172 }
173
174 fn view(&self, ctx: &Context<Self>) -> Html {
175 html! { { ctx.props().children.iter().collect::<Html>() } }
176 }
177}