telar 0.2.1

A modular Rust UI framework with its own template language, reactive signals and a self-contained renderer.
//! The Telar facade: the one crate an application depends on.
//!
//! Re-exports the widget catalogue, the reactive primitives and the geometry types, and carries the runner that turns a mounted tree into a window.
//!
//! # Feature flags
//!
//! Enable one target and stop. The list below is long because nothing is bundled, not because a build
//! carries it: a terminal app links about 160 crates where a desktop one links about 410.
#![cfg_attr(
    feature = "document-features",
    doc = document_features::document_features!()
)]
#![warn(rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

mod macros;

pub mod config;

#[cfg(feature = "runtime")]
pub mod app;
#[cfg(feature = "runtime")]
pub mod app_config;
#[cfg(feature = "runtime")]
pub mod app_runtime;
#[cfg(feature = "runtime")]
mod direction;
#[cfg(feature = "runtime")]
pub mod files;
#[cfg(all(
    feature = "dev",
    not(target_os = "android"),
    not(target_arch = "wasm32")
))]
pub mod hot;
#[cfg(feature = "dev")]
pub mod hot_state;
#[cfg(feature = "runtime")]
pub mod prefs;
#[cfg(feature = "headless")]
mod raster;
#[cfg(feature = "runtime")]
pub mod runner;
#[cfg(feature = "runtime")]
pub mod surface;
#[cfg(all(feature = "runtime", feature = "testing"))]
pub mod testing;
#[cfg(feature = "hardware")]
mod texture_ui;
#[cfg(feature = "runtime")]
pub mod tree;
#[cfg(feature = "watch")]
pub mod watch;
#[cfg(feature = "runtime")]
pub mod window;

pub use config::RendererBackend;

#[cfg(feature = "previews")]
mod preview_runner;

#[cfg(feature = "previews")]
pub use preview_runner::{PreviewEntry, PreviewSurface};

#[cfg(feature = "runtime")]
pub use app::App;
#[cfg(feature = "runtime")]
pub use app_config::AppConfig;
#[cfg(feature = "runtime")]
pub use platform_core::{AppCtx, RedrawWaker};
// For a backend author driving a handler by hand. An application implements `App` and names neither.
#[cfg(feature = "runtime")]
pub use app_runtime::{AppRuntime, LocalApp};
// The faces a surface loads and the family it shapes in — what an `AppConfig` carries, as one value, for the seams that take it directly.
#[cfg(feature = "runtime")]
pub use runner::font_config::FontSetup;
#[cfg(feature = "runtime")]
pub use ui_tree::{DevAction, DevPlugin};

