-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
search-input.js
143 lines (132 loc) · 3.65 KB
/
search-input.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* External dependencies
*/
import { noop, omit } from 'lodash';
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
import { forwardRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { URLInput } from '../';
import LinkControlSearchResults from './search-results';
import { CREATE_TYPE } from './constants';
import useSearchHandler from './use-search-handler';
const noopSearchHandler = Promise.resolve( [] );
const LinkControlSearchInput = forwardRef(
(
{
value,
children,
currentLink = {},
className = null,
placeholder = null,
withCreateSuggestion = false,
onCreateSuggestion = noop,
onChange = noop,
onSelect = noop,
showSuggestions = true,
renderSuggestions = ( props ) => (
<LinkControlSearchResults { ...props } />
),
fetchSuggestions = null,
allowDirectEntry = true,
showInitialSuggestions = false,
suggestionsQuery = {},
withURLSuggestion = true,
createSuggestionButtonText,
},
ref
) => {
const genericSearchHandler = useSearchHandler(
suggestionsQuery,
allowDirectEntry,
withCreateSuggestion,
withURLSuggestion
);
const searchHandler = showSuggestions
? fetchSuggestions || genericSearchHandler
: noopSearchHandler;
const instanceId = useInstanceId( LinkControlSearchInput );
const [ focusedSuggestion, setFocusedSuggestion ] = useState();
/**
* Handles the user moving between different suggestions. Does not handle
* choosing an individual item.
*
* @param {string} selection the url of the selected suggestion.
* @param {Object} suggestion the suggestion object.
*/
const onInputChange = ( selection, suggestion ) => {
onChange( selection );
setFocusedSuggestion( suggestion );
};
const onFormSubmit = ( event ) => {
event.preventDefault();
onSuggestionSelected( focusedSuggestion || { url: value } );
};
const handleRenderSuggestions = ( props ) =>
renderSuggestions( {
...props,
instanceId,
withCreateSuggestion,
currentInputValue: value,
createSuggestionButtonText,
suggestionsQuery,
handleSuggestionClick: ( suggestion ) => {
if ( props.handleSuggestionClick ) {
props.handleSuggestionClick( suggestion );
}
onSuggestionSelected( suggestion );
},
} );
const onSuggestionSelected = async ( selectedSuggestion ) => {
let suggestion = selectedSuggestion;
if ( CREATE_TYPE === selectedSuggestion.type ) {
// Create a new page and call onSelect with the output from the onCreateSuggestion callback
try {
suggestion = await onCreateSuggestion(
selectedSuggestion.title
);
if ( suggestion?.url ) {
onSelect( suggestion );
}
} catch ( e ) {}
return;
}
if (
allowDirectEntry ||
( suggestion && Object.keys( suggestion ).length >= 1 )
) {
onSelect(
// Some direct entries don't have types or IDs, and we still need to clear the previous ones.
{ ...omit( currentLink, 'id', 'url' ), ...suggestion },
suggestion
);
}
};
return (
<form onSubmit={ onFormSubmit }>
<URLInput
className={ className }
value={ value }
onChange={ onInputChange }
placeholder={ placeholder ?? __( 'Search or type url' ) }
__experimentalRenderSuggestions={
showSuggestions ? handleRenderSuggestions : null
}
__experimentalFetchLinkSuggestions={ searchHandler }
__experimentalHandleURLSuggestions={ true }
__experimentalShowInitialSuggestions={
showInitialSuggestions
}
ref={ ref }
/>
{ children }
</form>
);
}
);
export default LinkControlSearchInput;