@@ -15,11 +15,11 @@ import PropTypes from 'prop-types';
1515import { v4 as uuidv4 } from 'uuid' ;
1616
1717import LocaleUtils from '../../utils/LocaleUtils' ;
18- import MiscUtils from '../../utils/MiscUtils' ;
1918import { SearchResultType } from '../../utils/SearchProviders' ;
2019import VectorLayerUtils from '../../utils/VectorLayerUtils' ;
2120import Icon from '../Icon' ;
2221import InputContainer from './InputContainer' ;
22+ import PopupMenu from './PopupMenu' ;
2323import Spinner from './Spinner' ;
2424
2525import './style/SearchWidget.css' ;
@@ -28,8 +28,6 @@ import './style/SearchWidget.css';
2828export default class SearchWidget extends React . Component {
2929 static propTypes = {
3030 className : PropTypes . string ,
31- onBlur : PropTypes . func ,
32- onFocus : PropTypes . func ,
3331 placeholder : PropTypes . string ,
3432 queryGeometries : PropTypes . bool ,
3533 resultSelected : PropTypes . func . isRequired ,
@@ -42,8 +40,6 @@ export default class SearchWidget extends React.Component {
4240 value : PropTypes . string
4341 } ;
4442 static defaultProps = {
45- onBlur : ( ) => { } ,
46- onFocus : ( ) => { } ,
4743 resultTypeFilter : [ SearchResultType . PLACE ] ,
4844 searchParams : { } ,
4945 searchProviders : [ ]
@@ -53,7 +49,7 @@ export default class SearchWidget extends React.Component {
5349 reqId : null ,
5450 results : [ ] ,
5551 pending : 0 ,
56- active : false
52+ resultsVisible : false
5753 } ;
5854 constructor ( props ) {
5955 super ( props ) ;
@@ -75,8 +71,8 @@ export default class SearchWidget extends React.Component {
7571 < div className = "search-widget-container" >
7672 < InputContainer >
7773 < input
78- onBlur = { this . onBlur }
7974 onChange = { this . textChanged }
75+ onClick = { ( ) => this . setState ( { resultsVisible : true } ) }
8076 onFocus = { this . onFocus }
8177 onKeyDown = { this . onKeyDown }
8278 placeholder = { this . props . placeholder ?? LocaleUtils . tr ( "search.search" ) }
@@ -86,31 +82,29 @@ export default class SearchWidget extends React.Component {
8682 value = { this . state . text } />
8783 { this . state . pending > 0 ? ( < Spinner role = "suffix" /> ) : ( < Icon icon = "clear" onClick = { this . clear } role = "suffix" /> ) }
8884 </ InputContainer >
89- { ( ! isEmpty ( this . state . results ) || this . state . pending > 0 ) && this . state . active ? this . renderResults ( ) : null }
85+ { ( ! isEmpty ( this . state . results ) || this . state . pending > 0 ) && this . state . resultsVisible ? this . renderResults ( ) : null }
9086 </ div >
9187 ) ;
9288 }
9389 renderResults = ( ) => {
9490 return (
95- < div className = "search-widget-results" onMouseDown = { this . setPreventBlur } >
96- { this . state . results . filter ( group => this . props . resultTypeFilter . includes ( group . type ?? SearchResultType . PLACE ) ) . map ( group => (
97- < div className = "search-widget-results-group" key = { group . id } onMouseDown = { MiscUtils . killEvent } >
98- < div className = "search-widget-results-group-title" > < span > { group . title ?? LocaleUtils . tr ( group . titlemsgid ) } </ span > </ div >
99- { group . items . map ( item => {
100- item . text = ( item . label !== undefined ? item . label : item . text || '' ) . replace ( / < \/ ? \w + \s * \/ ? > / g, '' ) ;
101- return (
102- < div className = "search-widget-results-group-item" key = { item . id } onClick = { ( ) => this . resultSelected ( group , item ) } title = { item . text } > { item . text } </ div >
103- ) ;
104- } ) }
105- </ div >
106- ) ) }
107- </ div >
91+ < PopupMenu anchor = { this . input } className = "search-widget-results" onClose = { ( ) => this . setState ( { resultsVisible : false } ) } setMaxWidth spaceKeyActivation = { false } >
92+ { this . state . results . filter ( group => this . props . resultTypeFilter . includes ( group . type ?? SearchResultType . PLACE ) ) . map ( group => {
93+ return [ (
94+ < div className = "search-widget-results-group-title" disabled key = { group . id } >
95+ < span > { group . title ?? LocaleUtils . tr ( group . titlemsgid ) } </ span >
96+ </ div >
97+ ) ,
98+ group . items . map ( item => {
99+ item . text = ( item . label !== undefined ? item . label : item . text || '' ) . replace ( / < \/ ? \w + \s * \/ ? > / g, '' ) ;
100+ return (
101+ < div className = "search-widget-results-item" key = { group . id + ":" + item . id } onClick = { ( ) => this . resultSelected ( group , item ) } title = { item . text } > { item . text } </ div >
102+ ) ;
103+ } ) ] ;
104+ } ) . flat ( ) }
105+ </ PopupMenu >
108106 ) ;
109107 } ;
110- setPreventBlur = ( ) => {
111- this . preventBlur = true ;
112- setTimeout ( ( ) => { this . preventBlur = false ; return false ; } , 100 ) ;
113- } ;
114108 textChanged = ( ev ) => {
115109 this . setState ( { text : ev . target . value , reqId : null , results : [ ] , pending : 0 } ) ;
116110 clearTimeout ( this . searchTimeout ) ;
@@ -120,23 +114,17 @@ export default class SearchWidget extends React.Component {
120114 this . searchTimeout = setTimeout ( this . startSearch , 250 ) ;
121115 }
122116 } ;
123- onBlur = ( ) => {
124- if ( ! this . preventBlur ) {
125- clearTimeout ( this . searchTimeout ) ;
126- this . props . onBlur ( ) ;
127- this . setState ( { active : false } ) ;
128- }
129- } ;
130117 onFocus = ( ev ) => {
131- ev . target . select ( ) ;
132- this . props . onFocus ( ) ;
133- this . setState ( { active : true } ) ;
118+ if ( this . input && ! this . state . resultsVisible ) {
119+ ev . target . select ( ) ;
120+ }
134121 } ;
135122 onKeyDown = ( ev ) => {
136123 if ( ev . key === 'Enter' ) {
137124 this . startSearch ( ) ;
138- } else if ( ev . key === 'Escape' ) {
139- ev . target . blur ( ) ;
125+ } else if ( ev . key === 'ArrowDown' || ev . key === 'ArrowUp' ) {
126+ ev . preventDefault ( ) ;
127+ this . setState ( { resultsVisible : true } ) ;
140128 }
141129 } ;
142130 startSearch = ( ) => {
@@ -158,7 +146,8 @@ export default class SearchWidget extends React.Component {
158146 }
159147 return {
160148 results : [ ...state . results , ...response . results . map ( group => ( { ...group , provider} ) ) ] ,
161- pending : state . pending - 1
149+ pending : state . pending - 1 ,
150+ resultsVisible : true
162151 } ;
163152 } ) ;
164153 } , axios ) ;
@@ -186,7 +175,7 @@ export default class SearchWidget extends React.Component {
186175 }
187176 } ;
188177 clear = ( ) => {
189- this . setState ( { results : [ ] , text : "" } ) ;
178+ this . setState ( { results : [ ] , text : "" , resultsVisible : false } ) ;
190179 this . props . resultSelected ( null ) ;
191180 } ;
192181}
0 commit comments