github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/components/dashboards/layout/Panel/PanelControls.tsx (about) 1 import Icon from "../../../Icon"; 2 import { createPortal } from "react-dom"; 3 import { ThemeProvider, ThemeWrapper } from "../../../../hooks/useTheme"; 4 import { useMemo, useState } from "react"; 5 import { usePopper } from "react-popper"; 6 7 export type IPanelControl = { 8 action: (e: any) => Promise<void>; 9 icon: string; 10 title: string; 11 }; 12 13 const PanelControl = ({ action, icon, title }: IPanelControl) => { 14 return ( 15 <div 16 className="p-1.5 cursor-pointer bg-dashboard-panel text-foreground first:rounded-tl-[4px] first:rounded-bl-[4px] last:rounded-tr-[4px] last:rounded-br-[4px] hover:bg-dashboard" 17 onClick={async (e) => await action(e)} 18 title={title} 19 > 20 <Icon className="w-4.5 h-4.5" icon={icon} /> 21 </div> 22 ); 23 }; 24 25 const PanelControls = ({ controls, referenceElement }) => { 26 const [popperElement, setPopperElement] = useState(null); 27 // Need to define memoized / stable modifiers else the usePopper hook will infinitely re-render 28 const noFlip = useMemo(() => ({ name: "flip", enabled: false }), []); 29 const offset = useMemo( 30 () => ({ 31 name: "offset", 32 options: { 33 // For some reason the height of the popper is not correct unless scrollbars are visible. 34 // I've sunk too much time trying to find the root cause, but luckily I only 35 // need to modify this along a fixed offset, so can hard-code this for now. 36 offset: [-14.125, -14.125], 37 // offset: ({ popper }) => { 38 // const offset = -popper.height / 2; 39 // return [offset, offset]; 40 // }, 41 }, 42 }), 43 [] 44 ); 45 const { styles, attributes } = usePopper(referenceElement, popperElement, { 46 modifiers: [noFlip, offset], 47 placement: "top-end", 48 }); 49 50 return createPortal( 51 <ThemeProvider> 52 <ThemeWrapper> 53 <div 54 // @ts-ignore 55 ref={setPopperElement} 56 style={{ ...styles.popper }} 57 {...attributes.popper} 58 > 59 <div className="flex border border-black-scale-3 rounded-md"> 60 {controls.map((control, idx) => ( 61 <PanelControl 62 key={idx} 63 action={control.action} 64 icon={control.icon} 65 title={control.title} 66 /> 67 ))} 68 </div> 69 </div> 70 </ThemeWrapper> 71 </ThemeProvider>, 72 // @ts-ignore as this element definitely exists 73 document.getElementById("portals") 74 ); 75 }; 76 77 export default PanelControls;