diff --git a/dev/app/builtin/init-stories.js b/dev/app/builtin/init-stories.js
index 0f69d4370a..c9f1c8e951 100644
--- a/dev/app/builtin/init-stories.js
+++ b/dev/app/builtin/init-stories.js
@@ -11,7 +11,6 @@ import initInstantSearchStories from './stories/instantsearch.stories';
import initMenuStories from './stories/menu.stories';
import initMenuSelectStories from './stories/menu-select.stories';
import initNumericRefinementListStories from './stories/numeric-refinement-list.stories';
-import initNumericSelectorStories from './stories/numeric-selector.stories';
import initPaginationStories from './stories/pagination.stories';
import initRangeInputStories from './stories/range-input.stories.js';
import initRangeSliderStories from './stories/range-slider.stories';
@@ -38,7 +37,6 @@ export default () => {
initMenuStories();
initMenuSelectStories();
initNumericRefinementListStories();
- initNumericSelectorStories();
initPaginationStories();
initRangeInputStories();
initRangeSliderStories();
diff --git a/dev/app/builtin/stories/numeric-selector.stories.js b/dev/app/builtin/stories/numeric-selector.stories.js
deleted file mode 100644
index ad9ad21f36..0000000000
--- a/dev/app/builtin/stories/numeric-selector.stories.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* eslint-disable import/default */
-
-import { storiesOf } from 'dev-novel';
-import instantsearch from '../../../../index';
-import { wrapWithHits } from '../../utils/wrap-with-hits.js';
-
-const stories = storiesOf('NumericSelector');
-
-export default () => {
- stories.add(
- 'default',
- wrapWithHits(container => {
- window.search.addWidget(
- instantsearch.widgets.numericSelector({
- container,
- operator: '>=',
- attributeName: 'popularity',
- options: [
- { label: 'Default', value: 0 },
- { label: 'Top 10', value: 21459 },
- { label: 'Top 100', value: 21369 },
- { label: 'Top 500', value: 20969 },
- ],
- })
- );
- })
- );
- stories.add(
- 'with default value',
- wrapWithHits(container => {
- window.search.addWidget(
- instantsearch.widgets.numericSelector({
- container,
- operator: '=',
- attributeName: 'rating',
- options: [
- { label: 'No rating selected', value: undefined },
- { label: 'Rating: 5', value: 5 },
- { label: 'Rating: 4', value: 4 },
- { label: 'Rating: 3', value: 3 },
- { label: 'Rating: 2', value: 2 },
- { label: 'Rating: 1', value: 1 },
- ],
- })
- );
- })
- );
- stories.add(
- 'with transformed items',
- wrapWithHits(container => {
- window.search.addWidget(
- instantsearch.widgets.numericSelector({
- container,
- operator: '=',
- attributeName: 'rating',
- options: [
- { label: 'No rating selected', value: undefined },
- { label: 'Rating: 5', value: 5 },
- { label: 'Rating: 4', value: 4 },
- { label: 'Rating: 3', value: 3 },
- { label: 'Rating: 2', value: 2 },
- { label: 'Rating: 1', value: 1 },
- ],
- transformItems: items =>
- items.map(item => ({
- ...item,
- label: `${item.label} (transformed)`,
- })),
- })
- );
- })
- );
-};
diff --git a/dev/app/init-unmount-widgets.js b/dev/app/init-unmount-widgets.js
index b13677fff0..e008ce5820 100644
--- a/dev/app/init-unmount-widgets.js
+++ b/dev/app/init-unmount-widgets.js
@@ -206,23 +206,6 @@ export default () => {
)
);
- storiesOf('NumericSelector').add(
- 'default',
- wrapWithUnmount(container =>
- instantsearch.widgets.numericSelector({
- container,
- operator: '>=',
- attributeName: 'popularity',
- options: [
- { label: 'Default', value: 0 },
- { label: 'Top 10', value: 9991 },
- { label: 'Top 100', value: 9901 },
- { label: 'Top 500', value: 9501 },
- ],
- })
- )
- );
-
storiesOf('Pagination').add(
'default',
wrapWithUnmount(container =>
diff --git a/dev/app/jquery/init-stories.js b/dev/app/jquery/init-stories.js
index dcd55943eb..72e7a5a3d8 100644
--- a/dev/app/jquery/init-stories.js
+++ b/dev/app/jquery/init-stories.js
@@ -6,7 +6,6 @@ import initHitsPerPageStories from './stories/hits-per-page.stories';
import initInfiniteHitsStories from './stories/infinite-hits.stories';
import initMenuStories from './stories/menu.stories';
import initNumericRefinementListStories from './stories/numeric-refinement-list.stories';
-import initNumericSelectorStories from './stories/numeric-selector.stories';
import initPaginationStories from './stories/pagination.stories';
import initRefinementListStories from './stories/refinement-list.stories';
import initSearchBoxStories from './stories/search-box.stories';
@@ -25,7 +24,6 @@ export default () => {
initInfiniteHitsStories();
initMenuStories();
initNumericRefinementListStories();
- initNumericSelectorStories();
initPaginationStories();
initRefinementListStories();
initSearchBoxStories();
diff --git a/dev/app/jquery/stories/numeric-selector.stories.js b/dev/app/jquery/stories/numeric-selector.stories.js
deleted file mode 100644
index 89145836f9..0000000000
--- a/dev/app/jquery/stories/numeric-selector.stories.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { storiesOf } from 'dev-novel';
-import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js';
-import * as widgets from '../widgets/index.js';
-
-const stories = storiesOf('NumericSelector');
-
-export default () => {
- stories.add(
- 'default',
- wrapWithHitsAndJquery(containerNode => {
- window.search.addWidget(
- widgets.numericSelector({
- containerNode,
- operator: '>=',
- attributeName: 'popularity',
- options: [
- { label: 'Default', value: 0 },
- { label: 'Top 10', value: 9991 },
- { label: 'Top 100', value: 9901 },
- { label: 'Top 500', value: 9501 },
- ],
- })
- );
- })
- );
-};
diff --git a/dev/app/jquery/widgets/index.js b/dev/app/jquery/widgets/index.js
index c6161aaa73..2b3b07ea6e 100644
--- a/dev/app/jquery/widgets/index.js
+++ b/dev/app/jquery/widgets/index.js
@@ -6,7 +6,6 @@ export { default as pagination } from './pagination';
export { default as hitsPerPage } from './hitsPerPage';
export { default as hits } from './hits';
export { default as refinementList } from './refinementList';
-export { default as numericSelector } from './numericSelector';
export { default as numericRefinementList } from './numericRefinementList';
export { default as searchBox } from './searchBox';
export { default as sortBy } from './sortBy';
diff --git a/dev/app/jquery/widgets/numericSelector.js b/dev/app/jquery/widgets/numericSelector.js
deleted file mode 100644
index 6b0775e7bb..0000000000
--- a/dev/app/jquery/widgets/numericSelector.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* eslint-disable import/default */
-import instantsearch from '../../../../index.js';
-
-const renderFn = (
- { currentRefinement, options, refine, widgetParams: { containerNode } },
- isFirstRendering
-) => {
- if (isFirstRendering) {
- const markup = '';
- containerNode.append(markup);
- }
-
- const optionsHTML = options.map(
- ({ value, label }) => `
-
- `
- );
-
- containerNode.find('select').html(optionsHTML);
-
- containerNode
- .find('select')
- .off('change')
- .on('change', e => {
- refine(e.target.value);
- });
-};
-
-export default instantsearch.connectors.connectNumericSelector(renderFn);
diff --git a/docgen/src/examples/tourism/search.js b/docgen/src/examples/tourism/search.js
index ff8cf9d7bf..1ccedcc389 100644
--- a/docgen/src/examples/tourism/search.js
+++ b/docgen/src/examples/tourism/search.js
@@ -88,21 +88,5 @@ window.addEventListener('load', function() {
})
);
- search.addWidget(
- instantsearch.widgets.numericSelector({
- container: '#guests',
- attributeName: 'person_capacity',
- operator: '>=',
- options: [
- { label: '1 guest', value: 1},
- { label: '2 guests', value: 2},
- { label: '3 guests', value: 3},
- { label: '4 guests', value: 4},
- { label: '5 guests', value: 5},
- { label: '6 guests', value: 6}
- ]
- })
- );
-
search.start();
});
diff --git a/docgen/src/guides/routing.md b/docgen/src/guides/routing.md
index d05d652e22..e8d0e52571 100644
--- a/docgen/src/guides/routing.md
+++ b/docgen/src/guides/routing.md
@@ -234,9 +234,6 @@ But the `uiState` object is created by InstantSearch.js internally and thus part
numericRefinementList: {
heightInCm: 40
},
- numericSelector: {
- widthInCm: 30
- },
range: {
ageInYears: '2-10'
},
diff --git a/docgen/src/guides/v3-migration.md b/docgen/src/guides/v3-migration.md
index 79d890e8b5..63d676e325 100644
--- a/docgen/src/guides/v3-migration.md
+++ b/docgen/src/guides/v3-migration.md
@@ -308,6 +308,10 @@ With the redo button:
```
+### NumericSelector
+
+Widget removed.
+
### Pagination
#### Options
diff --git a/functional-tests/app/app.js b/functional-tests/app/app.js
index eb12072744..d623dd35de 100644
--- a/functional-tests/app/app.js
+++ b/functional-tests/app/app.js
@@ -268,21 +268,4 @@ search.once('render', function() {
document.querySelector('.search').className = 'row search search--visible';
});
-search.addWidget(
- instantsearch.widgets.numericSelector({
- container: '#popularity-selector',
- operator: '>=',
- attributeName: 'popularity',
- options: [
- { label: 'Default', value: 0 },
- { label: 'Top 10', value: 9991 },
- { label: 'Top 100', value: 9901 },
- { label: 'Top 500', value: 9501 },
- ],
- cssClasses: {
- select: 'form-control',
- },
- })
-);
-
search.start();
diff --git a/src/connectors/index.js b/src/connectors/index.js
index 6557ba4692..655e69ae65 100644
--- a/src/connectors/index.js
+++ b/src/connectors/index.js
@@ -18,9 +18,6 @@ export { default as connectMenu } from './menu/connectMenu.js';
export {
default as connectNumericRefinementList,
} from './numeric-refinement-list/connectNumericRefinementList.js';
-export {
- default as connectNumericSelector,
-} from './numeric-selector/connectNumericSelector.js';
export {
default as connectPagination,
} from './pagination/connectPagination.js';
diff --git a/src/connectors/numeric-selector/__tests__/__snapshots__/connectNumericSelector-test.js.snap b/src/connectors/numeric-selector/__tests__/__snapshots__/connectNumericSelector-test.js.snap
deleted file mode 100644
index 1e269defb9..0000000000
--- a/src/connectors/numeric-selector/__tests__/__snapshots__/connectNumericSelector-test.js.snap
+++ /dev/null
@@ -1,144 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`connectNumericSelector routing getWidgetSearchParameters should add the refinements according to the UI state provided 1`] = `
-SearchParameters {
- "advancedSyntax": undefined,
- "allowTyposOnNumericTokens": undefined,
- "analytics": undefined,
- "analyticsTags": undefined,
- "aroundLatLng": undefined,
- "aroundLatLngViaIP": undefined,
- "aroundPrecision": undefined,
- "aroundRadius": undefined,
- "attributesToHighlight": undefined,
- "attributesToRetrieve": undefined,
- "attributesToSnippet": undefined,
- "disableExactOnAttributes": undefined,
- "disjunctiveFacets": Array [],
- "disjunctiveFacetsRefinements": Object {},
- "distinct": undefined,
- "enableExactOnSingleWordQuery": undefined,
- "facets": Array [],
- "facetsExcludes": Object {},
- "facetsRefinements": Object {},
- "getRankingInfo": undefined,
- "hierarchicalFacets": Array [],
- "hierarchicalFacetsRefinements": Object {},
- "highlightPostTag": undefined,
- "highlightPreTag": undefined,
- "hitsPerPage": undefined,
- "ignorePlurals": undefined,
- "index": "",
- "insideBoundingBox": undefined,
- "insidePolygon": undefined,
- "length": undefined,
- "maxValuesPerFacet": undefined,
- "minProximity": undefined,
- "minWordSizefor1Typo": undefined,
- "minWordSizefor2Typos": undefined,
- "minimumAroundRadius": undefined,
- "numericFilters": undefined,
- "numericRefinements": Object {
- "numerics": Object {
- "=": Array [
- 20,
- ],
- },
- },
- "offset": undefined,
- "optionalFacetFilters": undefined,
- "optionalTagFilters": undefined,
- "optionalWords": undefined,
- "page": 0,
- "query": "",
- "queryType": undefined,
- "removeWordsIfNoResults": undefined,
- "replaceSynonymsInHighlight": undefined,
- "restrictSearchableAttributes": undefined,
- "snippetEllipsisText": undefined,
- "synonyms": undefined,
- "tagFilters": undefined,
- "tagRefinements": Array [],
- "typoTolerance": undefined,
-}
-`;
-
-exports[`connectNumericSelector routing getWidgetSearchParameters should enforce the default value if there are no refinements in the UI state 1`] = `
-SearchParameters {
- "advancedSyntax": undefined,
- "allowTyposOnNumericTokens": undefined,
- "analytics": undefined,
- "analyticsTags": undefined,
- "aroundLatLng": undefined,
- "aroundLatLngViaIP": undefined,
- "aroundPrecision": undefined,
- "aroundRadius": undefined,
- "attributesToHighlight": undefined,
- "attributesToRetrieve": undefined,
- "attributesToSnippet": undefined,
- "disableExactOnAttributes": undefined,
- "disjunctiveFacets": Array [],
- "disjunctiveFacetsRefinements": Object {},
- "distinct": undefined,
- "enableExactOnSingleWordQuery": undefined,
- "facets": Array [],
- "facetsExcludes": Object {},
- "facetsRefinements": Object {},
- "getRankingInfo": undefined,
- "hierarchicalFacets": Array [],
- "hierarchicalFacetsRefinements": Object {},
- "highlightPostTag": undefined,
- "highlightPreTag": undefined,
- "hitsPerPage": undefined,
- "ignorePlurals": undefined,
- "index": "",
- "insideBoundingBox": undefined,
- "insidePolygon": undefined,
- "length": undefined,
- "maxValuesPerFacet": undefined,
- "minProximity": undefined,
- "minWordSizefor1Typo": undefined,
- "minWordSizefor2Typos": undefined,
- "minimumAroundRadius": undefined,
- "numericFilters": undefined,
- "numericRefinements": Object {
- "numerics": Object {
- "=": Array [
- 10,
- ],
- },
- },
- "offset": undefined,
- "optionalFacetFilters": undefined,
- "optionalTagFilters": undefined,
- "optionalWords": undefined,
- "page": 0,
- "query": "",
- "queryType": undefined,
- "removeWordsIfNoResults": undefined,
- "replaceSynonymsInHighlight": undefined,
- "restrictSearchableAttributes": undefined,
- "snippetEllipsisText": undefined,
- "synonyms": undefined,
- "tagFilters": undefined,
- "tagRefinements": Array [],
- "typoTolerance": undefined,
-}
-`;
-
-exports[`connectNumericSelector routing getWidgetState should add an entry equal to the refinement 1`] = `
-Object {
- "numericSelector": Object {
- "numerics": 20,
- },
-}
-`;
-
-exports[`connectNumericSelector routing getWidgetState should not override other values in the same namespace 1`] = `
-Object {
- "numericSelector": Object {
- "numerics": 20,
- "numerics-2": "36",
- },
-}
-`;
diff --git a/src/connectors/numeric-selector/__tests__/connectNumericSelector-test.js b/src/connectors/numeric-selector/__tests__/connectNumericSelector-test.js
deleted file mode 100644
index beb3e9dbde..0000000000
--- a/src/connectors/numeric-selector/__tests__/connectNumericSelector-test.js
+++ /dev/null
@@ -1,481 +0,0 @@
-import jsHelper, {
- SearchResults,
- SearchParameters,
-} from 'algoliasearch-helper';
-
-import connectNumericSelector from '../connectNumericSelector.js';
-
-describe('connectNumericSelector', () => {
- it('Renders during init and render', () => {
- // test that the dummyRendering is called with the isFirstRendering
- // flag set accordingly
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- const config = widget.getConfiguration({}, {});
- expect(config).toEqual({
- numericRefinements: {
- numerics: {
- '=': [listOptions[0].value],
- },
- },
- });
-
- // test if widget is not rendered yet at this point
- expect(rendering).not.toHaveBeenCalled();
-
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- // test that rendering has been called during init with isFirstRendering = true
- expect(rendering).toHaveBeenCalledTimes(1);
- // test if isFirstRendering is true during init
- expect(rendering).toHaveBeenLastCalledWith(expect.any(Object), true);
-
- const firstRenderingOptions = rendering.mock.calls[0][0];
- expect(firstRenderingOptions.currentRefinement).toBe(listOptions[0].value);
- expect(firstRenderingOptions.widgetParams).toEqual({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- widget.render({
- results: new SearchResults(helper.state, [{ nbHits: 0 }]),
- state: helper.state,
- helper,
- createURL: () => '#',
- });
-
- // test that rendering has been called during init with isFirstRendering = false
- expect(rendering).toHaveBeenCalledTimes(2);
- expect(rendering).toHaveBeenLastCalledWith(expect.any(Object), false);
-
- const secondRenderingOptions = rendering.mock.calls[1][0];
- expect(secondRenderingOptions.currentRefinement).toBe(listOptions[0].value);
- expect(secondRenderingOptions.widgetParams).toEqual({
- attributeName: 'numerics',
- options: listOptions,
- });
- });
-
- it('Renders during init and render with transformed items', () => {
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- transformItems: items =>
- items.map(item => ({ ...item, label: 'transformed' })),
- });
-
- const config = widget.getConfiguration({}, {});
-
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- const firstRenderingOptions = rendering.mock.calls[0][0];
- expect(firstRenderingOptions.options).toEqual([
- { name: '10', value: 10, label: 'transformed' },
- { name: '20', value: 20, label: 'transformed' },
- { name: '30', value: 30, label: 'transformed' },
- ]);
-
- widget.render({
- results: new SearchResults(helper.state, [{ nbHits: 0 }]),
- state: helper.state,
- helper,
- createURL: () => '#',
- });
-
- const secondRenderingOptions = rendering.mock.calls[1][0];
- expect(secondRenderingOptions.options).toEqual([
- { name: '10', value: 10, label: 'transformed' },
- { name: '20', value: 20, label: 'transformed' },
- { name: '30', value: 30, label: 'transformed' },
- ]);
- });
-
- it('Reads the default value from the URL if possible', () => {
- // test that the dummyRendering is called with the isFirstRendering
- // flag set accordingly
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- expect(widget.getConfiguration({}, {})).toEqual({
- numericRefinements: {
- numerics: {
- '=': [listOptions[0].value],
- },
- },
- });
-
- expect(
- widget.getConfiguration(
- {},
- {
- numericRefinements: {
- numerics: {
- '=': [30],
- },
- },
- }
- )
- ).toEqual({
- numericRefinements: {
- numerics: {
- '=': [30],
- },
- },
- });
- });
-
- it('Provide a function to update the refinements at each step', () => {
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- const config = widget.getConfiguration({}, {});
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- const firstRenderingOptions = rendering.mock.calls[0][0];
- const { refine } = firstRenderingOptions;
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
- refine(listOptions[1].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [20],
- });
- refine(listOptions[2].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [30],
- });
- refine(listOptions[0].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
-
- widget.render({
- results: new SearchResults(helper.state, [{}]),
- state: helper.state,
- helper,
- createURL: () => '#',
- });
-
- const secondRenderingOptions = rendering.mock.calls[1][0];
- const { refine: renderSetValue } = secondRenderingOptions;
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
- renderSetValue(listOptions[1].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [20],
- });
- renderSetValue(listOptions[2].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [30],
- });
- renderSetValue(listOptions[0].name);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
- });
-
- it('provides isRefined for the currently selected value', () => {
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- const config = widget.getConfiguration({}, {});
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- let refine = rendering.mock.calls[0][0].refine;
-
- listOptions.forEach((_, i) => {
- // we loop with 1 increment because the first value is selected by default
- const currentOption = listOptions[(i + 1) % listOptions.length];
- refine(currentOption.name);
-
- widget.render({
- results: new SearchResults(helper.state, [{}]),
- state: helper.state,
- helper,
- createURL: () => '#',
- });
-
- // The current option should be the one selected
- // First we copy and set the default added values
- const expectedResult = currentOption.value;
-
- const renderingParameters = rendering.mock.calls[1 + i][0];
- expect(renderingParameters.currentRefinement).toEqual(expectedResult);
-
- refine = renderingParameters.refine;
- });
- });
-
- it('The refine function can unselect with `undefined` and "undefined"', () => {
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '' },
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- const config = widget.getConfiguration({}, {});
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- const firstRenderingOptions = rendering.mock.calls[0][0];
- const { refine } = firstRenderingOptions;
- expect(helper.state.getNumericRefinements('numerics')).toEqual({});
- refine(listOptions[1].value);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
- refine(listOptions[0].value);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({});
-
- widget.render({
- results: new SearchResults(helper.state, [{}]),
- state: helper.state,
- helper,
- createURL: () => '#',
- });
-
- const secondRenderingOptions = rendering.mock.calls[1][0];
- const { refine: refineBis } = secondRenderingOptions;
- expect(helper.state.getNumericRefinements('numerics')).toEqual({});
- refineBis(listOptions[1].value);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({
- '=': [10],
- });
- refineBis(listOptions[0].value);
- expect(helper.state.getNumericRefinements('numerics')).toEqual({});
- });
-
- describe('routing', () => {
- const getInitializedWidget = () => {
- const rendering = jest.fn();
- const makeWidget = connectNumericSelector(rendering);
- const listOptions = [
- { name: '10', value: 10 },
- { name: '20', value: 20 },
- { name: '30', value: 30 },
- ];
- const widget = makeWidget({
- attributeName: 'numerics',
- options: listOptions,
- });
-
- const config = widget.getConfiguration({}, {});
- const helper = jsHelper({}, '', config);
- helper.search = jest.fn();
-
- widget.init({
- helper,
- state: helper.state,
- createURL: () => '#',
- onHistoryChange: () => {},
- });
-
- const { refine } = rendering.mock.calls[0][0];
-
- return [widget, helper, refine];
- };
-
- describe('getWidgetState', () => {
- test('should give back the object unmodified if the default value is selected', () => {
- const [widget, helper] = getInitializedWidget();
- const uiStateBefore = {};
- const uiStateAfter = widget.getWidgetState(uiStateBefore, {
- searchParameters: helper.state,
- helper,
- });
-
- expect(uiStateAfter).toBe(uiStateBefore);
- });
-
- test('should add an entry equal to the refinement', () => {
- const [widget, helper, refine] = getInitializedWidget();
- refine(20);
- const uiStateBefore = {};
- const uiStateAfter = widget.getWidgetState(uiStateBefore, {
- searchParameters: helper.state,
- helper,
- });
-
- expect(uiStateAfter).toMatchSnapshot();
- });
-
- test('should not override other values in the same namespace', () => {
- const [widget, helper, refine] = getInitializedWidget();
- const uiStateBefore = {
- numericSelector: {
- 'numerics-2': '36',
- },
- };
-
- refine(20);
-
- const uiStateAfter = widget.getWidgetState(uiStateBefore, {
- searchParameters: helper.state,
- helper,
- });
-
- expect(uiStateAfter).toMatchSnapshot();
- });
-
- test('should give back the object unmodified if refinements are already set', () => {
- const [widget, helper] = getInitializedWidget();
- const uiStateBefore = {
- numericSelector: {
- numerics: 20,
- },
- };
- helper.addNumericRefinement('numerics', '=', 20);
- const uiStateAfter = widget.getWidgetState(uiStateBefore, {
- searchParameters: helper.state,
- helper,
- });
-
- expect(uiStateAfter).toBe(uiStateBefore);
- });
- });
-
- describe('getWidgetSearchParameters', () => {
- test('should enforce the default value if there are no refinements in the UI state', () => {
- const [widget, helper] = getInitializedWidget();
- // User presses back (browser) and the URL contains nothing
- const uiState = {};
- // The current search is empty
- const searchParametersBefore = SearchParameters.make(helper.state);
- const searchParametersAfter = widget.getWidgetSearchParameters(
- searchParametersBefore,
- { uiState }
- );
- // The default parameters should be applied
- expect(searchParametersAfter).toMatchSnapshot();
- });
-
- test('should return the same SP if the value is the same in both UI State and SP', () => {
- const [widget, helper, refine] = getInitializedWidget();
- // User presses back (browser) and the URL contains some refinements
- const uiState = {
- numericSelector: {
- numerics: 30,
- },
- };
- // The current state has the same parameters
- refine(30);
- const searchParametersBefore = SearchParameters.make(helper.state);
- const searchParametersAfter = widget.getWidgetSearchParameters(
- searchParametersBefore,
- { uiState }
- );
- // Applying the same parameters should not return a new object
- expect(searchParametersAfter).toBe(searchParametersBefore);
- });
-
- test('should add the refinements according to the UI state provided', () => {
- const [widget, helper] = getInitializedWidget();
- // User presses back (browser) and the URL contains some refinements
- const uiState = {
- numericSelector: {
- numerics: 20,
- },
- };
- // The current state is empty
- const searchParametersBefore = SearchParameters.make(helper.state);
- const searchParametersAfter = widget.getWidgetSearchParameters(
- searchParametersBefore,
- { uiState }
- );
- // The new parameters should be applies
- expect(searchParametersAfter).toMatchSnapshot();
- });
- });
- });
-});
diff --git a/src/connectors/numeric-selector/connectNumericSelector.js b/src/connectors/numeric-selector/connectNumericSelector.js
deleted file mode 100644
index 7e3f169402..0000000000
--- a/src/connectors/numeric-selector/connectNumericSelector.js
+++ /dev/null
@@ -1,231 +0,0 @@
-import { checkRendering } from '../../lib/utils.js';
-
-const usage = `Usage:
-var customNumericSelector = connectNumericSelector(function renderFn(params, isFirstRendering) {
- // params = {
- // currentRefinement,
- // options,
- // refine,
- // hasNoResults,
- // instantSearchInstance,
- // widgetParams,
- // }
-});
-search.addWidget(
- customNumericSelector({
- attributeName,
- options,
- [ operator = '=' ],
- [ transformItems ]
- })
-);
-Full documentation available at https://community.algolia.com/instantsearch.js/v2/connectors/connectNumericSelector.html
-`;
-
-/**
- * @typedef {Object} NumericSelectorOption
- * @property {number} value The numerical value to refine with.
- * If the value is `undefined` or `"undefined"`, the option resets the filter.
- * @property {string} label Label to display in the option.
- */
-
-/**
- * @typedef {Object} CustomNumericSelectorWidgetOptions
- * @property {string} attributeName Name of the attribute for faceting (eg. "free_shipping").
- * @property {NumericSelectorOption[]} options Array of objects defining the different values and labels.
- * @property {string} [operator = '='] The operator to use to refine. Supports following operators: <, <=, =, >, >= and !=.
- * @property {function(object[]):object[]} [transformItems] Function to transform the items passed to the templates.
- */
-
-/**
- * @typedef {Object} NumericSelectorRenderingOptions
- * @property {string} currentRefinement The currently selected value.
- * @property {NumericSelectorOption[]} options The different values and labels of the selector.
- * @property {function(option.value)} refine Updates the results with the selected value.
- * @property {boolean} hasNoResults `true` if the last search contains no result.
- * @property {Object} widgetParams All original `CustomNumericSelectorWidgetOptions` forwarded to the `renderFn`.
- */
-
-/**
- * **NumericSelector** connector provides the logic to build a custom widget that will let the
- * user filter the results based on a list of numerical filters.
- *
- * It provides a `refine(value)` function to trigger a new search with selected option.
- * @type {Connector}
- * @param {function(NumericSelectorRenderingOptions, boolean)} renderFn Rendering function for the custom **NumericSelector** widget.
- * @param {function} unmountFn Unmount function called when the widget is disposed.
- * @return {function(CustomNumericSelectorWidgetOptions)} Re-usable widget factory for a custom **NumericSelector** widget.
- * @example
- * // custom `renderFn` to render the custom NumericSelector widget
- * function renderFn(NumericSelectorRenderingOptions, isFirstRendering) {
- * if (isFirstRendering) {
- * NumericSelectorRenderingOptions.widgetParams.containerNode.html('');
- * NumericSelectorRenderingOptions.widgetParams.containerNode
- * .find('select')
- * .on('change', function(event) {
- * NumericSelectorRenderingOptions.refine(event.target.value);
- * })
- * }
- *
- * var optionsHTML = NumericSelectorRenderingOptions.options.map(function(option) {
- * return '';
- * });
- *
- * NumericSelectorRenderingOptions.widgetParams.containerNode
- * .find('select')
- * .html(optionsHTML);
- * }
- *
- * // connect `renderFn` to NumericSelector logic
- * var customNumericSelector = instantsearch.connectors.connectNumericSelector(renderFn);
- *
- * // mount widget on the page
- * search.addWidget(
- * customNumericSelector({
- * containerNode: $('#custom-numeric-selector-container'),
- * operator: '>=',
- * attributeName: 'popularity',
- * options: [
- * {label: 'Default', value: 0},
- * {label: 'Top 10', value: 9991},
- * {label: 'Top 100', value: 9901},
- * {label: 'Top 500', value: 9501},
- * ],
- * })
- * );
- */
-export default function connectNumericSelector(renderFn, unmountFn) {
- checkRendering(renderFn, usage);
-
- return (widgetParams = {}) => {
- const {
- attributeName,
- options,
- operator = '=',
- transformItems = items => items,
- } = widgetParams;
-
- if (!attributeName || !options) {
- throw new Error(usage);
- }
-
- return {
- getConfiguration(currentSearchParameters, searchParametersFromUrl) {
- const value = this._getRefinedValue(searchParametersFromUrl);
- if (value) {
- return {
- numericRefinements: {
- [attributeName]: {
- [operator]: [value],
- },
- },
- };
- }
- return {};
- },
-
- init({ helper, instantSearchInstance }) {
- this._refine = value => {
- helper.clearRefinements(attributeName);
- if (value !== undefined && value !== 'undefined') {
- helper.addNumericRefinement(attributeName, operator, value);
- }
- helper.search();
- };
-
- renderFn(
- {
- currentRefinement: this._getRefinedValue(helper.state),
- options: transformItems(options),
- refine: this._refine,
- hasNoResults: true,
- instantSearchInstance,
- widgetParams,
- },
- true
- );
- },
-
- render({ helper, results, instantSearchInstance }) {
- renderFn(
- {
- currentRefinement: this._getRefinedValue(helper.state),
- options: transformItems(options),
- refine: this._refine,
- hasNoResults: results.nbHits === 0,
- instantSearchInstance,
- widgetParams,
- },
- false
- );
- },
-
- dispose({ state }) {
- unmountFn();
- return state.removeNumericRefinement(attributeName);
- },
-
- getWidgetState(uiState, { searchParameters }) {
- const currentRefinement = this._getRefinedValue(searchParameters);
- if (
- // Does the current state contain the current refinement?
- (uiState.numericSelector &&
- currentRefinement === uiState.numericSelector[attributeName]) ||
- // Is the current value the first option / default value?
- currentRefinement === options[0].value
- ) {
- return uiState;
- }
-
- if (currentRefinement || currentRefinement === 0)
- return {
- ...uiState,
- numericSelector: {
- ...uiState.numericSelector,
- [attributeName]: currentRefinement,
- },
- };
- return uiState;
- },
-
- getWidgetSearchParameters(searchParameters, { uiState }) {
- const value =
- uiState.numericSelector && uiState.numericSelector[attributeName];
- const currentlyRefinedValue = this._getRefinedValue(searchParameters);
-
- if (value) {
- if (value === currentlyRefinedValue) return searchParameters;
- return searchParameters
- .clearRefinements(attributeName)
- .addNumericRefinement(attributeName, operator, value);
- }
-
- const firstItemValue = options[0] && options[0].value;
- if (typeof firstItemValue === 'number') {
- return searchParameters
- .clearRefinements(attributeName)
- .addNumericRefinement(attributeName, operator, options[0].value);
- }
-
- return searchParameters;
- },
-
- _getRefinedValue(state) {
- // This is reimplementing state.getNumericRefinement
- // But searchParametersFromUrl is not an actual SearchParameters object
- // It's only the object structure without the methods, because getStateFromQueryString
- // is not sending a SearchParameters. There's no way given how we built the helper
- // to initialize a true partial state where only the refinements are present
- return state &&
- state.numericRefinements &&
- state.numericRefinements[attributeName] !== undefined &&
- state.numericRefinements[attributeName][operator] !== undefined &&
- state.numericRefinements[attributeName][operator][0] !== undefined // could be 0
- ? state.numericRefinements[attributeName][operator][0]
- : options[0].value;
- },
- };
- };
-}
diff --git a/src/widgets/index.js b/src/widgets/index.js
index ed62aae9e1..f88a27bb13 100644
--- a/src/widgets/index.js
+++ b/src/widgets/index.js
@@ -30,9 +30,6 @@ export {
export {
default as numericRefinementList,
} from '../widgets/numeric-refinement-list/numeric-refinement-list.js';
-export {
- default as numericSelector,
-} from '../widgets/numeric-selector/numeric-selector.js';
export { default as pagination } from '../widgets/pagination/pagination.js';
export { default as rangeInput } from '../widgets/range-input/range-input.js';
export { default as searchBox } from '../widgets/search-box/search-box.js';
diff --git a/src/widgets/numeric-selector/__tests__/__snapshots__/numeric-selector-test.js.snap b/src/widgets/numeric-selector/__tests__/__snapshots__/numeric-selector-test.js.snap
deleted file mode 100644
index 8405c36754..0000000000
--- a/src/widgets/numeric-selector/__tests__/__snapshots__/numeric-selector-test.js.snap
+++ /dev/null
@@ -1,82 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`numericSelector() calls twice ReactDOM.render(