patternfly_yew/layouts/
flex.rs

1//! Flex
2
3use crate::prelude::{
4    AsClasses, ChildrenProperties, ExtendClasses, Raw, SpaceItems, Spacer, WithBreakpoints,
5};
6use std::{fmt::Debug, rc::Rc};
7use yew::{
8    html::ChildrenRenderer,
9    prelude::*,
10    virtual_dom::{VChild, VComp},
11};
12
13#[derive(Copy, Clone, Debug, PartialEq)]
14pub enum FlexModifier {
15    /// Can grow beyond required size
16    Grow,
17    /// Try to minimize size
18    Shrink,
19    /// Weight of 1
20    Flex1,
21    /// Weight of 2
22    Flex2,
23    /// Weight of 3
24    Flex3,
25    /// Weight of 4
26    Flex4,
27    /// Full width item
28    FullWidth,
29    /// Column ordering
30    Column,
31    /// Row ordering
32    ///
33    /// This is the opposite of [`Column`] and the default. It can be used for response
34    /// modifiers in combination with [`WithBreakpoints`] to bring back the default for some
35    /// breakpoints.
36    Row,
37    Justify(Justify),
38    Align(Alignment),
39}
40
41#[derive(Copy, Clone, Debug, PartialEq)]
42pub enum Justify {
43    Start,
44    End,
45    SpaceBetween,
46}
47
48#[derive(Copy, Clone, Debug, PartialEq)]
49pub enum Alignment {
50    Right,
51    Left,
52    Start,
53    Center,
54    End,
55    Baseline,
56    Stretch,
57}
58
59impl AsClasses for FlexModifier {
60    fn extend_classes(&self, classes: &mut Classes) {
61        match self {
62            FlexModifier::Grow => classes.push("pf-m-grow"),
63            FlexModifier::Shrink => classes.push("pf-m-shrink"),
64            FlexModifier::Flex1 => classes.push("pf-m-flex-1"),
65            FlexModifier::Flex2 => classes.push("pf-m-flex-2"),
66            FlexModifier::Flex3 => classes.push("pf-m-flex-3"),
67            FlexModifier::Flex4 => classes.push("pf-m-flex-4"),
68            FlexModifier::FullWidth => classes.push("pf-m-full-width"),
69            FlexModifier::Column => classes.push("pf-m-column"),
70            FlexModifier::Row => classes.push("pf-m-row"),
71            FlexModifier::Justify(layout) => match layout {
72                Justify::Start => classes.push("pf-m-justify-content-flex-start"),
73                Justify::End => classes.push("pf-m-justify-content-flex-end"),
74                Justify::SpaceBetween => classes.push("pf-m-justify-content-space-between"),
75            },
76            FlexModifier::Align(alignment) => match alignment {
77                Alignment::Right => classes.push("pf-m-align-right"),
78                Alignment::Left => classes.push("pf-m-align-left"),
79                Alignment::Start => classes.push("pf-m-align-self-flex-start"),
80                Alignment::Center => classes.push("pf-m-align-self-center"),
81                Alignment::End => classes.push("pf-m-align-self-flex-end"),
82                Alignment::Baseline => classes.push("pf-m-align-self-baseline"),
83                Alignment::Stretch => classes.push("pf-m-align-self-stretch"),
84            },
85        }
86    }
87}
88
89#[derive(Clone, PartialEq)]
90pub enum FlexChild {
91    Flex(Rc<<Flex as BaseComponent>::Properties>),
92    FlexItem(Rc<<FlexItem as BaseComponent>::Properties>),
93    Raw(Rc<<Raw as BaseComponent>::Properties>),
94}
95
96impl From<FlexProperties> for FlexChild {
97    fn from(props: FlexProperties) -> Self {
98        FlexChild::Flex(Rc::new(props))
99    }
100}
101
102impl From<FlexItemProperties> for FlexChild {
103    fn from(props: FlexItemProperties) -> Self {
104        FlexChild::FlexItem(Rc::new(props))
105    }
106}
107
108impl From<ChildrenProperties> for FlexChild {
109    fn from(props: ChildrenProperties) -> Self {
110        FlexChild::Raw(Rc::new(props))
111    }
112}
113
114#[derive(PartialEq, Clone)]
115pub struct FlexChildVariant {
116    props: FlexChild,
117}
118
119impl<CHILD> From<VChild<CHILD>> for FlexChildVariant
120where
121    CHILD: BaseComponent,
122    CHILD::Properties: Into<FlexChild> + Clone,
123{
124    fn from(vchild: VChild<CHILD>) -> Self {
125        Self {
126            props: (*vchild.props).clone().into(),
127        }
128    }
129}
130
131impl From<FlexChildVariant> for Html {
132    fn from(value: FlexChildVariant) -> Self {
133        match value.props {
134            FlexChild::Flex(props) => VComp::new::<Flex>(props, None).into(),
135            FlexChild::FlexItem(props) => VComp::new::<FlexItem>(props, None).into(),
136            FlexChild::Raw(props) => VComp::new::<Raw>(props, None).into(),
137        }
138    }
139}
140
141pub trait ToFlexItems {
142    fn into_flex_items(self) -> Vec<VChild<FlexItem>>;
143}
144
145impl ToFlexItems for Vec<Html> {
146    fn into_flex_items(self) -> Vec<VChild<FlexItem>> {
147        self.into_iter()
148            .map(|html| html_nested! {<FlexItem> { html }</FlexItem>})
149            .collect()
150    }
151}
152
153#[derive(Clone, PartialEq, Properties)]
154pub struct FlexProperties {
155    #[prop_or_default]
156    pub children: ChildrenRenderer<FlexChildVariant>,
157    #[prop_or_default]
158    pub modifiers: WithBreakpoints<FlexModifier>,
159    /// Individual spacing for this item, in context of its siblings.
160    #[prop_or_default]
161    pub spacer: WithBreakpoints<Spacer>,
162    /// Spacing for all child items.
163    #[prop_or_default]
164    pub space_items: WithBreakpoints<SpaceItems>,
165}
166
167/// Flex layout
168///
169/// > The Flex layout is a tool to build your own custom layout that builds-in the PatternFly spacer and breakpoint systems.
170///
171/// See: <https://www.patternfly.org/layouts/flex>
172///
173/// ## Properties
174///
175/// Defined by [`FlexProperties`].
176///
177/// ## Children
178///
179/// The Flex layout contains either [`FlexItem`] children, or nested [`Flex`] layouts.
180#[function_component(Flex)]
181pub fn flex(props: &FlexProperties) -> Html {
182    let mut classes = Classes::from("pf-v5-l-flex");
183
184    classes.extend_from(&props.modifiers);
185    classes.extend_from(&props.space_items);
186    classes.extend_from(&props.spacer);
187
188    html! (
189        <div class={classes}>
190            { for props.children.iter() }
191        </div>
192    )
193}
194
195// flex item
196
197#[derive(Clone, PartialEq, Properties)]
198pub struct FlexItemProperties {
199    #[prop_or_default]
200    pub children: Html,
201    #[prop_or_default]
202    pub modifiers: WithBreakpoints<FlexModifier>,
203    #[prop_or_default]
204    pub spacer: WithBreakpoints<Spacer>,
205}
206
207/// An item of the [`Flex`] layout.
208///
209/// ## Properties
210///
211/// Defined by [`FlexItemProperties`].
212#[function_component(FlexItem)]
213pub fn flex_item(props: &FlexItemProperties) -> Html {
214    let mut classes = Classes::from("pf-v5-l-flex__item");
215
216    classes.extend_from(&props.modifiers);
217    classes.extend_from(&props.spacer);
218
219    html! (
220        <div class={classes}>
221            { props.children.clone() }
222        </div>
223    )
224}