Skip to content
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

Controlled usage break animations #52

Open
ciaoben opened this issue Feb 12, 2024 · 13 comments
Open

Controlled usage break animations #52

ciaoben opened this issue Feb 12, 2024 · 13 comments

Comments

@ciaoben
Copy link

ciaoben commented Feb 12, 2024

Describe the bug

I noticed that close animation is broken when using the bind:open prop.

Reproduction

https://stackblitz.com/edit/vaul-svelte-scaled-z2k92v?file=src%2Froutes%2F%2Bpage.svelte

Logs

No response

System Info

Every browser

Severity

annoyance

@huntabyte
Copy link
Owner

I've spent the past couple of hours trying to come up with a clean solution for this with no luck so far.

The tricky part is we have a few different pieces at play here, one being the underlying Dialog's open state, our true "isOpen" state (which changes once the animation completes), and then also the user's bind:open to the Drawer.Root.

I plan to keep experimenting with a way to work around this but if anyone else wants to take a look I'm open to ideas!

@huntabyte
Copy link
Owner

If this is something you all desperately need, in the meantime I can expose the closeDrawer() function as a prop so you could do something like:

<script lang="ts">
	let closeDrawer: CloseDrawer;
</script>

<Drawer.Root bind:closeDrawer>

</Drawer.Root>

