aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
244 lines (241 loc) • 9.88 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { Check, AlertCircle, Circle } from 'lucide-react';
import React 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';
/**
* GlassFormStepper component
* A visual stepper component for multi-step forms with glassmorphism design
*/
const GlassFormStepper = ({
steps,
currentStep = 0,
onStepClick,
orientation = "horizontal",
size = "md",
showNumbers = true,
showDescriptions = false,
allowClickCompleted = true,
showProgressLine = true,
className,
...props
}) => {
// Size configurations
const sizeConfigs = {
sm: {
stepSize: "w-8 h-8",
iconSize: "w-4 h-4",
fontSize: "glass-text-sm",
lineHeight: "h-px",
spacing: "glass-gap-4"
},
md: {
stepSize: "w-10 h-10",
iconSize: "w-5 h-5",
fontSize: "glass-text-base",
lineHeight: "h-0.5",
spacing: "glass-gap-6"
},
lg: {
stepSize: "w-12 h-12",
iconSize: "w-6 h-6",
fontSize: "glass-text-lg",
lineHeight: "h-1",
spacing: "gap-8"
}
};
const config = sizeConfigs[size];
// Get step state
const getStepState = (stepIndex, step) => {
if (step.disabled) return "disabled";
if (step.error) return "error";
if (step.completed) return "completed";
if (stepIndex === currentStep) return "active";
if (stepIndex < currentStep) return "completed";
return "pending";
};
// Get step styles based on state
const getStepStyles = state => {
switch (state) {
case "completed":
return {
circle: "bg-green-500 border-green-500 glass-text-primary",
icon: "glass-text-primary",
line: "bg-green-500",
text: "glass-text-primary"
};
case "active":
return {
circle: "bg-primary border-primary glass-text-primary",
icon: "glass-text-primary",
line: "bg-primary/50",
text: "glass-text-primary"
};
case "error":
return {
circle: "bg-red-500 border-red-500 glass-text-primary",
icon: "glass-text-primary",
line: "bg-red-500/50",
text: "text-red-300"
};
case "disabled":
return {
circle: "bg-white/10 border-white/30 glass-text-primary/50",
icon: "glass-text-primary/50",
line: "bg-white/30",
text: "glass-text-primary/50"
};
default:
return {
circle: "bg-white/10 border-white/30 glass-text-primary/60",
icon: "glass-text-primary/60",
line: "bg-white/30",
text: "glass-text-primary/60"
};
}
};
// Handle step click
const handleStepClick = (stepIndex, step) => {
const state = getStepState(stepIndex, step);
if (state === "disabled") return;
if (state === "pending" && !allowClickCompleted) return;
onStepClick?.(stepIndex);
};
// Render horizontal stepper
const renderHorizontalStepper = () => jsx("nav", {
"aria-label": "Form steps",
className: cn("flex items-center justify-center", config.spacing, className),
children: steps.map((step, index) => {
const state = getStepState(index, step);
const styles = getStepStyles(state);
const isLast = index === steps.length - 1;
return jsxs(React.Fragment, {
"data-glass-component": true,
children: [jsx("div", {
className: 'glass-flex glass-flex-col glass-items-center group',
children: jsxs(MotionFramer, {
preset: state === "active" ? "scaleIn" : "fadeIn",
className: 'glass-flex glass-flex-col glass-items-center cursor-pointer',
onClick: e => handleStepClick(index, step),
role: "button",
"aria-label": `Step ${index + 1}: ${step.title}${state === "completed" ? " (completed)" : state === "active" ? " (current)" : ""}`,
"aria-current": state === "active" ? "step" : undefined,
"aria-disabled": state === "disabled",
tabIndex: state === "disabled" ? -1 : 0,
onKeyDown: e => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleStepClick(index, step);
}
},
children: [jsxs("div", {
className: cn("relative glass-radius-full border-2 flex items-center justify-center transition-all duration-200", "hover:scale-110 group-hover:shadow-lg", config.stepSize, styles.circle),
children: [state === "completed" ? jsx(Check, {
className: config.iconSize
}) : state === "error" ? jsx(AlertCircle, {
className: config.iconSize
}) : step.icon ? jsx("span", {
className: cn(config.iconSize, styles.icon),
children: step.icon
}) : showNumbers ? jsx("span", {
className: cn("font-medium", config.fontSize.replace("text-", "text-"), styles.icon),
children: index + 1
}) : jsx(Circle, {
className: config.iconSize
}), step.optional && jsx("div", {
className: 'absolute glass-top-1 -right-1 w-2 h-2 glass-surface-yellow glass-radius-full'
})]
}), jsxs("div", {
className: 'mt-3 text-center max-w-24',
children: [jsx("h3", {
className: cn("font-medium leading-tight", config.fontSize, styles.text),
children: step.title
}), showDescriptions && step.description && jsx("p", {
className: cn("glass-text-xs glass-mt-1 leading-tight", state === "active" ? "glass-text-primary/80" : "glass-text-primary/50"),
children: step.description
})]
})]
})
}), !isLast && showProgressLine && jsx("div", {
className: cn("flex-1 glass-mx-2 transition-all duration-300", config.lineHeight, index < currentStep ? styles.line : "bg-white/20")
})]
}, step.id);
})
});
// Render vertical stepper
const renderVerticalStepper = () => jsx("nav", {
"aria-label": "Form steps",
className: cn("flex flex-col", config.spacing, className),
children: steps.map((step, index) => {
const state = getStepState(index, step);
const styles = getStepStyles(state);
const isLast = index === steps.length - 1;
return jsxs(React.Fragment, {
children: [jsx("div", {
className: 'glass-flex glass-items-start group',
children: jsxs(MotionFramer, {
preset: state === "active" ? "slideRight" : "fadeIn",
className: 'glass-flex glass-items-start cursor-pointer',
onClick: e => handleStepClick(index, step),
role: "button",
"aria-label": `Step ${index + 1}: ${step.title}${state === "completed" ? " (completed)" : state === "active" ? " (current)" : ""}`,
"aria-current": state === "active" ? "step" : undefined,
"aria-disabled": state === "disabled",
tabIndex: state === "disabled" ? -1 : 0,
onKeyDown: e => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleStepClick(index, step);
}
},
children: [jsxs("div", {
className: cn("relative glass-radius-full border-2 flex items-center justify-center transition-all duration-200", "hover:scale-110 group-hover:shadow-lg glass-mr-4", config.stepSize, styles.circle),
children: [state === "completed" ? jsx(Check, {
className: config.iconSize
}) : state === "error" ? jsx(AlertCircle, {
className: config.iconSize
}) : step.icon ? jsx("span", {
className: cn(config.iconSize, styles.icon),
children: step.icon
}) : showNumbers ? jsx("span", {
className: cn("font-medium", config.fontSize.replace("text-", "text-"), styles.icon),
children: index + 1
}) : jsx(Circle, {
className: config.iconSize
}), step.optional && jsx("div", {
className: 'absolute glass-top-1 -right-1 w-2 h-2 glass-surface-yellow glass-radius-full'
})]
}), jsxs("div", {
className: 'glass-flex-1 pt-1',
children: [jsx("h3", {
className: cn("font-medium leading-tight", config.fontSize, styles.text),
children: step.title
}), showDescriptions && step.description && jsx("p", {
className: cn("glass-text-sm glass-mt-1 leading-tight", state === "active" ? "glass-text-primary/80" : "glass-text-primary/50"),
children: step.description
})]
})]
})
}), !isLast && showProgressLine && jsx("div", {
className: "glass-flex glass-justify-center glass-py-2",
children: jsx("div", {
className: cn("w-px h-8 transition-all duration-300", index < currentStep ? styles.line : "bg-white/20")
})
})]
}, step.id);
})
});
return jsx(MotionFramer, {
preset: "fadeIn",
className: "glass-w-full",
children: orientation === "horizontal" ? renderHorizontalStepper() : renderVerticalStepper()
});
};
export { GlassFormStepper, GlassFormStepper as default };
//# sourceMappingURL=GlassFormStepper.js.map