material-ui-rs 0.5.3

A Material3 inspired theme for `iced`
Documentation
use iced::Task;
use js_sys::{Function, Promise, Reflect, Uint8Array};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;

use super::{WebFontError, is_supported_web_font};

pub(super) fn load(url: String) -> Task<Result<(), WebFontError>> {
    Task::future(fetch(url)).then(|result| match result {
        Ok(bytes) => iced::font::load(bytes).map(|result| result.map_err(WebFontError::FontLoad)),
        Err(error) => Task::done(Err(error)),
    })
}

async fn fetch(url: String) -> Result<Vec<u8>, WebFontError> {
    let global = js_sys::global();
    let fetch = function(&global, "fetch")?;
    let response = fetch
        .call1(&global, &JsValue::from_str(&url))
        .map_err(|_| WebFontError::RequestFailed)?;
    let response = response
        .dyn_into::<Promise>()
        .map_err(|_| WebFontError::MissingBrowserApi("fetch Promise"))?;
    let response = JsFuture::from(response)
        .await
        .map_err(|_| WebFontError::RequestFailed)?;

    let ok = Reflect::get(&response, &JsValue::from_str("ok"))
        .ok()
        .and_then(|value| value.as_bool())
        .ok_or(WebFontError::MissingBrowserApi("Response.ok"))?;

    if !ok {
        let status = Reflect::get(&response, &JsValue::from_str("status"))
            .ok()
            .and_then(|value| value.as_f64())
            .unwrap_or_default() as u16;

        return Err(WebFontError::HttpStatus(status));
    }

    let array_buffer = function(&response, "arrayBuffer")?
        .call0(&response)
        .map_err(|_| WebFontError::ReadFailed)?;
    let array_buffer = array_buffer
        .dyn_into::<Promise>()
        .map_err(|_| WebFontError::MissingBrowserApi("Response.arrayBuffer Promise"))?;
    let array_buffer = JsFuture::from(array_buffer)
        .await
        .map_err(|_| WebFontError::ReadFailed)?;
    let bytes = Uint8Array::new(&array_buffer).to_vec();

    if !is_supported_web_font(&bytes) {
        return Err(WebFontError::UnsupportedFormat);
    }

    Ok(bytes)
}

fn function(target: &JsValue, name: &'static str) -> Result<Function, WebFontError> {
    Reflect::get(target, &JsValue::from_str(name))
        .ok()
        .and_then(|value| value.dyn_into::<Function>().ok())
        .ok_or(WebFontError::MissingBrowserApi(name))
}