89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import React from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
/**
|
|
* FormError Component
|
|
* Display error messages with different variants and animations
|
|
*/
|
|
|
|
export interface FormErrorProps {
|
|
errors?: string | string[];
|
|
variant?: 'inline' | 'block' | 'toast';
|
|
className?: string;
|
|
showIcon?: boolean;
|
|
animate?: boolean;
|
|
id?: string;
|
|
}
|
|
|
|
export const FormError: React.FC<FormErrorProps> = ({
|
|
errors,
|
|
variant = 'inline',
|
|
className,
|
|
showIcon = true,
|
|
animate = true,
|
|
id,
|
|
}) => {
|
|
if (!errors || (Array.isArray(errors) && errors.length === 0)) {
|
|
return null;
|
|
}
|
|
|
|
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
const hasMultipleErrors = errorArray.length > 1;
|
|
|
|
const baseClasses = {
|
|
inline: 'text-sm text-danger mt-1',
|
|
block: 'p-3 bg-danger/10 border border-danger/20 rounded-md text-danger text-sm',
|
|
toast: 'fixed bottom-4 right-4 p-4 bg-danger text-white rounded-lg shadow-lg max-w-md z-tooltip animate-slide-up',
|
|
};
|
|
|
|
const animationClasses = animate ? 'animate-fade-in' : '';
|
|
|
|
const Icon = () => (
|
|
<svg
|
|
className="w-4 h-4 mr-1 inline-block"
|
|
fill="currentColor"
|
|
viewBox="0 0 20 20"
|
|
aria-hidden="true"
|
|
>
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
role="alert"
|
|
aria-live="polite"
|
|
id={id}
|
|
className={cn(
|
|
baseClasses[variant],
|
|
animationClasses,
|
|
'transition-all duration-200',
|
|
className
|
|
)}
|
|
>
|
|
{hasMultipleErrors ? (
|
|
<ul className="list-disc list-inside space-y-1">
|
|
{errorArray.map((error, index) => (
|
|
<li key={index} className="flex items-start">
|
|
{showIcon && <Icon />}
|
|
<span>{error}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : (
|
|
<div className="flex items-start">
|
|
{showIcon && <Icon />}
|
|
<span>{errorArray[0]}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
FormError.displayName = 'FormError';
|
|
|
|
export default FormError; |