import * as Ariakit from '@ariakit/react' import React from 'react' import { Button, ButtonProps as ButtonProps } from '../Button/Button' import { Tag, Props as TagProps } from '../Tag/Tag' import { Box, BoxProps } from '../Box/Box' const PopoverContext = React.createContext( {} as Ariakit.PopoverStore, ) export const usePopover = () => React.useContext(PopoverContext) export type PopoverProps = React.PropsWithChildren< Partial & { store?: Ariakit.PopoverStore } > type PopoverComponent = React.FC & { ButtonTrigger: typeof ButtonTrigger TagTrigger: typeof TagTrigger BoxTrigger: typeof BoxTrigger Content: typeof Content usePopoverStore: typeof Ariakit.usePopoverStore } export const Popover: PopoverComponent = ({ children, ...props }: PopoverProps) => { const popoverStore = props.store ?? Ariakit.usePopoverStore({ placement: 'bottom', ...props, }) return ( {children} ) } // TODO: See if we can come up with a generic component that can accommodate an // `as` prop that preserves types. Creating separate tag/button components as // a workaround for now. const ButtonTrigger: React.FC> = ({ children, ...props }) => { const popover = usePopover() return ( {children} ) } const TagTrigger: React.FC> = ({ children, ...props }) => { const popover = usePopover() return ( {children} ) } const BoxTrigger: React.FC> = ({ children, ...props }) => { const popover = usePopover() return ( {children} ) } const Content: React.FC< React.PropsWithChildren, 'store'>> & { className?: string } > = ({ children, className, ...props }) => { const popover = usePopover() return ( {/* There is a bug in v0.2.17 of Ariakit where you need to have this arrow rendered or else positioning of the popover breaks. We render it, but hide it by setting size={0}. This is an issue with anything using a popover coming from the floating-ui library. */} {children} ) } Popover.ButtonTrigger = ButtonTrigger Popover.TagTrigger = TagTrigger Popover.BoxTrigger = BoxTrigger Popover.Content = Content Popover.usePopoverStore = Ariakit.usePopoverStore