Skip to main content

freya_components/
lazy.rs

1use freya_core::prelude::*;
2
3/// Renders its children only once its wrapper element has become visible.
4///
5/// By default the children stay rendered afterwards, use [`Lazy::keep_rendered`] to
6/// unrender them whenever the wrapper goes out of view again.
7/// Give the wrapper a size so that it can be scrolled into view while still empty.
8///
9/// # Example
10///
11/// ```rust,no_run
12/// # use freya::prelude::*;
13/// fn app() -> impl IntoElement {
14///     ScrollView::new()
15///         .child(rect().height(Size::px(1000.)))
16///         .child(
17///             Lazy::new()
18///                 .height(Size::px(200.))
19///                 .child("Rendered once scrolled into view"),
20///         )
21/// }
22/// ```
23#[derive(PartialEq)]
24pub struct Lazy {
25    keep_rendered: bool,
26    elements: Vec<Element>,
27    layout: LayoutData,
28    key: DiffKey,
29}
30
31impl KeyExt for Lazy {
32    fn write_key(&mut self) -> &mut DiffKey {
33        &mut self.key
34    }
35}
36
37impl ChildrenExt for Lazy {
38    fn get_children(&mut self) -> &mut Vec<Element> {
39        &mut self.elements
40    }
41}
42
43impl LayoutExt for Lazy {
44    fn get_layout(&mut self) -> &mut LayoutData {
45        &mut self.layout
46    }
47}
48
49impl ContainerExt for Lazy {}
50
51impl ContainerWithContentExt for Lazy {}
52
53impl Default for Lazy {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59impl Lazy {
60    pub fn new() -> Self {
61        Self {
62            keep_rendered: true,
63            elements: Vec::new(),
64            layout: LayoutData::default(),
65            key: DiffKey::None,
66        }
67    }
68
69    /// Keep the children rendered once the wrapper goes out of view again. Enabled by default.
70    pub fn keep_rendered(mut self, keep_rendered: bool) -> Self {
71        self.keep_rendered = keep_rendered;
72        self
73    }
74}
75
76impl Component for Lazy {
77    fn render(&self) -> impl IntoElement {
78        let mut visible = use_state(|| false);
79        let elements = self.elements.clone();
80        let keep_rendered = self.keep_rendered;
81        let is_visible = *visible.read();
82
83        rect()
84            .layout(self.layout.clone())
85            .maybe(!is_visible, |el| el.on_visible(move |_| visible.set(true)))
86            .maybe(is_visible && !keep_rendered, |el| {
87                el.on_hidden(move |_| visible.set(false))
88            })
89            .maybe(is_visible, |el| el.children(elements))
90    }
91
92    fn render_key(&self) -> DiffKey {
93        self.key.clone().or(self.default_key())
94    }
95}