mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
parent
b09f9e4814
commit
71de6c395b
10 changed files with 237 additions and 1 deletions
|
@ -5,6 +5,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
|||
CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = ""
|
||||
CARGO_MAKE_WORKSPACE_EMULATION = true
|
||||
CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
||||
"animated_show",
|
||||
"counter",
|
||||
"counter_isomorphic",
|
||||
"counters",
|
||||
|
|
14
examples/animated_show/Cargo.toml
Normal file
14
examples/animated_show/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "animated-show"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
11
examples/animated_show/Makefile.toml
Normal file
11
examples/animated_show/Makefile.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
extend = { path = "../cargo-make/main.toml" }
|
||||
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
9
examples/animated_show/README.md
Normal file
9
examples/animated_show/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# `<AnimatedShow>` combined with CSS animations
|
||||
|
||||
This is a very simple example of the `<AnimatedShow>` component.
|
||||
|
||||
This component is an extension for the `<Show>` component and it will not take in a fallback, but it will unmount the
|
||||
component from the DOM after a given duration. This makes it possible to have really easy unmount animations with just
|
||||
CSS.
|
||||
|
||||
Just execute `trunk serve` to start the demo.
|
42
examples/animated_show/index.html
Normal file
42
examples/animated_show/index.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
<style>
|
||||
.hover-me {
|
||||
width: 100px;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid grey;
|
||||
}
|
||||
.here-i-am {
|
||||
width: 100px;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
background: black;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@keyframes fade-out {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
.fade-in-1000 {
|
||||
animation: 1000ms fade-in forwards;
|
||||
}
|
||||
.fade-out-1000 {
|
||||
animation: 1000ms fade-out forwards;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
BIN
examples/animated_show/public/favicon.ico
Normal file
BIN
examples/animated_show/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
34
examples/animated_show/src/lib.rs
Normal file
34
examples/animated_show/src/lib.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use core::time::Duration;
|
||||
use leptos::*;
|
||||
|
||||
#[component]
|
||||
pub fn App(cx: Scope) -> impl IntoView {
|
||||
let show = create_rw_signal(cx, false);
|
||||
|
||||
// the CSS classes in this example are just written directly inside the `index.html`
|
||||
view! { cx,
|
||||
<div
|
||||
class="hover-me"
|
||||
on:mouseenter=move |_| show.set(true)
|
||||
on:mouseleave=move |_| show.set(false)
|
||||
>
|
||||
"Hover Me"
|
||||
</div>
|
||||
|
||||
<AnimatedShow
|
||||
when=show
|
||||
// optional CSS class which will be applied if `when == true`
|
||||
show_class="fade-in-1000"
|
||||
// optional CSS class which will be applied if `when == false` and before the
|
||||
// `hide_delay` starts -> makes CSS unmount animations really easy
|
||||
hide_class="fade-out-1000"
|
||||
// the given unmount delay which should match your unmount animation duration
|
||||
hide_delay=Duration::from_millis(1000)
|
||||
>
|
||||
// provide any `Children` inside here
|
||||
<div class="here-i-am">
|
||||
"Here I Am!"
|
||||
</div>
|
||||
</AnimatedShow>
|
||||
}
|
||||
}
|
12
examples/animated_show/src/main.rs
Normal file
12
examples/animated_show/src/main.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use animated_show::App;
|
||||
use leptos::*;
|
||||
|
||||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|cx| {
|
||||
view! { cx,
|
||||
<App />
|
||||
}
|
||||
})
|
||||
}
|
111
leptos/src/animated_show.rs
Normal file
111
leptos/src/animated_show.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use crate::Show;
|
||||
use core::time::Duration;
|
||||
use leptos::component;
|
||||
use leptos_dom::{helpers::TimeoutHandle, Fragment, IntoView};
|
||||
use leptos_macro::view;
|
||||
use leptos_reactive::{
|
||||
create_effect, on_cleanup, signal_prelude::*, store_value, Scope,
|
||||
StoredValue,
|
||||
};
|
||||
|
||||
/// A component that will show its children when the `when` condition is `true`.
|
||||
/// Additionally, you need to specify a `hide_delay`. If the `when` condition changes to `false`,
|
||||
/// the unmounting of the children will be delayed by the specified Duration.
|
||||
/// If you provide the optional `show_class` and `hide_class`, you can create very easy mount /
|
||||
/// unmount animations.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use core::time::Duration;
|
||||
/// # use leptos::*;
|
||||
/// # #[component]
|
||||
/// # pub fn App(cx: Scope) -> impl IntoView {
|
||||
/// let show = create_rw_signal(cx, false);
|
||||
///
|
||||
/// view! { cx,
|
||||
/// <div
|
||||
/// class="hover-me"
|
||||
/// on:mouseenter=move |_| show.set(true)
|
||||
/// on:mouseleave=move |_| show.set(false)
|
||||
/// >
|
||||
/// "Hover Me"
|
||||
/// </div>
|
||||
///
|
||||
/// <AnimatedShow
|
||||
/// when=show
|
||||
/// show_class="fade-in-1000"
|
||||
/// hide_class="fade-out-1000"
|
||||
/// hide_delay=Duration::from_millis(1000)
|
||||
/// >
|
||||
/// <div class="here-i-am">
|
||||
/// "Here I Am!"
|
||||
/// </div>
|
||||
/// </AnimatedShow>
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
any(debug_assertions, feature = "ssr"),
|
||||
tracing::instrument(level = "info", skip_all)
|
||||
)]
|
||||
#[component]
|
||||
pub fn AnimatedShow(
|
||||
/// The scope the component is running in
|
||||
cx: Scope,
|
||||
/// The components Show wraps
|
||||
children: Box<dyn Fn(Scope) -> Fragment>,
|
||||
/// If the component should show or not
|
||||
#[prop(into)]
|
||||
when: MaybeSignal<bool>,
|
||||
/// Optional CSS class to apply if `when == true`
|
||||
#[prop(optional)]
|
||||
show_class: &'static str,
|
||||
/// Optional CSS class to apply if `when == false`
|
||||
#[prop(optional)]
|
||||
hide_class: &'static str,
|
||||
/// The timeout after which the component will be unmounted if `when == false`
|
||||
hide_delay: Duration,
|
||||
) -> impl IntoView {
|
||||
let handle: StoredValue<Option<TimeoutHandle>> = store_value(cx, None);
|
||||
let cls = create_rw_signal(
|
||||
cx,
|
||||
if when.get_untracked() {
|
||||
show_class
|
||||
} else {
|
||||
hide_class
|
||||
},
|
||||
);
|
||||
let show = create_rw_signal(cx, when.get_untracked());
|
||||
|
||||
create_effect(cx, move |_| {
|
||||
if when.get() {
|
||||
// clear any possibly active timer
|
||||
if let Some(h) = handle.get_value() {
|
||||
h.clear();
|
||||
}
|
||||
|
||||
cls.set(show_class);
|
||||
show.set(true);
|
||||
} else {
|
||||
cls.set(hide_class);
|
||||
|
||||
let h = leptos_dom::helpers::set_timeout_with_handle(
|
||||
move || show.set(false),
|
||||
hide_delay,
|
||||
)
|
||||
.expect("set timeout in AnimatedShow");
|
||||
handle.set_value(Some(h));
|
||||
}
|
||||
});
|
||||
|
||||
on_cleanup(cx, move || {
|
||||
if let Some(h) = handle.get_value() {
|
||||
h.clear();
|
||||
}
|
||||
});
|
||||
|
||||
view! { cx,
|
||||
<Show when=move || show.get() fallback=|_| ()>
|
||||
<div class=move || cls.get()>{children(cx)}</div>
|
||||
</Show>
|
||||
}
|
||||
}
|
|
@ -189,12 +189,14 @@ pub use typed_builder;
|
|||
pub use {leptos_macro::template, wasm_bindgen, web_sys};
|
||||
mod error_boundary;
|
||||
pub use error_boundary::*;
|
||||
mod animated_show;
|
||||
mod for_loop;
|
||||
mod show;
|
||||
pub use animated_show::*;
|
||||
pub use for_loop::*;
|
||||
pub use show::*;
|
||||
mod suspense_component;
|
||||
pub use suspense_component::*;
|
||||
mod suspense_component;
|
||||
mod text_prop;
|
||||
mod transition;
|
||||
pub use text_prop::TextProp;
|
||||
|
|
Loading…
Reference in a new issue