UNPKG

aura-glass

Version:

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

275 lines (272 loc) 8.83 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { forwardRef, useState } from 'react'; import '../../../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 { GlassFormBuilder } from '../../interactive/GlassFormBuilder.js'; import { GlassButton } from '../../button/GlassButton.js'; import { GlassProgress } from '../../data-display/GlassProgress.js'; import { PageHeader } from '../../layout/GlassAppShell.js'; import { VStack, HStack } from '../../layout/GlassStack.js'; import { GlassCard } from '../../card/GlassCard.js'; import { cn } from '../../../lib/utilsComprehensive.js'; /** * GlassFormTemplate component * Comprehensive form template with single-step and multi-step support */ const GlassFormTemplate = /*#__PURE__*/forwardRef(({ title, description, steps = [], schema = [], values = {}, errors = {}, multiStep = false, currentStep = 0, onStepChange, onSubmit, onCancel, onChange, onValidate, loading = false, allowDraft = false, onSaveDraft, layout = "default", sidebar, showProgress = true, autoSave = false, submitText = "Submit", cancelText = "Cancel", nextText = "Next", previousText = "Previous", className, ...props }, ref) => { const [internalValues, setInternalValues] = useState(values); const [internalErrors, setInternalErrors] = useState(errors); const [stepValidation, setStepValidation] = useState({}); const isMultiStep = multiStep && (steps?.length || 0) > 0; const totalSteps = isMultiStep ? steps?.length || 0 : 1; const currentStepData = isMultiStep ? steps[currentStep] : null; const currentSchema = isMultiStep ? currentStepData?.sections : schema; // Handle value change const handleValueChange = newValues => { setInternalValues(newValues); onChange?.(newValues); }; // Handle form validation const handleValidate = async stepValues => { let errors = {}; // Global validation if (onValidate) { errors = { ...errors, ...onValidate(stepValues) }; } // Step-specific validation if (currentStepData?.validation) { const stepErrors = await currentStepData.validation(stepValues); errors = { ...errors, ...stepErrors }; } setInternalErrors(errors); return errors; }; // Handle step navigation const handleNext = async () => { if (!isMultiStep || currentStep >= totalSteps - 1) return; const errors = await handleValidate(internalValues); const hasErrors = Object.keys(errors).length > 0; if (!hasErrors) { setStepValidation({ ...stepValidation, [currentStep]: true }); onStepChange?.(currentStep + 1); } }; const handlePrevious = () => { if (!isMultiStep || currentStep <= 0) return; onStepChange?.(currentStep - 1); }; // Handle form submission const handleSubmit = async formValues => { if (isMultiStep) { const errors = await handleValidate(formValues); const hasErrors = Object.keys(errors).length > 0; if (hasErrors) return; if (currentStep < totalSteps - 1) { handleNext(); return; } } await onSubmit?.(formValues); }; // Handle draft save const handleSaveDraft = () => { onSaveDraft?.(internalValues); }; // Calculate progress const getProgress = () => { if (!isMultiStep) return 100; return (currentStep + 1) / totalSteps * 100; }; // Render step indicator const renderStepIndicator = () => { if (!isMultiStep || !showProgress) return null; return jsxs(VStack, { "data-glass-component": true, space: "md", children: [jsxs(HStack, { space: "sm", align: "center", justify: "between", children: [jsxs("span", { className: 'glass-text-sm font-medium text-primary', children: ["Step ", currentStep + 1, " of ", totalSteps] }), jsxs("span", { className: "glass-text-sm glass-text-secondary", children: [Math.round(getProgress()), "% Complete"] })] }), jsx(GlassProgress, { value: getProgress(), size: "sm", variant: "default", showValue: false }), jsx("div", { className: "glass-flex glass-justify-between", children: steps.map((step, index) => jsxs("div", { className: cn("flex flex-col items-center glass-gap-2 cursor-pointer transition-opacity", index > currentStep && "opacity-50", index < currentStep && "opacity-75"), onClick: e => stepValidation[index] && onStepChange?.(index), children: [jsx("div", { className: cn("w-8 h-8 glass-radius-full flex items-center justify-center glass-text-sm font-medium", index === currentStep ? "bg-primary text-primary-foreground" : index < currentStep ? "bg-success text-success-foreground" : "bg-muted glass-text-secondary"), children: index < currentStep ? "✓" : index + 1 }), jsx("span", { className: 'glass-text-xs text-center max-w-16 truncate', children: step.title })] }, step.id)) })] }); }; // Render form actions const renderFormActions = () => 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: [isMultiStep && currentStep > 0 && jsx(GlassButton, { variant: "ghost", onClick: handlePrevious, disabled: loading, children: previousText }), jsx(GlassButton, { variant: "default", type: "submit", loading: loading, children: isMultiStep && currentStep < totalSteps - 1 ? nextText : submitText })] })] }); // Render form content const renderFormContent = () => jsxs(VStack, { space: "lg", children: [renderStepIndicator(), isMultiStep && currentStepData && jsxs(VStack, { space: "sm", children: [jsx("h2", { className: 'glass-text-xl font-semibold text-primary', children: currentStepData.title }), currentStepData.description && jsx("p", { className: "glass-text-secondary", children: currentStepData.description })] }), jsx("div", { className: "glass-flex-1", children: jsx(GlassFormBuilder, { schema: currentSchema || [], values: internalValues, errors: internalErrors, onChange: handleValueChange, onSubmit: handleSubmit, onValidate: onValidate, validateOnChange: true, autoSave: autoSave, showProgress: false, submitText: "", showCancel: false }) }), renderFormActions()] }); // Render layout const renderLayout = () => { switch (layout) { case "centered": return jsx("div", { className: 'max-w-2xl glass-mx-auto', children: jsx(GlassCard, { variant: "default", className: "glass-p-8", children: renderFormContent() }) }); case "sidebar": return jsxs("div", { className: "glass-grid glass-grid-cols-12 glass-gap-8", children: [jsx("div", { className: 'col-span-8', children: jsx(GlassCard, { variant: "default", className: "glass-p-6", children: renderFormContent() }) }), jsx("div", { className: 'col-span-4', children: sidebar })] }); default: return jsx(GlassCard, { variant: "default", className: "glass-p-6", children: renderFormContent() }); } }; return jsxs("div", { ref: ref, className: cn("w-full glass-auto-gap glass-auto-gap-3xl", className), ...props, children: [jsx(PageHeader, { title: title, description: description, variant: layout === "centered" ? "centered" : "default" }), jsx(MotionFramer, { preset: "fadeIn", children: renderLayout() })] }); }); GlassFormTemplate.displayName = "GlassFormTemplate"; export { GlassFormTemplate }; //# sourceMappingURL=GlassFormTemplate.js.map