diff --git a/src/ColorPicker/ColorPicker.test.jsx b/src/ColorPicker/ColorPicker.test.jsx
index a79a24126e..7f156f51ea 100644
--- a/src/ColorPicker/ColorPicker.test.jsx
+++ b/src/ColorPicker/ColorPicker.test.jsx
@@ -29,13 +29,35 @@ describe('picker works as expected', () => {
const color = 'wassap';
const setColor = jest.fn();
it('validates hex color', async () => {
- const { rerender } = render();
+ render();
+
await act(async () => {
await userEvent.click(screen.getByRole('button'));
});
+ expect(screen.queryByTestId('hex-input').value).toEqual('#wassap');
expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
- rerender();
+ await act(async () => {
+ await userEvent.clear(screen.getByTestId('hex-input'));
+ await userEvent.paste(screen.getByTestId('hex-input'), '32116c');
+ });
+ expect(screen.queryByTestId('hex-input').value).toEqual('#32116c');
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
+
+ await act(async () => {
+ await userEvent.clear(screen.getByTestId('hex-input'));
+ await userEvent.paste(screen.getByTestId('hex-input'), 'yuk');
+ });
+
+ expect(screen.queryByTestId('hex-input').value).toEqual('#yuk');
+ expect(screen.queryByText('Colors must be in hexadecimal format.')).toBeInTheDocument();
+
+ await act(async () => {
+ await userEvent.clear(screen.getByTestId('hex-input'));
+ await userEvent.paste(screen.getByTestId('hex-input'), '#fad');
+ });
+
+ expect(screen.queryByTestId('hex-input').value).toEqual('#fad');
expect(screen.queryByText('Colors must be in hexadecimal format.')).not.toBeInTheDocument();
});
});
diff --git a/src/ColorPicker/index.jsx b/src/ColorPicker/index.jsx
index 1cef1c336b..2877ec6f23 100644
--- a/src/ColorPicker/index.jsx
+++ b/src/ColorPicker/index.jsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { HexColorPicker } from 'react-colorful';
@@ -15,24 +15,63 @@ function ColorPicker({
}) {
const [isOpen, open, close] = useToggle(false);
const [target, setTarget] = React.useState(null);
- const [hexValid, setHexValid] = React.useState(true);
- const validateHex = useCallback((input) => {
+ const colorIsValid = (colorToValidate) => {
const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
- if (input.length > 1 && !input.startsWith('#')) {
- setColor(`#${input}`);
- } else {
- setColor(input);
+ return hexRegex.test(colorToValidate);
+ };
+
+ const formatHexColorString = (colorString) => {
+ if (!colorString.startsWith('#')) {
+ return `#${colorString}`.slice(0, 7);
+ }
+
+ return colorString.slice(0, 7);
+ };
+
+ const [hexValid, setHexValid] = React.useState(() => (color === '' || colorIsValid(formatHexColorString(color))));
+
+ const [hexColorString, setHexColorString] = React.useState(() => {
+ if (color === '') {
+ return '';
+ }
+
+ return formatHexColorString(color);
+ });
+ const [colorToDisplay, setColorToDisplay] = React.useState(() => {
+ const formattedColor = formatHexColorString(color);
+ if (colorIsValid(formattedColor)) {
+ return formattedColor;
}
- if (input === '' || hexRegex.test(input) === true) {
+
+ return '#fff';
+ });
+
+ const setValidatedColor = (newColor) => {
+ if (newColor === '') {
setHexValid(true);
- } else {
- setHexValid(false);
+ setColor('');
+ setHexColorString('');
+ setColorToDisplay('#fff');
+ return;
}
- }, [setColor]);
- // this is needed for when a user changes the color through the sliders
- useEffect(() => validateHex(color), [validateHex, color]);
+ const formattedColor = formatHexColorString(newColor);
+
+ if (colorIsValid(formattedColor)) {
+ setHexValid(true);
+ setColor(formattedColor);
+ setHexColorString(formattedColor);
+ setColorToDisplay(formattedColor);
+ return;
+ }
+
+ setHexValid(false);
+ setHexColorString(formattedColor);
+
+ // ensure the picker value stays in sync with the textbox
+ setColor(formattedColor);
+ };
return (
<>
@@ -65,16 +104,17 @@ function ColorPicker({
className="pgn__color-modal rounded shadow"
style={{ textAlign: 'start' }}
>
-
+
Hex
validateHex(e.target.value)}
+ value={hexColorString}
+ onChange={(e) => setValidatedColor(e.target.value)}
data-testid="hex-input"
+ spellCheck="false"
/>
{!hexValid && (