import { createElement, forwardRef, useContext } from 'react'; import { isForwardRef } from 'react-is'; import PopoverContext from './Context'; import Popover from './Popover'; function isClassComponent(component: any) { return !!component?.prototype?.isReactComponent; } export function usePopover() { const ctx = useContext(PopoverContext); if (ctx === null) { throw new Error('usePopover must be used as child of Popover'); } return ctx.popover; } /** * A high order component to expose imperative APIs for popover. * * Adds a popover prop to component. */ export function exposePopover(propName: N) { return function expose = Record>( Base: React.ComponentType ) { const componentName = Base.displayName || Base.constructor.name || 'Component'; const shouldPassRef = isClassComponent(Base) || isForwardRef(Base); const comp = forwardRef>((props, ref) => { const popover = usePopover(); const childProps: any = { [propName]: popover, }; if (shouldPassRef) { childProps.ref = ref; } return createElement(Base, { ...props, ...childProps, }); }); comp.displayName = `withPopover(${componentName})`; return comp; }; } export default exposePopover('popover') as ( Comp: React.ComponentType ) => React.ComponentType>;