patternfly_yew/components/menu/
item.rs

1use super::use_close_menu_callback;
2use crate::prelude::Icon;
3use yew::prelude::*;
4
5#[derive(Clone, Debug, PartialEq, Properties)]
6struct MenuItemProperties {
7    pub children: Html,
8    pub icon: Option<Html>,
9    pub danger: bool,
10    pub disabled: bool,
11    pub selected: bool,
12    pub r#type: MenuItemType,
13    pub description: Option<String>,
14    pub style: Option<AttrValue>,
15    pub class: Classes,
16}
17
18#[derive(Clone, PartialEq, Debug)]
19enum MenuItemType {
20    Button(Callback<()>),
21    Link { href: AttrValue, target: AttrValue },
22}
23
24#[function_component(MenuItem)]
25fn menu_item(props: &MenuItemProperties) -> Html {
26    let mut class = classes!("pf-v5-c-menu__list-item");
27
28    if props.danger {
29        class.push(classes!("pf-m-danger"));
30    }
31
32    if props.disabled {
33        class.push(classes!("pf-m-disabled"));
34    }
35
36    let onclose = use_close_menu_callback();
37
38    let mut item_class = classes!("pf-v5-c-menu__item");
39    if props.selected {
40        item_class.push(classes!("pf-m-selected"));
41    }
42
43    let element = |content: Html| match &props.r#type {
44        MenuItemType::Button(callback) => {
45            html!(
46                <button
47                    class={item_class}
48                    type="button"
49                    role="menuitem"
50                    tabindex="-1"
51                    disabled={props.disabled}
52                    onclick={callback.reform(move |_| {
53                        onclose.emit(());
54                    })}
55                >
56                    { content }
57                </button>
58            )
59        }
60        MenuItemType::Link { href, target } => {
61            let tabindex = match props.disabled {
62                true => Some("-1"),
63                false => None,
64            };
65
66            html!(
67                <a
68                    class={item_class}
69                    {href} {target}
70                    onclick={onclose.reform(|_|())}
71                    aria-disabled={props.disabled.to_string()}
72                    {tabindex}
73                    role="menuitem"
74                >
75                    { content }
76                </a>
77            )
78        }
79    };
80
81    class.extend(&props.class);
82
83    html!(
84        <li {class} style={&props.style}>
85            { element(html!(
86                <>
87                    <span class="pf-v5-c-menu__item-main">
88                        if let Some(icon) = &props.icon {
89                            <span class="pf-v5-c-menu__item-icon"> {icon.clone()} </span>
90                        }
91                        if props.danger {
92                            <span class="pf-v5-screen-reader">{ "Danger Item:" }</span>
93                        }
94
95                        <span class="pf-v5-c-menu__item-text">{ props.children.clone() }</span>
96
97                        if props.selected {
98                            <span class="pf-v5-c-menu__item-select-icon">{ Icon::Check }</span>
99                        }
100                    </span>
101                    if let Some(description) = &props.description {
102                        <span class="pf-v5-c-menu__item-description"> {description} </span>
103                    }
104                </>
105            )) }
106        </li>
107    )
108}
109
110#[derive(Clone, Debug, PartialEq, Properties)]
111pub struct MenuActionProperties {
112    #[prop_or_default]
113    pub children: Html,
114
115    #[prop_or_default]
116    pub description: Option<String>,
117
118    #[prop_or_default]
119    pub icon: Option<Html>,
120
121    #[prop_or_default]
122    pub danger: bool,
123
124    #[prop_or_default]
125    pub disabled: bool,
126
127    #[prop_or_default]
128    pub onclick: Callback<()>,
129
130    #[prop_or_default]
131    pub selected: bool,
132
133    #[prop_or_default]
134    pub style: Option<AttrValue>,
135
136    #[prop_or_default]
137    pub class: Classes,
138}
139
140#[function_component(MenuAction)]
141pub fn menu_action(props: &MenuActionProperties) -> Html {
142    // we use destructing and struct initialization here to ensure we're not missing any new field
143
144    let MenuActionProperties {
145        children,
146        icon,
147        danger,
148        disabled,
149        onclick,
150        description,
151        selected,
152        style,
153        class,
154    } = props.clone();
155
156    let props = MenuItemProperties {
157        children,
158        icon,
159        danger,
160        disabled,
161        r#type: MenuItemType::Button(onclick),
162        description,
163        selected,
164        style,
165        class,
166    };
167
168    html!(<MenuItem ..props />)
169}
170
171#[derive(Clone, Debug, PartialEq, Properties)]
172pub struct MenuLinkProperties {
173    #[prop_or_default]
174    pub children: Html,
175
176    #[prop_or_default]
177    pub description: Option<String>,
178
179    #[prop_or_default]
180    pub icon: Option<Html>,
181
182    #[prop_or_default]
183    pub danger: bool,
184
185    #[prop_or_default]
186    pub disabled: bool,
187
188    pub href: AttrValue,
189
190    #[prop_or_default]
191    pub target: AttrValue,
192
193    #[prop_or_default]
194    pub selected: bool,
195
196    #[prop_or_default]
197    pub style: Option<AttrValue>,
198
199    #[prop_or_default]
200    pub class: Classes,
201}
202
203#[function_component(MenuLink)]
204pub fn menu_link(props: &MenuLinkProperties) -> Html {
205    // we use destructing and struct initialization here to ensure we're not missing any new field
206
207    let MenuLinkProperties {
208        children,
209        icon,
210        danger,
211        disabled,
212        href,
213        target,
214        description,
215        selected,
216        style,
217        class,
218    } = props.clone();
219
220    let props = MenuItemProperties {
221        children,
222        icon,
223        danger,
224        disabled,
225        r#type: MenuItemType::Link { href, target },
226        description,
227        selected,
228        style,
229        class,
230    };
231
232    html!(<MenuItem ..props />)
233}