dioxus_leaflet/
components.rs

1use dioxus::prelude::*;
2use crate::types::*;
3use crate::utils::*;
4
5#[derive(Props, Clone, PartialEq)]
6pub struct MapProps {
7    /// Initial position of the map
8    #[props(default = MapPosition::default())]
9    pub initial_position: MapPosition,
10    
11    /// Markers to display on the map
12    #[props(default = vec![])]
13    pub markers: Vec<MapMarker>,
14    
15    /// Height of the map container
16    #[props(default = "500px".to_string())]
17    pub height: String,
18    
19    /// Width of the map container
20    #[props(default = "100%".to_string())]
21    pub width: String,
22    
23    /// Map configuration options
24    #[props(default = MapOptions::default())]
25    pub options: MapOptions,
26    
27    /// Custom CSS class for the map container
28    #[props(default = "".to_string())]
29    pub class: String,
30    
31    /// Custom CSS styles for the map container
32    #[props(default = "".to_string())]
33    pub style: String,
34    
35    /// Callback when marker is clicked
36    pub on_marker_click: Option<EventHandler<MapMarker>>,
37    
38    /// Callback when map is clicked
39    pub on_map_click: Option<EventHandler<MapPosition>>,
40    
41    /// Callback when map is moved
42    pub on_map_move: Option<EventHandler<MapPosition>>,
43}
44
45/// Main map component using Leaflet
46#[component]
47pub fn Map(props: MapProps) -> Element {
48    let map_id: Signal<String> = use_signal(generate_map_id);
49    let map_id_clone: String = map_id.read().clone();
50    
51    let init_script: String = generate_map_script(
52        &map_id_clone,
53        &props.initial_position,
54        &props.markers,
55        &props.options,
56    );
57    
58    let container_style = format!(
59        "position: relative; width: {}; height: {}; {}",
60        props.width, props.height, props.style
61    );
62    
63    let container_class = if props.class.is_empty() {
64        "dioxus-leaflet-container".to_string()
65    } else {
66        format!("dioxus-leaflet-container {}", props.class)
67    };
68    
69    rsx! {
70        div {
71            class: "{container_class}",
72            style: "{container_style}",
73            
74            // Leaflet CSS
75            if let Some(integrity) = props.options.leaflet_resources.css_integrity() {
76                link {
77                    rel: "stylesheet",
78                    href: "{props.options.leaflet_resources.css_url()}",
79                    integrity: "{integrity}",
80                    crossorigin: ""
81                }
82            } else {
83                link {
84                    rel: "stylesheet",
85                    href: "{props.options.leaflet_resources.css_url()}"
86                }
87            }
88            
89            // Map container
90            div {
91                id: "{map_id_clone}",
92                class: "dioxus-leaflet-map",
93                style: "width: 100%; height: 100%; z-index: 1;",
94            }
95            
96            // Leaflet JavaScript
97            if let Some(integrity) = props.options.leaflet_resources.js_integrity() {
98                script {
99                    src: "{props.options.leaflet_resources.js_url()}",
100                    integrity: "{integrity}",
101                    crossorigin: ""
102                }
103            } else {
104                script {
105                    src: "{props.options.leaflet_resources.js_url()}"
106                }
107            }
108            
109            // Initialize map script
110            script {
111                dangerous_inner_html: "{init_script}"
112            }
113        }
114    }
115}