Spaces:
Sleeping
Sleeping
File size: 2,328 Bytes
b64de39 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | /**
* ErrorMessage - Inline error/alert display.
*
* Renders a styled error box with an optional retry action.
* Supports dismissible mode via an onDismiss callback.
*/
import PropTypes from "prop-types";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
function ErrorMessage({
message,
title,
onRetry,
onDismiss,
className = "",
}) {
if (!message) {
return null;
}
return (
<div
className={`rounded-lg border border-danger-200 bg-danger-50 p-4 ${className}`}
role="alert"
>
<div className="flex items-start gap-3">
<ExclamationTriangleIcon
className="h-5 w-5 shrink-0 text-danger-500 mt-0.5"
aria-hidden="true"
/>
<div className="flex-1 min-w-0">
{title && (
<h3 className="text-sm font-semibold text-danger-800 mb-1">
{title}
</h3>
)}
<p className="text-sm text-danger-700">{message}</p>
{onRetry && (
<button
type="button"
onClick={onRetry}
className="mt-2 text-sm font-medium text-danger-700 underline hover:text-danger-900 focus:outline-none focus:ring-2 focus:ring-danger-500 rounded"
>
Try again
</button>
)}
</div>
{onDismiss && (
<button
type="button"
onClick={onDismiss}
className="shrink-0 rounded-lg p-1 text-danger-400 hover:text-danger-600 hover:bg-danger-100 transition-colors focus:outline-none focus:ring-2 focus:ring-danger-500"
aria-label="Dismiss error"
>
<svg
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
)}
</div>
</div>
);
}
ErrorMessage.propTypes = {
message: PropTypes.string,
title: PropTypes.string,
onRetry: PropTypes.func,
onDismiss: PropTypes.func,
className: PropTypes.string,
};
export default ErrorMessage;
|