/// The overlay [`run_app_with_name`] installs: the one `cargo telar dev` ships, or none at all.
///
/// A type alias rather than a runtime choice so a build without `dev` monomorphises the frame loop over `()` and the overlay costs it nothing — not a branch, not a vtable. Name [`run_app_with_devtools`] to install your own instead.
#[cfg(all(feature = "runtime", feature = "dev"))]
pub type DefaultDevTools = telar_devtools::DevTools;
#[cfg(all(feature = "runtime", not(feature = "dev")))]
pub type DefaultDevTools = ();
#[cfg(feature = "runtime")]
pub use geometry_core::{ObjectFit, Point, Rect, Transform};
#[cfg(feature = "runtime")]
pub use layout_core::{
    AlignItems, AvailableSpace, Direction, JustifyContent, LayoutError, LayoutStyle, Margin,
    SizeDimension, TemplateTrack,
};
#[cfg(feature = "runtime")]
pub use prefs::UserPrefs;
pub use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
#[cfg(feature = "runtime")]
pub use tree::{Frame, HotTree, LocalTree, UiTree};
// Named in the tree shims the `app!` macro exports, so it has to be reachable through the facade.
#[cfg(feature = "runtime")]
pub use ui_tree::SegmentNodeInfo;
// Always on: kernel functionality, not an opt-in module. The transpiler emits `motion::` paths against this.
pub use motion_core as motion;
// Always on for the same reason: the transpiler emits `i18n::` paths and the baked catalog module names these types. Inert unless the app has a `locales/` catalog.
#[cfg(feature = "runtime")]
pub use direction::follow_locale_direction;
pub use i18n_core as i18n;
// App lifecycle, like `set_locale`, so it belongs at the root. Its lookup `i18n::t` is deliberately not re-exported: `t` here is already the `t!` macro, and a second `t` resolving at runtime would be unreadable.
pub use i18n_core::set_catalog;
pub use i18n_core::{current_locale, detect_system_locale, set_locale, use_locale};
#[cfg(feature = "runtime")]
pub use platform_core::{
    Cursor, Event, FullscreenMode, Key, NamedKey, ScrollDelta, WindowCommand, WindowConfig,
    WindowPosition, push_window_command, take_window_commands,
};
#[cfg(feature = "watch")]
pub use watch::watch_path;
// The seam for an application rendering its own GPU content: it borrows the device Telar draws with, and re-exports the `wgpu` both sides must agree on. Two `wgpu` versions in one binary are two incompatible `Device` types, and the error names neither crate.
#[cfg(feature = "hardware")]
pub use renderer_hardware::gpu;
// The same seam facing the other way: Telar composing into a texture the application owns.
#[cfg(feature = "hardware")]
pub use texture_ui::{TextureUi, TextureUiError};
// Backend-author API: an out-of-tree `Platform` implements these and drives a full app through `run_with_platform` without depending on `platform-core` directly.
#[cfg(feature = "runtime")]
pub use platform_core::{
    EventHandler, ModifiersState, MultiSurfacePlatform, Platform, PlatformError, PointerButton,
    PointerSource, SurfaceId, Window,
};
#[cfg(all(
    feature = "runtime",
    feature = "desktop-bare",
    not(target_os = "android"),
    not(target_arch = "wasm32")
))]
pub use platform_desktop::DesktopPathsProvider;
#[cfg(feature = "runtime")]
pub use reactive_core::{
    Effect, Emitter, Memo, OwnerGuard, OwnerId, Reactive, ReadSignal, RwSignal, Source, Task,
    batch, begin_batch, current_owner, derive, derive_pair, detached, dispose_owner, drain_tasks,
    effect, end_batch, memo, on_cleanup, owner_scope, reset_runtime, reset_tasks, set_task_waker,
    signal, spawn_stream, spawn_task, with_owner,
};
#[cfg(all(feature = "runtime", feature = "svg"))]
pub use renderer_assets::{SvgData, SvgError, VectorCommand};
#[cfg(feature = "runtime")]
pub use renderer_core::{
    Border, BorderRadius, Clamp, Color, Declared, DrawCommand, DrawState, FillRule, FontFamily,
    FontStyle, Gradient, GradientKind, GradientStop, GradientStops, ImageData, LineCap, LineHeight,
    LineJoin, Paint, PathData, PathStyle, PathVerb, Raster, RectStyle, RendererError, Role, Scale,
    Semantics, Shadow, ShapeStyle, Span, Stroke, TextAlign, TextShadow, TextStyle, TextWrap,
    for_each_with_matrix, hash_draw_commands, measure_text, transform_clip_rect,
};
// The drawing half of the backend-author API: a frontend implements `RendererFactory` and installs a `TextMetrics` for whatever "how wide is this string" means on its surface.
#[cfg(feature = "runtime")]
pub use geometry_core::{LayoutGrid, layout_grid, set_layout_grid};
#[cfg(feature = "runtime")]
pub use renderer_core::{
    FontConfig, RenderBackend, RendererBuild, RendererFactory, TextMetrics,
    set_default_text_metrics, set_text_metrics,
};

/// Whether this build turns font files into glyphs itself.
///
/// The question an application asks before supplying [`AppConfig::font_data`](crate::AppConfig::font_data): a shaper on a target with no font directory behind it — a browser — finds nothing and measures every string to zero, so the app has to carry a face. A build that draws as a document has no shaper to feed. Its text is laid out and drawn by the browser in the browser's own fonts, and a face baked into the module would be bytes nothing reads.
///
/// A `const` rather than a function so the branch that answers it is folded away, and the faces behind an `include_bytes!` in the arm not taken never reach the binary.
pub const SHAPES_TEXT: bool = cfg!(feature = "shaper");

/// Whether `family` names a font installed on this system.
///
/// Both [`AppConfig::font_family`](crate::AppConfig::font_family) and [`TextStyle::with_font_family`](crate::TextStyle::with_font_family) take any name and fall back silently when the family is not installed, so this is how an application warns instead. Answered by the database the text shaper already loaded — asking it costs nothing, where a second `fontdb` is a full system font scan and a second answer that can disagree with the one the text is shaped in.
#[cfg(feature = "shaper")]
pub fn font_family_available(family: &str) -> bool {
    renderer_text::font_family_available(family)
}

