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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
//! # The Resolve Pattern
//!
//! The resolve pattern is `WaterUI`'s core abstraction for **dynamic, reactive configuration**.
//! Instead of hard-coding values, types implement [`Resolvable`](crate::resolve::Resolvable) to look up their actual
//! values from an [`Environment`] at runtime, returning a **reactive signal** that
//! automatically updates when the environment changes.
//!
//! ## For Users
//!
//! ### What is Resolvable?
//!
//! When you use a `Color` or `Font` in `WaterUI`, you're not specifying a fixed value—you're
//! specifying something that will be **resolved** against the current environment. This
//! enables powerful features like theming and dark mode.
//!
//! ```text
//! // This color isn't "#FF0000" - it's "whatever the Accent color is in this
//! // environment". Shown as text: the authoring layer lives in crates that
//! // depend on this one, so it cannot be compiled from here.
//! use waterui::theme::color::Accent;
//! text("Hello").foreground(Accent)
//! ```
//!
//! ### Why Reactive?
//!
//! The key insight is that `resolve()` returns a [`Signal`](nami::Signal), not a plain value.
//! This means:
//!
//! 1. **Native backends can inject reactive signals** - The iOS/Android runtime can inject
//! system colors that update when the user toggles dark mode.
//! 2. **Views automatically re-render** - When the signal's value changes, any view using
//! that resolved value will update without manual intervention.
//! 3. **No rebuild required** - Theme changes propagate instantly through the entire UI.
//!
//! ### The Flow
//!
//! ```text
//! ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
//! │ Native Backend │ │ Environment │ │ View │
//! │ (iOS/Android) │ │ │ │ │
//! └────────┬────────┘ └────────┬────────┘ └────────┬────────┘
//! │ │ │
//! │ 1. Create reactive │ │
//! │ signal (Computed) │ │
//! │──────────────────────>│ │
//! │ │ │
//! │ 2. Install into env │ │
//! │ via Theme::install │ │
//! │──────────────────────>│ │
//! │ │ │
//! │ │ 3. View resolves │
//! │ │ Accent.resolve(env)│
//! │ │<──────────────────────│
//! │ │ │
//! │ │ 4. Returns Computed │
//! │ │ (reactive signal) │
//! │ │──────────────────────>│
//! │ │ │
//! │ 5. User toggles │ │
//! │ dark mode │ │
//! │──────────────────────>│ 6. Signal updates │
//! │ │──────────────────────>│
//! │ │ View re-renders │
//! ```
//!
//! ## For Maintainers
//!
//! ### Implementing Resolvable
//!
//! To make a type resolvable, implement the [`Resolvable`](crate::resolve::Resolvable) trait:
//!
//! ```
//! use nami::{Computed, Signal};
//! use waterui_core::{Environment, resolve::Resolvable};
//!
//! #[derive(Debug, Clone, Copy)]
//! pub struct MyToken;
//!
//! impl Resolvable for MyToken {
//! type Resolved = u32;
//!
//! fn resolve(&self, env: &Environment) -> impl Signal<Output = Self::Resolved> {
//! env.query::<Self, Computed<u32>>()
//! .cloned()
//! .unwrap_or_else(|| Computed::constant(0))
//! }
//! }
//! ```
//!
//! ### Key Types
//!
//! - [`Resolvable`](crate::resolve::Resolvable) - The core trait. Implementations look up values from the environment.
//! - [`AnyResolvable<T>`](crate::resolve::AnyResolvable) - Type-erased wrapper for storing heterogeneous resolvables.
//! - [`Map<R, F>`](crate::resolve::Map) - Transforms a resolvable's output (e.g., adjust opacity on a color).
//!
//! ### Integration with Theme System
//!
//! The theme system uses this pattern to inject platform-specific colors and fonts:
//!
//! 1. Native backend creates `Computed<ResolvedColor>` signals from system palette
//! 2. `Theme::install()` stores these signals in the environment keyed by token type
//! 3. Token types (e.g., `color::Foreground`) implement `Resolvable` to query these signals
//! 4. When the native signal updates, all views using that token automatically update
//!
//! ### The nami Signal System
//!
//! This module integrates with [nami](https://github.com/aspect-rs/nami), `WaterUI`'s reactive
//! primitives library. Key concepts:
//!
//! - `Signal` - A trait for values that can change over time
//! - `Computed<T>` - A cached, reactive value that re-evaluates when dependencies change
//! - `.computed()` - Converts any `impl Signal` into a `Computed` for storage/cloning
use Box;
use fmt;
use Debug;
use ;
use crateEnvironment;
/// A trait for types that can be resolved to a reactive value from an environment.
///
/// This is the core abstraction for `WaterUI`'s dynamic configuration system. Types that
/// implement `Resolvable` don't hold their final value directly—instead, they know how
/// to look up or compute that value from an [`Environment`].
///
/// # Contract
///
/// - The same `Resolvable` instance resolved against the same `Environment` should return
/// a signal that produces equivalent values (though the signal itself may be a new instance).
/// - The returned signal is **reactive**: if the underlying data in the environment changes,
/// the signal will emit updated values.
///
/// # Example
///
/// ```
/// use nami::{Computed, Signal};
/// use waterui_core::{Environment, resolve::Resolvable};
///
/// /// A token standing for the primary brand tint, as packed `0xRRGGBB`.
/// #[derive(Debug, Clone, Copy)]
/// pub struct BrandTint;
///
/// impl Resolvable for BrandTint {
/// type Resolved = u32;
///
/// fn resolve(&self, env: &Environment) -> impl Signal<Output = Self::Resolved> {
/// // Query the environment for a pre-installed signal, and fall back to
/// // a constant when the backend installed none.
/// env.query::<Self, Computed<u32>>()
/// .cloned()
/// .unwrap_or_else(|| Computed::constant(0x0066_CC))
/// }
/// }
///
/// let tint = BrandTint.resolve(&Environment::new());
/// ```
/// A type-erased wrapper for any resolvable value.
///
/// `AnyResolvable<T>` allows storing different `Resolvable` implementations that all
/// resolve to the same output type `T`. This is essential for types like `Color` and
/// `Font` which can be constructed from many different sources (hex strings, theme
/// tokens, computed values) but all resolve to the same concrete type.
///
/// # Example
///
/// ```
/// use nami::{Computed, Signal};
/// use waterui_core::{Environment, resolve::{AnyResolvable, Map, Resolvable}};
///
/// #[derive(Debug, Clone, Copy)]
/// struct Accent;
///
/// impl Resolvable for Accent {
/// type Resolved = u32;
/// fn resolve(&self, _env: &Environment) -> impl Signal<Output = Self::Resolved> {
/// Computed::constant(0x0066_CC)
/// }
/// }
///
/// // Both resolve to the same concrete type, from different sources.
/// let from_token: AnyResolvable<u32> = AnyResolvable::new(Accent);
/// let from_mapped: AnyResolvable<u32> = AnyResolvable::new(Map::new(Accent, |tint| tint >> 1));
/// ```
/// A mapping type that transforms a resolvable value using a function.
///
/// `Map` wraps an existing `Resolvable` and applies a transformation function to its
/// resolved output. This enables fluent APIs like `color.lighten(0.2)` or
/// `font.with_weight(Bold)` without losing reactivity.
///
/// # Example
///
/// ```
/// use nami::{Computed, Signal};
/// use waterui_core::{Environment, resolve::{Map, Resolvable}};
///
/// #[derive(Debug, Clone, Copy)]
/// struct Accent;
///
/// impl Resolvable for Accent {
/// type Resolved = u32;
/// fn resolve(&self, _env: &Environment) -> impl Signal<Output = Self::Resolved> {
/// Computed::constant(0x0066_CC)
/// }
/// }
///
/// // Halve the accent's brightness without losing reactivity.
/// let dimmed = Map::new(Accent, |tint| tint >> 1);
/// ```
///
/// The transformation is applied lazily when the signal emits, so if the underlying
/// `Accent` color changes (e.g., dark mode toggle), the lighter version updates too.