diff --git a/.changeset/rich-ghosts-push.md b/.changeset/rich-ghosts-push.md new file mode 100644 index 00000000000..1dc96cba0e9 --- /dev/null +++ b/.changeset/rich-ghosts-push.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': patch +--- + +Fixed `TextField` blurring when interacting with the `Spinner` buttons diff --git a/polaris-react/src/components/TextField/TextField.tsx b/polaris-react/src/components/TextField/TextField.tsx index b28f52d6692..9cc08df151a 100644 --- a/polaris-react/src/components/TextField/TextField.tsx +++ b/polaris-react/src/components/TextField/TextField.tsx @@ -249,6 +249,7 @@ export function TextField({ const uniqId = useId(); const id = idProp ?? uniqId; + const textFieldRef = useRef(null); const inputRef = useRef(null); const textAreaRef = useRef(null); const prefixRef = useRef(null); @@ -603,7 +604,7 @@ export function TextField({ readOnly={readOnly} > -
+
{prefixMarkup} {inputMarkup} {suffixMarkup} @@ -736,6 +737,11 @@ export function TextField({ function handleOnBlur(event: React.FocusEvent) { setFocus(false); + // Return early if new focus target is inside the TextField component + if (textFieldRef.current?.contains(event?.relatedTarget)) { + return; + } + if (onBlur) { onBlur(event); } diff --git a/polaris-react/src/components/TextField/tests/TextField.test.tsx b/polaris-react/src/components/TextField/tests/TextField.test.tsx index e2f79273f24..7f137dac812 100644 --- a/polaris-react/src/components/TextField/tests/TextField.test.tsx +++ b/polaris-react/src/components/TextField/tests/TextField.test.tsx @@ -227,6 +227,55 @@ describe('', () => { element.find('input')!.trigger('onBlur'); expect(spy).toHaveBeenCalled(); }); + + it('is called when the Spinner is blurred', () => { + const spy = jest.fn(); + const element = mountWithApp( + , + ); + element.find(Spinner)!.trigger('onBlur'); + expect(spy).toHaveBeenCalled(); + }); + + it('is not called when the input is blurred and focus moves to the Spinner', () => { + const spy = jest.fn(); + const element = mountWithApp( + , + ); + const relatedTarget = element.find(Spinner)!.domNode; + + element.find('input')!.trigger('onBlur', {relatedTarget}); + expect(spy).not.toHaveBeenCalled(); + }); + + it('is not called when the Spinner is blurred and focus moves to the input', () => { + const spy = jest.fn(); + const element = mountWithApp( + , + ); + const relatedTarget = element.find('input')!.domNode; + + element.find(Spinner)!.trigger('onBlur', {relatedTarget}); + expect(spy).not.toHaveBeenCalled(); + }); }); describe('id', () => {