diff --git a/src/Panel.tsx b/src/Panel.tsx index 9373570..6c17c2b 100644 --- a/src/Panel.tsx +++ b/src/Panel.tsx @@ -39,8 +39,16 @@ const CollapsePanel = React.forwardRef((prop onItemClick?.(panelKey); }, onKeyDown: (e: React.KeyboardEvent) => { + // Leave key events from nested controls (e.g. a button in `extra`) to those controls + if (e.target !== e.currentTarget) { + return; + } if (e.key === 'Enter' || e.keyCode === KeyCode.ENTER || e.which === KeyCode.ENTER) { onItemClick?.(panelKey); + } else if (e.key === ' ') { + // Prevent the page from scrolling, like a native button + e.preventDefault(); + onItemClick?.(panelKey); } }, role: accordion ? 'tab' : 'button', diff --git a/tests/index.spec.tsx b/tests/index.spec.tsx index c91c7d9..7c5d420 100644 --- a/tests/index.spec.tsx +++ b/tests/index.spec.tsx @@ -445,6 +445,47 @@ describe('collapse', () => { ); }); + it('should toggle panel when press space', () => { + const { container } = render( + + + first + + + second + + , + ); + const [header, disabledHeader] = container.querySelectorAll('.rc-collapse-header'); + + fireEvent.keyDown(disabledHeader, { key: ' ' }); + jest.runAllTimers(); + expect(container.querySelectorAll('.rc-collapse-panel-active')).toHaveLength(0); + + // `fireEvent` returns false when the default action (page scroll) is prevented + expect(fireEvent.keyDown(header, { key: ' ' })).toBe(false); + jest.runAllTimers(); + expect(container.querySelector('.rc-collapse-panel')).toHaveClass('rc-collapse-panel-active'); + + fireEvent.keyDown(header, { key: ' ' }); + jest.runAllTimers(); + expect(container.querySelectorAll('.rc-collapse-panel-active')).toHaveLength(0); + }); + + it('should leave keyboard events on a nested extra button to the button', () => { + const { getByRole, container } = render( + Action, children: 'Content' }]} + />, + ); + const button = getByRole('button', { name: 'Action' }); + + expect(fireEvent.keyDown(button, { key: ' ' })).toBe(true); + fireEvent.keyDown(button, { key: 'Enter', keyCode: KeyCode.ENTER }); + jest.runAllTimers(); + expect(container.querySelectorAll('.rc-collapse-panel-active')).toHaveLength(0); + }); + it('should link the header to its panel with aria-controls', () => { const { container } = render(