Skip to content

Commit 203be96

Browse files
fix(ui): render popovers in portals to ensure they are on top of other ui elements
1 parent b0aa48d commit 203be96

File tree

11 files changed

+272
-226
lines changed

11 files changed

+272
-226
lines changed

invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarFill.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { Box, Flex, Popover, PopoverBody, PopoverContent, PopoverTrigger, Tooltip } from '@invoke-ai/ui-library';
1+
import {
2+
Box,
3+
Flex,
4+
Popover,
5+
PopoverBody,
6+
PopoverContent,
7+
PopoverTrigger,
8+
Portal,
9+
Tooltip,
10+
} from '@invoke-ai/ui-library';
211
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
312
import RgbColorPicker from 'common/components/ColorPicker/RgbColorPicker';
413
import { rgbColorToString } from 'common/util/colorCodeTransformers';
@@ -62,14 +71,16 @@ export const EntityListSelectedEntityActionBarFill = memo(() => {
6271
</Tooltip>
6372
</Flex>
6473
</PopoverTrigger>
65-
<PopoverContent>
66-
<PopoverBody minH={64}>
67-
<Flex flexDir="column" gap={4}>
68-
<RgbColorPicker color={fill.color} onChange={onChangeFillColor} withNumberInput withSwatches />
69-
<MaskFillStyle style={fill.style} onChange={onChangeFillStyle} />
70-
</Flex>
71-
</PopoverBody>
72-
</PopoverContent>
74+
<Portal>
75+
<PopoverContent>
76+
<PopoverBody minH={64}>
77+
<Flex flexDir="column" gap={4}>
78+
<RgbColorPicker color={fill.color} onChange={onChangeFillColor} withNumberInput withSwatches />
79+
<MaskFillStyle style={fill.style} onChange={onChangeFillStyle} />
80+
</Flex>
81+
</PopoverBody>
82+
</PopoverContent>
83+
</Portal>
7384
</Popover>
7485
);
7586
});

invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList/EntityListSelectedEntityActionBarOpacity.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
PopoverBody,
1313
PopoverContent,
1414
PopoverTrigger,
15+
Portal,
1516
} from '@invoke-ai/ui-library';
1617
import { createSelector } from '@reduxjs/toolkit';
1718
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -165,22 +166,24 @@ export const EntityListSelectedEntityActionBarOpacity = memo(() => {
165166
</NumberInput>
166167
</PopoverAnchor>
167168
</FormControl>
168-
<PopoverContent w={200} pt={0} pb={2} px={4}>
169-
<PopoverArrow />
170-
<PopoverBody>
171-
<CompositeSlider
172-
min={0}
173-
max={100}
174-
value={localOpacity}
175-
onChange={onChangeSlider}
176-
defaultValue={sliderDefaultValue}
177-
marks={marks}
178-
formatValue={formatSliderValue}
179-
alwaysShowMarks
180-
isDisabled={selectedEntityIdentifier === null}
181-
/>
182-
</PopoverBody>
183-
</PopoverContent>
169+
<Portal>
170+
<PopoverContent w={200} pt={0} pb={2} px={4}>
171+
<PopoverArrow />
172+
<PopoverBody>
173+
<CompositeSlider
174+
min={0}
175+
max={100}
176+
value={localOpacity}
177+
onChange={onChangeSlider}
178+
defaultValue={sliderDefaultValue}
179+
marks={marks}
180+
formatValue={formatSliderValue}
181+
alwaysShowMarks
182+
isDisabled={selectedEntityIdentifier === null}
183+
/>
184+
</PopoverBody>
185+
</PopoverContent>
186+
</Portal>
184187
</Popover>
185188
);
186189
});

