Skip to content

Commit f6cc373

Browse files
authored
bug(preprod): Fix overlay color selection (#110772)
Fixes overlay color selection. The inherent issue is the overlay selection being in a tooltip prevented the clicking on the specific swatch buttons. This now leverages a more custom component to handle the overlay. Resolves EME-954. <img width="788" height="1062" alt="Screenshot 2026-03-16 at 11 25 04 AM" src="https://github.com/user-attachments/assets/6dc1971b-25f2-45fe-bf33-9a40a58e5a88" />
1 parent 342dcbb commit f6cc373

1 file changed

Lines changed: 65 additions & 26 deletions

File tree

static/app/views/preprod/snapshots/main/snapshotMainContent.tsx

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import {useEffect, useRef, useState} from 'react';
12
import {useTheme} from '@emotion/react';
23
import styled from '@emotion/styled';
34

45
import {Button} from '@sentry/scraps/button';
56
import {Flex, Stack} from '@sentry/scraps/layout';
67
import {Separator} from '@sentry/scraps/separator';
78
import {Text} from '@sentry/scraps/text';
8-
import {Tooltip} from '@sentry/scraps/tooltip';
99

1010
import {IconChevron} from 'sentry/icons';
1111
import {t} from 'sentry/locale';
@@ -168,9 +168,25 @@ function OverlayControls({
168168
showOverlay: boolean;
169169
}) {
170170
const theme = useTheme();
171+
const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);
172+
const pickerRef = useRef<HTMLDivElement>(null);
171173

172174
const overlayColors = theme.chart.getColorPalette(10);
173175

176+
useEffect(() => {
177+
if (!isColorPickerOpen) {
178+
return undefined;
179+
}
180+
181+
function handleMouseDown(e: MouseEvent) {
182+
if (pickerRef.current && !pickerRef.current.contains(e.target as Node)) {
183+
setIsColorPickerOpen(false);
184+
}
185+
}
186+
document.addEventListener('mousedown', handleMouseDown);
187+
return () => document.removeEventListener('mousedown', handleMouseDown);
188+
}, [isColorPickerOpen]);
189+
174190
return (
175191
<Flex align="center" gap="sm">
176192
<Button
@@ -180,52 +196,75 @@ function OverlayControls({
180196
>
181197
{showOverlay ? t('Hide Overlay') : t('Show Overlay')}
182198
</Button>
183-
<Tooltip
184-
isHoverable
185-
maxWidth={400}
186-
title={
187-
<Flex gap="xs">
188-
{overlayColors.map(color => (
189-
<ColorSwatch
190-
key={color}
191-
$color={color}
192-
$selected={overlayColor === color}
193-
onClick={() => onOverlayColorChange(color)}
194-
aria-label={t('Overlay color %s', color)}
195-
/>
196-
))}
197-
</Flex>
198-
}
199-
>
200-
<ColorTrigger $color={overlayColor} aria-label={t('Pick overlay color')} />
201-
</Tooltip>
199+
<ColorPickerWrapper ref={pickerRef}>
200+
<ColorTrigger
201+
color={overlayColor}
202+
aria-label={t('Pick overlay color')}
203+
onClick={() => setIsColorPickerOpen(open => !open)}
204+
/>
205+
{isColorPickerOpen && (
206+
<ColorPickerDropdown>
207+
<Flex gap="xs">
208+
{overlayColors.map(color => (
209+
<ColorSwatch
210+
key={color}
211+
color={color}
212+
selected={overlayColor === color}
213+
onClick={() => {
214+
onOverlayColorChange(color);
215+
setIsColorPickerOpen(false);
216+
}}
217+
aria-label={t('Overlay color %s', color)}
218+
/>
219+
))}
220+
</Flex>
221+
</ColorPickerDropdown>
222+
)}
223+
</ColorPickerWrapper>
202224
</Flex>
203225
);
204226
}
205227

206-
const ColorTrigger = styled('button')<{$color: string}>`
228+
const ColorPickerWrapper = styled('div')`
229+
position: relative;
230+
`;
231+
232+
const ColorPickerDropdown = styled('div')`
233+
position: absolute;
234+
top: 100%;
235+
right: 0;
236+
margin-top: ${p => p.theme.space.xs};
237+
padding: ${p => p.theme.space.sm};
238+
background: ${p => p.theme.tokens.background.primary};
239+
border: 1px solid ${p => p.theme.tokens.border.primary};
240+
border-radius: ${p => p.theme.radius.md};
241+
box-shadow: ${p => p.theme.dropShadowHeavy};
242+
z-index: ${p => p.theme.zIndex.dropdown};
243+
`;
244+
245+
const ColorTrigger = styled('button')<{color: string}>`
207246
width: 24px;
208247
height: 24px;
209248
border-radius: 50%;
210249
cursor: pointer;
211250
border: 2px solid ${p => p.theme.tokens.border.primary};
212-
background-color: ${p => p.$color};
251+
background-color: ${p => p.color};
213252
padding: 0;
214253
215254
&:hover {
216255
border-color: ${p => p.theme.tokens.border.accent};
217256
}
218257
`;
219258

220-
const ColorSwatch = styled('button')<{$color: string; $selected: boolean}>`
259+
const ColorSwatch = styled('button')<{color: string; selected: boolean}>`
221260
width: 20px;
222261
height: 20px;
223262
border-radius: 50%;
224263
cursor: pointer;
225264
border: 2px solid
226-
${p => (p.$selected ? p.theme.tokens.border.accent : p.theme.tokens.border.primary)};
227-
background-color: ${p => p.$color};
265+
${p => (p.selected ? p.theme.tokens.border.accent : p.theme.tokens.border.primary)};
266+
background-color: ${p => p.color};
228267
padding: 0;
229-
outline: ${p => (p.$selected ? `2px solid ${p.theme.tokens.focus.default}` : 'none')};
268+
outline: ${p => (p.selected ? `2px solid ${p.theme.tokens.focus.default}` : 'none')};
230269
outline-offset: 1px;
231270
`;

0 commit comments

Comments
 (0)