UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

316 lines (313 loc) 10.9 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { forwardRef, useState, useCallback, useEffect } from 'react'; import { GlassButton } from '../../button/GlassButton.js'; import '../../button/GlassFab.js'; import '../../button/GlassMagneticButton.js'; import { cn } from '../../../lib/utilsComprehensive.js'; import { GlassCard } from '../../card/GlassCard.js'; import { GlassFormBuilder } from '../../interactive/GlassFormBuilder.js'; import '../../layout/GlassBox.js'; import '../../layout/GlassContainer.js'; import '../../layout/GlassFlex.js'; import '../../layout/GlassGrid.js'; import '../../layout/GlassMasonry.js'; import '../../layout/GlassScrollArea.js'; import '../../layout/GlassSplitPane.js'; import { VStack, HStack } from '../../layout/GlassStack.js'; import '../../layout/OptimizedGlassContainer.js'; import '../../layout/Box.js'; import { GlassCore } from '../../../primitives/GlassCore.js'; import '../../../primitives/glass/GlassAdvanced.js'; import '../../../primitives/OptimizedGlassCore.js'; import '../../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../../primitives/MotionNative.js'; import { MotionFramer } from '../../../primitives/motion/MotionFramer.js'; import { GlassFormWizardSteps } from './GlassFormWizardSteps.js'; /** * GlassWizardTemplate component * Multi-step wizard template with advanced navigation and validation */ const GlassWizardTemplate = /*#__PURE__*/forwardRef(({ title, description, steps, currentStep = 0, values = {}, errors = {}, onStepChange, onSubmit, onCancel, onChange, onStepValidate, loading = false, allowDraft = false, onSaveDraft, autoSave = false, showStepIndicator = true, allowSkipping = false, layout = "default", submitText = "Submit", cancelText = "Cancel", nextText = "Next", previousText = "Previous", skipText = "Skip", finishText = "Finish", className, ...props }, ref) => { const [internalValues, setInternalValues] = useState(values); const [internalErrors, setInternalErrors] = useState(errors); const [stepValidation, setStepValidation] = useState({}); const [completedSteps, setCompletedSteps] = useState(new Set()); const totalSteps = steps?.length || 0; const currentStepData = steps?.[currentStep]; const isFirstStep = currentStep === 0; const isLastStep = currentStep === totalSteps - 1; // Handle value change const handleValueChange = useCallback(newValues => { setInternalValues(newValues); onChange?.(newValues); }, [onChange]); // Handle step validation const handleStepValidation = useCallback(async (stepIndex, stepValues) => { const step = steps?.[stepIndex]; let errors = {}; // Step-specific validation if (step.validation) { errors = await step.validation(stepValues); } // Custom validation handler if (onStepValidate) { const customErrors = await onStepValidate(stepIndex, stepValues); errors = { ...errors, ...customErrors }; } setInternalErrors(errors); const isValid = Object.keys(errors).length === 0; setStepValidation(prev => ({ ...prev, [stepIndex]: isValid })); return isValid; }, [steps, onStepValidate]); // Handle next step const handleNext = useCallback(async () => { if (isLastStep) return; const isValid = await handleStepValidation(currentStep, internalValues); if (isValid) { setCompletedSteps(prev => new Set([...prev, currentStep])); onStepChange?.(currentStep + 1); } }, [currentStep, isLastStep, handleStepValidation, internalValues, onStepChange]); // Handle previous step const handlePrevious = useCallback(() => { if (isFirstStep) return; onStepChange?.(currentStep - 1); }, [currentStep, isFirstStep, onStepChange]); // Handle skip step const handleSkip = useCallback(() => { if (isLastStep || !currentStepData.canSkip) return; onStepChange?.(currentStep + 1); }, [currentStep, isLastStep, currentStepData?.canSkip, onStepChange]); // Handle step click (direct navigation) const handleStepClick = useCallback(stepIndex => { // Only allow navigation to completed steps or the next step if (stepIndex <= currentStep || completedSteps.has(stepIndex - 1)) { onStepChange?.(stepIndex); } }, [currentStep, completedSteps, onStepChange]); // Handle form submission const handleSubmit = useCallback(async () => { const isValid = await handleStepValidation(currentStep, internalValues); if (isValid) { if (isLastStep) { await onSubmit?.(internalValues); } else { handleNext(); } } }, [currentStep, internalValues, isLastStep, handleStepValidation, onSubmit, handleNext]); // Handle draft save const handleSaveDraft = useCallback(() => { onSaveDraft?.(internalValues); }, [internalValues, onSaveDraft]); // Auto-save effect useEffect(() => { if (autoSave && onSaveDraft) { const timeoutId = setTimeout(() => { onSaveDraft(internalValues); }, 2000); return () => clearTimeout(timeoutId); } }, [internalValues, autoSave, onSaveDraft]); // Render wizard header const renderHeader = () => jsxs(VStack, { space: "md", children: [jsxs(VStack, { space: "sm", children: [jsx("h1", { className: 'glass-text-2xl font-bold text-primary', children: title }), description && jsx("p", { className: "glass-text-secondary", children: description })] }), showStepIndicator && jsx(GlassFormWizardSteps, { steps: steps, currentStep: currentStep, completedSteps: completedSteps, onStepClick: handleStepClick, layout: layout === "compact" ? "compact" : "default" })] }); // Render step content const renderStepContent = () => jsxs(VStack, { space: "lg", children: [jsxs(VStack, { space: "sm", children: [jsxs(HStack, { space: "sm", align: "center", children: [jsx("h2", { className: 'glass-text-xl font-semibold text-primary', children: currentStepData.title }), currentStepData.optional && jsx("span", { className: "glass-text-sm glass-text-secondary glass-surface-subtle glass-px-2 glass-py-1 glass-radius-md", children: "Optional" })] }), currentStepData.description && jsx("p", { className: "glass-text-secondary", children: currentStepData.description })] }), jsx("div", { className: "glass-flex-1", children: currentStepData.component ? currentStepData.component : jsx(GlassFormBuilder, { schema: currentStepData.schema || [], values: internalValues, errors: internalErrors, onChange: handleValueChange, onSubmit: handleSubmit, validateOnChange: true, autoSave: false, showProgress: false, submitText: "", showCancel: false }) })] }); // Render navigation buttons const renderNavigation = () => jsxs(HStack, { space: "sm", align: "center", justify: "between", children: [jsxs(HStack, { space: "sm", children: [onCancel && jsx(GlassButton, { variant: "ghost", onClick: onCancel, disabled: loading, children: cancelText }), allowDraft && jsx(GlassButton, { variant: "outline", onClick: handleSaveDraft, disabled: loading, children: "Save Draft" })] }), jsxs(HStack, { space: "sm", children: [!isFirstStep && jsx(GlassButton, { variant: "ghost", onClick: handlePrevious, disabled: loading, children: previousText }), allowSkipping && currentStepData.canSkip && !isLastStep && jsx(GlassButton, { variant: "outline", onClick: handleSkip, disabled: loading, children: skipText }), jsx(GlassButton, { variant: "default", onClick: handleSubmit, loading: loading, children: isLastStep ? finishText : nextText })] })] }); // Render layout const renderLayout = () => { const content = jsxs(VStack, { space: "lg", children: [renderStepContent(), renderNavigation()] }); switch (layout) { case "compact": return jsx("div", { "data-glass-component": true, className: 'max-w-2xl glass-mx-auto', children: jsx(GlassCard, { variant: "default", className: "glass-p-6", children: content }) }); case "sidebar": return jsxs("div", { className: "glass-grid glass-grid-cols-12 glass-gap-8", children: [jsx("div", { className: 'col-span-4', children: jsx(GlassCore, { className: 'glass-p-6 sticky top-8', children: jsxs(VStack, { space: "md", children: [jsx("h3", { className: 'font-semibold text-primary', children: "Steps" }), jsx(VStack, { space: "sm", children: steps.map((step, index) => jsxs(GlassButton, { onClick: e => handleStepClick(index), className: cn("text-left glass-p-3 glass-radius-lg transition-colors", index === currentStep ? "bg-primary/10 text-primary border border-primary/20" : completedSteps.has(index) ? "bg-success/10 text-success border border-success/20" : "glass-text-secondary hover:bg-muted/50"), disabled: index > currentStep && !completedSteps.has(index - 1), children: [jsx("div", { className: 'font-medium', children: step.title }), step.description && jsx("div", { className: 'glass-text-sm opacity-75 glass-mt-1', children: step.description })] }, step.id)) })] }) }) }), jsx("div", { className: 'col-span-8', children: jsx(GlassCard, { variant: "default", className: "glass-p-6", children: content }) })] }); default: return jsx(GlassCard, { variant: "default", className: "glass-p-6", children: content }); } }; return jsxs("div", { ref: ref, className: cn("w-full glass-auto-gap glass-auto-gap-3xl", className), ...props, children: [layout !== "sidebar" && renderHeader(), jsx(MotionFramer, { children: renderLayout() })] }); }); GlassWizardTemplate.displayName = "GlassWizardTemplate"; export { GlassWizardTemplate }; //# sourceMappingURL=GlassWizardTemplate.js.map