waterui 0.5.0

A modern UI framework for Rust
# Migrating from WaterUI 0.2 to 0.3

WaterUI 0.3 is a breaking pre-1.0 release. It removes ambiguous constructors and
silent conversions, makes accessibility metadata mandatory at construction,
and aligns the native and self-rendering backends on one semantic contract.

## Dependency versions

Update the facade and FFI packages together:

```toml
[dependencies]
waterui = "0.3"
waterui-ffi = "0.3"
```

Projects generated by the matching `waterui-cli` release already use these
requirements. Do not mix a 0.3 facade with a 0.2 FFI package or backend.

## Controls require labels at construction

`Toggle`, `TextField`, and `Picker` can no longer be constructed without a
semantic label. The former `.label(...)` setter has been removed from these
types.

```rust
// 0.2
Toggle::new(&enabled).label("Sync");
TextField::new(&name).label("Name");
Picker::new(items, &selection);

// 0.3
Toggle::new("Sync", &enabled);
TextField::new("Name", &name);
Picker::new("Mode", items, &selection);
```

When surrounding chrome already draws the label, retain its accessibility
meaning and hide only its presentation:

```rust
Toggle::new("Sync", &enabled).hide_label()
```

The ergonomic free constructors follow the same rule, for example
`toggle("Sync", &enabled)` and `field("Name", &name)`.

## Runtime URLs must be parsed explicitly

The `From<String>`, `From<Str>`, and `From<Cow<str>>` conversions to `Url` were
removed because invalid input previously degraded silently into a file path.

```rust
// 0.2: invalid network input could become a local path.
let url = Url::from(input);

// 0.3: propagate or display the parse failure.
let url: Url = input.parse()?;
```

For a value that is intentionally a filesystem path, say so:

```rust
let url = Url::from_file_path_str(path);
```

APIs accepting `IntoUrl` still accept statically validated `Url::new(...)`
values and already-parsed `Url` values. Dynamic user input must be parsed
before it is passed to media, images, navigation, or WebView.

## Video uses `ContentMode`

The media fitting mode is no longer named `AspectRatio`; that name conflicted
with the layout component that applies an actual ratio.

```rust
// 0.2
video(source).aspect_ratio(AspectRatio::Fit);

// 0.3
video(source).content_mode(ContentMode::Fit);
```

The same rename applies to `VideoPlayer`, media configuration, FFI declarations,
and native backend fields: `WuiAspectRatio` becomes `WuiContentMode`, and
`aspect_ratio` becomes `content_mode`.

## Stack layout is content-sized and priority-aware

Stacks now report their content size instead of expanding implicitly. Put the
expansion requirement on the view that owns it, and use layout priority when
children compete for finite main-axis space.

```rust
vstack((
    text("Keep this visible").layout_priority(1),
    text(long_description),
))
```

Do not add fixed frames merely to reproduce the old expansion behavior.
Containers probe child minimums, preserve stretch axes through type erasure,
and compress lower-priority children first.

## Navigation paths and restoration

Navigation destinations use typed paths. Applications that persist navigation
state should enable the facade feature and serialize the path through serde:

```toml
[dependencies]
waterui = { version = "0.3", features = ["navigation-restoration"] }
```

```rust
let encoded = serde_json::to_string(&path)?;
let restored: NavigationPath<Route> = serde_json::from_str(&encoded)?;
```

For heterogeneous paths, register every destination before calling
`path.restoration().deserialize(...)`. Restoration atomically replaces the
whole path; do not push the decoded routes one at a time.

Navigation bar colors now use resolved semantic color values. An unresolved
environment-dependent color can no longer cross the native navigation
boundary.

## WebView bridge contract

WebView now exposes one asynchronous request/reply bridge across Apple,
Android, GTK, CEF, and WPE.

- Handlers accept extractors and may return futures.
- JavaScript evaluation is awaited and returns its typed result or error.
- Event watcher registration returns a guard; retain the guard for as long as
  the subscription should remain active.
- Internal backend event variants are no longer public `WebViewEvent` values.
- Script injection is keyed so replacing a script does not accumulate copies.
- Bridge access is origin-gated. The default policy admits the initial origin;
  broaden it explicitly with `.bridge_origins(...)`.

```rust
let page = WebView::open(Url::new("https://waterui.dev"))
    .bridge_origins(BridgeOrigins::Initial)
    .handler("profile", |Json(request): Json<ProfileRequest>| async move {
        Json(load_profile(request).await)
    });
```

Code that previously called `watch(...)` and discarded its return value must
now store the `WatcherGuard`, or use the declarative `.on_event(...)` entry
point when the subscription has the same lifetime as the view.

## Reactive collection and list content

Dynamic children are collections, not structural watchers. Use `ForEach` or
`List` over `nami::collection::List` with identifiable items. List section
headers and footers are semantic reactive text rather than eagerly converted
strings, so pass a signal when the title changes.

```rust
List::content(
    Section::new(section_title.clone()).content((
        row("Status", text!("Connected")),
    )),
)
```

## Theme selection tokens

Selection styling uses the dedicated `SelectionContainer` and
`SelectionForeground` theme tokens. Custom themes must provide both tokens so
selected text and controls remain readable. Backend code should resolve these
tokens rather than substituting platform hard-coded colors.

## Assets, barcode, media, chart, and canvas

- `asset!` and `include_bundle!` now resolve through the typed asset planner;
  regenerate projects and asset plans with the matching CLI.
- Barcode content is reactive and encoding returns typed errors instead of
  hiding invalid data.
- Media picker filters represent exactly the platform selection contract;
  removed filter variants have no compatibility fallback.
- Chart axes are one reactive configuration and candle timestamps retain full
  precision.
- Canvas image subregions use the repaired `draw_image_sub` contract. The dead
  shadow API was removed, and text measurement is cached by the rendering
  backend.

## Tests and benchmarks

UI tests now run through `#[waterui::test]` and the Hydrolysis accessibility
tree. Interactions panic when the semantic action is unavailable, and waits
pump until a concrete condition or quiescence instead of sleeping.

```rust
#[waterui::test(settings_view, theme = hydrolysis_m3::install)]
fn toggles_sync(app: &mut SemanticApp) {
    app.query().label("Sync").tap();
    app.query().label("Enabled").assert_exists();
}
```

Performance coverage uses `#[waterui::bench]` and `water bench`. The old
`water preview perf` command has been removed. Benchmarks run in-process and
can declare budgets for latency, rebuild ratio, and scene complexity.

Tests that sampled animations with `std::thread::sleep` must use
`OffscreenApp::pump_for(Duration)` so the virtual frame clock actually
advances.

## Feature-gated FFI and GPU packages

The map FFI is off by default in `waterui-ffi`, while the common GPU stack is a
default-on feature. Consumers that disable defaults must opt into the facade
and FFI features they use. Map is no longer a `waterui` facade feature; depend
on `waterui-map` directly, and add `waterui-map-gpu` when using the self-drawn
realization:

```toml
[dependencies]
waterui = { version = "0.3", default-features = false, features = ["gpu"] }
waterui-ffi = { version = "0.3", default-features = false, features = ["gpu", "map"] }
waterui-map = "0.1"
waterui-map-gpu = "0.1"
```

Regenerate native bindings and generated projects after changing these
features. Do not reuse a 0.2 generated header or native backend with 0.3 Rust
artifacts.