1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use dominator::{html, Dom};
use futures_signals::signal::SignalExt;
use futures_signals_utils::split_signal::split_signal;

use crate::components::input::label::label_element;
use crate::components::input::validation_result::ValidationResult;

use crate::components::mixins::{assistive_text, disabled_signal_mixin};

#[component(render_fn = input_wrapper)]
struct InputWrapper {
    input: Dom,

    #[signal]
    #[default(None)]
    label: Option<Dom>,

    #[signal]
    #[default("".to_string())]
    value: String,

    #[signal]
    #[default(ValidationResult::Valid)]
    is_valid: ValidationResult,

    #[signal]
    #[default(false)]
    disabled: bool,

    #[signal]
    #[default(None)]
    assistive_text: Option<Dom>,

    #[signal]
    #[default(false)]
    has_focus: bool,

    class_name: String,

    extra_child: Dom,

    #[default(None)]
    input_id: Option<String>,
}

pub fn input_wrapper(props: impl InputWrapperPropsTrait + 'static) -> Dom {
    let InputWrapperProps {
        input,
        label,
        value,
        is_valid,
        disabled: disabled_signal,
        assistive_text: assistive_text_signal,
        has_focus,
        class_name,
        extra_child,
        input_id,
        apply,
    } = props.take();

    let label_element = label_element(value.map(|v| !v.is_empty()), has_focus, label, input_id);

    let (assistive_text_signal, has_assistive) =
        split_signal(assistive_text_signal, false, |v| v.is_some());

    let assistive = assistive_text(assistive_text_signal);
    let (error, has_error) = split_signal(is_valid, false, |v| !v.is_valid());
    let error = error.map(|e| match e {
        ValidationResult::Invalid { message } => Some(html!("div", {
            .class("error")
            .text(message.as_str())
        })),
        _ => None,
    });

    html!("div", {
        .apply_if(apply.is_some(), |d| d.apply(apply.unwrap()))
        .class_signal("-with-assistive",has_assistive)
        .class_signal("-invalid", has_error)
        .apply(disabled_signal_mixin(disabled_signal))
        .apply_if(class_name.is_some(), |d| d.class(class_name.unwrap()))
        .child(label_element)
        .apply_if(input.is_some(), |d| d.child(input.unwrap()))
        .apply_if(extra_child.is_some(), |d| d.child(extra_child.unwrap()))
        .child(html!("div", {
            .class("supporting-text")
            .child_signal(assistive)
            .child_signal(error)
        }))
    })
}