UNPKG

@trail-ui/react

Version:
117 lines (107 loc) 3.27 kB
/** * This code comes from @react-aria/overlays */ import { AriaOverlayProps, AriaPositionProps, ariaHideOutside, useOverlay, useOverlayPosition, usePreventScroll, } from '@react-aria/overlays'; import { mergeProps, useLayoutEffect } from '@react-aria/utils'; import { DOMAttributes } from '@react-types/shared'; import { RefObject } from 'react'; import { PlacementAxis } from 'react-aria'; import { OverlayTriggerState } from 'react-stately'; export interface AriaPopoverProps extends AriaOverlayProps, Omit<AriaPositionProps, 'isOpen' | 'onClose' | 'targetRef' | 'overlayRef'> { /** * The ref for the element which the popover positions itself with respect to. */ triggerRef: RefObject<Element>; /** * The ref for the popover element. */ popoverRef: RefObject<Element>; /** * Whether the popover is non-modal, i.e. elements outside the popover may be * interacted with by assistive technologies. * * Most popovers should not use this option as it may negatively impact the screen * reader experience. Only use with components such as combobox, which are designed * to handle this situation carefully. */ isNonModal?: boolean; /** * Whether pressing the escape key to close the popover should be disabled. * * Most popovers should not use this option. When set to true, an alternative * way to close the popover with a keyboard must be provided. * * @default false */ isKeyboardDismissDisabled?: boolean; } export interface PopoverAria { /** Props for the popover element. */ popoverProps: DOMAttributes; /** Props for the popover tip arrow if any. */ arrowProps: DOMAttributes; /** Props to apply to the underlay element, if any. */ underlayProps: DOMAttributes; /** Placement of the popover with respect to the trigger. */ placement: PlacementAxis; } /** * Provides the behavior and accessibility implementation for a popover component. * A popover is an overlay element positioned relative to a trigger. */ export function usePopover(props: AriaPopoverProps, state: OverlayTriggerState): PopoverAria { const { triggerRef, popoverRef, isNonModal, isKeyboardDismissDisabled, shouldCloseOnInteractOutside, ...otherProps } = props; const { overlayProps, underlayProps } = useOverlay( { isOpen: state.isOpen, onClose: state.close, shouldCloseOnBlur: true, // isDismissable: !isNonModal, isDismissable: true, isKeyboardDismissDisabled, shouldCloseOnInteractOutside: shouldCloseOnInteractOutside, }, popoverRef, ); const { overlayProps: positionProps, arrowProps, placement, } = useOverlayPosition({ ...otherProps, targetRef: triggerRef, overlayRef: popoverRef, isOpen: state.isOpen, onClose: () => {}, }); usePreventScroll({ isDisabled: isNonModal || !state.isOpen, }); useLayoutEffect(() => { if (state.isOpen && !isNonModal && popoverRef.current) { return ariaHideOutside([popoverRef.current]); } }, [isNonModal, state.isOpen, popoverRef]); return { popoverProps: mergeProps(overlayProps, positionProps), arrowProps, underlayProps, placement: placement as PlacementAxis, }; }