mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-23 14:29:22 -05:00
feat: upload component
This commit is contained in:
parent
0f0fde49a3
commit
5c1943bdd4
5 changed files with 108 additions and 6 deletions
|
@ -14,7 +14,7 @@ license = "MIT"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
leptos = { version = "0.5.1", features = ["csr"] }
|
leptos = { version = "0.5.1", features = ["csr"] }
|
||||||
web-sys = { version = "0.3.62", features = ["DomRect"] }
|
web-sys = { version = "0.3.62", features = ["DomRect", "File", "FileList"] }
|
||||||
wasm-bindgen = "0.2.85"
|
wasm-bindgen = "0.2.85"
|
||||||
icondata = { version = "0.1.0", features = [
|
icondata = { version = "0.1.0", features = [
|
||||||
"AiCloseOutlined",
|
"AiCloseOutlined",
|
||||||
|
|
|
@ -40,7 +40,6 @@ pub fn Skeleton(
|
||||||
css_vars
|
css_vars
|
||||||
});
|
});
|
||||||
(0..repeat.get())
|
(0..repeat.get())
|
||||||
.into_iter()
|
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
view! { <div class="melt-skeleton" style=move || css_vars.get()></div> }
|
view! { <div class="melt-skeleton" style=move || css_vars.get()></div> }
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
|
use crate::{mount_style, utils::AsyncCallback};
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use crate::mount_style;
|
use web_sys::FileList;
|
||||||
// TODO
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Upload(
|
pub fn Upload(
|
||||||
#[prop(optional, into)] accept: MaybeSignal<String>,
|
#[prop(optional, into)] accept: MaybeSignal<String>,
|
||||||
#[prop(optional, into)] multiple: MaybeSignal<bool>,
|
#[prop(optional, into)] multiple: MaybeSignal<bool>,
|
||||||
|
#[prop(optional, into)] on_before_upload: Option<AsyncCallback<FileList, bool>>,
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("upload", include_str!("./upload.css"));
|
mount_style("upload", include_str!("./upload.css"));
|
||||||
let on_file_addition = move || {
|
|
||||||
|
|
||||||
|
let on_file_addition = move |files: FileList| {
|
||||||
|
spawn_local(async move {
|
||||||
|
if let Some(on_before_upload) = on_before_upload {
|
||||||
|
let is_allow = on_before_upload.call(files).await;
|
||||||
|
if is_allow {
|
||||||
|
//TODO submit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
let input_ref = create_node_ref::<html::Input>();
|
let input_ref = create_node_ref::<html::Input>();
|
||||||
let on_change = move |_| {
|
let on_change = move |_| {
|
||||||
if let Some(input_ref) = input_ref.get_untracked() {
|
if let Some(input_ref) = input_ref.get_untracked() {
|
||||||
|
if let Some(files) = input_ref.files() {
|
||||||
|
on_file_addition(files);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let on_click = move |_| {
|
let on_click = move |_| {
|
||||||
|
|
89
src/utils/callback.rs
Normal file
89
src/utils/callback.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use leptos::StoredValue;
|
||||||
|
use std::{fmt, future::Future, pin::Pin, rc::Rc};
|
||||||
|
|
||||||
|
pub struct AsyncCallback<In: 'static, Out: 'static = ()>(
|
||||||
|
#[allow(clippy::complexity)] StoredValue<Rc<dyn Fn(In) -> Pin<Box<dyn Future<Output = Out>>>>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<In> fmt::Debug for AsyncCallback<In> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
fmt.write_str("AsyncCallback")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<In, Out> Clone for AsyncCallback<In, Out> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<In, Out> Copy for AsyncCallback<In, Out> {}
|
||||||
|
|
||||||
|
impl<In, Out> AsyncCallback<In, Out> {
|
||||||
|
pub fn new<F, Fu>(f: F) -> Self
|
||||||
|
where
|
||||||
|
F: Fn(In) -> Fu + 'static,
|
||||||
|
Fu: Future<Output = Out> + 'static,
|
||||||
|
{
|
||||||
|
let f = Rc::new(move |input: In| {
|
||||||
|
let fut = f(input);
|
||||||
|
Box::pin(fut) as Pin<Box<dyn Future<Output = Out>>>
|
||||||
|
});
|
||||||
|
Self(StoredValue::new(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn call(&self, input: In) -> Out {
|
||||||
|
let f = self.0.get_value();
|
||||||
|
f(input).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, In, Fu, Out> From<F> for AsyncCallback<In, Out>
|
||||||
|
where
|
||||||
|
F: Fn(In) -> Fu + 'static,
|
||||||
|
Fu: Future<Output = Out> + 'static,
|
||||||
|
{
|
||||||
|
fn from(f: F) -> AsyncCallback<In, Out> {
|
||||||
|
AsyncCallback::new(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::utils::AsyncCallback;
|
||||||
|
use leptos::create_runtime;
|
||||||
|
|
||||||
|
struct NoClone {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clone_async_callback() {
|
||||||
|
let rt = create_runtime();
|
||||||
|
let callback = AsyncCallback::new(move |_no_clone: NoClone| async { NoClone {} });
|
||||||
|
let _cloned = callback.clone();
|
||||||
|
rt.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn async_callback_from() {
|
||||||
|
let rt = create_runtime();
|
||||||
|
let _callback: AsyncCallback<(), String> = (|()| async { "test".to_string() }).into();
|
||||||
|
rt.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn async_callback_from_html() {
|
||||||
|
let rt = create_runtime();
|
||||||
|
use leptos::{
|
||||||
|
html::{HtmlElement, H1},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
let _callback: AsyncCallback<String, HtmlElement<H1>> = (|x: String| async move {
|
||||||
|
view! {
|
||||||
|
<h1>{x}</h1>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
rt.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
|
mod callback;
|
||||||
pub mod maybe_rw_signal;
|
pub mod maybe_rw_signal;
|
||||||
mod maybe_signal_store;
|
mod maybe_signal_store;
|
||||||
pub mod mount_style;
|
pub mod mount_style;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
|
|
||||||
|
pub use callback::AsyncCallback;
|
||||||
pub use maybe_signal_store::*;
|
pub use maybe_signal_store::*;
|
||||||
|
|
Loading…
Add table
Reference in a new issue