import { useState } from 'react'
type Position = {
/**
* @description This is the top position of the popover.
* @default 0
*/
top: number
/**
* @description This is the left position of the popover.
* @default 0
*/
left: number
}
/**
* @deprecated This hook is deprecated and will be removed in v3.0.0.
* Use the native Popover component instead, which provides better accessibility,
* automatic layer management, and platform-native behavior.
*
* @see {@link ../components/popover/popover.tsx} New Popover Component
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/popover} HTML Popover API
*
* @description Legacy hook for custom popover positioning with pointer events.
* Manually calculates popover position and handles show/hide logic.
*
* @param elementRef - Ref of the trigger element
* @param hoverRef - Ref of the popover element
* @param spacing - Spacing between trigger and popover (in pixels)
*
* @example
* ```tsx
* // ❌ Old approach (deprecated)
* const { isVisible, popoverPosition, handlePointerEvent, handlePointerLeave } =
* usePopover(hoverRef, popOverRef, 1);
*
* // ✅ New approach (recommended)
* import { Popover } from '@fpkit/acss';
* Content
* ```
*
* @returns Hook state and handlers
* @returns isVisible - Boolean indicating popover visibility
* @returns popoverPosition - Position object with top/left coordinates
* @returns handlePointerEvent - Function to show popover on pointer enter
* @returns handlePointerLeave - Function to hide popover on pointer leave
*/
export const usePopover = (
elementRef: React.RefObject,
hoverRef: React.RefObject,
spacing = 1,
) => {
const [isVisible, setIsVisible] = useState(false)
const [popoverPosition, setPopoverPosition] = useState({
top: 0,
left: 0,
})
const handlePointerEvent = (
event: React.MouseEvent,
) => {
event?.stopPropagation()
const height = elementRef.current?.offsetHeight || 40
if (elementRef.current) {
const rect = elementRef.current.getBoundingClientRect()
const { scrollY, scrollX, innerHeight } = window
const popoverTop = rect.bottom + scrollY + spacing
const popoverLeft = rect.left + scrollX
const popoverBottom = popoverTop + height // Adjust the popover height as needed
const popoverHeight = hoverRef.current?.offsetHeight ?? height // Adjust the popover height as needed
const adjustedTop =
popoverBottom > scrollY + innerHeight
? Math.max(
scrollY + innerHeight - popoverHeight - height - spacing,
scrollY,
) -
height -
spacing
: popoverTop
setPopoverPosition({
top: adjustedTop,
left: popoverLeft,
})
setIsVisible(true)
}
}
const handlePointerLeave = () => {
setIsVisible(false)
}
return {
isVisible,
popoverPosition,
handlePointerEvent,
handlePointerLeave,
}
}
export default usePopover