hyperchad 0.3.0

HyperChad package
# HyperChad

A template-based UI framework for building cross-platform applications with a unified codebase. HyperChad enables developers to write UI templates once and deploy across desktop (Egui, FLTK), web (HTML, Vanilla JS), and server-side (Actix, Lambda) environments.

## Features

- **Multi-Renderer Architecture**: Support for Egui, FLTK, HTML, Vanilla JS, and server-side rendering
- **Template-Based UI**: Build interfaces using the `container!` macro system
- **Routing System**: Async router with navigation support
- **Action System**: Event handling and data flow management
- **State Persistence**: Key-value state store with optional SQLite persistence
- **Color Management**: Consistent theming across all renderers
- **JavaScript Bundling**: Automatic bundling for web deployments
- **Responsive Design**: Responsive triggers for adaptive layouts
- **Cross-Platform**: Desktop, web, and server applications from single codebase

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
hyperchad = "0.1.0"
```

## Usage

### Basic Application

```rust
use hyperchad::app::{App, AppBuilder};
use hyperchad::router::{Router, RoutePath, RouteRequest};
use hyperchad::template::container;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let router = Router::new()
        .with_route("/", |_req: RouteRequest| async move {
            container! {
                div {
                    h1 { "Welcome to HyperChad" }
                    button { "Click Me" }
                }
            }
        });

    let app = AppBuilder::new()
        .with_title("My App".to_string())
        .with_router(router)
        .build_default()?;

    app.run()?;
    Ok(())
}
```

### Template System

HyperChad uses a template macro system for building UIs:

```rust
use hyperchad::template::container;

let ui = container! {
    div id="user-card" class="card" {
        h2 { "User Profile" }
        p { "Email: user@example.com" }
        button fx-click=fx { navigate("/profile") } {
            "View Profile"
        }
    }
};
```

### Routing

```rust
use hyperchad::router::{Router, RoutePath, RouteRequest};

let router = Router::new()
    .with_route("/", |_req| async move {
        container! {
            div { "Home Page" }
        }
    })
    .with_route("/about", |_req| async move {
        container! {
            div { "About Page" }
        }
    })
    .with_route(RoutePath::LiteralPrefix("/user/".to_string()), |req| async move {
        let user_id = req.path.strip_prefix("/user/").unwrap_or("");
        container! {
            div {
                h1 { "User Profile" }
                p { format!("User ID: {}", user_id) }
            }
        }
    });
```

### State Management

HyperChad provides a simple key-value state store:

```rust
use hyperchad::state::{StateStore, sqlite::SqlitePersistence};
use serde_json::json;

let state = StateStore::new(SqlitePersistence::new_in_memory().await?);

// Set values
state.set("user_id", &json!("12345")).await?;
state.set("theme", &json!("dark")).await?;

// Get values
if let Some(user_id) = state.get::<serde_json::Value>("user_id").await? {
    println!("User ID: {}", user_id);
}

// With SQLite file persistence (requires "state-sqlite" feature)
#[cfg(feature = "state-sqlite")]
{
    use hyperchad::state::sqlite::SqlitePersistence;
    let state = StateStore::new(SqlitePersistence::new("app.db").await?);
}
```

### Action System

```rust
// Define actions in templates using the fx DSL
let ui = container! {
    div {
        button fx-click=fx { show("modal") } {
            "Open Modal"
        }
        button fx-click=fx { navigate("/success") } {
            "Submit"
        }
    }
};

// Actions support conditionals and logic (with "actions-logic" feature)
#[cfg(feature = "actions-logic")]
let ui = container! {
    button fx-click=fx {
        if get_visibility("panel") == visible() {
            hide("panel")
        } else {
            show("panel")
        }
    } {
        "Toggle Panel"
    }
};
```

## Programming Interface

### Core Types

```rust
// Container - the fundamental building block
pub struct Container {
    pub element: Element,
    pub children: Vec<Container>,
    // ... styling and layout fields
}

// Element - defines HTML/UI element types
pub enum Element {
    Div,
    Span,
    Button { r#type: Option<String> },
    Input { input: Input, name: Option<String>, autofocus: Option<bool> },
    Heading { size: HeaderSize },
    Image { source: Option<String>, alt: Option<String>, /* ... */ },
    Anchor { target: Option<LinkTarget>, href: Option<String> },
    // ... other variants
}
```

### Renderer Trait

```rust
use async_trait::async_trait;

#[async_trait]
pub trait Renderer: ToRenderRunner + Send + Sync {
    async fn init(&mut self, width: f32, height: f32, /* ... */)
        -> Result<(), Box<dyn std::error::Error>>;

    async fn render(&self, view: View) -> Result<(), Box<dyn std::error::Error>>;

    async fn emit_event(&self, event_name: String, event_value: Option<String>)
        -> Result<(), Box<dyn std::error::Error>>;

