/* eslint-disable complexity */ import React, { type AnchorHTMLAttributes, type ButtonHTMLAttributes, forwardRef, useEffect, useRef, useState, } from 'react'; import mergeRefs from 'react-merge-refs'; import cn from 'classnames'; import { getDataTestId } from '@alfalab/core-components-shared'; import { Spinner } from '@alfalab/core-components-spinner'; import { useFocus } from '@alfalab/hooks'; import { LOADER_MIN_DISPLAY_INTERVAL } from '../../constants/loader-min-display-interval'; import { type CommonButtonProps, type PrivateButtonProps } from '../../typings'; import defaultColors from './default.module.css'; import commonStyles from './index.module.css'; import invertedColors from './inverted.module.css'; const colorStyles = { default: defaultColors, inverted: invertedColors, }; export const BaseButton = forwardRef< HTMLAnchorElement | HTMLButtonElement, CommonButtonProps & PrivateButtonProps >( ( { allowBackdropBlur, children, view = 'secondary', shape = 'rectangular', textResizing = 'hug', hint, leftAddons, rightAddons, size = 56, block = false, className, spinnerClassName, dataTestId, href, loading = false, nowrap = false, colors = 'default', Component = href ? 'a' : 'button', onClick, styles = {}, colorStylesMap = { default: {}, inverted: {} }, labelClassName, hintClassName, ...restProps }, ref, ) => { const buttonRef = useRef(null); const [focused] = useFocus(buttonRef, 'keyboard'); const [loaderTimePassed, setLoaderTimePassed] = useState(true); const timerId = useRef(0); const showLoader = loading || !loaderTimePassed; const showHint = hint && [56, 64, 72].includes(size); const iconOnly = !children; const sizeStyle = `size-${size}`; const componentProps = { className: cn( commonStyles.component, commonStyles[view], commonStyles[sizeStyle], commonStyles[textResizing], shape === 'rectangular' && styles[sizeStyle], shape === 'rounded' && commonStyles[shape], colorStyles[colors].component, colorStyles[colors][view], colorStylesMap[colors].component, { [commonStyles.allowBackdropBlur]: allowBackdropBlur, [colorStylesMap[colors][view]]: Boolean(colorStylesMap[colors][view]), [commonStyles.focused]: focused, [commonStyles.block]: block, [commonStyles.iconOnly]: iconOnly, [commonStyles.loading]: showLoader, [commonStyles.withRightAddons]: Boolean(rightAddons) && !iconOnly, [commonStyles.withLeftAddons]: Boolean(leftAddons) && !iconOnly, [colorStyles[colors].loading]: showLoader, [colorStylesMap[colors].loading]: showLoader, }, className, ), 'data-test-id': dataTestId || null, }; const { disabled, type = 'button', ...restButtonProps } = restProps as ButtonHTMLAttributes; const buttonChildren = ( {leftAddons && {leftAddons}} {children && ( {children} {showHint && ( {hint} )} )} {showLoader && ( )} {rightAddons && {rightAddons}} ); useEffect(() => { if (loading) { setLoaderTimePassed(false); timerId.current = window.setTimeout(() => { setLoaderTimePassed(true); }, LOADER_MIN_DISPLAY_INTERVAL); } }, [loading]); useEffect( () => () => { window.clearTimeout(timerId.current); }, [], ); const handleClick = ( e: React.MouseEvent & React.MouseEvent, ) => { if (disabled || showLoader) { e.preventDefault(); e.stopPropagation(); return; } onClick?.(e); }; if (href) { const { target } = restProps as AnchorHTMLAttributes; // Для совместимости с react-router-dom, меняем href на to const hrefProps = { [typeof Component === 'string' ? 'href' : 'to']: href }; return ( )} {...hrefProps} onClick={handleClick} disabled={disabled || showLoader} ref={mergeRefs([buttonRef, ref])} > {buttonChildren} ); } return ( {buttonChildren} ); }, );