import React from "react"; import { ButtonProps } from "./types"; import { AnimationWrapper, DEFAULT_BUTTON_ANIMATION_TYPE, } from "@shared/components/animation-wrapper"; import { BrandButton, ButtonVariantsT } from "@shared/components/brand-button"; import { Button as CoreButton } from "@shared/components/button"; import { Link } from "@shared/components/link"; import { MaterialIcon } from "@shared/components/material-icon"; import type { IconName } from "@shared/components/material-icon/types"; import { Text } from "@shared/components/text"; import { cx } from "@shared/utils"; import { buildPreservedQueryHref } from "@shared/utils/utm"; const textVariantClasses: Record = { primary_brand: "text-text-brand", primary_inverse: "text-text", secondary: "text-text", }; export const Button: React.FC = props => { const { showButtonAs = "solid", buttonVariant = "primary_brand", buttonLabel, buttonPrefix, href, target = "_blank", anchorId, linkClassName, linkVariant, fullWidth, preDefinedFunctionExecution, renderCheckPlans, buttonClassName, clickToOpen, tabmodalNameToOpen, idNameToOpen, onModalButtonClick, onClick, iconFill = 0, buttonIconName, buttonIconPosition, size, iconSize = 24, preserveQueryParameters, disableAnimation, animationType = DEFAULT_BUTTON_ANIMATION_TYPE, ...rest } = props; const isLeftIcon = buttonIconPosition === "left"; const matIconName = buttonIconName as IconName | undefined; const brandButtonClassName = cx( buttonClassName, isLeftIcon && matIconName ? "flex-row-reverse" : "" ); if ( preDefinedFunctionExecution === "check availability" && renderCheckPlans ) { const checkPlansNode = renderCheckPlans?.({ ctaText: buttonLabel, buttonVariant: buttonVariant, showButtonAs: showButtonAs, cta: { ...props }, }); return React.isValidElement(checkPlansNode) ? ( // `disableAnimation` is passed through as-is (not defaulted to `false`). // Animations are opt-in: when unset, AnimationWrapper falls back to its // default of `true` (disabled), matching the CMS contract where an unset // value means "no animation". This stays consistent with the other // branches in this block. Animation runs only when a caller explicitly // passes `disableAnimation={false}`. {checkPlansNode} ) : ( checkPlansNode ); } function handleClickId() { if (clickToOpen === "clickId" && idNameToOpen) { const element = document.getElementById(idNameToOpen); if (element) { element.scrollIntoView({ behavior: "smooth", block: "start", }); element.click?.(); } } } function handleModalClick( event?: React.MouseEvent ) { if (clickToOpen === "modal") { // Prevent the anchor's href from navigating so the CTA only opens the modal. event?.preventDefault(); onModalButtonClick?.(tabmodalNameToOpen); } if (clickToOpen === "clickId") { event?.preventDefault(); handleClickId(); } } function linkClick(event: React.MouseEvent) { handleModalClick(event); onClick?.(event); } function buttonClick(event: React.MouseEvent) { handleModalClick(event); onClick?.(event); } // Resolve the final href — merge non-UTM query params when preserveQueryParameters is true const currentSearch = typeof window !== "undefined" ? window.location.search : ""; const resolvedHref = preDefinedFunctionExecution ? undefined : href && preserveQueryParameters && currentSearch ? buildPreservedQueryHref(href, currentSearch) : href; let CTA = ( ); switch (showButtonAs) { case "solid": CTA = resolvedHref ? ( ) : ( ); break; case "text": CTA = ( {matIconName ? ( <> {isLeftIcon ? ( ) : null} {buttonLabel} {!isLeftIcon ? ( ) : null} ) : ( <>{buttonLabel} )} ); break; case "button-with-icon": CTA = resolvedHref ? ( ) : ( ); break; case "text-with-icon": { const getTextWithIconVariantClass = ( variant: ButtonVariantsT ): string => { const variantMap: Record = { primary_brand: "text-text-brand", primary_inverse: "text-text-inverse", secondary: "text-text", }; return variantMap[variant] || "text-text-brand"; }; const textWithIconVariantClass = getTextWithIconVariantClass(buttonVariant); CTA = ( {isLeftIcon && matIconName ? ( ) : null} {buttonLabel} {matIconName && !isLeftIcon && ( )} ); break; } case "unstyled": // For unstyled, we can use the CoreButton without any additional styling break; default: // For default, we can use the CoreButton without any additional styling break; } return ( {CTA} ); }; export default Button;