floating-ui 0.0.1

Rust bindings for Floating UI
Documentation
use wasm_bindgen::JsValue;

use super::{Alignment, AlignmentPlacement, Side};
use crate::{
    utils_::{enum_union, StringUnion as _},
    Error, Result,
};

macro_rules! impl_placement {
    () => {
        impl Placement {
            impl_placement!(side: Top);
            impl_placement!(side: Right);
            impl_placement!(side: Bottom);
            impl_placement!(side: Left);
        }
    };
    (side: $side:ident) => {
        paste::paste! {
            pub fn [<$side:snake>]()-> Self {
                Placement::Side(Side::$side)
            }

            pub fn [<$side:snake _start>]() -> Self {
                Placement::AlignmentPlacement(AlignmentPlacement{ side: Side::$side, alignment: Alignment::Start })
            }

            pub fn [<$side:snake _end>]() -> Self {
                Placement::AlignmentPlacement(AlignmentPlacement{ side: Side::$side, alignment: Alignment::End })
            }
        }
    }
}

enum_union!(Placement, Side, AlignmentPlacement);
impl_placement!();

impl TryFrom<JsValue> for Placement {
    type Error = Error;

    fn try_from(value: JsValue) -> Result<Self> {
        let s = value
            .as_string()
            .ok_or(Error::InvalidJsValue("value".to_string(), "String"))?;

        let parts: Vec<&str> = s.split("-").collect();

        if parts.len() > 2 {
            return Err(Error::InvalidValue(s, "Placement"));
        }

        let side = Side::try_from_str(parts[0])?;

        if parts.len() == 1 {
            return Ok(side.into());
        }

        let alignment = Alignment::try_from_str(parts[1])?;

        Ok(AlignmentPlacement { side, alignment }.into())
    }
}

impl Into<JsValue> for Placement {
    fn into(self) -> JsValue {
        match self {
            Placement::Side(side) => side.into(),
            Placement::AlignmentPlacement(ap) => ap.into(),
        }
    }
}