Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

feat: loading indicator #544

Merged
merged 36 commits into from
Dec 8, 2017
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
12edcd6
chore(package.json): update yarn requirement
bobylito Oct 31, 2017
317e2a5
feat(loading-indicator): add information about stalled searches
bobylito Oct 31, 2017
cc40543
feat(loading-indicator): Make timeout for stalled search configurable
bobylito Oct 31, 2017
05eebf0
feat(loading-indicator): add option to searchbox
bobylito Oct 31, 2017
37d353c
chore(ci): update yarn version in travis config
bobylito Nov 2, 2017
eb55566
chore: rename stalledSearchTimeout into stalledSearchDelay
bobylito Nov 27, 2017
549368f
fix: revert behaviour change of `searching`
bobylito Dec 4, 2017
499525d
feat(SearchBox): new API for the loading indicator
bobylito Dec 4, 2017
b6c6e5b
Merge remote-tracking branch 'origin' into feat/searchbox-loading-ind…
bobylito Dec 4, 2017
f2b3ccf
fix: actually add the loading indicator
bobylito Dec 4, 2017
6a3d96b
chore(stories): add with custom loading indicator
bobylito Dec 4, 2017
dd9a214
chore(doc): add doc for new API
bobylito Dec 4, 2017
38990cd
chore(createInstantSearchManager): test loading status
bobylito Dec 5, 2017
17f3a3e
chore: remove loading indicator DOM when not needed
bobylito Dec 5, 2017
5dbcaed
Merge branch 'master' into feat/searchbox-loading-indicator
bobylito Dec 5, 2017
090b338
refactor(createInstantSearchManager): isSearchStalled should be in store
bobylito Dec 7, 2017
249a66e
refactoring(InstantSearch): stalledSearchDelay as a defaultProps
bobylito Dec 7, 2017
06c25f8
refactor(SearchBox): isSearchStalled computed once
bobylito Dec 7, 2017
94b5d3d
chore: eslint:fix
bobylito Dec 7, 2017
b0c59a4
refactor(SearchBox): use default props for components
bobylito Dec 7, 2017
10e94d1
chore: isSearchStalled should have a default value
bobylito Dec 7, 2017
cf84f01
chore: update yarn version (consistency)
bobylito Dec 7, 2017
a6783a5
chore: remove props since it's the same value as default
bobylito Dec 7, 2017
4f1e07f
Merge branch 'feat/searchbox-loading-indicator' of github.com:algolia…
bobylito Dec 7, 2017
4999728
Merge branch 'master' into feat/searchbox-loading-indicator
bobylito Dec 7, 2017
7c63e77
chore(storybook): loading indicator as knob
bobylito Dec 7, 2017
5d95fd4
chore: udpate the behaviour and improve test
bobylito Dec 7, 2017
7432ec9
Merge branch 'feat/searchbox-loading-indicator' of github.com:algolia…
bobylito Dec 7, 2017
624a58a
chore: fix lint
bobylito Dec 7, 2017
54ac58c
refactor: variable renaming in createConnector
bobylito Dec 7, 2017
a14ed1a
Merge branch 'master' into feat/searchbox-loading-indicator
bobylito Dec 8, 2017
f594a62
chore: syntactic sugar
bobylito Dec 8, 2017
af014c3
chore(SearchBox): test behaviour with stalled search
bobylito Dec 8, 2017
8521fa3
Merge branch 'feat/searchbox-loading-indicator' of github.com:algolia…
bobylito Dec 8, 2017
84a4614
refactor: consolidate destructuring of props
bobylito Dec 8, 2017
c9e156c
Merge branch 'master' into feat/searchbox-loading-indicator
samouss Dec 8, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ addons:
before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.2.0
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.3.2
- export PATH=$HOME/.yarn/bin:$PATH
cache:
yarn: true
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
},
"engines": {
"node": "8.6.0",
"yarn": "1.2.0"
"yarn": "1.3.2"
},
"jest": {
"notify": false,
Expand Down
31 changes: 31 additions & 0 deletions packages/react-instantsearch-theme-algolia/styles/_SearchBox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,34 @@ $main-searchbox-config: (
.ais-SearchBox {
@include searchbox($main-searchbox-config...);
}

.ais-SearchBox__loading-indicator {
position: absolute;
top: 0;
right: inherit;
left: 0;
margin: 0;
border: 0;
border-radius: 4px 0 0 4px;
background-color: rgba(255, 255, 255, 0);
padding: 0;
width: 46px;
height: 100%;
vertical-align: middle;
text-align: center;
font-size: inherit;
}

.ais-SearchBox__loading-indicator::before {
display: inline-block;
margin-right: -4px;
height: 100%;
vertical-align: middle;
content: '';
}

.ais-SearchBox__loading-indicator > svg {
height: 1.3em;
width: 1.3em;
margin-top: 1em;
}
86 changes: 70 additions & 16 deletions packages/react-instantsearch/src/components/SearchBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,51 @@ import classNames from './classNames.js';

const cx = classNames('SearchBox');

const DefaultLoadingIndicator = () => (
<svg
width="18"
height="18"
viewBox="0 0 38 38"
xmlns="http://www.w3.org/2000/svg"
stroke="#BFC7D8"
>
<g fill="none" fillRule="evenodd">
<g transform="translate(1 1)" strokeWidth="2">
<circle strokeOpacity=".5" cx="18" cy="18" r="18" />
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"
/>
</path>
</g>
</g>
</svg>
);

const DefaultReset = () => (
<svg role="img" width="1em" height="1em">
<use xlinkHref="#sbx-icon-clear-3" />
</svg>
);

const DefaultSubmit = () => (
<svg role="img" width="1em" height="1em">
<use xlinkHref="#sbx-icon-search-13" />
</svg>
);

class SearchBox extends Component {
static propTypes = {
currentRefinement: PropTypes.string,
refine: PropTypes.func.isRequired,
translate: PropTypes.func.isRequired,

loadingIndicatorComponent: PropTypes.element,
resetComponent: PropTypes.element,
submitComponent: PropTypes.element,

Expand All @@ -25,6 +64,9 @@ class SearchBox extends Component {
onReset: PropTypes.func,
onChange: PropTypes.func,

isSearchStalled: PropTypes.bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could set this value required since isSearchStalled will be always pass to the component.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a usage perspective, I would argue that this value is only useful if showLoadingIndicator is true and the only value that we really about is true. Considering that, do you think it should still be marked as required?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can leave it as it it then, but when we define an optional props it's recommended to always give them a default value. So we can put a default value to false on the isSearchStalled. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok WFM 👍

showLoadingIndicator: PropTypes.bool,

// For testing purposes
__inputRef: PropTypes.func,
};
Expand All @@ -34,6 +76,11 @@ class SearchBox extends Component {
focusShortcuts: ['s', '/'],
autoFocus: false,
searchAsYouType: true,
showLoadingIndicator: false,
isSearchStalled: false,
loadingIndicatorComponent: <DefaultLoadingIndicator />,
submitComponent: <DefaultSubmit />,
resetComponent: <DefaultReset />,
};

constructor(props) {
Expand Down Expand Up @@ -156,21 +203,9 @@ class SearchBox extends Component {
const { translate, autoFocus } = this.props;
const query = this.getQuery();

const submitComponent = this.props.submitComponent ? (
this.props.submitComponent
) : (
<svg role="img" width="1em" height="1em">
<use xlinkHref="#sbx-icon-search-13" />
</svg>
);

const resetComponent = this.props.resetComponent ? (
this.props.resetComponent
) : (
<svg role="img" width="1em" height="1em">
<use xlinkHref="#sbx-icon-clear-3" />
</svg>
);
const submitComponent = this.props.submitComponent;
const resetComponent = this.props.resetComponent;
const loadingIndicatorComponent = this.props.loadingIndicatorComponent;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use destructuring assignment for those variables.


const searchInputEvents = Object.keys(this.props).reduce((props, prop) => {
if (
Expand All @@ -184,6 +219,9 @@ class SearchBox extends Component {
return props;
}, {});

const isSearchStalled =
this.props.showLoadingIndicator && this.props.isSearchStalled;

/* eslint-disable max-len */
return (
<form
Expand Down Expand Up @@ -216,7 +254,10 @@ class SearchBox extends Component {
/>
</symbol>
</svg>
<div role="search" {...cx('wrapper')}>
<div
role="search"
{...cx('wrapper', isSearchStalled && 'stalled-search')}
>
<input
ref={this.onInputMount}
type="search"
Expand All @@ -233,9 +274,22 @@ class SearchBox extends Component {
{...searchInputEvents}
{...cx('input')}
/>
{this.props.showLoadingIndicator && (
<div
style={{
display: isSearchStalled ? 'block' : 'none',
}}
{...cx('loading-indicator')}
>
{loadingIndicatorComponent}
</div>
)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a test for this logic. Verify depending on the given props that the loading component is displayed or not (with a Snapshot).

<button
type="submit"
title={translate('submitTitle')}
style={{
display: isSearchStalled ? 'none' : 'block',
}}
{...cx('submit')}
>
{submitComponent}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ exports[`Menu Menu with search inside items but no search results 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -230,6 +235,11 @@ exports[`Menu Menu with search inside items with search results 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -352,6 +362,11 @@ exports[`Menu applies translations 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ exports[`RefinementList applies translations 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -320,6 +325,11 @@ exports[`RefinementList refinement list with search inside items but no search r
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -503,6 +513,11 @@ exports[`RefinementList refinement list with search inside items with search res
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ exports[`SearchBox applies its default props 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -149,6 +154,11 @@ exports[`SearchBox lets you customize its theme 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -240,6 +250,11 @@ exports[`SearchBox lets you customize its translations 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -331,6 +346,11 @@ exports[`SearchBox lets you give custom components for reset and submit 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -414,6 +434,11 @@ exports[`SearchBox transfers the autoFocus prop to the underlying input element
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -505,6 +530,11 @@ exports[`SearchBox treats its query prop as its input value 1`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down Expand Up @@ -596,6 +626,11 @@ exports[`SearchBox treats its query prop as its input value 2`] = `
/>
<button
className="ais-SearchBox__submit"
style={
Object {
"display": "block",
}
}
title="Submit your search query."
type="submit"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function cleanUp(props, searchState, context) {
* @providedPropType {function} refine - a function to remove a single filter
* @providedPropType {function} createURL - a function to generate a URL for the corresponding search state
* @providedPropType {string} currentRefinement - the query to search for.
* @providedPropType {boolean} isSearchStalled - a flag that indicates if react-is has detected that searches are stalled.
*/
export default createConnector({
displayName: 'AlgoliaSearchBox',
Expand All @@ -55,9 +56,10 @@ export default createConnector({
defaultRefinement: PropTypes.string,
},

getProvidedProps(props, searchState) {
getProvidedProps(props, searchState, searchResults) {
return {
currentRefinement: getCurrentRefinement(props, searchState, this.context),
isSearchStalled: searchResults.isSearchStalled,
};
},

Expand Down
Loading