'use client'; import * as React from 'react'; import { type Ref, useCallback } from 'react'; import { classNames } from '@vkontakte/vkjs'; import { type FloatingComponentProps, useFloatingElement, type UseFloatingElementProps, } from '../../hooks/useFloatingElement'; import { animationFadeClassNames } from '../../lib/animation'; import { getArrowCoordsByMiddlewareData } from '../../lib/floating'; import { type ReferenceProps } from '../../lib/floating/useFloatingWithInteractions/types'; import { AppRootPortal } from '../AppRoot/AppRootPortal'; import { TooltipBase } from '../TooltipBase/TooltipBase'; import { type TooltipProps } from './Tooltip'; export type UseTooltipProps = Omit & { [key: `data-${string}`]: string | number | boolean; }; export type UseTooltipResult = { /** * Реф на якорный элемент. */ anchorRef: Ref; /** * Свойства для якорного элемента, содержит необходимые обработчики. */ anchorProps: ReferenceProps; /** * Отрендеренный компонент тултипа. */ tooltip: React.ReactNode | null; }; export const useTooltip = ({ // UseFloatingMiddlewaresBootstrapOptions placement: placementProp = 'bottom', arrowPadding = 10, arrowHeight = 8, offsetByMainAxis = 8, offsetByCrossAxis = 0, hideWhenReferenceHidden, disableFlipMiddleware = false, disableShiftMiddleware = false, disableTriggerOnFocus = false, onReferenceHiddenChange, overflowPadding, // useFloatingWithInteractions defaultShown, shown: shownProp, onShownChange, hoverDelay = 150, strategy, // инверсированные св-ва для useFloatingWithInteractions enableInteractive = false, disableArrow = false, disableCloseAfterClick = false, // AppRootProps usePortal, // TooltipBaseProps id: idProp, getRootRef, appearance = 'neutral', style: styleProp, className, zIndex = 'var(--vkui--z_index_popout)', closable, onPlacementChange, ...popperProps }: UseTooltipProps): UseTooltipResult => { const generatedId = React.useId(); const tooltipId = idProp || generatedId; const renderFloatingComponent = useCallback( ({ shown, floatingProps, floatingRef, placement: resultPlacement, middlewareData, setArrowRef, willBeHide, onClose, }: FloatingComponentProps) => { if (!shown) { return null; } return ( ); }, [ appearance, className, closable, disableArrow, popperProps, styleProp, tooltipId, usePortal, zIndex, ], ); const remapReferenceProps: Exclude = useCallback( ({ shown, ...referenceProps }) => ({ ...referenceProps, ...(shown && { 'aria-describedby': tooltipId }), }), [tooltipId], ); const { component, anchorRef, anchorProps } = useFloatingElement({ placement: placementProp, arrow: !disableArrow, arrowHeight, arrowPadding, offsetByMainAxis, offsetByCrossAxis, hideWhenReferenceHidden, disableFlipMiddleware, disableShiftMiddleware, overflowPadding, defaultShown, shown: shownProp, onShownChange, trigger: disableTriggerOnFocus ? 'hover' : ['hover', 'focus'], onReferenceHiddenChange, hoverDelay, closeAfterClick: !disableCloseAfterClick, disableInteractive: !enableInteractive, strategy, onPlacementChange, renderFloatingComponent, externalFloatingElementRef: getRootRef, remapReferenceProps, }); return { anchorRef, anchorProps, tooltip: component, }; };