Add popover component

This commit is contained in:
Chewbacca
2023-03-14 15:58:11 -04:00
parent af69c7564e
commit 283935e837
4 changed files with 148 additions and 18 deletions

View File

@@ -39,6 +39,7 @@ export {
} from './menu/menu';
export { default as Modal } from './modal/modal';
export { default as PhoneInput } from './phone-input/phone-input';
export { default as Popover } from './popover/popover';
export { default as Portal } from './portal/portal';
export { default as ProgressBar } from './progress-bar/progress-bar';
export { default as RadioButton } from './radio-button/radio-button';

View File

@@ -0,0 +1,90 @@
import {
arrow,
FloatingArrow,
offset,
useClick,
useDismiss,
useFloating,
useInteractions,
useTransitionStyles,
} from '@floating-ui/react';
import React, { useRef, useState } from 'react';
interface IPopover {
children: React.ReactElement<any, string | React.JSXElementConstructor<any>>
content: React.ReactNode
}
/**
* Popover
*
* Similar to tooltip, but requires a click and is used for larger blocks
* of information.
*/
const Popover: React.FC<IPopover> = (props) => {
const { children, content } = props;
const [isOpen, setIsOpen] = useState<boolean>(false);
const arrowRef = useRef<SVGSVGElement>(null);
const { x, y, strategy, refs, context } = useFloating({
open: isOpen,
onOpenChange: setIsOpen,
placement: 'top',
middleware: [
offset(10),
arrow({
element: arrowRef,
}),
],
});
const click = useClick(context);
const dismiss = useDismiss(context);
const { isMounted, styles } = useTransitionStyles(context, {
initial: {
opacity: 0,
transform: 'scale(0.8)',
},
duration: {
open: 200,
close: 200,
},
});
const { getReferenceProps, getFloatingProps } = useInteractions([
click,
dismiss,
]);
return (
<>
{React.cloneElement(children, {
ref: refs.setReference,
...getReferenceProps(),
className: 'cursor-help',
})}
{(isMounted) && (
<div
ref={refs.setFloating}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
...styles,
}}
className='rounded-lg bg-white p-6 shadow-2xl dark:bg-gray-900 dark:ring-2 dark:ring-primary-700'
{...getFloatingProps()}
>
{content}
<FloatingArrow ref={arrowRef} context={context} className='fill-white dark:hidden' />
</div>
)}
</>
);
};
export default Popover;