patternfly_yew/components/
context_selector.rs1use crate::prelude::{GlobalClose, Icon, InputGroup, TextInput, TextInputType};
3use std::rc::Rc;
4use yew::prelude::*;
5
6#[derive(Properties, Debug, Clone, PartialEq)]
8pub struct ContextSelectorProperties {
9 #[prop_or_default]
10 pub selected: String,
11 #[prop_or_default]
12 pub onsearch: Callback<String>,
13 #[prop_or_default]
14 pub children: ChildrenWithProps<ContextSelectorItem>,
15}
16
17#[doc(hidden)]
18#[derive(Clone, Debug)]
19pub enum ContextSelectorMsg {
20 Toggle,
21 Close,
22 Search(String),
23}
24
25#[deprecated(
35 since = "5.0.0",
36 note = "The ContentSelector component has been deprecated by PatternFly. \
37 See https://pf5.patternfly.org/components/menus/context-selector for more information."
38)]
39pub struct ContextSelector {
40 expanded: bool,
41 global_close: GlobalClose,
42}
43
44#[allow(deprecated)]
45impl Component for ContextSelector {
46 type Message = ContextSelectorMsg;
47 type Properties = ContextSelectorProperties;
48
49 fn create(ctx: &Context<Self>) -> Self {
50 let global_close = GlobalClose::new(
51 NodeRef::default(),
52 ctx.link().callback(|_| ContextSelectorMsg::Close),
53 );
54 Self {
55 expanded: false,
56 global_close,
57 }
58 }
59
60 fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
61 match msg {
62 Self::Message::Toggle => {
63 self.expanded = !self.expanded;
64 }
65 Self::Message::Close => {
66 self.expanded = false;
67 }
68 Self::Message::Search(value) => {
69 ctx.props().onsearch.emit(value);
70 return false;
71 }
72 }
73 true
74 }
75
76 fn view(&self, ctx: &Context<Self>) -> Html {
77 let mut classes = Classes::from("pf-v5-c-context-selector");
78
79 if self.expanded {
80 classes.push("pf-m-expanded");
81 }
82
83 html! (
84 <div
85 class={classes}
86 ref={self.global_close.clone()}
87 >
88 <button
89 class="pf-v5-c-context-selector__toggle"
90 aria-expanded={self.expanded.to_string()}
91 type="button"
92 onclick={ctx.link().callback(|_|ContextSelectorMsg::Toggle)}
93 >
94 <span class="pf-v5-c-context-selector__toggle-text">{&ctx.props().selected}</span>
95 <span class="pf-v5-c-context-selector__toggle-icon">{Icon::CaretDown}</span>
96 </button>
97 <div class="pf-v5-c-context-selector__menu"
98 hidden={!self.expanded}
99 >
100 <div class="pf-v5-c-context-selector__menu-search">
101 <InputGroup>
102 <TextInput
103 onchange={ctx.link().callback(ContextSelectorMsg::Search)}
104 icon={Icon::Search}
105 r#type={TextInputType::Search}
106 />
107 </InputGroup>
108 </div>
109 <ul class="pf-v5-c-context-selector__menu-list">
110 { for ctx.props().children.iter().map(|mut item|{
111 let props = Rc::make_mut(&mut item.props);
112 props.need_close = ctx.link().callback(|_|ContextSelectorMsg::Close);
113 item
114 }) }
115 </ul>
116 </div>
117 </div>
118 )
119 }
120}
121
122#[derive(Properties, Debug, Clone, PartialEq)]
126pub struct ItemProperties {
127 pub label: String,
128 #[prop_or_default]
129 pub onclick: Callback<()>,
130 #[prop_or_default]
131 pub disabled: bool,
132 #[prop_or_default]
133 pub(crate) need_close: Callback<()>,
134}
135
136#[doc(hidden)]
137#[derive(Clone, Copy, Debug)]
138pub enum ItemMsg {
139 Clicked,
140}
141
142pub struct ContextSelectorItem {}
144
145impl Component for ContextSelectorItem {
146 type Message = ItemMsg;
147 type Properties = ItemProperties;
148
149 fn create(_ctx: &Context<Self>) -> Self {
150 Self {}
151 }
152
153 fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
154 match msg {
155 Self::Message::Clicked => {
156 ctx.props().onclick.emit(());
157 ctx.props().need_close.emit(());
158 }
159 }
160 true
161 }
162
163 fn view(&self, ctx: &Context<Self>) -> Html {
164 let classes = Classes::from("pf-v5-c-context-selector__menu-list-item");
165
166 html!(
167 <li>
168 <button
169 class={classes}
170 disabled={ctx.props().disabled}
171 type="button"
172 onclick={ctx.link().callback(|_|ItemMsg::Clicked)}
173 >
174 { &ctx.props().label }
175 </button>
176 </li>
177 )
178 }
179}