Skip to main content

telar_ui_core/
lib.rs

1#[cfg(feature = "async-assets")]
2mod async_asset;
3mod canvas;
4mod child_host;
5mod container;
6mod context;
7pub mod dismiss;
8mod drag;
9pub mod focus;
10mod image;
11mod input;
12mod input_region;
13mod kept;
14mod layout_item;
15mod layout_leaf;
16mod lazy;
17mod line;
18mod line_gutter;
19pub mod named_overlay;
20pub mod overlay;
21mod path;
22mod pointer;
23mod press;
24mod reactive_list;
25mod rect;
26mod rich_text;
27mod scroll_area;
28pub mod scroll_region;
29mod slots;
30mod styled_container;
31mod surface;
32mod surface_context;
33#[cfg(feature = "svg")]
34mod svg;
35mod text;
36mod text_area;
37mod virtual_list;
38
39#[cfg(feature = "async-assets")]
40pub use async_asset::{AssetSource, AssetState};
41pub use canvas::Canvas;
42pub use child_host::{
43    ChildSlot, fragment, fragment_gap, fragment_positional, fragment_positional_gap,
44};
45pub use container::Container;
46pub use context::{
47    NodeId, absolute_rect, compute_layout, compute_layout_root, current_direction, mark_dirty,
48    new_container, new_leaf, relayout_if_dirty, remove_node, reset_layout_runtime, set_children,
49    set_direction, set_display, set_min_height, set_overlay_host, track_layout, use_direction,
50};
51pub use dismiss::{dismiss_depth, dismiss_top, use_dismiss_depth};
52pub use image::Image;
53pub use input::Input;
54pub use input_region::{interactive_rects, register_interactive, unregister_interactive};
55pub use kept::kept;
56pub use layout_item::{ClippedItem, LayoutItem, box_item};
57pub use layout_leaf::LayoutLeaf;
58pub use lazy::Lazy;
59pub use line::Line;
60pub use line_gutter::LineGutter;
61pub use named_overlay::{
62    close as close_overlay, is_open as use_overlay_open, open as open_overlay,
63    peek_open as overlay_open, state as overlay_state, toggle as toggle_overlay,
64};
65pub use overlay::{Overlay, Placement, anchor_rect};
66pub use path::Path;
67pub use pointer::transform_pointer;
68pub use reactive_list::ReactiveList;
69pub use rect::Rectangle;
70pub use rich_text::RichText;
71pub use scroll_area::{LayoutScrollArea, ScrollViewport, ScrollbarStyle};
72pub use scroll_region::visible_rect;
73pub use slots::Slots;
74pub use styled_container::{StyledContainer, box_transform, style_follows};
75pub use surface::{
76    DEFAULT_SCRIM, KeyboardMode, MIN_FRAME_SIZE, SurfaceAlign, SurfaceAnchor, SurfaceFrameStyle,
77    SurfacePlacement, SurfaceRole, SurfaceRoot, SurfaceScaffold, SurfaceSize, SurfaceTransition,
78    surface_frame,
79};
80pub use surface_context::{Surface, SurfaceGuard};
81#[cfg(feature = "svg")]
82pub use svg::Svg;
83pub use text::Text;
84pub use text_area::TextArea;
85pub use ui_tree::{Component, ComponentList, EventResult, NodeVec, RenderNode};
86pub use virtual_list::{VirtualList, visible_window};
87
88/// Routes an event to the overlay layer before the widget tree sees it.
89///
90/// Wraps `ui_tree`'s pointer routing with the keyboard half it cannot do: the dismiss stack and the focus
91/// state both live in this crate, so Escape is resolved here. Every caller (the runner, the plugin bridge)
92/// already goes through `ui_core`, so this is the single choke point either way.
93pub fn dispatch_overlays(event: &platform_core::Event) -> EventResult {
94    // Escape closes the frontmost dialog only when nothing holds focus: a focused editor gets first refusal
95    // and blurs itself (see `Input`'s Escape), so a second press then closes the dialog around it. Dismissing
96    // ahead of the focused widget would make Escape unable to leave a field without also tearing down its form.
97    if let platform_core::Event::KeyPressed {
98        key: platform_core::Key::Named(platform_core::NamedKey::Escape),
99        ..
100    } = event
101        && focus::current().is_none()
102        && dismiss::dismiss_top()
103    {
104        return EventResult::Handled;
105    }
106    ui_tree::dispatch_overlays(event)
107}