diff --git a/src/SelectInput/index.tsx b/src/SelectInput/index.tsx index 7df30183..995c31c1 100644 --- a/src/SelectInput/index.tsx +++ b/src/SelectInput/index.tsx @@ -211,6 +211,18 @@ export default React.forwardRef(function Selec onMouseDown?.(event); }); + // ===================== Clear ====================== + // The clear button lives inside the select root, whose `onKeyDown` treats + // Enter/Space as "open the dropdown" and calls `preventDefault` on them. + // That would cancel the native button activation, so keyboard users would + // never get the `click` event which performs the clear. Keep the activation + // keys scoped to the button itself. + const onClearKeyDown: React.KeyboardEventHandler = (event) => { + if (event.key === 'Enter' || event.key === ' ') { + event.stopPropagation(); + } + }; + // =================== Components =================== const { root: RootComponent } = components; @@ -298,6 +310,7 @@ export default React.forwardRef(function Selec e.preventDefault(); (e.nativeEvent as any)._select_lazy = true; }} + onKeyDown={onClearKeyDown} // Clearing happens on click so it works for both pointer and // keyboard (Enter/Space) activation. onClick={onClearMouseDown} diff --git a/tests/shared/allowClearTest.tsx b/tests/shared/allowClearTest.tsx index 012f79fc..8974d7f4 100644 --- a/tests/shared/allowClearTest.tsx +++ b/tests/shared/allowClearTest.tsx @@ -23,6 +23,7 @@ export default function allowClearTest(mode: any, value: any) { fireEvent(clear, mouseDownEvent); expect(mouseDownEvent.defaultPrevented).toBe(true); }); + it('clears value', () => { const onClear = jest.fn(); const onChange = jest.fn(); @@ -62,5 +63,47 @@ export default function allowClearTest(mode: any, value: any) { expect(container.querySelector('input').value).toEqual(''); expect(onClear).toHaveBeenCalled(); }); + + it('clears value with keyboard', () => { + ['Enter', ' '].forEach((key) => { + const onClear = jest.fn(); + const onChange = jest.fn(); + const onDeselect = jest.fn(); + const useArrayValue = ['tags', 'multiple'].includes(mode); + + const { container } = render( + , + ); + const clear = container.querySelector('.rc-select-clear'); + const keyDownEvent = createEvent.keyDown(clear, { key }); + + fireEvent(clear, keyDownEvent); + + expect(keyDownEvent.defaultPrevented).toBe(false); + expect(container.querySelector('.rc-select-open')).toBeFalsy(); + + // The native button activation should fire a click + fireEvent.click(clear); + + if (useArrayValue) { + expect(onChange).toHaveBeenCalledWith([], []); + } else { + expect(onChange).toHaveBeenCalledWith(undefined, undefined); + } + expect(onDeselect).not.toBeCalled(); + expect(container.querySelector('input').value).toEqual(''); + expect(onClear).toHaveBeenCalled(); + }); + }); }); }