freya/_docs/ui_and_components.rs
1//! # UI and Components
2//!
3//! Freya uses a [declarative](https://en.wikipedia.org/wiki/Declarative_programming) model for the UI.
4//! This means that you dont instantiate e.g Buttons, you simply declare them and Freya will take care of running them and painting them on screen.
5//!
6//! Example of how the UI is declared:
7//!
8//! ```rust, no_run
9//! # use freya::prelude::*;
10//! # fn app() -> impl IntoElement {
11//! rect()
12//! .background((255, 0, 0))
13//! .width(Size::fill())
14//! .height(Size::px(100.))
15//! .on_mouse_up(|_| println!("Clicked!"))
16//! # }
17//! ```
18//!
19//! You can also split your UI in reusable pieces called **Components**.
20//!
21//! ### [Component](freya_core::prelude::Component) trait
22//!
23//! For normal components you may use the [Component](freya_core::prelude::Component) trait.
24//!
25//! ```rust
26//! # use freya::prelude::*;
27//! #[derive(PartialEq)]
28//! struct App;
29//!
30//! impl Component for App {
31//! fn render(&self) -> impl IntoElement {
32//! "Hello, World!"
33//! }
34//! }
35//! ```
36//!
37//! ## App/Root Component
38//! The app/root component is the component passed to [WindowConfig](crate::prelude::WindowConfig).
39//!
40//! For convenience it can be a `Fn() -> Element` instead of a struct that implements [Component](freya_core::prelude::Component).
41//!
42//! ```rust
43//! # use freya::prelude::*;
44//! fn app() -> impl IntoElement {
45//! "Hello, World!"
46//! }
47//! ```
48//!
49//! If you wanted to pass data from your **main** function to your **root** component you would need to make it use a struct component, like this:
50//!
51//! ```rust, no_run
52//! # use freya::prelude::*;
53//! fn main() {
54//! launch(
55//! LaunchConfig::new()
56//! .with_window(WindowConfig::new(AppComponent::new(App { number: 1 }))),
57//! )
58//! }
59//!
60//! #[derive(PartialEq)]
61//! struct App {
62//! number: u8,
63//! }
64//!
65//! impl Component for App {
66//! fn render(&self) -> impl IntoElement {
67//! label().text(self.number.to_string())
68//! }
69//! }
70//! ```
71//!
72//! To separate the UI of the app you may create more components.
73//!
74//! ```rust
75//! # use freya::prelude::*;
76//! # use std::borrow::Cow;
77//! // Reusable component that we might call as many times we want
78//! #[derive(PartialEq)]
79//! struct TextLabel(Cow<'static, str>);
80//! impl Component for TextLabel {
81//! fn render(&self) -> impl IntoElement {
82//! label().text(self.0.clone())
83//! }
84//! }
85//!
86//! fn app() -> impl IntoElement {
87//! rect()
88//! .child(TextLabel("Number 1".into()))
89//! .child("Number 2")
90//! .child(TextLabel("Number 3".into()))
91//! }
92//! ```
93//!
94//! Notice how all these component are returning an [`Element`](freya_core::prelude::Element), this is because `rect()` gives you a [`Rect`](freya_core::elements::rect::Rect) which implements `Into<Element>` / `IntoElement`, same happens for the rest of elements.
95//! So, in other words, the [`Element`](freya_core::prelude::Element) contains the UI of that component.
96//! Every time the component render function reruns a new UI is created and later diffed by Freya internally.
97//!
98//! ## Renders
99//!
100//! "Components renders" are simply when the component's `render` function runs, this can happen in multiple scenarios:
101//!
102//! 1. The component just got instantiated for the first time (also called mounted in other UI libraries)
103//! 2. A state that this component is reading (thus subscribed to), got mutated
104//! 3. The component data (also called props) changed (this is why `PartialEq` is required)
105//!
106//! > **Note:** The naming of `render` might give you the impression that it means the window canvas will effectively rerender again, it has nothing to do with it, in fact, a component might render (run its function) a thousand times but generate the exact same UI, if that was the case Freya would not render the canvas again.
107//!
108//! Consider this simple component:
109//!
110//! ```rust
111//! # use freya::prelude::*;
112//! #[derive(PartialEq)]
113//! struct CoolComp;
114//!
115//! impl Component for CoolComp {
116//! // One run of this function is the same as saying one render of this component
117//! fn render(&self) -> impl IntoElement {
118//! let mut count = use_state(|| 0);
119//!
120//! label()
121//! .on_mouse_up(move |_| *count.write() += 1)
122//! // Here we subscribe to `count` because we called .read() on it
123//! .text(format!("Increase {}", count.read()))
124//! }
125//! }
126//! ```