The Environment System

The Environment system is WaterUI's approach to dependency injection and configuration management. It provides a type-safe way to pass data, themes, services, and other dependencies through your view hierarchy without explicit parameter passing. Think of it as a context that flows down through your UI tree.

Basic Environment Usage

Storing Values

The most common way to add values to an environment:

use waterui::{Environment, View, ViewExt};
use waterui::component::layout::{Edge, Frame};

#[derive(Debug, Clone)]
struct AppConfig {
    api_url: String,
    timeout_seconds: u64,
}

#[derive(Debug, Clone)]
struct Theme {
    primary_color: waterui::core::Color,
    background_color: waterui::core::Color,
}

pub fn entry() -> impl View {
    home
        .with(AppConfig {
        api_url: "https://api.example.com".to_string(),
        timeout_seconds: 30,
    })
    .with(Theme {
        primary_color: (0.0, 0.4, 1.0).into(),
        background_color: (1.0, 1.0, 1.0).into(),
    })
}

pub fn home() -> impl View{
	// Your home page
}

Accessing Values in Views

For Struct Views

Views can access environment values in their body method:

struct ApiStatusView;

impl View for ApiStatusView {
    fn body(self, env: &Environment) -> impl View {
        // Get configuration from environment
        let config = env.get::<AppConfig>()
            .expect("AppConfig should be provided");
            
        let theme = env.get::<Theme>()
            .expect("Theme should be provided");
        
        vstack((
            waterui_text::Text::new(config.api_url.clone()).foreground(theme.primary_color.clone()),
            waterui_text::Text::new(format!("Timeout: {}s", config.timeout_seconds)).size(14.0),
        ))
        .background(waterui::background::Background::color(theme.background_color.clone()))
        .frame(Frame::new().margin(Edge::round(12.0)))
    }
}

For Function Views

You can pass values through the environment at the call site and read them inside struct views as shown above. Function views typically compose other views and don’t receive env directly.

In action

use waterui::{View};
use waterui::reactive::binding;
use waterui_text::text;
use waterui::component::{layout::stack::vstack, button::button};

#[derive(Debug, Clone)]
pub struct Message(&'static str);

pub fn click_me() -> impl View {
    let value = binding(String::new());
    vstack((
        button("Show environment value").action_with(&value, |value, msg: waterui::core::extract::Use<Message>| {
            value.set(msg.0 .0.to_string());
        }),
        text!("{}", value),
    ))
    .with(Message("I'm Lexo"))
}