svecosystem / paneforge

Resizable pane components for Svelte.
https://paneforge.com
MIT License
370 stars 3 forks source link

Add option to animate expanding/collapsing #25

Open mhkeller opened 4 months ago

mhkeller commented 4 months ago

Describe the feature in detail (code, mocks, or screenshots encouraged)

It would be nice if you could define a tween or easing function to animate the opening and closing of a pane.

What type of pull request would this be?

New Feature

Provide relevant links or additional information.

No response

huntabyte commented 3 months ago

I feel like this should be possible using CSS alongside the data-* attributes. What do you see this looking like?

mhkeller commented 3 months ago

I was thinking something like paneOne.collapse({ duration: 200 });. If it's already possible then that's great. I was trying to add a CSS transition in devtools to the example on the site but the inline styles get overwritten on collapse/expand and adding a new class seemed to disrupt other things and also didn't work.

mhkeller commented 3 months ago

@huntabyte If you have the time to create a barebones REPL example with how you were thinking it could work with CSS that would be great!

Marceltbn commented 2 months ago

Using a css transition-duration on the Pane while collapsing works well, until u have more than 2 Panes. Then the others start mirroring the movement until they fall back into their original position. I couldn't implement it in the source code but you can hack it with some js.

    let paneOne: PaneAPI;
    let paneThree: PaneAPI;
    let ogSize: number;  // move to cookies or local storage for each pane

    function togglePanes(paneId: number, duration: number = 500) {
        let pane: PaneAPI = paneId === 1 ? paneOne : paneThree;
        let startTime: number | null = null;
        let isCollapesd = pane.isCollapsed();
        let targetSize = isCollapesd ? ogSize : 0;

        if (!isCollapesd) {
            ogSize = pane.getSize();
        }

        let initialSize = pane.getSize();
        let sizeChange = targetSize - initialSize;

        function animate(timestamp: number) {
            if (!startTime) startTime = timestamp;
            let elapsed = timestamp - startTime;
            let progress = Math.min(elapsed / duration, 1);
            let easedProgress = sineInOut(progress);
            let currentSize = initialSize + sizeChange * easedProgress;

            pane.resize(currentSize);

            if (progress < 1) {
                requestAnimationFrame(animate);
            } else {
                if (isCollapesd) {
                    pane.expand();
                } else {
                    pane.collapse();
                }
            }
        }
        requestAnimationFrame(animate);
    }
mhkeller commented 1 week ago

One solution might be to take the delta value calculated here and instead of setting the layout to the new value, call everything between these lines for each pixel inside of a requestAnimationFrame or something. I haven't tried any of this but it seems like the place in the code to adjust.