Skip to main content

perspective_viewer/components/
modal.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use 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}