impulse_thaw/upload/
mod.rs1mod upload_dragger;
2
3pub use upload_dragger::UploadDragger;
4pub use web_sys::FileList;
5
6use leptos::{ev, html, prelude::*};
7use thaw_utils::{add_event_listener, class_list, mount_style, ArcOneCallback};
8
9#[component]
10pub fn Upload(
11 #[prop(optional, into)] class: MaybeProp<String>,
12 #[prop(optional, into)] id: MaybeProp<String>,
13 #[prop(optional, into)]
16 name: MaybeProp<String>,
17 #[prop(optional, into)]
19 accept: Signal<String>,
20 #[prop(optional, into)]
22 multiple: Signal<bool>,
23 #[prop(optional, into)]
25 custom_request: Option<ArcOneCallback<FileList>>,
26 children: Children,
27) -> impl IntoView {
28 mount_style("upload", include_str!("./upload.css"));
29
30 let input_ref = NodeRef::<html::Input>::new();
31 let trigger_ref = NodeRef::<html::Div>::new();
32
33 Effect::new(move |_| {
34 let Some(trigger_el) = trigger_ref.get() else {
35 return;
36 };
37 let handle = add_event_listener(trigger_el, ev::click, move |_| {
38 if let Some(input_ref) = input_ref.get_untracked() {
39 input_ref.click();
40 }
41 });
42 on_cleanup(move || {
43 handle.remove();
44 });
45 });
46
47 let on_file_addition = move |files: FileList| {
48 if let Some(custom_request) = custom_request.as_ref() {
49 custom_request(files);
50 }
51 };
52
53 let on_change = {
54 let on_file_addition = on_file_addition.clone();
55 move |_| {
56 if let Some(input_ref) = input_ref.get_untracked() {
57 if let Some(files) = input_ref.files() {
58 on_file_addition(files);
59 }
60 input_ref.set_value("");
61 }
62 }
63 };
64
65 let is_trigger_dragover = RwSignal::new(false);
66 let on_trigger_drop = move |event: ev::DragEvent| {
67 event.prevent_default();
68 if let Some(data) = event.data_transfer() {
69 if let Some(files) = data.files() {
70 on_file_addition(files);
71 }
72 }
73 is_trigger_dragover.set(false);
74 };
75 let on_trigger_dragover = move |event: ev::DragEvent| {
76 event.prevent_default();
77 is_trigger_dragover.set(true);
78 };
79 let on_trigger_dragenter = move |event: ev::DragEvent| {
80 event.prevent_default();
81 };
82 let on_trigger_dragleave = move |event: ev::DragEvent| {
83 event.prevent_default();
84 is_trigger_dragover.set(false);
85 };
86
87 view! {
88 <div class=class_list![
89 "thaw-upload",
90 ("thaw-upload--drag-over", move || is_trigger_dragover.get()),
91 class
92 ]>
93 <input
94 class="thaw-upload__input"
95 id=move || id.get()
96 name=move || name.get()
97 node_ref=input_ref
98 type="file"
99 accept=move || accept.get()
100 multiple=move || multiple.get()
101 on:change=on_change
102 />
103 <div
104 class="thaw-upload__trigger"
105 node_ref=trigger_ref
106 on:drop=on_trigger_drop
107 on:dragover=on_trigger_dragover
108 on:dragenter=on_trigger_dragenter
109 on:dragleave=on_trigger_dragleave
110 >
111 {children()}
112 </div>
113 </div>
114 }
115}