kayrx_ui/widget/
file_drop_area.rs1use web_sys::DragEvent;
2use crate::fabric::prelude::*;
3use crate::fabric::services::reader::File;
4
5pub struct FileDropArea {
6 props: Props,
7 link: ComponentLink<Self>,
8 input_ref: NodeRef,
9}
10
11pub enum Msg {
12 Files(Vec<File>),
13 Nop,
14}
15
16#[derive(Clone, Properties)]
17pub struct Props {
18 #[prop_or_default]
19 pub disabled: bool,
20 #[prop_or_else(Callback::noop)]
21 pub onchange: Callback<Vec<File>>,
22 #[prop_or_default]
23 pub children: Children,
24}
25
26impl Component for FileDropArea {
27 type Message = Msg;
28 type Properties = Props;
29
30 fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
31 FileDropArea {
32 props,
33 link,
34 input_ref: NodeRef::default(),
35 }
36 }
37
38 fn update(&mut self, msg: Self::Message) -> ShouldRender {
39 match msg {
40 Msg::Files(v) => {
41 self.props.onchange.emit(v);
42 return true;
43 }
44 Msg::Nop => {}
45 }
46 true
47 }
48
49 fn change(&mut self, props: Self::Properties) -> ShouldRender {
50 self.props = props;
51 true
52 }
53
54 fn view(&self) -> Html {
55 let ondragover = self.link.callback(|e: DragEvent| {
56 e.prevent_default();
57 Msg::Nop
58 });
59 let ondrop = self.link.callback(|e: DragEvent| {
60 e.prevent_default();
61 if let Some(ft) = e.data_transfer() {
62 return Msg::Files(
63 js_sys::try_iter(&ft.files().unwrap())
64 .unwrap()
65 .unwrap()
66 .map(|v| File::from(v.unwrap()))
67 .collect(),
68 );
69 }
70
71 Msg::Nop
72 });
73 let onchange = self.link.callback(|e| {
74 let res = match e {
75 ChangeData::Files(f) => js_sys::try_iter(&f)
76 .unwrap()
77 .unwrap()
78 .map(|v| File::from(v.unwrap()))
79 .collect(),
80 _ => unreachable!(),
81 };
82 Msg::Files(res)
83 });
84 html! {
85 <div class="bow-drop-area"
86 ondrop=ondrop
87 ondragover=ondragover
88 disabled=self.props.disabled>
89
90 <input type="file" hidden=true
91 ref=self.input_ref.clone(),
92 multiple=true
93 onchange=onchange></input>
94
95 { self.props.children.render() }
96 </div>
97 }
98 }
99}