fig_schema/present.rs
1//! Renderer-neutral presentation hints. A frontend maps these to its own
2//! symbols and colours (SwiftUI → SF Symbols + adaptive `Color`; ratatui →
3//! unicode + ANSI). Carried on [`crate::FieldRule`] but never interpreted by
4//! this crate — purely a payload for the embedder's renderer.
5
6/// Presentation hints for one field rule.
7///
8/// `#[non_exhaustive]`: this is the type that grows every time a frontend needs
9/// a new hint, so it is built from [`Presentation::default`] and the chainable
10/// setters below rather than a struct literal. Reading the fields is unchanged.
11///
12/// ```
13/// use fig_schema::{Icon, Presentation, Tint};
14///
15/// let p = Presentation::default()
16/// .title("Audience")
17/// .description("Who may read this")
18/// .icon(Icon::Globe)
19/// .tint(Tint::Positive);
20/// assert_eq!(p.title.as_deref(), Some("Audience"));
21/// ```
22#[derive(Debug, Clone, Default, PartialEq, Eq)]
23#[non_exhaustive]
24pub struct Presentation {
25 /// A human field label.
26 pub title: Option<String>,
27 /// Help text / section subtitle.
28 pub description: Option<String>,
29 /// A semantic icon.
30 pub icon: Option<Icon>,
31 /// A semantic tint.
32 pub tint: Option<Tint>,
33}
34
35impl Presentation {
36 /// Set the human field label.
37 pub fn title(mut self, title: impl Into<String>) -> Self {
38 self.title = Some(title.into());
39 self
40 }
41
42 /// Set the label from an optional one — for a caller reading a config where
43 /// the title may be absent. `None` leaves it unset.
44 pub fn title_opt(mut self, title: Option<impl Into<String>>) -> Self {
45 self.title = title.map(Into::into);
46 self
47 }
48
49 /// Set the help text.
50 pub fn description(mut self, description: impl Into<String>) -> Self {
51 self.description = Some(description.into());
52 self
53 }
54
55 /// Set the help text from an optional one. `None` leaves it unset.
56 pub fn description_opt(mut self, description: Option<impl Into<String>>) -> Self {
57 self.description = description.map(Into::into);
58 self
59 }
60
61 /// Set the semantic icon. Takes an [`Icon`] or an `Option<Icon>`.
62 pub fn icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
63 self.icon = icon.into();
64 self
65 }
66
67 /// Set the semantic tint. Takes a [`Tint`] or an `Option<Tint>`.
68 pub fn tint(mut self, tint: impl Into<Option<Tint>>) -> Self {
69 self.tint = tint.into();
70 self
71 }
72}
73
74/// A semantic icon hint. Frontends map to their own symbol set.
75///
76/// `#[non_exhaustive]`: the set grows as fields do, so a `match` needs a `_`
77/// arm. Constructing a variant is unaffected.
78#[derive(Debug, Clone, PartialEq, Eq)]
79#[non_exhaustive]
80pub enum Icon {
81 Link,
82 Enum,
83 Toggle,
84 Lock,
85 Globe,
86 Clock,
87 Tag,
88 Text,
89 /// An escape hatch naming a frontend-specific symbol.
90 Other(String),
91}
92
93/// A semantic tint hint. Frontends map to theme-adaptive colours.
94///
95/// `#[non_exhaustive]`: a palette grows the same way an icon set does, so a
96/// `match` needs a `_` arm.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98#[non_exhaustive]
99pub enum Tint {
100 Accent,
101 Neutral,
102 Positive,
103 Warning,
104 Danger,
105}