yew_bs/components/
typography.rs

1use yew::prelude::*;
2use crate::components::common::{
3    Variant, TextAlign, TextWrap, TextTransform, FontWeight, FontStyle, TextDecoration,
4};
5#[derive(Properties, PartialEq)]
6pub struct HeadingProps {
7    #[prop_or_default]
8    pub children: Children,
9    #[prop_or_default]
10    pub level: HeadingLevel,
11    #[prop_or_default]
12    pub display: Option<DisplayHeading>,
13    #[prop_or_default]
14    pub lead: bool,
15    #[prop_or_default]
16    pub color: Option<Variant>,
17    #[prop_or_default]
18    pub text_align: Option<TextAlign>,
19    #[prop_or_default]
20    pub weight: Option<FontWeight>,
21    #[prop_or_default]
22    pub style: Option<FontStyle>,
23    #[prop_or_default]
24    pub transform: Option<TextTransform>,
25    #[prop_or_default]
26    pub decoration: Option<TextDecoration>,
27    #[prop_or_default]
28    pub wrap: Option<TextWrap>,
29    #[prop_or_default]
30    pub truncate: bool,
31    #[prop_or_default]
32    pub break_text: bool,
33    #[prop_or_default]
34    pub class: Option<AttrValue>,
35    #[prop_or_default]
36    pub node_ref: NodeRef,
37    #[prop_or_default]
38    pub id: Option<AttrValue>,
39}
40#[derive(Clone, Copy, PartialEq, Debug, Default)]
41pub enum HeadingLevel {
42    #[default]
43    H1,
44    H2,
45    H3,
46    H4,
47    H5,
48    H6,
49}
50impl HeadingLevel {
51    pub fn as_str(&self) -> &'static str {
52        match self {
53            HeadingLevel::H1 => "h1",
54            HeadingLevel::H2 => "h2",
55            HeadingLevel::H3 => "h3",
56            HeadingLevel::H4 => "h4",
57            HeadingLevel::H5 => "h5",
58            HeadingLevel::H6 => "h6",
59        }
60    }
61}
62/// Display heading sizes
63#[derive(Clone, Copy, PartialEq, Debug)]
64pub enum DisplayHeading {
65    D1,
66    D2,
67    D3,
68    D4,
69    D5,
70    D6,
71}
72impl DisplayHeading {
73    pub fn as_str(&self) -> &'static str {
74        match self {
75            DisplayHeading::D1 => "display-1",
76            DisplayHeading::D2 => "display-2",
77            DisplayHeading::D3 => "display-3",
78            DisplayHeading::D4 => "display-4",
79            DisplayHeading::D5 => "display-5",
80            DisplayHeading::D6 => "display-6",
81        }
82    }
83}
84#[function_component(Heading)]
85pub fn heading(props: &HeadingProps) -> Html {
86    let mut classes = Classes::new();
87    if let Some(display) = &props.display {
88        classes.push(display.as_str());
89    }
90    if props.lead && matches!(props.level, HeadingLevel::H1) {
91        classes.push("lead");
92    }
93    if let Some(color) = &props.color {
94        classes.push(format!("text-{}", color.as_str()));
95    }
96    if let Some(align) = &props.text_align {
97        classes.push(align.as_str());
98    }
99    if let Some(weight) = &props.weight {
100        classes.push(weight.as_str());
101    }
102    if let Some(style) = &props.style {
103        classes.push(style.as_str());
104    }
105    if let Some(transform) = &props.transform {
106        classes.push(transform.as_str());
107    }
108    if let Some(decoration) = &props.decoration {
109        classes.push(decoration.as_str());
110    }
111    if let Some(wrap) = &props.wrap {
112        classes.push(wrap.as_str());
113    }
114    if props.truncate {
115        classes.push("text-truncate");
116    }
117    if props.break_text {
118        classes.push("text-break");
119    }
120    if let Some(class) = &props.class {
121        classes.push(class.to_string());
122    }
123    let tag = props.level.as_str();
124    html! {
125        <@ { tag } class = { classes } ref = { props.node_ref.clone() } id = { props.id
126        .clone() } > { for props.children.iter() } </@>
127    }
128}
129#[derive(Properties, PartialEq)]
130pub struct ParagraphProps {
131    #[prop_or_default]
132    pub children: Children,
133    #[prop_or_default]
134    pub color: Option<Variant>,
135    #[prop_or_default]
136    pub text_align: Option<TextAlign>,
137    #[prop_or_default]
138    pub weight: Option<FontWeight>,
139    #[prop_or_default]
140    pub style: Option<FontStyle>,
141    #[prop_or_default]
142    pub transform: Option<TextTransform>,
143    #[prop_or_default]
144    pub decoration: Option<TextDecoration>,
145    #[prop_or_default]
146    pub wrap: Option<TextWrap>,
147    #[prop_or_default]
148    pub truncate: bool,
149    #[prop_or_default]
150    pub break_text: bool,
151    #[prop_or_default]
152    pub class: Option<AttrValue>,
153    #[prop_or_default]
154    pub node_ref: NodeRef,
155}
156#[function_component(Paragraph)]
157pub fn paragraph(props: &ParagraphProps) -> Html {
158    let mut classes = Classes::new();
159    if let Some(color) = &props.color {
160        classes.push(format!("text-{}", color.as_str()));
161    }
162    if let Some(align) = &props.text_align {
163        classes.push(align.as_str());
164    }
165    if let Some(weight) = &props.weight {
166        classes.push(weight.as_str());
167    }
168    if let Some(style) = &props.style {
169        classes.push(style.as_str());
170    }
171    if let Some(transform) = &props.transform {
172        classes.push(transform.as_str());
173    }
174    if let Some(decoration) = &props.decoration {
175        classes.push(decoration.as_str());
176    }
177    if let Some(wrap) = &props.wrap {
178        classes.push(wrap.as_str());
179    }
180    if props.truncate {
181        classes.push("text-truncate");
182    }
183    if props.break_text {
184        classes.push("text-break");
185    }
186    if let Some(class) = &props.class {
187        classes.push(class.to_string());
188    }
189    html! {
190        < p class = { classes } ref = { props.node_ref.clone() } > { for props.children
191        .iter() } </ p >
192    }
193}
194#[derive(Properties, PartialEq)]
195pub struct BlockquoteProps {
196    #[prop_or_default]
197    pub children: Children,
198    #[prop_or_default]
199    pub footer: Option<Html>,
200    #[prop_or_default]
201    pub class: Option<AttrValue>,
202    #[prop_or_default]
203    pub node_ref: NodeRef,
204}
205#[function_component(Blockquote)]
206pub fn blockquote(props: &BlockquoteProps) -> Html {
207    let mut classes = Classes::new();
208    classes.push("blockquote");
209    if let Some(class) = &props.class {
210        classes.push(class.to_string());
211    }
212    html! {
213        < blockquote class = { classes } ref = { props.node_ref.clone() } > { for props
214        .children.iter() } if let Some(footer) = & props.footer { < footer class =
215        "blockquote-footer" > { footer.clone() } </ footer > } </ blockquote >
216    }
217}
218#[derive(Properties, PartialEq)]
219pub struct TextProps {
220    #[prop_or_default]
221    pub children: Children,
222    #[prop_or_default]
223    pub element: TextElement,
224    #[prop_or_default]
225    pub color: Option<Variant>,
226    #[prop_or_default]
227    pub text_align: Option<TextAlign>,
228    #[prop_or_default]
229    pub weight: Option<FontWeight>,
230    #[prop_or_default]
231    pub style: Option<FontStyle>,
232    #[prop_or_default]
233    pub transform: Option<TextTransform>,
234    #[prop_or_default]
235    pub decoration: Option<TextDecoration>,
236    #[prop_or_default]
237    pub wrap: Option<TextWrap>,
238    #[prop_or_default]
239    pub truncate: bool,
240    #[prop_or_default]
241    pub break_text: bool,
242    #[prop_or_default]
243    pub class: Option<AttrValue>,
244    #[prop_or_default]
245    pub node_ref: NodeRef,
246}
247#[derive(Clone, Copy, PartialEq, Debug, Default)]
248pub enum TextElement {
249    #[default]
250    Span,
251    Div,
252    Strong,
253    Em,
254    Small,
255    Mark,
256    Del,
257    Ins,
258    Sub,
259    Sup,
260    Code,
261    Kbd,
262    Samp,
263    Var,
264    Pre,
265}
266impl TextElement {
267    pub fn as_str(&self) -> &'static str {
268        match self {
269            TextElement::Span => "span",
270            TextElement::Div => "div",
271            TextElement::Strong => "strong",
272            TextElement::Em => "em",
273            TextElement::Small => "small",
274            TextElement::Mark => "mark",
275            TextElement::Del => "del",
276            TextElement::Ins => "ins",
277            TextElement::Sub => "sub",
278            TextElement::Sup => "sup",
279            TextElement::Code => "code",
280            TextElement::Kbd => "kbd",
281            TextElement::Samp => "samp",
282            TextElement::Var => "var",
283            TextElement::Pre => "pre",
284        }
285    }
286}
287/// Bootstrap Text component for generic text styling
288#[function_component(Text)]
289pub fn text(props: &TextProps) -> Html {
290    let mut classes = Classes::new();
291    if let Some(color) = &props.color {
292        classes.push(format!("text-{}", color.as_str()));
293    }
294    if let Some(align) = &props.text_align {
295        classes.push(align.as_str());
296    }
297    if let Some(weight) = &props.weight {
298        classes.push(weight.as_str());
299    }
300    if let Some(style) = &props.style {
301        classes.push(style.as_str());
302    }
303    if let Some(transform) = &props.transform {
304        classes.push(transform.as_str());
305    }
306    if let Some(decoration) = &props.decoration {
307        classes.push(decoration.as_str());
308    }
309    if let Some(wrap) = &props.wrap {
310        classes.push(wrap.as_str());
311    }
312    if props.truncate {
313        classes.push("text-truncate");
314    }
315    if props.break_text {
316        classes.push("text-break");
317    }
318    if let Some(class) = &props.class {
319        classes.push(class.to_string());
320    }
321    let tag = props.element.as_str();
322    html! {
323        <@ { tag } class = { classes } ref = { props.node_ref.clone() } > { for props
324        .children.iter() } </@>
325    }
326}