Skip to content

Commit

Permalink
feat: add exit animation to mobile dialog drawer (#1108)
Browse files Browse the repository at this point in the history
* feat: add react-transition-state hook to control transition states

* feat: use transitionGroup to handle exiting animation in dialog component

* feat: remove usage of the react-transition-group library

* feat: remove usage of the react-transition-group library

* feat: remove usage of the @types/react-transition-group library

* fix: fix lint changes to mockServiceWorker.js-

* fix: fix dismiss animation jank by using transition property on dialog backdrop

* fix: remove portal when slide down animation ends

---------

Co-authored-by: Michael Moldoveanu <[email protected]>
  • Loading branch information
iykazrji and moldy530 authored Nov 11, 2024
1 parent eae2877 commit afa37ea
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
43 changes: 39 additions & 4 deletions account-kit/react/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
"use client";

import { useCallback, useEffect, useState, type ReactNode } from "react";
import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
type ReactNode,
} from "react";
import { createPortal } from "react-dom";
import { RemoveScroll } from "react-remove-scroll";
import { FocusTrap } from "./focustrap.js";
Expand All @@ -20,10 +27,33 @@ type DialogProps = {
export const Dialog = ({ isOpen, onClose, children }: DialogProps) => {
const [isScrollLocked, setScrollLocked] = useState(false);

const [renderPortal, setRenderPortal] = useState(false);

const dialogCardRef = useRef<HTMLDivElement>(null);

const handleBackgroundClick = useCallback(() => {
onClose();
}, [onClose]);

useLayoutEffect(() => {
const dialogCard = dialogCardRef.current;

if (isOpen) {
setRenderPortal(true);
return;
}

const renderPortalHandler = () => {
setRenderPortal(false);
};

dialogCard?.addEventListener("animationend", renderPortalHandler);

return () => {
dialogCard?.removeEventListener("animationend", renderPortalHandler);
};
}, [isOpen]);

useEffect(() => {
const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape" && isOpen) {
Expand All @@ -40,19 +70,24 @@ export const Dialog = ({ isOpen, onClose, children }: DialogProps) => {
setScrollLocked(getComputedStyle(document.body).overflow !== "hidden");
}, []);

return isOpen
return renderPortal
? createPortal(
<RemoveScroll enabled={isScrollLocked}>
{/* Overlay */}
<div
aria-modal
role="dialog"
className="fixed inset-0 bg-black/80 flex items-end md:items-center justify-center z-[999999] animate-fade-in"
className={`fixed inset-0 bg-black/80 flex items-end md:items-center justify-center z-[999999] transition-opacity ${
isOpen ? "opacity-100" : "opacity-0 delay-75"
}`}
onClick={handleBackgroundClick}
>
<FocusTrap>
<div
className="animate-fade-in animate-slide-up max-md:w-screen md:max-w-sm"
ref={dialogCardRef}
className={`max-md:w-screen md:max-w-sm block ${
isOpen ? "animate-slide-up" : "animate-slide-down"
}`}
onClick={(event) => event.stopPropagation()}
>
{children}
Expand Down
26 changes: 24 additions & 2 deletions account-kit/react/src/tailwind/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,35 @@ export const accountKitUi: (
"100%": { opacity: "1" },
},
"slide-up": {
"0%": { transform: "translateY(100%)", opacity: "0" },
"100%": { transform: "translateY(0%)", opacity: "1" },
"0%": {
transform: "translateY(100%)",
opacity: "0",
},
"100%": {
transform: "translateY(0%)",
opacity: "1",
},
},
"fade-out": {
"0%": { opacity: "1" },
"100%": { opacity: "0" },
},
"slide-down": {
"0%": {
transform: "translateY(0%)",
opacity: "1",
},
"100%": {
transform: "translateY(100%)",
opacity: "0",
},
},
},
animation: {
"fade-in": "fade-in 150ms ease",
"slide-up": "slide-up 350ms cubic-bezier(.15,1.15,0.6,1.00)",
"fade-out": "fade-out 150ms ease",
"slide-down": "slide-down 350ms cubic-bezier(.15,1.15,0.6,1.00)",
},
},
},
Expand Down

0 comments on commit afa37ea

Please sign in to comment.