line_ui/element/
styled.rs

1/*
2 * Copyright (c) 2025 Jasmine Tai. All rights reserved.
3 */
4
5use crate::element::Element;
6use crate::render::RenderChunk;
7use crate::style::Style;
8
9/// An element that renders its content with a particular style.
10pub struct Styled<E> {
11    style: Style,
12    inner: E,
13}
14
15impl<E> Styled<E> {
16    /// Creates a new [`Styled`].
17    pub fn new(style: Style, inner: E) -> Self {
18        Styled { style, inner }
19    }
20}
21
22impl<E: Element> Element for Styled<E> {
23    fn width(&self) -> usize {
24        self.inner.width()
25    }
26
27    fn render(&self) -> impl DoubleEndedIterator<Item = RenderChunk<'_>> {
28        self.inner.render().map(|mut item| {
29            item.style = item.style.or(self.style);
30            item
31        })
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use crate::element::Text;
38
39    use super::*;
40
41    const STYLE_1: Style = Style {
42        foreground: Some(42),
43        ..Style::EMPTY
44    };
45
46    const STYLE_2: Style = Style {
47        foreground: Some(96),
48        ..Style::EMPTY
49    };
50
51    const STYLE_3: Style = Style {
52        background: Some(1),
53        ..Style::EMPTY
54    };
55
56    #[test]
57    fn basic() {
58        let element = Styled::new(STYLE_1, Text::from("Hello, world!"));
59        let render: Vec<_> = element.render().collect();
60        assert_eq!(render, [RenderChunk::new("Hello, world!", STYLE_1)]);
61    }
62
63    #[test]
64    fn nested() {
65        let element = Styled::new(STYLE_1, Styled::new(STYLE_2, Text::from("Hello, world!")));
66        let render: Vec<_> = element.render().collect();
67        assert_eq!(render, [RenderChunk::new("Hello, world!", STYLE_2)]);
68    }
69
70    #[test]
71    fn nested_merge() {
72        let element = Styled::new(STYLE_3, Styled::new(STYLE_2, Text::from("Hello, world!")));
73        let render: Vec<_> = element.render().collect();
74        assert_eq!(
75            render,
76            [RenderChunk::new(
77                "Hello, world!",
78                Style {
79                    foreground: Some(96),
80                    background: Some(1),
81                    ..Style::EMPTY
82                },
83            )],
84        );
85    }
86}