Skip to main content

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