impulse_thaw/field/
field_context_provider.rs1use 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}