(null);
- usePopper({
- contents: menuRef,
- reference: buttonRef,
- placement,
- offset,
- fixed,
- });
+ usePopper(
+ {
+ contents: menuRef,
+ reference: buttonRef,
+ placement,
+ offset,
+ fixed,
+ },
+ [isOpen, items],
+ );
return (
diff --git a/src/app/dim-ui/PressTip.tsx b/src/app/dim-ui/PressTip.tsx
index 2bf4c71d6d..35a07706bb 100644
--- a/src/app/dim-ui/PressTip.tsx
+++ b/src/app/dim-ui/PressTip.tsx
@@ -93,12 +93,15 @@ function Control({
const pressTipRoot = useContext(PressTipRoot);
const [customization, customizeTooltip] = useState({ className: null });
- usePopper({
- contents: tooltipContents,
- reference: triggerRef,
- arrowClassName: styles.arrow,
- placement,
- });
+ usePopper(
+ {
+ contents: tooltipContents,
+ reference: triggerRef,
+ arrowClassName: styles.arrow,
+ placement,
+ },
+ [open],
+ );
if (!tooltip) {
const { style } = rest;
diff --git a/src/app/dim-ui/Select.tsx b/src/app/dim-ui/Select.tsx
index 542f52e761..57760ce996 100644
--- a/src/app/dim-ui/Select.tsx
+++ b/src/app/dim-ui/Select.tsx
@@ -79,12 +79,15 @@ export default function Select({
);
const [dropdownHeight, setDropdownHeight] = useState();
- usePopper({
- contents: menuRef,
- reference: buttonRef,
- placement: 'bottom-start',
- offset: 2,
- });
+ usePopper(
+ {
+ contents: menuRef,
+ reference: buttonRef,
+ placement: 'bottom-start',
+ offset: 2,
+ },
+ [isOpen, items],
+ );
if (!selectedItem) {
throw new Error('value must correspond to one of the provided options');
diff --git a/src/app/dim-ui/usePopper.ts b/src/app/dim-ui/usePopper.ts
index 22d674de9c..32944af420 100644
--- a/src/app/dim-ui/usePopper.ts
+++ b/src/app/dim-ui/usePopper.ts
@@ -97,35 +97,38 @@ const popperOptions = (
};
};
-export function usePopper({
- contents,
- reference,
- arrowClassName,
- menuClassName,
- boundarySelector,
- placement,
- offset,
- fixed,
- padding,
-}: {
- /** A ref to the rendered contents of a popper-positioned item */
- contents: React.RefObject;
- /** An ref to the item that triggered the popper, which anchors it */
- reference: React.RefObject;
- /** A class used to identify the arrow */
- arrowClassName?: string;
- /** A class used to identify the sidecar menu */
- menuClassName?: string;
- /** An optional additional selector for a "boundary area" */
- boundarySelector?: string;
- /** Placement preference of the popper. Defaults to "auto" */
- placement?: Placement;
- /** Offset of how far from the element to shift the popper. */
- offset?: number;
- /** Is this placed on a fixed item? Workaround for https://github.com/popperjs/popper-core/issues/1156. TODO: make a "positioning context" context value for this */
- fixed?: boolean;
- padding?: Padding;
-}) {
+export function usePopper(
+ {
+ contents,
+ reference,
+ arrowClassName,
+ menuClassName,
+ boundarySelector,
+ placement,
+ offset,
+ fixed,
+ padding,
+ }: {
+ /** A ref to the rendered contents of a popper-positioned item */
+ contents: React.RefObject;
+ /** An ref to the item that triggered the popper, which anchors it */
+ reference: React.RefObject;
+ /** A class used to identify the arrow */
+ arrowClassName?: string;
+ /** A class used to identify the sidecar menu */
+ menuClassName?: string;
+ /** An optional additional selector for a "boundary area" */
+ boundarySelector?: string;
+ /** Placement preference of the popper. Defaults to "auto" */
+ placement?: Placement;
+ /** Offset of how far from the element to shift the popper. */
+ offset?: number;
+ /** Is this placed on a fixed item? Workaround for https://github.com/popperjs/popper-core/issues/1156. TODO: make a "positioning context" context value for this */
+ fixed?: boolean;
+ padding?: Padding;
+ },
+ deps: React.DependencyList = [],
+) {
const popper = useRef();
const destroy = () => {
@@ -160,5 +163,24 @@ export function usePopper({
}
return destroy;
- });
+ }, [
+ contents,
+ reference,
+ arrowClassName,
+ menuClassName,
+ boundarySelector,
+ placement,
+ offset,
+ fixed,
+ padding,
+
+ /**
+ * Doing ...deps allows us to pass dependencies from the components that rely on
+ * usePopper. Certain popovers are only shown when specific conditions are met,
+ * so by making those conditions dependencies we can position the popover
+ * correctly once the popover is actually shown.
+ */
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ ...deps,
+ ]);
}