From bf451a8c65ab24a3812fd16e1f176a977eddd223 Mon Sep 17 00:00:00 2001 From: Simon Guo Date: Tue, 17 Oct 2023 09:41:14 +0800 Subject: [PATCH] feat(Table): support table scrolling through keyboard arrow keys (#463) --- src/Table.tsx | 5 ++++- src/utils/useScrollListener.ts | 28 ++++++++++++++++++++++++++- test/TableSpec.js | 35 +++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/Table.tsx b/src/Table.tsx index 420060a..1b02aef 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -476,7 +476,8 @@ const Table = React.forwardRef((props: TableProps< onScrollBody, onScrollTop, onScrollLeft, - onScrollTo + onScrollTo, + onScrollByKeydown } = useScrollListener({ rtl, data: dataProp, @@ -1110,6 +1111,8 @@ const Table = React.forwardRef((props: TableProps< className={classes} style={styles} ref={tableRef} + tabIndex={-1} + onKeyDown={onScrollByKeydown} > {showHeader && renderTableHeader(headerCells, rowWidth)} {children && renderTableBody(bodyCells, rowWidth)} diff --git a/src/utils/useScrollListener.ts b/src/utils/useScrollListener.ts index 3b3e285..f12226c 100644 --- a/src/utils/useScrollListener.ts +++ b/src/utils/useScrollListener.ts @@ -504,6 +504,31 @@ const useScrollListener = (props: ScrollListenerProps) => { tableBodyRef ]); + const onScrollByKeydown = useCallback( + (event: React.KeyboardEvent) => { + if (event.currentTarget === event.target) { + event.preventDefault(); + const step = 40; + + switch (event.key) { + case 'ArrowUp': + onWheel(0, -step); + break; + case 'ArrowDown': + onWheel(0, step); + break; + case 'ArrowLeft': + onWheel(-step, 0); + break; + case 'ArrowRight': + onWheel(step, 0); + break; + } + } + }, + [onWheel] + ); + useMount(() => { if (rtl) { // Initialize scroll position @@ -526,7 +551,8 @@ const useScrollListener = (props: ScrollListenerProps) => { onScrollBody, onScrollTop, onScrollLeft, - onScrollTo + onScrollTo, + onScrollByKeydown }; }; diff --git a/test/TableSpec.js b/test/TableSpec.js index 65b681c..b8bfadc 100644 --- a/test/TableSpec.js +++ b/test/TableSpec.js @@ -1,5 +1,5 @@ import React from 'react'; -import { render, waitFor, act, fireEvent } from '@testing-library/react'; +import { render, waitFor, act, fireEvent, screen } from '@testing-library/react'; import getHeight from 'dom-lib/getHeight'; import getWidth from 'dom-lib/getWidth'; import Table from '../src/Table'; @@ -1391,4 +1391,37 @@ describe('Table', () => { expect(width).not.equal(100); expect(width).to.equal(instance.getBoundingClientRect().width); }); + + it('Should call `onScroll` callback when trigger keyboard event', () => { + const onScrollSpy = sinon.spy(); + render( + + + 11 + + + + 11 + + +
+ ); + + fireEvent.keyDown(screen.getByRole('grid'), { key: 'ArrowDown' }); + + expect(onScrollSpy).to.have.been.calledOnce; + expect(onScrollSpy).to.be.calledWith(0, 40); + + fireEvent.keyDown(screen.getByRole('grid'), { key: 'ArrowUp' }); + expect(onScrollSpy).to.have.been.calledTwice; + expect(onScrollSpy).to.be.calledWith(0, 0); + + fireEvent.keyDown(screen.getByRole('grid'), { key: 'ArrowRight' }); + expect(onScrollSpy).to.have.been.calledThrice; + expect(onScrollSpy).to.be.calledWith(40, 0); + + fireEvent.keyDown(screen.getByRole('grid'), { key: 'ArrowLeft' }); + expect(onScrollSpy).to.have.callCount(4); + expect(onScrollSpy).to.be.calledWith(0, 0); + }); });