import React , { useCallback , useState , useRef } from 'react' ; import ClearAdornment from '../helper/ClearAdornment' ; import Search from '@material-ui/icons/Search' ; import { AppState } from '../../reducers' ; import { bindActionCreators } from 'redux' ; import { connect } from 'react-redux' ; import { InputBase } from '@material-ui/core' ; import { settingsActions } from '../../actions' ; import { fade , Theme , withStyles } from '@material-ui/core/styles' ; import { useGlobalKeyEventHandler } from '../../effects/useGlobalKeyEventHandler' ; import { KeyCodes } from '../../utils/KeyCodes' ; function SearchBar ( props ) { const { actions , classes , hasConnection , topicFilter } = props ; const [ hasFocus , setHasFocus ] = useState ( false ) ; const inputRef = useRef < HTMLInputElement > ( ) ; const onFocus = useCallback ( ( ) => setHasFocus ( true ) , [ ] ) ; const onBlur = useCallback ( ( ) => setHasFocus ( false ) , [ ] ) ; const clearFilter = useCallback ( ( ) => { actions . settings . filterTopics ( '' ) ; } , [ ] ) ; const onFilterChange = useCallback ( ( event ) => { actions . settings . filterTopics ( event . target . value ) ; } , [ ] ) ; useGlobalKeyEventHandler ( undefined , event => { const isCharacter = event . key . length === 1 ; const isModifierKey = event . metaKey || event . ctrlKey ; const isAllowedControlCharacter = event . keyCode === KeyCodes . backspace || event . keyCode === KeyCodes . delete ; const tagNameBlacklist = [ 'INPUT' , 'TEXTAREA' , 'RADIO' , 'CHECKBOX' , 'OPTION' , 'FORM' ] ; const tagElementIsNotBlacklisted = document . activeElement && tagNameBlacklist . indexOf ( document . activeElement . tagName ) === - 1 ; if ( ( isCharacter || isAllowedControlCharacter ) && ! isModifierKey && ! event . defaultPrevented && ! hasFocus && tagElementIsNotBlacklisted && hasConnection ) { inputRef . current && inputRef . current . focus ( ) ; } } ) ; return ( < div className = { classes . search } > < div className = { classes . searchIcon } > < Search /> < /div> < InputBase value = { topicFilter } inputProps = { { onFocus , onBlur , ref : inputRef , } } onChange = { onFilterChange } placeholder = "Search…" endAdornment = { < div style = { { width : '24px' , paddingRight : '8px' } } > < ClearAdornment variant = "primary" action = { clearFilter } value = { topicFilter } / > < /div>} classes={{ root: classes.inputRoot, input: classes.inputInput }}/ > < /div>); } const mapStateToProps = ( state ) => { return { topicFilter : state . settings . get ( 'topicFilter' ) , hasConnection : Boolean ( state . connection . connectionId ) , } ; } ; const mapDispatchToProps = ( dispatch ) => { return { actions : { settings : bindActionCreators ( settingsActions , dispatch ) , } , } ; } ; const styles = ( theme ) => ( { search : { position : 'relative' as 'relative' , borderRadius : theme . shape . borderRadius , backgroundColor : fade ( theme . palette . common . white , 0.15 ) , '&:hover' : { backgroundColor : fade ( theme . palette . common . white , 0.25 ) , } , marginRight : theme . spacing ( 2 ) , marginLeft : 0 , flexGrow : 1 , maxWidth : '60%' , [ theme . breakpoints . up ( 'md' ) ] : { maxWidth : '30%' , marginLeft : theme . spacing ( 4 ) , width : 'auto' as 'auto' , } , [ theme . breakpoints . up ( 750 ) ] : { marginLeft : theme . spacing ( 4 ) , width : 'auto' as 'auto' , } , } , searchIcon : { width : theme . spacing ( 6 ) , height : '100%' , position : 'absolute' as 'absolute' , pointerEvents : 'none' as 'none' , display : 'flex' as 'flex' , alignItems : 'center' as 'center' , justifyContent : 'center' as 'center' , } , inputRoot : { color : 'inherit' as 'inherit' , width : '100%' , } , inputInput : { paddingTop : theme . spacing ( 1 ) , paddingRight : theme . spacing ( 1 ) , paddingBottom : theme . spacing ( 1 ) , paddingLeft : theme . spacing ( 6 ) , transition : theme . transitions . create ( 'width' ) , width : '100%' , } , } ) ; export default connect ( mapStateToProps , mapDispatchToProps ) ( withStyles ( styles ) ( SearchBar ) ) ;