perspective_viewer/components/style/
style_provider.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 web_sys::HtmlStyleElement;
14use yew::prelude::*;
15use yew::virtual_dom::VNode;
16
17use super::style_cache::StyleCache;
18
19#[derive(Properties, PartialEq)]
20pub struct StyleProviderProps {
21    #[prop_or(true)]
22    pub is_shadow: bool,
23    pub children: Children,
24}
25
26/// A context which injects any CSS snippet registered within its tree, doing
27/// so only once for each unqiue snippet name.
28///
29/// CSS can be registered within sub-components via the `<LocalStyle>` component
30/// and `css!()` resource inlining macro.
31pub struct StyleProvider {
32    cache: StyleCache,
33}
34
35impl Component for StyleProvider {
36    type Message = ();
37    type Properties = StyleProviderProps;
38
39    fn create(ctx: &Context<Self>) -> Self {
40        let cache = StyleCache::new(ctx.props().is_shadow);
41        Self { cache }
42    }
43
44    fn view(&self, ctx: &Context<Self>) -> Html {
45        let styles = self.cache.iter_styles();
46
47        html! {
48            <>
49                { for styles.map(|x| {
50                html! {
51                    <StyleKeyed key={ x.0 } elem={ x.1 } />
52                }
53            }) }
54                <ContextProvider<StyleCache> context={self.cache.clone()}>
55                    { for ctx.props().children.iter() }
56                </ContextProvider<StyleCache>>
57            </>
58        }
59    }
60}
61
62#[derive(Properties, PartialEq)]
63struct StyleKeyedProps {
64    elem: HtmlStyleElement,
65}
66
67/// Necessary only to attach `key` to individual `HtmlStylElement` children,
68/// as `yew` does not calculate list updates correctly for sequences of these
69/// without keys.
70#[function_component(StyleKeyed)]
71fn style_renderer(props: &StyleKeyedProps) -> Html {
72    VNode::VRef(props.elem.clone().into())
73}