// File Path: web/frontend/src/components/UIX/CreateButton/CreateButton.jsx
// CreateButton Component - Performance Optimized
import React, { memo, useMemo } from "react";
import { PlusIcon } from "@heroicons/react/24/outline";
import { useUIXTheme } from "../themes/useUIXTheme.jsx";
/**
* CreateButton Component - Performance Optimized
* Green-themed button specifically for creation actions
*
* @param {React.ReactNode} children - Button text content
* @param {Function} onClick - Click handler function
* @param {boolean} disabled - Whether button is disabled
* @param {string} type - Button type (button, submit, reset)
* @param {string} className - Additional CSS classes
* @param {boolean} loading - Loading state
* @param {string} loadingText - Text to show when loading
* @param {boolean} fullWidth - Whether button should take full width
* @param {string} size - Button size (sm, md, lg, xl)
* @param {React.ComponentType} icon - Icon component (defaults to PlusIcon)
* @param {boolean} gradient - Whether to use gradient background
*/
// Static size classes - moved outside to prevent recreation
const SIZE_CLASSES = Object.freeze({
sm: "px-3 py-2 text-xs sm:text-sm",
md: "px-4 py-3 text-sm sm:text-base",
lg: "px-6 sm:px-8 py-3 sm:py-4 text-sm sm:text-base",
xl: "px-8 py-4 text-base sm:text-lg",
});
// Loading Spinner Component - Separated for better performance
const LoadingSpinner = memo(function LoadingSpinner() {
return (
);
});
LoadingSpinner.displayName = "LoadingSpinner";
const CreateButton = memo(
function CreateButton({
children,
onClick,
disabled = false,
type = "button",
className = "",
loading = false,
loadingText,
fullWidth = false,
size = "lg",
icon: Icon = PlusIcon,
gradient = false,
}) {
const { getThemeClasses } = useUIXTheme();
// Computed disabled state
const isDisabled = disabled || loading;
// Memoize theme classes
const themeClasses = useMemo(
() => ({
buttonCreate: getThemeClasses("button-create"),
inputFocusRing: getThemeClasses("input-focus-ring"),
bgGradientSecondary: getThemeClasses("bg-gradient-secondary"),
}),
[getThemeClasses],
);
// Memoize gradient style
const gradientStyle = useMemo(() => {
if (!gradient) return {};
return {
background:
themeClasses.bgGradientSecondary ||
"linear-gradient(to right, #059669, #10b981)",
};
}, [gradient, themeClasses.bgGradientSecondary]);
// Memoize button classes
const buttonClasses = useMemo(() => {
const classes = [
SIZE_CLASSES[size] || SIZE_CLASSES.lg,
"font-medium",
"rounded-xl",
"focus:outline-none",
"transition-all",
"duration-200",
"inline-flex",
"items-center",
"justify-center",
];
if (fullWidth) {
classes.push("w-full");
}
// Variant classes
if (gradient) {
classes.push(
"border-transparent",
"text-white",
"shadow-lg",
"hover:shadow-xl",
themeClasses.inputFocusRing,
"transform",
"hover:scale-105",
"font-bold",
);
} else {
classes.push(themeClasses.buttonCreate);
}
// State classes
if (isDisabled) {
classes.push("opacity-50", "cursor-not-allowed");
} else {
classes.push("cursor-pointer");
}
// Custom className
if (className) {
classes.push(className);
}
return classes.filter(Boolean).join(" ");
}, [size, fullWidth, gradient, themeClasses, isDisabled, className]);
// Memoize button content
const ButtonContent = useMemo(() => {
if (loading) {
return (
<>
{loadingText || "Creating..."}
>
);
}
return (
<>
{Icon && }
{children}
>
);
}, [loading, loadingText, Icon, children]);
return (
);
},
(prevProps, nextProps) => {
// Custom comparison function - only re-render when these props actually change
return (
prevProps.children === nextProps.children &&
prevProps.onClick === nextProps.onClick &&
prevProps.disabled === nextProps.disabled &&
prevProps.type === nextProps.type &&
prevProps.className === nextProps.className &&
prevProps.loading === nextProps.loading &&
prevProps.loadingText === nextProps.loadingText &&
prevProps.fullWidth === nextProps.fullWidth &&
prevProps.size === nextProps.size &&
prevProps.icon === nextProps.icon &&
prevProps.gradient === nextProps.gradient
);
},
);
// Display name for debugging
CreateButton.displayName = "CreateButton";
export default CreateButton;