leptos_forms_rs/components/
markdown_input.rs1use crate::core::types::FieldValue;
2use leptos::prelude::*;
3
4#[component]
6pub fn MarkdownInput(
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_preview: Option<bool>,
37 #[prop(optional)]
39 show_toolbar: Option<bool>,
40 #[prop(optional)]
42 min_height: Option<u32>,
43 #[prop(optional)]
45 max_height: Option<u32>,
46) -> impl IntoView {
47 let _show_preview = show_preview.unwrap_or(true);
48 let show_toolbar = show_toolbar.unwrap_or(true);
49 let min_height = min_height.unwrap_or(200);
50 let max_height = max_height.unwrap_or(600);
51
52 let current_value = move || match value.get() {
53 FieldValue::String(s) => s,
54 _ => String::new(),
55 };
56
57 let toolbar_view = move || {
58 if show_toolbar {
59 Some(view! {
60 <div class="markdown-toolbar">
61 <button type="button" class="toolbar-btn">"H1"</button>
62 <button type="button" class="toolbar-btn">"H2"</button>
63 <button type="button" class="toolbar-btn">"H3"</button>
64 <div class="toolbar-separator"></div>
65 <button type="button" class="toolbar-btn">"B"</button>
66 <button type="button" class="toolbar-btn">"I"</button>
67 <div class="toolbar-separator"></div>
68 <button type="button" class="toolbar-btn">"•"</button>
69 <button type="button" class="toolbar-btn">"1."</button>
70 <div class="toolbar-separator"></div>
71 <button type="button" class="toolbar-btn">"🔗"</button>
72 <button type="button" class="toolbar-btn">"🖼️"</button>
73 <button type="button" class="toolbar-btn">"```"</button>
74 <button type="button" class="toolbar-btn">">"</button>
75 <div class="toolbar-separator"></div>
76 <button type="button" class="toolbar-btn">"👁️"</button>
77 <button type="button" class="toolbar-btn">"⫴"</button>
78 </div>
79 })
80 } else {
81 None
82 }
83 };
84
85 let error_view = move || {
86 error.as_ref().map(|error_msg| {
87 view! {
88 <div class="error-message">
89 {error_msg.clone()}
90 </div>
91 }
92 })
93 };
94
95 view! {
96 <div class={format!("markdown-input {}", class.unwrap_or_default())}>
97 {toolbar_view}
98
99 <div class="markdown-editor-container">
100 <textarea
101 name={name.clone()}
102 placeholder={placeholder}
103 required={required}
104 disabled={disabled}
105 class={move || {
106 let mut classes = vec!["markdown-textarea"];
107 if has_error.unwrap_or(false) {
108 classes.push("error");
109 }
110 if disabled.unwrap_or(false) {
111 classes.push("disabled");
112 }
113 classes.join(" ")
114 }}
115 style={format!("min-height: {}px; max-height: {}px;", min_height, max_height)}
116 >{current_value}</textarea>
117 </div>
118
119 {error_view}
120 </div>
121 }
122}