euv_ui/component/switch/view/struct.rs
1use super::*;
2
3/// Props for the `euv_switch` component.
4///
5/// Defines the strongly-typed interface for a toggle switch. The checked
6/// state is owned by the caller through a `Signal<bool>` so the switch can
7/// participate in two-way binding with the rest of the page.
8#[derive(Clone, CustomDebug, Data, Default, New)]
9pub struct EuvSwitchProps {
10 /// The unique identifier for the switch element.
11 #[get(type(copy))]
12 pub id: &'static str,
13 /// The HTML name attribute shared by switches in the same form group.
14 #[get(type(copy))]
15 pub name: &'static str,
16 /// The boolean signal bound to the switch checked state.
17 #[get(type(copy))]
18 pub checked: Signal<bool>,
19 /// The label text displayed next to the switch.
20 #[get(type(copy))]
21 pub label: &'static str,
22 /// Whether the switch is disabled.
23 #[get(type(copy))]
24 pub disabled: Signal<bool>,
25}
26
27/// The reactive state handle for the `euv_switch` component.
28///
29/// Registered against the current hook context slot via
30/// [`HookContext::use_hook`], so every render at the same hook index
31/// observes the same `Signal<bool>` and the switch keeps its state
32/// across re-renders.
33#[derive(Clone, Copy, CustomDebug, Data, Default)]
34pub struct EuvSwitchState {
35 /// The signal holding the switch checked state.
36 #[get(type(copy))]
37 pub checked: Signal<bool>,
38}
39
40impl EuvSwitchState {
41 /// Creates a state handle for the given checked signal.
42 ///
43 /// The handle is a thin wrapper: it never owns the signal, it only
44 /// gives the view a place to hang [`Self::toggle`] and
45 /// [`Self::on_toggle`] without threading bare signals around.
46 ///
47 /// # Arguments
48 ///
49 /// - `Signal<bool>` - The checked-state signal to wrap.
50 ///
51 /// # Returns
52 ///
53 /// - `EuvSwitchState` - The state handle.
54 pub fn new(checked: Signal<bool>) -> Self {
55 Self { checked }
56 }
57
58 /// Flips the checked state of the switch.
59 ///
60 /// The click handler is a no-op while the switch is disabled, so a
61 /// disabled switch can never be flipped by a stray click.
62 pub fn toggle(&self) {
63 let current: bool = self.get_checked().get();
64 self.get_checked().set(!current);
65 }
66
67 /// Builds a click handler that toggles the switch.
68 ///
69 /// # Arguments
70 ///
71 /// - `Signal<bool>` - The disabled signal consulted on every click.
72 ///
73 /// # Returns
74 ///
75 /// - `Option<Rc<dyn Fn(Event)>>` - A click handler toggling the
76 /// checked signal, or ignoring the event while disabled.
77 pub fn on_toggle(&self, disabled: Signal<bool>) -> Option<Rc<dyn Fn(Event)>> {
78 let state: EuvSwitchState = *self;
79 Some(Rc::new(move |_: Event| {
80 if disabled.get() {
81 return;
82 }
83 state.toggle();
84 }))
85 }
86}
87
88/// Obtains the switch state handle registered against the current hook
89/// context slot.
90///
91/// Behaves like [`HookContext::use_hook`] — the same handle is returned
92/// on every render at the same hook index, so the captured signal
93/// survives re-renders. The factory is used directly when no hook
94/// context is active (e.g. when called outside a render cycle).
95///
96/// # Arguments
97///
98/// - `Signal<bool>` - The checked-state signal owned by the caller.
99///
100/// # Returns
101///
102/// - `EuvSwitchState` - The switch state handle.
103pub fn use_euv_switch_state(checked: Signal<bool>) -> EuvSwitchState {
104 HookContext::use_hook(move || EuvSwitchState::new(checked))
105}