patternfly_yew/components/menu/
toggle.rs

1use crate::prelude::*;
2use yew::prelude::*;
3
4#[derive(Clone, Debug, PartialEq, Properties)]
5pub struct MenuToggleProperties {
6    #[prop_or_default]
7    pub r#ref: NodeRef,
8
9    #[prop_or_default]
10    pub text: Option<String>,
11
12    #[prop_or_default]
13    pub icon: Option<Html>,
14
15    #[prop_or_default]
16    pub aria_label: AttrValue,
17
18    #[prop_or_default]
19    pub expanded: bool,
20
21    #[prop_or_default]
22    pub disabled: bool,
23
24    #[prop_or_default]
25    pub full_height: bool,
26
27    #[prop_or_default]
28    pub full_width: bool,
29
30    #[prop_or_default]
31    pub variant: MenuToggleVariant,
32
33    #[prop_or_default]
34    pub ontoggle: Callback<()>,
35
36    #[prop_or_default]
37    pub children: Html,
38}
39
40#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
41pub enum MenuToggleVariant {
42    #[default]
43    Default,
44    Plain,
45    Primary,
46    Secondary,
47}
48
49impl AsClasses for MenuToggleVariant {
50    fn extend_classes(&self, classes: &mut Classes) {
51        match self {
52            Self::Default => {}
53            Self::Primary => classes.push(classes!("pf-m-primary")),
54            Self::Secondary => classes.push(classes!("pf-m-secondary")),
55            Self::Plain => classes.push(classes!("pf-m-plain")),
56        }
57    }
58}
59
60/// Menu toggle component
61///
62/// See: <https://www.patternfly.org/components/menus/menu-toggle>
63///
64/// ## Properties
65///
66/// Defined by [`MenuToggleProperties`].
67#[function_component(MenuToggle)]
68pub fn menu_toggle(props: &MenuToggleProperties) -> Html {
69    let mut class = classes!("pf-v5-c-menu-toggle");
70
71    if props.expanded {
72        class.push(classes!("pf-m-expanded"));
73    }
74
75    if props.full_height {
76        class.push(classes!("pf-m-full-height"));
77    }
78
79    if props.full_width {
80        class.push(classes!("pf-m-full-width"));
81    }
82
83    if matches!(props.variant, MenuToggleVariant::Plain) && props.text.is_some() {
84        class.push(classes!("pf-m-text"));
85    }
86
87    class.extend_from(&props.variant);
88
89    let plain = matches!(props.variant, MenuToggleVariant::Plain);
90    let text = props.text.is_some();
91
92    html!(
93        <button
94            ref={props.r#ref.clone()}
95            {class}
96            type="button"
97            disabled={ props.disabled }
98            aria-expanded={ props.expanded.to_string() }
99            aria-label={ &props.aria_label }
100            onclick={ props.ontoggle.reform(|_|()) }
101        >
102            if let Some(icon) = &props.icon {
103                if plain && !text{
104                    // if we just have an icon, don't wrap it
105                    { icon.clone() }
106                } else {
107                    <span class="pf-v5-c-menu-toggle__icon">{ icon.clone() }</span>
108                }
109            }
110            if let Some(text) = &props.text {
111                <span class="pf-v5-c-menu-toggle__text">{ text }</span>
112            }
113
114            if !plain || text {
115                // if we have more than just a plain icon, add the toggle control
116                <span class="pf-v5-c-menu-toggle__controls">
117                    <span class="pf-v5-c-menu-toggle__toggle-icon">
118                        <i class="fas fa-caret-down" aria-hidden="true"></i>
119                    </span>
120                </span>
121            }
122
123            { props.children.clone() }
124
125        </button>
126    )
127}