Skip to content

Commit

Permalink
feat(widgets): auto hide some widgets
Browse files Browse the repository at this point in the history
We now auto hide:
- refinementList
- menu
- rangeSlider
- toggle
- pagination

+ option hideWhenNoResults available for all widgets
+ refactor the way we handle hiding: now somehow a decorator, see:
  - https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775
  - https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775#gistcomment-1574787

For more details, or ask me.
  • Loading branch information
vvo committed Sep 24, 2015
1 parent 8435bc5 commit 187b4bd
Show file tree
Hide file tree
Showing 18 changed files with 121 additions and 60 deletions.
7 changes: 5 additions & 2 deletions README.md
Expand Up @@ -264,6 +264,7 @@ search.addWidget(
* @param {String|DOMElement} options.container Valid CSS Selector as a string or DOMElement
* @param {Array} options.indices Array of objects defining the different indices to choose from. Each object must contain a `name` and `label` key.
* @param {String} [options.cssClass] Class name(s) to be added to the generated select element
* @param {boolean} [hideIfEmpty=false] Hide the container when no results match
* @return {Object}
*/
```
Expand Down Expand Up @@ -355,6 +356,7 @@ search.addWidget(
* @param {String} options.facetName Name of the attribute for faceting (eg. "free_shipping")
* @param {String} options.label Human-readable name of the filter (eg. "Free Shipping")
* @param {String|Function} [options.template] Item template, provided with `label` and `isRefined`
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
```
Expand Down Expand Up @@ -386,7 +388,7 @@ search.addWidget(
* @param {String|Function} [options.templates.footer] Footer template
* @param {String|Function} [options.singleRefine=true] Are multiple refinements allowed or only one at the same time. You can use this
* to build radio based refinement lists for example
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
```
Expand Down Expand Up @@ -429,7 +431,7 @@ search.addWidget(
* @param {String|Function} [options.templates.header=''] Header template
* @param {String|Function} [options.templates.item='<a href="{{href}}">{{name}}</a> {{count}}'] Item template, provided with `name`, `count`, `isRefined`
* @param {String|Function} [options.templates.footer=''] Footer template
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
```
Expand Down Expand Up @@ -466,6 +468,7 @@ search.addWidget(
* You can also provide
* tooltips: {format: function(formattedValue, rawValue) {return '$' + formattedValue}}
* So that you can format the tooltip display value as you want
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
```
Expand Down
4 changes: 3 additions & 1 deletion components/IndexSelector.js
@@ -1,5 +1,7 @@
var React = require('react');

var autoHide = require('../decorators/autoHide');

class IndexSelector extends React.Component {
handleChange(event) {
this.props.setIndex(event.target.value).search();
Expand Down Expand Up @@ -34,4 +36,4 @@ IndexSelector.propTypes = {
setIndex: React.PropTypes.func
};

module.exports = IndexSelector;
module.exports = autoHide(IndexSelector);
8 changes: 3 additions & 5 deletions components/Pagination/Pagination.js
Expand Up @@ -6,6 +6,8 @@ var Paginator = require('./Paginator');
var PaginationHiddenLink = require('./PaginationHiddenLink');
var PaginationLink = require('./PaginationLink');

var autoHide = require('../../decorators/autoHide');

var bem = require('../../lib/utils').bemHelper;
var cx = require('classnames');

Expand Down Expand Up @@ -99,10 +101,6 @@ class Pagination extends React.Component {
}

render() {
if (this.props.nbHits === 0) {
return null;
}

var pager = new Paginator({
currentPage: this.props.currentPage,
total: this.props.nbPages,
Expand Down Expand Up @@ -156,4 +154,4 @@ Pagination.defaultProps = {
padding: 3
};

module.exports = Pagination;
module.exports = autoHide(Pagination);
3 changes: 2 additions & 1 deletion components/RefinementList.js
@@ -1,6 +1,7 @@
var React = require('react');

var Template = require('./Template');
var autoHide = require('../decorators/autoHide');
var cx = require('classnames');

class RefinementList extends React.Component {
Expand Down Expand Up @@ -108,4 +109,4 @@ RefinementList.defaultProps = {
}
};

module.exports = RefinementList;
module.exports = autoHide(RefinementList);
3 changes: 2 additions & 1 deletion components/Slider/index.js
@@ -1,6 +1,7 @@
var React = require('react');

var Nouislider = require('react-nouislider');
var autoHide = require('../../decorators/autoHide');

require('style?prepend!raw!./index.css');

Expand Down Expand Up @@ -38,4 +39,4 @@ Slider.propTypes = {
])
};

module.exports = Slider;
module.exports = autoHide(Slider);
3 changes: 2 additions & 1 deletion components/Stats.js
@@ -1,6 +1,7 @@
var React = require('react');

var Template = require('./Template');
var autoHide = require('../decorators/autoHide');

class Stats extends React.Component {
render() {
Expand Down Expand Up @@ -42,4 +43,4 @@ Stats.propTypes = {
query: React.PropTypes.string
};

module.exports = Stats;
module.exports = autoHide(Stats);
3 changes: 2 additions & 1 deletion components/Toggle.js
@@ -1,6 +1,7 @@
var React = require('react');

var Template = require('./Template');
var autoHide = require('../decorators/autoHide');
var debounce = require('lodash/function/debounce');

class Toggle extends React.Component {
Expand Down Expand Up @@ -35,4 +36,4 @@ Toggle.propTypes = {
isRefined: React.PropTypes.bool
};

module.exports = Toggle;
module.exports = autoHide(Toggle);
43 changes: 43 additions & 0 deletions decorators/autoHide.js
@@ -0,0 +1,43 @@
var React = require('react');

function autoHide(ComposedComponent) {
class AutoHide extends React.Component {
componentDidMount() {
this._hideOrShowContainer(this.props);
}

componentWillReceiveProps(nextProps) {
this._hideOrShowContainer(nextProps);
}

_hideOrShowContainer(props) {
var container = React.findDOMNode(this).parentNode;
if (props.hideIfEmpty === true && props.hasResults === false) {
container.style.display = 'none';
} else if (props.hideIfEmpty === true) {
container.style.display = '';
}
}

render() {
if (this.props.hasResults === false &&
this.props.hideIfEmpty === true) {
return <div/>;
}

return <ComposedComponent {...this.props} />;
}
}

AutoHide.propTypes = {
hasResults: React.PropTypes.bool.isRequired,
hideIfEmpty: React.PropTypes.bool.isRequired
};

// precise displayName for ease of debugging (react dev tool, react warnings)
AutoHide.displayName = ComposedComponent.name + '-AutoHide';

return AutoHide;
}

module.exports = autoHide;
2 changes: 0 additions & 2 deletions index.js
Expand Up @@ -3,8 +3,6 @@ var toFactory = require('to-factory');
var InstantSearch = require('./lib/InstantSearch');
var instantsearch = toFactory(InstantSearch);

require('style?prepend!raw!./lib/style.css');

instantsearch.widgets = {
hits: require('./widgets/hits'),
indexSelector: require('./widgets/index-selector'),
Expand Down
3 changes: 0 additions & 3 deletions lib/style.css

This file was deleted.

9 changes: 8 additions & 1 deletion widgets/hits.js
Expand Up @@ -2,7 +2,12 @@ var React = require('react');

var utils = require('../lib/utils.js');

function hits({container = null, templates = {}, hitsPerPage = 20}) {
function hits({
container = null,
templates = {},
hitsPerPage = 20,
hideIfEmpty = false
}) {
var Hits = require('../components/Hits');

var containerNode = utils.getContainerNode(container);
Expand All @@ -16,6 +21,8 @@ function hits({container = null, templates = {}, hitsPerPage = 20}) {
results={results}
helper={helper}
noResultsTemplate={templates.empty}
hideIfEmpty={hideIfEmpty}
hasResults={results.hits.length > 0}
hitTemplate={templates.hit}
/>,
containerNode
Expand Down
8 changes: 6 additions & 2 deletions widgets/index-selector.js
Expand Up @@ -8,12 +8,14 @@ var utils = require('../lib/utils.js');
* @param {String|DOMElement} options.container Valid CSS Selector as a string or DOMElement
* @param {Array} options.indices Array of objects defining the different indices to choose from. Each object must contain a `name` and `label` key.
* @param {String} [options.cssClass] Class name(s) to be added to the generated select element
* @param {boolean} [hideIfEmpty=false] Hide the container when no results match
* @return {Object}
*/
function indexSelector({
container = null,
indices = null,
cssClass
cssClass,
hideIfEmpty = false
}) {
var IndexSelector = require('../components/IndexSelector');
var containerNode = utils.getContainerNode(container);
Expand All @@ -32,14 +34,16 @@ function indexSelector({
}
},

render: function({helper}) {
render: function({helper, results}) {
var containerId = containerNode.id;
React.render(
<IndexSelector
containerId={containerId}
cssClass={cssClass}
currentIndex={helper.getIndex()}
indices={indices}
hideIfEmpty={hideIfEmpty}
hasResults={results.hits.length > 0}
setIndex={helper.setIndex.bind(helper)}
/>,
containerNode
Expand Down
22 changes: 6 additions & 16 deletions widgets/menu.js
Expand Up @@ -28,7 +28,7 @@ var defaults = require('lodash/object/defaults');
* @param {String|Function} [options.templates.item='<a href="{{href}}">{{name}}</a> {{count}}'] Item template, provided with `name`, `count`, `isRefined`
* @param {String|Function} [options.templates.footer=''] Footer template
* @param {Function} [options.transformData] Method to change the object passed to the item template
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
function menu({
Expand All @@ -41,7 +41,7 @@ function menu({
list: null,
item: null
},
hideWhenNoResults = true,
hideIfEmpty = true,
templates = defaultTemplates,
transformData = null
}) {
Expand Down Expand Up @@ -70,26 +70,16 @@ function menu({
}]
}),
render: function({results, helper}) {
var values = getFacetValues(results, hierarchicalFacetName, sortBy, limit);

if (values.length === 0) {
React.render(<div/>, containerNode);
if (hideWhenNoResults === true) {
containerNode.classList.add('as-display-none');
}
return;
}

if (hideWhenNoResults === true) {
containerNode.classList.remove('as-display-none');
}
var facetValues = getFacetValues(results, hierarchicalFacetName, sortBy, limit);

React.render(
<RefinementList
cssClasses={cssClasses}
facetValues={getFacetValues(results, hierarchicalFacetName, sortBy, limit)}
facetValues={facetValues}
templates={templates}
transformData={transformData}
hideIfEmpty={hideIfEmpty}
hasResults={facetValues.length > 0}
toggleRefinement={toggleRefinement.bind(null, helper, hierarchicalFacetName)}
/>,
containerNode
Expand Down
11 changes: 10 additions & 1 deletion widgets/pagination.js
Expand Up @@ -2,7 +2,14 @@ var React = require('react');

var utils = require('../lib/utils.js');

function pagination({container, cssClass, labels, maxPages, showFirstLast} = {}) {
function pagination({
container = null,
cssClass,
labels,
maxPages,
showFirstLast,
hideIfEmpty = true
}) {
var Pagination = require('../components/Pagination/Pagination.js');

var containerNode = utils.getContainerNode(container);
Expand All @@ -21,6 +28,8 @@ function pagination({container, cssClass, labels, maxPages, showFirstLast} = {})
nbPages={nbPages}
setCurrentPage={helper.setCurrentPage.bind(helper)}
cssClass={cssClass}
hideIfEmpty={hideIfEmpty}
hasResults={results.hits.length > 0}
labels={labels}
showFirstLast={showFirstLast}
/>,
Expand Down
14 changes: 10 additions & 4 deletions widgets/range-slider.js
Expand Up @@ -11,12 +11,14 @@ var utils = require('../lib/utils.js');
* You can also provide
* tooltips: {format: function(formattedValue, rawValue) {return '$' + formattedValue}}
* So that you can format the tooltip display value as you want
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
function rangeSlider({
container = null,
facetName = null,
tooltips = true
tooltips = true,
hideIfEmpty = true
}) {
var Slider = require('../components/Slider');

Expand Down Expand Up @@ -58,15 +60,19 @@ function rangeSlider({

var currentRefinement = this._getCurrentRefinement(helper);

if (!stats) {
React.render(<div/>, containerNode);
return;
if (stats === undefined) {
stats = {
min: null,
max: null
};
}

React.render(
<Slider
start={[currentRefinement.min, currentRefinement.max]}
range={{min: stats.min, max: stats.max}}
hideIfEmpty={hideIfEmpty}
hasResults={stats.min !== null && stats.max !== null}
onChange={this._refine.bind(this, helper)}
tooltips={tooltips}
/>,
Expand Down

0 comments on commit 187b4bd

Please sign in to comment.