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;