Last active
June 19, 2019 07:55
-
-
Save 197291/6915d3b439c3b8e2b23ff6c5182aa91d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import { KeyCodeMap } from 'constants/core/key-code-map'; | |
import { getComponentDisplayName } from 'helpers/common/get-component-display-name'; | |
interface State { | |
selectedRowIndex: number; | |
mouseIndex: number; | |
scrollElement: any; | |
rowsLength: number; | |
} | |
interface Data { | |
shouldSelectOnHover?: boolean; | |
ROW_HEIGHT: number; | |
DROPDOWN_HEIGHT: number; | |
} | |
export interface SelectKeyEventsProps { | |
selectedRowIndex?: number; | |
selectRow?(event: React.KeyboardEvent<HTMLInputElement>); | |
resetRow?(); | |
setIndex?(index: number); | |
setRowsLength?(length: number); | |
setScrollElement?(scrollElement: any); | |
} | |
export interface SelectKeyEvents { | |
input?: HTMLInputElement; | |
scrollElement: any; | |
selectOption(index: number): void; | |
closeDropdown?(); | |
} | |
export default function selectKeyEvents<P extends SelectKeyEventsProps>( | |
WrappedComponent: React.ComponentType<P>, | |
data: Data | |
) { | |
class WithSelectKeyEvents extends React.Component<P, State> { | |
state = { | |
selectedRowIndex: -1, | |
mouseIndex: null, | |
scrollElement: null, | |
rowsLength: 0 | |
}; | |
instance; | |
static displayName: string; | |
proc(wrappedComponentInstance: any) { | |
this.instance = wrappedComponentInstance; | |
} | |
setRowsLength = (rowsLength: number) => { | |
this.setState({ rowsLength }); | |
}; | |
setScrollElement = (scrollElement: any) => { | |
this.setState({ scrollElement }); | |
}; | |
setIndex = (index: number) => { | |
this.setState((state) => ({ | |
mouseIndex: index, | |
selectedRowIndex: data.shouldSelectOnHover ? index : state.selectedRowIndex | |
})); | |
}; | |
resetRow = () => { | |
this.setState({ selectedRowIndex: -1 }); | |
}; | |
selectRow = (event: React.KeyboardEvent<HTMLInputElement>) => { | |
const key = event.keyCode; | |
if ( | |
key !== KeyCodeMap.ArrowDown && | |
key !== KeyCodeMap.ArrowUp && | |
key !== KeyCodeMap.Enter && | |
key !== KeyCodeMap.Escape && | |
key !== KeyCodeMap.Tab | |
) { | |
return; | |
} | |
const { selectedRowIndex, mouseIndex, rowsLength, scrollElement } = this.state; | |
let index = selectedRowIndex; | |
if (mouseIndex !== null) { | |
index = mouseIndex; | |
this.setState({ mouseIndex: null }); | |
} | |
if (key === KeyCodeMap.Enter && index !== -1) { | |
if (this.instance.input) { | |
this.instance.input.blur(); | |
} | |
if (this.instance.selectOption) { | |
this.instance.selectOption(index); | |
} | |
event.preventDefault(); | |
event.stopPropagation(); | |
return; | |
} | |
if (key === KeyCodeMap.Tab || key === KeyCodeMap.Escape) { | |
if (this.instance.closeDropdown) { | |
this.instance.closeDropdown(index); | |
} | |
return; | |
} | |
if (key === KeyCodeMap.ArrowDown) { | |
++index; | |
} | |
if (key === KeyCodeMap.ArrowUp) { | |
--index; | |
} | |
index = index < 0 ? rowsLength - 1 : index === rowsLength ? 0 : index; | |
const scrollEl = scrollElement || this.instance.scrollElement; | |
if (!scrollEl) { | |
return; | |
} | |
const topOffset = scrollEl.getScrollTop(); | |
const i0 = Math.ceil(topOffset / data.ROW_HEIGHT); | |
const i1 = i0 + Math.round(data.DROPDOWN_HEIGHT / data.ROW_HEIGHT) - 1; | |
if (index < i0) { | |
scrollEl.scrollTop(topOffset - data.ROW_HEIGHT); | |
} | |
if (index > i1) { | |
scrollEl.scrollTop(topOffset + data.ROW_HEIGHT); | |
} | |
if (index === 0) { | |
scrollEl.scrollTop(0); | |
} | |
if (index === rowsLength - 1) { | |
scrollEl.scrollTop(data.ROW_HEIGHT * rowsLength); | |
} | |
this.setState({ selectedRowIndex: index }); | |
}; | |
render() { | |
const props = Object.assign({}, this.props, { ref: this.proc.bind(this) }); | |
return ( | |
<WrappedComponent | |
{...props} | |
selectedRowIndex={this.state.selectedRowIndex} | |
selectRow={this.selectRow} | |
resetRow={this.resetRow} | |
setIndex={this.setIndex} | |
setRowsLength={this.setRowsLength} | |
setScrollElement={this.setScrollElement} | |
/> | |
); | |
} | |
} | |
WithSelectKeyEvents.displayName = `WithSelectKeyEvents(${getComponentDisplayName( | |
WrappedComponent | |
)})`; | |
return WithSelectKeyEvents; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment