import { useReducedMotion } from "motion/react"; import { Children, cloneElement, forwardRef, isValidElement, useEffect, useState, type ComponentPropsWithoutRef, type CSSProperties } from "react"; import { emptyStateActionsVariants, emptyStateDescriptionVariants, emptyStateEyebrowVariants, emptyStateHeaderVariants, emptyStateMediaVariants, emptyStateTitleVariants, emptyStateVariants } from "./empty-state.variants"; import { cn } from "../lib/cn"; import type { VariantProps } from "../lib/cva"; import { createDataAttributes, createSlot } from "../lib/contracts"; function getIsStaticMotion() { if (typeof document === "undefined") { return false; } return document.documentElement.dataset.motion === "static"; } function useMotionDisabled() { const prefersReducedMotion = useReducedMotion(); const [isStaticMotion, setIsStaticMotion] = useState(getIsStaticMotion); useEffect(() => { if (typeof document === "undefined") { return; } const syncMotionMode = () => { setIsStaticMotion(getIsStaticMotion()); }; syncMotionMode(); const observer = new MutationObserver(syncMotionMode); observer.observe(document.documentElement, { attributeFilter: ["data-motion"] }); return () => observer.disconnect(); }, []); return prefersReducedMotion || isStaticMotion; } export type EmptyStateProps = ComponentPropsWithoutRef<"div"> & VariantProps; export const EmptyState = forwardRef(function EmptyState( { align, className, layout, tone, ...props }, ref ) { return (
); }); export type EmptyStateMediaProps = ComponentPropsWithoutRef<"div"> & VariantProps; export const EmptyStateMedia = forwardRef( function EmptyStateMedia({ className, size, ...props }, ref) { const disableMotion = useMotionDisabled(); const ambientMotionClassName = disableMotion || size === "compact" ? undefined : size === "hero" ? "motion-float-delayed will-change-transform" : "motion-breathe will-change-transform"; return (
); } ); export type EmptyStateHeaderProps = ComponentPropsWithoutRef<"div"> & VariantProps; export const EmptyStateHeader = forwardRef( function EmptyStateHeader({ align, className, ...props }, ref) { return (
); } ); export type EmptyStateEyebrowProps = ComponentPropsWithoutRef<"p">; export const EmptyStateEyebrow = forwardRef( function EmptyStateEyebrow({ className, ...props }, ref) { return (

); } ); export type EmptyStateTitleProps = ComponentPropsWithoutRef<"h3">; export const EmptyStateTitle = forwardRef( function EmptyStateTitle({ className, ...props }, ref) { return (

); } ); export type EmptyStateDescriptionProps = ComponentPropsWithoutRef<"p">; export const EmptyStateDescription = forwardRef< HTMLParagraphElement, EmptyStateDescriptionProps >(function EmptyStateDescription({ className, ...props }, ref) { return (

); }); export type EmptyStateActionsProps = ComponentPropsWithoutRef<"div"> & VariantProps; export const EmptyStateActions = forwardRef( function EmptyStateActions({ children, className, layout, ...props }, ref) { const disableMotion = useMotionDisabled(); const animatedChildren = disableMotion ? children : Children.map(children, (child, index) => { if ( !isValidElement<{ className?: string; style?: CSSProperties }>(child) || typeof child.type === "symbol" ) { return child; } return cloneElement(child, { className: cn( "[animation:aiui-slide-up-sm_var(--dur-base)_var(--ease-emphasized)_both]", "will-change-transform", child.props.className ), style: { ...(child.props.style ?? {}), animationDelay: `${Math.min(index * 70, 140)}ms` } }); }); return (

{animatedChildren}
); } );