Skip to main content

repose_core/
lib.rs

1//! # State, Signals, and Effects
2//!
3//! Repose uses a small reactive core instead of an explicit widget tree with
4//! mutable fields. There are three main pieces:
5//!
6//! - `Signal<T>` - observable, reactive value.
7//! - `remember*` - lifecycle‑aware storage bound to composition.
8//! - `effect` / `scoped_effect` - side‑effects with cleanup.
9//!
10//! ## Signals
11//!
12//! `Signal<T>` is a cloneable handle to a piece of state:
13//!
14//! ```rust
15//! use repose_core::*;
16//!
17//! let count = signal(0);
18//! count.set(1);
19//! count.update(|v| *v += 1);
20//! assert_eq!(count.get(), 2);
21//! ```
22//!
23//! Reads participate in a dependency graph: when you call `get()` inside an
24//! observer or `produce_state`, future writes will automatically recompute that
25//! observer.
26//!
27//! ## Remembered state
28//!
29//! UI state is typically held in `remember_*` slots rather than globals:
30//!
31//! ```ignore
32//! use repose_core::*;
33//!
34//! fn CounterView() -> View {
35//!     let count = remember_state(|| 0); // Rc<RefCell<i32>>
36//!
37//!     let on_click = {
38//!         let count = count.clone();
39//!         move || *count.borrow_mut() += 1
40//!     };
41//!
42//!     repose_ui::Button(
43//!         format!("Count = {}", *count.borrow()),
44//!         on_click,
45//!     )
46//! }
47//! ```
48//!
49//! - `remember` and `remember_state` are order‑based: the Nth call in a
50//!   composition slot always refers to the Nth stored value.
51//! - `remember_with_key` and `remember_state_with_key` are key‑based and more
52//!   stable across conditional branches.
53//!
54//! ## Derived state
55//!
56//! `produce_state` computes a `Signal<T>` from other signals and recomputes it
57//! automatically when dependencies change:
58//!
59//! ```rust
60//! use repose_core::*;
61//!
62//! let first = signal("Jane".to_string());
63//! let last  = signal("Doe".to_string());
64//!
65//! let full = produce_state("full_name", {
66//!     let first = first.clone();
67//!     let last  = last.clone();
68//!     move || format!("{} {}", first.get(), last.get())
69//! });
70//!
71//! assert_eq!(full.get(), "Jane Doe");
72//! ```
73//!
74//! ## Effects and cleanup
75//!
76//! Use `effect` / `scoped_effect` for one‑off side‑effects with cleanups:
77//!
78//! ```ignore
79//! use repose_core::*;
80//!
81//! fn Example() -> View {
82//!     scoped_effect(|| {
83//!         log::info!("Mounted Example");
84//!         on_unmount(|| log::info!("Unmounted Example"))
85//!     });
86//!
87//!     // ...
88//!     repose_ui::Box(Modifier::new())
89//! }
90//! ```
91//!
92//! - `effect` runs once when the view is composed and returns a `Dispose`
93//!   guard that will be run when the scope is torn down.
94//! - `scoped_effect` is wired to the current `Scope` and is cleaned up on
95//!   scope disposal (e.g. when a navigation entry is popped).
96//!
97//! For long‑running tasks (network, timers), prefer building small helpers on
98//! top of `scoped_effect` so everything cleans up correctly when the UI that
99//! owns it disappears.
100
101pub mod animation;
102pub mod color;
103pub mod cursor;
104pub mod dnd;
105pub mod effects;
106pub mod effects_ext;
107pub mod error;
108pub mod frame_clock;
109pub mod geometry;
110pub mod input;
111pub mod locals;
112pub mod modifier;
113pub mod prelude;
114pub mod reactive;
115pub mod render_api;
116pub mod runtime;
117pub mod scope;
118pub mod semantics;
119pub mod shortcuts;
120pub mod signal;
121pub mod state;
122pub mod tests;
123pub mod text;
124pub mod view;
125
126pub use color::*;
127pub use cursor::*;
128pub use dnd::*;
129pub use effects::*;
130pub use effects_ext::*;
131pub use frame_clock::{peek_frame_request, request_frame, take_frame_request};
132pub use geometry::*;
133pub use locals::*;
134pub use modifier::*;
135pub use prelude::*;
136pub use reactive::*;
137pub use render_api::*;
138pub use runtime::*;
139pub use runtime::{FocusDirection, FocusManager, FocusRequester, take_focus_request};
140pub use semantics::*;
141pub use signal::*;
142pub use state::*;
143pub use text::*;
144pub use view::*;
145
146pub use repose_macros::View;
147
148// Ensure a clock is installed even if platform didn't (tests, benches).
149#[doc(hidden)]
150#[allow(dead_code)]
151fn __ensure_clock() {
152    animation::ensure_system_clock();
153}