<button on:click={() => closeDrawer()>Programatic close</button>

Let me know if this would work. I feel I'm getting close to a solution though.

@MentalGear
Copy link

MentalGear commented Feb 29, 2024

Thanks for looking into this. The mentioned workaround is not working for me on the latest Drawer update.

ModalBottomDrawer.svelte:66 Uncaught TypeError: $.get(...) is not a function
    at HTMLButtonElement.click (ModalBottomDrawer.svelte:66:36)
    at HTMLButtonElement.bubble_event (chunk-6IUIVARJ.js?v=ff411993:1472:8)
    at HTMLButtonElement.click (button.svelte:20:17)
    at HTMLButtonElement.bubble_event (chunk-6IUIVARJ.js?v=ff411993:1472:8)
    at HTMLButtonElement.<anonymous> (bits-ui.js?v=ff411993:13667:24)
    at HTMLButtonElement.target_handler (chunk-H4AWZ5LT.js?v=ff411993:1847:22)
Screenshot 2024-02-29 at 14 33 29

@julien-blanchon
Copy link

julien-blanchon commented Mar 7, 2024

I'm also struggling with that

@Wizzel1
Copy link

Wizzel1 commented May 10, 2024

If this is something you all desperately need, in the meantime I can expose the closeDrawer() function as a prop so you could do something like:

<script lang="ts">
	let closeDrawer: CloseDrawer;
</script>

<Drawer.Root bind:closeDrawer>

</Drawer.Root>

<button on:click={() => closeDrawer()>Programatic close</button>

Let me know if this would work. I feel I'm getting close to a solution though.

I'd need that too

@pixellush
Copy link

I've spent the past couple of hours trying to come up with a clean solution for this with no luck so far.

The tricky part is we have a few different pieces at play here, one being the underlying Dialog's open state, our true "isOpen" state (which changes once the animation completes), and then also the user's bind:open to the Drawer.Root.

I plan to keep experimenting with a way to work around this but if anyone else wants to take a look I'm open to ideas!

Would it not work to replace bind:open with open={$isOpen} in root.svelte?
That way the underlying bits-ui Dialog only responds to isOpen changes, our true open/close state.
And we still have open exposed as a prop, which already triggers openDrawer & closeDrawer.

Trying this worked for me... mostly:

  • The overlay's style gets added properly and fades.
  • But the content's style does not, unless I remove style={$getContentStyle(style)} from content.svelte.

Just some findings that I hope can help.

@shajidhasan
Copy link

Any update on this?

@Krulknul
Copy link

Krulknul commented Aug 18, 2024

I was running into this from shadcdn-svelte, and I couldn't get that workaround to work because I believe the closeDrawer prop isn't exposed there.

Instead I found the following workaround:

<script>
let dialogTrigger;
</script>

<button on:click={() => {dialogTrigger.click()}}>close</button

<Drawer.Root bind:open={dialogOpen}>
    <Drawer.Close>
        <div bind:this={dialogTrigger}></div>
    </Drawer.Close>
</Drawer.Root>

@MitchMigala
Copy link

@huntabyte Great work porting this all to Svelte. Keep carrying the Svelte torch man. I had to get back to making money and stop making videos on my Consulting Ninja channel. Super busy with work now, but a quick fix for anyone that just needs this to look like there isn't a bug....

<script lang="ts">
let expanded: boolean = false;
let delayClose: boolean = false;

// Reactive Statement to actually set the drawer closed
$: {
  if (delayClose) {
    setTimeout(() => {
      expanded = false;
      delayClose = false;
    }, 300); // <--- Adjust this also as needed. I feel like this looks good. The overlay disappears just as it is reach bottom
  }
}
</script>

<button on:click={() => expanded = !expanded}>Open Drawer</button>

<Drawer.Root bind:open={expanded}>
  <!-- I like my drawers to close a bit faster than they open so I purposely set duration shorter here -->
  <Drawer.Content class="transition-all duration-200 ease-in-out {delayClose ? '!transform translate-y-full' : ''}">
    <!-- I am performing an api call when a user chooses something inside of a scroll area in the drawer , but you can put this anywhere on the page you need to initiate the the close -->
    <button
      on:click={() => {
        // Inline for simplicity, but this or in other button click functions works of course
        loading = true;
        // Whatever else you need to do wrapped in error handling 
        delayClose = true;
      }}
    >
      I am an option in giant list of options for the user
    </button>
  </Drawer.Content>
</Drawer.Root>

@tomekrozalski
Copy link

tomekrozalski commented Aug 22, 2024

My workaround is to add fade to Drawer.Content:

<script>
  import { fade } from 'svelte/transition';
  export let drawerOpen = false;
</script>

<button type="button" on:click={() => { drawerOpen = !drawerOpen;}}>Toggle</button>

<Drawer.Root bind:open={drawerOpen} direction="right">
  <Drawer.Overlay />
  <Drawer.Content transition={fade}>
...

My blind idea was that it could force transition when we close drawer. And it works for me.

On the other hand, your workaround is better @Krulknul 🙏

@AleksNankiewicz
Copy link

How to make it work in react?

@VityaSchel
Copy link

I was running into this from shadcdn-svelte, and I couldn't get that workaround to work because I believe the closeDrawer prop isn't exposed there.

Instead I found the following workaround:

<script>
let dialogTrigger;
</script>

<button on:click={() => {dialogTrigger.click()}}>close</button

<Drawer.Root bind:open={dialogOpen}>
    <Drawer.Close>
        <div bind:this={dialogTrigger}></div>
    </Drawer.Close>
</Drawer.Root>

This causes each unmounted portal to have some certain height depending on line height. In my case this solution was adding 24 px in bottom of the page even though element with data-melt-dialog-portalled had no specified height and button inside it had no content.
Passing asChild to Drawer.close effectively removes this element and does not allow to click it programmatically.

The solution: add display: none to Drawer.close:

<Drawer.Close class="hidden"><div bind:this={dialogCloseTrigger}></div></Drawer.Close>

@OctupusPrime
Copy link

OctupusPrime commented Nov 13, 2024

I improved workaround of @tomekrozalski, so it will not have fade effect

<script lang="ts">
    function fixTransition(node: Element) {
        getComputedStyle(node).height;
        
        return {
	        delay: 0,
	        duration: 0,
	        easing: (x: number) => x
        };
    }
</script>

...
<Drawer.Content transition={fixTransition}>
...

For some reason calling svelte inner fn getComputedStyle with css param fixes transition

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests