Skip to content

Commit

Permalink
chore: improving the animations
Browse files Browse the repository at this point in the history
  • Loading branch information
macci001 committed Dec 31, 2024
1 parent 5530248 commit 6823ce5
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 45 deletions.
11 changes: 4 additions & 7 deletions packages/components/toast/src/toast-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,18 @@ interface ToastProviderProps {
| "center-top";
}

export const getToastQueue = (maxVisibleToasts: number) => {
export const getToastQueue = () => {
if (!globalToastQueue) {
globalToastQueue = new ToastQueue({
maxVisibleToasts,
maxVisibleToasts: Infinity,
});
}

return globalToastQueue;
};

export const ToastProvider = ({
maxVisibleToasts = 3,
position = "right-bottom",
}: ToastProviderProps) => {
const toastQueue = useToastQueue(getToastQueue(maxVisibleToasts));
export const ToastProvider = ({position = "right-bottom"}: ToastProviderProps) => {
const toastQueue = useToastQueue(getToastQueue());

if (toastQueue.visibleToasts.length == 0) {
return null;
Expand Down
13 changes: 4 additions & 9 deletions packages/components/toast/src/toast-region.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useRef} from "react";
import {useRef, useState} from "react";
import {useToastRegion, AriaToastRegionProps} from "@react-aria/toast";
import {QueuedToast, ToastState} from "@react-stately/toast";
import {createPortal} from "react-dom";
Expand Down Expand Up @@ -40,14 +40,7 @@ export function ToastRegion<T extends ToastProps>({
"center-top": "top-0 left-1/2 -translate-x-1/2",
};
const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"];

const toasts = document.querySelectorAll<HTMLElement>("[data-toast]");
let height = 0;

for (let i = toasts.length - 1; i >= 0; i--) {
toasts[i].style.setProperty(`--toast-gap`, `${height}px`);
height = height + toasts[i].offsetHeight;
}
const [heights, setHeights] = useState<number[]>([]);

return createPortal(
<div
Expand All @@ -62,9 +55,11 @@ export function ToastRegion<T extends ToastProps>({
state={toastQueue}
toast={toast}
{...toast.content}
heights={heights}
index={index}
isRegionHovered={isHovered}
position={position}
setHeights={setHeights}
total={toastQueue.visibleToasts.length}
/>
);
Expand Down
39 changes: 11 additions & 28 deletions packages/components/toast/src/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => {
getDescriptionProps,
getCloseButtonProps,
getIconProps,
liftHeight,
initialHeight,
frontHeight,
} = useToast({
...props,
ref,
Expand Down Expand Up @@ -109,31 +112,14 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => {
);

const positionStyles: Record<string, string> = {
"right-bottom": "bottom-0 right-0 max-auto w-max",
"right-bottom": "bottom-0 right-0 mx-auto w-max",
"left-bottom": "bottom-0 left-0 mx-auto w-max",
"center-bottom": "bottom-0 left-0 right-0 mx-auto w-max",
"right-top": "top-0 right-0 max-auto w-max",
"right-top": "top-0 right-0 mx-auto w-max",
"left-top": "top-0 left-0 mx-auto w-max",
"center-top": "top-0 left-0 right-0 mx-auto w-max",
};
const positionStyle = position ? positionStyles[position] : positionStyles["right-bottom"];
const multiplier = position.includes("top") ? -1 : 1;
let gap = 0;
let currentHeight = 0;

if (domRef.current) {
const styles = getComputedStyle(domRef.current);

gap = parseFloat(styles.getPropertyValue("--toast-gap")) || 0;
currentHeight = domRef.current.offsetHeight || 0;
}

const toasts = document.querySelectorAll<HTMLElement>("[data-toast]");
let height = 0;

if (toasts.length > 0) {
height = toasts[toasts.length - 1].offsetHeight;
}

return (
<>
Expand All @@ -143,20 +129,17 @@ const Toast = forwardRef<"div", ToastProps>((props, ref) => {
<AnimatePresence>
<motion.div
animate={{
opacity: 1,
y: isRegionHovered
? (-gap + 4 * (1 + index - total)) * multiplier
: total - 1 - index === 0
? 0
: (currentHeight * (1 - 0.1 * (total - 1 - index)) - height) * multiplier,
opacity: total - index - 1 <= 2 ? 1 : 0,
y: isRegionHovered ? liftHeight * -1 - 20 : -20 + (index + 1 - total) * 8,
scaleX: isRegionHovered ? 1 : 1 - (total - 1 - index) * 0.1,
height: isRegionHovered ? initialHeight : frontHeight,
}}
className={clsx("absolute", positionStyle)}
drag={position.includes("center") ? "y" : "x"}
dragConstraints={{left: 0, right: 0, top: 0, bottom: 0}}
exit={{opacity: 0, y: -100}}
initial={{opacity: 0, y: 50 * multiplier, scale: 1}}
transition={{duration: 0.5, ease: "easeOut"}}
exit={{opacity: 0, y: 100}}
initial={{opacity: 0, y: 40 * multiplier, scale: 1}}
transition={{duration: 0.3, ease: "easeOut"}}
variants={toastVariants}
onDragEnd={(_, info) => {
const offsetX = info.offset.x;
Expand Down
48 changes: 47 additions & 1 deletion packages/components/toast/src/use-toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import {toast as toastTheme} from "@nextui-org/theme";
import {ReactRef, useDOMRef} from "@nextui-org/react-utils";
import {clsx, dataAttr, isEmpty, objectToDeps} from "@nextui-org/shared-utils";
import {ReactNode, useCallback, useEffect, useMemo, useRef, useState} from "react";
import {ReactNode, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from "react";
import {useToast as useToastAria, AriaToastProps} from "@react-aria/toast";
import {mergeProps} from "@react-aria/utils";
import {QueuedToast, ToastState} from "@react-stately/toast";
Expand Down Expand Up @@ -93,6 +93,8 @@ export interface ToastProps extends ToastVariantProps {
interface Props<T> extends HTMLNextUIProps<"div">, ToastProps {
toast: QueuedToast<T>;
state: ToastState<T>;
heights: number[];
setHeights: (val: number[]) => void;
}

export type UseToastProps<T = ToastProps> = Props<T> &
Expand Down Expand Up @@ -170,6 +172,8 @@ export function useToast<T extends ToastProps>(originalProps: UseToastProps<T>)
state,
total = 1,
index = 0,
heights,
setHeights,
...otherProps
} = props;

Expand All @@ -184,6 +188,45 @@ export function useToast<T extends ToastProps>(originalProps: UseToastProps<T>)
domRef,
);

const [mounted, setMounted] = useState<boolean>(false);

useEffect(() => {
setMounted(true);
}, []);

const [initialHeight, setInitialHeight] = useState<number>(0);

useLayoutEffect(() => {
if (!domRef.current || !mounted) {
return;
}
const toastNode = domRef.current;
const originalHeight = toastNode.style.height;

toastNode.style.height = "auto";
const newHeight = toastNode.getBoundingClientRect().height;

toastNode.style.height = originalHeight;

setInitialHeight((prevHeight) => (prevHeight !== newHeight ? newHeight : prevHeight));
const updatedHeights = [...heights];

if (updatedHeights.length > index) {
updatedHeights[index] = newHeight;
} else {
updatedHeights.push(newHeight);
}
setHeights(updatedHeights);
}, [mounted, total, setHeights, index]);

let liftHeight = 4;

for (let idx = index + 1; idx < total; idx++) {
liftHeight += 4 + heights[idx];
}

const frontHeight = heights[heights.length - 1];

const slots = useMemo(
() =>
toastTheme({
Expand Down Expand Up @@ -286,6 +329,9 @@ export function useToast<T extends ToastProps>(originalProps: UseToastProps<T>)
endContent,
slots,
isRegionHovered,
liftHeight,
frontHeight,
initialHeight,
};
}

Expand Down

0 comments on commit 6823ce5

Please sign in to comment.