import { PolymorphicRef } from '@cloud-ru/ds-card'; import { useThemeClassnames } from '@cloud-ru/ds-theme'; import { TooltipProps } from '@cloud-ru/ds-tooltip'; import { TruncateString } from '@cloud-ru/ds-truncate-string'; import { Typography } from '@cloud-ru/ds-typography'; import { useValueControl, withInnerRefSupport } from '@cloud-ru/ds-utils'; import cn from 'classnames'; import mergeRefs from 'merge-refs'; import { ComponentPropsWithoutRef, ElementType, KeyboardEventHandler, MouseEvent, MouseEventHandler, ReactElement, useRef, useState, } from 'react'; import { TEST_IDS, VISIBILITY_STRATEGY } from '../../constants'; import { CardActionsSurface, CardPromoTag, createCardActionsKeyDownHandler } from '../../helperComponents'; import { CardPromoTagProps, FavoriteProps, VisibilityStrategy } from '../../types'; import styles from './styles.module.scss'; const TARGET_BLANK = '_blank'; type BaseCardServiceLightProps = { /** Иконка сервиса */ icon?: ReactElement; /** Заголовок карточки */ title: string; /** Настройки promo tag. При отсутствии не отображается */ promoTag?: CardPromoTagProps; /** Настройки обрезки текста заголовка */ truncate?: { /** Максимальное количество строк заголовка */ title?: number; }; /** * Формат отображения дополнительных действий: всегда или при наведении и фокусе * @default 'hover' */ actionsVisibility?: VisibilityStrategy; /** Подсказка с иконкой «?» рядом с заголовком */ tooltip?: Omit; /** * Настройки кнопки «Избранное». * Keyboard: ArrowRight на карточке → tooltip (если есть) → Favorite; ArrowLeft — в обратном порядке. */ favorite?: FavoriteProps; /** Неактивное состояние */ disabled?: boolean; /** CSS-класс корневого элемента */ className?: string; /** Support prop для тестов */ 'data-test-id'?: string; /** Настройки кнопки раскрытия */ expandable?: { value: boolean; onClick(): void; }; }; export type CardServiceLightProps = BaseCardServiceLightProps & { /** Полиморфный элемент: `'button'`, `'a'`, `{Link}` и т.д. */ as?: T; /** Ref на реальный DOM-элемент / инстанс */ innerRef?: PolymorphicRef; } & Omit, keyof BaseCardServiceLightProps | 'as' | 'ref'>; export function CardServiceLight({ as, innerRef, icon, title, promoTag, truncate, actionsVisibility: actionsVisibilityProp, favorite, tooltip, className, disabled = false, expandable, 'data-test-id': dataTestId, ...rest }: CardServiceLightProps): ReactElement | null { const Component: ElementType = as ?? 'button'; const cardRef = useRef(null); const tooltipTriggerRef = useRef(null); const promoTagTooltipTriggerRef = useRef(null); const favoriteRef = useRef(null); const expandButtonRef = useRef(null); const compactThemeClassName = useThemeClassnames({ density: 'compact' }); const actionsVisibility = actionsVisibilityProp ?? VISIBILITY_STRATEGY.hover; const [isFavorite, setIsFavorite] = useValueControl({ value: favorite?.checked, defaultValue: false, onChange: favorite?.onChange, }); const [isTooltipOpen, setIsTooltipOpen] = useState(false); const tooltipTrigger = actionsVisibility === VISIBILITY_STRATEGY.hover ? 'hoverAndFocusVisible' : 'click'; const { onKeyDown: onKeyDownProp, ...restWithoutKeyDown } = rest as ComponentPropsWithoutRef & { onKeyDown?: KeyboardEventHandler; }; const handleKeyDown = createCardActionsKeyDownHandler({ disabled, cardRef, onKeyDown: onKeyDownProp, items: [ promoTag && { ref: promoTagTooltipTriggerRef }, tooltip && { ref: tooltipTriggerRef }, favorite?.enabled && { ref: favoriteRef, onActivate: () => setIsFavorite(!isFavorite), }, expandable && { ref: expandButtonRef, onActivate: () => expandable.onClick(), }, ], }); let polymorphicProps: Record; if (Component === 'a') { const { href, target, onClick, ...anchorRest } = restWithoutKeyDown as ComponentPropsWithoutRef<'a'>; polymorphicProps = { ...anchorRest, href: href ?? '#', target, rel: target === TARGET_BLANK ? 'noopener noreferrer' : undefined, onClick: disabled ? (e: MouseEvent) => { e.preventDefault(); onClick?.(e); } : onClick, }; } else if (Component === 'button') { const { type = 'button', onClick, ...buttonRest } = restWithoutKeyDown as ComponentPropsWithoutRef<'button'>; polymorphicProps = { type, disabled, onClick: disabled ? undefined : onClick, ...buttonRest, }; } else { // Кастомный компонент (роутерный Link и т.п.) нативный `disabled` не понимает: гасим переход // тем же preventDefault, что и на анкоре — иначе disabled-карточка остаётся кликабельной. const { onClick, ...componentRest } = restWithoutKeyDown as { onClick?: MouseEventHandler }; polymorphicProps = { ...componentRest, onClick: disabled ? (e: MouseEvent) => { e.preventDefault(); } : onClick, }; } return (
{icon &&
{icon}
}
{promoTag && ( )}
); } withInnerRefSupport(CardServiceLight);