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.
//! Trait `Styled`: encadenamiento fluido con los mismos nombres que Tailwind CSS.

use crate::core::{Pixels, px};
use crate::gpu::{TextAlign, TextTransform};
use crate::view::scale::scale_utilities;
use crate::view::style::{Align, Direction, Justify, Length, Overflow, ShadowPreset, Shadows, Style};
use crate::view::style_box::{
    border_sides, border_widths, box_utilities, gradients, opacities, rounded_corners, rounded_sizes,
};
use crate::view::style_extra::{AUTO_ALL, AUTO_BOTTOM, AUTO_LEFT, AUTO_RIGHT, AUTO_TOP};
use crate::view::style_filter::{blurs, filter_utilities};
use crate::view::style_grid::{grid_numbers, grid_utilities};
use crate::view::style_layout::{layout_utilities, z_indexes};
use crate::view::style_macros::{fraction_steps, fractions, scale_methods, scale_steps, setters};
use crate::view::style_text::{line_clamps, text_utilities};
use crate::view::style_transform::{
    numbered, percents, transform_utilities, translate_fraction_steps, translate_fractions,
};
use crate::view::theme::ColorSpec;

/// Método sin argumentos que fija un campo a un valor constante: `.items_center()`.
macro_rules! constant_setters {
    ($($name:ident => $field:ident = $value:expr;)*) => {
        $(
            fn $name(mut self) -> Self {
                self.style().$field = Some($value);
                self
            }
        )*
    };
}

/// Método con un argumento que envuelve el valor en un `Length`: `.w(px(200.))`.
macro_rules! length_setters {
    ($($name:ident => $field:ident;)*) => {
        $(
            fn $name(mut self, value: Pixels) -> Self {
                self.style().$field = Some(Length::Px(value));
                self
            }
        )*
    };
}

pub trait Styled: Sized {
    fn style(&mut self) -> &mut Style;

    // Utilidades por tema; cada macro vive en su archivo para mantenerlos cortos.
    scale_utilities!();
    layout_utilities!();
    text_utilities!();
    box_utilities!();
    grid_utilities!();
    transform_utilities!();
    filter_utilities!();

    // ---------- Layout y flexbox ----------

    fn flex(self) -> Self {
        self
    }

    constant_setters! {
        flex_row => direction = Direction::Row;
        flex_col => direction = Direction::Column;
        flex_wrap => wrap = true;
        flex_grow => flex_grow = 1.0;
        flex_shrink_0 => flex_shrink = 0.0;
        items_start => align_items = Align::Start;
        items_center => align_items = Align::Center;
        items_end => align_items = Align::End;
        justify_start => justify_content = Justify::Start;
        justify_center => justify_content = Justify::Center;
        justify_end => justify_content = Justify::End;
        justify_between => justify_content = Justify::SpaceBetween;
        absolute => absolute = true;
        hidden => hidden = true;
        w_full => width = Length::Percent(1.0);
        h_full => height = Length::Percent(1.0);
        rounded_none => radius = Pixels::ZERO;
        rounded_sm => radius = px(2.0);
        rounded_md => radius = px(6.0);
        rounded_lg => radius = px(8.0);
        rounded_xl => radius = px(12.0);
        rounded_full => radius = px(9999.0);
        border_1 => border_width = px(1.0);
        border_2 => border_width = px(2.0);
        text_xs => font_size = px(12.0);
        text_sm => font_size = px(13.0);
        text_base => font_size = px(14.0);
        text_lg => font_size = px(18.0);
        overflow_y_scroll => overflow_y = Overflow::Scroll;
        font_bold => font_bold = true;
        italic => italic = true;
        underline => underline = true;
        whitespace_nowrap => text_wrap = false;
        whitespace_normal => text_wrap = true;
        text_2xl => font_size = px(24.0);
    }

    fn flex_1(mut self) -> Self {
        let style = self.style();
        style.flex_grow = Some(1.0);
        style.flex_shrink = Some(1.0);
        style.flex_basis = Some(Length::Px(Pixels::ZERO));
        self
    }

    // ---------- Dimensiones ----------

    length_setters! {
        w => width;
        h => height;
        min_w => min_width;
        min_h => min_height;
        max_w => max_width;
        max_h => max_height;
    }

