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.
//! Panel dividido redimensionable: el estado del tamaño vive en la vista dueña.

use crate::core::px;
use crate::view::interactivity::DragHandler;
use crate::view::prelude::*;
use std::rc::Rc;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SplitDirection {
    /// Paneles lado a lado; el divisor se arrastra en horizontal.
    Horizontal,
    /// Paneles apilados; el divisor se arrastra en vertical.
    Vertical,
}

pub struct SplitPane {
    direction: SplitDirection,
    first_size: Pixels,
    first: AnyElement,
    second: AnyElement,
    on_drag: Option<DragHandler>,
}

impl SplitPane {
    pub fn new(first: impl IntoElement, second: impl IntoElement) -> Self {
        Self {
            direction: SplitDirection::Horizontal,
            first_size: px(240.0),
            first: first.into_element(),
            second: second.into_element(),
            on_drag: None,
        }
    }

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

    /// Tamaño del primer panel en píxeles; el segundo ocupa el resto.
    pub fn first_size(mut self, size: Pixels) -> Self {
        self.first_size = size;
        self
    }

    /// Recibe la posición absoluta del puntero mientras se arrastra el divisor.
    pub fn on_resize(mut self, handler: impl Fn(&DragEvent, &mut EventContext) + 'static) -> Self {
        self.on_drag = Some(Rc::new(handler));
        self
    }
}

impl IntoElement for SplitPane {
    fn into_element(self) -> AnyElement {
        let horizontal = self.direction == SplitDirection::Horizontal;
        let handler = self.on_drag.clone();
        let grip = div()
            .flex_shrink_0()
            .bg(Token::BorderSubtle)
            .hover(|style| style.bg(Token::Accent))
            .active(|style| style.bg(Token::Accent))
            .when(horizontal, |grip| grip.w(px(4.0)).h_full().cursor_col_resize())
            .when(!horizontal, |grip| grip.h(px(4.0)).w_full().cursor_row_resize())
            .when_some(handler, |grip, handler| grip.on_drag(move |event, cx| handler(event, cx)));

        let first = div()
            .flex_shrink_0()
            .overflow_hidden()
            .when(horizontal, |pane| pane.w(self.first_size).h_full())
            .when(!horizontal, |pane| pane.h(self.first_size).w_full())
            .child(self.first);
        let second = div().flex_1().overflow_hidden().child(self.second);

        div()
            .size_full()
            .when(!horizontal, |pane| pane.flex_col())
            .child(first)
            .child(grip)
            .child(second)
            .into_element()
    }
}