diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx index 8b81be33bf0..9f13e67918b 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx @@ -12,6 +12,24 @@ describe('ColorPickerInput', () => { expect(screen.getByTestId('color-popover')).toBeInTheDocument(); }); + it('should hide color popover on blur', async () => { + render(); + expect(screen.queryByTestId('color-popover')).not.toBeInTheDocument(); + await userEvent.click(screen.getByRole('textbox')); + expect(screen.getByTestId('color-popover')).toBeInTheDocument(); + await userEvent.click(document.body); + expect(screen.queryByTestId('color-popover')).not.toBeInTheDocument(); + }); + + it('should not hide color popover on blur if clicked inside the color picker', async () => { + render(); + expect(screen.queryByTestId('color-popover')).not.toBeInTheDocument(); + await userEvent.click(screen.getByRole('textbox')); + expect(screen.getByTestId('color-popover')).toBeInTheDocument(); + await userEvent.click(screen.getAllByRole('slider')[0]); + expect(screen.queryByTestId('color-popover')).toBeInTheDocument(); + }); + it('should pass correct color to onChange callback', async () => { const mockOnChange = jest.fn(); render(); diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx index add799af11c..381ad0403b2 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx @@ -1,5 +1,5 @@ import { css, cx } from '@emotion/css'; -import { useState, forwardRef } from 'react'; +import { useState, forwardRef, FocusEvent } from 'react'; import { RgbaStringColorPicker } from 'react-colorful'; import { useThrottleFn } from 'react-use'; @@ -48,6 +48,14 @@ export const ColorPickerInput = forwardRef) => { + // Unless the user clicked inside the color picker, close it on blur + const isClickInPopover = document.querySelector('[data-testid="color-popover"]')?.contains(evt.relatedTarget); + if (!isClickInPopover) { + setIsOpen(false); + } + }; + return ( setIsOpen(false)}> @@ -66,7 +74,7 @@ export const ColorPickerInput = forwardRef setIsOpen(true)} - onBlur={() => setIsOpen(false)} + onBlur={(e) => handleBlur(e)} ref={ref} isClearable />