teksilo_core/styles/toast_style.rs
1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! Tier-3 style protocol for `Toast`. See `docs/styling-system.md`.
5//!
6//! Themes the floating toast surface — the per-severity card the
7//! `ToastHost` stacks at a viewport corner. The `Toast` widget keeps
8//! its accessibility node (`Role::Alert` for Warning/Error,
9//! `Role::Status` for Info/Success, plus the matching `Live` setting);
10//! `ToastStyle` only owns the surface chrome.
11//!
12//! `ToastStyleConfig` exposes both severity AND priority so the recipe
13//! can give Urgent/High toasts a slightly heavier shadow or a more
14//! emphatic border without changing the severity tint. Pre-built child
15//! ids (`content`, `leading_glyph`, `trailing_close`) follow the same
16//! pattern as `BannerStyleConfig` — the widget assembles the functional
17//! subtrees, the recipe arranges them.
18
19use std::rc::Rc;
20
21use serde::{Deserialize, Serialize};
22
23use crate::build_context::BuildContext;
24use crate::styles::BannerSeverity;
25use crate::widget_id::WidgetId;
26
27/// Queue / assertiveness level — shared with the public `Toast` builder
28/// API. Lives here in teksilo-core so the style trait can take it in its
29/// config without depending on teksilo-widgets.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
31pub enum ToastPriority {
32 /// Queues if `max_visible` reached; admits in order. Default.
33 #[default]
34 Normal,
35 /// Shown immediately; bumps the oldest Normal entry if needed.
36 /// Doesn't interrupt screen-reader speech.
37 High,
38 /// Shown immediately; forces `Live::Assertive` regardless of severity.
39 Urgent,
40}
41
42#[derive(Clone, Debug)]
43pub struct ToastStyleConfig {
44 /// Severity hint — drives the recipe's surface tint (same mapping
45 /// as `BannerSeverity::surface()`).
46 pub severity: BannerSeverity,
47 /// Priority hint — recipes can use this to differentiate Urgent
48 /// toasts (e.g., heavier shadow). Most recipes ignore it.
49 pub priority: ToastPriority,
50 /// Pre-built body subtree (title + body + optional action row +
51 /// optional progress bar). The recipe arranges it next to the
52 /// leading glyph.
53 pub content: WidgetId,
54 /// Pre-built `SeverityGlyph` (or app-supplied custom leading
55 /// widget). The recipe places it at the leading edge.
56 pub leading_glyph: WidgetId,
57 /// Optional pre-built close `IconButton`. `None` when the toast
58 /// was constructed with `.show_close_button(false)`.
59 pub trailing_close: Option<WidgetId>,
60}
61
62pub trait ToastStyle: 'static {
63 fn make_body(&self, cfg: &ToastStyleConfig, ctx: &mut BuildContext) -> WidgetId;
64}
65
66pub type SharedToastStyle = Rc<dyn ToastStyle>;