perspective_viewer/components/containers/
scroll_panel_item.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
13// Forked from https://github.com/AircastDev/yew-virtual-scroller (Apache 2.0)
14// Adds support for Yew 0.19, auto-width and a simplified message structure.
15
16#[cfg(debug_assertions)]
17use std::cell::Cell;
18#[cfg(debug_assertions)]
19use std::rc::Rc;
20
21use yew::prelude::*;
22
23#[derive(PartialEq, Properties)]
24pub struct ScrollPanelItemProps {
25    /// The expected size of this component in pixels. Calculating this value
26    /// ahead of time makes it easier to implement a high-performance virtual
27    /// renderer without resorting to weird tricks, _but_ checking that this
28    /// hint is correct is nearly as expensive. So, we only generate the
29    /// validation code in debug builds.
30    pub size_hint: f64,
31    pub children: Children,
32
33    #[cfg(debug_assertions)]
34    #[prop_or_default]
35    measured_size: Rc<Cell<Option<f64>>>,
36}
37
38impl ScrollPanelItemProps {
39    #[cfg(debug_assertions)]
40    pub fn get_size(&self) -> f64 {
41        self.measured_size.get().unwrap_or(self.size_hint)
42    }
43
44    #[cfg(not(debug_assertions))]
45    pub fn get_size(&self) -> f64 {
46        self.size_hint
47    }
48}
49
50#[cfg(debug_assertions)]
51pub struct ScrollPanelItem {
52    node: NodeRef,
53}
54
55#[cfg(not(debug_assertions))]
56pub struct ScrollPanelItem {}
57
58impl Component for ScrollPanelItem {
59    type Message = ();
60    type Properties = ScrollPanelItemProps;
61
62    #[cfg(debug_assertions)]
63    fn create(ctx: &Context<Self>) -> Self {
64        ctx.props().measured_size.set(Some(ctx.props().size_hint));
65        Self {
66            node: NodeRef::default(),
67        }
68    }
69
70    #[cfg(not(debug_assertions))]
71    fn create(_ctx: &Context<Self>) -> Self {
72        Self {}
73    }
74
75    #[cfg(debug_assertions)]
76    fn view(&self, ctx: &Context<Self>) -> Html {
77        html! {
78            <div class="debug-size-wrapper" style="display:flow-root" ref={self.node.clone()}>
79                { for ctx.props().children.iter() }
80            </div>
81        }
82    }
83
84    #[cfg(not(debug_assertions))]
85    fn view(&self, ctx: &Context<Self>) -> Html {
86        html! { { for ctx.props().children.iter() } }
87    }
88
89    #[cfg(debug_assertions)]
90    fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
91        ctx.props().measured_size.set(Some(ctx.props().size_hint));
92        true
93    }
94
95    #[cfg(debug_assertions)]
96    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
97        if first_render {
98            let elem = self.node.cast::<web_sys::HtmlElement>().unwrap();
99            let new_height = elem.get_bounding_client_rect().height();
100            if ctx.props().measured_size.get() != Some(new_height) {
101                tracing::warn!(
102                    "ScrollPanel size_hint does not match element size: {} != {}",
103                    ctx.props().size_hint,
104                    new_height
105                );
106                web_sys::console::warn_1(&elem);
107                ctx.props().measured_size.set(Some(new_height));
108            }
109        }
110    }
111}