import React from "react"; import Spinner from "../../atoms/spinner/spinner"; import Box from "../../atoms/box/box"; import Text from "../../atoms/text/text"; import Pressable, { PressableProps } from "../../atoms/pressable/pressable"; import { MoleculeComponentProps } from "../../../theme/src/types"; import { useButtonGroup } from "./button-group"; import { useMolecularComponentConfig } from "../../../hooks/useMolecularComponentConfig"; import { boxStyleFunctions } from "../../../theme/src/style-functions"; import { ButtonAtoms } from "./button.config"; export type BaseButtonProps = PressableProps & { /** * Whether the button is in a loading state. * * @default false */ isLoading?: boolean; /** * Whether the button should span the entire width of the parent container. * * @default false */ isFullWidth?: boolean; /** The text value to display when the button is in a loading state */ loadingText?: string; /** * The position of the loading spinner with respect to the loadingText. * * @default "start" */ spinnerPlacement?: "start" | "end"; /** Icon to display on the left side of the main text */ leftIcon?: React.ReactElement; /** Icon to display on the right side of the main text */ rightIcon?: React.ReactElement; children?: string; }; /** Button is used to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation */ const Button = React.memo( React.forwardRef( ( { children, loadingText = undefined, spinnerPlacement = "start", isLoading = false, isFullWidth = false, leftIcon = undefined, rightIcon = undefined, ...rest }: Omit< MoleculeComponentProps<"Button", BaseButtonProps, ButtonAtoms>, "atoms" > & { atoms?: Partial; }, ref: any ) => { const { size, variant, isDisabled, colorScheme } = useButtonGroup(); // Overwrite props from checkbox group rest.size = rest.size ?? size; rest.variant = rest.variant ?? variant; rest.isDisabled = rest.isDisabled ?? isDisabled; rest.colorScheme = rest.colorScheme ?? colorScheme; const molecularProps = useMolecularComponentConfig( "Button", rest, { size: rest.size, variant: rest.variant, }, rest.colorScheme, boxStyleFunctions, "pressable", "pressable", "pressable" ); const { atoms } = molecularProps; // Determine if the button is disabled const isButtonDisabled = rest.isDisabled ? true : isLoading; // Function to render the loading status of the button const renderLoadingStatus = () => { // If there is loading text, render the spinner and the loading text if (loadingText) { return ( {spinnerPlacement === "start" ? ( <> {loadingText} ) : ( <> {loadingText} )} ); } else { // If there is no loading text, render the spinner and the children with transparent color return ( <> {children} ); } }; // Function to render the main content of the button const renderMainContent = () => { // If there are left or right icons, render them along with the children if (leftIcon || rightIcon) { return ( {leftIcon ? React.cloneElement(leftIcon, { ...atoms.icon, marginLeft: 0, marginRight: atoms.icon.mr ?? atoms.icon.marginRight ?? atoms.icon.mx ?? atoms.icon.marginHorizontal ?? atoms.icon.m ?? atoms.icon.margin, ...leftIcon.props, }) : null} {children} {rightIcon ? React.cloneElement(rightIcon, { ...atoms.icon, marginRight: 0, marginLeft: atoms.icon.ml ?? atoms.icon.marginLeft ?? atoms.icon.mx ?? atoms.icon.marginHorizontal ?? atoms.icon.m ?? atoms.icon.margin, ...rightIcon.props, }) : null} ); } else { // If there are no icons, render only the children return {children}; } }; return ( {isLoading ? renderLoadingStatus() : renderMainContent()} ); } ) ); export type ButtonProps = React.ComponentProps; Button.displayName = "Button"; export default Button;