dioxus_bulma/components/
file.rs1use dioxus::prelude::*;
2use crate::theme::{BulmaColor, BulmaSize};
3use crate::utils::build_class;
4
5#[derive(Props, Clone, PartialEq)]
6pub struct FileProps {
7 #[props(default)]
8 pub color: Option<BulmaColor>,
9 #[props(default)]
10 pub size: Option<BulmaSize>,
11 #[props(default)]
12 pub boxed: Option<bool>,
13 #[props(default)]
14 pub centered: Option<bool>,
15 #[props(default)]
16 pub right: Option<bool>,
17 #[props(default)]
18 pub fullwidth: Option<bool>,
19 #[props(default)]
20 pub has_name: Option<bool>,
21 #[props(default)]
22 pub accept: Option<String>,
23 #[props(default)]
24 pub multiple: Option<bool>,
25 #[props(default)]
26 pub disabled: Option<bool>,
27 #[props(default)]
28 pub name: Option<String>,
29 #[props(default)]
30 pub filename: Option<String>,
31 #[props(default)]
32 pub onchange: Option<EventHandler<FormEvent>>,
33 #[props(default)]
34 pub id: Option<String>,
35 #[props(default)]
36 pub class: Option<String>,
37 #[props(default)]
38 pub style: Option<String>,
39 pub children: Element,
40}
41
42#[component]
43pub fn File(props: FileProps) -> Element {
44 let size = props.size.unwrap_or_default();
45 let boxed = props.boxed.unwrap_or(false);
46 let centered = props.centered.unwrap_or(false);
47 let right = props.right.unwrap_or(false);
48 let fullwidth = props.fullwidth.unwrap_or(false);
49 let has_name = props.has_name.unwrap_or(false);
50 let multiple = props.multiple.unwrap_or(false);
51 let disabled = props.disabled.unwrap_or(false);
52
53 let base_classes = vec!["file"];
54 let optional_classes = vec![
55 props.color.map(|c| format!("is-{}", c.as_str())),
56 if size != BulmaSize::Normal { Some(size.as_class().to_string()) } else { None },
57 if boxed { Some("is-boxed".to_string()) } else { None },
58 if centered { Some("is-centered".to_string()) } else { None },
59 if right { Some("is-right".to_string()) } else { None },
60 if fullwidth { Some("is-fullwidth".to_string()) } else { None },
61 if has_name { Some("has-name".to_string()) } else { None },
62 props.class.clone(),
63 ];
64
65 let final_class = build_class(&base_classes, &optional_classes);
66 let file_style = props.style.as_deref().unwrap_or("");
67
68 rsx! {
69 div {
70 class: "{final_class}",
71 style: "{file_style}",
72 id: props.id.clone(),
73 label {
74 class: "file-label",
75 input {
76 class: "file-input",
77 r#type: "file",
78 accept: props.accept.as_deref(),
79 multiple: multiple,
80 disabled: disabled,
81 name: props.name.as_deref(),
82 onchange: move |evt| {
83 if let Some(handler) = &props.onchange {
84 handler.call(evt);
85 }
86 }
87 }
88 span {
89 class: "file-cta",
90 span {
91 class: "file-icon",
92 i { class: "fas fa-upload" }
93 }
94 span {
95 class: "file-label",
96 {props.children}
97 }
98 }
99 if has_name {
100 span {
101 class: "file-name",
102 {props.filename.as_deref().unwrap_or("No file chosen")}
103 }
104 }
105 }
106 }
107 }
108}