-
Notifications
You must be signed in to change notification settings - Fork 557
feat(searchbox): implement InstantSearch.css #3127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This way, the root level only keeps a few boolean flag to activate / deactivate the reset, magnifier and loading indicator. This also defaults the visibility of the loading indicator to `true`.
|
Deploy preview for algolia-instantsearch ready! Built with commit 0c4f45a https://deploy-preview-3127--algolia-instantsearch.netlify.com |
francoischalifour
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few notes before approving.
src/widgets/search-box/search-box.js
Outdated
| const containerNode = getContainerNode(container); | ||
|
|
||
| if (containerNode.tagName === 'INPUT') { | ||
| throw new Error(`container should not be an INPUT`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be more explicit? (friendly error message, link to the migration guide)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK will provide a link to the current documentation.
| loadingIndicator, | ||
| searchAsYouType, | ||
| showReset, | ||
| showSubmit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does that option name come from?
It's not in the specs, is it InstantSearch.js-specific?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we were writing this component, we thought it was a good idea to let the user choose if they wanted the magnifying glass and the cross (with submit and reset behavior). The former name of the option is magnifier actually, I just renamed it.
Happy to change things here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this seems implemented, but not documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is documented there, right? https://github.com/algolia/instantsearch.js/blob/feat/3.0-searchbox/src/widgets/search-box/search-box.js#L162
|
I would also rename |
|
Now that the |
src/widgets/search-box/search-box.js
Outdated
| input.parentNode.insertBefore(htmlNode, input.nextSibling); | ||
| } | ||
| const form = document.createElement('form'); | ||
| form.className = cx(suit({ descendantName: 'form' }), cssClasses.form); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this kept in vanilla JS for compat reasons?
The form needs an onSubmit handler with preventDefault and the focus moving like in RIS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you tell me more about the behavior of the focus @Haroenv ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://blog.algolia.com/mobile-search-ux-tips/ should have most of it explained :) for the rest you can base on the React InstantSearch one, which I know is correct :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it's good now @Haroenv ? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so based on the code, but the dev novel still has the old code 🤔
This searchbox is used for the refinement list searchable feature. So it's kinda out of scope. |
src/widgets/search-box/search-box.js
Outdated
| }); | ||
| addListener(input, 'keyup', e => { | ||
| if (e.keyCode === KEY_ENTER) refine(getValue(e)); | ||
| if (e.keyCode === KEY_ENTER) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we have a form now, this can be done in a submit event on the form instead, and the ENTER code can be removed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes indeed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KEY_ENTER is unused and should be removed (see yarn run lint).
autofocus should be set to false by default now according to the specs, not to "autofocus".
Will review all changes more attentively later in the day :)
Indeed and I completely agree with that :) |
|
@bobylito |
src/widgets/search-box/search-box.js
Outdated
| }); | ||
| } else { | ||
| addListener(input, 'input', e => { | ||
| refine(getValue(e), false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can drop the call to getValue since we dropped the support of IE8.
src/widgets/search-box/search-box.js
Outdated
| const form = input.parentElement; | ||
|
|
||
| if (searchAsYouType) { | ||
| addListener(input, 'input', getInputValueAndCall(refine)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can drop the call to getInputValueAndCall since we dropped the support of IE8.
src/widgets/search-box/search-box.js
Outdated
| } | ||
|
|
||
| function addListener(el, type, fn) { | ||
| if (el.addEventListener) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can drop the call to addListener since we dropped the support of IE8.
src/widgets/search-box/search-box.js
Outdated
| : containerNode.querySelector(resetBtnSelector); | ||
| resetButton.style.display = query && query.trim() ? 'block' : 'none'; | ||
| } | ||
| renderAfterInit({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the previous implement we trigger this function only on render but now it also trigger on init, not sure about the implications. But we almost never render on the init lifecycle to avoid a flash with the empty state.
src/widgets/search-box/search-box.js
Outdated
| addListener(input, 'input', getInputValueAndCall(refine)); | ||
| addListener(form, 'submit', e => { | ||
| e.preventDefault(); | ||
| input.addEventListener('input', refine); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't work anymore since we provide the event to refine rather than the value. It should probably be catch with a test.
src/widgets/search-box/search-box.js
Outdated
| addListener(input, 'input', e => { | ||
| refine(getValue(e), false); | ||
| input.addEventListener('input', event => { | ||
| refine(event, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't work anymore since we provide the event to refine rather than the value. It should probably be catch with a test.
Haroenv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems correct now, doc question and migration change
docgen/src/guides/v3-migration.md
Outdated
|
|
||
| With the drop of `wrapInput`, we decided not to accept `input`s as containers anymore. If you want complete control over the rendering, you should use the `connectSearchBox` connector. | ||
|
|
||
| The search box does not support `powered-by`. If you're using a community plan, you should now use the `poweredBy` widget to display the Algolia logo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have to use the poweredBy widget
| loadingIndicator, | ||
| searchAsYouType, | ||
| showReset, | ||
| showSubmit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this seems implemented, but not documented?
Haroenv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
action=""on the form for iOS keyboard- firing "reset" should focus the input
Haroenv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice to have a story of autofocus: true now too (since it's no longer the defautl)
<a name=3.0.0-beta.0></a> # [3.0.0-beta.0](v2.10.3...v3.0.0-beta.0) (2018-12-10) ### Bug Fixes * **api:** remove transformData ([#3241](#3241)) ([5232936](5232936)) * **breadcrumb:** fix story with transformed label ([5a39312](5a39312)) * **breadcrumb:** rename item's name to label ([#3273](#3273)) ([0189cb4](0189cb4)) * **breadcrumb:** rename noRefinement to noRefinementRoot ([#3272](#3272)) ([21a5c61](21a5c61)) * **community:** fix search config ([#3142](#3142)) ([2b41982](2b41982)) * **connectRangeSlider:** remove deprecated connector ([#3189](#3189)) ([096ebeb](096ebeb)) * **current-refinements:** remove alphabetic sorting ([#3249](#3249)) ([9914f87](9914f87)), closes [/github.com/algolia/instantsearch.js/blob/011d47909894837f2c2da5088bc81803135d201b/src/lib/utils.js#L249](https://github.com//github.com/algolia/instantsearch.js/blob/011d47909894837f2c2da5088bc81803135d201b/src/lib/utils.js/issues/L249) * **getRefinements:** provide attributeName for type: query ([6006fe1](6006fe1)), closes [#3205](#3205) * **highlight:** avoid to ignore highlightedTagName ([#3323](#3323)) ([9871829](9871829)) * **highlight:** HighLight -> Highlight ([#3324](#3324)) ([5b4600d](5b4600d)) * **hits:** transform items after escaping ([#3251](#3251)) ([c46b82a](c46b82a)), closes [#3250](#3250) * **infiniteHits:** move option to templates ([#3300](#3300)) ([1828d66](1828d66)) * **InfiniteHits:** set the correct class for the last page ([#3232](#3232)) ([f604835](f604835)) * **lint:** remove unused import ([a9ec14c](a9ec14c)) * **pagination:** rename to ([#3275](#3275)) ([336945b](336945b)) * **range-input:** fix button classname ([#3234](#3234)) ([56695e1](56695e1)), closes [algolia/instantsearch-specs#92](algolia/instantsearch-specs#92) * **range-input:** remove templates ([#3128](#3128)) ([94a1ce5](94a1ce5)) * **rangeInput:** convert labels to templates ([#3312](#3312)) ([cdf91e8](cdf91e8)) * **rangeSlider:** fix CSS classes ([#3316](#3316)) ([56a5255](56a5255)) * **refinement-list:** remove in story ([0bf8db1](0bf8db1)) * **routing:** enforce RoutingManager is the last widget ([#3149](#3149)) ([1e86b2e](1e86b2e)), closes [#3148](#3148) * **searchbox:** fix and templates ([#3313](#3313)) ([4e13122](4e13122)) * **tests:** add react-test-renderer ([176494b](176494b)) * **toggleRefinement:** provide to templates ([#3303](#3303)) ([f515b62](f515b62)) ### Features * **3.0:** remove named exports on widgets ([#3129](#3129)) ([e718ea3](e718ea3)) * **breadcrumb:** implement InstantSearch.css ([#3115](#3115)) ([84d9f18](84d9f18)) * **clearRefinements:** implement InstantSearch.css ([#3308](#3308)) ([d98ecaf](d98ecaf)), closes [#3299](#3299) * **clearRefinements:** implement is.css ([#3114](#3114)) ([11cdc14](11cdc14)) * **current-refinements:** implement InstantSearch.css ([#3190](#3190)) ([a70917d](a70917d)) * **GeoSearch:** implement InstantSearch.css ([#3138](#3138)) ([1867d30](1867d30)) * **hierarchical-menu:** implement InstantSearch.css ([#3182](#3182)) ([be0890d](be0890d)) * **hierarchical-menu:** implement show more feature ([#3151](#3151)) ([f54fccd](f54fccd)) * **hierarchicalMenu:** merge showMore templates ([#3318](#3318)) ([0059251](0059251)) * **highlight:** export highlight function ([#3137](#3137)) ([d4b6fb1](d4b6fb1)) * **highlight:** implement InstantSearch.css ([#3132](#3132)) ([260a0b8](260a0b8)) * **hits:** implement InstantSearch.css ([#3096](#3096)) ([b3cc413](b3cc413)) * **hits-per-page:** implement InstantSearch.css ([#3125](#3125)) ([49e7096](49e7096)) * **menu:** implement InstantSearch.css ([#3181](#3181)) ([a274ab7](a274ab7)) * **menuSelect:** implement is.css ([#3109](#3109)) ([43e654a](43e654a)) * **numeric-menu:** implement InstantSearch.css ([#3162](#3162)) ([f5358f4](f5358f4)) * **numericSelector:** remove widget ([#3183](#3183)) ([e9063c0](e9063c0)) * **pagination:** implement InstantSearch.css ([#3119](#3119)) ([f3c3343](f3c3343)) * **panel:** add Panel widget ([#3253](#3253)) ([82e19fc](82e19fc)) * **poweredBy:** implement InstantSearch.css ([#3164](#3164)) ([bcc18a0](bcc18a0)) * **poweredBy:** update logo ([#3256](#3256)) ([838abec](838abec)) * **price-ranges:** implement InstantSearch.css ([#3124](#3124)) ([335339b](335339b)) * **range-input:** implement InstantSearch.css ([#3098](#3098)) ([ee6bc7e](ee6bc7e)) * **range-slider:** implement InstantSearch.css ([#3126](#3126)) ([b9b8d31](b9b8d31)) * **rating-menu:** implement InstantSearch.css ([#3161](#3161)) ([d039e11](d039e11)) * **ratingMenu:** merge labels and templates ([#3317](#3317)) ([505a2e7](505a2e7)) * **refinement-list:** implement InstantSearch.css ([#3152](#3152)) ([11c5580](11c5580)) * **refinement-list:** implement InstantSearch.css (2) ([#3179](#3179)) ([0365641](0365641)) * **refinement-list:** implement InstantSearch.css to searchbox ([#3263](#3263)) ([ad905c7](ad905c7)) * **search-client:** use search client ([#3133](#3133)) ([8e70a3e](8e70a3e)) * **searchbox:** implement InstantSearch.css ([#3127](#3127)) ([c68c1fe](c68c1fe)) * **snippet:** implement InstantSearch.css ([#3134](#3134)) ([fa56657](fa56657)) * **sort-by:** implement InstantSearch.css ([#3120](#3120)) ([5f21723](5f21723)) * **sortBy:** rename item to ([#3230](#3230)) ([9e24a68](9e24a68)) * **stats:** implement InstantSearch.css ([#3097](#3097)) ([63a688e](63a688e)) * **stories:** add default CurrentRefinements story ([#3252](#3252)) ([45a8fd5](45a8fd5)) * **suit:** Default component names to empty object ([0b26356](0b26356)) * **suit-helper:** provide a helper to create suit css classnames ([f142496](f142496)) * **toggleRefinement:** implement InstantSearch.css ([#3135](#3135)) ([d67a437](d67a437)) * compress templates ([#3176](#3176)) ([54f2f77](54f2f77)), closes [#3095](#3095) * **widgets:** use warn utils ([#3175](#3175)) ([3164b06](3164b06))
<a name=3.0.0-beta.1></a> # [3.0.0-beta.1](v2.10.3...v3.0.0-beta.1) (2018-12-14) ### Bug Fixes * **api:** remove transformData ([#3241](#3241)) ([5232936](5232936)) * **breadcrumb:** fix story with transformed label ([5a39312](5a39312)) * **breadcrumb:** rename item's name to label ([#3273](#3273)) ([0189cb4](0189cb4)) * **breadcrumb:** rename noRefinement to noRefinementRoot ([#3272](#3272)) ([21a5c61](21a5c61)) * **community:** fix search config ([#3142](#3142)) ([2b41982](2b41982)) * **configure:** make lifecycle functions optional ([#3339](#3339)) ([2b88cfa](2b88cfa)) * **connectRangeSlider:** remove deprecated connector ([#3189](#3189)) ([096ebeb](096ebeb)) * **current-refinements:** remove alphabetic sorting ([#3249](#3249)) ([9914f87](9914f87)), closes [/github.com/algolia/instantsearch.js/blob/011d47909894837f2c2da5088bc81803135d201b/src/lib/utils.js#L249](https://github.com//github.com/algolia/instantsearch.js/blob/011d47909894837f2c2da5088bc81803135d201b/src/lib/utils.js/issues/L249) * **getRefinements:** provide attributeName for type: query ([6006fe1](6006fe1)), closes [#3205](#3205) * **highlight:** avoid to ignore highlightedTagName ([#3323](#3323)) ([9871829](9871829)) * **highlight:** HighLight -> Highlight ([#3324](#3324)) ([5b4600d](5b4600d)) * **hits:** transform items after escaping ([#3251](#3251)) ([c46b82a](c46b82a)), closes [#3250](#3250) * **infiniteHits:** move option to templates ([#3300](#3300)) ([1828d66](1828d66)) * **InfiniteHits:** set the correct class for the last page ([#3232](#3232)) ([f604835](f604835)) * **lint:** remove unused import ([a9ec14c](a9ec14c)) * **pagination:** rename to ([#3275](#3275)) ([336945b](336945b)) * **poweredBy:** export connectPoweredBy connector ([#3331](#3331)) ([7d48c46](7d48c46)) * **poweredBy:** fix CSS classes ([#3332](#3332)) ([abc9b82](abc9b82)) * **range-input:** fix button classname ([#3234](#3234)) ([56695e1](56695e1)), closes [algolia/instantsearch-specs#92](algolia/instantsearch-specs#92) * **range-input:** remove templates ([#3128](#3128)) ([94a1ce5](94a1ce5)) * **rangeInput:** convert labels to templates ([#3312](#3312)) ([cdf91e8](cdf91e8)) * **rangeSlider:** fix CSS classes ([#3316](#3316)) ([56a5255](56a5255)) * **refinement-list:** remove in story ([0bf8db1](0bf8db1)) * **routing:** enforce RoutingManager is the last widget ([#3149](#3149)) ([1e86b2e](1e86b2e)), closes [#3148](#3148) * **searchbox:** fix and templates ([#3313](#3313)) ([4e13122](4e13122)) * **tests:** add react-test-renderer ([176494b](176494b)) * **toggleRefinement:** provide to templates ([#3303](#3303)) ([f515b62](f515b62)) ### Features * **3.0:** remove named exports on widgets ([#3129](#3129)) ([e718ea3](e718ea3)) * **breadcrumb:** implement InstantSearch.css ([#3115](#3115)) ([84d9f18](84d9f18)) * **bundle:** update bundle strategy ([#3260](#3260)) ([a7dab81](a7dab81)) * **clearRefinements:** implement InstantSearch.css ([#3308](#3308)) ([d98ecaf](d98ecaf)), closes [#3299](#3299) * **clearRefinements:** implement is.css ([#3114](#3114)) ([11cdc14](11cdc14)) * **current-refinements:** implement InstantSearch.css ([#3190](#3190)) ([a70917d](a70917d)) * **GeoSearch:** implement InstantSearch.css ([#3138](#3138)) ([1867d30](1867d30)) * **hierarchical-menu:** implement InstantSearch.css ([#3182](#3182)) ([be0890d](be0890d)) * **hierarchical-menu:** implement show more feature ([#3151](#3151)) ([f54fccd](f54fccd)) * **hierarchicalMenu:** merge showMore templates ([#3318](#3318)) ([0059251](0059251)) * **highlight:** export highlight function ([#3137](#3137)) ([d4b6fb1](d4b6fb1)) * **highlight:** implement InstantSearch.css ([#3132](#3132)) ([260a0b8](260a0b8)) * **hits:** implement InstantSearch.css ([#3096](#3096)) ([b3cc413](b3cc413)) * **hits-per-page:** implement InstantSearch.css ([#3125](#3125)) ([49e7096](49e7096)) * **infiniteHits:** rename showMore template to showMoreText ([#3330](#3330)) ([babad39](babad39)) * **menu:** implement InstantSearch.css ([#3181](#3181)) ([a274ab7](a274ab7)) * **menu:** merge showMore templates ([#3328](#3328)) ([73a450b](73a450b)) * **menuSelect:** implement is.css ([#3109](#3109)) ([43e654a](43e654a)) * **numeric-menu:** implement InstantSearch.css ([#3162](#3162)) ([f5358f4](f5358f4)) * **numericSelector:** remove widget ([#3183](#3183)) ([e9063c0](e9063c0)) * **pagination:** implement InstantSearch.css ([#3119](#3119)) ([f3c3343](f3c3343)) * **pagination:** rename labels to templates ([#3333](#3333)) ([9f24098](9f24098)) * **panel:** add Panel widget ([#3253](#3253)) ([82e19fc](82e19fc)) * **poweredBy:** disable setting URL from widget ([#3334](#3334)) ([a5ff6af](a5ff6af)) * **poweredBy:** implement InstantSearch.css ([#3164](#3164)) ([bcc18a0](bcc18a0)) * **poweredBy:** update logo ([#3256](#3256)) ([838abec](838abec)) * **price-ranges:** implement InstantSearch.css ([#3124](#3124)) ([335339b](335339b)) * **range-input:** implement InstantSearch.css ([#3098](#3098)) ([ee6bc7e](ee6bc7e)) * **range-slider:** implement InstantSearch.css ([#3126](#3126)) ([b9b8d31](b9b8d31)) * **rating-menu:** implement InstantSearch.css ([#3161](#3161)) ([d039e11](d039e11)) * **ratingMenu:** merge labels and templates ([#3317](#3317)) ([505a2e7](505a2e7)) * **refinement-list:** implement InstantSearch.css ([#3152](#3152)) ([11c5580](11c5580)) * **refinement-list:** implement InstantSearch.css (2) ([#3179](#3179)) ([0365641](0365641)) * **refinement-list:** implement InstantSearch.css to searchbox ([#3263](#3263)) ([ad905c7](ad905c7)) * **refinementList:** merge showMore templates ([#3329](#3329)) ([9b6a9c4](9b6a9c4)) * **search-client:** use search client ([#3133](#3133)) ([8e70a3e](8e70a3e)) * **searchbox:** implement InstantSearch.css ([#3127](#3127)) ([c68c1fe](c68c1fe)) * **snippet:** implement InstantSearch.css ([#3134](#3134)) ([fa56657](fa56657)) * **sort-by:** implement InstantSearch.css ([#3120](#3120)) ([5f21723](5f21723)) * **sortBy:** rename item to ([#3230](#3230)) ([9e24a68](9e24a68)) * **stats:** implement InstantSearch.css ([#3097](#3097)) ([63a688e](63a688e)) * **stories:** add default CurrentRefinements story ([#3252](#3252)) ([45a8fd5](45a8fd5)) * **suit:** Default component names to empty object ([0b26356](0b26356)) * **suit-helper:** provide a helper to create suit css classnames ([f142496](f142496)) * **toggleRefinement:** implement InstantSearch.css ([#3135](#3135)) ([d67a437](d67a437)) * **widgets:** use warn utils ([#3175](#3175)) ([3164b06](3164b06)) * compress templates ([#3176](#3176)) ([54f2f77](54f2f77)), closes [#3095](#3095)
| // Only possible values are 'auto', true and false | ||
| if (typeof autofocus !== 'boolean') { | ||
| autofocus = 'auto'; | ||
| if (containerNode.tagName === 'INPUT') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
Why would you force user to not use an already existing input as a search input?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change was made to be more consistent across all widgets in all InstantSearch flavors. You probably want to use connectSearchBox now.
Please file an issue if you have trouble migrating.
This updates the usage errors messages for `searchBox`. - `input`s are not valid containers anymore - `autofocus` used to accept string values for `"auto"`, which is not a valid value for the HTML attribute `autofocus` (converted to a warning). > Related: #3127 (review)
Specs
https://instantsearch-css.netlify.com/widgets/search-box/
Stories
https://deploy-preview-3127--algolia-instantsearch.netlify.com/v2/dev-novel/?selectedStory=SearchBox.default