17 releases (4 breaking)

new 0.6.1 Nov 19, 2024
0.6.0 Nov 19, 2024
0.5.0 Nov 18, 2024
0.4.0 Nov 17, 2024
0.1.0 Feb 23, 2024

#119 in GUI

Download history 3/week @ 2024-09-17 21/week @ 2024-09-24 1/week @ 2024-10-29 267/week @ 2024-11-05 761/week @ 2024-11-12

1,037 downloads per month
Used in bevy_mod_actuate

MIT/Apache

105KB
2.5K SLoC

Actuate

Crates.io version docs.rs docs CI status

A high-performance reactive user-interface framework for Rust. This crate provides a generic library that lets you define UI using declarative, borrow-checker friendly syntax.

Features

  • Efficient and borrow-checker friendly state management: Manage state with components and hooks, all using zero-cost smart pointers
  • High-performance multi-platform rendering with Vello
  • CSS Block, Flex, and Grid layout support with Taffy
  • Built-in accessibility via Accesskit
  • Generic core crate for custom use-cases (such as bevy_mod_actuate)
use actuate::prelude::*;

#[derive(Data)]
struct Counter {
    start: i32,
}

impl Compose for Counter {
    fn compose(cx: Scope<Self>) -> impl Compose {
        let count = use_mut(&cx, || cx.me().start);

        Window::new((
            Text::new(format!("High five count: {}", *count))
                .font(GenericFamily::Cursive)
                .font_size(60.),
            Text::new("Up high")
                .on_click(move || count.update(|x| *x += 1))
                .background_color(Color::BLUE),
            Text::new("Down low")
                .on_click(move || count.update(|x| *x -= 1))
                .background_color(Color::RED),
            if *count == 0 {
                Some(Text::new("Gimme five!"))
            } else {
                None
            },
        ))
        .font_size(40.)
    }
}

fn main() {
    actuate::run(Counter { start: 0 })
}

Borrowing

Composables can borrow from their ancestors, as well as state.

use actuate::prelude::*;

#[derive(Data)]
struct User<'a> {
    // `actuate::Cow` allows for either a borrowed or owned value.
    name: Cow<'a, String>,
}

impl Compose for User<'_> {
    fn compose(cx: Scope<Self>) -> impl Compose {
        Text::new(Ref::map(cx.me(), |me| &me.name))
    }
}

#[derive(Data)]
struct App {
    name: String
}

impl Compose for App {
    fn compose(cx: Scope<Self>) -> impl Compose {
        // Get a mapped reference to the app's `name` field.
        let name = Ref::map(cx.me(), |me| &me.name).into();

        User { name }
    }
}

actuate::run(App { name: String::from("Matt") })

Installation

To add this crate to your project:

cargo add actuate --features full

Inspiration

This crate is inspired by Xilem and uses a similar approach to type-safe reactivity. The main difference with this crate is the concept of scopes, components store their state in their own scope and updates to that scope re-render the component.

State management is inspired by React and Dioxus.

Previous implementations were in Concoct but were never very compatible with lifetimes.

Dependencies

~3–41MB
~660K SLoC