Skip to main content

patternfly_yew/components/menu/
checkbox.rs

1use super::use_close_menu_callback;
2use crate::hooks::id::use_prop_id;
3use web_sys::HtmlInputElement;
4use yew::prelude::*;
5
6/// Properties for [`MenuCheckbox`].
7#[derive(Clone, Debug, PartialEq, Properties)]
8pub struct MenuCheckboxProperties {
9    /// The label of the item
10    #[prop_or_default]
11    pub children: Html,
12
13    /// Id of the checkbox input
14    #[prop_or_default]
15    pub id: Option<String>,
16
17    /// The name of the checkbox input
18    #[prop_or_default]
19    pub name: Option<AttrValue>,
20
21    #[prop_or_default]
22    pub description: Option<String>,
23
24    #[prop_or_default]
25    pub disabled: bool,
26
27    /// Flag if the checkbox is checked.
28    #[prop_or_default]
29    pub checked: bool,
30
31    /// Callback when the state of the checkbox changes, providing the new state.
32    #[prop_or_default]
33    pub onchange: Callback<bool>,
34
35    /// Close the surrounding menu (e.g. a dropdown) when the checkbox is toggled.
36    #[prop_or_default]
37    pub close_on_select: bool,
38
39    #[prop_or_default]
40    pub style: Option<AttrValue>,
41
42    #[prop_or_default]
43    pub class: Classes,
44}
45
46/// A menu item with a checkbox.
47///
48/// By default, toggling the checkbox does not close the surrounding menu. This can be changed
49/// using the `close_on_select` property.
50#[component]
51pub fn MenuCheckbox(props: &MenuCheckboxProperties) -> Html {
52    let id = use_prop_id(props.id.clone());
53    let node_ref = use_node_ref();
54    let onclose = use_close_menu_callback();
55
56    let mut class = classes!("pf-v6-c-menu__list-item");
57    if props.disabled {
58        class.push(classes!("pf-m-disabled"));
59    }
60    class.extend(&props.class);
61
62    let mut item_class = classes!("pf-v6-c-menu__item");
63    if props.disabled {
64        item_class.push(classes!("pf-m-disabled"));
65    }
66
67    let onchange = use_callback(
68        (
69            props.onchange.clone(),
70            props.close_on_select,
71            node_ref.clone(),
72            onclose,
73        ),
74        |_: Event, (onchange, close_on_select, node_ref, onclose)| {
75            if let Some(input) = node_ref.cast::<HtmlInputElement>() {
76                onchange.emit(input.checked());
77            }
78            if *close_on_select {
79                onclose.emit(());
80            }
81        },
82    );
83
84    html!(
85        <li {class} style={&props.style}>
86            <label class={item_class} for={(*id).clone()}>
87                <span class="pf-v6-c-menu__item-main">
88                    <span class="pf-v6-c-menu__item-check">
89                        <span class="pf-v6-c-check pf-m-standalone">
90                            <input
91                                ref={node_ref}
92                                class="pf-v6-c-check__input"
93                                type="checkbox"
94                                role="menuitemcheckbox"
95                                id={(*id).clone()}
96                                name={&props.name}
97                                tabindex="-1"
98                                checked={props.checked}
99                                aria-checked={props.checked.to_string()}
100                                disabled={props.disabled}
101                                {onchange}
102                            />
103                        </span>
104                    </span>
105                    <span class="pf-v6-c-menu__item-text">{ props.children.clone() }</span>
106                </span>
107                if let Some(description) = &props.description {
108                    <span class="pf-v6-c-menu__item-description"> {description} </span>
109                }
110            </label>
111        </li>
112    )
113}