impulse_thaw/textarea/
mod.rs1mod rule;
2mod types;
3
4pub use rule::*;
5pub use types::*;
6
7use crate::{FieldInjection, Rule};
8use leptos::{ev, html, prelude::*};
9use thaw_utils::{class_list, mount_style, BoxOneCallback, ComponentRef, Model};
10
11#[component]
12pub fn Textarea(
13 #[prop(optional, into)] class: MaybeProp<String>,
14 #[prop(optional, into)] id: MaybeProp<String>,
15 #[prop(optional, into)]
18 name: MaybeProp<String>,
19 #[prop(optional, into)]
21 rules: Vec<TextareaRule>,
22 #[prop(optional, into)]
24 value: Model<String>,
25 #[prop(optional, into)]
27 allow_value: Option<BoxOneCallback<String, bool>>,
28 #[prop(optional, into)]
30 placeholder: MaybeProp<String>,
31 #[prop(optional, into)]
33 on_focus: Option<BoxOneCallback<ev::FocusEvent>>,
34 #[prop(optional, into)]
36 on_blur: Option<BoxOneCallback<ev::FocusEvent>>,
37 #[prop(optional, into)]
39 disabled: Signal<bool>,
40 #[prop(optional, into)]
42 resize: Signal<TextareaResize>,
43 #[prop(optional, into)]
45 size: Signal<TextareaSize>,
46 #[prop(optional)] comp_ref: ComponentRef<TextareaRef>,
47 ) -> impl IntoView {
49 mount_style("textarea", include_str!("./textarea.css"));
50 let (id, name) = FieldInjection::use_id_and_name(id, name);
51 let validate = Rule::validate(rules, value, name);
52 let value_trigger = ArcTrigger::new();
53 let on_input = {
54 let value_trigger = value_trigger.clone();
55 move |ev| {
56 let input_value = event_target_value(&ev);
57 if let Some(allow_value) = allow_value.as_ref() {
58 if !allow_value(input_value.clone()) {
59 value_trigger.notify();
60 return;
61 }
62 }
63 value.set(input_value);
64 validate.run(Some(TextareaRuleTrigger::Input));
65 }
66 };
67 let on_change = move |_| {
68 validate.run(Some(TextareaRuleTrigger::Change));
69 };
70 let on_internal_focus = move |ev| {
71 if let Some(on_focus) = on_focus.as_ref() {
72 on_focus(ev);
73 }
74 validate.run(Some(TextareaRuleTrigger::Focus));
75 };
76 let on_internal_blur = move |ev| {
77 if let Some(on_blur) = on_blur.as_ref() {
78 on_blur(ev);
79 }
80 validate.run(Some(TextareaRuleTrigger::Blur));
81 };
82
83 let textarea_ref = NodeRef::<html::Textarea>::new();
84 comp_ref.load(TextareaRef { textarea_ref });
85
86 view! {
87 <span class=class_list![
88 "thaw-textarea",
89 ("thaw-textarea--disabled", move || disabled.get()),
90 move || format!("thaw-textarea--resize-{}", resize.get().as_str()),
91 move || format!("thaw-textarea--{}", size.get().as_str()),
92 class
93 ]>
94 <textarea
95 prop:value=move || {
96 value_trigger.track();
97 value.get()
98 }
99
100 on:input=on_input
101 on:change=on_change
102 on:focus=on_internal_focus
103 on:blur=on_internal_blur
104 class="thaw-textarea__textarea"
105 id=id
106 name=name
107 disabled=move || disabled.get()
108 placeholder=move || placeholder.get()
109 node_ref=textarea_ref
110 ></textarea>
111 </span>
112 }
113}