feat(ExpanableWrapper): add onResize prop and trigger it in ResizeObserver
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
Animated wrapper for content that can be expanded and collapsed.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { debounce } from '$shared/lib/utils';
|
||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
@@ -38,6 +39,10 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
* Optional badge to render
|
||||
*/
|
||||
badge?: Snippet<[{ expanded?: boolean; disabled?: boolean }]>;
|
||||
/**
|
||||
* Callback for when the element's size changes
|
||||
*/
|
||||
onResize?: (rect: DOMRectReadOnly) => void;
|
||||
/**
|
||||
* Rotation animation direction
|
||||
* @default 'clockwise'
|
||||
@@ -56,6 +61,7 @@ let {
|
||||
visibleContent,
|
||||
hiddenContent,
|
||||
badge,
|
||||
onResize,
|
||||
rotation = 'clockwise',
|
||||
class: className = '',
|
||||
containerClassName = '',
|
||||
@@ -64,7 +70,7 @@ let {
|
||||
|
||||
let timeoutId = $state<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
export const xSpring = new Spring(0, {
|
||||
const xSpring = new Spring(0, {
|
||||
stiffness: 0.14, // Lower is slower
|
||||
damping: 0.5, // Settle
|
||||
});
|
||||
@@ -79,7 +85,7 @@ const scaleSpring = new Spring(1, {
|
||||
damping: 0.65,
|
||||
});
|
||||
|
||||
export const rotateSpring = new Spring(0, {
|
||||
const rotateSpring = new Spring(0, {
|
||||
stiffness: 0.12,
|
||||
damping: 0.55,
|
||||
});
|
||||
@@ -107,6 +113,9 @@ function handleKeyDown(e: KeyboardEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
// Create debounced recize callback
|
||||
const debouncedResize = debounce((entry: ResizeObserverEntry) => onResize?.(entry.contentRect), 50);
|
||||
|
||||
// Elevation and scale on activation
|
||||
$effect(() => {
|
||||
if (expanded && !disabled) {
|
||||
@@ -149,6 +158,21 @@ $effect(() => {
|
||||
expanded = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Use an effect to watch the element's actual physical size
|
||||
$effect(() => {
|
||||
if (!element) return;
|
||||
|
||||
const observer = new ResizeObserver(entries => {
|
||||
const entry = entries[0];
|
||||
if (entry) {
|
||||
debouncedResize(entry);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(element);
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -158,7 +182,7 @@ $effect(() => {
|
||||
role="button"
|
||||
tabindex={0}
|
||||
class={cn(
|
||||
'will-change-transform duration-300',
|
||||
'will-change-[transform, width, height] duration-300',
|
||||
disabled ? 'pointer-events-none' : 'pointer-events-auto',
|
||||
className,
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user