freya_components/hooks/
use_form.rs

1// This hook is in freya-components instead of freya-hooks because it uses some component props.
2
3use std::{
4    collections::HashMap,
5    fmt::Display,
6    hash::Hash,
7};
8
9use dioxus::prelude::*;
10
11use crate::{
12    ButtonProps,
13    InputMode,
14    InputProps,
15};
16
17type SubmitCallback<Id> = Box<dyn Fn(&HashMap<Id, String>)>;
18
19/// Form controller
20///
21/// Use [`Self::input()`] to register inputs
22/// And [`Self::submit()`] to register a submitter button
23#[derive(Clone)]
24pub struct UseForm<Id: Hash + Eq + 'static> {
25    data: Signal<HashMap<Id, String>>,
26    onsubmit: Signal<SubmitCallback<Id>>,
27}
28
29impl<Id: Clone + Hash + Eq + Display> UseForm<Id> {
30    /// Register an [crate::Input] component.
31    pub fn input(&self, id: Id) -> InputProps {
32        let value = self.data.read().get(&id).cloned().unwrap_or_default();
33        let placeholder = id.to_string();
34        let mut data = self.data;
35        InputProps {
36            onchange: EventHandler::new(move |txt| {
37                data.write().insert(id.clone(), txt);
38            }),
39            theme: None,
40            mode: InputMode::default(),
41            value: dioxus_core::prelude::SuperInto::super_into(value),
42            placeholder: dioxus_core::prelude::SuperInto::super_into(Some(placeholder)),
43            auto_focus: false,
44            onvalidate: None,
45            width: "150".to_string(),
46        }
47    }
48
49    /// Register a [crate::Button] component.
50    pub fn submit(&self) -> ButtonProps {
51        let submit = self.onsubmit;
52        let data = self.data;
53        ButtonProps {
54            theme: None,
55            onpress: Some(EventHandler::new(move |_| {
56                (submit.peek())(&data.read());
57            })),
58            children: Ok(VNode::placeholder()),
59            onclick: None,
60        }
61    }
62}
63
64/// Create a Form controller with a submit callback.
65pub fn use_form<Id: Hash + Eq + Clone>(
66    onsubmit: impl Fn(&HashMap<Id, String>) + 'static,
67) -> UseForm<Id> {
68    use_hook(|| UseForm {
69        data: Signal::new(HashMap::default()),
70        onsubmit: Signal::new(Box::new(onsubmit)),
71    })
72}