aura-gui 0.3.5

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Espaciado y tamaños de Tailwind con su escala completa: `p_4`, márgenes,  `gap_x_2`, `w_64`,
//! `size_10`, `inset_0`, `top_1_5`, `mx_auto`, fracciones (`w_1_2`) y `w_full`. 1 unidad = 4 px.
//!
//! Son métodos con valor por defecto de `Styled` (el macro se expande allí): no cuestan nada hasta que se llaman.
//! Los nombres de tipo del macro (`Length`, `AUTO_*`) se resuelven en `styled.rs`.

use crate::core::Pixels;
use crate::view::style::Length;

pub(crate) fn length(value: Pixels) -> Option<Length> {
    Some(Length::Px(value))
}

/// Se expande dentro de `Styled`: así un solo `use` trae todas las utilidades y no hay rasgos extra que importar.
macro_rules! scale_utilities {
    () => {
        scale_methods!(p, |s, v| s.padding.set_all(v));
        scale_methods!(px, |s, v| s.padding.set_horizontal(v));
        scale_methods!(py, |s, v| s.padding.set_vertical(v));
        scale_methods!(pt, |s, v| s.padding.top = Some(v));
        scale_methods!(pr, |s, v| s.padding.right = Some(v));
        scale_methods!(pb, |s, v| s.padding.bottom = Some(v));
        scale_methods!(pl, |s, v| s.padding.left = Some(v));

        scale_methods!(m, |s, v| s.margin.set_all(v));
        scale_methods!(mx, |s, v| s.margin.set_horizontal(v));
        scale_methods!(my, |s, v| s.margin.set_vertical(v));
        scale_methods!(mt, |s, v| s.margin.top = Some(v));
        scale_methods!(mr, |s, v| s.margin.right = Some(v));
        scale_methods!(mb, |s, v| s.margin.bottom = Some(v));
        scale_methods!(ml, |s, v| s.margin.left = Some(v));

        scale_methods!(gap, |s, v| {
            s.gap_x = Some(v);
            s.gap_y = Some(v);
        });
        scale_methods!(gap_x, |s, v| s.gap_x = Some(v));
        scale_methods!(gap_y, |s, v| s.gap_y = Some(v));

        scale_methods!(w, |s, v| s.width = crate::view::scale::length(v));
        scale_methods!(h, |s, v| s.height = crate::view::scale::length(v));
        scale_methods!(size, |s, v| {
            s.width = crate::view::scale::length(v);
            s.height = crate::view::scale::length(v);
        });
        scale_methods!(min_w, |s, v| s.min_width = crate::view::scale::length(v));
        scale_methods!(min_h, |s, v| s.min_height = crate::view::scale::length(v));
        scale_methods!(max_w, |s, v| s.max_width = crate::view::scale::length(v));
        scale_methods!(max_h, |s, v| s.max_height = crate::view::scale::length(v));

        scale_methods!(inset, |s, v| s.inset.set_all(v));
        scale_methods!(inset_x, |s, v| s.inset.set_horizontal(v));
        scale_methods!(inset_y, |s, v| s.inset.set_vertical(v));
        scale_methods!(top, |s, v| s.inset.top = Some(v));
        scale_methods!(right, |s, v| s.inset.right = Some(v));
        scale_methods!(bottom, |s, v| s.inset.bottom = Some(v));
        scale_methods!(left, |s, v| s.inset.left = Some(v));

        fractions!(w, width);
        fractions!(h, height);
        fractions!(min_w, min_width);
        fractions!(max_w, max_width);

        setters! {
            w_auto => |s| s.width = Some(Length::Auto);
            h_auto => |s| s.height = Some(Length::Auto);
            // Relativos al contenedor; en la raíz de la ventana equivalen a `w-screen` y `h-screen`.
            w_screen => |s| s.width = Some(Length::Percent(1.0));
            h_screen => |s| s.height = Some(Length::Percent(1.0));
            min_w_full => |s| s.min_width = Some(Length::Percent(1.0));
            min_h_full => |s| s.min_height = Some(Length::Percent(1.0));
            max_w_full => |s| s.max_width = Some(Length::Percent(1.0));
            max_h_full => |s| s.max_height = Some(Length::Percent(1.0));
            m_auto => |s| s.extra_mut().margin_auto |= AUTO_ALL;
            mx_auto => |s| s.extra_mut().margin_auto |= AUTO_LEFT | AUTO_RIGHT;
            my_auto => |s| s.extra_mut().margin_auto |= AUTO_TOP | AUTO_BOTTOM;
            mt_auto => |s| s.extra_mut().margin_auto |= AUTO_TOP;
            mr_auto => |s| s.extra_mut().margin_auto |= AUTO_RIGHT;
            mb_auto => |s| s.extra_mut().margin_auto |= AUTO_BOTTOM;
            ml_auto => |s| s.extra_mut().margin_auto |= AUTO_LEFT;
        }
    };
}

pub(crate) use scale_utilities;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::view::div::div;
    use crate::view::style::Style;
    use crate::view::styled::Styled;

    fn style_of(build: impl FnOnce(crate::view::div::Div) -> crate::view::div::Div) -> Style {
        build(div()).style
    }

    #[test]
    fn la_escala_son_cuatro_pixeles_por_unidad() {
        let style = style_of(|d| d.p_4().mx_2().gap_x_0_5().top_px());
        assert_eq!(style.padding.top, Some(Pixels(16.0)));
        assert_eq!(style.margin.left, Some(Pixels(8.0)));
        assert_eq!(style.gap_x, Some(Pixels(2.0)));
        assert_eq!(style.inset.top, Some(Pixels(1.0)));
    }

    #[test]
    fn tamanos_absolutos_y_relativos() {
        let style = style_of(|d| d.w_96().h_1_2().size_10().max_w_1_3());
        assert_eq!(style.width, Some(Length::Px(Pixels(40.0))), "size_10 pisa a w_96");
        assert_eq!(style.height, Some(Length::Px(Pixels(40.0))));
        assert_eq!(style.max_width, Some(Length::Percent(1.0 / 3.0)));
    }

    #[test]
    fn lo_ultimo_manda_como_en_css() {
        let style = style_of(|d| d.p_8().px_2());
        assert_eq!((style.padding.top, style.padding.left), (Some(Pixels(32.0)), Some(Pixels(8.0))));
    }
}