Skip to main content

teksilo_widgets/styles/
recipe_drop_zone_style.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! Default `DropZoneStyle` impl driven by paint-recipe data.
5//!
6//! `RecipeDropZoneStyle` ships the IntUI drop-zone chrome: a rounded,
7//! bordered region whose surface tint and border color track the
8//! interaction state (idle / accepting / rejecting) via the config's
9//! reactive `Signal<DropZoneVisualState>`. The content column (prompt,
10//! subtitle, status line, Browse button) is centered and inset by the
11//! zone padding.
12//!
13//! Apps wanting a different look (dashed border, full-bleed dropzone,
14//! image-backed) write their own `impl DropZoneStyle` block and install it
15//! per-call (`DropZone::style(...)`) or theme-wide
16//! (`theme.style_slots.drop_zone = Some(Rc::new(...))`).
17
18use teksilo_core::build_context::BuildContext;
19use teksilo_core::styles::{DropZoneStyle, DropZoneStyleConfig};
20use teksilo_core::widget_id::WidgetId;
21use teksilo_tokens::CornerRadius;
22
23use crate::primitives::{Center, Padding, RectWidget, ZStack};
24
25/// Corner radius of the zone's rounded rectangle.
26pub const DROP_ZONE_CORNER_RADIUS: f32 = 12.0;
27/// Border thickness in logical pixels.
28pub const DROP_ZONE_BORDER_WIDTH: f32 = 2.0;
29/// Inner padding between the border and the content column.
30pub const DROP_ZONE_PADDING: f32 = 20.0;
31
32/// Configurable dimensions for [`RecipeDropZoneStyle`].
33#[derive(Debug, Clone, Copy, PartialEq)]
34pub struct DropZoneRecipe {
35    /// Corner radius of the zone's rounded rectangle.
36    pub corner_radius: f32,
37    /// Border thickness in logical pixels.
38    pub border_width: f32,
39    /// Inner padding between the border and the content column.
40    pub padding: f32,
41}
42
43impl Default for DropZoneRecipe {
44    fn default() -> Self {
45        Self {
46            corner_radius: DROP_ZONE_CORNER_RADIUS,
47            border_width: DROP_ZONE_BORDER_WIDTH,
48            padding: DROP_ZONE_PADDING,
49        }
50    }
51}
52
53/// Default `DropZoneStyle` shipped with Teksilo.
54#[derive(Debug, Default, Clone, Copy)]
55pub struct RecipeDropZoneStyle {
56    /// Dimension recipe used when painting the drop zone chrome.
57    pub recipe: DropZoneRecipe,
58}
59
60impl RecipeDropZoneStyle {
61    /// Create a style with a custom dimension recipe.
62    pub fn new(recipe: DropZoneRecipe) -> Self {
63        Self { recipe }
64    }
65}
66
67impl DropZoneStyle for RecipeDropZoneStyle {
68    fn make_body(&self, cfg: &DropZoneStyleConfig, ctx: &mut BuildContext) -> WidgetId {
69        // Surface + border colors track the reactive interaction state.
70        let bg = cfg.state.map(|s| s.surface_role());
71        let border = cfg.state.map(|s| s.border_role());
72
73        let rect = ctx.add(
74            RectWidget::new()
75                .background(bg)
76                .border_color(border)
77                .border_width(self.recipe.border_width)
78                .corner_radius(CornerRadius::uniform(self.recipe.corner_radius)),
79        );
80
81        let centered =
82            Center::new().child(Padding::uniform(self.recipe.padding).child_id(cfg.content));
83
84        ctx.add(ZStack::new().add_child(rect).child(centered))
85    }
86}