-
-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ripple effect #107
Conversation
Thanks for the contribution. However... (Also, ideally, each component would need less modification and events, and could just have a ripple plopped inside of it. Eg the ripple attaches to the parent element, like |
for your first point, yeah 1000% my bad, should've remembered. google's official implementation of m3 on the web doesn't even do this yet so i guess we'd be trailblazers haha for your second point however there isn't all that much modification outside of what is required. im just exporting a ripple function from the ripple component which handles all the heavy lifting; all other code modifications are to allow an element to call that function (i assume you're looking at the tab code?) |
I'm pretty sure
Right, but the modification can still be reduced. Auto-attaching to the parent would simplify the logic and reduce the scope of this PR. |
i'll see what i can do, but i'm gonna try and improve the visuals first ^^' |
@KTibow made the effect more accurate using svg noise and a mask. i'll clean up the code next :3 |
code's cleaned up. unfortunately can't send a sample video since the noise gets washed away in compression artifacts, but i think it looks pretty accurate |
apologies for all the new commits; i've gotten feedback from various android users on how the effect could be improved. |
I appreciate the work, but I need to make this closer to the original (possibly also reducing complexity, eg having 40 svgs on a page seems bad for perf) before it's merged. Unless you want to take up initiative, I'll try to update it to be closer later today. |
the original provided is inaccurate to the current state of material you, afaik (though this has only something i've been told, so i wouldn't know.) regarding performance issues, a simple way to fix this would be using #each instead of cloning an already-existing element. i could implement this now if you want? |
Right, but I'll still need to make this
Like the Android version does: What are the things you had to change in your ripple make it more accurate to Material 3? |
the svg provides a white noise effect, which is standard on androids implementation of material you. unless you want to embed a very large image into the library (since the noise needs to be masked, not scaled), an svg is the best way to approach this. that being said, my implementation of the ripple isn't entirely accurate... |
@KTibow i've fixed the checks and improved the ripple effect some more. i would argue its pretty close to perfect now. |
Cool. I'm working on a simpler ripple, here's what I have so far. <script lang="ts">
import { onMount } from "svelte";
let rippleEl: HTMLDivElement;
let rippleContainer: HTMLDivElement;
const ripple = async (e: MouseEvent) => {
const bounds = rippleContainer.getBoundingClientRect();
const initialSize = Math.max(bounds.width, bounds.height) * 0.2;
const diagonalSize = Math.hypot(bounds.width, bounds.height) * 2;
const maxSize = diagonalSize * 1.2;
rippleEl.style.left = `${e.clientX - bounds.left}px`;
rippleEl.style.top = `${e.clientY - bounds.top}px`;
rippleEl.style.width = `${maxSize}px`;
rippleEl.style.height = `${maxSize}px`;
rippleEl.classList.add("active");
rippleEl.animate(
{
scale: [initialSize / maxSize, 1],
},
{ easing: "cubic-bezier(0.2, 0, 0, 1)", duration: 450 },
);
const stop = () => {
rippleEl.classList.remove("active");
window.removeEventListener("mouseup", stop);
};
window.addEventListener("mouseup", stop);
};
onMount(() => {
rippleContainer.parentElement?.addEventListener("mousedown", ripple);
return () => {
rippleContainer.parentElement?.removeEventListener("mousedown", ripple);
};
});
</script>
<div class="rippleContainer" bind:this={rippleContainer}>
<div
style="background: radial-gradient(closest-side, currentColor max(100% - 300px, 65%), transparent 100%);"
bind:this={rippleEl}
class="ripple"
/>
</div>
<style>
.rippleContainer {
position: absolute;
inset: 0;
border-radius: inherit;
overflow: hidden;
}
.ripple {
border-radius: 50%;
position: absolute;
pointer-events: none;
overflow: hidden;
width: 100%;
height: 100%;
translate: -50% -50%;
opacity: 0;
transition: opacity 375ms linear;
}
.ripple:global(.active) {
opacity: 0.12;
transition-duration: 100ms;
}
</style> |
this works, but it doesn't have noise and it doesn't handle multiple clicks within a short timespan well |
i understand that, but i really need to keep bundle sizes down, and i would rather just have something simple that looks like material web. noise is a subtle detail (heck, i'd go as far as to say it's only required on oled screens) and i can easily handle multiple clicks. aside from complexity, the other thing i worry about is that right now there's two animations, one from css and one from the ripple. ideally the ripple can handle all of the animations, including hover, like material web does it. it would be progressively enhanced, from css to js. idk. i kinda feel like i might need dependency injection somewhere in this which would further complicate things, and ideally i can implement this relatively simply. |
Some other problems:
|
right now, material web components does not implement the noise. if you'd rather be ahead of the curve, you could merge my fix. but honestly, your one looks fine too. |
anything on this? it doesnt necessarily need to be my ripple but i think this is seriously holding back the project, the ripple on click is a huge part of material's design language |
yeah i honestly don't know why i haven't been working on this. i'm going to see if i can do this (in the subjectively most "right" way) by making a single component that handles hover as well as click states. |
@not-nullptr https://github.com/KTibow/m3-svelte/tree/ripples how does this look |
feels too slow at the beginning (+ is the hero supposed to have a ripple? lol) |
yeah just upped the speed to make it feel more functional |
seems great now |
this PR adds an albeit rudimentary ripple effect to most clickable components. there's no clear consensus on how ripple should look in m3 just yet so this currently replicates a version of what's seen on the m3 website, except slightly slower and with a lighter colour to improve accessibility.