@@ -125,18 +125,23 @@ function useTable<TData>(
125125 return [ table , columnVisibility , setColumnVisibility , columnOrder , setColumnOrder , columnSizing , sorting ] ;
126126}
127127
128+ interface HIDEvent {
129+ modKey : boolean ,
130+ shiftKey : boolean ,
131+ isRmb : boolean ,
132+ }
133+
128134function useSelectHandler < TData > (
129135 table : Table < TData > ,
130136 selectedReducer : TableSelectReducer ,
131137 getRowId : ( row : TData ) => string ,
132138 setCurrent ?: ( id : string ) => void ,
133- ) : [ number , ( event : React . MouseEvent < Element > , index : number , lastIndex : number ) => void ] {
139+ ) : [ number , ( event : HIDEvent , index : number , lastIndex : number ) => void ] {
134140 const [ lastIndex , setLastIndex ] = useState ( - 1 ) ;
135141
136- const onRowClick = useCallback ( ( event : React . MouseEvent < Element > , index : number , lastIndex : number ) => {
142+ const onRowClick = useCallback ( ( event : HIDEvent , index : number , lastIndex : number ) => {
137143 const rows = table . getRowModel ( ) . rows ;
138- event . preventDefault ( ) ;
139- const modKey = eventHasModKey ( event ) ;
144+ if ( index < 0 || index >= rows . length ) return ;
140145
141146 function genIds ( ) {
142147 const minIndex = Math . min ( index , lastIndex ) ;
@@ -148,15 +153,15 @@ function useSelectHandler<TData>(
148153 return ids ;
149154 }
150155
151- if ( event . shiftKey && modKey && lastIndex !== - 1 ) {
156+ if ( event . shiftKey && event . modKey && lastIndex !== - 1 ) {
152157 const ids = genIds ( ) ;
153158 selectedReducer ( { verb : "add" , ids } ) ;
154159 } else if ( event . shiftKey && lastIndex !== - 1 ) {
155160 const ids = genIds ( ) ;
156161 selectedReducer ( { verb : "set" , ids } ) ;
157- } else if ( modKey ) {
162+ } else if ( event . modKey ) {
158163 selectedReducer ( { verb : "toggle" , ids : [ getRowId ( rows [ index ] . original ) ] } ) ;
159- } else if ( event . button !== 2 || ! rows [ index ] . getIsSelected ( ) ) {
164+ } else if ( ! event . isRmb || ! rows [ index ] . getIsSelected ( ) ) {
160165 selectedReducer ( { verb : "set" , ids : [ getRowId ( rows [ index ] . original ) ] } ) ;
161166 }
162167
@@ -258,7 +263,7 @@ function TableRow<TData>(props: {
258263 index : number ,
259264 start : number ,
260265 lastIndex : number ,
261- onRowClick : ( e : React . MouseEvent < Element > , i : number , li : number ) => void ,
266+ onRowClick : ( e : HIDEvent , i : number , li : number ) => void ,
262267 onRowDoubleClick ?: ( row : TData ) => void ,
263268 height : number ,
264269 columnSizing : ColumnSizingState ,
@@ -272,17 +277,55 @@ function TableRow<TData>(props: {
272277 }
273278 } , [ propsDblClick , row . original ] ) ;
274279
280+ const { onRowClick, index, lastIndex } = props ;
281+
282+ const onMouseEvent = useCallback ( ( e : React . MouseEvent < HTMLDivElement > ) => {
283+ onRowClick ( {
284+ modKey : eventHasModKey ( e ) ,
285+ shiftKey : e . shiftKey ,
286+ isRmb : e . button === 2 ,
287+ } , index , lastIndex ) ;
288+ } , [ index , lastIndex , onRowClick ] ) ;
289+
290+ const ref = useRef < HTMLDivElement > ( null ) ;
291+
292+ const onKeyDown = useCallback ( ( e : React . KeyboardEvent < HTMLDivElement > ) => {
293+ let newIndex = index ;
294+ if ( e . key === "ArrowDown" ) {
295+ newIndex += 1 ;
296+ } else if ( e . key === "ArrowUp" ) {
297+ newIndex -= 1 ;
298+ } else if ( e . key !== "ContextMenu" ) {
299+ return ;
300+ }
301+ e . preventDefault ( ) ;
302+ if ( ref . current != null ) {
303+ if ( e . key === "ArrowDown" && ref . current . nextElementSibling != null ) {
304+ const element = ref . current . nextElementSibling as HTMLElement ;
305+ element . scrollIntoView ( { behavior : "instant" , block : "nearest" } ) ;
306+ element . focus ( ) ;
307+ }
308+ if ( e . key === "ArrowUp" && ref . current . previousElementSibling != null ) {
309+ const element = ref . current . previousElementSibling as HTMLElement ;
310+ element . scrollIntoView ( { behavior : "instant" , block : "nearest" } ) ;
311+ element . focus ( ) ;
312+ }
313+ }
314+ onRowClick ( {
315+ modKey : eventHasModKey ( e ) ,
316+ shiftKey : e . shiftKey ,
317+ isRmb : e . key === "ContextMenu" ,
318+ } , newIndex , lastIndex ) ;
319+ } , [ index , lastIndex , onRowClick ] ) ;
320+
275321 return (
276- < div
322+ < div ref = { ref }
277323 className = { `tr${ props . selected ? " selected" : "" } ` }
278324 style = { { height : `${ props . height } px` , transform : `translateY(${ props . start } px)` } }
279- onClick = { ( e ) => {
280- props . onRowClick ( e , props . index , props . lastIndex ) ;
281- } }
282- onContextMenu = { ( e ) => {
283- props . onRowClick ( e , props . index , props . lastIndex ) ;
284- } }
325+ onClick = { onMouseEvent }
326+ onContextMenu = { onMouseEvent }
285327 onDoubleClick = { onRowDoubleClick }
328+ onKeyDown = { onKeyDown }
286329 tabIndex = { - 1 }
287330 >
288331 < MemoizedInnerRow { ...props } />
@@ -530,7 +573,9 @@ export function EditableNameField(props: EditableNameFieldProps) {
530573 setNewName ( props . currentName ) ;
531574 } , [ props . currentName ] ) ;
532575
533- const onEnter = useCallback ( ( event : React . KeyboardEvent < HTMLInputElement > ) => {
576+ const ref = useRef < HTMLDivElement > ( null ) ;
577+
578+ const onTextKeyDown = useCallback ( ( event : React . KeyboardEvent < HTMLInputElement > ) => {
534579 if ( event . key === "Enter" ) {
535580 props . onUpdate ?.(
536581 newName ,
@@ -539,6 +584,10 @@ export function EditableNameField(props: EditableNameFieldProps) {
539584 } ,
540585 ( ) => { setRenaming ( false ) ; } ) ;
541586 }
587+ if ( event . key === "Escape" ) {
588+ setRenaming ( false ) ;
589+ ref . current ?. focus ( ) ;
590+ }
542591 } , [ newName , props ] ) ;
543592
544593 useEffect ( ( ) => {
@@ -548,8 +597,6 @@ export function EditableNameField(props: EditableNameFieldProps) {
548597 }
549598 } , [ isRenaming ] ) ;
550599
551- const ref = useRef < HTMLDivElement > ( null ) ;
552-
553600 useEffect ( ( ) => {
554601 if ( ref . current != null ) {
555602 const row = ref . current . parentNode ?. parentNode as HTMLDivElement ;
@@ -580,7 +627,7 @@ export function EditableNameField(props: EditableNameFieldProps) {
580627 } }
581628 onChange = { ( e ) => { setNewName ( e . target . value ) ; } }
582629 onBlur = { ( ) => { setRenaming ( false ) ; } }
583- onKeyDown = { onEnter }
630+ onKeyDown = { onTextKeyDown }
584631 onClick = { ( e ) => { e . stopPropagation ( ) ; } } />
585632 : < Box pl = "xs" sx = { { flexGrow : 1 , textOverflow : "ellipsis" , overflow : "hidden" } } >
586633 { props . currentName }
0 commit comments