Skip to content

Commit

Permalink
feat(connector): connectNumericSelector (iteration 2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandre Stanislawski committed Mar 22, 2017
1 parent 4111c90 commit 1eda8a2
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


import sinon from 'sinon';

import jsHelper from 'algoliasearch-helper';
Expand Down Expand Up @@ -56,8 +54,6 @@ describe('connectNumericSelector', () => {

const firstRenderingOptions = rendering.lastCall.args[0];
expect(firstRenderingOptions.currentValue).toBe(listOptions[0].value);
expect(firstRenderingOptions.shouldAutoHideContainer).toBe(false);
expect(firstRenderingOptions.containerNode).toBe(container);

widget.render({
results: new SearchResults(helper.state, [{nbHits: 0}]),
Expand All @@ -71,9 +67,7 @@ describe('connectNumericSelector', () => {
expect(rendering.lastCall.args[1]).toBe(false);

const secondRenderingOptions = rendering.lastCall.args[0];
expect(secondRenderingOptions.shouldAutoHideContainer).toBe(false);
expect(secondRenderingOptions.currentValue).toBe(listOptions[0].value);
expect(secondRenderingOptions.containerNode).toBe(container);
});

it('Reads the default value from the URL if possible', () => {
Expand Down
65 changes: 9 additions & 56 deletions src/connectors/numeric-selector/connectNumericSelector.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,8 @@
import {
bemHelper,
getContainerNode,
} from '../../lib/utils.js';
import cx from 'classnames';

const bem = bemHelper('ais-numeric-selector');

/**
* Instantiate a dropdown element to choose the number of hits to display per page
* @function numericSelector
* @param {string|DOMElement} options.container CSS Selector or DOMElement to insert the widget
* @param {string} options.attributeName Name of the numeric attribute to use
* @param {Array} options.options Array of objects defining the different values and labels
* @param {number} options.options[i].value The numerical value to refine with
* @param {string} options.options[i].label Label to display in the option
* @param {string} [options.operator='='] The operator to use to refine
* @param {boolean} [options.autoHideContainer=false] Hide the container when no results match
* @param {Object} [options.cssClasses] CSS classes to be added
* @param {string|string[]} [options.cssClasses.root] CSS classes added to the parent `<select>`
* @param {string|string[]} [options.cssClasses.item] CSS classes added to each `<option>`
* @return {Object}
*/
const usage = `Usage: numericSelector({
container,
attributeName,
options,
cssClasses.{root,item},
autoHideContainer
})`;

const connectNumericSelector = numericSelectorRendering => ({
container,
operator = '=',
attributeName,
options,
cssClasses: userCssClasses = {},
autoHideContainer = false,
}) => {
const containerNode = getContainerNode(container);
if (!container || !options || options.length === 0 || !attributeName) {
throw new Error(usage);
}

const cssClasses = {
root: cx(bem(null), userCssClasses.root),
item: cx(bem('item'), userCssClasses.item),
};

return {
}) => ({
getConfiguration(currentSearchParameters, searchParametersFromUrl) {
return {
numericRefinements: {
Expand All @@ -57,7 +12,7 @@ const connectNumericSelector = numericSelectorRendering => ({
},
};
},
init({helper}) {
init({helper, instantSearchInstance}) {
this._refine = value => {
helper.clearRefinements(attributeName);
if (value !== undefined) {
Expand All @@ -67,23 +22,22 @@ const connectNumericSelector = numericSelectorRendering => ({
};

numericSelectorRendering({
cssClasses,
currentValue: this._getRefinedValue(helper.state),
options,
setValue: this._refine,
shouldAutoHideContainer: autoHideContainer,
containerNode,
noResults: true,
instantSearchInstance,
}, true);
},

render({helper, results}) {
render({helper, results, instantSearchInstance}) {
const noResults = results.nbHits === 0;
numericSelectorRendering({
cssClasses,
currentValue: this._getRefinedValue(helper.state),
options,
setValue: this._refine,
shouldAutoHideContainer: autoHideContainer && results.nbHits === 0,
containerNode,
noResults,
instantSearchInstance,
}, false);
},

Expand All @@ -101,7 +55,6 @@ const connectNumericSelector = numericSelectorRendering => ({
state.numericRefinements[attributeName][operator][0] :
options[0].value;
},
};
};
});

export default connectNumericSelector;
86 changes: 65 additions & 21 deletions src/widgets/numeric-selector/numeric-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,46 @@ import ReactDOM from 'react-dom';
import Selector from '../../components/Selector.js';
import connectNumericSelector from '../../connectors/numeric-selector/connectNumericSelector.js';

import {
bemHelper,
getContainerNode,
} from '../../lib/utils.js';
import cx from 'classnames';

const bem = bemHelper('ais-numeric-selector');

const renderer = ({
containerNode,
autoHideContainer,
cssClasses,
}) => ({
currentValue,
setValue,
noResults,
options,
}, isFirstRendering) => {
if (isFirstRendering) return;

ReactDOM.render(
<Selector
cssClasses={cssClasses}
currentValue={currentValue}
options={options}
setValue={setValue}
shouldAutoHideContainer={autoHideContainer && noResults}
/>,
containerNode
);
};

const usage = `Usage: numericSelector({
container,
attributeName,
options,
cssClasses.{root,item},
autoHideContainer
})`;

/**
* Instantiate a dropdown element to choose the number of hits to display per page
* @function numericSelector
Expand All @@ -16,28 +56,32 @@ import connectNumericSelector from '../../connectors/numeric-selector/connectNum
* @param {Object} [options.cssClasses] CSS classes to be added
* @param {string|string[]} [options.cssClasses.root] CSS classes added to the parent `<select>`
* @param {string|string[]} [options.cssClasses.item] CSS classes added to each `<option>`
* @return {Object}
* @return {Object} a numeric selector widget instance
*/
export default connectNumericSelector(defaultRendering);

function defaultRendering({
cssClasses,
currentValue,
export default function numericSelector({
container,
operator = '=',
attributeName,
options,
setValue,
shouldAutoHideContainer,
containerNode,
}, isFirstRendering) {
if (isFirstRendering) return;
cssClasses: userCssClasses = {},
autoHideContainer = false,
}) {
const containerNode = getContainerNode(container);
if (!container || !options || options.length === 0 || !attributeName) {
throw new Error(usage);
}

ReactDOM.render(
<Selector
cssClasses={cssClasses}
currentValue={currentValue}
options={options}
setValue={setValue}
shouldAutoHideContainer={shouldAutoHideContainer}
/>,
containerNode
);
const cssClasses = {
root: cx(bem(null), userCssClasses.root),
item: cx(bem('item'), userCssClasses.item),
};

const specializedRenderer = renderer({autoHideContainer, containerNode, cssClasses});
const makeNumericSelector = connectNumericSelector(specializedRenderer);

return makeNumericSelector({
operator,
attributeName,
options,
});
}

0 comments on commit 1eda8a2

Please sign in to comment.