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} + ))} + + + + + + + ); };