tui_realm_stdlib/components/
span.rs1use tuirealm::command::{Cmd, CmdResult};
7use tuirealm::props::{
8 Alignment, AttrValue, Attribute, Color, PropPayload, PropValue, Props, Style, TextModifiers,
9 TextSpan,
10};
11use tuirealm::ratatui::text::Line;
12use tuirealm::ratatui::{
13 layout::Rect,
14 text::{Span as TuiSpan, Text},
15 widgets::Paragraph,
16};
17use tuirealm::{Frame, MockComponent, State};
18
19#[derive(Default)]
25#[must_use]
26pub struct Span {
27 props: Props,
28}
29
30impl Span {
31 pub fn foreground(mut self, fg: Color) -> Self {
32 self.attr(Attribute::Foreground, AttrValue::Color(fg));
33 self
34 }
35
36 pub fn background(mut self, bg: Color) -> Self {
37 self.attr(Attribute::Background, AttrValue::Color(bg));
38 self
39 }
40
41 pub fn modifiers(mut self, m: TextModifiers) -> Self {
42 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
43 self
44 }
45
46 pub fn alignment(mut self, a: Alignment) -> Self {
47 self.attr(Attribute::Alignment, AttrValue::Alignment(a));
48 self
49 }
50
51 pub fn spans(mut self, s: impl IntoIterator<Item = TextSpan>) -> Self {
52 self.attr(
53 Attribute::Text,
54 AttrValue::Payload(PropPayload::Vec(
55 s.into_iter().map(PropValue::TextSpan).collect(),
56 )),
57 );
58 self
59 }
60}
61
62impl MockComponent for Span {
63 fn view(&mut self, render: &mut Frame, area: Rect) {
64 if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
66 let foreground = self
68 .props
69 .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
70 .unwrap_color();
71 let background = self
72 .props
73 .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
74 .unwrap_color();
75 let payload = self
77 .props
78 .get_ref(Attribute::Text)
79 .and_then(|x| x.as_payload());
80 let spans: Vec<TuiSpan> = match payload {
81 Some(PropPayload::Vec(spans)) => spans
82 .iter()
83 .filter_map(|x| x.as_text_span())
85 .map(|x| {
86 let (fg, bg, modifiers) =
88 crate::utils::use_or_default_styles(&self.props, x);
89 TuiSpan::styled(
90 &x.content,
91 Style::default().add_modifier(modifiers).fg(fg).bg(bg),
92 )
93 })
94 .collect(),
95 _ => Vec::new(),
96 };
97 let text: Text = Text::from(Line::from(spans));
98 let alignment: Alignment = self
100 .props
101 .get_or(Attribute::Alignment, AttrValue::Alignment(Alignment::Left))
102 .unwrap_alignment();
103 render.render_widget(
104 Paragraph::new(text)
105 .alignment(alignment)
106 .style(Style::default().bg(background).fg(foreground)),
107 area,
108 );
109 }
110 }
111
112 fn query(&self, attr: Attribute) -> Option<AttrValue> {
113 self.props.get(attr)
114 }
115
116 fn attr(&mut self, attr: Attribute, value: AttrValue) {
117 self.props.set(attr, value);
118 }
119
120 fn state(&self) -> State {
121 State::None
122 }
123
124 fn perform(&mut self, _cmd: Cmd) -> CmdResult {
125 CmdResult::None
126 }
127}
128
129#[cfg(test)]
130mod tests {
131
132 use super::*;
133
134 use pretty_assertions::assert_eq;
135
136 #[test]
137 fn test_components_span() {
138 let component = Span::default()
139 .background(Color::Blue)
140 .foreground(Color::Red)
141 .modifiers(TextModifiers::BOLD)
142 .alignment(Alignment::Center)
143 .spans([
144 TextSpan::from("Press "),
145 TextSpan::from("<ESC>").fg(Color::Cyan).bold(),
146 TextSpan::from(" to quit"),
147 ]);
148 assert_eq!(component.state(), State::None);
150 }
151
152 #[test]
153 fn various_spans_types() {
154 let _ = Span::default().spans(vec![TextSpan::new("hello")]);
156 let _ = Span::default().spans([TextSpan::new("hello")]);
158 let _ = Span::default().spans(vec![TextSpan::new("hello")].into_boxed_slice());
160 let _ = Span::default().spans(["Hello"].map(TextSpan::new));
162 }
163}