/// Installs the glyph-shaping text measurer, for code that lays out text with no runner behind it — a layout test, or a tool that composes a tree only to measure it.
///
/// An app never needs this: the runner installs it on resume with the app's own fonts. Nothing happens if a measurer is already installed.
#[cfg(feature = "shaper")]
pub fn install_default_text_metrics() {
    renderer_core::set_default_text_metrics(renderer_text::ShaperMetrics);
}

/// What the CPU renderer's caches are holding, and a way to make them let go. Exposed so an app can answer "is the memory in the renderer?" from outside the renderer, which nothing short of a heap profiler could do before.
#[cfg(feature = "software")]
pub use renderer_software::{CacheStat, cache_stats, sweep_idle as sweep_renderer_caches};
pub use services_core::app_paths as paths;
pub use services_core::{AppPathsProvider, NoPaths};
pub use services_core::{Clipboard, clipboard, clipboard_text, set_clipboard, set_clipboard_text};
// Available in every GUI build rather than opt-in: `ui_core::Surface` composes the per-surface service scope, so `runtime` turns on services-core/di. A non-GUI build has no ui-core and nothing to re-export.
#[cfg(feature = "runtime")]
pub use services_core::{Scope, context, provide, set_context, try_inject, with_service};
#[cfg(feature = "runtime")]
pub use surface::{
    SurfaceContent, SurfaceControl, SurfaceHost, SurfaceToken, open_surface, set_surface_host,
    surface_content,
};
#[cfg(feature = "runtime")]
pub use theme_core::{
    ControlSize, Theme, ThemeTokens, active_mode, control_scale, follow_system, register_mode,
    set_control_size, set_mode, set_system_dark, set_theme, use_control_size, use_theme,
    use_theme_tokens,
};
#[cfg(all(feature = "runtime", feature = "svg"))]
pub use ui_core::Svg;
// The seam and nothing behind it: `telar-dynamic` carries the decoders and transports that plug in here, and an application's own plug in exactly the same way.
#[cfg(feature = "async-assets")]
pub use ui_core::{
    AssetCache, AssetDecoder, AssetError, AssetKey, AssetLoader, AssetState, AssetTransport, Reply,
};
#[cfg(feature = "runtime")]
pub use ui_core::{
    Axis, Canvas, ChildSlot, Children, Clip, ClipAxis, ClippedItem, Component, ComponentList,
    Container, DEFAULT_SCRIM, DragAxis, DragStart, Edge, EventResult, Image, Inherited, Input,
    KeyAnswer, KeyNav, KeyNavMove, LayoutItem, LayoutScrollArea, Lazy, LineGutter, NodeId, NodeVec,
    Overlay, Path, PointerButtons, ReactiveList, Rectangle, RenderNode, ScrollPage, ScrollViewport,
    ScrollbarStyle, Slots, StyledContainer, SurfaceScaffold, SurfaceTransition, Text, TextArea,
    VirtualList, WindowRoot, anchor_rect, apply_move, box_item, box_transform, close_overlay,
    compute_layout, current_direction, declare, dismiss_depth, dismiss_top, drag_start,
    drag_travel, focus, fragment, fragment_positional, inherited_text_style, insertion_index,
    interactive_rects, kept, key_held, key_nav_apply, key_nav_apply_grid, key_pressed,
    logical_border_radius, logical_border_widths, mark_dirty, modifiers, new_container, new_leaf,
    observe_keyboard, observe_pointer, open_overlay, overlay_state, pointer_buttons,
    relayout_if_dirty, remove_node, set_children, set_direction, set_display, set_min_height,
    set_overlay_host, track_layout, transform_pointer, undeclare, use_context, use_direction,
    use_dismiss_depth, visible_window,
};

/// Empties the layout runtime for a fresh tree, and installs the glyph measurer if nothing installed one.
///
/// The measurer rides along because sizing text is part of laying it out, and this is the first call every tree makes: a tree built with no runner behind it — a layout test, a tool measuring a page — would otherwise have to ask for one separately. A frontend that installed its own keeps it; see [`install_default_text_metrics`].
///
/// A build with no shaper has no measurer to fall back to, and needs none: the only frontend that comes without one draws as a document, which measures with the engine that will draw the text and installs that before the first tree is built.
#[cfg(feature = "runtime")]
pub fn reset_layout_runtime() {
    #[cfg(feature = "shaper")]
    install_default_text_metrics();
    ui_core::reset_layout_runtime();
}

