leptos_forms_rs/components/
rich_text_input.rs1use crate::core::types::FieldValue;
2use leptos::prelude::*;
3
4#[component]
6pub fn RichTextInput(
7 #[prop(into)]
9 name: String,
10 #[prop(into)]
12 value: Signal<FieldValue>,
13 #[prop(into)]
15 _on_change: Callback<FieldValue>,
16 #[prop(optional, into)]
18 placeholder: Option<String>,
19 #[prop(optional)]
21 required: Option<bool>,
22 #[prop(optional)]
24 disabled: Option<bool>,
25 #[prop(optional, into)]
27 class: Option<String>,
28 #[prop(optional, into)]
30 error: Option<String>,
31 #[prop(optional)]
33 has_error: Option<bool>,
34 #[prop(optional)]
36 show_toolbar: Option<bool>,
37 #[prop(optional)]
39 min_height: Option<u32>,
40 #[prop(optional)]
42 max_height: Option<u32>,
43) -> impl IntoView {
44 let show_toolbar = show_toolbar.unwrap_or(true);
45 let min_height = min_height.unwrap_or(200);
46 let max_height = max_height.unwrap_or(600);
47
48 let current_value = move || match value.get() {
49 FieldValue::String(s) => s,
50 _ => String::new(),
51 };
52
53 let toolbar_view = move || {
54 if show_toolbar {
55 Some(view! {
56 <div class="rich-text-toolbar">
57 <button type="button" class="toolbar-btn">"B"</button>
58 <button type="button" class="toolbar-btn">"I"</button>
59 <button type="button" class="toolbar-btn">"U"</button>
60 <div class="toolbar-separator"></div>
61 <button type="button" class="toolbar-btn">"โข"</button>
62 <button type="button" class="toolbar-btn">"1."</button>
63 <div class="toolbar-separator"></div>
64 <button type="button" class="toolbar-btn">"๐"</button>
65 <button type="button" class="toolbar-btn">"๐ผ๏ธ"</button>
66 <div class="toolbar-separator"></div>
67 <button type="button" class="toolbar-btn">"๐งน"</button>
68 </div>
69 })
70 } else {
71 None
72 }
73 };
74
75 let error_view = move || {
76 error.as_ref().map(|error_msg| {
77 view! {
78 <div class="error-message">
79 {error_msg.clone()}
80 </div>
81 }
82 })
83 };
84
85 view! {
86 <div class={format!("rich-text-input {}", class.unwrap_or_default())}>
87 {toolbar_view}
88
89 <textarea
90 name={name.clone()}
91 placeholder={placeholder}
92 required={required}
93 disabled={disabled}
94 class={move || {
95 let mut classes = vec!["rich-text-editor"];
96 if has_error.unwrap_or(false) {
97 classes.push("error");
98 }
99 if disabled.unwrap_or(false) {
100 classes.push("disabled");
101 }
102 classes.join(" ")
103 }}
104 style={format!("min-height: {}px; max-height: {}px;", min_height, max_height)}
105 >{current_value}</textarea>
106
107 {error_view}
108 </div>
109 }
110}