yew_hooks/hooks/
use_toggle.rs

1use std::fmt;
2use std::ops::Deref;
3use std::rc::Rc;
4
5use yew::prelude::*;
6
7enum ToggleAction<T> {
8    Toggle,
9    Reset,
10    Set(T),
11    SetLeft,
12    SetRight,
13}
14
15struct UseToggleReducer<T>
16where
17    T: PartialEq,
18{
19    value: Rc<T>,
20    left: Rc<T>,
21    right: Rc<T>,
22}
23
24impl<T> Reducible for UseToggleReducer<T>
25where
26    T: PartialEq,
27{
28    type Action = ToggleAction<T>;
29
30    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
31        let next_value = match action {
32            ToggleAction::Toggle => {
33                if self.value == self.left {
34                    self.right.clone()
35                } else {
36                    self.left.clone()
37                }
38            }
39            ToggleAction::Set(value) => Rc::new(value),
40            ToggleAction::Reset | ToggleAction::SetLeft => self.left.clone(),
41            ToggleAction::SetRight => self.right.clone(),
42        };
43
44        Self {
45            value: next_value,
46            left: self.left.clone(),
47            right: self.right.clone(),
48        }
49        .into()
50    }
51}
52
53impl<T> PartialEq for UseToggleReducer<T>
54where
55    T: PartialEq,
56{
57    fn eq(&self, other: &Self) -> bool {
58        self.value == other.value
59    }
60}
61
62/// State handle for the [`use_toggle`] hook.
63pub struct UseToggleHandle<T>
64where
65    T: PartialEq,
66{
67    inner: UseReducerHandle<UseToggleReducer<T>>,
68}
69
70impl<T> UseToggleHandle<T>
71where
72    T: PartialEq,
73{
74    /// Toggle the value.
75    pub fn toggle(&self) {
76        self.inner.dispatch(ToggleAction::Toggle);
77    }
78
79    /// Set to a value.
80    pub fn set(&self, value: T) {
81        self.inner.dispatch(ToggleAction::Set(value));
82    }
83
84    /// Set to the left default value.
85    pub fn set_left(&self) {
86        self.inner.dispatch(ToggleAction::SetLeft);
87    }
88
89    /// Set to the right other value.
90    pub fn set_right(&self) {
91        self.inner.dispatch(ToggleAction::SetRight);
92    }
93
94    /// Reset to the default value.
95    pub fn reset(&self) {
96        self.inner.dispatch(ToggleAction::Reset);
97    }
98}
99
100impl<T> Deref for UseToggleHandle<T>
101where
102    T: PartialEq,
103{
104    type Target = T;
105
106    fn deref(&self) -> &Self::Target {
107        &(*self.inner).value
108    }
109}
110
111impl<T> Clone for UseToggleHandle<T>
112where
113    T: PartialEq,
114{
115    fn clone(&self) -> Self {
116        Self {
117            inner: self.inner.clone(),
118        }
119    }
120}
121
122impl<T> PartialEq for UseToggleHandle<T>
123where
124    T: PartialEq,
125{
126    fn eq(&self, other: &Self) -> bool {
127        *self.inner == *other.inner
128    }
129}
130
131impl<T: fmt::Debug + PartialEq> fmt::Debug for UseToggleHandle<T> {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        f.debug_struct("UseToggleHandle")
134            .field("value", &format!("{:?}", self.inner.value))
135            .field("left", &format!("{:?}", self.inner.left))
136            .field("right", &format!("{:?}", self.inner.right))
137            .finish()
138    }
139}
140
141/// This hook is a simplified [`use_toggle`] to manage boolean toggle state in a function component.
142///
143/// # Example
144///
145/// ```rust
146/// # use yew::prelude::*;
147/// #
148/// use yew_hooks::prelude::*;
149///
150/// #[function_component(Toggle)]
151/// fn toggle() -> Html {
152///     let toggle = use_bool_toggle(true);
153///
154///     let onclick = {
155///         let toggle = toggle.clone();
156///         Callback::from(move |_| toggle.toggle())
157///     };
158///     
159///     html! {
160///         <div>
161///             <button {onclick}>{ "Toggle" }</button>
162///             <p>
163///                 <b>{ "Current value: " }</b>
164///                 { *toggle }
165///             </p>
166///         </div>
167///     }
168/// }
169/// ```
170#[hook]
171pub fn use_bool_toggle(default: bool) -> UseToggleHandle<bool> {
172    use_toggle(default, !default)
173}
174
175/// This hook is used to manage toggle state in a function component.
176///
177/// # Example
178///
179/// ```rust
180/// # use yew::prelude::*;
181/// #
182/// use yew_hooks::prelude::*;
183///
184/// #[function_component(UseToggle)]
185/// fn toggle() -> Html {
186///     let toggle = use_toggle("Hello", "World");
187///
188///     let onclick = {
189///         let toggle = toggle.clone();
190///         Callback::from(move |_| toggle.toggle())
191///     };
192///     
193///     html! {
194///         <div>
195///             <button {onclick}>{ "Toggle" }</button>
196///             <p>
197///                 <b>{ "Current value: " }</b>
198///                 { *toggle }
199///             </p>
200///         </div>
201///     }
202/// }
203/// ```
204#[hook]
205pub fn use_toggle<T>(default: T, other: T) -> UseToggleHandle<T>
206where
207    T: 'static + PartialEq,
208{
209    let value = Rc::new(default);
210    let left = value.clone();
211    let right = Rc::new(other);
212
213    let inner = use_reducer(move || UseToggleReducer { value, left, right });
214
215    UseToggleHandle { inner }
216}
OSZAR »