#[cfg(feature = "navigate")]
pub use navigate_core::{
    NavHost, NavPage, NavTransition, Navigator, PagePolicy, SimplePage, TabHost, TabStacks,
};

#[cfg(feature = "components-advanced")]
pub use ui_components::{
    AccordionProps, ReorderableProps, StepperProps, accordion, reorderable, stepper,
};
#[cfg(feature = "components-base")]
pub use ui_components::{
    BadgeProps, ButtonProps, CheckboxProps, ChipProps, GroupProps, HeadingProps, ItemProps,
    ProgressProps, RadioProps, SectionProps, SelectProps, SeparatorProps, SliderProps,
    SpinnerProps, TabsProps, TextFieldProps, ToggleProps, badge, button, checkbox, chip, group,
    heading, item, progress, radio, section, select, separator, slider, spinner, tabs, text_field,
    toggle,
};
#[cfg(feature = "components-overlays")]
pub use ui_components::{
    ContextMenuProps, DrawerProps, MenuCustomProps, MenuEntry, MenuProps, MenuRowProps,
    MenuSeparatorProps, MenuStyle, MenuSubProps, ModalProps, TooltipProps, context_menu, drawer,
    menu, menu_custom, menu_row, menu_separator, menu_sub, modal, tooltip,
};
#[cfg(feature = "components-chrome")]
pub use ui_components::{MIN_FRAME_SIZE, SurfaceFrameStyle, WindowControls, window_frame};

#[cfg(feature = "runtime")]
/// Offers an event to the overlay registry first, returning whether an overlay consumed it.
pub fn dispatch_overlays(event: &Event) -> bool {
    ui_core::dispatch_overlays(event) == EventResult::Handled
}

#[cfg(all(
    any(feature = "preview", feature = "preview-headless"),
    not(target_os = "android")
))]
mod preview;
#[cfg(all(
    any(feature = "preview", feature = "preview-headless"),
    not(target_os = "android")
))]
pub use preview::PreviewApp;
#[cfg(all(feature = "preview-headless", not(target_os = "android")))]
pub use preview::run_preview_png;
#[cfg(feature = "headless")]
pub use raster::rasterize;

#[cfg(feature = "dev")]
pub use hot_state::{hot_restore_json, hot_signal, hot_snapshot_json, probe};

/// Without `dev` there is no dylib swap to survive, so the key is inert and this degrades to a plain signal. The bounds match the `dev` build's so a type that compiles here cannot fail once hot-reload is on — letting hand-written app state (a navigation stack, an active locale) be declared once instead of behind a `cfg`.
#[cfg(all(feature = "runtime", not(feature = "dev")))]
pub fn hot_signal<T>(key: &str, init: T) -> reactive_core::RwSignal<T>
where
    T: Clone + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
    let _ = key;
    reactive_core::signal(init)
}
#[cfg(all(feature = "android-bare", target_os = "android"))]
pub use platform_android::AndroidApp;
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub use runner::build_surface_handler;
#[cfg(all(feature = "android-bare", target_os = "android"))]
pub use runner::run_android_app_with_name;
#[cfg(all(
    feature = "desktop-bare",
    feature = "dev",
    not(target_os = "android"),
    not(target_arch = "wasm32")
))]
pub use runner::run_hot_reload_host;
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub use runner::run_multi_with_platform;
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub use runner::run_with_platform;
#[cfg(feature = "runtime")]
// The renderer seam, and what a window has to be for the built-in renderers to draw on it.
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub use runner::{SurfaceWindow, run_with_platform_and_renderer};
#[cfg(all(
    feature = "runtime",
    feature = "desktop-bare",
    not(target_os = "android"),
    not(target_arch = "wasm32")
))]
pub use runner::{open_window, run_app_windowed, run_desktop_app_with_name};
// The frontend an app actually starts on. Not gated on `desktop`: choosing between the frontends a build has is the whole point of it, and a terminal-only build has no window to open.
#[cfg(all(feature = "runtime", feature = "tui", not(target_os = "android")))]
pub use runner::{TuiOptions, run_tui_app_with_name};
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub use runner::{run_app_with_devtools, run_app_with_name};

pub use telar_macros::{Props, ThemeTokens, app, component, rsx_modules, t};

#[cfg(all(feature = "previews", not(target_os = "android")))]
pub use preview_runner::{dev_entry, try_run_test};