    fn aspect_ratio(mut self, ratio: f32) -> Self {
        self.style().aspect_ratio = Some(ratio);
        self
    }

    fn size(self, side: Pixels) -> Self {
        self.w(side).h(side)
    }

    fn size_full(self) -> Self {
        self.w_full().h_full()
    }

    // ---------- Espaciado ----------

    fn px(mut self, value: Pixels) -> Self {
        self.style().padding.set_horizontal(value);
        self
    }

    fn py(mut self, value: Pixels) -> Self {
        self.style().padding.set_vertical(value);
        self
    }

    fn m(mut self, value: Pixels) -> Self {
        self.style().margin.set_all(value);
        self
    }

    fn pl(mut self, value: Pixels) -> Self {
        self.style().padding.left = Some(value);
        self
    }

    fn pr(mut self, value: Pixels) -> Self {
        self.style().padding.right = Some(value);
        self
    }

    fn pt(mut self, value: Pixels) -> Self {
        self.style().padding.top = Some(value);
        self
    }

    fn pb(mut self, value: Pixels) -> Self {
        self.style().padding.bottom = Some(value);
        self
    }

    fn mt(mut self, value: Pixels) -> Self {
        self.style().margin.top = Some(value);
        self
    }

    fn ml(mut self, value: Pixels) -> Self {
        self.style().margin.left = Some(value);
        self
    }

    fn gap(mut self, value: Pixels) -> Self {
        let style = self.style();
        style.gap_x = Some(value);
        style.gap_y = Some(value);
        self
    }

    fn top(mut self, value: Pixels) -> Self {
        self.style().inset.top = Some(value);
        self
    }

    fn right(mut self, value: Pixels) -> Self {
        self.style().inset.right = Some(value);
        self
    }

    fn bottom(mut self, value: Pixels) -> Self {
        self.style().inset.bottom = Some(value);
        self
    }

    fn left(mut self, value: Pixels) -> Self {
        self.style().inset.left = Some(value);
        self
    }

    // ---------- Color, bordes, sombras y texto ----------

    /// Un preset, una capa (`BoxShadow::new(0., 8., 24.).spread(-4.)`) o varias (`Shadows`).
    fn shadow(mut self, shadow: impl Into<Shadows>) -> Self {
        self.style().extra_mut().shadow = Some(shadow.into());
        self
    }

    /// Cambia el color de la sombra actual (o de una `shadow_md` si no había).
    fn shadow_color(mut self, color: impl Into<ColorSpec>) -> Self {
        let current = self.style().shadows().copied().unwrap_or(ShadowPreset::Md.shadows());
        self.style().extra_mut().shadow = Some(current.tinted(color.into()));
        self
    }

    /// Resplandor de color alrededor de la caja, sin desplazamiento.
    fn glow(self, color: impl Into<ColorSpec>, blur: f32) -> Self {
        self.shadow(crate::view::style::BoxShadow::new(0.0, 0.0, blur).color(color))
    }

    fn border_color(mut self, color: impl Into<ColorSpec>) -> Self {
        self.style().border_color = Some(color.into());
        self
    }

    /// Degradado lineal; `angle` en grados CSS (180 = de arriba hacia abajo).
    fn bg_gradient(mut self, angle: f32, from: impl Into<ColorSpec>, to: impl Into<ColorSpec>) -> Self {
        self.style().background = Some(from.into());
        self.style().extra_mut().gradient = Some((angle, to.into()));
        self
    }

    fn bg(mut self, color: impl Into<ColorSpec>) -> Self {
        self.style().background = Some(color.into());
        self
    }

    fn text_color(mut self, color: impl Into<ColorSpec>) -> Self {
        self.style().text_color = Some(color.into());
        self
    }

    fn text_size(mut self, size: Pixels) -> Self {
        self.style().font_size = Some(size);
        self
    }

    fn opacity(mut self, value: f32) -> Self {
        self.style().opacity = Some(value);
        self
    }

    fn overflow_hidden(mut self) -> Self {
        let style = self.style();
        style.overflow_x = Some(Overflow::Hidden);
        style.overflow_y = Some(Overflow::Hidden);
        self
    }
}

impl Styled for Style {
    fn style(&mut self) -> &mut Style {
        self
    }
}