impulse_thaw/flex/
flex.rs

1use leptos::prelude::*;
2use thaw_utils::class_list;
3
4#[component]
5pub fn Flex(
6    #[prop(optional, into)] class: MaybeProp<String>,
7    #[prop(optional, into)] style: MaybeProp<String>,
8    /// Flex's gap.
9    #[prop(optional)]
10    gap: FlexGap,
11    /// Whether to lay out vertically.
12    #[prop(optional)]
13    vertical: bool,
14    /// Whether it's display is `inline-flex`.
15    #[prop(optional, into)]
16    inline: Signal<bool>,
17    /// Vertical arrangement.
18    #[prop(optional, into)]
19    align: MaybeProp<FlexAlign>,
20    /// Horizontal arrangement.
21    #[prop(optional, into)]
22    justify: MaybeProp<FlexJustify>,
23    children: Children,
24) -> impl IntoView {
25    let style = Memo::new(move |_| {
26        let mut s = String::new();
27        let display = if inline.get() {
28            "display: inline-flex;"
29        } else {
30            "display: flex;"
31        };
32        s.push_str(display);
33        let direction = if vertical {
34            "flex-direction: column;"
35        } else {
36            "flex-direction: row;"
37        };
38        let gap = match gap {
39            FlexGap::Small => "gap: 4px 8px;",
40            FlexGap::Medium => "gap: 8px 12px;",
41            FlexGap::Large => "gap: 12px 16px;",
42            FlexGap::Size(size) => &format!("gap: {size}px {size}px;"),
43            FlexGap::WH(width, height) => &format!("gap: {width}px {height}px;"),
44        };
45        s.push_str(direction);
46        s.push_str(gap);
47        if let Some(align) = align.get() {
48            s.push_str(&format!("align-items: {};", align.as_str()));
49        }
50        if let Some(justify) = justify.get() {
51            s.push_str(&format!("justify-content: {};", justify.as_str()));
52        }
53        style.with(|style| {
54            if let Some(style) = style.as_ref() {
55                s.push_str(style);
56            }
57        });
58
59        s
60    });
61
62    view! {
63        <div class=class_list!["thaw-flex", class] style=move || style.get()>
64            {children()}
65        </div>
66    }
67}
68
69#[derive(Default)]
70pub enum FlexGap {
71    Small,
72    #[default]
73    Medium,
74    Large,
75    Size(u16),
76    /// width and height
77    WH(u16, u16),
78}
79
80#[derive(Clone)]
81pub enum FlexAlign {
82    FlexStart,
83    FlexEnd,
84    Start,
85    End,
86    Center,
87    Baseline,
88    Stretch,
89}
90
91impl FlexAlign {
92    fn as_str(&self) -> &'static str {
93        match self {
94            Self::FlexStart => "flex-start",
95            Self::FlexEnd => "flex-end",
96            Self::Start => "start",
97            Self::End => "end",
98            Self::Center => "center",
99            Self::Baseline => "baseline",
100            Self::Stretch => "stretch",
101        }
102    }
103}
104
105#[derive(Clone)]
106pub enum FlexJustify {
107    FlexStart,
108    FlexEnd,
109    Start,
110    End,
111    Center,
112    SpaceAround,
113    SpaceBetween,
114    SpaceEvenly,
115}
116
117impl FlexJustify {
118    fn as_str(&self) -> &'static str {
119        match self {
120            Self::FlexStart => "flex-start",
121            Self::FlexEnd => "flex-end",
122            Self::Start => "start",
123            Self::End => "end",
124            Self::Center => "center",
125            Self::SpaceAround => "space-around",
126            Self::SpaceBetween => "space-between",
127            Self::SpaceEvenly => "space-evenly",
128        }
129    }
130}