Key Concepts
Components

Components

The atomic unit of Pax is a component definition. A component definition for MyNewComponent may look like:

lib.rs
//File: lib.rs
#![allow(unused_imports)]
 
use pax_engine::api::*;
use pax_engine::*;
use pax_std::components::Stacker;
use pax_std::components::*;
use pax_std::primitives::*;
use pax_std::types::text::*;
use pax_std::types::*;
 
#[pax]
#[main]
#[file("lib.pax")]
pub struct Example {
    pub ticks: Property<usize>,
    pub num_clicks: Property<usize>,
}
 
impl Example {
    pub fn handle_pre_render(&mut self, ctx: &NodeContext) {
        let old_ticks = self.ticks.get();
        self.ticks.set((old_ticks + 1) % 255);
    }
 
    pub fn increment(&mut self, ctx: &NodeContext, args: Event<Click>) {
        let old_num_clicks = self.num_clicks.get();
        self.num_clicks.set(old_num_clicks + 1);
    }
}
increment-me.pax
<Group x=50% y=50% width=120px height=120px @click=self.increment >
    <Text text={self.num_clicks + " clicks"} id=text />
    <Rectangle
        fill={rgb(ticks, 75, 150)}
        corner_radii={RectangleCornerRadii::radii(10.0,10.0,10.0,10.0)}
    />
</Group>
 
@settings {
    @pre_render: handle_pre_render,
    #text {
        style: {
                font: {Font::system("Times New Roman", FontStyle::Normal, FontWeight::Bold)},
                font_size: 22px,
                fill: WHITE,
                align_vertical: TextAlignVertical::Center,
                align_horizontal: TextAlignHorizontal::Center,
                align_multiline: TextAlignHorizontal::Center
        }
    }
}

You can think of the component definition as a package for a number of different interconnected pieces.

Inside a component definition, there may be:

A component definition centers around a Rust struct, to which a piece of Pax is attached to through the macro #[pax]. Pax can either be attached inline using the inlined() attribute or link to a .pax file using the file() attribute using a relative path. For example, the following defines an empty component called EmptyComponent:

use pax_lang::api::*;
use pax_std::primitives::Group;
 
#[pax]
#[inlined(<Group />)] //a one-element template, simply an empty Group
pub struct EmptyComponent {
    //no properties
}

Any component created in Pax can be used inside other components — for example, EmptyComponent can be imported and used in another component's template like:

use pax_lang::api::*;
use crate::EmptyComponent;
 
#[pax]
#[inlined(<EmptyComponent />)] //another one-element template, ultimately still not rendering anything
pub struct StillEmptyComponent {
    //no properties
}

This "components all the way down" pattern may be familiar if you have used a GUI framework like React or Vue.

This is essentially how you define a Pax Component. The only exception is the root component which is signified with the main attribute and lives in the root lib.rs.

Notice that Pax builds off of Rust's import and namespace resolution mechanisms, so importing crate::EmptyComponent to a .rs file means that you can use <EmptyComponent /> inside a template in that file.

You can read more about Pax components in the chapter Hardware Component Model.




A biological cell with computer chips for organelles

A biological cell with computer chips for organelles