diff --git a/src/components/auth/login/LoginForm.tsx b/src/components/auth/login/LoginForm.tsx index 286f994..09099c6 100644 --- a/src/components/auth/login/LoginForm.tsx +++ b/src/components/auth/login/LoginForm.tsx @@ -1,5 +1,6 @@ "use client"; +import { useFadeSlideInOnMount } from "@/hooks/useMotionPresets"; import { cn } from "@/lib/utils"; import { Button } from "@/shared/button"; import { Icon } from "@/shared/Icon"; @@ -44,11 +45,14 @@ export function LoginForm() { setPassword(event.target.value); }; + const fadeClass = useFadeSlideInOnMount("up"); + return (
{ + const timer = window.setTimeout(() => { + setIsVisible(true); + }, 0); + + return () => window.clearTimeout(timer); + }, []); + + const baseTransition = durationClass ?? "transition-all duration-1000 ease-out"; + + const hiddenByDirection: Record = { + up: distanceClass ? `opacity-0 ${distanceClass}` : "opacity-0 translate-y-4", + down: distanceClass ? `opacity-0 ${distanceClass}` : "opacity-0 -translate-y-4", + left: distanceClass ? `opacity-0 ${distanceClass}` : "opacity-0 translate-x-4", + right: distanceClass ? `opacity-0 ${distanceClass}` : "opacity-0 -translate-x-4", + }; + + const visibleClass = "opacity-100 translate-x-0 translate-y-0"; + + const stateClass = isVisible ? visibleClass : hiddenByDirection[direction]; + + return `${baseTransition} ${stateClass}`; +} + +export function useStepSlideOnMount( + from: "left" | "right" = "right", + options: FadeSlideOptions = {}, +): string { + const { distanceClass, durationClass } = options; + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const timer = window.setTimeout(() => { + setIsVisible(true); + }, 0); + + return () => window.clearTimeout(timer); + }, []); + + const baseTransition = durationClass ?? "transition-all duration-300 ease-out"; + + const hidden = + from === "right" ? (distanceClass ?? "translate-x-4") : (distanceClass ?? "-translate-x-4"); + + const hiddenClass = `opacity-0 ${hidden}`; + const visibleClass = "opacity-100 translate-x-0"; + + const stateClass = isVisible ? visibleClass : hiddenClass; + + return `${baseTransition} ${stateClass}`; +} diff --git a/src/types/motion.ts b/src/types/motion.ts new file mode 100644 index 0000000..690ad7e --- /dev/null +++ b/src/types/motion.ts @@ -0,0 +1,8 @@ +export type MotionDirection = "up" | "down" | "left" | "right"; + +/** Tailwind 기반 페이드+슬라이드 옵션 */ +export interface FadeSlideOptions { + distanceClass?: string; + + durationClass?: string; +}