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.
//! PestaƱas del editor: `Tab` individual y `TabBar` contenedora.

use crate::core::px;
use crate::view::interactivity::ClickHandler;
use crate::view::prelude::*;
use crate::widgets::separator::horizontal_separator;
use std::rc::Rc;

pub struct Tab {
    label: String,
    active: bool,
    id: Option<String>,
    on_click: Option<ClickHandler>,
}

impl Tab {
    pub fn new(label: impl Into<String>) -> Self {
        Self { label: label.into(), active: false, id: None, on_click: None }
    }

    pub fn active(mut self, active: bool) -> Self {
        self.active = active;
        self
    }

    pub fn id(mut self, id: impl Into<String>) -> Self {
        self.id = Some(id.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 Tab {
    fn into_element(self) -> AnyElement {
        let indicator = if self.active { Token::Accent } else { Token::Surface };
        let handler = self.on_click.clone();
        div()
            .role(Role::Tab)
            .label(self.label.clone())
            .flex_col()
            .h_full()
            .bg(if self.active { Token::Canvas } else { Token::Surface })
            .hover(|style| style.bg(Token::Hover))
            .when_some(self.id, |tab, id| tab.id(id))
            .when_some(handler, |tab, handler| tab.cursor_pointer().on_click(move |event, cx| handler(event, cx)))
            .child(div().w_full().h(px(2.0)).bg(indicator))
            .child(
                div()
                    .flex_1()
                    .flex_row()
                    .items_center()
                    .px_3()
                    .text_sm()
                    .text_color(if self.active { Token::Text } else { Token::TextMuted })
                    .child(self.label),
            )
            .into_element()
    }
}

pub struct TabBar {
    tabs: Vec<Tab>,
}

impl TabBar {
    pub fn new() -> Self {
        Self { tabs: Vec::new() }
    }

    pub fn tab(mut self, tab: Tab) -> Self {
        self.tabs.push(tab);
        self
    }
}

impl Default for TabBar {
    fn default() -> Self {
        Self::new()
    }
}

impl IntoElement for TabBar {
    fn into_element(self) -> AnyElement {
        div()
            .flex_col()
            .w_full()
            .h(px(36.0))
            .flex_shrink_0()
            .bg(Token::Surface)
            .child(div().flex_1().flex_row().children(self.tabs))
            .child(horizontal_separator())
            .into_element()
    }
}