1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//! # Floem
//! Floem is a cross-platform GUI library for Rust. It aims to be extremely performant while providing world-class developer ergonomics.
//!
//! The following is a simple example to demonstrate Floem's API and capabilities.
//!
//! ## Example: Counter
//! ```rust
//! use floem::prelude::*;
//!
//! let mut counter = RwSignal::new(0);
//!
//! v_stack((
//! label(move || format!("Value: {counter}")),
//! h_stack((
//! button("Increment").action(move || counter += 1),
//! button("Decrement").action(move || counter -= 1),
//! )),
//! ));
//! ```
//! This example demonstrates the core concepts of building a reactive GUI with Floem:
//!
//! - State Management: The `RwSignal` provides a reactive way to manage the counter's state.
//! - Widgets: Common UI elements like `stack`, `label`, and `button` are easily implemented.
//! - Reactivity: The label automatically updates when the counter changes.
//! - Event Handling: Button clicks are handled with simple closures that modify the state.
//!
//! Floem's objectives prioritize simplicity and performance, enabling the development of complex graphical user interfaces with minimal boilerplate.
//!
//! ## Views
//! Floem models the UI using a tree of [Views](view::View). Views, such as the `h_stack`, `label`, and
//! `button` elements are the building blocks of UI in Floem.
//!
//! Floem's main view tree is constructed only once.
//! This guards against unnecessary and expensive rebuilds of your views;
//! however, even though the tree is built only once, views can still receive reactive updates.
//!
//! ### Composition and Flexibility
//! Views in Floem are composable, allowing for the construction of complex user interfaces by integrating simpler components.
//! In the counter example, label and button views were combined within vertical (v_stack) and horizontal (h_stack) layouts to create a more intricate interface.
//!
//! This compositional approach provides the following benefits:
//! - Reusable UI components
//! - Easy and consistent refactoring
//!
//! ### Learn More
//! Floem provides a set of built-in views to help you create UIs quickly.
//! To learn more about the built-in views, check out the [views module](crate::views) documentation.
//!
//! ## State management
//!
//! Floem uses a reactive system built on signals and effects for its state management.
//!
//! Floem uses its own reactive system with an API that is similar to the one in the [leptos_reactive](https://docs.rs/leptos_reactive/latest/leptos_reactive/index.html) crate.
//!
//! ### Signals as State
//!
//! You can create reactive state by creating a signal anywhere in the program using [`RwSignal::new()`](floem_reactive::RwSignal::new), [`RwSignal::new_split()`](floem_reactive::RwSignal::new_split), or use a [different signal type](floem_reactive).
//!
//! When you use a signal by calling the [`get`](floem_reactive::SignalGet::get) or [`with`](floem_reactive::SignalWith::with) methods, (which are also called when you use an operator such as `==`)
//! the runtime will automatically subscribe the correct side effects
//! to changes in that signal, creating reactivity. To the programmer this is transparent.
//! By simply accessing the value where you want to use it, the reactivity will "just work" and
//! your views will stay in sync with changes to that signal.
//!
//!
//! #### Example: Changing Text
//! ```rust
//! # use floem::reactive::*;
//! # use floem::views::*;
//! # use floem::IntoView;
//! fn app_view() -> impl IntoView {
//!
//! // All signal types implement `Copy`, so they can be easily used without needing to manually clone them.
//! let text = RwSignal::new("Hello, World!".to_string());
//!
//! let label_view = label(move || text.get());
//!
//! let button = button("Change Text").action(move || text.set("Hello, Floem!".to_string()));
//!
//! v_stack((button, label_view))
//! }
//! ```
//!
//! In this example, `text` is a signal containing a `String` that can be both read from and written to.
//! The button, when clicked, changes the text in the signal.
//! The label view is subscribed to changes in the `text` signal and will automatically trigger a re-render with the updated text value whenever the signal changes.
//!
//! ### Functions as a Primitive of Reactivity
//!
//! The most fundamental primitive of reactivity is a function that can be re-run in response to changes in a signal.
//! For this reason, many of Floem's APIs accept functions as arguments (such as in the label view in the `Changing Text` example above).
//! Most of the functions is Floem's API will
//! update reactively, but not all of them do. For this reason, all arguments in Floem's API that are functions will
//! be marked with a `# Reactivity` section that will inform you if the function will be re-run in response to reactive updates.
//!
//! ### Learn More
//! To learn more about signals and
//! effects, you may want to explore the Leptos [documentation](https://docs.rs/leptos_reactive/latest/leptos_reactive/index.html)
//! and the [leptos book](https://leptos-rs.github.io/leptos/).
//!
//! ## Style: Customizing Appearance
//!
//! Floem has a powerful, built-in styling system that allows you to customize the appearance of your UI.
//!
//! Example:
//! ```
//! # use floem::peniko::Color;
//! # use floem::reactive::*;
//! # use floem::style::Style;
//! # use floem::unit::UnitExt;
//! # use floem::View;
//! # use floem::views::{text, Decorators};
//! #
//! text("Some text").style(|s| s.font_size(21.).color(Color::DARK_GRAY));
//! ```
//!
//! The text view is styled by calling the [`style`](crate::views::Decorators::style) method (you'll need to import the
//! [`Decorators`](crate::views::Decorators) trait to use the it). The `style` method takes a closure that takes and returns a
//! [`Style`](crate::style::Style) value using the builder pattern. Through this value, you can access methods that modify a variety
//! of familiar properties such as width, padding, and background. Some `Style` properties
//! such as font size are `inherited` and will apply to all of a view's children until overridden.
// TODO: Add links on these
//!
//! In this same style value, floem supports:
//! - themeing with [classes](style::Style::class)
//! - [property transitions](style::Style::transition)
//! - defining styles on different [interaction states](style::Style::hover)
//! - reactive updates
//! - applying styles [conditionally](style::Style::apply_if)
//! - setting custom properties
//! - and more
//!
//! For additional information about styling, [see here](crate::style).
//!
//! ## Animation
//!
//! In addition to [property transitions](style::Style::transition) that can be added to `Style`s,
//! Floem has a full keyframe animation system that allows you to animate any property that can be [interpolated](style::StylePropValue::interpolate) and builds on the capabilities and ergonomics of the style system.
//!
//! Animations in Floem, by default, have keyframes ranging from 0-100.
//!
//! #### Example: Rectangle to Square
//!
//! ```
//! # use floem::peniko::Color;
//! # use floem::reactive::*;
//! # use floem::style::Style;
//! # use floem::unit::{UnitExt, DurationUnitExt};
//! # use floem::View;
//! # use floem::views::*;
//! #
//! empty()
//! .style(|s| s.background(Color::RED).size(500, 100))
//! .animation(move |a| {
//! a.duration(5.seconds())
//! .keyframe(0, |f| f.computed_style())
//! .keyframe(50, |f| {
//! f.style(|s| s.background(Color::BLACK).size(30, 30))
//! .ease_in()
//! })
//! .keyframe(100, |f| {
//! f.style(|s| s.background(Color::AQUAMARINE).size(10, 300))
//! .ease_out()
//! })
//! .auto_reverse(true)
//! .repeat(true)
//! });
//! ```
//! - The first keyframe will use the computed style, which will include the red background with size of 500x100.
//! - At 50%, the animation will animate to a black square of 30x30 with a bezier easing of ease_in.
//! - At 100% the animation will animate to an aquamarine rectangle of 10x300 with an bezier easing of ease_out.
//! - The animation is also set to automatically reverse (the animation will run and reverse in 5 seconds) and repeat forever.
//!
//! You can add aninimations to a View instance by calling the [`animation`](crate::views::Decorators::animation) method from the `Decorators` trait.
//! The `animation` method takes a closure that takes and returns an [`Animation`](crate::animate::Animation) value using the builder pattern.
//!
//! For additional information about animation, [see here](crate::animate::Animation).
pub
pub
pub
pub
pub
pub
pub use ;
pub use AppState;
pub use ;
pub use floem_reactive as reactive;
pub use text;
use Renderer;
pub use ViewId;
pub use peniko;
pub use kurbo;
pub use ScreenLayout;
pub use taffy;
pub use ;
pub use ;
pub use ;