From 8886e4f6a13f669f140b4b326818adc8449792fc Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Mon, 15 Sep 2025 11:42:31 +1000
Subject: [PATCH] fix(ui): render popovers in portals to ensure they are on top
of other ui elements
---
.../EntityListSelectedEntityActionBarFill.tsx | 29 ++--
...tityListSelectedEntityActionBarOpacity.tsx | 35 +++--
.../Settings/CanvasSettingsPopover.tsx | 99 ++++++------
.../components/Tool/ToolFillColorPicker.tsx | 15 +-
.../components/Tool/ToolWidthPicker.tsx | 33 ++--
.../components/Toolbar/CanvasToolbarScale.tsx | 33 ++--
.../fields/InputFieldDescriptionPopover.tsx | 9 +-
.../BottomLeftPanel/AutoLayoutPopover.tsx | 143 ++++++++++--------
.../PostProcessing/PostProcessingPopover.tsx | 33 ++--
.../web/src/features/prompt/PromptPopover.tsx | 28 ++--
.../features/ui/components/Notifications.tsx | 41 ++---
11 files changed, 272 insertions(+), 226 deletions(-)
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx
index 3004ddc0b8e..62928f2094f 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx
@@ -1,4 +1,13 @@
-import { Box, Flex, Popover, PopoverBody, PopoverContent, PopoverTrigger, Tooltip } from '@invoke-ai/ui-library';
+import {
+ Box,
+ Flex,
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+ Portal,
+ Tooltip,
+} from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import RgbColorPicker from 'common/components/ColorPicker/RgbColorPicker';
import { rgbColorToString } from 'common/util/colorCodeTransformers';
@@ -62,14 +71,16 @@ export const EntityListSelectedEntityActionBarFill = memo(() => {
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarOpacity.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarOpacity.tsx
index 29720212be0..7e38cdd9fda 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarOpacity.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarOpacity.tsx
@@ -12,6 +12,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
} from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -165,22 +166,24 @@ export const EntityListSelectedEntityActionBarOpacity = memo(() => {
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
index c2eba6db1dd..31ce8bd88a7 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx
@@ -8,6 +8,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
Text,
useShiftModifier,
} from '@invoke-ai/ui-library';
@@ -45,62 +46,64 @@ export const CanvasSettingsPopover = memo(() => {
alignSelf="stretch"
/>
-
-
-
-
- {/* Behavior Settings */}
-
-
-
-
- {t('hotkeys.canvas.settings.behavior')}
-
+
+
+
+
+
+ {/* Behavior Settings */}
+
+
+
+
+ {t('hotkeys.canvas.settings.behavior')}
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
- {/* Display Settings */}
-
-
-
-
- {t('hotkeys.canvas.settings.display')}
-
+ {/* Display Settings */}
+
+
+
+
+ {t('hotkeys.canvas.settings.display')}
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
- {/* Grid Settings */}
-
-
-
-
- {t('hotkeys.canvas.settings.grid')}
-
+ {/* Grid Settings */}
+
+
+
+
+ {t('hotkeys.canvas.settings.grid')}
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx
index 1fa70434dfa..c192687e2e9 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx
@@ -6,6 +6,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
Tooltip,
} from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
@@ -102,12 +103,14 @@ export const ToolFillColorPicker = memo(() => {
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx
index a74d750ae02..3fa270893a3 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx
@@ -12,6 +12,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
} from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -122,21 +123,23 @@ const DropDownToolWidthPickerComponent = memo(
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
}
diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx
index 484dcc9d1fc..85dfccbf82d 100644
--- a/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx
+++ b/invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx
@@ -12,6 +12,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
} from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { round } from 'es-toolkit/compat';
@@ -153,21 +154,23 @@ export const CanvasToolbarScale = memo(() => {
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldDescriptionPopover.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldDescriptionPopover.tsx
index 6b020a221c4..5aa236a7bda 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldDescriptionPopover.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldDescriptionPopover.tsx
@@ -5,6 +5,7 @@ import {
Popover,
PopoverContent,
PopoverTrigger,
+ Portal,
Textarea,
} from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
@@ -36,9 +37,11 @@ export const InputFieldDescriptionPopover = memo(({ nodeId, fieldName }: Props)
size="xs"
/>
-
-
-
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/AutoLayoutPopover.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/AutoLayoutPopover.tsx
index e2366e4cdd2..10609fbc267 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/AutoLayoutPopover.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/BottomLeftPanel/AutoLayoutPopover.tsx
@@ -13,6 +13,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
Select,
} from '@invoke-ai/ui-library';
import { useReactFlow } from '@xyflow/react';
@@ -120,74 +121,82 @@ export const AutoLayoutPopover = memo(() => {
onClick={popover.toggle}
/>
-
-
+
+
+
-
-
-
- {t('nodes.layout.layoutDirection')}
-
-
-
- {t('nodes.layout.layeringStrategy')}
-
-
-
- {t('nodes.layout.alignment')}
-
-
-
-
- {t('nodes.layout.nodeSpacing')}
-
-
-
-
-
-
- {t('nodes.layout.layerSpacing')}
-
-
-
-
-
-
-
-
-
-
+
+
+
+ {t('nodes.layout.layoutDirection')}
+
+
+
+ {t('nodes.layout.layeringStrategy')}
+
+
+
+ {t('nodes.layout.alignment')}
+
+
+
+
+ {t('nodes.layout.nodeSpacing')}
+
+
+
+
+
+
+ {t('nodes.layout.layerSpacing')}
+
+
+
+
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx b/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx
index 2eb68b4b6b1..0a98817bffe 100644
--- a/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx
@@ -6,6 +6,7 @@ import {
PopoverBody,
PopoverContent,
PopoverTrigger,
+ Portal,
Text,
useDisclosure,
} from '@invoke-ai/ui-library';
@@ -52,21 +53,23 @@ export const PostProcessingPopover = memo((props: Props) => {
isDisabled={isDisabled}
/>
-
-
-
-
- {!postProcessingModel && }
-
-
-
-
+
+
+
+
+
+ {!postProcessingModel && }
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/prompt/PromptPopover.tsx b/invokeai/frontend/web/src/features/prompt/PromptPopover.tsx
index 685df7ae738..a9d21cd909f 100644
--- a/invokeai/frontend/web/src/features/prompt/PromptPopover.tsx
+++ b/invokeai/frontend/web/src/features/prompt/PromptPopover.tsx
@@ -1,4 +1,4 @@
-import { Popover, PopoverAnchor, PopoverBody, PopoverContent } from '@invoke-ai/ui-library';
+import { Popover, PopoverAnchor, PopoverBody, PopoverContent, Portal } from '@invoke-ai/ui-library';
import { PromptTriggerSelect } from 'features/prompt/PromptTriggerSelect';
import type { PromptPopoverProps } from 'features/prompt/types';
import { memo } from 'react';
@@ -18,18 +18,20 @@ export const PromptPopover = memo((props: PromptPopoverProps) => {
isLazy
>
{children}
-
-
-
-
-
+
+
+
+
+
+
+
);
});
diff --git a/invokeai/frontend/web/src/features/ui/components/Notifications.tsx b/invokeai/frontend/web/src/features/ui/components/Notifications.tsx
index ca11e3ce210..8a08b5086db 100644
--- a/invokeai/frontend/web/src/features/ui/components/Notifications.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/Notifications.tsx
@@ -9,6 +9,7 @@ import {
PopoverContent,
PopoverHeader,
PopoverTrigger,
+ Portal,
Text,
} from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
@@ -54,25 +55,27 @@ export const Notifications = () => {
/>
-
-
-
-
-
-
- {t('whatsNew.whatsNewInInvoke')}
- {!!data.version.length &&
- (isLocal ? (
- {`v${data.version}`}
- ) : (
- {data.version}
- ))}
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {t('whatsNew.whatsNewInInvoke')}
+ {!!data.version.length &&
+ (isLocal ? (
+ {`v${data.version}`}
+ ) : (
+ {data.version}
+ ))}
+
+
+
+
+
+
+
);
};