aura-gui 0.2.2

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.
//! Botón de solo icono, con estado conmutado opcional (opciones de búsqueda, paneles), y `tool_button` para iconos
//! propios de la app (`Svg`) con estado deshabilitado.

use crate::core::px;
use crate::view::interactivity::ClickHandler;
use crate::view::media::Svg;
use crate::view::prelude::*;
use crate::widgets::icons::{IconName, icon};
use std::rc::Rc;

pub struct IconButton {
    icon: IconName,
    selected: bool,
    tooltip: Option<String>,
    on_click: Option<ClickHandler>,
}

impl IconButton {
    pub fn new(icon: IconName) -> Self {
        Self { icon, selected: false, tooltip: None, on_click: None }
    }

    /// Estilo de "activado", para usarlo como interruptor.
    pub fn selected(mut self, selected: bool) -> Self {
        self.selected = selected;
        self
    }

    pub fn tooltip(mut self, text: impl Into<String>) -> Self {
        self.tooltip = Some(text.into());
        self
    }

    pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut EventContext) + 'static) -> Self {
        self.on_click = Some(Rc::new(handler));
        self
    }
}

impl IntoElement for IconButton {
    fn into_element(self) -> AnyElement {
        let handler = self.on_click.clone();
        div()
            .role(Role::Button)
            .label(self.tooltip.clone().unwrap_or_default())
            .flex_row()
            .items_center()
            .justify_center()
            .size(px(24.0))
            .flex_shrink_0()
            .rounded_md()
            .text_color(if self.selected { Token::AccentText } else { Token::TextMuted })
            .when(self.selected, |button| button.bg(Token::Accent))
            .hover(|style| style.bg(Token::Hover).text_color(Token::Text))
            .when_some(handler, |button, handler| button.cursor_pointer().on_click(move |event, cx| handler(event, cx)))
            .when_some(self.tooltip, |button, text| button.tooltip(text))
            .child(icon(self.icon).size(px(14.0)))
            .into_element()
    }
}

/// Botón cuadrado con un icono cualquiera (`Svg`) y tooltip. Deshabilitado no responde al clic ni al puntero.
pub fn tool_button(
    icon: Svg,
    tip: &str,
    enabled: bool,
    on_click: impl Fn(&ClickEvent, &mut EventContext) + 'static,
) -> Div {
    let button = div()
        .role(Role::Button)
        .label(tip)
        .flex_row()
        .items_center()
        .justify_center()
        .flex_shrink_0()
        .w(px(28.0))
        .h(px(28.0))
        .rounded_md()
        .text_color(Token::Text)
        .tooltip(tip)
        .child(icon.size(px(15.0)))
        .pressable_if(enabled);
    if enabled { button.on_click(on_click) } else { button }
}