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