impulse_thaw/field/
field_context_provider.rs

1use leptos::{context::Provider, prelude::*};
2use slotmap::{DefaultKey, SlotMap};
3
4#[component]
5pub fn FieldContextProvider(children: Children) -> impl IntoView {
6    view! { <Provider value=FieldContextInjection::new()>{children()}</Provider> }
7}
8
9#[derive(Clone)]
10pub struct FieldContextInjection(
11    StoredValue<SlotMap<DefaultKey, (Signal<Option<String>>, Callback<(), bool>)>>,
12);
13
14impl FieldContextInjection {
15    fn new() -> Self {
16        Self(StoredValue::new(SlotMap::new()))
17    }
18
19    pub fn expect_context() -> Self {
20        expect_context()
21    }
22
23    pub fn use_context() -> Option<Self> {
24        use_context()
25    }
26
27    pub(crate) fn register_field(
28        &self,
29        name: Signal<Option<String>>,
30        validate: impl Fn() -> bool + Send + Sync + 'static,
31    ) {
32        let mut key = None;
33        let validate: Callback<(), bool> = Callback::from(move || validate());
34        self.0.update_value(|map| {
35            key = Some(map.insert((name, validate)));
36            ()
37        });
38
39        let map = self.0.clone();
40        Owner::on_cleanup(move || {
41            map.update_value(|map| {
42                map.remove(key.unwrap());
43            });
44        });
45    }
46
47    pub fn validate(&self) -> bool {
48        self.0.with_value(|map| {
49            let mut rt = true;
50            for (_, (_, validate)) in map.iter() {
51                if !validate.run(()) {
52                    rt = false;
53                }
54            }
55            rt
56        })
57    }
58
59    pub fn validate_field(&self, name: String) -> bool {
60        self.0.with_value(|map| {
61            for (_, (n, validate)) in map.iter() {
62                if n.get_untracked().as_ref() == Some(&name) && !validate.run(()) {
63                    return false;
64                }
65            }
66            true
67        })
68    }
69}