// 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;