    fn add_responsive_trigger(&mut self, name: String, trigger: ResponsiveTrigger);
}
```

### Application Builder

```rust
pub struct AppBuilder {
    // ...
}

impl AppBuilder {
    pub fn new() -> Self;
    pub fn with_title(self, title: String) -> Self;
    pub fn with_router(self, router: Router) -> Self;
    pub fn build<R: Renderer + /* ... */ + 'static>(self, renderer: R) -> Result<App<R>, BuilderError>;
}

pub struct App<R: Renderer + /* ... */> {
    pub renderer: R,
    pub router: Router,
    // ...
}

impl<R: Renderer + /* ... */> App<R> {
    pub fn run(self) -> Result<(), Error>;
    pub async fn serve(&mut self) -> Result<Box<dyn RenderRunner>, Error>;
    pub async fn generate(&self, output: Option<String>) -> Result<(), Error>;
    pub async fn clean(&self, output: Option<String>) -> Result<(), Error>;
}
```

## Configuration

### Feature Flags

```toml
[features]
default = ["all"]

# Renderer features
renderer-egui = ["hyperchad_renderer_egui"]
renderer-fltk = ["hyperchad_renderer_fltk"]
renderer-html = ["hyperchad_renderer_html"]
renderer-vanilla-js = ["hyperchad_renderer_vanilla_js"]

# Platform features
renderer-html-actix = ["hyperchad_renderer_html_actix"]
renderer-html-lambda = ["hyperchad_renderer_html_lambda"]
renderer-html-web-server = ["hyperchad_renderer_html_web_server"]

# State features
state = ["hyperchad_state"]
state-sqlite = ["hyperchad_state/persistence-sqlite"]

# Development features
actions-logic = ["hyperchad_actions/logic"]
renderer-egui-debug = ["hyperchad_renderer_egui/debug"]
debug = ["hyperchad_app/debug", "renderer-egui-debug", "renderer-fltk-debug"]
```

## Renderer-Specific Usage

HyperChad supports multiple renderers through the `AppBuilder`. Use `build_default()` to automatically select the appropriate renderer based on enabled features, or use renderer-specific build methods:

```rust
use hyperchad::app::AppBuilder;

// Build with default renderer (based on features)
let app = AppBuilder::new()
    .with_title("My App".to_string())
    .with_router(router)
    .build_default()?;

// Or use renderer-specific methods when available:
// - build_egui(renderer) for Egui desktop apps
// - build_fltk(renderer) for FLTK desktop apps
// - build_html(renderer) for HTML rendering
// See the renderer module documentation for specific usage
```

### App Runtime Commands

`App::run()` dispatches to subcommands. Use one of these when running your binary:

```bash
# Start serving the application
your-app serve

# Generate static output (optional custom directory)
your-app gen --output ./gen

# Clean generated output (optional custom directory)
your-app clean --output ./gen

# Print dynamic routes
your-app dynamic-routes
```

## Testing

```bash
# Run all tests
cargo test

# Test specific renderer
cargo test --features "renderer-egui"

# Test with all renderers
cargo test --features "all"
```

## Error Handling

Each module provides its own error types:

```rust
use hyperchad::app::{Error as AppError, BuilderError};
use hyperchad::state::Error as StateError;
use hyperchad::router::ParseError;

// App errors
match app.run() {
    Ok(()) => println!("App completed successfully"),
    Err(AppError::IO(e)) => eprintln!("IO error: {}", e),
    Err(AppError::Builder(e)) => eprintln!("Builder error: {}", e),
    Err(e) => eprintln!("Error: {}", e),
}

// State errors
match state.get::<serde_json::Value>("key").await {
    Ok(Some(value)) => println!("Value: {}", value),
    Ok(None) => println!("Key not found"),
    Err(StateError::Serde(e)) => eprintln!("Serialization error: {}", e),
    Err(e) => eprintln!("Error: {}", e),
}
```

## Architecture

HyperChad is built on these core concepts:

1. **Templates**: Use the `container!` macro to define UI structure
2. **Containers**: Styled elements that form the UI tree
3. **Renderers**: Transform containers into platform-specific output
4. **Router**: Maps paths to content generators (async closures)
5. **Actions**: Handle events and trigger state changes or navigation
6. **State**: Optional key-value persistence layer

## See Also

- [`hyperchad_app`] - Application builder and runtime
- [`hyperchad_renderer`] - Base renderer trait
- [`hyperchad_renderer_egui`] - Egui desktop renderer implementation
- [`hyperchad_renderer_fltk`] - FLTK desktop renderer implementation
- [`hyperchad_renderer_html`] - HTML server-side renderer
- [`hyperchad_renderer_vanilla_js`] - Client-side JavaScript renderer
- [`hyperchad_state`] - State persistence system
- [`hyperchad_router`] - Routing functionality
- [`hyperchad_template`] - Template macro system
- [`hyperchad_actions`] - Action system for events
- [`hyperchad_color`] - Color management
- [`hyperchad_transformer`] - Container and element types

[`hyperchad_app`]: app
[`hyperchad_renderer`]: renderer
[`hyperchad_renderer_egui`]: renderer/egui
[`hyperchad_renderer_fltk`]: renderer/fltk
[`hyperchad_renderer_html`]: renderer/html
[`hyperchad_renderer_vanilla_js`]: renderer/vanilla_js
[`hyperchad_state`]: state
[`hyperchad_router`]: router
[`hyperchad_template`]: template
[`hyperchad_actions`]: actions
[`hyperchad_color`]: color
[`hyperchad_transformer`]: transformer