2017-05-03 03:04:16 +03:00
import React from 'react' ;
2017-04-21 21:05:35 +03:00
import PropTypes from 'prop-types' ;
2017-10-02 19:24:05 +03:00
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
2017-10-06 04:24:33 +03:00
import Overlay from 'react-overlays/lib/Overlay' ;
2017-10-16 10:36:15 +03:00
import Motion from '../../ui/util/optional_motion' ;
2017-10-06 04:46:15 +03:00
import spring from 'react-motion/lib/spring' ;
2018-03-02 07:02:42 +02:00
import { searchEnabled } from '../../../initial_state' ;
2016-11-18 16:36:16 +02:00
const messages = defineMessages ( {
2017-05-20 18:31:47 +03:00
placeholder : { id : 'search.placeholder' , defaultMessage : 'Search' } ,
2016-11-18 16:36:16 +02:00
} ) ;
2016-11-13 14:04:18 +02:00
2017-10-02 19:24:05 +03:00
class SearchPopout extends React . PureComponent {
static propTypes = {
style : PropTypes . object ,
} ;
render ( ) {
const { style } = this . props ;
2018-03-02 07:02:42 +02:00
const extraInformation = searchEnabled ? < FormattedMessage id = 'search_popout.tips.full_text' defaultMessage = 'Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' / > : < FormattedMessage id = 'search_popout.tips.text' defaultMessage = 'Simple text returns matching display names, usernames and hashtags' / > ;
2017-10-02 19:24:05 +03:00
return (
< div style = { { ... style , position : 'absolute' , width : 285 } } >
< Motion defaultStyle = { { opacity : 0 , scaleX : 0.85 , scaleY : 0.75 } } style = { { opacity : spring ( 1 , { damping : 35 , stiffness : 400 } ) , scaleX : spring ( 1 , { damping : 35 , stiffness : 400 } ) , scaleY : spring ( 1 , { damping : 35 , stiffness : 400 } ) } } >
{ ( { opacity , scaleX , scaleY } ) => (
< div className = 'search-popout' style = { { opacity : opacity , transform : ` scale( ${ scaleX } , ${ scaleY } ) ` } } >
< h4 > < FormattedMessage id = 'search_popout.search_format' defaultMessage = 'Advanced search format' / > < / h 4 >
< ul >
< li > < em > # example < /em> <FormattedMessage id='search_popout.tips.hashtag' defaultMessage='hashtag' / > < / l i >
< li > < em > @ username @ domain < /em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' / > < / l i >
< li > < em > URL < /em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' / > < / l i >
< li > < em > URL < /em> <FormattedMessage id='search_popout.tips.status' defaultMessage='status' / > < / l i >
< / u l >
2018-03-02 07:02:42 +02:00
{ extraInformation }
2017-10-02 19:24:05 +03:00
< / d i v >
) }
< / M o t i o n >
< / d i v >
) ;
}
}
2017-06-23 20:36:54 +03:00
@ injectIntl
export default class Search extends React . PureComponent {
2016-11-13 14:04:18 +02:00
2017-05-12 15:44:10 +03:00
static propTypes = {
value : PropTypes . string . isRequired ,
submitted : PropTypes . bool ,
onChange : PropTypes . func . isRequired ,
onSubmit : PropTypes . func . isRequired ,
onClear : PropTypes . func . isRequired ,
onShow : PropTypes . func . isRequired ,
2017-05-20 18:31:47 +03:00
intl : PropTypes . object . isRequired ,
2017-05-12 15:44:10 +03:00
} ;
2017-10-02 19:24:05 +03:00
state = {
expanded : false ,
} ;
2017-05-12 15:44:10 +03:00
handleChange = ( e ) => {
2017-03-31 20:59:54 +03:00
this . props . onChange ( e . target . value ) ;
2017-04-21 21:05:35 +03:00
}
2016-11-13 14:04:18 +02:00
2017-05-12 15:44:10 +03:00
handleClear = ( e ) => {
2017-03-31 20:59:54 +03:00
e . preventDefault ( ) ;
2017-04-23 05:39:50 +03:00
if ( this . props . value . length > 0 || this . props . submitted ) {
this . props . onClear ( ) ;
}
2017-04-21 21:05:35 +03:00
}
2016-11-13 14:04:18 +02:00
2017-05-12 15:44:10 +03:00
handleKeyDown = ( e ) => {
2017-03-31 20:59:54 +03:00
if ( e . key === 'Enter' ) {
e . preventDefault ( ) ;
this . props . onSubmit ( ) ;
2017-10-06 02:07:59 +03:00
} else if ( e . key === 'Escape' ) {
document . querySelector ( '.ui' ) . parentElement . focus ( ) ;
2017-03-31 20:59:54 +03:00
}
2017-04-21 21:05:35 +03:00
}
2016-11-13 14:04:18 +02:00
2017-04-15 14:27:27 +03:00
noop ( ) {
2017-04-21 21:05:35 +03:00
}
2017-04-15 14:27:27 +03:00
2017-05-12 15:44:10 +03:00
handleFocus = ( ) => {
2017-10-02 19:24:05 +03:00
this . setState ( { expanded : true } ) ;
2017-03-31 20:59:54 +03:00
this . props . onShow ( ) ;
2017-04-21 21:05:35 +03:00
}
2016-11-13 14:04:18 +02:00
2017-10-02 19:24:05 +03:00
handleBlur = ( ) => {
this . setState ( { expanded : false } ) ;
}
2016-11-13 14:04:18 +02:00
render ( ) {
2017-03-31 23:44:12 +03:00
const { intl , value , submitted } = this . props ;
2017-10-02 19:24:05 +03:00
const { expanded } = this . state ;
2017-03-31 23:44:12 +03:00
const hasValue = value . length > 0 || submitted ;
2016-11-13 14:04:18 +02:00
return (
2017-03-31 20:59:54 +03:00
< div className = 'search' >
2017-07-28 01:54:48 +03:00
< label >
< span style = { { display : 'none' } } > { intl . formatMessage ( messages . placeholder ) } < / s p a n >
< input
className = 'search__input'
type = 'text'
placeholder = { intl . formatMessage ( messages . placeholder ) }
value = { value }
onChange = { this . handleChange }
onKeyUp = { this . handleKeyDown }
onFocus = { this . handleFocus }
2017-10-02 19:24:05 +03:00
onBlur = { this . handleBlur }
2017-07-28 01:54:48 +03:00
/ >
< / l a b e l >
2016-11-13 14:04:18 +02:00
2017-04-23 05:39:50 +03:00
< div role = 'button' tabIndex = '0' className = 'search__icon' onClick = { this . handleClear } >
2017-03-31 20:59:54 +03:00
< i className = { ` fa fa-search ${ hasValue ? '' : 'active' } ` } / >
2017-04-23 05:39:50 +03:00
< i aria - label = { intl . formatMessage ( messages . placeholder ) } className = { ` fa fa-times-circle ${ hasValue ? 'active' : '' } ` } / >
2017-03-31 20:59:54 +03:00
< / d i v >
2017-10-02 19:24:05 +03:00
< Overlay show = { expanded && ! hasValue } placement = 'bottom' target = { this } >
< SearchPopout / >
< / O v e r l a y >
2016-11-13 14:04:18 +02:00
< / d i v >
) ;
2017-03-31 20:59:54 +03:00
}
2016-11-13 14:04:18 +02:00
2017-04-21 21:05:35 +03:00
}