Skip to content

Commit

Permalink
Create use_ripple hook
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Oct 29, 2023
1 parent a664fb4 commit 9628d36
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 61 deletions.
31 changes: 15 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ pub use theme::{use_theme, Theme, ThemeProps, UseTheme};

mod text_field;
pub use text_field::TextField;

mod use_ripple;
pub use use_ripple::{use_ripple, UseRipple};
53 changes: 8 additions & 45 deletions src/ripple.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use dioxus::prelude::*;
use dioxus_resize_observer::use_size;
use dioxus_spring::{use_animated, use_spring_signal};
use dioxus_use_mounted::use_mounted;
use crate::use_ripple;
use std::time::Duration;

#[component]
Expand All @@ -11,32 +9,8 @@ pub fn Ripple<'a>(
children: Element<'a>,
duration: Option<Duration>,
) -> Element<'a> {
let is_pressed = use_state(cx, || false);

let container_ref = use_mounted(cx);
let content_rect = use_size(cx, container_ref);
let size = content_rect.width().max(content_rect.height()) * 1.2;

let (spring_ref, value_ref) = use_spring_signal(cx, [0f32; 2]);
let animated_ref = use_mounted(cx);

let duration = duration.unwrap_or(Duration::from_millis(200));

use_animated(cx, animated_ref, value_ref, |[size, opacity]| {
format!(
r"
width: {size}px;
height: {size}px;
opacity: {opacity};
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: rgba(150, 150, 150, 0.5);
"
)
});
let ripple = use_ripple(cx, duration);

render!(
div {
Expand All @@ -45,26 +19,15 @@ pub fn Ripple<'a>(
position: "relative",
overflow: "hidden",
cursor: "pointer",
onmounted: move |event| container_ref.onmounted(event),
onmousedown: move |_| {
spring_ref.animate([size as _, 1.], duration);
is_pressed.set(true)
},
onmounted: move |event| ripple.container_ref.onmounted(event),
onmousedown: move |_| ripple.onmousedown(),
onmouseup: move |event| {
if **is_pressed {
spring_ref.queue([size as _, 0.], duration);
spring_ref.queue([0., 0.], Duration::ZERO);
onclick.call(event);
is_pressed.set(false)
}
},
onmouseleave: move |_| {
if **is_pressed {
spring_ref.animate([0., 0.], duration);
is_pressed.set(false)
if ripple.onmouseup() {
onclick.call(event)
}
},
div { onmounted: move |event| animated_ref.onmounted(event) }
onmouseleave: move |_| ripple.onmouseleave(),
div { onmounted: move |event| ripple.animated_ref.onmounted(event) }
div { position: "relative", z_index: 9, user_select: "none", webkit_user_select: "none", children }
}
)
Expand Down
77 changes: 77 additions & 0 deletions src/use_ripple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use dioxus::prelude::*;
use dioxus_resize_observer::use_size;
use dioxus_spring::{use_animated, use_spring_signal, UseSpringSignal};
use dioxus_use_mounted::{use_mounted, UseMounted};
use std::time::Duration;

/// Hook to create a ripple from a container and animated component.
pub fn use_ripple<T>(cx: Scope<T>, duration: Duration) -> UseRipple {
let is_pressed = use_state(cx, || false);

let container_ref = use_mounted(cx);
let content_rect = use_size(cx, container_ref);
let size = content_rect.width().max(content_rect.height()) * 1.2;

let (spring_ref, value_ref) = use_spring_signal(cx, [0f32; 2]);
let animated_ref = use_mounted(cx);

use_animated(cx, animated_ref, value_ref, |[size, opacity]| {
format!(
r"
width: {size}px;
height: {size}px;
opacity: {opacity};
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: rgba(150, 150, 150, 0.5);
"
)
});

UseRipple {
spring_ref,
size,
is_pressed,
duration,
container_ref,
animated_ref,
}
}

#[derive(Clone, Copy)]
pub struct UseRipple<'a> {
pub spring_ref: UseSpringSignal<[f32; 2]>,
pub size: f64,
pub is_pressed: &'a UseState<bool>,
pub duration: Duration,
pub container_ref: UseMounted,
pub animated_ref: UseMounted,
}

impl UseRipple<'_> {
pub fn onmousedown(&self) {
self.spring_ref.animate([self.size as _, 1.], self.duration);
self.is_pressed.set(true)
}

pub fn onmouseup(&self) -> bool {
if **self.is_pressed {
self.spring_ref.queue([self.size as _, 0.], self.duration);
self.spring_ref.queue([0., 0.], Duration::ZERO);
self.is_pressed.set(false);
true
} else {
false
}
}

pub fn onmouseleave(&self) {
if **self.is_pressed {
self.spring_ref.animate([0., 0.], self.duration);
self.is_pressed.set(false)
}
}
}

0 comments on commit 9628d36

Please sign in to comment.