telar 0.1.5

A modular Rust UI framework with its own template language, reactive signals and a self-contained renderer.
Documentation
[package]
name = "telar"
version = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
description = "A modular Rust UI framework with its own template language, reactive signals and a self-contained renderer."
keywords = ["ui", "gui", "framework", "reactive", "declarative"]
categories = ["gui", "rendering", "graphics"]
readme = { workspace = true }
license = { workspace = true }
repository = { workspace = true }

[features]
default = ["runtime", "desktop", "hardware", "software"]

runtime = [
    "dep:platform-core",
    "dep:platform-android",
    "dep:renderer-core",
    "dep:renderer-assets",
    "dep:renderer-text",
    "dep:reactive-core",
    "dep:layout-core",
    "dep:theme-core",
    "dep:ui-core",
    "dep:ui-tree",
    "dep:geometry-core",
    "dep:toml",
    "dep:tracing",
    "dep:libc",
]

# Both renderers are opt-in, so a frontend installing its own via `run_with_platform_and_renderer` compiles
# neither. `RendererBackend::Auto` resolves to whichever is present.
# `platform-headless` rides along because `TextureUi` names `HeadlessWindow` as its offscreen marker.
hardware = ["runtime", "dep:renderer-hardware", "dep:platform-headless"]
software = ["runtime", "dep:renderer-software"]

desktop = ["runtime", "dep:platform-desktop"]
# Exposes `rasterize`: draw commands in, pixels out, with no window and no GPU.
platform-headless = ["runtime", "software", "dep:platform-headless"]

dev = ["runtime", "desktop", "dep:libloading", "dep:serde_json"]
preview = ["runtime", "desktop"]
# `platform-headless` plus a PNG encoder, which is the only thing `image` is here for.
preview-headless = ["platform-headless", "dep:image"]

# Production dylibs, distinct from dev hot-reload: `plugin` is the dylib side, `plugin-host` the loader.
plugin = ["runtime"]
# Test helpers an out-of-tree app needs to say what its tree drew, and the GPU gate that keeps a pixel test
# from passing having asserted nothing. Opt-in: nothing in a shipping binary should reach for these.
testing = ["runtime"]
plugin-host = ["plugin", "dep:libloading"]

components = ["runtime", "dep:ui-components"]
navigate = ["runtime", "dep:navigate-core"]
async-assets = ["runtime", "ui-core/async-assets"]
# The HTTP implementation of that seam. Split from `async-assets` because the seam itself is pure reactive
# glue: an app supplying its own transport gets it without an HTTP client and a TLS stack.
http-assets = ["async-assets", "dynamic-svg", "dep:ureq"]
di = ["services-core/di"]
# Loading a translation catalog from TOML instead of linking one the transpiler baked. What an app with no
# `.rsx` file in it needs to reach i18n at all.
runtime-catalog = ["i18n-core/runtime-catalog"]
# Filesystem watching delivered on the UI thread. Opt-in: an app that reloads nothing should not link a
# platform file-notification backend.
watch = ["runtime", "dep:notify"]

svg = ["ui-core?/svg"]
dynamic-svg = ["svg", "renderer-assets?/dynamic-svg"]
dynamic-image = ["renderer-assets?/dynamic-image"]
# Decode formats beyond the always-on PNG and JPEG. See `renderer-assets` for why there is one per format:
# a format nobody enabled fails at runtime, not at compile time.
image-avif = ["dynamic-image", "renderer-assets?/image-avif"]
image-bmp = ["dynamic-image", "renderer-assets?/image-bmp"]
image-dds = ["dynamic-image", "renderer-assets?/image-dds"]
image-exr = ["dynamic-image", "renderer-assets?/image-exr"]
image-ff = ["dynamic-image", "renderer-assets?/image-ff"]
image-gif = ["dynamic-image", "renderer-assets?/image-gif"]
image-hdr = ["dynamic-image", "renderer-assets?/image-hdr"]
image-ico = ["dynamic-image", "renderer-assets?/image-ico"]
image-pnm = ["dynamic-image", "renderer-assets?/image-pnm"]
image-qoi = ["dynamic-image", "renderer-assets?/image-qoi"]
image-tga = ["dynamic-image", "renderer-assets?/image-tga"]
image-tiff = ["dynamic-image", "renderer-assets?/image-tiff"]
image-webp = ["dynamic-image", "renderer-assets?/image-webp"]
image-formats = ["dynamic-image", "renderer-assets?/image-formats"]

[dependencies]
image = { version = "0.25.10", default-features = false, features = ["png"], optional = true }
libloading = { version = "0.9.0", optional = true }
raw-window-handle = { workspace = true }
serde = { workspace = true }
serde_json = { version = "1", optional = true }
toml = { workspace = true, optional = true }
tracing = { workspace = true, optional = true }

geometry-core = { workspace = true, optional = true }
i18n-core = { workspace = true }
layout-core = { workspace = true, optional = true }
# Always-on (D2): the motion engine is small and dependency-free, and the facade must expose `motion::*` for transpiler codegen whatever else is off.
motion-core = { workspace = true }
navigate-core = { workspace = true, optional = true }
platform-core = { workspace = true, optional = true }
platform-headless = { workspace = true, optional = true }
reactive-core = { workspace = true, optional = true }
renderer-assets = { workspace = true, optional = true }
renderer-core = { workspace = true, optional = true }
renderer-hardware = { workspace = true, optional = true }
renderer-software = { workspace = true, optional = true }
renderer-text = { workspace = true, optional = true }
services-core = { workspace = true }
telar-macros = { workspace = true }
theme-core = { workspace = true, optional = true }
ui-components = { workspace = true, optional = true }
ui-core = { workspace = true, optional = true }
ui-tree = { workspace = true, optional = true }
ureq = { version = "3.4.0", optional = true }
notify = { version = "8.2.0", optional = true }

[target.'cfg(not(target_os = "android"))'.dependencies]
platform-desktop = { workspace = true, optional = true }

[target.'cfg(target_os = "android")'.dependencies]
platform-android = { workspace = true, optional = true }

[target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
libc = { version = "0.2.186", optional = true }

[dev-dependencies]
platform-headless = { workspace = true }
# Self-referencing so the integration tests get the opt-in `testing` module without it being a default that
# ships in every binary. `http-assets` rides along for the same reason: `tests/http_assets.rs` is real
# coverage of the transport, not an `--all-features`-only extra.
telar = { path = ".", features = ["testing", "http-assets", "watch"] }
renderer-record = { workspace = true }

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
    'cfg(telar_hot_reload)',
    'cfg(telar_preview)',
] }