ecklf/tailwindcss-radix

Unmount Animations

pondorasti opened this issue ยท 5 comments

Radix supports leave animations by suspending unmount while your animation plays out, more info here.

While going over the source code, I've noticed how this plugin adds support for the closed state (radix-state-closed). However, I was not able to successfully animate the unmount phase using tailwind. Most if not all of the demo components have the same issue of being instantly unmounted without a smooth transition.

Is it possible with the current API to achieve this? Otherwise, is it feasible to implement support for it?

ecklf commented

I don't believe this is an issue with Tailwind. The Dialog example components use HeadlessUI Transitions which were missing Radix's forceMount prop (thanks for pointing that out). Can you provide a minimal reproduction?

This example seems to work fine for me:

tailwind.config.js

module.exports = {
  extend: {
    keyframes: {
      "fade-in": {
        from: {
          opacity: 0,
        },
        to: {
          opacity: 1,
        },
      },
      "fade-out": {
        from: {
          opacity: 1,
        },
        to: {
          opacity: 0,
        },
      },
    },
    animation: {
      "fade-in": "fade-in 300ms ease-out",
      "fade-out": "fade-out 200ms ease-in",
    },
  },
  variants: {
    extend: {},
  },
  plugins: [require("tailwindcss-radix")()],
};

DialogWithCSS.tsx

import * as DialogPrimitive from "@radix-ui/react-dialog";
import cx from "classnames";
import React from "react";

interface Props {}

const DialogWithCSS = (props: Props) => {
  return (
    <DialogPrimitive.Root>
      <DialogPrimitive.Trigger
        className={cx(
          "radix-state-open:bg-gray-100 dark:radix-state-open:bg-gray-900",
          "inline-flex justify-center px-4 py-2 text-sm font-medium rounded-md select-none",
          "bg-white text-gray-900 dark:text-gray-100 dark:bg-gray-800",
          "focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75"
        )}
      >
        Dialog
      </DialogPrimitive.Trigger>
      <DialogPrimitive.Overlay
        className={cx(
          "fixed inset-0 z-20 bg-black/50",
          "radix-state-open:animate-fade-in radix-state-closed:animate-fade-out"
        )}
      />
      <DialogPrimitive.Content>
        <DialogPrimitive.Close />
      </DialogPrimitive.Content>
    </DialogPrimitive.Root>
  );
};

export default DialogWithCSS;

@ecklf I'm sorry for the delay, I've got sidetracked with other things. In hindsight, I should have gave you a code example to make it more clear, my bad.

While working on snippets.alexandru.so, I've implemented a ContextMenu and Tooltip. For both of them, I've been unable to figure out unmount animation. As mentioned above, I've added custom keyframe animations to my tailwind.config.js and then tried binding them with radix-state-closed. You can check out my implementation for the ContextMenu. My project has been bootstrapped with Next.js so running locally just requires npm install && npm run dev.

Screen.Recording.2022-01-03.at.11.52.30.mov

This might be worth opening another issue, but I've also wasn't able to style disabled ContextMenu.Item. Providing an example for this edge case would be greatly appreciated!

ecklf commented

I've added custom keyframe animations to my tailwind.config.js and then tried binding them with radix-state-closed

The context menu content is wrapped in a conditional render which causes the component to unmount immediately L73.

This might be worth opening another issue, but I've also wasn't able to style disabled ContextMenu.Item. Providing an example for this edge case would be greatly appreciated!

Just published a new version that adds a radix-disabled variant with an example in the readme.

Thank you! You are right about the conditional render too, I was trying to figure out a way to programmatically dismiss Context Menus and didn't realize that ๐Ÿคฆโ€โ™‚๏ธ.