From f546347e42c9f4694153c8543fd996da92f14449 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" Date: Thu, 2 Nov 2017 13:47:30 +0100 Subject: [PATCH 1/8] chore(deps): update dependency eslint-config-prettier to v2.7.0 (#2547) --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 64b6f55e7e..43227dca1a 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "enzyme": "2.9.1", "eslint": "4.10.0", "eslint-config-algolia": "12.0.0", - "eslint-config-prettier": "2.6.0", + "eslint-config-prettier": "2.7.0", "eslint-import-resolver-webpack": "0.8.3", "eslint-plugin-import": "2.8.0", "eslint-plugin-jasmine": "2.9.1", diff --git a/yarn.lock b/yarn.lock index bf69a3677e..7dc42611e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3228,9 +3228,9 @@ eslint-config-algolia@12.0.0: version "12.0.0" resolved "https://registry.yarnpkg.com/eslint-config-algolia/-/eslint-config-algolia-12.0.0.tgz#5d0ead285f84054713f623bc9bfb2e189967a0c8" -eslint-config-prettier@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.6.0.tgz#f21db0ebb438ad678fb98946097c4bb198befccc" +eslint-config-prettier@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.7.0.tgz#7bbfef66ad783277836f4ea556e68b9bcc9da4d0" dependencies: get-stdin "^5.0.1" From 83211772bbad06d75bb70564465aba4549245522 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" Date: Fri, 3 Nov 2017 13:39:50 +0100 Subject: [PATCH 2/8] chore(deps): update dependency sinon to v4.1.1 (#2548) --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 43227dca1a..eb935cd4b1 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "sass-loader": "6.0.6", "semver": "5.4.1", "shelljs": "0.7.8", - "sinon": "4.0.2", + "sinon": "4.1.1", "style-loader": "0.19.0", "unminified-webpack-plugin": "1.4.1", "watch": "1.0.2", diff --git a/yarn.lock b/yarn.lock index 7dc42611e8..65b35149bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8508,9 +8508,9 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.0.2.tgz#c81f62456d37986c84e9f522ddb9ce413bda49d2" +sinon@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.1.1.tgz#bd657be815df608887fe1f0b75f9590ec563748a" dependencies: diff "^3.1.0" formatio "1.2.0" From 95421ef6c42b984ee7c27e6f94b236bbe5d5ff8f Mon Sep 17 00:00:00 2001 From: Samuel Vaillant Date: Fri, 3 Nov 2017 13:40:21 +0100 Subject: [PATCH 3/8] Chore split stories (#2544) * chore: refactor folder structure for dev app * chore: move instantsearch stories to external file * chore: move analytics stories to external file * chore: move ClearAll stories to external file * chore: move CurrentRefinedStories stories to external file * chore: move HierarchicalMenu stories to external file * chore: move Hits stories to external file * chore: move HitsPerPageSelector stories to external file * chore: move InfiniteHits stories to external file * chore: move Menu stories to external file * chore: move NumericRefinementList stories to external file * chore: move NumericSelector stories to external file * chore: move Pagination stories to external file * chore: move PriceRanges stories to external file * chore: move RangeSlider stories to external file * chore: move RefinementList stories to external file * chore: move SearchBox stories to external file * chore: move SortBySelector stories to external file * chore: move Stats stories to external file * chore: move StarRating stories to external file * chore: move Toggle stories to external file * fix(stories): reorder builtin import * refactor(stories): use named export for utils * feat(stories): add wrapWithHitsAndJquery * chore: move jQuery ClearAll stories to external file * chore: move jQuery CurrentRefinedValues stories to external file * chore: move jQuery HierarchicalMenu stories to external file * chore: move jQuery Hits stories to external file * chore: move jQuery HitsPerPageSelector stories to external file * chore: move jQuery InfiniteHits stories to external file * chore: move jQuery Menu stories to external file * chore: move jQuery NumericRefinementList stories to external file * chore: move jQuery NumericSelector stories to external file * chore: move jQuery Pagination stories to external file * chore: move jQuery PriceRanges stories to external file * chore: move jQuery RefinementList stories to external file * chore: move jQuery SearchBox stories to external file * chore: move jQuery SortBySelector stories to external file * chore: move jQuery StarRating stories to external file * chore: move jQuery Stats stories to external file * chore: move jQuery Toggle stories to external file * chore: move vanilla ClearAll stories to external file * chore: move vanilla Hits stories to external file * chore: move vanilla Menu stories to external file * chore: move vanilla RefinementList stories to external file * chore: move vanilla SearchBox stories to external file --- dev/app/builtin/init-stories.js | 43 + dev/app/builtin/stories/analytics.stories.js | 30 + dev/app/builtin/stories/clear-all.stories.js | 64 ++ .../stories/current-refined-values.stories.js | 84 ++ .../stories/hierarchical-menu.stories.js | 89 ++ .../stories/hits-per-page-selector.stories.js | 41 + dev/app/builtin/stories/hits.stories.js | 16 + .../builtin/stories/infinite-hits.stories.js | 48 + .../builtin/stories/instantsearch.stories.js | 21 + dev/app/builtin/stories/menu.stories.js | 56 ++ .../numeric-refinement-list.stories.js | 38 + .../stories/numeric-selector.stories.js | 28 + dev/app/builtin/stories/pagination.stories.js | 21 + .../builtin/stories/price-ranges.stories.js | 24 + .../builtin/stories/range-slider.stories.js | 183 ++++ .../stories/refinement-list.stories.js | 119 +++ dev/app/builtin/stories/search-box.stories.js | 49 + .../stories/sort-by-selector.stories.js | 25 + .../builtin/stories/star-rating.stories.js | 28 + dev/app/builtin/stories/stats.stories.js | 16 + dev/app/builtin/stories/toggle.stories.js | 45 + dev/app/index.js | 8 +- dev/app/init-builtin-widgets.js | 853 ------------------ dev/app/init-jquery-widgets.js | 233 ----- dev/app/init-vanilla-widgets.js | 80 -- dev/app/jquery/init-stories.js | 37 + dev/app/jquery/stories/clear-all.stories.js | 14 + .../stories/current-refined-values.stories.js | 14 + .../stories/hierarchical-menu.stories.js | 23 + .../stories/hits-per-page-selector.stories.js | 23 + dev/app/jquery/stories/hits.stories.js | 14 + .../jquery/stories/infinite-hits.stories.js | 14 + dev/app/jquery/stories/menu.stories.js | 34 + .../numeric-refinement-list.stories.js | 27 + .../stories/numeric-selector.stories.js | 26 + dev/app/jquery/stories/pagination.stories.js | 19 + .../jquery/stories/price-ranges.stories.js | 19 + .../jquery/stories/refinement-list.stories.js | 22 + dev/app/jquery/stories/search-box.stories.js | 18 + .../stories/sort-by-selector.stories.js | 23 + dev/app/jquery/stories/star-rating.stories.js | 20 + dev/app/jquery/stories/stats.stories.js | 14 + dev/app/jquery/stories/toggle.stories.js | 21 + .../jquery => jquery/widgets}/clearAll.js | 0 .../widgets}/currentRefinedValues.js | 0 .../widgets}/hierarchicalMenu.js | 0 .../jquery => jquery/widgets}/hits.js | 0 .../widgets}/hitsPerPageSelector.js | 0 .../jquery => jquery/widgets}/index.js | 0 .../jquery => jquery/widgets}/infiniteHits.js | 0 .../jquery => jquery/widgets}/menu.js | 0 .../widgets}/numericRefinementList.js | 0 .../widgets}/numericSelector.js | 0 .../jquery => jquery/widgets}/pagination.js | 0 .../jquery => jquery/widgets}/priceRanges.js | 0 .../widgets}/refinementList.js | 0 .../jquery => jquery/widgets}/searchBox.js | 0 .../jquery => jquery/widgets}/showMoreMenu.js | 0 .../widgets}/sortBySelector.js | 0 .../jquery => jquery/widgets}/starRating.js | 0 .../jquery => jquery/widgets}/stats.js | 0 .../jquery => jquery/widgets}/toggle.js | 0 dev/app/{templates => utils}/all-items.html | 0 dev/app/{templates => utils}/item.html | 0 dev/app/{templates => utils}/no-results.html | 0 dev/app/{ => utils}/wrap-with-hits.js | 16 +- dev/app/vanilla/init-stories.js | 13 + dev/app/vanilla/stories/clear-all.stories.js | 14 + dev/app/vanilla/stories/hits.stories.js | 14 + dev/app/vanilla/stories/menu.stories.js | 21 + .../stories/refinement-list.stories.js | 22 + dev/app/vanilla/stories/search-box.stories.js | 37 + .../vanilla => vanilla/widgets}/clearAll.js | 0 .../vanilla => vanilla/widgets}/hits.js | 0 .../vanilla => vanilla/widgets}/index.js | 0 .../widgets}/refinementList.js | 0 .../vanilla => vanilla/widgets}/searchBox.js | 0 .../widgets}/searchBoxReturn.js | 0 .../vanilla => vanilla/widgets}/selectMenu.js | 0 79 files changed, 1585 insertions(+), 1176 deletions(-) create mode 100644 dev/app/builtin/init-stories.js create mode 100644 dev/app/builtin/stories/analytics.stories.js create mode 100644 dev/app/builtin/stories/clear-all.stories.js create mode 100644 dev/app/builtin/stories/current-refined-values.stories.js create mode 100644 dev/app/builtin/stories/hierarchical-menu.stories.js create mode 100644 dev/app/builtin/stories/hits-per-page-selector.stories.js create mode 100644 dev/app/builtin/stories/hits.stories.js create mode 100644 dev/app/builtin/stories/infinite-hits.stories.js create mode 100644 dev/app/builtin/stories/instantsearch.stories.js create mode 100644 dev/app/builtin/stories/menu.stories.js create mode 100644 dev/app/builtin/stories/numeric-refinement-list.stories.js create mode 100644 dev/app/builtin/stories/numeric-selector.stories.js create mode 100644 dev/app/builtin/stories/pagination.stories.js create mode 100644 dev/app/builtin/stories/price-ranges.stories.js create mode 100644 dev/app/builtin/stories/range-slider.stories.js create mode 100644 dev/app/builtin/stories/refinement-list.stories.js create mode 100644 dev/app/builtin/stories/search-box.stories.js create mode 100644 dev/app/builtin/stories/sort-by-selector.stories.js create mode 100644 dev/app/builtin/stories/star-rating.stories.js create mode 100644 dev/app/builtin/stories/stats.stories.js create mode 100644 dev/app/builtin/stories/toggle.stories.js delete mode 100644 dev/app/init-builtin-widgets.js delete mode 100644 dev/app/init-jquery-widgets.js delete mode 100644 dev/app/init-vanilla-widgets.js create mode 100644 dev/app/jquery/init-stories.js create mode 100644 dev/app/jquery/stories/clear-all.stories.js create mode 100644 dev/app/jquery/stories/current-refined-values.stories.js create mode 100644 dev/app/jquery/stories/hierarchical-menu.stories.js create mode 100644 dev/app/jquery/stories/hits-per-page-selector.stories.js create mode 100644 dev/app/jquery/stories/hits.stories.js create mode 100644 dev/app/jquery/stories/infinite-hits.stories.js create mode 100644 dev/app/jquery/stories/menu.stories.js create mode 100644 dev/app/jquery/stories/numeric-refinement-list.stories.js create mode 100644 dev/app/jquery/stories/numeric-selector.stories.js create mode 100644 dev/app/jquery/stories/pagination.stories.js create mode 100644 dev/app/jquery/stories/price-ranges.stories.js create mode 100644 dev/app/jquery/stories/refinement-list.stories.js create mode 100644 dev/app/jquery/stories/search-box.stories.js create mode 100644 dev/app/jquery/stories/sort-by-selector.stories.js create mode 100644 dev/app/jquery/stories/star-rating.stories.js create mode 100644 dev/app/jquery/stories/stats.stories.js create mode 100644 dev/app/jquery/stories/toggle.stories.js rename dev/app/{custom-widgets/jquery => jquery/widgets}/clearAll.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/currentRefinedValues.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/hierarchicalMenu.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/hits.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/hitsPerPageSelector.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/index.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/infiniteHits.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/menu.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/numericRefinementList.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/numericSelector.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/pagination.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/priceRanges.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/refinementList.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/searchBox.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/showMoreMenu.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/sortBySelector.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/starRating.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/stats.js (100%) rename dev/app/{custom-widgets/jquery => jquery/widgets}/toggle.js (100%) rename dev/app/{templates => utils}/all-items.html (100%) rename dev/app/{templates => utils}/item.html (100%) rename dev/app/{templates => utils}/no-results.html (100%) rename dev/app/{ => utils}/wrap-with-hits.js (84%) create mode 100644 dev/app/vanilla/init-stories.js create mode 100644 dev/app/vanilla/stories/clear-all.stories.js create mode 100644 dev/app/vanilla/stories/hits.stories.js create mode 100644 dev/app/vanilla/stories/menu.stories.js create mode 100644 dev/app/vanilla/stories/refinement-list.stories.js create mode 100644 dev/app/vanilla/stories/search-box.stories.js rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/clearAll.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/hits.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/index.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/refinementList.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/searchBox.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/searchBoxReturn.js (100%) rename dev/app/{custom-widgets/vanilla => vanilla/widgets}/selectMenu.js (100%) diff --git a/dev/app/builtin/init-stories.js b/dev/app/builtin/init-stories.js new file mode 100644 index 0000000000..e484d295a3 --- /dev/null +++ b/dev/app/builtin/init-stories.js @@ -0,0 +1,43 @@ +import initAnalyticsStories from './stories/analytics.stories'; +import initClearAllStories from './stories/clear-all.stories'; +import initCurrentRefinedValuesStories from './stories/current-refined-values.stories'; +import initHierarchicalMenu from './stories/hierarchical-menu.stories'; +import initHitsStories from './stories/hits.stories'; +import initHitsPerPageSelectorStories from './stories/hits-per-page-selector.stories'; +import initInfiniteHitsStories from './stories/infinite-hits.stories'; +import initInstantSearchStories from './stories/instantsearch.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 initPriceRangesStories from './stories/price-ranges.stories'; +import initRangeSliderStories from './stories/range-slider.stories'; +import initRefinementListStories from './stories/refinement-list.stories'; +import initSearchBoxStories from './stories/search-box.stories'; +import initSortBySelectorStories from './stories/sort-by-selector.stories'; +import initStarRatingStories from './stories/star-rating.stories'; +import initStatsStories from './stories/stats.stories'; +import initToggleStories from './stories/toggle.stories'; + +export default () => { + initAnalyticsStories(); + initClearAllStories(); + initCurrentRefinedValuesStories(); + initHierarchicalMenu(); + initHitsStories(); + initHitsPerPageSelectorStories(); + initInfiniteHitsStories(); + initInstantSearchStories(); + initMenuStories(); + initNumericRefinementListStories(); + initNumericSelectorStories(); + initPaginationStories(); + initPriceRangesStories(); + initRangeSliderStories(); + initRefinementListStories(); + initSearchBoxStories(); + initSortBySelectorStories(); + initStatsStories(); + initStarRatingStories(); + initToggleStories(); +}; diff --git a/dev/app/builtin/stories/analytics.stories.js b/dev/app/builtin/stories/analytics.stories.js new file mode 100644 index 0000000000..93f84ea173 --- /dev/null +++ b/dev/app/builtin/stories/analytics.stories.js @@ -0,0 +1,30 @@ +/* eslint-disable import/default */ + +import { action, storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Analytics'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + const description = document.createElement('p'); + description.innerText = 'Search for something, look into Action Logger'; + container.appendChild(description); + + window.search.addWidget( + instantsearch.widgets.analytics({ + pushFunction(formattedParameters, state, results) { + action('pushFunction[formattedParameters]')(formattedParameters); + action('pushFunction[state]')(state); + action('pushFunction[results]')(results); + }, + triggerOnUIInteraction: true, + pushInitialSearch: false, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/clear-all.stories.js b/dev/app/builtin/stories/clear-all.stories.js new file mode 100644 index 0000000000..9beda8e203 --- /dev/null +++ b/dev/app/builtin/stories/clear-all.stories.js @@ -0,0 +1,64 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('ClearAll'); + +export default () => { + stories + .add( + 'default', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.clearAll({ + container, + autoHideContainer: false, + }) + ); + }, + { + searchParameters: { + disjunctiveFacetsRefinements: { brand: ['Apple'] }, + disjunctiveFacets: ['brand'], + }, + } + ) + ) + .add( + 'with nothing to clear', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.clearAll({ + container, + autoHideContainer: false, + }) + ); + }) + ) + .add( + 'with clear refinements and query', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.clearAll({ + container, + autoHideContainer: false, + clearsQuery: true, + templates: { + link: 'Clear refinements and query', + }, + }) + ); + }, + { + searchParameters: { + disjunctiveFacetsRefinements: { brand: ['Apple'] }, + disjunctiveFacets: ['brand'], + }, + } + ) + ); +}; diff --git a/dev/app/builtin/stories/current-refined-values.stories.js b/dev/app/builtin/stories/current-refined-values.stories.js new file mode 100644 index 0000000000..7a4b00c845 --- /dev/null +++ b/dev/app/builtin/stories/current-refined-values.stories.js @@ -0,0 +1,84 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('CurrentRefinedValues'); + +export default () => { + stories + .add( + 'default', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.currentRefinedValues({ container }) + ); + }, + { + searchParameters: { + disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, + disjunctiveFacets: ['brand'], + numericRefinements: { price: { '>=': [100] } }, + }, + } + ) + ) + .add( + 'with header', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.currentRefinedValues({ + container, + templates: { + header: 'Current refinements', + }, + }) + ); + }, + { + searchParameters: { + disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, + disjunctiveFacets: ['brand'], + numericRefinements: { price: { '>=': [100] } }, + }, + } + ) + ) + .add( + 'with header but no refinements', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.currentRefinedValues({ + container, + autoHideContainer: false, + templates: { + header: 'Current refinements', + }, + }) + ); + }) + ) + .add( + 'with clearsQuery', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.currentRefinedValues({ + container, + clearsQuery: true, + }) + ); + }, + { + searchParameters: { + disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, + disjunctiveFacets: ['brand'], + numericRefinements: { price: { '>=': [100] } }, + }, + } + ) + ); +}; diff --git a/dev/app/builtin/stories/hierarchical-menu.stories.js b/dev/app/builtin/stories/hierarchical-menu.stories.js new file mode 100644 index 0000000000..345d526a6a --- /dev/null +++ b/dev/app/builtin/stories/hierarchical-menu.stories.js @@ -0,0 +1,89 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('HierarchicalMenu'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.hierarchicalMenu({ + container, + attributes: [ + 'hierarchicalCategories.lvl0', + 'hierarchicalCategories.lvl1', + 'hierarchicalCategories.lvl2', + ], + showParentLevel: false, + }) + ); + }) + ) + .add( + 'hide parent levels', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.hierarchicalMenu({ + container, + attributes: [ + 'hierarchicalCategories.lvl0', + 'hierarchicalCategories.lvl1', + 'hierarchicalCategories.lvl2', + ], + showParentLevel: true, + }) + ); + }) + ) + .add( + 'with default selected item', + wrapWithHits( + container => { + window.search.addWidget( + instantsearch.widgets.hierarchicalMenu({ + container, + attributes: [ + 'hierarchicalCategories.lvl0', + 'hierarchicalCategories.lvl1', + 'hierarchicalCategories.lvl2', + ], + rootPath: 'Cameras & Camcorders', + }) + ); + }, + { + searchParameters: { + hierarchicalFacetsRefinements: { + 'hierarchicalCategories.lvl0': [ + 'Cameras & Camcorders > Digital Cameras', + ], + }, + }, + } + ) + ) + .add( + 'with header', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.hierarchicalMenu({ + container, + attributes: [ + 'hierarchicalCategories.lvl0', + 'hierarchicalCategories.lvl1', + 'hierarchicalCategories.lvl2', + ], + rootPath: 'Cameras & Camcorders', + templates: { + header: 'Hierarchical categories', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/hits-per-page-selector.stories.js b/dev/app/builtin/stories/hits-per-page-selector.stories.js new file mode 100644 index 0000000000..79d9919599 --- /dev/null +++ b/dev/app/builtin/stories/hits-per-page-selector.stories.js @@ -0,0 +1,41 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('HitsPerPageSelector'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.hitsPerPageSelector({ + container, + items: [ + { value: 3, label: '3 per page' }, + { value: 5, label: '5 per page' }, + { value: 10, label: '10 per page' }, + ], + }) + ); + }) + ) + .add( + 'with default hitPerPage to 5', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.hitsPerPageSelector({ + container, + items: [ + { value: 3, label: '3 per page' }, + { value: 5, label: '5 per page', default: true }, + { value: 10, label: '10 per page' }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/hits.stories.js b/dev/app/builtin/stories/hits.stories.js new file mode 100644 index 0000000000..41158f7af1 --- /dev/null +++ b/dev/app/builtin/stories/hits.stories.js @@ -0,0 +1,16 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Hits'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget(instantsearch.widgets.hits({ container })); + }) + ); +}; diff --git a/dev/app/builtin/stories/infinite-hits.stories.js b/dev/app/builtin/stories/infinite-hits.stories.js new file mode 100644 index 0000000000..9d7c2bbea1 --- /dev/null +++ b/dev/app/builtin/stories/infinite-hits.stories.js @@ -0,0 +1,48 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('InfiniteHits'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.infiniteHits({ + container, + showMoreLabel: 'Show more', + templates: { + item: '{{name}}', + }, + }) + ); + }) + ) + .add( + 'with custom css classes', + wrapWithHits(container => { + const style = window.document.createElement('style'); + window.document.head.appendChild(style); + style.sheet.insertRule( + '.button button{border: 1px solid black; background: #fff;}' + ); + + window.search.addWidget( + instantsearch.widgets.infiniteHits({ + container, + showMoreLabel: 'Show more', + cssClasses: { + showmore: 'button', + }, + templates: { + item: '{{name}}', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/instantsearch.stories.js b/dev/app/builtin/stories/instantsearch.stories.js new file mode 100644 index 0000000000..29cd33e23a --- /dev/null +++ b/dev/app/builtin/stories/instantsearch.stories.js @@ -0,0 +1,21 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Instantsearch'); + +export default () => { + stories.add( + 'With searchfunction that prevent search', + wrapWithHits(() => {}, { + searchFunction: helper => { + const query = helper.state.query; + if (query === '') { + return; + } + helper.search(); + }, + }) + ); +}; diff --git a/dev/app/builtin/stories/menu.stories.js b/dev/app/builtin/stories/menu.stories.js new file mode 100644 index 0000000000..d4c6223c47 --- /dev/null +++ b/dev/app/builtin/stories/menu.stories.js @@ -0,0 +1,56 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Menu'); + +export default () => { + stories + .add( + 'Default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.menu({ + container, + attributeName: 'categories', + }) + ); + }) + ) + .add( + 'with show more and header', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.menu({ + container, + attributeName: 'categories', + limit: 3, + showMore: { + templates: { + active: '', + inactive: '', + }, + limit: 10, + }, + templates: { + header: 'Categories (menu widget)', + }, + }) + ); + }) + ) + .add( + 'as a Select DOM element', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.menuSelect({ + container, + attributeName: 'categories', + limit: 10, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/numeric-refinement-list.stories.js b/dev/app/builtin/stories/numeric-refinement-list.stories.js new file mode 100644 index 0000000000..d8dca85c5b --- /dev/null +++ b/dev/app/builtin/stories/numeric-refinement-list.stories.js @@ -0,0 +1,38 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('NumericRefinementList'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.numericRefinementList({ + container, + attributeName: 'price', + operator: 'or', + options: [ + { name: 'All' }, + { end: 4, name: 'less than 4' }, + { start: 4, end: 4, name: '4' }, + { start: 5, end: 10, name: 'between 5 and 10' }, + { start: 10, name: 'more than 10' }, + ], + cssClasses: { + header: 'facet-title', + link: 'facet-value', + count: 'facet-count pull-right', + active: 'facet-active', + }, + templates: { + header: 'Numeric refinement list (price)', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/numeric-selector.stories.js b/dev/app/builtin/stories/numeric-selector.stories.js new file mode 100644 index 0000000000..560478b49f --- /dev/null +++ b/dev/app/builtin/stories/numeric-selector.stories.js @@ -0,0 +1,28 @@ +/* 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: 9991 }, + { label: 'Top 100', value: 9901 }, + { label: 'Top 500', value: 9501 }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/pagination.stories.js b/dev/app/builtin/stories/pagination.stories.js new file mode 100644 index 0000000000..966e4a5cee --- /dev/null +++ b/dev/app/builtin/stories/pagination.stories.js @@ -0,0 +1,21 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Pagination'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.pagination({ + container, + maxPages: 20, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/price-ranges.stories.js b/dev/app/builtin/stories/price-ranges.stories.js new file mode 100644 index 0000000000..2cbbf7b4fb --- /dev/null +++ b/dev/app/builtin/stories/price-ranges.stories.js @@ -0,0 +1,24 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('PriceRanges'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.priceRanges({ + container, + attributeName: 'price', + templates: { + header: 'Price ranges', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/range-slider.stories.js b/dev/app/builtin/stories/range-slider.stories.js new file mode 100644 index 0000000000..5c3be70bc9 --- /dev/null +++ b/dev/app/builtin/stories/range-slider.stories.js @@ -0,0 +1,183 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('RangeSlider'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'disabled', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + min: 100, + max: 50, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'collapsible', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + collapsible: { + collapsed: false, + }, + templates: { + header: 'Price', + }, + }) + ); + }) + ) + .add( + 'with step', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + step: 500, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'without pips', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + pips: false, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'with 0 as first pit', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + min: 0, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'with min boundaries', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + min: 36, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'with max boundaries', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + max: 36, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ) + .add( + 'with min / max boundaries', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.rangeSlider({ + container, + attributeName: 'price', + templates: { + header: 'Price', + }, + min: 10, + max: 500, + tooltips: { + format(rawValue) { + return `$${Math.round(rawValue).toLocaleString()}`; + }, + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/refinement-list.stories.js b/dev/app/builtin/stories/refinement-list.stories.js new file mode 100644 index 0000000000..b6f952cc8c --- /dev/null +++ b/dev/app/builtin/stories/refinement-list.stories.js @@ -0,0 +1,119 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('RefinementList'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.refinementList({ + container, + attributeName: 'brand', + operator: 'or', + limit: 10, + templates: { + header: 'Brands', + }, + }) + ); + }) + ) + .add( + 'with show more', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.refinementList({ + container, + attributeName: 'brand', + operator: 'or', + limit: 3, + templates: { + header: 'Brands with show more', + }, + showMore: { + templates: { + active: '', + inactive: '', + }, + limit: 10, + }, + }) + ); + }) + ) + .add( + 'with search inside items', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.refinementList({ + container, + attributeName: 'brand', + operator: 'or', + limit: 10, + templates: { + header: 'Searchable brands', + }, + searchForFacetValues: { + placeholder: 'Find other brands...', + templates: { + noResults: 'No results', + }, + }, + }) + ); + }) + ) + .add( + 'with search inside items (using the default noResults template)', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.refinementList({ + container, + attributeName: 'brand', + operator: 'or', + limit: 10, + templates: { + header: 'Searchable brands', + }, + searchForFacetValues: { + placeholder: 'Find other brands...', + }, + }) + ); + }) + ) + .add( + 'with operator `and`', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.refinementList({ + container, + attributeName: 'price_range', + operator: 'and', + limit: 10, + cssClasses: { + header: 'facet-title', + item: 'facet-value checkbox', + count: 'facet-count pull-right', + active: 'facet-active', + }, + templates: { + header: 'Price ranges', + }, + transformData(data) { + data.label = data.label + .replace(/(\d+) - (\d+)/, '$$$1 - $$$2') + .replace(/> (\d+)/, '> $$$1'); + return data; + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/search-box.stories.js b/dev/app/builtin/stories/search-box.stories.js new file mode 100644 index 0000000000..4af5b958f8 --- /dev/null +++ b/dev/app/builtin/stories/search-box.stories.js @@ -0,0 +1,49 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('SearchBox'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.searchBox({ + container, + placeholder: 'Search for products', + poweredBy: true, + }) + ); + }) + ) + .add( + 'search on enter', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.searchBox({ + container, + placeholder: 'Search for products', + poweredBy: true, + searchOnEnterKeyPressOnly: true, + }) + ); + }) + ) + .add( + 'input with initial value', + wrapWithHits(container => { + container.innerHTML = ''; + const input = container.firstChild; + container.appendChild(input); + window.search.addWidget( + instantsearch.widgets.searchBox({ + container: input, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/sort-by-selector.stories.js b/dev/app/builtin/stories/sort-by-selector.stories.js new file mode 100644 index 0000000000..7a87a18131 --- /dev/null +++ b/dev/app/builtin/stories/sort-by-selector.stories.js @@ -0,0 +1,25 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('SortBySelector'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.sortBySelector({ + container, + indices: [ + { name: 'instant_search', label: 'Most relevant' }, + { name: 'instant_search_price_asc', label: 'Lowest price' }, + { name: 'instant_search_price_desc', label: 'Highest price' }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/star-rating.stories.js b/dev/app/builtin/stories/star-rating.stories.js new file mode 100644 index 0000000000..6f779e8847 --- /dev/null +++ b/dev/app/builtin/stories/star-rating.stories.js @@ -0,0 +1,28 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('StarRating'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.starRating({ + container, + attributeName: 'rating', + max: 5, + labels: { + andUp: '& Up', + }, + templates: { + header: 'Rating', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/builtin/stories/stats.stories.js b/dev/app/builtin/stories/stats.stories.js new file mode 100644 index 0000000000..f3224e99bb --- /dev/null +++ b/dev/app/builtin/stories/stats.stories.js @@ -0,0 +1,16 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Stats'); + +export default () => { + stories.add( + 'default', + wrapWithHits(container => { + window.search.addWidget(instantsearch.widgets.stats({ container })); + }) + ); +}; diff --git a/dev/app/builtin/stories/toggle.stories.js b/dev/app/builtin/stories/toggle.stories.js new file mode 100644 index 0000000000..00abc12f22 --- /dev/null +++ b/dev/app/builtin/stories/toggle.stories.js @@ -0,0 +1,45 @@ +/* eslint-disable import/default */ + +import { storiesOf } from 'dev-novel'; +import instantsearch from '../../../../index'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; + +const stories = storiesOf('Toggle'); + +export default () => { + stories + .add( + 'with single value', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.toggle({ + container, + attributeName: 'free_shipping', + label: 'Free Shipping (toggle single value)', + templates: { + header: 'Shipping', + }, + }) + ); + }) + ) + .add( + 'with on & off values', + wrapWithHits(container => { + window.search.addWidget( + instantsearch.widgets.toggle({ + container, + attributeName: 'brand', + label: 'Canon (not checked) or sony (checked)', + values: { + on: 'Sony', + off: 'Canon', + }, + templates: { + header: 'Google or amazon (toggle two values)', + }, + }) + ); + }) + ); +}; diff --git a/dev/app/index.js b/dev/app/index.js index ddffba9a9c..d2e1d0a621 100644 --- a/dev/app/index.js +++ b/dev/app/index.js @@ -1,9 +1,7 @@ -/* eslint-disable import/default */ import { registerDisposer, start } from 'dev-novel'; - -import initBuiltInWidgets from './init-builtin-widgets.js'; -import initVanillaWidgets from './init-vanilla-widgets.js'; -import initJqueryWidgets from './init-jquery-widgets.js'; +import initBuiltInWidgets from './builtin/init-stories'; +import initJqueryWidgets from './jquery/init-stories'; +import initVanillaWidgets from './vanilla/init-stories'; import '../style.css'; import '../../src/css/instantsearch.scss'; diff --git a/dev/app/init-builtin-widgets.js b/dev/app/init-builtin-widgets.js deleted file mode 100644 index 335db9adea..0000000000 --- a/dev/app/init-builtin-widgets.js +++ /dev/null @@ -1,853 +0,0 @@ -/* eslint-disable import/default */ -import { action, storiesOf } from 'dev-novel'; -import instantsearch from '../../index.js'; - -import wrapWithHits from './wrap-with-hits.js'; - -export default () => { - storiesOf('instantsearch').add( - 'With searchfunction that prevent search', - wrapWithHits(() => {}, { - searchFunction: helper => { - const query = helper.state.query; - if (query === '') { - return; - } - helper.search(); - }, - }) - ); - - storiesOf('Analytics').add( - 'default', - wrapWithHits(container => { - const description = document.createElement('p'); - description.innerText = 'Search for something, look into Action Logger'; - container.appendChild(description); - - window.search.addWidget( - instantsearch.widgets.analytics({ - pushFunction(formattedParameters, state, results) { - action('pushFunction[formattedParameters]')(formattedParameters); - action('pushFunction[state]')(state); - action('pushFunction[results]')(results); - }, - triggerOnUIInteraction: true, - pushInitialSearch: false, - }) - ); - }) - ); - - storiesOf('SearchBox') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.searchBox({ - container, - placeholder: 'Search for products', - poweredBy: true, - }) - ); - }) - ) - .add( - 'search on enter', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.searchBox({ - container, - placeholder: 'Search for products', - poweredBy: true, - searchOnEnterKeyPressOnly: true, - }) - ); - }) - ) - .add( - 'input with initial value', - wrapWithHits(container => { - container.innerHTML = ''; - const input = container.firstChild; - container.appendChild(input); - window.search.addWidget( - instantsearch.widgets.searchBox({ - container: input, - }) - ); - }) - ); - - storiesOf('Stats').add( - 'default', - wrapWithHits(container => { - window.search.addWidget(instantsearch.widgets.stats({ container })); - }) - ); - - storiesOf('SortBySelector').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.sortBySelector({ - container, - indices: [ - { name: 'instant_search', label: 'Most relevant' }, - { name: 'instant_search_price_asc', label: 'Lowest price' }, - { name: 'instant_search_price_desc', label: 'Highest price' }, - ], - }) - ); - }) - ); - - storiesOf('HitsPerPageSelector') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.hitsPerPageSelector({ - container, - items: [ - { value: 3, label: '3 per page' }, - { value: 5, label: '5 per page' }, - { value: 10, label: '10 per page' }, - ], - }) - ); - }) - ) - .add( - 'With default hitPerPage to 5', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.hitsPerPageSelector({ - container, - items: [ - { value: 3, label: '3 per page' }, - { value: 5, label: '5 per page', default: true }, - { value: 10, label: '10 per page' }, - ], - }) - ); - }) - ); - - storiesOf('Hits').add( - 'default', - wrapWithHits(container => { - window.search.addWidget(instantsearch.widgets.hits({ container })); - }) - ); - - storiesOf('InfiniteHits') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.infiniteHits({ - container, - showMoreLabel: 'Show more', - templates: { - item: '{{name}}', - }, - }) - ); - }) - ) - .add( - 'with custom css classes', - wrapWithHits(container => { - const style = window.document.createElement('style'); - window.document.head.appendChild(style); - style.sheet.insertRule( - '.button button{border: 1px solid black; background: #fff;}' - ); - - window.search.addWidget( - instantsearch.widgets.infiniteHits({ - container, - showMoreLabel: 'Show more', - cssClasses: { - showmore: 'button', - }, - templates: { - item: '{{name}}', - }, - }) - ); - }) - ); - - storiesOf('Pagination').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.pagination({ - container, - maxPages: 20, - }) - ); - }) - ); - - storiesOf('ClearAll') - .add( - 'default', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.clearAll({ - container, - autoHideContainer: false, - }) - ); - }, - { - searchParameters: { - disjunctiveFacetsRefinements: { brand: ['Apple'] }, - disjunctiveFacets: ['brand'], - }, - } - ) - ) - .add( - 'with nothing to clear', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.clearAll({ - container, - autoHideContainer: false, - }) - ); - }) - ) - .add( - 'with clear refinements and query', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.clearAll({ - container, - autoHideContainer: false, - clearsQuery: true, - templates: { - link: 'Clear refinements and query', - }, - }) - ); - }, - { - searchParameters: { - disjunctiveFacetsRefinements: { brand: ['Apple'] }, - disjunctiveFacets: ['brand'], - }, - } - ) - ); - - storiesOf('CurrentRefinedValues') - .add( - 'default', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.currentRefinedValues({ container }) - ); - }, - { - searchParameters: { - disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, - disjunctiveFacets: ['brand'], - numericRefinements: { price: { '>=': [100] } }, - }, - } - ) - ) - .add( - 'with header', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.currentRefinedValues({ - container, - templates: { - header: 'Current refinements', - }, - }) - ); - }, - { - searchParameters: { - disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, - disjunctiveFacets: ['brand'], - numericRefinements: { price: { '>=': [100] } }, - }, - } - ) - ) - .add( - 'with header but no refinements', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.currentRefinedValues({ - container, - autoHideContainer: false, - templates: { - header: 'Current refinements', - }, - }) - ); - }) - ) - .add( - 'with clearsQuery', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.currentRefinedValues({ - container, - clearsQuery: true, - }) - ); - }, - { - searchParameters: { - disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'] }, - disjunctiveFacets: ['brand'], - numericRefinements: { price: { '>=': [100] } }, - }, - } - ) - ); - - storiesOf('RefinementList') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.refinementList({ - container, - attributeName: 'brand', - operator: 'or', - limit: 10, - templates: { - header: 'Brands', - }, - }) - ); - }) - ) - .add( - 'with show more', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.refinementList({ - container, - attributeName: 'brand', - operator: 'or', - limit: 3, - templates: { - header: 'Brands with show more', - }, - showMore: { - templates: { - active: '', - inactive: '', - }, - limit: 10, - }, - }) - ); - }) - ) - .add( - 'with search inside items', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.refinementList({ - container, - attributeName: 'brand', - operator: 'or', - limit: 10, - templates: { - header: 'Searchable brands', - }, - searchForFacetValues: { - placeholder: 'Find other brands...', - templates: { - noResults: 'No results', - }, - }, - }) - ); - }) - ) - .add( - 'with search inside items (using the default noResults template)', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.refinementList({ - container, - attributeName: 'brand', - operator: 'or', - limit: 10, - templates: { - header: 'Searchable brands', - }, - searchForFacetValues: { - placeholder: 'Find other brands...', - }, - }) - ); - }) - ) - .add( - 'with operator `and`', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.refinementList({ - container, - attributeName: 'price_range', - operator: 'and', - limit: 10, - cssClasses: { - header: 'facet-title', - item: 'facet-value checkbox', - count: 'facet-count pull-right', - active: 'facet-active', - }, - templates: { - header: 'Price ranges', - }, - transformData(data) { - data.label = data.label - .replace(/(\d+) - (\d+)/, '$$$1 - $$$2') - .replace(/> (\d+)/, '> $$$1'); - return data; - }, - }) - ); - }) - ); - - storiesOf('StarRating').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.starRating({ - container, - attributeName: 'rating', - max: 5, - labels: { - andUp: '& Up', - }, - templates: { - header: 'Rating', - }, - }) - ); - }) - ); - - storiesOf('NumericRefinementList').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.numericRefinementList({ - container, - attributeName: 'price', - operator: 'or', - options: [ - { name: 'All' }, - { end: 4, name: 'less than 4' }, - { start: 4, end: 4, name: '4' }, - { start: 5, end: 10, name: 'between 5 and 10' }, - { start: 10, name: 'more than 10' }, - ], - cssClasses: { - header: 'facet-title', - link: 'facet-value', - count: 'facet-count pull-right', - active: 'facet-active', - }, - templates: { - header: 'Numeric refinement list (price)', - }, - }) - ); - }) - ); - - storiesOf('Toggle') - .add( - 'with single value', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.toggle({ - container, - attributeName: 'free_shipping', - label: 'Free Shipping (toggle single value)', - templates: { - header: 'Shipping', - }, - }) - ); - }) - ) - .add( - 'with on & off values', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.toggle({ - container, - attributeName: 'brand', - label: 'Canon (not checked) or sony (checked)', - values: { - on: 'Sony', - off: 'Canon', - }, - templates: { - header: 'Google or amazon (toggle two values)', - }, - }) - ); - }) - ); - - storiesOf('Menu') - .add( - 'Default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.menu({ - container, - attributeName: 'categories', - }) - ); - }) - ) - .add( - 'with show more and header', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.menu({ - container, - attributeName: 'categories', - limit: 3, - showMore: { - templates: { - active: '', - inactive: '', - }, - limit: 10, - }, - templates: { - header: 'Categories (menu widget)', - }, - }) - ); - }) - ) - .add( - 'as a Select DOM element', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.menuSelect({ - container, - attributeName: 'categories', - limit: 10, - }) - ); - }) - ); - - storiesOf('RangeSlider') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'disabled', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - min: 100, - max: 50, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'collapsible', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - collapsible: { - collapsed: false, - }, - templates: { - header: 'Price', - }, - }) - ); - }) - ) - .add( - 'with step', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - step: 500, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'without pips', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - pips: false, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'with 0 as first pit', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - min: 0, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'with min boundaries', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - min: 36, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'with max boundaries', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - max: 36, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ) - .add( - 'with min / max boundaries', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.rangeSlider({ - container, - attributeName: 'price', - templates: { - header: 'Price', - }, - min: 10, - max: 500, - tooltips: { - format(rawValue) { - return `$${Math.round(rawValue).toLocaleString()}`; - }, - }, - }) - ); - }) - ); - - storiesOf('HierarchicalMenu') - .add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.hierarchicalMenu({ - container, - attributes: [ - 'hierarchicalCategories.lvl0', - 'hierarchicalCategories.lvl1', - 'hierarchicalCategories.lvl2', - ], - showParentLevel: false, - }) - ); - }) - ) - .add( - 'hide parent levels', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.hierarchicalMenu({ - container, - attributes: [ - 'hierarchicalCategories.lvl0', - 'hierarchicalCategories.lvl1', - 'hierarchicalCategories.lvl2', - ], - showParentLevel: true, - }) - ); - }) - ) - .add( - 'with default selected item', - wrapWithHits( - container => { - window.search.addWidget( - instantsearch.widgets.hierarchicalMenu({ - container, - attributes: [ - 'hierarchicalCategories.lvl0', - 'hierarchicalCategories.lvl1', - 'hierarchicalCategories.lvl2', - ], - rootPath: 'Cameras & Camcorders', - }) - ); - }, - { - searchParameters: { - hierarchicalFacetsRefinements: { - 'hierarchicalCategories.lvl0': [ - 'Cameras & Camcorders > Digital Cameras', - ], - }, - }, - } - ) - ) - .add( - 'with header', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.hierarchicalMenu({ - container, - attributes: [ - 'hierarchicalCategories.lvl0', - 'hierarchicalCategories.lvl1', - 'hierarchicalCategories.lvl2', - ], - rootPath: 'Cameras & Camcorders', - templates: { - header: 'Hierarchical categories', - }, - }) - ); - }) - ); - - storiesOf('PriceRanges').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - instantsearch.widgets.priceRanges({ - container, - attributeName: 'price', - templates: { - header: 'Price ranges', - }, - }) - ); - }) - ); - - storiesOf('NumericSelector').add( - 'default', - wrapWithHits(container => { - window.search.addWidget( - 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 }, - ], - }) - ); - }) - ); -}; diff --git a/dev/app/init-jquery-widgets.js b/dev/app/init-jquery-widgets.js deleted file mode 100644 index 1a2bdb37c8..0000000000 --- a/dev/app/init-jquery-widgets.js +++ /dev/null @@ -1,233 +0,0 @@ -/* eslint-disable import/default */ -import { storiesOf } from 'dev-novel'; -import * as jqueryWidgets from './custom-widgets/jquery/index.js'; - -import wrapWithHits from './wrap-with-hits.js'; - -// transform `container` to jQuery object -const wrap = fn => wrapWithHits(container => fn(window.$(container))); - -export default () => { - storiesOf('Pagination').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.pagination({ - containerNode, - maxPages: 20, - }) - ); - }) - ); - - storiesOf('Menu') - .add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.menu({ - containerNode, - attributeName: 'categories', - limit: 3, - }) - ); - }) - ) - .add( - 'with show more', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.showMoreMenu({ - containerNode, - attributeName: 'categories', - limit: 3, - showMoreLimit: 10, - }) - ); - }) - ); - - storiesOf('ClearAll').add( - 'default', - wrap(containerNode => { - window.search.addWidget(jqueryWidgets.clearAll({ containerNode })); - }) - ); - - storiesOf('CurrentRefinedValues').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.currentRefinedValues({ containerNode }) - ); - }) - ); - - storiesOf('HitsPerPageSelector').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.hitsPerPageSelector({ - containerNode, - items: [ - { value: 3, label: '3 per page' }, - { value: 5, label: '5 per page' }, - { value: 10, label: '10 per page' }, - ], - }) - ); - }) - ); - - storiesOf('HierarchicalMenu').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.hierarchicalMenu({ - containerNode, - attributes: [ - 'hierarchicalCategories.lvl0', - 'hierarchicalCategories.lvl1', - 'hierarchicalCategories.lvl2', - ], - }) - ); - }) - ); - - storiesOf('Hits').add( - 'default', - wrap(containerNode => { - window.search.addWidget(jqueryWidgets.hits({ containerNode })); - }) - ); - - storiesOf('RefinementList').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.refinementList({ - containerNode, - attributeName: 'brand', - operator: 'or', - limit: 10, - title: 'Brands', - }) - ); - }) - ); - - storiesOf('NumericSelector').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.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 }, - ], - }) - ); - }) - ); - - storiesOf('NumericRefinementList').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.numericRefinementList({ - containerNode, - attributeName: 'price', - operator: 'or', - options: [ - { name: 'All' }, - { end: 4, name: 'less than 4' }, - { start: 4, end: 4, name: '4' }, - { start: 5, end: 10, name: 'between 5 and 10' }, - { start: 10, name: 'more than 10' }, - ], - }) - ); - }) - ); - - storiesOf('PriceRanges').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.priceRanges({ - containerNode, - attributeName: 'price', - }) - ); - }) - ); - - storiesOf('SearchBox').add( - 'default', - wrap(containerNode => { - const inputNode = document.createElement('input'); - containerNode.appendChild(inputNode); - window.search.addWidget(jqueryWidgets.searchBox({ inputNode })); - }) - ); - - storiesOf('SortBySelector').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.sortBySelector({ - containerNode, - indices: [ - { name: 'instant_search', label: 'Most relevant' }, - { name: 'instant_search_price_asc', label: 'Lowest price' }, - { name: 'instant_search_price_desc', label: 'Highest price' }, - ], - }) - ); - }) - ); - - storiesOf('StarRating').add('default', containerNode => { - window.search.addWidget( - jqueryWidgets.starRating({ - containerNode, - attributeName: 'rating', - max: 5, - }) - ); - }); - - storiesOf('Stats').add( - 'default', - wrap(containerNode => { - window.search.addWidget(jqueryWidgets.stats({ containerNode })); - }) - ); - - storiesOf('Toggle').add( - 'default', - wrap(containerNode => { - window.search.addWidget( - jqueryWidgets.toggle({ - containerNode, - attributeName: 'free_shipping', - label: 'Free Shipping (toggle single value)', - title: 'Free Shipping', - }) - ); - }) - ); - - storiesOf('InfiniteHits').add( - 'default', - wrap(containerNode => { - window.search.addWidget(jqueryWidgets.infiniteHits({ containerNode })); - }) - ); -}; diff --git a/dev/app/init-vanilla-widgets.js b/dev/app/init-vanilla-widgets.js deleted file mode 100644 index 2a71c38ade..0000000000 --- a/dev/app/init-vanilla-widgets.js +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable import/default */ -import { storiesOf } from 'dev-novel'; - -import * as vanillaWidgets from './custom-widgets/vanilla/index.js'; -import wrapWithHits from './wrap-with-hits.js'; - -export default () => { - storiesOf('SearchBox') - .add( - 'default', - wrapWithHits(container => { - const input = document.createElement('input'); - container.appendChild(input); - - window.search.addWidget( - vanillaWidgets.searchBox({ - node: input, - placeholder: 'Search for products', - }) - ); - }) - ) - .add( - 'with enter to search', - wrapWithHits(container => { - const input = document.createElement('input'); - container.appendChild(input); - - window.search.addWidget( - vanillaWidgets.searchBoxReturn({ - node: input, - placeholder: 'Search for products', - }) - ); - }) - ); - - storiesOf('ClearAll').add( - 'default', - wrapWithHits(containerNode => { - window.search.addWidget(vanillaWidgets.clearAll({ containerNode })); - }) - ); - - storiesOf('Hits').add( - 'default', - wrapWithHits(containerNode => { - window.search.addWidget(vanillaWidgets.hits({ containerNode })); - }) - ); - - storiesOf('Menu').add( - 'select', - wrapWithHits(containerNode => { - window.search.addWidget( - vanillaWidgets.selectMenu({ - containerNode, - attributeName: 'brand', - limit: 10, - title: 'Brands', - }) - ); - }) - ); - - storiesOf('RefinementList').add( - 'default', - wrapWithHits(containerNode => { - window.search.addWidget( - vanillaWidgets.refinementList({ - containerNode, - attributeName: 'brand', - operator: 'or', - limit: 10, - title: 'Brands', - }) - ); - }) - ); -}; diff --git a/dev/app/jquery/init-stories.js b/dev/app/jquery/init-stories.js new file mode 100644 index 0000000000..8b7329de46 --- /dev/null +++ b/dev/app/jquery/init-stories.js @@ -0,0 +1,37 @@ +import initClearAllStories from './stories/clear-all.stories'; +import initCurrentRefinedValuesStories from './stories/current-refined-values.stories'; +import initHierarchicalMenuStories from './stories/hierarchical-menu.stories'; +import initHitsStories from './stories/hits.stories'; +import initHitsPerPageSelectorStories from './stories/hits-per-page-selector.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 initPriceRangesStories from './stories/price-ranges.stories'; +import initRefinementListStories from './stories/refinement-list.stories'; +import initSearchBoxStories from './stories/search-box.stories'; +import initSortBySelectorStories from './stories/sort-by-selector.stories'; +import initStarRatingStories from './stories/star-rating.stories'; +import initStatsStories from './stories/stats.stories'; +import initToggleStories from './stories/toggle.stories'; + +export default () => { + initClearAllStories(); + initCurrentRefinedValuesStories(); + initHierarchicalMenuStories(); + initHitsStories(); + initHitsPerPageSelectorStories(); + initInfiniteHitsStories(); + initMenuStories(); + initNumericRefinementListStories(); + initNumericSelectorStories(); + initPaginationStories(); + initPriceRangesStories(); + initRefinementListStories(); + initSearchBoxStories(); + initSortBySelectorStories(); + initStarRatingStories(); + initStatsStories(); + initToggleStories(); +}; diff --git a/dev/app/jquery/stories/clear-all.stories.js b/dev/app/jquery/stories/clear-all.stories.js new file mode 100644 index 0000000000..a7f287a518 --- /dev/null +++ b/dev/app/jquery/stories/clear-all.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('ClearAll'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget(widgets.clearAll({ containerNode })); + }) + ); +}; diff --git a/dev/app/jquery/stories/current-refined-values.stories.js b/dev/app/jquery/stories/current-refined-values.stories.js new file mode 100644 index 0000000000..c8288c79a6 --- /dev/null +++ b/dev/app/jquery/stories/current-refined-values.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('CurrentRefinedValues'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget(widgets.currentRefinedValues({ containerNode })); + }) + ); +}; diff --git a/dev/app/jquery/stories/hierarchical-menu.stories.js b/dev/app/jquery/stories/hierarchical-menu.stories.js new file mode 100644 index 0000000000..c5d31cc142 --- /dev/null +++ b/dev/app/jquery/stories/hierarchical-menu.stories.js @@ -0,0 +1,23 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('HierarchicalMenu'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.hierarchicalMenu({ + containerNode, + attributes: [ + 'hierarchicalCategories.lvl0', + 'hierarchicalCategories.lvl1', + 'hierarchicalCategories.lvl2', + ], + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/hits-per-page-selector.stories.js b/dev/app/jquery/stories/hits-per-page-selector.stories.js new file mode 100644 index 0000000000..03d9d5dd7b --- /dev/null +++ b/dev/app/jquery/stories/hits-per-page-selector.stories.js @@ -0,0 +1,23 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('HitsPerPageSelector'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.hitsPerPageSelector({ + containerNode, + items: [ + { value: 3, label: '3 per page' }, + { value: 5, label: '5 per page' }, + { value: 10, label: '10 per page' }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/hits.stories.js b/dev/app/jquery/stories/hits.stories.js new file mode 100644 index 0000000000..ca28484484 --- /dev/null +++ b/dev/app/jquery/stories/hits.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Hits'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget(widgets.hits({ containerNode })); + }) + ); +}; diff --git a/dev/app/jquery/stories/infinite-hits.stories.js b/dev/app/jquery/stories/infinite-hits.stories.js new file mode 100644 index 0000000000..2c74770b82 --- /dev/null +++ b/dev/app/jquery/stories/infinite-hits.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('InfiniteHits'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget(widgets.infiniteHits({ containerNode })); + }) + ); +}; diff --git a/dev/app/jquery/stories/menu.stories.js b/dev/app/jquery/stories/menu.stories.js new file mode 100644 index 0000000000..4e73b49be9 --- /dev/null +++ b/dev/app/jquery/stories/menu.stories.js @@ -0,0 +1,34 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Menu'); + +export default () => { + stories + .add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.menu({ + containerNode, + attributeName: 'categories', + limit: 3, + }) + ); + }) + ) + .add( + 'with show more', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.showMoreMenu({ + containerNode, + attributeName: 'categories', + limit: 3, + showMoreLimit: 10, + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/numeric-refinement-list.stories.js b/dev/app/jquery/stories/numeric-refinement-list.stories.js new file mode 100644 index 0000000000..3698e56559 --- /dev/null +++ b/dev/app/jquery/stories/numeric-refinement-list.stories.js @@ -0,0 +1,27 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('NumericRefinementList'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.numericRefinementList({ + containerNode, + attributeName: 'price', + operator: 'or', + options: [ + { name: 'All' }, + { end: 4, name: 'less than 4' }, + { start: 4, end: 4, name: '4' }, + { start: 5, end: 10, name: 'between 5 and 10' }, + { start: 10, name: 'more than 10' }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/numeric-selector.stories.js b/dev/app/jquery/stories/numeric-selector.stories.js new file mode 100644 index 0000000000..89145836f9 --- /dev/null +++ b/dev/app/jquery/stories/numeric-selector.stories.js @@ -0,0 +1,26 @@ +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/stories/pagination.stories.js b/dev/app/jquery/stories/pagination.stories.js new file mode 100644 index 0000000000..8f59102c7b --- /dev/null +++ b/dev/app/jquery/stories/pagination.stories.js @@ -0,0 +1,19 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Pagination'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.pagination({ + containerNode, + maxPages: 20, + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/price-ranges.stories.js b/dev/app/jquery/stories/price-ranges.stories.js new file mode 100644 index 0000000000..bb78d233b1 --- /dev/null +++ b/dev/app/jquery/stories/price-ranges.stories.js @@ -0,0 +1,19 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('PriceRanges'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.priceRanges({ + containerNode, + attributeName: 'price', + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/refinement-list.stories.js b/dev/app/jquery/stories/refinement-list.stories.js new file mode 100644 index 0000000000..14dc8dddff --- /dev/null +++ b/dev/app/jquery/stories/refinement-list.stories.js @@ -0,0 +1,22 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('RefinementList'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.refinementList({ + containerNode, + attributeName: 'brand', + operator: 'or', + limit: 10, + title: 'Brands', + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/search-box.stories.js b/dev/app/jquery/stories/search-box.stories.js new file mode 100644 index 0000000000..32a0e2441a --- /dev/null +++ b/dev/app/jquery/stories/search-box.stories.js @@ -0,0 +1,18 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('SearchBox'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + const inputNode = document.createElement('input'); + containerNode.append(inputNode); + window.search.addWidget( + widgets.searchBox({ inputNode: window.$(inputNode) }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/sort-by-selector.stories.js b/dev/app/jquery/stories/sort-by-selector.stories.js new file mode 100644 index 0000000000..e6eb2cc0e5 --- /dev/null +++ b/dev/app/jquery/stories/sort-by-selector.stories.js @@ -0,0 +1,23 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('SortBySelector'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.sortBySelector({ + containerNode, + indices: [ + { name: 'instant_search', label: 'Most relevant' }, + { name: 'instant_search_price_asc', label: 'Lowest price' }, + { name: 'instant_search_price_desc', label: 'Highest price' }, + ], + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/star-rating.stories.js b/dev/app/jquery/stories/star-rating.stories.js new file mode 100644 index 0000000000..4930a171e4 --- /dev/null +++ b/dev/app/jquery/stories/star-rating.stories.js @@ -0,0 +1,20 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('StarRating'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.starRating({ + containerNode, + attributeName: 'rating', + max: 5, + }) + ); + }) + ); +}; diff --git a/dev/app/jquery/stories/stats.stories.js b/dev/app/jquery/stories/stats.stories.js new file mode 100644 index 0000000000..21f728c207 --- /dev/null +++ b/dev/app/jquery/stories/stats.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Stats'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget(widgets.stats({ containerNode })); + }) + ); +}; diff --git a/dev/app/jquery/stories/toggle.stories.js b/dev/app/jquery/stories/toggle.stories.js new file mode 100644 index 0000000000..d90184aae9 --- /dev/null +++ b/dev/app/jquery/stories/toggle.stories.js @@ -0,0 +1,21 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHitsAndJquery } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Toggle'); + +export default () => { + stories.add( + 'default', + wrapWithHitsAndJquery(containerNode => { + window.search.addWidget( + widgets.toggle({ + containerNode, + attributeName: 'free_shipping', + label: 'Free Shipping (toggle single value)', + title: 'Free Shipping', + }) + ); + }) + ); +}; diff --git a/dev/app/custom-widgets/jquery/clearAll.js b/dev/app/jquery/widgets/clearAll.js similarity index 100% rename from dev/app/custom-widgets/jquery/clearAll.js rename to dev/app/jquery/widgets/clearAll.js diff --git a/dev/app/custom-widgets/jquery/currentRefinedValues.js b/dev/app/jquery/widgets/currentRefinedValues.js similarity index 100% rename from dev/app/custom-widgets/jquery/currentRefinedValues.js rename to dev/app/jquery/widgets/currentRefinedValues.js diff --git a/dev/app/custom-widgets/jquery/hierarchicalMenu.js b/dev/app/jquery/widgets/hierarchicalMenu.js similarity index 100% rename from dev/app/custom-widgets/jquery/hierarchicalMenu.js rename to dev/app/jquery/widgets/hierarchicalMenu.js diff --git a/dev/app/custom-widgets/jquery/hits.js b/dev/app/jquery/widgets/hits.js similarity index 100% rename from dev/app/custom-widgets/jquery/hits.js rename to dev/app/jquery/widgets/hits.js diff --git a/dev/app/custom-widgets/jquery/hitsPerPageSelector.js b/dev/app/jquery/widgets/hitsPerPageSelector.js similarity index 100% rename from dev/app/custom-widgets/jquery/hitsPerPageSelector.js rename to dev/app/jquery/widgets/hitsPerPageSelector.js diff --git a/dev/app/custom-widgets/jquery/index.js b/dev/app/jquery/widgets/index.js similarity index 100% rename from dev/app/custom-widgets/jquery/index.js rename to dev/app/jquery/widgets/index.js diff --git a/dev/app/custom-widgets/jquery/infiniteHits.js b/dev/app/jquery/widgets/infiniteHits.js similarity index 100% rename from dev/app/custom-widgets/jquery/infiniteHits.js rename to dev/app/jquery/widgets/infiniteHits.js diff --git a/dev/app/custom-widgets/jquery/menu.js b/dev/app/jquery/widgets/menu.js similarity index 100% rename from dev/app/custom-widgets/jquery/menu.js rename to dev/app/jquery/widgets/menu.js diff --git a/dev/app/custom-widgets/jquery/numericRefinementList.js b/dev/app/jquery/widgets/numericRefinementList.js similarity index 100% rename from dev/app/custom-widgets/jquery/numericRefinementList.js rename to dev/app/jquery/widgets/numericRefinementList.js diff --git a/dev/app/custom-widgets/jquery/numericSelector.js b/dev/app/jquery/widgets/numericSelector.js similarity index 100% rename from dev/app/custom-widgets/jquery/numericSelector.js rename to dev/app/jquery/widgets/numericSelector.js diff --git a/dev/app/custom-widgets/jquery/pagination.js b/dev/app/jquery/widgets/pagination.js similarity index 100% rename from dev/app/custom-widgets/jquery/pagination.js rename to dev/app/jquery/widgets/pagination.js diff --git a/dev/app/custom-widgets/jquery/priceRanges.js b/dev/app/jquery/widgets/priceRanges.js similarity index 100% rename from dev/app/custom-widgets/jquery/priceRanges.js rename to dev/app/jquery/widgets/priceRanges.js diff --git a/dev/app/custom-widgets/jquery/refinementList.js b/dev/app/jquery/widgets/refinementList.js similarity index 100% rename from dev/app/custom-widgets/jquery/refinementList.js rename to dev/app/jquery/widgets/refinementList.js diff --git a/dev/app/custom-widgets/jquery/searchBox.js b/dev/app/jquery/widgets/searchBox.js similarity index 100% rename from dev/app/custom-widgets/jquery/searchBox.js rename to dev/app/jquery/widgets/searchBox.js diff --git a/dev/app/custom-widgets/jquery/showMoreMenu.js b/dev/app/jquery/widgets/showMoreMenu.js similarity index 100% rename from dev/app/custom-widgets/jquery/showMoreMenu.js rename to dev/app/jquery/widgets/showMoreMenu.js diff --git a/dev/app/custom-widgets/jquery/sortBySelector.js b/dev/app/jquery/widgets/sortBySelector.js similarity index 100% rename from dev/app/custom-widgets/jquery/sortBySelector.js rename to dev/app/jquery/widgets/sortBySelector.js diff --git a/dev/app/custom-widgets/jquery/starRating.js b/dev/app/jquery/widgets/starRating.js similarity index 100% rename from dev/app/custom-widgets/jquery/starRating.js rename to dev/app/jquery/widgets/starRating.js diff --git a/dev/app/custom-widgets/jquery/stats.js b/dev/app/jquery/widgets/stats.js similarity index 100% rename from dev/app/custom-widgets/jquery/stats.js rename to dev/app/jquery/widgets/stats.js diff --git a/dev/app/custom-widgets/jquery/toggle.js b/dev/app/jquery/widgets/toggle.js similarity index 100% rename from dev/app/custom-widgets/jquery/toggle.js rename to dev/app/jquery/widgets/toggle.js diff --git a/dev/app/templates/all-items.html b/dev/app/utils/all-items.html similarity index 100% rename from dev/app/templates/all-items.html rename to dev/app/utils/all-items.html diff --git a/dev/app/templates/item.html b/dev/app/utils/item.html similarity index 100% rename from dev/app/templates/item.html rename to dev/app/utils/item.html diff --git a/dev/app/templates/no-results.html b/dev/app/utils/no-results.html similarity index 100% rename from dev/app/templates/no-results.html rename to dev/app/utils/no-results.html diff --git a/dev/app/wrap-with-hits.js b/dev/app/utils/wrap-with-hits.js similarity index 84% rename from dev/app/wrap-with-hits.js rename to dev/app/utils/wrap-with-hits.js index 59671b1fc2..3224f769fc 100644 --- a/dev/app/wrap-with-hits.js +++ b/dev/app/utils/wrap-with-hits.js @@ -1,11 +1,14 @@ /* eslint-disable import/default */ -import { action } from 'dev-novel'; -import instantsearch from '../../index.js'; -import item from './templates/item.html'; -import empty from './templates/no-results.html'; +import { action } from 'dev-novel'; +import instantsearch from '../../../index.js'; +import item from './item.html'; +import empty from './no-results.html'; -export default (initWidget, instantSearchConfig = {}) => container => { +export const wrapWithHits = ( + initWidget, + instantSearchConfig = {} +) => container => { const { appId = 'latency', apiKey = '6be0576ff61c053d5f9a3225e2a90f76', @@ -79,3 +82,6 @@ export default (initWidget, instantSearchConfig = {}) => container => { window.search.start(); }; + +export const wrapWithHitsAndJquery = fn => + wrapWithHits(container => fn(window.$(container))); diff --git a/dev/app/vanilla/init-stories.js b/dev/app/vanilla/init-stories.js new file mode 100644 index 0000000000..893cf3c557 --- /dev/null +++ b/dev/app/vanilla/init-stories.js @@ -0,0 +1,13 @@ +import initClearAllStories from './stories/clear-all.stories'; +import initHitsStories from './stories/hits.stories'; +import initMenuStories from './stories/menu.stories'; +import initRefinementListStories from './stories/refinement-list.stories'; +import initSearchBoxStories from './stories/search-box.stories'; + +export default () => { + initClearAllStories(); + initHitsStories(); + initMenuStories(); + initRefinementListStories(); + initSearchBoxStories(); +}; diff --git a/dev/app/vanilla/stories/clear-all.stories.js b/dev/app/vanilla/stories/clear-all.stories.js new file mode 100644 index 0000000000..d0571bc0bf --- /dev/null +++ b/dev/app/vanilla/stories/clear-all.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('ClearAll'); + +export default () => { + stories.add( + 'default', + wrapWithHits(containerNode => { + window.search.addWidget(widgets.clearAll({ containerNode })); + }) + ); +}; diff --git a/dev/app/vanilla/stories/hits.stories.js b/dev/app/vanilla/stories/hits.stories.js new file mode 100644 index 0000000000..3583c7550c --- /dev/null +++ b/dev/app/vanilla/stories/hits.stories.js @@ -0,0 +1,14 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Hits'); + +export default () => { + stories.add( + 'default', + wrapWithHits(containerNode => { + window.search.addWidget(widgets.hits({ containerNode })); + }) + ); +}; diff --git a/dev/app/vanilla/stories/menu.stories.js b/dev/app/vanilla/stories/menu.stories.js new file mode 100644 index 0000000000..9adc2ea876 --- /dev/null +++ b/dev/app/vanilla/stories/menu.stories.js @@ -0,0 +1,21 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('Menu'); + +export default () => { + stories.add( + 'select', + wrapWithHits(containerNode => { + window.search.addWidget( + widgets.selectMenu({ + containerNode, + attributeName: 'brand', + limit: 10, + title: 'Brands', + }) + ); + }) + ); +}; diff --git a/dev/app/vanilla/stories/refinement-list.stories.js b/dev/app/vanilla/stories/refinement-list.stories.js new file mode 100644 index 0000000000..d3d94bd49d --- /dev/null +++ b/dev/app/vanilla/stories/refinement-list.stories.js @@ -0,0 +1,22 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('RefinementList'); + +export default () => { + stories.add( + 'default', + wrapWithHits(containerNode => { + window.search.addWidget( + widgets.refinementList({ + containerNode, + attributeName: 'brand', + operator: 'or', + limit: 10, + title: 'Brands', + }) + ); + }) + ); +}; diff --git a/dev/app/vanilla/stories/search-box.stories.js b/dev/app/vanilla/stories/search-box.stories.js new file mode 100644 index 0000000000..62e3330943 --- /dev/null +++ b/dev/app/vanilla/stories/search-box.stories.js @@ -0,0 +1,37 @@ +import { storiesOf } from 'dev-novel'; +import { wrapWithHits } from '../../utils/wrap-with-hits.js'; +import * as widgets from '../widgets/index.js'; + +const stories = storiesOf('SearchBox'); + +export default () => { + stories + .add( + 'default', + wrapWithHits(container => { + const input = document.createElement('input'); + container.appendChild(input); + + window.search.addWidget( + widgets.searchBox({ + node: input, + placeholder: 'Search for products', + }) + ); + }) + ) + .add( + 'with enter to search', + wrapWithHits(container => { + const input = document.createElement('input'); + container.appendChild(input); + + window.search.addWidget( + widgets.searchBoxReturn({ + node: input, + placeholder: 'Search for products', + }) + ); + }) + ); +}; diff --git a/dev/app/custom-widgets/vanilla/clearAll.js b/dev/app/vanilla/widgets/clearAll.js similarity index 100% rename from dev/app/custom-widgets/vanilla/clearAll.js rename to dev/app/vanilla/widgets/clearAll.js diff --git a/dev/app/custom-widgets/vanilla/hits.js b/dev/app/vanilla/widgets/hits.js similarity index 100% rename from dev/app/custom-widgets/vanilla/hits.js rename to dev/app/vanilla/widgets/hits.js diff --git a/dev/app/custom-widgets/vanilla/index.js b/dev/app/vanilla/widgets/index.js similarity index 100% rename from dev/app/custom-widgets/vanilla/index.js rename to dev/app/vanilla/widgets/index.js diff --git a/dev/app/custom-widgets/vanilla/refinementList.js b/dev/app/vanilla/widgets/refinementList.js similarity index 100% rename from dev/app/custom-widgets/vanilla/refinementList.js rename to dev/app/vanilla/widgets/refinementList.js diff --git a/dev/app/custom-widgets/vanilla/searchBox.js b/dev/app/vanilla/widgets/searchBox.js similarity index 100% rename from dev/app/custom-widgets/vanilla/searchBox.js rename to dev/app/vanilla/widgets/searchBox.js diff --git a/dev/app/custom-widgets/vanilla/searchBoxReturn.js b/dev/app/vanilla/widgets/searchBoxReturn.js similarity index 100% rename from dev/app/custom-widgets/vanilla/searchBoxReturn.js rename to dev/app/vanilla/widgets/searchBoxReturn.js diff --git a/dev/app/custom-widgets/vanilla/selectMenu.js b/dev/app/vanilla/widgets/selectMenu.js similarity index 100% rename from dev/app/custom-widgets/vanilla/selectMenu.js rename to dev/app/vanilla/widgets/selectMenu.js From ea7114b74b6b03a928fc307c9dae9e8d2efab971 Mon Sep 17 00:00:00 2001 From: Alex S Date: Fri, 3 Nov 2017 18:46:36 +0100 Subject: [PATCH 4/8] chore(doc): complete requirements for SFFV (#2549) Fix #2539 --- src/widgets/refinement-list/refinement-list.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/refinement-list/refinement-list.js b/src/widgets/refinement-list/refinement-list.js index 83e843b5ad..a6375945e1 100644 --- a/src/widgets/refinement-list/refinement-list.js +++ b/src/widgets/refinement-list/refinement-list.js @@ -177,7 +177,7 @@ refinementList({ * * You can also use a sort function that behaves like the standard Javascript [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Syntax). * @property {number} [limit=10] How much facet values to get. When the show more feature is activated this is the minimum number of facets requested (the show more button is not in active state). - * @property {SearchForFacetOptions|boolean} [searchForFacetValues=false] Add a search input to let the user search for more facet values. + * @property {SearchForFacetOptions|boolean} [searchForFacetValues=false] Add a search input to let the user search for more facet values. In order to make this feature work, you need to make the attribute searchable [using the API](https://www.algolia.com/doc/guides/searching/faceting/?language=js#declaring-a-searchable-attribute-for-faceting) or [the dashboard](https://www.algolia.com/explorer/display/). * @property {RefinementListShowMoreOptions|boolean} [showMore=false] Limit the number of results and display a showMore button. * @property {RefinementListTemplates} [templates] Templates to use for the widget. * @property {RefinementListTransforms} [transformData] Functions to update the values before applying the templates. @@ -203,7 +203,7 @@ refinementList({ * [attribute for faceting](https://www.algolia.com/doc/guides/searching/faceting/#declaring-attributes-for-faceting) * in your Algolia settings. * - * If you also want to use search for facet values on this attribute, then [declare it accordingly](https://www.algolia.com/doc/guides/searching/faceting/#search-for-facet-values). + * If you also want to use search for facet values on this attribute, you need to make it searchable using the [dashboard](https://www.algolia.com/explorer/display/) or using the [API](https://www.algolia.com/doc/guides/searching/faceting/#search-for-facet-values). * * @type {WidgetFactory} * @category filter From ec810fa714302704141151311ca70171c7484708 Mon Sep 17 00:00:00 2001 From: Maxime Janton <127086@supinfo.com> Date: Mon, 6 Nov 2017 15:08:48 +0100 Subject: [PATCH 5/8] fix(connectRefinementList): add label to searched items (#2553) --- src/connectors/refinement-list/connectRefinementList.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/connectors/refinement-list/connectRefinementList.js b/src/connectors/refinement-list/connectRefinementList.js index 4be4bd870c..2a17b6c98a 100644 --- a/src/connectors/refinement-list/connectRefinementList.js +++ b/src/connectors/refinement-list/connectRefinementList.js @@ -238,7 +238,11 @@ export default function connectRefinementList(renderFn) { }); } else { helper.searchForFacetValues(attributeName, query).then(results => { - const facetValues = results.facetHits; + const facetValues = results.facetHits.map(({ value, ...item }) => ({ + ...item, + value, + label: value, + })); render({ items: facetValues, From 0f1bf087f8001a1e94412b794a0f5fdce07ba0f1 Mon Sep 17 00:00:00 2001 From: Alex S Date: Mon, 6 Nov 2017 18:09:27 +0100 Subject: [PATCH 6/8] fix(refinementList): fix facet exhaustivity check (#2554) * fix(refinementList): fix facet exhausistivity check This check depends on wether or not there is another widget setting the max value per facet to a bigger value, we can't be sure that if there is the same number of items than the limit that it is exhaustive. Fixes the other part of #2552 * chore(style): fix according to prettier --- .../__tests__/connectRefinementList-test.js | 85 ++++++++++++++++++- .../refinement-list/connectRefinementList.js | 15 +++- .../__tests__/refinement-list-test.js | 4 +- 3 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/connectors/refinement-list/__tests__/connectRefinementList-test.js b/src/connectors/refinement-list/__tests__/connectRefinementList-test.js index 115f928337..c206dcd367 100644 --- a/src/connectors/refinement-list/__tests__/connectRefinementList-test.js +++ b/src/connectors/refinement-list/__tests__/connectRefinementList-test.js @@ -483,7 +483,7 @@ describe('connectRefinementList', () => { ]); }); - it('hasExhaustiveItems indicates if the items provided are exhaustive', () => { + it('hasExhaustiveItems indicates if the items provided are exhaustive - without other widgets making the maxValuesPerFacet bigger', () => { const widget = makeWidget({ attributeName: 'category', limit: 2, @@ -512,6 +512,7 @@ describe('connectRefinementList', () => { facets: { category: { c1: 880, + c2: 880, }, }, }, @@ -519,6 +520,86 @@ describe('connectRefinementList', () => { facets: { category: { c1: 880, + c2: 880, + }, + }, + }, + ]), + state: helper.state, + helper, + createURL: () => '#', + }); + + // this one is `false` because we're not sure that what we asked is the actual number of facet values + expect(rendering.lastCall.args[0].hasExhaustiveItems).toEqual(false); + + widget.render({ + results: new SearchResults(helper.state, [ + { + hits: [], + facets: { + category: { + c1: 880, + c2: 34, + c3: 440, + }, + }, + }, + { + facets: { + category: { + c1: 880, + c2: 34, + c3: 440, + }, + }, + }, + ]), + state: helper.state, + helper, + createURL: () => '#', + }); + + expect(rendering.lastCall.args[0].hasExhaustiveItems).toEqual(false); + }); + + it('hasExhaustiveItems indicates if the items provided are exhaustive - with an other widgets making the maxValuesPerFacet bigger', () => { + const widget = makeWidget({ + attributeName: 'category', + limit: 2, + }); + + const helper = algoliasearchHelper(fakeClient, '', { + ...widget.getConfiguration({}), + maxValuesPerFacet: 3, + }); + helper.search = sinon.stub(); + + widget.init({ + helper, + state: helper.state, + createURL: () => '#', + onHistoryChange: () => {}, + }); + + expect(rendering.lastCall.args[0].hasExhaustiveItems).toEqual(true); + + widget.render({ + results: new SearchResults(helper.state, [ + { + hits: [], + facets: { + category: { + c1: 880, + c2: 880, + }, + }, + }, + { + facets: { + category: { + c1: 880, + c2: 880, }, }, }, @@ -539,6 +620,7 @@ describe('connectRefinementList', () => { c1: 880, c2: 34, c3: 440, + c4: 440, }, }, }, @@ -548,6 +630,7 @@ describe('connectRefinementList', () => { c1: 880, c2: 34, c3: 440, + c4: 440, }, }, }, diff --git a/src/connectors/refinement-list/connectRefinementList.js b/src/connectors/refinement-list/connectRefinementList.js index 2a17b6c98a..0d5d7d3df9 100644 --- a/src/connectors/refinement-list/connectRefinementList.js +++ b/src/connectors/refinement-list/connectRefinementList.js @@ -338,7 +338,20 @@ export default function connectRefinementList(renderFn) { const facetValues = results.getFacetValues(attributeName, { sortBy }); const items = facetValues.slice(0, this.getLimit()).map(formatItems); - const hasExhaustiveItems = facetValues.length <= this.getLimit(); + const maxValuesPerFacetConfig = state.getQueryParameter( + 'maxValuesPerFacet' + ); + const currentLimit = this.getLimit(); + // If the limit is the max number of facet retrieved it is impossible to know + // if the facets are exhaustives. The only moment we are sure it is exhaustive + // is when it is strictly under the number requested unless we know that another + // widget has requested more values (maxValuesPerFacet > getLimit()). + // Because this is used for making the search of facets unable or not, it is important + // to be conservative here. + const hasExhaustiveItems = + maxValuesPerFacetConfig > currentLimit + ? facetValues.length <= currentLimit + : facetValues.length < currentLimit; lastResultsFromMainSearch = items; diff --git a/src/widgets/refinement-list/__tests__/refinement-list-test.js b/src/widgets/refinement-list/__tests__/refinement-list-test.js index fc048b9917..791edff5a0 100644 --- a/src/widgets/refinement-list/__tests__/refinement-list-test.js +++ b/src/widgets/refinement-list/__tests__/refinement-list-test.js @@ -3,6 +3,8 @@ import sinon from 'sinon'; import expectJSX from 'expect-jsx'; expect.extend(expectJSX); +import algoliasearchHelper from 'algoliasearch-helper'; +const SearchParameters = algoliasearchHelper.SearchParameters; import refinementList from '../refinement-list.js'; const instantSearchInstance = { templatesConfig: {} }; @@ -57,7 +59,7 @@ describe('refinementList()', () => { .stub() .returns([{ name: 'foo' }, { name: 'bar' }]), }; - state = { toggleRefinement: sinon.spy() }; + state = SearchParameters.make({}); createURL = () => '#'; }); From 50d99f03adcf3e2a059529815d63e18f00a687e0 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Tue, 7 Nov 2017 09:44:28 +0100 Subject: [PATCH 7/8] fix(theme): searchbar should have normal size input (#2545) Usually you want the searchbox to have the same font size (at least) as your body text. Otherwise it'll look awkardly small without other styling. Also fixed a typo in `appearance` before|after ---|--- meanwhile deduplicate width is also already in normal style --- src/css/theme/_search-box.scss | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/css/theme/_search-box.scss b/src/css/theme/_search-box.scss index ebe2daa243..a1c2bacd2c 100644 --- a/src/css/theme/_search-box.scss +++ b/src/css/theme/_search-box.scss @@ -1,15 +1,13 @@ .ais-search-box { display: inline-block; position: relative; - max-width: 300px; - width: 100%; height: 46px; white-space: nowrap; - box-sizing: border-box; font-size: 14px; &--input { - appearence: none; + appearance: none; + font: inherit; background: $white; display: inline-block; border: 1px solid #D4D8E3; From 09fca62174b5a9df212fe4e79498cf4e829700af Mon Sep 17 00:00:00 2001 From: Alex S Date: Tue, 7 Nov 2017 10:05:36 +0100 Subject: [PATCH 8/8] v2.2.3 ## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-11-07) ### Bug Fixes * **connectRefinementList:** add label to searched items ([#2553](https://github.com/algolia/instantsearch.js/issues/2553)) ([ec810fa](https://github.com/algolia/instantsearch.js/commit/ec810fa)) * **refinementList:** fix facet exhaustivity check ([#2554](https://github.com/algolia/instantsearch.js/issues/2554)) ([0f1bf08](https://github.com/algolia/instantsearch.js/commit/0f1bf08)), closes [#2552](https://github.com/algolia/instantsearch.js/issues/2552) * **theme:** searchbar should have normal size input ([#2545](https://github.com/algolia/instantsearch.js/issues/2545)) ([50d99f0](https://github.com/algolia/instantsearch.js/commit/50d99f0)) --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- src/lib/version.js | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f69ac507a2..6e5793b711 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + +## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-11-07) + + +### Bug Fixes + +* **connectRefinementList:** add label to searched items ([#2553](https://github.com/algolia/instantsearch.js/issues/2553)) ([ec810fa](https://github.com/algolia/instantsearch.js/commit/ec810fa)) +* **refinementList:** fix facet exhaustivity check ([#2554](https://github.com/algolia/instantsearch.js/issues/2554)) ([0f1bf08](https://github.com/algolia/instantsearch.js/commit/0f1bf08)), closes [#2552](https://github.com/algolia/instantsearch.js/issues/2552) +* **theme:** searchbar should have normal size input ([#2545](https://github.com/algolia/instantsearch.js/issues/2545)) ([50d99f0](https://github.com/algolia/instantsearch.js/commit/50d99f0)) + + + ## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-10-30) diff --git a/package.json b/package.json index eb935cd4b1..35dc78b1ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "instantsearch.js", - "version": "2.2.2", + "version": "2.2.3", "description": "instantsearch.js is a library of widgets to build high performance instant search experiences using Algolia", "homepage": "https://community.algolia.com/instantsearch.js/", "author": "Algolia ", diff --git a/src/lib/version.js b/src/lib/version.js index 4396617675..8a5f6d8dce 100644 --- a/src/lib/version.js +++ b/src/lib/version.js @@ -1 +1 @@ -export default '2.2.2'; +export default '2.2.3';