patternfly_yew/components/
text_input_group.rs

1//! Text Input Group
2
3use crate::{prelude::use_on_text_change, utils::HtmlElementSupport};
4use yew::prelude::*;
5
6#[derive(Clone, Debug, PartialEq, Properties)]
7pub struct TextInputGroupProperties {
8    #[prop_or_default]
9    pub id: Option<AttrValue>,
10
11    #[prop_or_default]
12    pub class: Classes,
13
14    #[prop_or_default]
15    pub style: Option<AttrValue>,
16
17    #[prop_or_default]
18    pub children: Html,
19
20    #[prop_or_default]
21    pub disabled: bool,
22}
23
24/// Text input group component
25///
26/// > A **text input** group is a more flexible composable version of a text input. It enables consumers of PatternFly to build custom inputs for filtering and similar use cases by placing elements like icons, chips groups and buttons within a text input.
27///
28/// See: <https://www.patternfly.org/components/text-input-group>
29///
30/// ## Properties
31///
32/// Defined by [`TextInputGroupProperties`].
33///
34/// ## Children
35///
36/// This component is mainly a container, it requires one [`TextInputGroupMain`] to work properly.
37#[function_component(TextInputGroup)]
38pub fn text_input_group(props: &TextInputGroupProperties) -> Html {
39    let mut class = classes!("pf-v5-c-text-input-group");
40
41    class.extend(props.class.clone());
42
43    if props.disabled {
44        class.extend(classes!("pf-m-disabled"));
45    }
46
47    html!(
48        <div {class} id={&props.id} style={&props.style}>
49            { props.children.clone() }
50        </div>
51    )
52}
53
54#[derive(Clone, Debug, PartialEq, Properties)]
55pub struct TextInputGroupMainProperties {
56    #[prop_or_default]
57    pub id: Option<AttrValue>,
58
59    #[prop_or_default]
60    pub class: Classes,
61
62    #[prop_or_default]
63    pub style: Option<AttrValue>,
64
65    /// The value of the input component
66    #[prop_or_default]
67    pub value: String,
68
69    #[prop_or_default]
70    pub placeholder: Option<AttrValue>,
71
72    #[prop_or_default]
73    pub icon: Option<Html>,
74
75    /// Disables the component
76    #[prop_or_default]
77    pub disabled: bool,
78
79    #[prop_or_default]
80    pub aria_label: Option<AttrValue>,
81
82    #[prop_or_default]
83    pub onchange: Callback<String>,
84
85    #[prop_or_default]
86    pub oninput: Callback<InputEvent>,
87
88    #[prop_or_default]
89    pub r#type: Option<AttrValue>,
90
91    #[prop_or_default]
92    pub inputmode: Option<AttrValue>,
93
94    #[prop_or_default]
95    pub onkeydown: Callback<KeyboardEvent>,
96
97    #[prop_or_default]
98    pub autofocus: bool,
99
100    #[prop_or_default]
101    pub inner_ref: Option<NodeRef>,
102
103    #[prop_or_default]
104    pub hint: Option<AttrValue>,
105}
106
107#[function_component(TextInputGroupMain)]
108pub fn text_input_group_main(props: &TextInputGroupMainProperties) -> Html {
109    let mut class = classes!("pf-v5-c-text-input-group__main");
110    class.extend(props.class.clone());
111
112    if props.icon.is_some() {
113        class.push(classes!("pf-m-icon"));
114    }
115
116    let node_ref = use_node_ref();
117    let node_ref = props.inner_ref.as_ref().unwrap_or(&node_ref);
118    let oninput = use_on_text_change(
119        node_ref.clone(),
120        props.oninput.clone(),
121        props.onchange.clone(),
122    );
123
124    // autofocus
125
126    {
127        let node_ref = node_ref.clone();
128        use_effect_with(props.autofocus, move |autofocus| {
129            if *autofocus {
130                node_ref.focus();
131            }
132        });
133    }
134
135    // render
136
137    html!(
138        <div
139            {class}
140            id={&props.id}
141            style={&props.style}
142        >
143            <span class="pf-v5-c-text-input-group__text">
144                if let Some(hint) = &props.hint {
145                    <input
146                        class="pf-v5-c-text-input-group__text-input pf-m-hint"
147                        type="text"
148                        disabled=true
149                        aria-hidden="true"
150                        value={hint}
151                    />
152                }
153                if let Some(icon) = &props.icon {
154                    <span class="pf-v5-c-text-input-group__icon">
155                        { icon.clone() }
156                    </span>
157                }
158                <input
159                    class="pf-v5-c-text-input-group__text-input"
160                    ref={node_ref}
161                    type={&props.r#type}
162                    inputmode={&props.inputmode}
163                    {oninput}
164                    disabled={props.disabled}
165                    placeholder={&props.placeholder}
166                    value={props.value.clone()}
167                    aria-label={&props.aria_label}
168                    onkeydown={&props.onkeydown}
169                />
170            </span>
171        </div>
172    )
173}
174
175#[derive(Clone, Debug, PartialEq, Properties)]
176pub struct TextInputGroupUtilitiesProperties {
177    #[prop_or_default]
178    pub children: Html,
179}
180
181#[function_component(TextInputGroupUtilities)]
182pub fn text_input_group_utilities(props: &TextInputGroupUtilitiesProperties) -> Html {
183    html! (
184        <div class="pf-v5-c-text-input-group__utilities">
185            { props.children.clone() }
186        </div>
187    )
188}