Skip to content

Commit 36fb186

Browse files
committed
feat(search): adding integration of typeahead api to autosuggest
1 parent bad3b8e commit 36fb186

33 files changed

+303
-637
lines changed

.eslintignore

+11
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
node_modules
22

33
# react
4+
packages/react/coverage
45
packages/react/es
56
packages/react/umd
67
packages/react/lib
78
packages/react/node_modules
9+
packages/react/storybook-static
810

911
# services
12+
packages/services/coverage
1013
packages/services/docs
1114
packages/services/es
1215
packages/services/umd
1316
packages/services/lib
1417
packages/services/node_modules
1518

19+
# styles
20+
packages/styles/dist
21+
packages/styles/es
22+
packages/styles/umd
23+
packages/styles/lib
24+
packages/styles/node_modules
25+
1626
# utilities
27+
packages/utilities/coverage
1728
packages/utilities/docs
1829
packages/utilities/es
1930
packages/utilities/umd
13.5 KB
Binary file not shown.
24.9 KB
Binary file not shown.
Binary file not shown.
4.75 KB
Binary file not shown.
Binary file not shown.

packages/eslint-config-ibmdotcom/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ module.exports = {
3030
'react/jsx-uses-react': 1,
3131
'react/no-find-dom-node': 1,
3232
'react/no-typos': 2,
33+
'react/no-unused-prop-types': 2,
34+
'react/prop-types': 2,
3335
'react-hooks/rules-of-hooks': 'error',
3436
'react-hooks/exhaustive-deps': 'error',
3537
'jsdoc/require-jsdoc': [

packages/react/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
},
4747
"dependencies": {
4848
"@carbon/icons-react": "10.3.0",
49+
"autosuggest-highlight": "^3.1.1",
4950
"classnames": "2.2.6",
5051
"downshift": "^1.31.14",
5152
"flatpickr": "4.6.1",

packages/react/src/components/Masthead/Masthead.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import PropTypes from 'prop-types';
99
import React from 'react';
10+
import MastheadSearch from './MastheadSearch';
1011

1112
/**
1213
* Test MastHead component
@@ -19,13 +20,13 @@ const Masthead = ({ type }) => {
1920
if (type === 'branded') {
2021
return (
2122
<div className="masthead">
22-
<p>This is a branded masthead</p>
23+
<MastheadSearch />
2324
</div>
2425
);
2526
} else {
2627
return (
2728
<div className="masthead">
28-
<p>This is the standard masthead</p>
29+
<MastheadSearch />
2930
</div>
3031
);
3132
}

packages/react/src/components/Masthead/MastheadSearch.jsx packages/react/src/components/Masthead/MastheadSearch.js

+52-41
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77

88
import React, { useReducer } from 'react';
99
import PropTypes from 'prop-types';
10+
import Autosuggest from 'react-autosuggest';
1011
import { SearchTypeaheadAPI } from '@ibmdotcom/services';
1112
import { escapeRegExp } from '@ibmdotcom/utilities';
12-
import { MastheadSearchInput, MastheadSearchSuggestion } from './';
13-
13+
import MastheadSearchInput from './MastheadSearchInput';
14+
import MastheadSearchSuggestion from './MastheadSearchSuggestion';
1415

1516
/**
1617
* Converts the string to lower case and trims extra white space
@@ -26,7 +27,7 @@ const _trimAndLower = valueString => valueString.toLowerCase().trim();
2627
* @param {object} suggestion The individual object from the data
2728
* @returns {*} The name val
2829
*/
29-
const _getSuggestionValue = suggestion => suggestion.name;
30+
const _getSuggestionValue = suggestion => suggestion[0];
3031

3132
/**
3233
* Initial state of the autocomplete component
@@ -52,17 +53,19 @@ const _initialState = {
5253
function _reducer(state, action) {
5354
switch (action.type) {
5455
case 'setVal':
55-
return Object.assign({}, state, {val: action.payload.val});
56+
return Object.assign({}, state, { val: action.payload.val });
5657
case 'emptySuggestions':
57-
return Object.assign({}, state, {suggestions: []});
58+
return Object.assign({}, state, { suggestions: [] });
5859
case 'setPrevSuggestions':
59-
return Object.assign({}, state, {prevSuggestions: action.payload.prevSuggestions});
60+
return Object.assign({}, state, {
61+
prevSuggestions: action.payload.prevSuggestions,
62+
});
6063
case 'setSuggestionsToPrevious':
61-
return Object.assign({}, state, {suggestions: state.prevSuggestions});
64+
return Object.assign({}, state, { suggestions: state.prevSuggestions });
6265
case 'showSuggestionsContainer':
63-
return Object.assign({}, state, {suggestionContainerVisible: true});
66+
return Object.assign({}, state, { suggestionContainerVisible: true });
6467
case 'hideSuggestionsContainer':
65-
return Object.assign({}, state, {suggestionContainerVisible: false});
68+
return Object.assign({}, state, { suggestionContainerVisible: false });
6669
default:
6770
return state;
6871
}
@@ -76,15 +79,12 @@ function _reducer(state, action) {
7679
* http://react-autosuggest.js.org/
7780
* https://github.com/moroshko/react-autosuggest
7881
*
79-
* @param {string} placeHolderText Placeholder text for the search field
80-
* @param {number} renderValue Number of characters to begin showing suggestions
81-
* @param {Function} getSuggestionValue Function for getting the suggestion value
82+
* @param {object} props Incoming props
83+
* @param {string} props.placeHolderText Placeholder text for the search field
84+
* @param {number} props.renderValue Number of characters to begin showing suggestions
8285
* @class
8386
*/
84-
const MastheadSearch = ({
85-
placeHolderText,
86-
renderValue,
87-
}) => {
87+
const MastheadSearch = ({ placeHolderText, renderValue }) => {
8888
const [state, dispatch] = useReducer(_reducer, _initialState);
8989

9090
/**
@@ -94,7 +94,7 @@ const MastheadSearch = ({
9494
* @param {string} newValue The new val of the input
9595
*/
9696
function onChange(event, { newValue }) {
97-
dispatch({type: 'setVal', payload: {val: newValue}});
97+
dispatch({ type: 'setVal', payload: { val: newValue } });
9898
}
9999

100100
/**
@@ -106,8 +106,12 @@ const MastheadSearch = ({
106106
placeholder: placeHolderText,
107107
value: state.val,
108108
onChange,
109-
onFocus: (e) => { e.target.placeholder = ''; },
110-
onBlur: (e) => { e.target.placeholder = placeHolderText; },
109+
onFocus: e => {
110+
e.target.placeholder = '';
111+
},
112+
onBlur: e => {
113+
e.target.placeholder = placeHolderText;
114+
},
111115
};
112116

113117
/**
@@ -128,12 +132,13 @@ const MastheadSearch = ({
128132
/**
129133
* Renders the Suggestion Value with the function for the adding the suggestion
130134
*
131-
* @param {object} suggestion The suggestion
132-
* @param {string} query The query being searched for
133-
* @param {boolean} isHighlighted Whether the suggestion is currently highlighted by the user
135+
* @param {object} suggestion The suggestion to render
136+
* @param {object} properties The property object of the incoming suggestion
137+
* @param {string} properties.query The query being searched for
138+
* @param {boolean} properties.isHighlighted Whether the suggestion is currently highlighted by the user
134139
* @returns {*} The suggestion value
135140
*/
136-
function renderSuggestionValue(suggestion, {query, isHighlighted}) {
141+
function renderSuggestion(suggestion, { query, isHighlighted }) {
137142
return (
138143
<MastheadSearchSuggestion
139144
suggestion={suggestion}
@@ -156,27 +161,35 @@ const MastheadSearch = ({
156161
* @param {string} request.value the current value of the input
157162
* @param {string} request.reason string describing why onSuggestionsFetchRequested was called
158163
*/
159-
function onSuggestionsFetchRequest(request) {
164+
async function onSuggestionsFetchRequest(request) {
160165
const searchValue = _trimAndLower(escapeRegExp(request.value));
161166

162-
if (request.reason === 'input-changed') { // if the search input has changed
163-
SearchTypeaheadAPI.getResults(searchValue).then((response) => {
164-
dispatch({type: 'setPrevSuggestions', payload: {prevSuggestions: response}});
165-
dispatch({type: 'setSuggestionsToPrevious'});
166-
dispatch({type: 'showSuggestionsContainer'});
167-
});
167+
if (request.reason === 'input-changed') {
168+
// if the search input has changed
169+
let response = await SearchTypeaheadAPI.getResults(searchValue);
170+
console.log('response', response);
171+
172+
if (response !== undefined) {
173+
console.log('response', response);
174+
dispatch({
175+
type: 'setPrevSuggestions',
176+
payload: { prevSuggestions: response },
177+
});
178+
dispatch({ type: 'setSuggestionsToPrevious' });
179+
dispatch({ type: 'showSuggestionsContainer' });
180+
}
168181
} else {
169-
dispatch({type: 'setSuggestionsToPrevious'});
170-
dispatch({type: 'showSuggestionsContainer'});
182+
dispatch({ type: 'setSuggestionsToPrevious' });
183+
dispatch({ type: 'showSuggestionsContainer' });
171184
}
172185
}
173186

174187
/**
175188
* Called every time we clear suggestions
176189
*/
177190
function onSuggestionsClearedRequested() {
178-
dispatch({type: 'emptySuggestions'});
179-
dispatch({type: 'hideSuggestionsContainer'});
191+
dispatch({ type: 'emptySuggestions' });
192+
dispatch({ type: 'hideSuggestionsContainer' });
180193
}
181194

182195
/**
@@ -190,15 +203,13 @@ const MastheadSearch = ({
190203
}
191204

192205
return (
193-
<div
194-
data-autoid="masthead__search"
195-
>
206+
<div data-autoid="masthead__search">
196207
<Autosuggest
197208
suggestions={state.suggestions} // The state value of suggestion
198209
onSuggestionsFetchRequested={onSuggestionsFetchRequest} // Method to fetch data (should be async call)
199210
onSuggestionsClearRequested={onSuggestionsClearedRequested} // When input bar loses focus
200211
getSuggestionValue={_getSuggestionValue} // Name of suggestion
201-
renderSuggestion={renderSuggestionValue} // How to display a suggestion
212+
renderSuggestion={renderSuggestion} // How to display a suggestion
202213
onSuggestionSelected={null} // When a suggestion is selected
203214
highlightFirstSuggestion // First suggestion is highlighted by default
204215
inputProps={inputProps}
@@ -212,16 +223,16 @@ const MastheadSearch = ({
212223
/**
213224
* @property propTypes
214225
* @description Defined property types for component
215-
* @type {{items: *}}
226+
* @type {{placeHolderText: shim, renderValue: shim}}
216227
*/
217228
MastheadSearch.propTypes = {
218229
placeHolderText: PropTypes.string,
219230
renderValue: PropTypes.number,
220231
};
221232

222233
/**
223-
*
224-
* @type {{setSuggestionValue: (function(*=): {name: *}), placeHolderText: string, renderValue: number}}
234+
* @property defaultProps
235+
* @type {{placeHolderText: string, renderValue: number}}
225236
*/
226237
MastheadSearch.defaultProps = {
227238
placeHolderText: '',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
// import classNames from 'classnames';
4+
5+
/**
6+
* Renders the input bar with the search icon
7+
*
8+
* @param {object} props Incoming props
9+
* @param {object} props.componentInputProps contains the input props
10+
* @param {Function} props.dispatch for component reducer
11+
* @returns {*} The rendered component
12+
*/
13+
const MastheadSearchInput = ({ componentInputProps, dispatch }) => (
14+
<div>
15+
<input {...componentInputProps} />
16+
<button
17+
type="button"
18+
onClick={() =>
19+
dispatch({ type: 'setVal', payload: { val: '' } })
20+
}></button>
21+
</div>
22+
);
23+
24+
/**
25+
* @property propTypes
26+
* @description Defined property types for component
27+
* @type {{placeHolderText: shim, renderValue: shim}}
28+
*/
29+
MastheadSearchInput.propTypes = {
30+
componentInputProps: PropTypes.object,
31+
dispatch: PropTypes.func,
32+
};
33+
34+
/**
35+
* @property defaultProps
36+
* @type {{placeHolderText: string, renderValue: number}}
37+
*/
38+
MastheadSearchInput.defaultProps = {
39+
componentInputProps: {},
40+
dispatch: () => {},
41+
};
42+
43+
export default MastheadSearchInput;

packages/react/src/components/Masthead/MastheadSearchInput.jsx

-28
This file was deleted.

0 commit comments

Comments
 (0)