aura-gui 0.3.0

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.
//! El árbol de accesibilidad solo existe con un lector activo y expone roles, etiquetas y acciones.

use accesskit::{Action, ActionRequest, NodeId, Role, TreeId};
use aura_ui::view::prelude::*;
use aura_ui::view::test_context::TestWindow;

#[derive(Default)]
struct Panel {
    clicks: usize,
}

impl Component for Panel {
    fn view(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
        div()
            .size_full()
            .flex_col()
            .child(text("Guardar cambios"))
            .child(div().role(Role::Button).label("Guardar").w(px(100.0)).h(px(30.0)).on_click(cx.listener(
                |this: &mut Panel, _: &ClickEvent, cx| {
                    this.clicks += 1;
                    cx.notify();
                },
            )))
            .into_element()
    }
}

#[test]
fn nothing_is_registered_until_a_screen_reader_asks() {
    let (test, _) = TestWindow::new(|_| Panel::default());
    assert!(test.window.accessibility_tree().nodes.len() == 1, "solo la ventana raíz");
}

#[test]
fn the_tree_lists_roles_labels_and_actions() {
    let (mut test, _) = TestWindow::new(|_| Panel::default());
    test.window.set_accessibility(true);
    test.window.draw(None);
    let tree = test.window.accessibility_tree();
    let find = |role: Role| tree.nodes.iter().find(|(_, node)| node.role() == role).map(|(id, node)| (*id, node));
    let (_, label) = find(Role::Label).expect("el texto se anuncia solo");
    assert_eq!(label.label(), Some("Guardar cambios"));
    let (_, button) = find(Role::Button).expect("botón");
    assert_eq!(button.label(), Some("Guardar"));
    assert!(button.supports_action(Action::Click));
    assert!(button.bounds().is_some_and(|bounds| bounds.x1 - bounds.x0 == 100.0));
}

#[test]
fn a_click_action_presses_the_button() {
    let (mut test, panel) = TestWindow::new(|_| Panel::default());
    test.window.set_accessibility(true);
    test.window.draw(None);
    let tree = test.window.accessibility_tree();
    let button = tree.nodes.iter().find(|(_, node)| node.role() == Role::Button).map(|(id, _)| *id).expect("botón");
    let request =
        ActionRequest { action: Action::Click, target_tree: TreeId::ROOT, target_node: NodeId(button.0), data: None };
    test.window.accessibility_action(&request);
    test.read(panel, |panel| assert_eq!(panel.clicks, 1));
}