diff --git a/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.spec.tsx b/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.spec.tsx index b9bc471acdc..e49dc563406 100644 --- a/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.spec.tsx +++ b/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.spec.tsx @@ -23,6 +23,24 @@ describe('InPlaceEditor', () => { fireEvent.blur(input); await screen.findByText('Jane Doe'); }); + + it('should save when focus moves to an element outside the editor', async () => { + const { container } = render(); + + const value = await screen.findByText('John Doe'); + value.click(); + + const input = await screen.findByDisplayValue('John Doe'); + fireEvent.change(input, { target: { value: 'Jane Doe' } }); + + const outsideButton = document.createElement('button'); + outsideButton.textContent = 'Next'; + container.appendChild(outsideButton); + + fireEvent.blur(input, { relatedTarget: outsideButton }); + + await screen.findByText('Jane Doe'); + }); it('should revert to the previous version on error', async () => { jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.tsx b/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.tsx index d8756b61b12..6ebbf056fdd 100644 --- a/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.tsx +++ b/packages/ra-ui-materialui/src/input/InPlaceEditor/InPlaceEditor.tsx @@ -197,16 +197,27 @@ export const InPlaceEditor = < const handleBlur = (event: React.FocusEvent) => { if (event.relatedTarget) { - return; + // Focus moved to an element inside the editor — ignore + if (event.currentTarget.contains(event.relatedTarget as Node)) { + return; + } + // Focus moved to a MUI portal (e.g. Select dropdown) — ignore + if ( + (event.relatedTarget as HTMLElement).closest?.( + '.MuiPopover-root, .MuiModal-root, .MuiMenu-root' + ) + ) { + return; + } } + if (cancelOnBlur) { dispatch({ type: 'cancel' }); return; } + if (state.state === 'editing') { - // trigger the parent form submit - // to save the changes - (submitButtonRef.current as HTMLButtonElement).click(); + (submitButtonRef.current as HTMLButtonElement)?.click(); } };