dioxus-leaflet 0.3.1

A general-purpose Leaflet map component for Dioxus applications
Documentation
use dioxus::prelude::*;
use dioxus_use_js::{JsError, SerdeJsonValue};
use std::error::Error;

use crate::{LatLng, MapOptions, MapPosition, MarkerIcon, PathOptions, PopupOptions, types::Id};

pub const DL_JS: Asset = asset!("/assets/dioxus_leaflet.js");

mod js_api {
    use dioxus::prelude::*;
    use dioxus_use_js::use_js;

    use_js!("js_utils/src/map.ts", "assets/dioxus_leaflet.js"::{update_map, delete_map, on_map_click, on_map_move});
    use_js!("js_utils/src/marker.ts", "assets/dioxus_leaflet.js"::{update_marker, delete_marker});
    use_js!("js_utils/src/polygon.ts", "assets/dioxus_leaflet.js"::{update_polygon, delete_polygon});
    use_js!("js_utils/src/popup.ts", "assets/dioxus_leaflet.js"::{update_popup});
}

fn js_to_eval(err: JsError) -> Box<dyn Error + Send + Sync> {
    match err {
        JsError::Eval { error, .. } => error.into(),
        JsError::Threw { func, .. } => Box::<dyn Error + Send + Sync>::from(func),
    }
}

pub async fn update_map<'a>(
    id: &Id,
    initial_position: &MapPosition,
    options: &MapOptions,
) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::update_map(id, initial_position, options)
        .await
        .map_err(js_to_eval)
}

pub async fn delete_map<'a>(id: &Id) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::delete_map(id).await.map_err(js_to_eval)
}

pub async fn on_map_click(map_id: &Id, callback: EventHandler<LatLng>) -> Result<(), Box<dyn Error + Send + Sync>> {
    let mapper_cb = Callback::new(move |coords: Vec<f64>| async move {
        callback.call(LatLng::new(coords[0], coords[1]));
        Result::<(), SerdeJsonValue>::Ok(())
    });
    js_api::on_map_click(map_id, mapper_cb).await.map_err(js_to_eval)
}

pub async fn on_map_move(map_id: &Id, callback: EventHandler<MapPosition>) -> Result<(), Box<dyn Error + Send + Sync>> {
    let mapper_cb = Callback::new(move |data: Vec<f64>| async move {
        let pos = MapPosition { coordinates: LatLng::new(data[0], data[1]), zoom: data[2] };
        callback.call(pos);
        Result::<(), SerdeJsonValue>::Ok(())
    });
    js_api::on_map_move(map_id, mapper_cb).await.map_err(js_to_eval)
}

pub async fn update_marker(
    marker_id: &Id,
    coordinate: &LatLng,
    icon: &Option<MarkerIcon>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::update_marker(
        marker_id.parent().unwrap(),
        marker_id.id(),
        coordinate,
        icon,
    )
    .await
    .map_err(js_to_eval)
}

pub async fn delete_marker(marker_id: &Id) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::delete_marker(marker_id.parent().unwrap(), marker_id.id())
        .await
        .map_err(js_to_eval)
}

pub async fn update_polygon(
    polygon_id: &Id,
    coordinates: &Vec<Vec<Vec<LatLng>>>,
    options: &PathOptions,
) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::update_polygon(
        polygon_id.parent().unwrap(),
        polygon_id.id(),
        coordinates,
        options,
    )
    .await
    .map_err(js_to_eval)
}

pub async fn delete_polygon(polygon_id: &Id) -> Result<(), Box<dyn Error + Send + Sync>> {
    js_api::delete_polygon(polygon_id.parent().unwrap(), polygon_id.id())
        .await
        .map_err(js_to_eval)
}

pub async fn update_popup(
    popup_id: &Id,
    options: &PopupOptions,
) -> Result<(), Box<dyn Error + Send + Sync>> {
    let marker_id = popup_id.parent().unwrap();
    js_api::update_popup(marker_id, popup_id, options)
        .await
        .map_err(js_to_eval)
}