Skip to main content

teksilo_widgets/styles/
recipe_badge_style.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! Default `BadgeStyle` impl driven by paint-recipe data.
5//!
6//! `RecipeBadgeStyle` ships the IntUI badge chrome: a fully-rounded
7//! (`9999` radius) pill with a soft `AccentSubtle` background by
8//! default, content inset by the badge padding. Pure composition —
9//! no custom paint.
10//!
11//! Apps that want a different badge look (square tag, status-tinted
12//! pill, bordered chip) write their own `impl BadgeStyle` block and
13//! install it per-call (`Badge::style(...)`) or theme-wide
14//! (`theme.style_slots.badge`).
15
16use teksilo_core::build_context::BuildContext;
17use teksilo_core::color_prop::ColorProp;
18use teksilo_core::styles::{BadgeStyle, BadgeStyleConfig};
19use teksilo_core::widget_id::WidgetId;
20use teksilo_tokens::{CornerRadius, SurfaceRole};
21
22use crate::primitives::{Padding, RectWidget, ZStack};
23
24// IntUI design tokens for Badge. The recipe owns its own dimensions.
25pub const BADGE_PADDING_HORIZONTAL: f32 = 6.0;
26pub const BADGE_PADDING_VERTICAL: f32 = 1.0;
27/// Fully-rounded pill — a large radius the renderer clamps to half the
28/// shorter side.
29pub const BADGE_CORNER_RADIUS: f32 = 9999.0;
30
31/// Dimension bundle for [`RecipeBadgeStyle`]. All fields are `f32` and
32/// the struct is `Copy`, so it can be passed freely.
33#[derive(Debug, Clone, Copy, PartialEq)]
34pub struct BadgeRecipe {
35    pub padding_horizontal: f32,
36    pub padding_vertical: f32,
37    pub corner_radius: f32,
38}
39
40impl Default for BadgeRecipe {
41    fn default() -> Self {
42        Self {
43            padding_horizontal: BADGE_PADDING_HORIZONTAL,
44            padding_vertical: BADGE_PADDING_VERTICAL,
45            corner_radius: BADGE_CORNER_RADIUS,
46        }
47    }
48}
49
50/// Default `BadgeStyle` shipped with Teksilo. Background defaults to
51/// `SurfaceRole::AccentSubtle` when the caller sets no override.
52#[derive(Debug, Default, Clone, Copy)]
53pub struct RecipeBadgeStyle {
54    pub recipe: BadgeRecipe,
55}
56
57impl RecipeBadgeStyle {
58    pub fn new(recipe: BadgeRecipe) -> Self {
59        Self { recipe }
60    }
61}
62
63impl BadgeStyle for RecipeBadgeStyle {
64    fn make_body(&self, cfg: &BadgeStyleConfig, ctx: &mut BuildContext) -> WidgetId {
65        let bg: ColorProp = cfg
66            .background_override
67            .clone()
68            .unwrap_or(ColorProp::SurfaceRole(SurfaceRole::AccentSubtle));
69        let bg_rect = ctx.add(
70            RectWidget::new()
71                .background(bg)
72                .corner_radius(CornerRadius::uniform(self.recipe.corner_radius)),
73        );
74        let padding_id = ctx.add(
75            Padding::symmetric(self.recipe.padding_vertical, self.recipe.padding_horizontal)
76                .child_id(cfg.content),
77        );
78        ctx.add(ZStack::new().add_child(bg_rect).add_child(padding_id))
79    }
80}