waterui-core
The foundational crate providing essential building blocks for the WaterUI cross-platform reactive UI framework.
Overview
waterui-core establishes the architectural foundation for WaterUI applications, enabling declarative, reactive user interfaces that render to native platform widgets. This crate provides the core abstractions used throughout the framework: the View trait for composable UI components, the Environment for type-safe context propagation, reactive primitives powered by the nami library, and type erasure utilities for dynamic composition.
Unlike traditional immediate-mode or retained-mode frameworks, WaterUI uses a reactive composition model where views automatically update when reactive state changes, and the entire view tree is transformed into native platform widgets (UIKit/AppKit on Apple platforms, Android View on Android) rather than custom rendering.
This crate is no_std compatible (with allocation) and works consistently across desktop, mobile, web, and embedded environments.
Installation
Add to your Cargo.toml:
[]
= "0.1.0"
For most applications, use the main waterui crate which re-exports all core functionality along with component libraries.
Quick Start
use ;
// Define a custom view
// Create an application environment
// Define the root view
Core Concepts
The View Trait
The View trait is the foundation of all UI components in WaterUI. It defines a single method that transforms the view into its rendered representation:
Views compose recursively - a view's body method returns another view, allowing complex UIs to be built from simple primitives. The framework handles the recursion, eventually reaching "raw views" (like Text, Button) that map directly to native widgets.
Implementing View for custom types:
use ;
Many standard types implement View automatically:
&'static str,String,Cow<'static, str>- render as text()- empty viewOption<V>- rendersSome(view)or nothingResult<V, E>- renders either the success or error view- Closures
Fn() -> impl View- lazy view construction
Environment
The Environment is a type-indexed store that propagates context through the view hierarchy without explicit parameter passing:
use Environment;
let env = new
.with;
// Later, in a view:
use use_env;
use Use;
let config_view = use_env;
The environment supports:
- Typed storage: Insert values of any
'statictype - Plugin installation: Modular extensions via the
Plugintrait - View hooks: Intercept and modify view configurations globally
- Cloning: Cheap cloning via
Rcfor child environments
AnyView - Type Erasure
AnyView enables storing different view types in homogeneous collections:
use AnyView;
let views: = vec!;
Type erasure is essential for dynamic UIs where the concrete view type isn't known at compile time. AnyView automatically unwraps nested erasure to avoid performance overhead.
Reactive Primitives
WaterUI integrates the nami reactive system for fine-grained updates:
use ;
// Create reactive state
let count: = binding;
// Create a view that watches the state
let counter_view = watch;
// Updating the binding automatically updates the view
count.set;
Key reactive types (re-exported from nami):
Binding<T>- Mutable reactive stateComputed<T>- Derived reactive valuesSignal<T>- Read-only reactive valuesSignalExt- Extension methods for all reactive types
The Dynamic component bridges reactive state to the view system. When a watched value changes, the view automatically re-renders with the new data.
Native Views
Native views are leaf components that map directly to platform widgets. The NativeView trait marks types that should be handled by the platform backend:
use ;
;
The raw_view! macro simplifies creating native views:
raw_view!;
raw_view!;
Examples
Custom Component with State
use ;
Environment-based Configuration
use ;
Reactive Computed Values
use ;
let count = binding;
let doubled: = count.map;
let view = watch;
Plugin System
use ;
let mut env = new;
AnalyticsPlugin .install;
API Overview
Core Traits
View- The fundamental UI component traitIntoView- Convert types into viewsTupleViews- Convert tuples of views into collectionsConfigurableView- Views with configuration objectsViewConfiguration- Configuration types for configurable views
Type Erasure
AnyView- Type-erased view containerNative<T>- Wrapper for platform-native componentsNativeView- Trait for native platform widgets
Reactive Components
Dynamic- Runtime-updatable view componentDynamicHandler- Handle for updating dynamic viewswatch()- Helper to create reactive views
Environment & Context
Environment- Type-indexed dependency injection storeUseEnv- View that accesses environment valuesuse_env()- Helper to create environment-aware viewsWith<V, T>- Wrap a view with additional environment value
Metadata & Hooks
Metadata<T>- Attach metadata to views (must be handled by renderer)IgnorableMetadata<T>- Optional metadata (can be ignored by renderer)Retain- Keep values alive for view lifetimeHook<C>- Intercept and modify view configurations
Layout Primitives
Rect,Size,Point- Geometry types (logical pixels)ProposalSize- Size proposals for layout negotiationStretchAxis- Specify which axis a view expands onLayout- Trait for custom layout algorithmsSubView- Proxy for querying child view sizes
Event Handling
Event- Enumeration of UI events (Appear,Disappear)OnEvent- Event handler componentHandler<T>,HandlerOnce<T>- Handler traits for environment-based callbacksActionObject- Type alias for action handlers
View Collections
Views- Trait for collections with stable identitiesAnyViews<V>- Type-erased view collectionForEach<C, F, V>- Transform data collections into viewsViewsExt- Extension methods for view collections
Animation
Animation- Declarative animation specificationsAnimationExt- Extension trait for reactive values.animated()- Apply default animation.with_animation()- Apply specific animation
Features
Default Features
- None - The crate has no default features for maximum flexibility
Optional Features
std- Enable standard library support (currently no-op, reserved for future use)nightly- Enable nightly-only features (e.g.,!never type)serde- Enable Serde serialization support for core types
Architecture Notes
Layout System
WaterUI uses logical pixels (points) for all layout values, matching design tools like Figma:
- 1 logical pixel = 1 point in design tools
- Backends handle conversion to physical pixels based on screen density
- Consistent physical size across platforms and densities
Layout is a two-phase process:
- Sizing: Determine container size given a proposal from parent
- Placement: Position children within the final bounds
The Layout trait defines custom layout algorithms. The StretchAxis enum specifies which axes views expand on:
None- Content-sizedHorizontal/Vertical- Expand on one axisBoth- Greedy, fills all spaceMainAxis/CrossAxis- Relative to container direction
View Rendering Pipeline
Custom View → body() → ... → body() → Raw View → Native Backend → Platform Widget
- Custom views define
body()that returns other views - Framework recursively calls
body()until reaching raw views - Raw views (marked with
NativeView) are handled by the platform backend - Backend translates to native widgets (SwiftUI views, Compose composables, etc.)
Handler System
The handler system supports automatic parameter extraction from environments:
use ;
let handler = into_handler;
Handlers come in three flavors:
Handler<T>- Reusable, takes&mut selfHandlerOnce<T>- Single-use, consumesselfHandlerFn<P, T>- Function-like trait with parameter extraction
License
MIT