import { cva } from "class-variance-authority"; import * as React from "react"; import { useState } from "react"; import { Avatar, Button, ScrollArea, Separator } from "@sparkle/components"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@sparkle/components/Dialog"; import { ChevronLeftIcon, ChevronRightIcon } from "@sparkle/icons/app"; import { cn } from "@sparkle/lib/utils"; const multiPageDialogLayoutVariants = cva( cn("s-flex s-flex-col s-h-full s-overflow-hidden") ); interface MultiPageDialogPage { id: string; title: string; description?: string; icon?: React.ComponentType; content: React.ReactNode; fixedContent?: React.ReactNode; } const MultiPageDialogRoot = Dialog; const MultiPageDialogTrigger = DialogTrigger; const MultiPageDialogClose = DialogClose; interface MultiPageDialogFooterProps extends React.HTMLAttributes { addTopSeparator: boolean; leftButton?: React.ComponentProps; centerButton?: React.ComponentProps; rightButton?: React.ComponentProps; } const MultiPageDialogFooter = ({ className, addTopSeparator, children, leftButton, centerButton, rightButton, ...props }: MultiPageDialogFooterProps) => { const content = (
{children}
{leftButton &&
{centerButton &&
); return addTopSeparator ? ( <> {content} ) : ( <>{content} ); }; MultiPageDialogFooter.displayName = "MultiPageDialogFooter"; interface MultiPageDialogProps { pages: MultiPageDialogPage[]; currentPageId: string; onPageChange: (pageId: string) => void; size?: React.ComponentProps["size"]; height?: React.ComponentProps["height"]; trapFocusScope?: boolean; isAlertDialog?: boolean; preventAutoFocusOnClose?: boolean; showNavigation?: boolean; showHeaderNavigation?: boolean; className?: string; disableNext?: boolean; leftButton?: React.ComponentProps; centerButton?: React.ComponentProps; rightButton?: React.ComponentProps; footerContent?: React.ReactNode; addFooterSeparator?: boolean; hideCloseButton?: boolean; } interface MultiPageDialogContentProps extends MultiPageDialogProps { children?: never; } const MultiPageDialogContent = React.forwardRef< React.ElementRef, MultiPageDialogContentProps >( ( { pages, currentPageId, onPageChange, size = "md", height, trapFocusScope, isAlertDialog, preventAutoFocusOnClose, showNavigation = true, showHeaderNavigation = true, className, disableNext = false, addFooterSeparator = false, leftButton, centerButton, rightButton, footerContent, hideCloseButton, ...props }, ref ) => { const currentPageIndex = pages.findIndex( (page) => page.id === currentPageId ); const currentPage = pages[currentPageIndex]; const [isTransitioning, setIsTransitioning] = useState(false); const [transitionDirection, setTransitionDirection] = useState< "next" | "prev" >("next"); const handlePrevious = ( e: React.MouseEvent ) => { e.preventDefault(); if (currentPageIndex > 0 && !isTransitioning) { setTransitionDirection("prev"); setIsTransitioning(true); setTimeout(() => { onPageChange(pages[currentPageIndex - 1].id); setTimeout(() => setIsTransitioning(false), 50); }, 150); } }; const handleNext = (e: React.MouseEvent) => { e.preventDefault(); if (currentPageIndex < pages.length - 1 && !isTransitioning) { setTransitionDirection("next"); setIsTransitioning(true); setTimeout(() => { onPageChange(pages[currentPageIndex + 1].id); setTimeout(() => setIsTransitioning(false), 50); }, 150); } }; if (!currentPage) { console.warn(`Page with id "${currentPageId}" not found`); return null; } const hasPrevious = currentPageIndex > 0; const hasNext = currentPageIndex < pages.length - 1; const nextButtonDisabled = disableNext || !hasNext || isTransitioning; const prevButtonDisabled = !hasPrevious || isTransitioning; return (
{showNavigation && showHeaderNavigation && (
)}
) : undefined } > {currentPage.title} {currentPage.description && ( {currentPage.description} )}
{showNavigation && pages.length > 1 && (
{currentPageIndex + 1}/{pages.length}
)}
{currentPage.fixedContent && ( <>
{currentPage.fixedContent}
)}
{currentPage.content}
{footerContent}
); } ); MultiPageDialogContent.displayName = "MultiPageDialogContent"; export { MultiPageDialogRoot as MultiPageDialog, MultiPageDialogClose, MultiPageDialogContent, MultiPageDialogFooter, type MultiPageDialogFooterProps, type MultiPageDialogPage, type MultiPageDialogProps, MultiPageDialogTrigger, };