Skip to main content

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-v6-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!(<div {class} id={&props.id} style={&props.style}>{ props.children.clone() }</div>)
48}
49
50#[derive(Clone, Debug, PartialEq, Properties)]
51pub struct TextInputGroupMainProperties {
52    #[prop_or_default]
53    pub id: Option<AttrValue>,
54
55    #[prop_or_default]
56    pub class: Classes,
57
58    #[prop_or_default]
59    pub style: Option<AttrValue>,
60
61    /// The value of the input component
62    #[prop_or_default]
63    pub value: String,
64
65    #[prop_or_default]
66    pub placeholder: Option<AttrValue>,
67
68    #[prop_or_default]
69    pub icon: Option<Html>,
70
71    /// Disables the component
72    #[prop_or_default]
73    pub disabled: bool,
74
75    #[prop_or_default]
76    pub aria_label: Option<AttrValue>,
77
78    #[prop_or_default]
79    pub onchange: Callback<String>,
80
81    #[prop_or_default]
82    pub oninput: Callback<InputEvent>,
83
84    #[prop_or_default]
85    pub r#type: Option<AttrValue>,
86
87    #[prop_or_default]
88    pub inputmode: Option<AttrValue>,
89
90    #[prop_or_default]
91    pub onkeydown: Callback<KeyboardEvent>,
92
93    #[prop_or_default]
94    pub autofocus: bool,
95
96    #[prop_or_default]
97    pub inner_ref: Option<NodeRef>,
98
99    #[prop_or_default]
100    pub hint: Option<AttrValue>,
101}
102
103#[function_component(TextInputGroupMain)]
104pub fn text_input_group_main(props: &TextInputGroupMainProperties) -> Html {
105    let mut class = classes!("pf-v6-c-text-input-group__main");
106    class.extend(props.class.clone());
107
108    if props.icon.is_some() {
109        class.push(classes!("pf-m-icon"));
110    }
111
112    let node_ref = use_node_ref();
113    let node_ref = props.inner_ref.as_ref().unwrap_or(&node_ref);
114    let oninput = use_on_text_change(
115        node_ref.clone(),
116        props.oninput.clone(),
117        props.onchange.clone(),
118    );
119
120    // autofocus
121
122    {
123        let node_ref = node_ref.clone();
124        use_effect_with(props.autofocus, move |autofocus| {
125            if *autofocus {
126                node_ref.focus();
127            }
128        });
129    }
130
131    // render
132
133    html!(
134        <div {class} id={&props.id} style={&props.style}>
135            <span class="pf-v6-c-text-input-group__text">
136                if let Some(hint) = &props.hint {
137                    <input
138                        class="pf-v6-c-text-input-group__text-input pf-m-hint"
139                        type="text"
140                        disabled=true
141                        aria-hidden="true"
142                        value={hint}
143                    />
144                }
145                if let Some(icon) = &props.icon {
146                    <span class="pf-v6-c-text-input-group__icon">{ icon.clone() }</span>
147                }
148                <input
149                    class="pf-v6-c-text-input-group__text-input"
150                    ref={node_ref}
151                    type={&props.r#type}
152                    inputmode={&props.inputmode}
153                    {oninput}
154                    disabled={props.disabled}
155                    placeholder={&props.placeholder}
156                    value={props.value.clone()}
157                    aria-label={&props.aria_label}
158                    onkeydown={&props.onkeydown}
159                />
160            </span>
161        </div>
162    )
163}
164
165#[derive(Clone, Debug, PartialEq, Properties)]
166pub struct TextInputGroupUtilitiesProperties {
167    #[prop_or_default]
168    pub children: Html,
169}
170
171#[function_component(TextInputGroupUtilities)]
172pub fn text_input_group_utilities(props: &TextInputGroupUtilitiesProperties) -> Html {
173    html! (<div class="pf-v6-c-text-input-group__utilities">{ props.children.clone() }</div>)
174}