leptos_leaflet/components/
control.rs

1use leaflet::Control;
2use leaflet::ControlOptions;
3use leptos::html::Div;
4use leptos::prelude::*;
5use wasm_bindgen::JsCast;
6use web_sys::HtmlDivElement;
7
8use crate::prelude::LeafletMapContext;
9
10/// Creates a new control.
11#[component]
12pub fn Control(
13    /// Wether the container should get the class `leaflet-bar`.
14    #[prop(optional, default = false)]
15    leaflet_bar: bool,
16    /// Position of the control.
17    #[prop(optional, into, default = Signal::derive(|| "topleft".to_string()))]
18    position: Signal<String>,
19    children: ChildrenFn,
20) -> impl IntoView {
21    let control = StoredValue::new_local(None::<Control>);
22
23    let options = ControlOptions::new();
24    options.set_position(position.get_untracked());
25
26    let ready_signal = Trigger::new();
27    let control_view_ref = NodeRef::<Div>::new();
28    let control_view = move || {
29        view! {
30            <div node_ref=control_view_ref>
31            { children() }
32            </div>
33        }
34    };
35
36    Effect::new(move |_| {
37        let Some(map) = use_context::<LeafletMapContext>()
38            .expect("Leaflet context not available. Could not initialize Control component.")
39            .map()
40        else {
41            return;
42        };
43
44        let c = Control::new(&options);
45
46        // Renders the children of the control.
47        c.on_add(move |_| {
48            let control_html: HtmlDivElement = document()
49                .create_element("div")
50                .expect("Could not create element.")
51                .unchecked_into();
52            if leaflet_bar {
53                control_html.set_class_name("leaflet-bar");
54            }
55
56            control_html.unchecked_into()
57        });
58
59        c.add_to(&map);
60        control.set_value(Some(c));
61        ready_signal.notify();
62    });
63
64    on_cleanup(move || {
65        control.with_value(|contr| {
66            if let Some(c) = contr {
67                c.remove();
68            }
69        });
70        control.set_value(None);
71    });
72
73    let update_position = move || {
74        let position = position.get();
75        let Some(c) = control.get_value() else {
76            return;
77        };
78        c.set_position(&position);
79    };
80
81    let move_control_view = move || {
82        ready_signal.track();
83        let c = control.get_value();
84        if let Some(ch) = c {
85            ch.get_container()
86                .prepend_with_node_1(&control_view_ref.get().unwrap())
87                .expect("append_child failed");
88        }
89    };
90
91    view! {
92        { control_view }
93        { update_position }
94        { move_control_view }
95    }
96}