Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

tuirealm_derive

logo

~ Automatically implements Component ~

Get started · tui-realm · Documentation

Developed by @veeso

Current version: 4.0.0 (2026-04-18)

License-MIT Downloads counter Latest version Ko-fi


About tuirealm_derive 👑

tuirealm_derive is a crate which implements the procedural macro Component which can be used to automatically implement the Component trait for a tui-realm Component. Indeed, as you already know if you're a tui-realm user, you've got two kind of component entities:

  • Component: generic graphic component which is not bridged to the application and is "reusable"
  • Component: which uses a Component as "backend" and is bridged to the application using the Event -> Msg system.

The Component wraps the Component along with additional states. Such as:

pub struct IpAddressInput {
  component: Input,
}

impl Component for IpAddressInput {
  
  ...

  fn state(&self) -> State {
    self.component.state()
  }

  ...

}

impl AppComponent<Msg, UserEvent> for IpAddressInput {

  fn on(&mut self, ev: Event<UserEvent>) -> Option<Msg> {
    let cmd: Cmd = match ev {
      ...
    };
    match self.perform(cmd) {
      ...
    }
  }

}

Since AppComponent MUST implement Component, we need to implement the Component trait too, which in most of the case it will just call the Component methods on the inner component field. This is obviously kinda annoying to do for each component. That's why I implemented this procedural macro, which will automatically implement this logic on your component.

So basically instead of implementing Component for your app components, you can just do as follows:

#[derive(Component)]
pub struct IpAddressInput {
  component: Input,
}

impl AppComponent<Msg, UserEvent> for IpAddressInput {
  ...
}

With the directive #[derive(Component)] we don't have to implement the Component trait.

❗ In order to work, the procedural macro requires you to name the "inner" Component as component as I did in the example.

If we give a deeper look at the macro, we'll see that what it does is:

impl Component for IpAddressInput {
    fn view(&mut self, frame: &mut Frame, area: Rect) {
        self.component.view(frame, area);
    }

    fn query<'a>(&'a self, attr: Attribute) -> Option<QueryResult<'a>> {
        self.component.query(attr)
    }

    fn attr(&mut self, query: Attribute, attr: AttrValue) {
        self.component.attr(query, attr)
    }

    fn state(&self) -> State {
        self.component.state()
    }

    fn perform(&mut self, cmd: Cmd) -> CmdResult {
        self.component.perform(cmd)
    }
}

Get started 🏁

In order to get started with tuirealm_derive all you need to do is to add tui-realm to your dependencies and enable the derive feature if needed.

If you're using the default features:

[dependencies]
tuirealm = "^4"

If you're not using the default features, be sure to enable the derive feature:

[dependencies]
tuirealm = { version = "^4", default-features = false, features = ["derive", "crossterm"] }

⚠️ tuirealm_derive requires tui-realm >= 4.0.0; the old API is not supported

Then you need to include tuirealm in your project using the macro use directive:

src/lib.rs

#[macro_use]
extern crate tuirealm;

and finally derive Component on your components:

#[derive(Component)]
pub struct MyComponent {
  component: MyComponentImpl,
}

❗ In order to work, the procedural macro requires you to name the "inner" component as component as I did in the example.

And ta-dah, you're ready to go 🎉

Custom field names

By default a field of name component will be used as can be seen in the earlier examples, but this can be customized.

First option is to use a container-level attribute:

#[derive(Component)]
#[component("radio")]
pub struct MyComponent1 {
  radio: Radio,
}

#[derive(Component)]
#[component = "radio"]
pub struct MyComponent2 {
  radio: Radio,
}

Or field-level attribute:

#[derive(Component)]
pub struct MyComponent {
  #[component]
  radio: Radio,
}

❗ Only one field can be the component and container- & field-level attributes cannot be used together.

Tuple Structs are also supported:

#[derive(Component)]
pub struct MyComponent(Radio, SomeOtherType);

#[derive(Component)]
pub struct MyComponent(SomeOtherType, #[component] Radio);

Support the developer ☕

If you like tui-realm and you're grateful for the work I've done, please consider a little donation 🥳

You can make a donation with one of these platforms:

ko-fi PayPal


Changelog ⏳

View tuirealm_derive's changelog HERE


License 📃

tuirealm_derive is licensed under the MIT license.

You can read the entire license HERE