invokeai/frontend/web/src/features/controlLayers/components/Settings/CanvasSettingsPopover.tsx

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
PopoverBody,
99
PopoverContent,
1010
PopoverTrigger,
11+
Portal,
1112
Text,
1213
useShiftModifier,
1314
} from '@invoke-ai/ui-library';
@@ -45,62 +46,64 @@ export const CanvasSettingsPopover = memo(() => {
4546
alignSelf="stretch"
4647
/>
4748
</PopoverTrigger>
48-
<PopoverContent maxW="280px">
49-
<PopoverArrow />
50-
<PopoverBody>
51-
<Flex direction="column" gap={2}>
52-
{/* Behavior Settings */}
53-
<Flex direction="column" gap={1}>
54-
<Flex align="center" gap={2}>
55-
<Icon as={PiPencilFill} boxSize={4} />
56-
<Text fontWeight="bold" fontSize="sm" color="base.100">
57-
{t('hotkeys.canvas.settings.behavior')}
58-
</Text>
49+
<Portal>
50+
<PopoverContent maxW="280px">
51+
<PopoverArrow />
52+
<PopoverBody>
53+
<Flex direction="column" gap={2}>
54+
{/* Behavior Settings */}
55+
<Flex direction="column" gap={1}>
56+
<Flex align="center" gap={2}>
57+
<Icon as={PiPencilFill} boxSize={4} />
58+
<Text fontWeight="bold" fontSize="sm" color="base.100">
59+
{t('hotkeys.canvas.settings.behavior')}
60+
</Text>
61+
</Flex>
62+
<CanvasSettingsInvertScrollCheckbox />
63+
<CanvasSettingsPressureSensitivityCheckbox />
64+
<CanvasSettingsPreserveMaskCheckbox />
65+
<CanvasSettingsClipToBboxCheckbox />
66+
<CanvasSettingsOutputOnlyMaskedRegionsCheckbox />
67+
<CanvasSettingsSaveAllImagesToGalleryCheckbox />
5968
</Flex>
60-
<CanvasSettingsInvertScrollCheckbox />
61-
<CanvasSettingsPressureSensitivityCheckbox />
62-
<CanvasSettingsPreserveMaskCheckbox />
63-
<CanvasSettingsClipToBboxCheckbox />
64-
<CanvasSettingsOutputOnlyMaskedRegionsCheckbox />
65-
<CanvasSettingsSaveAllImagesToGalleryCheckbox />
66-
</Flex>
6769

68-
<Divider />
70+
<Divider />
6971

70-
{/* Display Settings */}
71-
<Flex direction="column" gap={1}>
72-
<Flex align="center" gap={2} color="base.200">
73-
<Icon as={PiEyeFill} boxSize={4} />
74-
<Text fontWeight="bold" fontSize="sm">
75-
{t('hotkeys.canvas.settings.display')}
76-
</Text>
72+
{/* Display Settings */}
73+
<Flex direction="column" gap={1}>
74+
<Flex align="center" gap={2} color="base.200">
75+
<Icon as={PiEyeFill} boxSize={4} />
76+
<Text fontWeight="bold" fontSize="sm">
77+
{t('hotkeys.canvas.settings.display')}
78+
</Text>
79+
</Flex>
80+
<CanvasSettingsShowProgressOnCanvas />
81+
<CanvasSettingsIsolatedStagingPreviewSwitch />
82+
<CanvasSettingsIsolatedLayerPreviewSwitch />
83+
<CanvasSettingsBboxOverlaySwitch />
84+
<CanvasSettingsShowHUDSwitch />
7785
</Flex>
78-
<CanvasSettingsShowProgressOnCanvas />
79-
<CanvasSettingsIsolatedStagingPreviewSwitch />
80-
<CanvasSettingsIsolatedLayerPreviewSwitch />
81-
<CanvasSettingsBboxOverlaySwitch />
82-
<CanvasSettingsShowHUDSwitch />
83-
</Flex>
8486

85-
<Divider />
87+
<Divider />
8688

87-
{/* Grid Settings */}
88-
<Flex direction="column" gap={1}>
89-
<Flex align="center" gap={2} color="base.200">
90-
<Icon as={PiSquaresFourFill} boxSize={4} />
91-
<Text fontWeight="bold" fontSize="sm">
92-
{t('hotkeys.canvas.settings.grid')}
93-
</Text>
89+
{/* Grid Settings */}
90+
<Flex direction="column" gap={1}>
91+
<Flex align="center" gap={2} color="base.200">
92+
<Icon as={PiSquaresFourFill} boxSize={4} />
93+
<Text fontWeight="bold" fontSize="sm">
94+
{t('hotkeys.canvas.settings.grid')}
95+
</Text>
96+
</Flex>
97+
<CanvasSettingsSnapToGridCheckbox />
98+
<CanvasSettingsDynamicGridSwitch />
99+
<CanvasSettingsRuleOfThirdsSwitch />
94100
</Flex>
95-
<CanvasSettingsSnapToGridCheckbox />
96-
<CanvasSettingsDynamicGridSwitch />
97-
<CanvasSettingsRuleOfThirdsSwitch />
98-
</Flex>
99101

100-
<DebugSettings />
101-
</Flex>
102-
</PopoverBody>
103-
</PopoverContent>
102+
<DebugSettings />
103+
</Flex>
104+
</PopoverBody>
105+
</PopoverContent>
106+
</Portal>
104107
</Popover>
105108
);
106109
});

invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolFillColorPicker.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
PopoverBody,
77
PopoverContent,
88
PopoverTrigger,
9+
Portal,
910
Tooltip,
1011
} from '@invoke-ai/ui-library';
1112
import { createSelector } from '@reduxjs/toolkit';
@@ -102,12 +103,14 @@ export const ToolFillColorPicker = memo(() => {
102103
</Tooltip>
103104
</Flex>
104105
</PopoverTrigger>
105-
<PopoverContent>
106-
<PopoverArrow />
107-
<PopoverBody minH={64}>
108-
<RgbaColorPicker color={activeColor} onChange={onColorChange} withNumberInput withSwatches />
109-
</PopoverBody>
110-
</PopoverContent>
106+
<Portal>
107+
<PopoverContent>
108+
<PopoverArrow />
109+
<PopoverBody minH={64}>
110+
<RgbaColorPicker color={activeColor} onChange={onColorChange} withNumberInput withSwatches />
111+
</PopoverBody>
112+
</PopoverContent>
113+
</Portal>
111114
</Popover>
112115
);
113116
});

invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolWidthPicker.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
PopoverBody,
1313
PopoverContent,
1414
PopoverTrigger,
15+
Portal,
1516
} from '@invoke-ai/ui-library';
1617
import { createSelector } from '@reduxjs/toolkit';
1718
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -122,21 +123,23 @@ const DropDownToolWidthPickerComponent = memo(
122123
</NumberInput>
123124
</PopoverAnchor>
124125
</FormControl>
125-
<PopoverContent w={200} pt={0} pb={2} px={4}>
126-
<PopoverArrow />
127-
<PopoverBody>
128-
<CompositeSlider
129-
min={0}
130-
max={100}
131-
value={mapRawValueToSliderValue(localValue)}
132-
onChange={onChangeSlider}
133-
defaultValue={sliderDefaultValue}
134-
marks={marks}
135-
formatValue={formatSliderValue}
136-
alwaysShowMarks
137-
/>
138-
</PopoverBody>
139-
</PopoverContent>
126+
<Portal>
127+
<PopoverContent w={200} pt={0} pb={2} px={4}>
128+
<PopoverArrow />
129+
<PopoverBody>
130+
<CompositeSlider
131+
min={0}
132+
max={100}
133+
value={mapRawValueToSliderValue(localValue)}
134+
onChange={onChangeSlider}
135+
defaultValue={sliderDefaultValue}
136+
marks={marks}
137+
formatValue={formatSliderValue}
138+
alwaysShowMarks
139+
/>
140+
</PopoverBody>
141+
</PopoverContent>
142+
</Portal>
140143
</Popover>
141144
);
142145
}

invokeai/frontend/web/src/features/controlLayers/components/Toolbar/CanvasToolbarScale.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
PopoverBody,
1313
PopoverContent,
1414
PopoverTrigger,
15+
Portal,
1516
} from '@invoke-ai/ui-library';
1617
import { useStore } from '@nanostores/react';
1718
import { round } from 'es-toolkit/compat';
@@ -153,21 +154,23 @@ export const CanvasToolbarScale = memo(() => {
153154
</PopoverTrigger>
154155
</NumberInput>
155156
</PopoverAnchor>
156-
<PopoverContent w={200} pt={0} pb={2} px={4}>
157-
<PopoverArrow />
158-
<PopoverBody>
159-
<CompositeSlider
160-
min={0}
161-
max={100}
162-
value={mapRawValueToSliderValue(localScale)}
163-
onChange={onChangeSlider}
164-
defaultValue={sliderDefaultValue}
165-
marks={marks}
166-
formatValue={formatSliderValue}
167-
alwaysShowMarks
168-
/>
169-
</PopoverBody>
170-
</PopoverContent>
157+
<Portal>
158+
<PopoverContent w={200} pt={0} pb={2} px={4}>
159+
<PopoverArrow />
160+
<PopoverBody>
161+
<CompositeSlider
162+
min={0}
163+
max={100}
164+
value={mapRawValueToSliderValue(localScale)}
165+
onChange={onChangeSlider}
166+
defaultValue={sliderDefaultValue}
167+
marks={marks}
168+
formatValue={formatSliderValue}
169+
alwaysShowMarks
170+
/>
171+
</PopoverBody>
172+
</PopoverContent>
173+
</Portal>
171174
</Popover>
172175
<ZoomInButton />
173176
</Flex>

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldDescriptionPopover.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Popover,
66
PopoverContent,
77
PopoverTrigger,
8+
Portal,
89
Textarea,
910
} from '@invoke-ai/ui-library';
1011
import { useAppDispatch } from 'app/store/storeHooks';
@@ -36,9 +37,11 @@ export const InputFieldDescriptionPopover = memo(({ nodeId, fieldName }: Props)
3637
size="xs"
3738
/>
3839
</PopoverTrigger>
39-
<PopoverContent p={2} w={256}>
40-
<Content nodeId={nodeId} fieldName={fieldName} />
41-
</PopoverContent>
40+
<Portal>
41+
<PopoverContent p={2} w={256}>
42+
<Content nodeId={nodeId} fieldName={fieldName} />
43+
</PopoverContent>
44+
</Portal>
4245
</Popover>
4346
);
4447
});

0 commit comments

Comments
 (0)