import { ReactNode, useEffect, useRef } from 'react'; import { FloatingFocusManager, Side } from '@floating-ui/react'; import classnames from 'classnames'; import usePopover, { SIDES_MAP } from './usePopover'; import borderStyles from '../Borders.css'; import { Overflow } from '../boxTypes'; import Caret from '../Caret'; import styles from '../Contents.css'; import layoutStyles from '../Layout.css'; const CARET_HEIGHT = 4; const CARET_WIDTH = 12; export type Role = 'dialog' | 'listbox' | 'menu' | 'tooltip'; type MainDirections = 'up' | 'right' | 'down' | 'left'; const DIRECTIONS_MAP: Record = { down: 'bottom', left: 'left', right: 'right', up: 'top', }; type Props = { accessibilityLabel?: string; anchor: HTMLElement; bgColor?: 'blue' | 'darkGray' | 'white'; caret?: boolean; children?: ReactNode; id: string | undefined; idealDirection?: 'up' | 'right' | 'down' | 'left'; forceDirection?: boolean; onKeyDown: (event: React.KeyboardEvent) => void; role: Role | undefined; rounding?: 2 | 4; shouldFocus?: boolean; width: number | undefined; scrollBoundary?: HTMLElement; hideWhenReferenceHidden?: boolean; onPositioned?: () => void; shouldTrapFocus?: boolean; overflow?: Extract; }; export default function Contents({ accessibilityLabel, anchor, bgColor, caret = true, children, id, idealDirection, forceDirection, role, rounding, width, shouldFocus = true, onKeyDown, scrollBoundary, hideWhenReferenceHidden, onPositioned, shouldTrapFocus, overflow, }: Props) { const caretRef = useRef(null); let idealPlacement: Side = 'top'; if (idealDirection) { idealPlacement = DIRECTIONS_MAP[idealDirection]; } const { refs, placement, floatingStyles, middlewareData, context, isPositioned } = usePopover({ anchor, caretElement: caretRef.current, caretPadding: rounding && rounding * 4, forceDirection, direction: idealPlacement, scrollBoundary, hideWhenReferenceHidden, onPositioned, }); const caretOffset = middlewareData.arrow; const isAnchorInViewport = middlewareData.hide?.referenceHidden === true; const isCaretVertical = placement === 'top' || placement === 'bottom'; useEffect(() => { if (shouldFocus && refs.floating.current && isPositioned) { refs.floating.current.focus(); } }, [isPositioned, refs.floating, shouldFocus]); useEffect(() => { // @ts-expect-error - TS2769 - No overload matches this call. window.addEventListener('keydown', onKeyDown); // @ts-expect-error - TS2769 - No overload matches this call. return () => window.removeEventListener('keydown', onKeyDown); }, [onKeyDown]); return (
{caret && (
' is not assignable to type 'LegacyRef | undefined'. ref={caretRef} className={classnames(styles.caret, layoutStyles.flex, layoutStyles.absolute, { [styles.caretPrimary]: bgColor === 'white', [styles.caretSecondary]: bgColor === 'darkGray', [styles.caretEducation]: bgColor === 'blue', })} style={{ left: caretOffset?.x, top: caretOffset?.y, [placement]: '100%', }} > '. direction={SIDES_MAP[placement]} height={isCaretVertical ? CARET_HEIGHT : CARET_WIDTH} width={isCaretVertical ? CARET_WIDTH : CARET_HEIGHT} />
)}
{children}
); }